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