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 */
020
021package org.nuxeo.ecm.platform.routing.core.io;
022
023import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
024import static org.nuxeo.ecm.core.io.registry.reflect.Instantiations.SINGLETON;
025import static org.nuxeo.ecm.core.io.registry.reflect.Priorities.REFERENCE;
026
027import java.io.Closeable;
028import java.io.IOException;
029import java.io.OutputStream;
030import javax.inject.Inject;
031import org.apache.commons.lang.StringUtils;
032import org.codehaus.jackson.JsonGenerationException;
033import org.codehaus.jackson.JsonGenerator;
034import org.nuxeo.ecm.core.api.IdRef;
035import org.nuxeo.ecm.core.api.NuxeoPrincipal;
036import org.nuxeo.ecm.core.api.model.Property;
037import org.nuxeo.ecm.core.io.marshallers.json.ExtensibleEntityJsonWriter;
038import org.nuxeo.ecm.core.io.marshallers.json.OutputStreamWithJsonWriter;
039import org.nuxeo.ecm.core.io.marshallers.json.document.DocumentModelJsonWriter;
040import org.nuxeo.ecm.core.io.registry.MarshallerRegistry;
041import org.nuxeo.ecm.core.io.registry.Writer;
042import org.nuxeo.ecm.core.io.registry.context.RenderingContext;
043import org.nuxeo.ecm.core.io.registry.context.RenderingContext.SessionWrapper;
044import org.nuxeo.ecm.core.io.registry.reflect.Setup;
045import org.nuxeo.ecm.core.schema.SchemaManager;
046import org.nuxeo.ecm.core.schema.types.CompositeType;
047import org.nuxeo.ecm.core.schema.types.Field;
048import org.nuxeo.ecm.platform.routing.api.DocumentRoute;
049import org.nuxeo.ecm.platform.routing.core.impl.GraphRoute;
050import org.nuxeo.ecm.platform.usermanager.UserManager;
051
052/**
053 * @since 7.2
054 */
055@Setup(mode = SINGLETON, priority = REFERENCE)
056public class DocumentRouteWriter extends ExtensibleEntityJsonWriter<DocumentRoute> {
057
058    public static final String ATTACHED_DOCUMENT_IDS = "attachedDocumentIds";
059
060    public static final String FETCH_ATTACHED_DOCUMENTS = ATTACHED_DOCUMENT_IDS;
061
062    public static final String ENTITY_TYPE = "workflow";
063
064    public static final String FETCH_INITATIOR = "initiator";
065
066    @Inject
067    UserManager userManager;
068
069    @Inject
070    private SchemaManager schemaManager;
071
072    public DocumentRouteWriter() {
073        super(ENTITY_TYPE, DocumentRoute.class);
074    }
075
076    @Override
077    protected void writeEntityBody(DocumentRoute item, JsonGenerator jg) throws IOException {
078        jg.writeStringField("id", item.getDocument().getId());
079        jg.writeStringField("name", item.getName());
080        jg.writeStringField("title", item.getTitle());
081        jg.writeStringField("state", item.getDocument().getCurrentLifeCycleState());
082        jg.writeStringField("workflowModelName", item.getModelName());
083        if (ctx.getFetched(ENTITY_TYPE).contains(FETCH_INITATIOR)) {
084            NuxeoPrincipal principal = userManager.getPrincipal(item.getInitiator());
085            if (principal != null) {
086                writeEntityField("initiator", principal, jg);
087            } else {
088                jg.writeStringField("initiator", item.getInitiator());
089            }
090        } else {
091            jg.writeStringField("initiator", item.getInitiator());
092        }
093
094        jg.writeArrayFieldStart(ATTACHED_DOCUMENT_IDS);
095        try (SessionWrapper wrapper = ctx.getSession(item.getDocument())) {
096            final boolean isFetchAttachedDocumentIds = ctx.getFetched(ENTITY_TYPE).contains(FETCH_ATTACHED_DOCUMENTS);
097            for (String docId : item.getAttachedDocuments()) {
098                if (isFetchAttachedDocumentIds) {
099                    IdRef idRef = new IdRef(docId);
100                    if (wrapper.getSession().exists(idRef)) {
101                        writeEntity(wrapper.getSession().getDocument(idRef), jg);
102                        break;
103                    }
104                }
105                jg.writeStartObject();
106                jg.writeStringField("id", docId);
107                jg.writeEndObject();
108            }
109        }
110        jg.writeEndArray();
111
112        if (item instanceof GraphRoute) {
113            jg.writeFieldName("variables");
114            jg.writeStartObject();
115
116            writeVariables(item, jg, registry, ctx, schemaManager);
117
118            jg.writeEndObject();
119            String graphResourceUrl = "";
120            if (item.isValidated()) {
121                // it is a model
122                graphResourceUrl = ctx.getBaseUrl() + "api/v1/workflowModel/" + item.getDocument().getName() + "/graph";
123            } else {
124                // it is an instance
125                graphResourceUrl = ctx.getBaseUrl() + "api/v1/workflow/" + item.getDocument().getId() + "/graph";
126            }
127            jg.writeStringField("graphResource", graphResourceUrl);
128        }
129    }
130
131    /**
132     * @since 8.3
133     */
134    public static void writeVariables(DocumentRoute item, JsonGenerator jg, MarshallerRegistry registry,
135            RenderingContext ctx, SchemaManager schemaManager) throws IOException, JsonGenerationException {
136        String facet = (String) item.getDocument().getPropertyValue(GraphRoute.PROP_VARIABLES_FACET);
137        if (StringUtils.isNotBlank(facet)) {
138
139            CompositeType type = schemaManager.getFacet(facet);
140            if (type != null) {
141                boolean hasFacet = item.getDocument().hasFacet(facet);
142
143                Writer<Property> propertyWriter = registry.getWriter(ctx, Property.class, APPLICATION_JSON_TYPE);
144                // provides the current route to the property marshaller
145                try (Closeable resource = ctx.wrap().with(DocumentModelJsonWriter.ENTITY_TYPE,
146                        item.getDocument()).open()) {
147                    for (Field f : type.getFields()) {
148                        String name = f.getName().getLocalName();
149                        Property property = hasFacet ? item.getDocument().getProperty(name) : null;
150                        OutputStream out = new OutputStreamWithJsonWriter(jg);
151                        jg.writeFieldName(name);
152                        propertyWriter.write(property, Property.class, Property.class, APPLICATION_JSON_TYPE, out);
153                    }
154                }
155            }
156        }
157    }
158
159}