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.documents;
018
019import java.io.IOException;
020import java.io.InputStream;
021import java.lang.annotation.Annotation;
022import java.lang.reflect.Type;
023
024import javax.servlet.http.HttpServletRequest;
025import javax.ws.rs.WebApplicationException;
026import javax.ws.rs.core.Context;
027import javax.ws.rs.core.MediaType;
028import javax.ws.rs.core.MultivaluedMap;
029import javax.ws.rs.core.Response;
030import javax.ws.rs.ext.MessageBodyReader;
031
032import org.apache.commons.io.IOUtils;
033import org.codehaus.jackson.JsonFactory;
034import org.codehaus.jackson.JsonParser;
035import org.codehaus.jackson.JsonToken;
036import org.nuxeo.ecm.automation.jaxrs.io.documents.JSONDocumentModelReader;
037import org.nuxeo.ecm.core.api.DocumentModel;
038import org.nuxeo.ecm.core.api.DocumentModelList;
039import org.nuxeo.ecm.core.api.impl.DocumentModelListImpl;
040import org.nuxeo.ecm.webengine.WebException;
041
042/**
043 * @since 5.7.3
044 */
045public class JSONDocumentModelListReader implements MessageBodyReader<DocumentModelList> {
046
047    @Context
048    private HttpServletRequest request;
049
050    @Context
051    JsonFactory factory;
052
053    @Override
054    public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
055        return DocumentModelList.class.isAssignableFrom(type);
056    }
057
058    @Override
059    public DocumentModelList readFrom(Class<DocumentModelList> type, Type genericType, Annotation[] annotations,
060            MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
061            throws IOException, WebApplicationException {
062        String content = IOUtils.toString(entityStream);
063        if (content.isEmpty()) {
064            if (content.isEmpty()) {
065                throw new WebException("No content in request body", Response.Status.BAD_REQUEST.getStatusCode());
066            }
067
068        }
069        return readRequest(content, httpHeaders, request);
070    }
071
072    /**
073     * @param content
074     * @param httpHeaders
075     * @return
076     * @since 5.7.3
077     */
078    public DocumentModelList readRequest(String content, MultivaluedMap<String, String> httpHeaders,
079            HttpServletRequest request) throws IOException {
080
081        JsonParser jp = factory.createJsonParser(content);
082        return readRequest(jp, httpHeaders, request);
083
084    }
085
086    /**
087     * @param jp
088     * @param httpHeaders
089     * @param request2
090     * @return
091     * @since TODO
092     */
093    public static DocumentModelList readRequest(JsonParser jp, MultivaluedMap<String, String> httpHeaders,
094            HttpServletRequest request) throws IOException {
095        DocumentModelList result = null;
096        jp.nextToken(); // skip {
097        JsonToken tok = jp.nextToken();
098        while (tok != JsonToken.END_OBJECT) {
099            String key = jp.getCurrentName();
100            jp.nextToken();
101            if ("entries".equals(key)) {
102                result = readDocumentEntriesFromJson(jp, httpHeaders, request);
103            } else if ("entity-type".equals(key)) {
104                String entityType = jp.readValueAs(String.class);
105                if (!"documents".equals(entityType)) {
106                    throw new WebApplicationException(Response.Status.BAD_REQUEST);
107                }
108            }
109            tok = jp.nextToken();
110        }
111
112        if (result == null) {
113            throw new WebApplicationException(Response.Status.BAD_REQUEST);
114        } else {
115            return result;
116        }
117    }
118
119    /**
120     * @param jp
121     * @param httpHeaders
122     * @param request
123     * @return
124     * @since 5.7.3
125     */
126    private static DocumentModelList readDocumentEntriesFromJson(JsonParser jp,
127            MultivaluedMap<String, String> httpHeaders, HttpServletRequest request) throws IOException {
128
129        DocumentModelList entries = new DocumentModelListImpl();
130
131        // Skip the start of the array
132
133        while (jp.nextToken() == JsonToken.START_OBJECT) {
134
135            DocumentModel doc = JSONDocumentModelReader.readJson(jp, httpHeaders, request);
136            entries.add(doc);
137        }
138
139        return entries;
140
141    }
142
143}