001/*
002 * Copyright (c) 2006-2015 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     Nuxeo - initial API and implementation
011 *
012 */
013
014package org.nuxeo.ecm.automation.core.util;
015
016import java.io.IOException;
017import java.util.ArrayList;
018import java.util.Calendar;
019import java.util.HashMap;
020import java.util.Iterator;
021import java.util.List;
022import java.util.Map;
023
024import org.codehaus.jackson.JsonNode;
025import org.codehaus.jackson.JsonParser;
026import org.codehaus.jackson.map.ObjectMapper;
027import org.codehaus.jackson.node.ArrayNode;
028import org.codehaus.jackson.node.ObjectNode;
029import org.nuxeo.ecm.core.api.Blob;
030import org.nuxeo.ecm.core.schema.types.ComplexType;
031import org.nuxeo.ecm.core.schema.types.Field;
032import org.nuxeo.ecm.core.schema.types.ListType;
033import org.nuxeo.ecm.core.schema.types.SimpleType;
034import org.nuxeo.ecm.core.schema.types.Type;
035import org.nuxeo.ecm.core.schema.types.primitives.DateType;
036
037/**
038 * Helper to handle Complex types decoding from a JSON encoded String entries of a property file
039 *
040 * @author Tiry (tdelprat@nuxeo.com)
041 * @since 5.5
042 */
043public class ComplexTypeJSONDecoder {
044
045    private static final ObjectMapper mapper = new ObjectMapper();
046
047    protected static List<JSONBlobDecoder> blobDecoders = new ArrayList<JSONBlobDecoder>();
048    static {
049        mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
050        blobDecoders.add(new JSONStringBlobDecoder());
051    }
052
053    public static void registerBlobDecoder(JSONBlobDecoder blobDecoder) {
054        blobDecoders.add(blobDecoder);
055    }
056
057    public static List<Object> decodeList(ListType lt, String json) throws IOException {
058        ArrayNode jsonArray = (ArrayNode) mapper.readTree(json);
059        return decodeList(lt, jsonArray);
060    }
061
062    public static List<Object> decodeList(ListType lt, ArrayNode jsonArray) {
063        List<Object> result = new ArrayList<Object>();
064        Type currentObjectType = lt.getFieldType();
065        for (int i = 0; i < jsonArray.size(); i++) {
066            JsonNode node = jsonArray.get(i);
067            if (node.isArray()) {
068                result.add(decodeList((ListType) currentObjectType, (ArrayNode) node));
069            } else if (node.isObject()) {
070                result.add(decode((ComplexType) currentObjectType, (ObjectNode) node));
071            } else if (node.isTextual()) {
072                result.add(node.getTextValue());
073            } else if (node.isNumber()) {
074                result.add(node.getNumberValue());
075            } else if (node.isBoolean()) {
076                result.add(node.getBooleanValue());
077            }
078        }
079        return result;
080    }
081
082    public static Object decode(ComplexType ct, String json) throws IOException {
083        ObjectNode jsonObject = (ObjectNode) mapper.readTree(json);
084        return decode(ct, jsonObject);
085    }
086
087    public static Object decode(ComplexType ct, ObjectNode jsonObject) {
088
089        Map<String, Object> result = new HashMap<String, Object>();
090
091        String jsonType = "";
092        if (jsonObject.has("type")) {
093            jsonType = jsonObject.get("type").getTextValue();
094        }
095        if (jsonType.equals("blob") || ct.getName().equals("content")) {
096            return getBlobFromJSON(jsonObject);
097        }
098
099        Iterator<Map.Entry<String, JsonNode>> it = jsonObject.getFields();
100
101        while (it.hasNext()) {
102            Map.Entry<String, JsonNode> nodeEntry = it.next();
103            if (ct.hasField(nodeEntry.getKey())) {
104
105                Field field = ct.getField(nodeEntry.getKey());
106                Type fieldType = field.getType();
107                if (fieldType.isSimpleType()) {
108                    Object value;
109                    if (fieldType == DateType.INSTANCE && nodeEntry.getValue().isIntegralNumber()) {
110                        value = Calendar.getInstance();
111                        ((Calendar) value).setTimeInMillis(nodeEntry.getValue().getValueAsLong());
112                    } else {
113                        value = ((SimpleType) fieldType).decode(nodeEntry.getValue().getValueAsText());
114                    }
115                    result.put(nodeEntry.getKey(), value);
116                } else {
117                    JsonNode subNode = nodeEntry.getValue();
118                    if (subNode.isArray()) {
119                        result.put(nodeEntry.getKey(), decodeList(((ListType) fieldType), (ArrayNode) subNode));
120                    } else {
121                        result.put(nodeEntry.getKey(), decode(((ComplexType) fieldType), (ObjectNode) subNode));
122                    }
123                }
124            }
125        }
126
127        return result;
128    }
129
130    public static Blob getBlobFromJSON(ObjectNode jsonObject) {
131        Blob blob = null;
132        for (JSONBlobDecoder blobDecoder : blobDecoders) {
133            blob = blobDecoder.getBlobFromJSON(jsonObject);
134            if (blob != null) {
135                return blob;
136            }
137        }
138        return blob;
139    }
140
141}