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