001/*
002 * (C) Copyright 2013 Nuxeo SA (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl-2.1.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     dmetzler
016 */
017package org.nuxeo.ecm.restapi.jaxrs.io.directory;
018
019import java.io.IOException;
020import java.io.InputStream;
021import java.lang.annotation.Annotation;
022import java.lang.reflect.Type;
023import java.util.HashMap;
024import java.util.Iterator;
025import java.util.Map.Entry;
026
027import javax.ws.rs.Consumes;
028import javax.ws.rs.WebApplicationException;
029import javax.ws.rs.core.Context;
030import javax.ws.rs.core.MediaType;
031import javax.ws.rs.core.MultivaluedMap;
032import javax.ws.rs.core.Response;
033import javax.ws.rs.ext.MessageBodyReader;
034import javax.ws.rs.ext.Provider;
035
036import org.apache.commons.io.IOUtils;
037import org.apache.commons.logging.Log;
038import org.apache.commons.logging.LogFactory;
039import org.codehaus.jackson.JsonFactory;
040import org.codehaus.jackson.JsonNode;
041import org.codehaus.jackson.JsonParseException;
042import org.codehaus.jackson.JsonParser;
043import org.codehaus.jackson.JsonToken;
044import org.nuxeo.ecm.automation.core.util.DocumentHelper;
045import org.nuxeo.ecm.automation.core.util.Properties;
046import org.nuxeo.ecm.core.api.DocumentModel;
047import org.nuxeo.ecm.core.api.NuxeoException;
048import org.nuxeo.ecm.directory.BaseSession;
049import org.nuxeo.ecm.directory.Directory;
050import org.nuxeo.ecm.directory.DirectoryException;
051import org.nuxeo.ecm.directory.Session;
052import org.nuxeo.ecm.directory.api.DirectoryEntry;
053import org.nuxeo.ecm.directory.api.DirectoryService;
054import org.nuxeo.ecm.webengine.WebException;
055import org.nuxeo.ecm.webengine.model.exceptions.WebResourceNotFoundException;
056import org.nuxeo.runtime.api.Framework;
057
058/**
059 * @since 5.7.3
060 */
061@Provider
062@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON + "+nxentity" })
063public class DirectoryEntryReader implements MessageBodyReader<DirectoryEntry> {
064
065    protected static final Log log = LogFactory.getLog(DirectoryEntryReader.class);
066
067    @Context
068    private JsonFactory factory;
069
070    @Override
071    public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
072        return DirectoryEntry.class.isAssignableFrom(type);
073    }
074
075    @Override
076    public DirectoryEntry readFrom(Class<DirectoryEntry> type, Type genericType, Annotation[] annotations,
077            MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
078            throws IOException, WebApplicationException {
079        String content = IOUtils.toString(entityStream);
080        if (content.isEmpty()) {
081            if (content.isEmpty()) {
082                throw new WebException("No content in request body", Response.Status.BAD_REQUEST.getStatusCode());
083            }
084
085        }
086
087        try {
088            return readRequest(content, httpHeaders);
089        } catch (IOException | NuxeoException e) {
090            throw WebException.wrap(e);
091        }
092    }
093
094    /**
095     * @param content
096     * @param httpHeaders
097     * @return
098     * @throws IOException
099     * @throws JsonParseException
100     */
101    private DirectoryEntry readRequest(String content, MultivaluedMap<String, String> httpHeaders) throws IOException {
102
103        JsonParser jp = factory.createJsonParser(content);
104        return readJson(jp, httpHeaders);
105    }
106
107    public static DirectoryEntry readJson(JsonParser jp, MultivaluedMap<String, String> httpHeaders)
108            throws IOException {
109
110        JsonToken tok = jp.nextToken();
111
112        // skip {
113        if (jp.getCurrentToken() == JsonToken.START_OBJECT) {
114            tok = jp.nextToken();
115        }
116        String directoryName = null;
117        JsonNode propertiesNode = null;
118        while (tok != JsonToken.END_OBJECT) {
119            String key = jp.getCurrentName();
120            jp.nextToken();
121            if ("directoryName".equals(key)) {
122                directoryName = jp.readValueAs(String.class);
123            } else if ("properties".equals(key)) {
124                propertiesNode = jp.readValueAsTree();
125            } else if ("entity-type".equals(key)) {
126                String entityType = jp.readValueAs(String.class);
127                if (!DirectoryEntryWriter.ENTITY_TYPE.equals(entityType)) {
128                    throw new WebApplicationException(Response.Status.BAD_REQUEST);
129                }
130            } else {
131                log.debug("Unknown key: " + key);
132                jp.skipChildren();
133            }
134
135            tok = jp.nextToken();
136
137        }
138
139        DirectoryService ds = Framework.getLocalService(DirectoryService.class);
140        Directory directory = ds.getDirectory(directoryName);
141
142        if (directory == null) {
143            throw new WebResourceNotFoundException("Directory " + directoryName + " does not exists");
144        }
145
146        return getDirectoryEntryFromNode(propertiesNode, directory);
147
148    }
149
150    private static DirectoryEntry getDirectoryEntryFromNode(JsonNode propertiesNode, Directory directory)
151            throws DirectoryException, IOException {
152
153        String schema = directory.getSchema();
154        String id = propertiesNode.get(directory.getIdField()).getTextValue();
155
156        try (Session session = directory.getSession()) {
157            DocumentModel entry = session.getEntry(id);
158
159            if (entry == null) {
160                entry = BaseSession.createEntryModel(null, schema, id, new HashMap<>());
161            }
162
163            Properties props = new Properties();
164            Iterator<Entry<String, JsonNode>> fields = propertiesNode.getFields();
165            while (fields.hasNext()) {
166                Entry<String, JsonNode> fieldEntry = fields.next();
167                props.put(schema + ":" + fieldEntry.getKey(), fieldEntry.getValue().getTextValue());
168            }
169
170            DocumentHelper.setProperties(null, entry, props);
171
172            return new DirectoryEntry(directory.getName(), entry);
173
174        }
175    }
176
177}