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