001/* 002 * (C) Copyright 2006-2015 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 * Nuxeo - initial API and implementation 018 * 019 */ 020 021package org.nuxeo.ecm.automation.core.util; 022 023import java.io.IOException; 024import java.util.ArrayList; 025import java.util.Calendar; 026import java.util.HashMap; 027import java.util.Iterator; 028import java.util.List; 029import java.util.Map; 030 031import org.nuxeo.ecm.core.api.Blob; 032import org.nuxeo.ecm.core.schema.types.ComplexType; 033import org.nuxeo.ecm.core.schema.types.Field; 034import org.nuxeo.ecm.core.schema.types.ListType; 035import org.nuxeo.ecm.core.schema.types.SimpleType; 036import org.nuxeo.ecm.core.schema.types.Type; 037import org.nuxeo.ecm.core.schema.types.primitives.DateType; 038 039import com.fasterxml.jackson.core.JsonParser; 040import com.fasterxml.jackson.databind.JsonNode; 041import com.fasterxml.jackson.databind.ObjectMapper; 042import com.fasterxml.jackson.databind.node.ArrayNode; 043import com.fasterxml.jackson.databind.node.ObjectNode; 044 045/** 046 * Helper to handle Complex types decoding from a JSON encoded String entries of a property file 047 * 048 * @author Tiry (tdelprat@nuxeo.com) 049 * @since 5.5 050 */ 051public class ComplexTypeJSONDecoder { 052 053 private static final ObjectMapper mapper = new ObjectMapper(); 054 055 protected static List<JSONBlobDecoder> blobDecoders = new ArrayList<>(); 056 static { 057 mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); 058 blobDecoders.add(new JSONStringBlobDecoder()); 059 blobDecoders.add(new JSONManagedBlobDecoder()); 060 } 061 062 public static void registerBlobDecoder(JSONBlobDecoder blobDecoder) { 063 blobDecoders.add(blobDecoder); 064 } 065 066 public static List<Object> decodeList(ListType lt, String json) throws IOException { 067 ArrayNode jsonArray = (ArrayNode) mapper.readTree(json); 068 return decodeList(lt, jsonArray); 069 } 070 071 public static List<Object> decodeList(ListType lt, ArrayNode jsonArray) { 072 List<Object> result = new ArrayList<Object>(); 073 Type currentObjectType = lt.getFieldType(); 074 for (int i = 0; i < jsonArray.size(); i++) { 075 JsonNode node = jsonArray.get(i); 076 if (node.isArray()) { 077 result.add(decodeList((ListType) currentObjectType, (ArrayNode) node)); 078 } else if (node.isObject()) { 079 result.add(decode((ComplexType) currentObjectType, (ObjectNode) node)); 080 } else if (node.isTextual()) { 081 result.add(node.textValue()); 082 } else if (node.isNumber()) { 083 result.add(node.numberValue()); 084 } else if (node.isBoolean()) { 085 result.add(node.booleanValue()); 086 } 087 } 088 return result; 089 } 090 091 public static Object decode(ComplexType ct, String json) throws IOException { 092 ObjectNode jsonObject = (ObjectNode) mapper.readTree(json); 093 return decode(ct, jsonObject); 094 } 095 096 public static Object decode(ComplexType ct, ObjectNode jsonObject) { 097 098 Map<String, Object> result = new HashMap<String, Object>(); 099 100 String jsonType = ""; 101 if (jsonObject.has("type")) { 102 jsonType = jsonObject.get("type").textValue(); 103 } 104 if (jsonType.equals("blob") || ct.getName().equals("content")) { 105 return getBlobFromJSON(jsonObject); 106 } 107 108 Iterator<Map.Entry<String, JsonNode>> it = jsonObject.fields(); 109 110 while (it.hasNext()) { 111 Map.Entry<String, JsonNode> nodeEntry = it.next(); 112 if (ct.hasField(nodeEntry.getKey())) { 113 114 Field field = ct.getField(nodeEntry.getKey()); 115 Type fieldType = field.getType(); 116 if (fieldType.isSimpleType()) { 117 Object value; 118 if (fieldType == DateType.INSTANCE && nodeEntry.getValue().isIntegralNumber()) { 119 value = Calendar.getInstance(); 120 ((Calendar) value).setTimeInMillis(nodeEntry.getValue().asLong()); 121 } else { 122 value = ((SimpleType) fieldType).decode(nodeEntry.getValue().asText()); 123 } 124 result.put(nodeEntry.getKey(), value); 125 } else { 126 JsonNode subNode = nodeEntry.getValue(); 127 if (subNode.isArray()) { 128 result.put(nodeEntry.getKey(), decodeList(((ListType) fieldType), (ArrayNode) subNode)); 129 } else { 130 result.put(nodeEntry.getKey(), decode(((ComplexType) fieldType), (ObjectNode) subNode)); 131 } 132 } 133 } 134 } 135 136 return result; 137 } 138 139 public static Blob getBlobFromJSON(ObjectNode jsonObject) { 140 Blob blob = null; 141 for (JSONBlobDecoder blobDecoder : blobDecoders) { 142 blob = blobDecoder.getBlobFromJSON(jsonObject); 143 if (blob != null) { 144 return blob; 145 } 146 } 147 return blob; 148 } 149 150}