001/*
002 * (C) Copyright 2015 Nuxeo SA (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl-2.1.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Nicolas Chapurlat <nchapurlat@nuxeo.com>
016 */
017
018package org.nuxeo.ecm.core.io.marshallers.json.types;
019
020import static org.nuxeo.ecm.core.io.registry.reflect.Instantiations.SINGLETON;
021import static org.nuxeo.ecm.core.io.registry.reflect.Priorities.REFERENCE;
022
023import java.io.IOException;
024
025import org.apache.commons.lang.StringUtils;
026import org.codehaus.jackson.JsonGenerator;
027import org.nuxeo.ecm.core.io.marshallers.json.ExtensibleEntityJsonWriter;
028import org.nuxeo.ecm.core.io.marshallers.json.enrichers.AbstractJsonEnricher;
029import org.nuxeo.ecm.core.io.registry.reflect.Setup;
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.PrimitiveType;
034import org.nuxeo.ecm.core.schema.types.Schema;
035import org.nuxeo.ecm.core.schema.types.Type;
036
037import com.thoughtworks.xstream.io.json.JsonWriter;
038
039/**
040 * Convert {@link Schema} to Json.
041 * <p>
042 * This marshaller is enrichable: register class implementing {@link AbstractJsonEnricher} and managing {@link Schema}.
043 * </p>
044 * <p>
045 * This marshaller is also extensible: extend it and simply override
046 * {@link ExtensibleEntityJsonWriter#extend(Schema, JsonWriter)}.
047 * </p>
048 * <p>
049 * Format is:
050 *
051 * <pre>
052 * {@code
053 * {
054 *   "entity-type":"schema",
055 *   "name": "SCHEMA_NAME",
056 *   "prefix: "SCHEMA_PREFIX",  <- only if there's a prefix
057 *   "fields", {
058 *     "PRIMITIVE_FIELD_LOCAL_NAME": "FIELD_TYPE", <- where field type is {@link Type#getName()} (string, boolean, integer, ...)
059 *     "PRIMITIVE_LIST_LOCAL_NAME": "FIELD_TYPE[]" <- where field type is {@link Type#getName()} (string, boolean, integer, ...)
060 *     "COMPLEX_FIELD_LOCAL_NAME" : {
061 *       "type": "complex",
062 *       "fields": {
063 *         loop the same format
064 *       }
065 *     },
066 *     "COMPLEX_LIST_FIELD_LOCAL_NAME" : {
067 *       "type": "complex[]",
068 *       "fields": {
069 *         loop the same format
070 *       }
071 *     },
072 *     "CONTENT_FIELD": "blob",
073 *     "CONTENT_LIST_FIELD": "blob[]",
074 *     ...
075 *   }
076 *             <-- contextParameters if there are enrichers activated
077 *             <-- additional property provided by extend() method
078 * }
079 * </pre>
080 *
081 * </p>
082 *
083 * @since 7.2
084 */
085@Setup(mode = SINGLETON, priority = REFERENCE)
086public class SchemaJsonWriter extends ExtensibleEntityJsonWriter<Schema> {
087
088    public static final String ENTITY_TYPE = "schema";
089
090    public SchemaJsonWriter() {
091        super(ENTITY_TYPE, Schema.class);
092    }
093
094    @Override
095    protected void writeEntityBody(Schema schema, JsonGenerator jg) throws IOException {
096        jg.writeStringField("name", schema.getName());
097        String prefix = schema.getNamespace().prefix;
098        if (StringUtils.isNotBlank(prefix)) {
099            jg.writeStringField("prefix", prefix);
100        }
101        jg.writeObjectFieldStart("fields");
102        for (Field field : schema.getFields()) {
103            writeField(jg, field);
104        }
105        jg.writeEndObject();
106    }
107
108    protected void writeField(JsonGenerator jg, Field field) throws IOException {
109        if (!field.getType().isComplexType()) {
110            if (field.getType().isListType()) {
111                ListType lt = (ListType) field.getType();
112                if (lt.getFieldType().isComplexType()) {
113                    if (lt.getFieldType().getName().equals("content")) {
114                        jg.writeStringField(field.getName().getLocalName(), "blob[]");
115                    } else {
116                        jg.writeObjectFieldStart(field.getName().getLocalName());
117                        jg.writeStringField("type", "complex[]");
118                        jg.writeObjectFieldStart("fields");
119                        ComplexType cplXType = (ComplexType) lt.getField().getType();
120                        for (Field subField : cplXType.getFields()) {
121                            writeField(jg, subField);
122                        }
123                        jg.writeEndObject();
124                        jg.writeEndObject();
125                    }
126                } else {
127                    Type type = lt.getFieldType();
128                    while (!(type instanceof PrimitiveType)) {
129                        type = type.getSuperType();
130                    }
131                    jg.writeStringField(field.getName().getLocalName(), type.getName() + "[]");
132                }
133            } else {
134                Type type = field.getType();
135                while (!(type instanceof PrimitiveType)) {
136                    type = type.getSuperType();
137                }
138                jg.writeStringField(field.getName().getLocalName(), type.getName());
139            }
140        } else {
141            if (field.getType().getName().equals("content")) {
142                jg.writeStringField(field.getName().getLocalName(), "blob");
143            } else {
144                jg.writeObjectFieldStart(field.getName().getLocalName());
145                ComplexType cplXType = (ComplexType) field.getType();
146                jg.writeObjectFieldStart("fields");
147                for (Field subField : cplXType.getFields()) {
148                    writeField(jg, subField);
149                }
150                jg.writeEndObject();
151                jg.writeStringField("type", "complex");
152                jg.writeEndObject();
153            }
154        }
155    }
156
157}