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