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