001package org.nuxeo.ecm.platform.spreadsheet;
002
003import static org.nuxeo.ecm.core.io.registry.reflect.Instantiations.SINGLETON;
004import static org.nuxeo.ecm.core.io.registry.reflect.Priorities.REFERENCE;
005
006import java.io.IOException;
007import java.util.ArrayList;
008import java.util.HashMap;
009import java.util.List;
010import java.util.Map;
011
012import javax.inject.Inject;
013
014import org.apache.commons.logging.Log;
015import org.apache.commons.logging.LogFactory;
016import org.codehaus.jackson.JsonGenerationException;
017import org.codehaus.jackson.JsonGenerator;
018import org.nuxeo.ecm.core.api.DocumentModel;
019import org.nuxeo.ecm.core.api.model.Property;
020import org.nuxeo.ecm.core.api.model.PropertyNotFoundException;
021import org.nuxeo.ecm.core.io.marshallers.json.enrichers.AbstractJsonEnricher;
022import org.nuxeo.ecm.core.io.registry.reflect.Setup;
023import org.nuxeo.ecm.core.schema.SchemaManager;
024import org.nuxeo.ecm.core.schema.types.Field;
025import org.nuxeo.ecm.core.schema.types.Schema;
026import org.nuxeo.ecm.directory.DirectoryException;
027import org.nuxeo.ecm.directory.Session;
028import org.nuxeo.ecm.directory.api.DirectoryService;
029
030@Setup(mode = SINGLETON, priority = REFERENCE)
031public class DCVocabulariesJsonEnricher extends AbstractJsonEnricher<DocumentModel> {
032
033    private static final Log log = LogFactory.getLog(DCVocabulariesJsonEnricher.class);
034
035    public static final String NAME = "vocabularies";
036
037    private static final String DIRECTORY_DEFAULT_LABEL_PREFIX = "label_";
038
039    private static final String KEY_SEPARATOR = "/";
040
041    @Inject
042    private DirectoryService directoryService;
043
044    @Inject
045    private SchemaManager schemaManager;
046
047    public DCVocabulariesJsonEnricher() {
048        super(NAME);
049    }
050
051    @Override
052    public void write(JsonGenerator jg, DocumentModel document) throws IOException {
053        writeVocabulary(jg, document, "l10nsubjects", "dc:subjects");
054        writeVocabulary(jg, document, "l10ncoverage", "dc:coverage");
055    }
056
057    private void writeVocabulary(JsonGenerator jg, final DocumentModel doc, String directoryName, String fieldName)
058            throws IOException, JsonGenerationException {
059        try {
060            // Lookup directory schema to find label columns
061            List<String> labelFields = getLabelFields(directoryName);
062            // Get the field values
063            String[] entriesIds = getPropertyValues(doc, fieldName);
064            // 'field': [
065            jg.writeFieldName(fieldName);
066            jg.writeStartArray();
067            // { 'id': ..., 'label_*': ... }
068            if (entriesIds != null) {
069                writeLabels(jg, directoryName, entriesIds, labelFields);
070            }
071            // ]
072            jg.writeEndArray();
073        } catch (PropertyNotFoundException | DirectoryException e) {
074            log.error(e.getMessage());
075        }
076    }
077
078    /**
079     * Writes the labels for each entry
080     *
081     * @param jg
082     * @param directoryName
083     * @param entriesIds
084     * @param labelFields
085     * @throws IOException
086     */
087    private void writeLabels(JsonGenerator jg, String directoryName, String[] entriesIds, List<String> labelFields)
088            throws IOException {
089        try (Session session = directoryService.open(directoryName)) {
090            for (String entryId : entriesIds) {
091                Map<String, String> labels = getAbsoluteLabels(entryId, session, labelFields);
092                // Write absolute labels (<parent label> / <child label>)
093                jg.writeStartObject();
094                jg.writeStringField("id", entryId);
095                for (Map.Entry<String, String> label : labels.entrySet()) {
096                    jg.writeStringField(label.getKey(), label.getValue());
097                }
098                jg.writeEndObject();
099            }
100        }
101    }
102
103    /**
104     * Determines label columns based on the label prefix
105     *
106     * @param directoryName the name of the directory to inspect
107     * @return
108     */
109    private List<String> getLabelFields(String directoryName) {
110        String schemaName = directoryService.getDirectorySchema(directoryName);
111        Schema schema = schemaManager.getSchema(schemaName);
112        List<String> labelFields = new ArrayList<String>();
113        String fieldName;
114        for (Field field : schema.getFields()) {
115            fieldName = field.getName().toString();
116            if (fieldName.startsWith(DIRECTORY_DEFAULT_LABEL_PREFIX)) {
117                labelFields.add(fieldName);
118            }
119        }
120        return labelFields;
121    }
122
123    /**
124     * Return the values of a document's property as an array of strings
125     *
126     * @param doc
127     * @param fieldName
128     * @return
129     */
130    private static String[] getPropertyValues(DocumentModel doc, String fieldName) {
131        String[] entriesIds = null;
132        Property prop = doc.getProperty(fieldName);
133        if (prop.isList()) {
134            entriesIds = prop.getValue(String[].class);
135        } else {
136            String value = prop.getValue(String.class);
137            if (value != null) {
138                entriesIds = new String[] { value };
139            }
140        }
141        return entriesIds;
142    }
143
144    /**
145     * Returns absolute labels for a given entry (<parent label> / <child label>)
146     *
147     * @param entryId
148     * @param session
149     * @param labelFields
150     * @return a map of field: label
151     */
152    private static Map<String, String> getAbsoluteLabels(final String entryId, final Session session,
153            List<String> labelFields) {
154        String[] split = entryId.split(KEY_SEPARATOR);
155        Map<String, String> labels = new HashMap<>();
156        for (int i = 0; i < split.length; i++) {
157            DocumentModel entry = session.getEntry(split[i]);
158            if (entry == null) {
159                continue;
160            }
161            for (String labelField : labelFields) {
162                String result = labels.get(labelField);
163                if (result == null) {
164                    result = "";
165                }
166                String value = (String) entry.getPropertyValue(labelField);
167                result += (i > 0 ? "/" : "") + value;
168                labels.put(labelField, result);
169            }
170        }
171        return labels;
172    }
173
174}