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