001/*
002 * (C) Copyright 2006-2011 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 *     bstefanescu
018 */
019package org.nuxeo.ecm.restapi.server.jaxrs.routing.io;
020
021import java.io.IOException;
022import java.io.InputStream;
023import java.io.Serializable;
024import java.lang.annotation.Annotation;
025import java.lang.reflect.Type;
026import java.util.ArrayList;
027import java.util.List;
028import java.util.Map;
029
030import javax.servlet.http.HttpServletRequest;
031import javax.ws.rs.WebApplicationException;
032import javax.ws.rs.core.Context;
033import javax.ws.rs.core.MediaType;
034import javax.ws.rs.core.MultivaluedMap;
035import javax.ws.rs.core.Response;
036import javax.ws.rs.core.UriInfo;
037import javax.ws.rs.ext.MessageBodyReader;
038import javax.ws.rs.ext.Provider;
039
040import org.apache.commons.io.IOUtils;
041import org.apache.commons.logging.Log;
042import org.apache.commons.logging.LogFactory;
043import org.codehaus.jackson.JsonFactory;
044import org.codehaus.jackson.JsonNode;
045import org.codehaus.jackson.JsonParseException;
046import org.codehaus.jackson.JsonParser;
047import org.codehaus.jackson.JsonToken;
048import org.codehaus.jackson.node.ArrayNode;
049import org.nuxeo.ecm.core.api.CoreSession;
050import org.nuxeo.ecm.core.api.NuxeoException;
051import org.nuxeo.ecm.restapi.server.jaxrs.routing.io.util.JsonEncodeDecodeUtils;
052import org.nuxeo.ecm.restapi.server.jaxrs.routing.model.WorkflowRequest;
053import org.nuxeo.ecm.webengine.WebException;
054import org.nuxeo.ecm.webengine.jaxrs.session.SessionFactory;
055
056/**
057 * @author <a href="mailto:grenard@nuxeo.com">Guillaume Renard</a>
058 */
059@Provider
060public class WorkflowRequestReader implements MessageBodyReader<WorkflowRequest> {
061
062    protected static final Log log = LogFactory.getLog(WorkflowRequestReader.class);
063
064    public static final String ENTITY_TYPE = "workflow";
065
066    @Context
067    private JsonFactory factory;
068
069    @Context
070    HttpServletRequest request;
071
072    @Context
073    UriInfo uriInfo;
074
075    @Override
076    public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
077        return WorkflowRequest.class.isAssignableFrom(type);
078    }
079
080    @Override
081    public WorkflowRequest readFrom(Class<WorkflowRequest> type, Type genericType, Annotation[] annotations,
082            MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
083            throws IOException, WebApplicationException {
084        String content = IOUtils.toString(entityStream);
085        if (content.isEmpty()) {
086            if (content.isEmpty()) {
087                throw new WebException("No content in request body", Response.Status.BAD_REQUEST.getStatusCode());
088            }
089
090        }
091
092        try {
093            return readRequest(content, httpHeaders);
094        } catch (IOException | NuxeoException | ClassNotFoundException e) {
095            throw WebException.wrap(e);
096        }
097    }
098
099    protected WorkflowRequest readRequest(String content, MultivaluedMap<String, String> httpHeaders)
100            throws JsonParseException, IOException, ClassNotFoundException {
101        CoreSession session = SessionFactory.getSession(request);
102        JsonParser jp = factory.createJsonParser(content);
103        WorkflowRequest workflowRequest = new WorkflowRequest();
104
105        JsonToken tok = jp.nextToken();
106
107        // skip {
108        if (jp.getCurrentToken() == JsonToken.START_OBJECT) {
109            tok = jp.nextToken();
110        }
111        String workflowModelName = null;
112        List<String> attachedDocumentIds = null;
113        JsonNode variableNode = null;
114        Map<String, Serializable> variables = null;
115        while (tok != JsonToken.END_OBJECT) {
116            String key = jp.getCurrentName();
117            jp.nextToken();
118            if ("workflowModelName".equals(key)) {
119                workflowModelName = jp.readValueAs(String.class);
120            } else if ("attachedDocumentIds".equals(key)) {
121                ArrayNode docNodes = (ArrayNode) jp.readValueAsTree();
122                attachedDocumentIds = new ArrayList<String>();
123                for (int i = 0; i < docNodes.size(); i++) {
124                    JsonNode node = docNodes.get(i);
125                    attachedDocumentIds.add(node.getTextValue());
126                }
127            } else if ("variables".equals(key)) {
128                variableNode = jp.readValueAsTree();
129            } else if ("entity-type".equals(key)) {
130                String entityType = jp.readValueAs(String.class);
131                if (!WorkflowRequestReader.ENTITY_TYPE.equals(entityType)) {
132                    throw new WebApplicationException(Response.Status.BAD_REQUEST);
133                }
134            } else {
135                log.debug("Unknown key: " + key);
136                jp.skipChildren();
137            }
138            tok = jp.nextToken();
139
140        }
141
142        if (workflowModelName == null) {
143            throw new WebException("No workflowModelName found in request body",
144                    Response.Status.BAD_REQUEST.getStatusCode());
145        }
146
147        if (variableNode != null) {
148            variables = JsonEncodeDecodeUtils.decodeVariables(variableNode, null, session);
149        }
150        workflowRequest.setWorkflowModelName(workflowModelName);
151        workflowRequest.setVariables(variables);
152        workflowRequest.setAttachedDocumentIds(attachedDocumentIds);
153
154        return workflowRequest;
155    }
156
157}