001/*
002 * (C) Copyright 2012 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 *     Florent Guillaume
018 */
019package org.nuxeo.ecm.platform.routing.core.impl;
020
021import java.io.ByteArrayOutputStream;
022import java.io.IOException;
023import java.io.Serializable;
024import java.util.Calendar;
025import java.util.HashMap;
026import java.util.LinkedHashMap;
027import java.util.Map;
028
029import org.apache.commons.lang.StringUtils;
030import org.codehaus.jackson.JsonFactory;
031import org.codehaus.jackson.JsonGenerator;
032import org.nuxeo.ecm.automation.core.util.DocumentHelper;
033import org.nuxeo.ecm.automation.core.util.Properties;
034import org.nuxeo.ecm.core.api.CoreSession;
035import org.nuxeo.ecm.core.api.DocumentModel;
036import org.nuxeo.ecm.core.api.NuxeoException;
037import org.nuxeo.ecm.core.api.model.PropertyNotFoundException;
038import org.nuxeo.ecm.core.schema.SchemaManager;
039import org.nuxeo.ecm.core.schema.types.CompositeType;
040import org.nuxeo.ecm.core.schema.types.Field;
041import org.nuxeo.ecm.core.schema.utils.DateParser;
042import org.nuxeo.ecm.platform.routing.api.DocumentRoutingConstants;
043import org.nuxeo.ecm.webengine.JsonFactoryManager;
044import org.nuxeo.runtime.api.Framework;
045
046/**
047 * Helper to set/get variables on a document that are stored in a facet.
048 *
049 * @since 5.6
050 */
051public class GraphVariablesUtil {
052
053    private GraphVariablesUtil() {
054    }
055
056    protected static SchemaManager getSchemaManager() {
057        return Framework.getLocalService(SchemaManager.class);
058    }
059
060    private static JsonFactory getFactory() {
061        JsonFactoryManager jsonFactoryManager = Framework.getLocalService(JsonFactoryManager.class);
062        return jsonFactoryManager.getJsonFactory();
063    }
064
065    /**
066     * @since 7.2
067     */
068    public static Map<String, Serializable> getVariables(DocumentModel doc, String facetProp, boolean mapToJSON) {
069        String facet = (String) doc.getPropertyValue(facetProp);
070        Map<String, Serializable> map = new LinkedHashMap<String, Serializable>();
071        if (StringUtils.isBlank(facet)) {
072            return map;
073        }
074        CompositeType type = getSchemaManager().getFacet(facet);
075        if (type == null) {
076            return map;
077        }
078        boolean hasFacet = doc.hasFacet(facet);
079        for (Field f : type.getFields()) {
080            String name = f.getName().getLocalName();
081            Serializable value = hasFacet ? doc.getPropertyValue(name) : null;
082            if (value instanceof Calendar) {
083                if (mapToJSON) {
084                    value = DateParser.formatW3CDateTime(((Calendar) value).getTime());
085                } else {
086                    value = ((Calendar) value).getTime();
087                }
088            } else if (value instanceof Object[] && mapToJSON) {
089                try {
090                    Object[] objects = (Object[]) value;
091                    ByteArrayOutputStream out = new ByteArrayOutputStream();
092                    JsonGenerator jg = getFactory().createJsonGenerator(out);
093                    jg.writeStartArray();
094                    for (Object object : objects) {
095                        jg.writeString(type.encode(object));
096                    }
097                    jg.writeEndArray();
098                    jg.flush();
099                    jg.close();
100                    value = out.toString("UTF-8");
101                } catch (IOException e) {
102                    throw new NuxeoException(e);
103                }
104            }
105            if (mapToJSON) {
106                map.put(name, value != null ? value.toString() : null);
107            } else {
108                map.put(name, value);
109            }
110        }
111        return map;
112    }
113
114    public static Map<String, Serializable> getVariables(DocumentModel doc, String facetProp) {
115        return getVariables(doc, facetProp, false);
116    }
117
118    public static void setVariables(DocumentModel doc, String facetProp, Map<String, Serializable> map) {
119        setVariables(doc, facetProp, map, true);
120    }
121
122    /**
123     * @since 7.2
124     */
125    public static void setVariables(DocumentModel doc, String facetProp, Map<String, Serializable> map, final boolean save) {
126        if (map.containsKey(DocumentRoutingConstants._MAP_VAR_FORMAT_JSON)
127                && (Boolean) map.get(DocumentRoutingConstants._MAP_VAR_FORMAT_JSON)) {
128            Map<String, String> vars = new HashMap<String, String>();
129            map.remove(DocumentRoutingConstants._MAP_VAR_FORMAT_JSON);
130            for (String key : map.keySet()) {
131                if (map.get(key) != null && !(map.get(key) instanceof String)) {
132                    throw new NuxeoException(
133                            "Trying to decode JSON variables: The parameter 'map' should contain only Strings as it contains the marker '_MAP_VAR_FORMAT_JSON' ");
134                }
135                vars.put(key, (String) map.get(key));
136            }
137            GraphVariablesUtil.setJSONVariables(doc, facetProp, vars, save);
138        } else {
139            String facet = null;
140            try {
141                facet = (String) doc.getPropertyValue(facetProp);
142            } catch (PropertyNotFoundException e) {
143                facet = facetProp;
144            }
145            if (StringUtils.isBlank(facet)) {
146                return;
147            }
148            CompositeType type = getSchemaManager().getFacet(facet);
149            if (type == null) {
150                return;
151            }
152            boolean hasFacet = doc.hasFacet(facet);
153            for (Field f : type.getFields()) {
154                String name = f.getName().getLocalName();
155                if (!map.containsKey(name)) {
156                    continue;
157                }
158                Serializable value = map.get(name);
159                if (value == null && !hasFacet) {
160                    continue;
161                }
162                if (!hasFacet) {
163                    doc.addFacet(facet);
164                    hasFacet = true;
165                }
166                doc.setPropertyValue(name, value);
167            }
168            if (save) {
169                CoreSession session = doc.getCoreSession();
170                session.saveDocument(doc);
171            }
172        }
173    }
174
175    /**
176     * Sets the variables of the workflow based on their JSON representation (especially for scalar lists).
177     *
178     * @param doc
179     * @param facetProp
180     * @param map
181     * @param save
182     * @since 5.9.3, 5.8.0-HF10
183     */
184    public static void setJSONVariables(DocumentModel doc, String facetProp, Map<String, String> map) {
185        setJSONVariables(doc, facetProp, map, true);
186    }
187
188
189    /**
190     * @since 7.2
191     */
192    public static void setJSONVariables(DocumentModel doc, String facetProp, Map<String, String> map, final boolean save) {
193        // normally the variables in the map don't contain the schema prefix
194        Properties jsonProperties = new Properties();
195        String facet = null;
196        try {
197            facet = (String) doc.getPropertyValue(facetProp);
198        } catch (PropertyNotFoundException e) {
199            facet = facetProp;
200        }
201        if (StringUtils.isBlank(facet)) {
202            return;
203        }
204        CompositeType type = getSchemaManager().getFacet(facet);
205        if (type == null) {
206        }
207        boolean hasFacet = doc.hasFacet(facet);
208        for (Field f : type.getFields()) {
209            String name = f.getName().getLocalName();
210            if (!map.containsKey(name)) {
211                continue;
212            }
213            String value = map.get(name);
214            if (value == null && !hasFacet) {
215                continue;
216            }
217            if (!hasFacet) {
218                doc.addFacet(facet);
219                hasFacet = true;
220            }
221            jsonProperties.put(name, value);
222        }
223        CoreSession session = doc.getCoreSession();
224        try {
225            DocumentHelper.setJSONProperties(session, doc, jsonProperties);
226        } catch (IOException e) {
227            throw new NuxeoException(e);
228        }
229        if (save) {
230            session.saveDocument(doc);
231        }
232    }
233
234}