001/*
002 * (C) Copyright 2014 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 */
020package org.nuxeo.ecm.platform.routing.core.io;
021
022import static org.nuxeo.ecm.core.io.marshallers.json.document.DocumentPropertiesJsonReader.DEFAULT_SCHEMA_NAME;
023import static org.nuxeo.ecm.core.io.registry.reflect.Instantiations.SINGLETON;
024import static org.nuxeo.ecm.core.io.registry.reflect.Priorities.REFERENCE;
025
026import java.io.Closeable;
027import java.io.IOException;
028import java.io.Serializable;
029import java.lang.reflect.ParameterizedType;
030import java.lang.reflect.Type;
031import java.util.HashMap;
032import java.util.List;
033import java.util.Map;
034
035import javax.inject.Inject;
036import javax.ws.rs.core.MediaType;
037
038import org.apache.commons.lang3.reflect.TypeUtils;
039import org.codehaus.jackson.JsonNode;
040import org.nuxeo.ecm.core.api.CoreSession;
041import org.nuxeo.ecm.core.api.DocumentModel;
042import org.nuxeo.ecm.core.api.IdRef;
043import org.nuxeo.ecm.core.api.model.Property;
044import org.nuxeo.ecm.core.io.marshallers.json.EntityJsonReader;
045import org.nuxeo.ecm.core.io.registry.context.RenderingContext.SessionWrapper;
046import org.nuxeo.ecm.core.io.registry.reflect.Setup;
047import org.nuxeo.ecm.core.schema.SchemaManager;
048import org.nuxeo.ecm.core.schema.types.CompositeType;
049import org.nuxeo.ecm.platform.routing.api.DocumentRoutingConstants;
050import org.nuxeo.ecm.platform.routing.core.impl.GraphNode;
051import org.nuxeo.ecm.platform.routing.core.impl.GraphRoute;
052import org.nuxeo.ecm.platform.task.Task;
053import org.nuxeo.runtime.api.Framework;
054
055/**
056 * @since 8.2
057 */
058@Setup(mode = SINGLETON, priority = REFERENCE)
059public class TaskCompletionRequestJsonReader extends EntityJsonReader<TaskCompletionRequest> {
060
061    public static final String ENTITY_TYPE = "task";
062
063    private static final String USE_LEGACY_CONF_KEY = "nuxeo.document.routing.json.format.legacy";
064
065    private Boolean useLegacy = null;
066
067    @Inject
068    SchemaManager schemaManager;
069
070    public TaskCompletionRequestJsonReader() {
071        super(TaskCompletionRequestJsonReader.ENTITY_TYPE);
072        String prop = Framework.getProperty(USE_LEGACY_CONF_KEY);
073        if (prop != null && Boolean.parseBoolean(prop)) {
074            useLegacy = Boolean.TRUE;
075        } else {
076            useLegacy = Boolean.FALSE;
077        }
078    }
079
080    @Override
081    public boolean accept(Class<?> clazz, Type genericType, MediaType mediatype) {
082        return !useLegacy && !ctx.getBooleanParameter(USE_LEGACY_CONF_KEY)
083                && super.accept(clazz, genericType, mediatype);
084    }
085
086    @Override
087    public TaskCompletionRequest readEntity(JsonNode jn) throws IOException {
088
089        String comment = getStringField(jn, "comment");
090
091        // get the task and workflow schema names
092        String nodeSchema;
093        String workflowSchema;
094        Map<String, Serializable> variables = new HashMap<>();
095        try (SessionWrapper closeable = ctx.getSession(null)) {
096            CoreSession session = closeable.getSession();
097
098            String taskId = getStringField(jn, "id");
099
100            DocumentModel taskDoc = session.getDocument(new IdRef(taskId));
101            Task task = taskDoc.getAdapter(Task.class);
102            String routeId = task.getVariable(DocumentRoutingConstants.TASK_ROUTE_INSTANCE_DOCUMENT_ID_KEY);
103            String nodeId = task.getVariable(DocumentRoutingConstants.TASK_NODE_ID_KEY);
104
105            NodeAccessRunner nar = new NodeAccessRunner(session, routeId, nodeId);
106            nar.runUnrestricted();
107            GraphRoute graphRoute = nar.getWorkflowInstance();
108            GraphNode node = nar.getNode();
109
110            // get the variables
111            JsonNode variablesNode = jn.get("variables");
112            if (variablesNode != null) {
113                String workflowSchemaFacet = (String) graphRoute.getDocument().getPropertyValue(
114                        GraphRoute.PROP_VARIABLES_FACET);
115                CompositeType type = schemaManager.getFacet(workflowSchemaFacet);
116                workflowSchema = type.getSchemaNames()[0];
117                variables.putAll(getVariables(variablesNode, workflowSchema));
118
119                String nodeSchemaFacet = (String) node.getDocument().getPropertyValue(GraphNode.PROP_VARIABLES_FACET);
120                type = schemaManager.getFacet(nodeSchemaFacet);
121                nodeSchema = type.getSchemaNames()[0];
122                variables.putAll(getVariables(variablesNode, nodeSchema));
123            }
124
125        }
126
127        return new TaskCompletionRequest(comment, variables, false);
128    }
129
130    private Map<String, Serializable> getVariables(JsonNode variables, String schemaName) throws IOException {
131        Map<String, Serializable> variable = new HashMap<>();
132        ParameterizedType genericType = TypeUtils.parameterize(List.class, Property.class);
133        try (Closeable resource = ctx.wrap().with(DEFAULT_SCHEMA_NAME, schemaName).open()) {
134            List<Property> properties = readEntity(List.class, genericType, variables);
135            for (Property property : properties) {
136                variable.put(property.getName().substring(schemaName.length() + 1), property.getValue());
137            }
138        }
139        return variable;
140    }
141
142}