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