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.jaxrs.coreiodelegate.JsonCoreIODelegate;
056import org.nuxeo.ecm.webengine.model.exceptions.WebResourceNotFoundException;
057import org.nuxeo.runtime.api.Framework;
058
059/**
060 * @since 5.7.3
061 * @deprecated since 7.10 The Nuxeo JSON marshalling was migrated to nuxeo-core-io. This class is replaced by
062 *             org.nuxeo.ecm.directory.io.DirectoryEntryJsonReader which is registered by default and available to
063 *             marshal {@link DirectoryEntry} from the Nuxeo Rest API thanks to the JAX-RS marshaller
064 *             {@link JsonCoreIODelegate}.
065 */
066@Deprecated
067@Provider
068@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON + "+nxentity" })
069public class DirectoryEntryReader implements MessageBodyReader<DirectoryEntry> {
070
071    protected static final Log log = LogFactory.getLog(DirectoryEntryReader.class);
072
073    @Context
074    private JsonFactory factory;
075
076    @Override
077    public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
078        return DirectoryEntry.class.isAssignableFrom(type);
079    }
080
081    @Override
082    public DirectoryEntry readFrom(Class<DirectoryEntry> type, Type genericType, Annotation[] annotations,
083            MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
084            throws IOException, WebApplicationException {
085        String content = IOUtils.toString(entityStream);
086        if (content.isEmpty()) {
087            if (content.isEmpty()) {
088                throw new WebException("No content in request body", Response.Status.BAD_REQUEST.getStatusCode());
089            }
090
091        }
092
093        try {
094            return readRequest(content, httpHeaders);
095        } catch (IOException | NuxeoException e) {
096            throw WebException.wrap(e);
097        }
098    }
099
100    /**
101     * @param content
102     * @param httpHeaders
103     * @return
104     * @throws IOException
105     * @throws JsonParseException
106     */
107    private DirectoryEntry readRequest(String content, MultivaluedMap<String, String> httpHeaders) throws IOException {
108
109        JsonParser jp = factory.createJsonParser(content);
110        return readJson(jp, httpHeaders);
111    }
112
113    public static DirectoryEntry readJson(JsonParser jp, MultivaluedMap<String, String> httpHeaders) throws IOException {
114
115        JsonToken tok = jp.nextToken();
116
117        // skip {
118        if (jp.getCurrentToken() == JsonToken.START_OBJECT) {
119            tok = jp.nextToken();
120        }
121        String directoryName = null;
122        JsonNode propertiesNode = null;
123        while (tok != JsonToken.END_OBJECT) {
124            String key = jp.getCurrentName();
125            jp.nextToken();
126            if ("directoryName".equals(key)) {
127                directoryName = jp.readValueAs(String.class);
128            } else if ("properties".equals(key)) {
129                propertiesNode = jp.readValueAsTree();
130            } else if ("entity-type".equals(key)) {
131                String entityType = jp.readValueAs(String.class);
132                if (!DirectoryEntryWriter.ENTITY_TYPE.equals(entityType)) {
133                    throw new WebApplicationException(Response.Status.BAD_REQUEST);
134                }
135            } else {
136                log.debug("Unknown key: " + key);
137                jp.skipChildren();
138            }
139
140            tok = jp.nextToken();
141
142        }
143
144        DirectoryService ds = Framework.getLocalService(DirectoryService.class);
145        Directory directory = ds.getDirectory(directoryName);
146
147        if (directory == null) {
148            throw new WebResourceNotFoundException("Directory " + directoryName + " does not exists");
149        }
150
151        return getDirectoryEntryFromNode(propertiesNode, directory);
152
153    }
154
155    private static DirectoryEntry getDirectoryEntryFromNode(JsonNode propertiesNode, Directory directory)
156            throws DirectoryException, IOException {
157
158        String schema = directory.getSchema();
159        String id = propertiesNode.get(directory.getIdField()).getTextValue();
160
161        try (Session session = directory.getSession()) {
162            DocumentModel entry = session.getEntry(id);
163
164            if (entry == null) {
165                entry = BaseSession.createEntryModel(null, schema, id, new HashMap<>());
166            }
167
168            Properties props = new Properties();
169            Iterator<Entry<String, JsonNode>> fields = propertiesNode.getFields();
170            while (fields.hasNext()) {
171                Entry<String, JsonNode> fieldEntry = fields.next();
172                props.put(schema + ":" + fieldEntry.getKey(), fieldEntry.getValue().getTextValue());
173            }
174
175            DocumentHelper.setProperties(null, entry, props);
176
177            return new DirectoryEntry(directory.getName(), entry);
178
179        }
180    }
181
182}