001/*
002 * (C) Copyright 2014-2015 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 *     <a href="mailto:grenard@nuxeo.com">Guillaume Renard</a>
018 *
019 */
020
021package org.nuxeo.ecm.restapi.server.jaxrs.routing.io;
022
023import java.io.IOException;
024import java.io.Serializable;
025import java.util.Map.Entry;
026
027import javax.servlet.http.HttpServletRequest;
028import javax.ws.rs.Produces;
029import javax.ws.rs.core.Context;
030import javax.ws.rs.core.MediaType;
031import javax.ws.rs.core.UriInfo;
032import javax.ws.rs.ext.Provider;
033
034import org.apache.commons.lang.StringUtils;
035import org.codehaus.jackson.JsonGenerationException;
036import org.codehaus.jackson.JsonGenerator;
037import org.jboss.el.ExpressionFactoryImpl;
038import org.nuxeo.ecm.automation.jaxrs.io.EntityWriter;
039import org.nuxeo.ecm.core.api.CoreSession;
040import org.nuxeo.ecm.core.api.NuxeoPrincipal;
041import org.nuxeo.ecm.core.schema.SchemaManager;
042import org.nuxeo.ecm.core.schema.types.Schema;
043import org.nuxeo.ecm.core.schema.utils.DateParser;
044import org.nuxeo.ecm.platform.actions.ActionContext;
045import org.nuxeo.ecm.platform.actions.ELActionContext;
046import org.nuxeo.ecm.platform.actions.ejb.ActionManager;
047import org.nuxeo.ecm.platform.el.ExpressionContext;
048import org.nuxeo.ecm.platform.routing.api.DocumentRoutingConstants;
049import org.nuxeo.ecm.platform.routing.core.impl.GraphNode;
050import org.nuxeo.ecm.platform.routing.core.impl.GraphNode.Button;
051import org.nuxeo.ecm.platform.routing.core.impl.GraphRoute;
052import org.nuxeo.ecm.platform.task.Task;
053import org.nuxeo.ecm.platform.task.TaskComment;
054import org.nuxeo.ecm.restapi.server.jaxrs.routing.io.util.JsonEncodeDecodeUtils;
055import org.nuxeo.ecm.webengine.jaxrs.session.SessionFactory;
056import org.nuxeo.runtime.api.Framework;
057
058/**
059 * @since 7.2
060 */
061@Provider
062@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON + "+nxentity" })
063public class TaskWriter extends EntityWriter<Task> {
064
065    public static final String ENTITY_TYPE = "task";
066
067    @Context
068    HttpServletRequest request;
069
070    @Context
071    UriInfo uriInfo;
072
073    @Override
074    protected void writeEntityBody(JsonGenerator jg, Task item) throws IOException {
075        writeTask(jg, item, request, uriInfo);
076    }
077
078    public static void writeTask(JsonGenerator jg, Task item, HttpServletRequest request, UriInfo uriInfo)
079            throws JsonGenerationException, IOException {
080        CoreSession session = null;
081        GraphRoute workflowInstance = null;
082        GraphNode node = null;
083        String workflowInstanceId = item.getProcessId();
084        final String nodeId = item.getVariable(DocumentRoutingConstants.TASK_NODE_ID_KEY);
085        if (request != null) {
086            session = SessionFactory.getSession(request);
087        }
088        if (session != null && StringUtils.isNotBlank(workflowInstanceId)) {
089            NodeAccessRunner nodeAccessRunner = new NodeAccessRunner(session, workflowInstanceId, nodeId);
090            nodeAccessRunner.runUnrestricted();
091            workflowInstance = nodeAccessRunner.workflowInstance;
092            node = nodeAccessRunner.node;
093        }
094
095        jg.writeStringField("id", item.getDocument().getId());
096        jg.writeStringField("name", item.getName());
097        jg.writeStringField("workflowInstanceId", workflowInstanceId);
098        if (workflowInstance != null) {
099            jg.writeStringField("workflowModelName", workflowInstance.getModelName());
100        }
101        jg.writeStringField("state", item.getDocument().getCurrentLifeCycleState());
102        jg.writeStringField("directive", item.getDirective());
103        jg.writeStringField("created", DateParser.formatW3CDateTime(item.getCreated()));
104        jg.writeStringField("dueDate", DateParser.formatW3CDateTime(item.getDueDate()));
105        jg.writeStringField("nodeName", item.getVariable(DocumentRoutingConstants.TASK_NODE_ID_KEY));
106
107        jg.writeArrayFieldStart("targetDocumentIds");
108        for (String docId : item.getTargetDocumentsIds()) {
109            jg.writeStartObject();
110            jg.writeStringField("id", docId);
111            jg.writeEndObject();
112        }
113        jg.writeEndArray();
114
115        jg.writeArrayFieldStart("actors");
116        for (String actorId : item.getActors()) {
117            jg.writeStartObject();
118            jg.writeStringField("id", actorId);
119            jg.writeEndObject();
120        }
121        jg.writeEndArray();
122
123        jg.writeArrayFieldStart("comments");
124        for (TaskComment comment : item.getComments()) {
125            jg.writeStartObject();
126            jg.writeStringField("author", comment.getAuthor());
127            jg.writeStringField("text", comment.getText());
128            jg.writeStringField("date", DateParser.formatW3CDateTime(comment.getCreationDate().getTime()));
129            jg.writeEndObject();
130        }
131        jg.writeEndArray();
132
133        jg.writeFieldName("variables");
134        jg.writeStartObject();
135        // add nodeVariables
136        for (Entry<String, Serializable> e : node.getVariables().entrySet()) {
137            JsonEncodeDecodeUtils.encodeVariableEntry(node.getDocument(), GraphNode.PROP_VARIABLES_FACET, e, jg,
138                    request);
139        }
140        // add workflow variables
141        if (workflowInstance != null) {
142            final String transientSchemaName = DocumentRoutingConstants.GLOBAL_VAR_SCHEMA_PREFIX + node.getId();
143            final SchemaManager schemaManager = Framework.getService(SchemaManager.class);
144            final Schema transientSchema = schemaManager.getSchema(transientSchemaName);
145            for (Entry<String, Serializable> e : workflowInstance.getVariables().entrySet()) {
146                if (transientSchema == null || transientSchema.hasField(e.getKey())) {
147                    JsonEncodeDecodeUtils.encodeVariableEntry(workflowInstance.getDocument(),
148                            GraphRoute.PROP_VARIABLES_FACET, e, jg, request);
149                }
150            }
151        }
152        jg.writeEndObject();
153
154        if (session != null) {
155            jg.writeFieldName("taskInfo");
156            jg.writeStartObject();
157            final ActionManager actionManager = Framework.getService(ActionManager.class);
158            jg.writeArrayFieldStart("taskActions");
159            for (Button button : node.getTaskButtons()) {
160                if (StringUtils.isBlank(button.getFilter())
161                        || actionManager.checkFilter(button.getFilter(), createActionContext(session))) {
162                    jg.writeStartObject();
163                    jg.writeStringField("name", button.getName());
164                    jg.writeStringField("url", uriInfo.getBaseUri() + "api/v1/task/" + item.getDocument().getId() + "/"
165                            + button.getName());
166                    jg.writeStringField("label", button.getLabel());
167                    jg.writeEndObject();
168                }
169            }
170            jg.writeEndArray();
171
172            jg.writeFieldName("layoutResource");
173            jg.writeStartObject();
174            jg.writeStringField("name", node.getTaskLayout());
175            jg.writeStringField("url",
176                    uriInfo.getBaseUri() + "/layout-manager/layouts/?layoutName=" + node.getTaskLayout());
177            jg.writeEndObject();
178
179            jg.writeArrayFieldStart("schemas");
180            for (String schema : node.getDocument().getSchemas()) {
181                // TODO only keep functional schema once adaptation done
182                jg.writeStartObject();
183                jg.writeStringField("name", schema);
184                jg.writeStringField("url", uriInfo.getBaseUri() + "api/v1/config/schemas/" + schema);
185                jg.writeEndObject();
186            }
187            jg.writeEndArray();
188
189            jg.writeEndObject();
190        }
191
192    }
193
194    protected static ActionContext createActionContext(CoreSession session) {
195        ActionContext actionContext = new ELActionContext(new ExpressionContext(), new ExpressionFactoryImpl());
196        actionContext.setDocumentManager(session);
197        actionContext.setCurrentPrincipal((NuxeoPrincipal) session.getPrincipal());
198        return actionContext;
199    }
200
201    @Override
202    protected String getEntityType() {
203        return ENTITY_TYPE;
204    }
205
206}