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 <nchapurlat@nuxeo.com>
018 */
019
020package org.nuxeo.ecm.directory.io;
021
022import static org.nuxeo.ecm.core.io.marshallers.json.document.DocumentPropertiesJsonReader.DEFAULT_SCHEMA_NAME;
023import static org.nuxeo.ecm.core.io.registry.reflect.Instantiations.SINGLETON;
024import static org.nuxeo.ecm.core.io.registry.reflect.Priorities.REFERENCE;
025import static org.nuxeo.ecm.directory.io.DirectoryEntryJsonWriter.ENTITY_TYPE;
026
027import java.io.Closeable;
028import java.io.IOException;
029import java.lang.reflect.ParameterizedType;
030import java.util.HashMap;
031import java.util.List;
032
033import javax.inject.Inject;
034
035import org.apache.commons.lang.StringUtils;
036import org.apache.commons.lang3.reflect.TypeUtils;
037import org.codehaus.jackson.JsonNode;
038import org.nuxeo.ecm.core.api.DocumentModel;
039import org.nuxeo.ecm.core.api.model.Property;
040import org.nuxeo.ecm.core.io.marshallers.json.EntityJsonReader;
041import org.nuxeo.ecm.core.io.marshallers.json.document.DocumentPropertiesJsonReader;
042import org.nuxeo.ecm.core.io.registry.reflect.Setup;
043import org.nuxeo.ecm.directory.BaseSession;
044import org.nuxeo.ecm.directory.Directory;
045import org.nuxeo.ecm.directory.Session;
046import org.nuxeo.ecm.directory.api.DirectoryEntry;
047import org.nuxeo.ecm.directory.api.DirectoryService;
048
049/**
050 * Convert Json as {@link DirectoryEntry}.
051 * <p>
052 * Format is (any additional json property is ignored):
053 *
054 * <pre>
055 * {
056 *   "entity-type": "directoryEntry",
057 *   "directoryName": "DIRECTORY_NAME", <- use it to update an existing document
058 *   "properties": {
059 *     <- entry properties depending on the directory schema (password fields are hidden)
060 *     <- format is managed by {@link DocumentPropertiesJsonReader}
061 *   }
062 * }
063 * </pre>
064 * </p>
065 *
066 * @since 7.2
067 */
068@Setup(mode = SINGLETON, priority = REFERENCE)
069public class DirectoryEntryJsonReader extends EntityJsonReader<DirectoryEntry> {
070
071    @Inject
072    private DirectoryService directoryService;
073
074    public DirectoryEntryJsonReader() {
075        super(ENTITY_TYPE);
076    }
077
078    @Override
079    protected DirectoryEntry readEntity(JsonNode jn) throws IOException {
080        String directoryName = getStringField(jn, "directoryName");
081        Directory directory = directoryService.getDirectory(directoryName);
082        String schema = directory.getSchema();
083
084        try (Session session = directory.getSession()) {
085            DocumentModel entry = null;
086            String id = getStringField(jn, "id");
087            if (StringUtils.isNotBlank(id)) {
088                entry = session.getEntry(id);
089            }
090
091            JsonNode propsNode = jn.get("properties");
092            if (propsNode != null && !propsNode.isNull() && propsNode.isObject()) {
093                if (entry == null) {
094                    // backward compatibility; try to fetch the entry from the id inside the properties
095                    id = getStringField(propsNode, directory.getIdField());
096                    entry = session.getEntry(id);
097                }
098                if (entry == null) {
099                    entry = BaseSession.createEntryModel(null, schema, id, new HashMap<String, Object>());
100                }
101                ParameterizedType genericType = TypeUtils.parameterize(List.class, Property.class);
102                try (Closeable resource = ctx.wrap().with(DEFAULT_SCHEMA_NAME, schema).open()) {
103                    List<Property> properties = readEntity(List.class, genericType, propsNode);
104                    for (Property property : properties) {
105                        entry.setPropertyValue(property.getName(), property.getValue());
106                    }
107                }
108                return new DirectoryEntry(directory.getName(), entry);
109            }
110        }
111        return null;
112    }
113}