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