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}