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}