/* * (C) Copyright 2015 Nuxeo SA (http://nuxeo.com/) and others. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Contributors: * Nicolas Chapurlat <nchapurlat@nuxeo.com> */ package org.nuxeo.ecm.directory.io; import static java.util.Locale.ENGLISH; import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; import static org.nuxeo.ecm.core.io.registry.reflect.Instantiations.SINGLETON; import static org.nuxeo.ecm.core.io.registry.reflect.Priorities.REFERENCE; import java.io.Closeable; import java.io.IOException; import java.util.Locale; import java.util.MissingResourceException; import java.util.Set; import javax.inject.Inject; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.codehaus.jackson.JsonGenerator; import org.nuxeo.common.utils.i18n.I18NUtils; import org.nuxeo.ecm.core.api.DocumentModel; import org.nuxeo.ecm.core.api.model.Property; import org.nuxeo.ecm.core.io.marshallers.json.ExtensibleEntityJsonWriter; import org.nuxeo.ecm.core.io.marshallers.json.OutputStreamWithJsonWriter; import org.nuxeo.ecm.core.io.marshallers.json.document.DocumentPropertiesJsonReader; import org.nuxeo.ecm.core.io.marshallers.json.enrichers.AbstractJsonEnricher; import org.nuxeo.ecm.core.io.registry.Writer; import org.nuxeo.ecm.core.io.registry.context.MaxDepthReachedException; import org.nuxeo.ecm.core.io.registry.reflect.Setup; import org.nuxeo.ecm.core.schema.SchemaManager; import org.nuxeo.ecm.core.schema.types.Field; import org.nuxeo.ecm.core.schema.types.QName; import org.nuxeo.ecm.core.schema.types.Schema; import org.nuxeo.ecm.directory.Session; import org.nuxeo.ecm.directory.api.DirectoryEntry; import org.nuxeo.ecm.directory.api.DirectoryService; import com.thoughtworks.xstream.io.json.JsonWriter; /** * Convert {@link DirectoryEntry} to Json. * <p> * This marshaller is enrichable: register class implementing {@link AbstractJsonEnricher} and managing * {@link DirectoryEntry}. * </p> * <p> * This marshaller is also extensible: extend it and simply override * {@link ExtensibleEntityJsonWriter#extend(DirectoryEntry, JsonWriter)}. * </p> * <p> * Format is: * * <pre> * { * "entity-type": "directoryEntry", * "directoryName": "DIRECTORY_NAME", <- use it to update an existing document * "properties": { * <- entry properties depending on the directory schema (password fields are hidden) * <- format is managed by {@link DocumentPropertiesJsonReader} * } * <-- contextParameters if there are enrichers activated * <-- additional property provided by extend() method * } * </pre> * * </p> * * @since 7.2 */ @Setup(mode = SINGLETON, priority = REFERENCE) public class DirectoryEntryJsonWriter extends ExtensibleEntityJsonWriter<DirectoryEntry> { public static final String ENTITY_TYPE = "directoryEntry"; private static final String MESSAGES_BUNDLE = "messages"; private static final Log log = LogFactory.getLog(DirectoryEntryJsonWriter.class); @Inject private SchemaManager schemaManager; @Inject private DirectoryService directoryService; public DirectoryEntryJsonWriter() { super(ENTITY_TYPE, DirectoryEntry.class); } @Override protected void writeEntityBody(DirectoryEntry entry, JsonGenerator jg) throws IOException { String directoryName = entry.getDirectoryName(); DocumentModel document = entry.getDocumentModel(); String schemaName = directoryService.getDirectorySchema(directoryName); String passwordField = directoryService.getDirectoryPasswordField(directoryName); jg.writeStringField("directoryName", directoryName); Schema schema = schemaManager.getSchema(schemaName); Writer<Property> propertyWriter = registry.getWriter(ctx, Property.class, APPLICATION_JSON_TYPE); // for each properties, fetch it jg.writeObjectFieldStart("properties"); Set<String> translated = ctx.getTranslated(ENTITY_TYPE); Set<String> fetched = ctx.getFetched(ENTITY_TYPE); for (Field field : schema.getFields()) { QName fieldName = field.getName(); String key = fieldName.getLocalName(); jg.writeFieldName(key); if (key.equals(passwordField)) { jg.writeString(""); } else { Property property = document.getProperty(fieldName.getPrefixedName()); boolean managed = false; Object value = property.getValue(); if (value != null && value instanceof String) { String valueString = (String) value; if (fetched.contains(fieldName.getLocalName())) { // try to fetch a referenced entry (parent for example) try (Closeable resource = ctx.wrap().controlDepth().open()) { managed = writeFetchedValue(jg, directoryName, fieldName.getLocalName(), valueString); } catch (MaxDepthReachedException e) { managed = false; } } else if (translated.contains(fieldName.getLocalName())) { // try to fetch a translated property managed = writeTranslatedValue(jg, fieldName.getLocalName(), valueString); } } if (!managed) { propertyWriter.write(property, Property.class, Property.class, APPLICATION_JSON_TYPE, new OutputStreamWithJsonWriter(jg)); } } } jg.writeEndObject(); } protected boolean writeFetchedValue(JsonGenerator jg, String directoryName, String fieldName, String value) throws IOException { try (Session session = directoryService.open(directoryName)) { DocumentModel entryModel = session.getEntry(value); if (entryModel != null) { DirectoryEntry entry = new DirectoryEntry(directoryName, entryModel); writeEntity(entry, jg); return true; } } return false; } protected boolean writeTranslatedValue(JsonGenerator jg, String fieldName, String value) throws IOException { Locale locale = ctx.getLocale(); String msg = getMessageString(value, new Object[0], locale); if (msg == null && locale != ENGLISH) { msg = getMessageString(value, new Object[0], ENGLISH); } if (msg != null && !msg.equals(value)) { jg.writeString(msg); return true; } return false; } public static String getMessageString(String key, Object[] params, Locale locale) { try { return I18NUtils.getMessageString(MESSAGES_BUNDLE, key, params, locale); } catch (MissingResourceException e) { log.trace("No bundle found", e); return null; } } }