001/*
002 * (C) Copyright 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 *     Nicolas Chapurlat <nchapurlat@nuxeo.com>
018 */
019
020package org.nuxeo.ecm.core.io.marshallers.json.types;
021
022import static org.nuxeo.ecm.core.io.registry.reflect.Instantiations.SINGLETON;
023import static org.nuxeo.ecm.core.io.registry.reflect.Priorities.REFERENCE;
024
025import java.io.IOException;
026
027import org.apache.commons.lang.StringUtils;
028import org.codehaus.jackson.JsonGenerator;
029import org.nuxeo.ecm.core.io.marshallers.json.ExtensibleEntityJsonWriter;
030import org.nuxeo.ecm.core.io.marshallers.json.enrichers.AbstractJsonEnricher;
031import org.nuxeo.ecm.core.io.registry.reflect.Setup;
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.PrimitiveType;
036import org.nuxeo.ecm.core.schema.types.Schema;
037import org.nuxeo.ecm.core.schema.types.Type;
038
039import com.thoughtworks.xstream.io.json.JsonWriter;
040
041/**
042 * Convert {@link Schema} to Json.
043 * <p>
044 * This marshaller is enrichable: register class implementing {@link AbstractJsonEnricher} and managing {@link Schema}.
045 * </p>
046 * <p>
047 * This marshaller is also extensible: extend it and simply override
048 * {@link ExtensibleEntityJsonWriter#extend(Schema, JsonWriter)}.
049 * </p>
050 * <p>
051 * Format is:
052 *
053 * <pre>
054 * {@code
055 * {
056 *   "entity-type":"schema",
057 *   "name": "SCHEMA_NAME",
058 *   "prefix: "SCHEMA_PREFIX",  <- only if there's a prefix
059 *   "fields", {
060 *     "PRIMITIVE_FIELD_LOCAL_NAME": "FIELD_TYPE", <- where field type is {@link Type#getName()} (string, boolean, integer, ...)
061 *     "PRIMITIVE_LIST_LOCAL_NAME": "FIELD_TYPE[]" <- where field type is {@link Type#getName()} (string, boolean, integer, ...)
062 *     "COMPLEX_FIELD_LOCAL_NAME" : {
063 *       "type": "complex",
064 *       "fields": {
065 *         loop the same format
066 *       }
067 *     },
068 *     "COMPLEX_LIST_FIELD_LOCAL_NAME" : {
069 *       "type": "complex[]",
070 *       "fields": {
071 *         loop the same format
072 *       }
073 *     },
074 *     "CONTENT_FIELD": "blob",
075 *     "CONTENT_LIST_FIELD": "blob[]",
076 *     ...
077 *   }
078 *             <-- contextParameters if there are enrichers activated
079 *             <-- additional property provided by extend() method
080 * }
081 * </pre>
082 *
083 * </p>
084 *
085 * @since 7.2
086 */
087@Setup(mode = SINGLETON, priority = REFERENCE)
088public class SchemaJsonWriter extends ExtensibleEntityJsonWriter<Schema> {
089
090    public static final String ENTITY_TYPE = "schema";
091
092    public SchemaJsonWriter() {
093        super(ENTITY_TYPE, Schema.class);
094    }
095
096    @Override
097    protected void writeEntityBody(Schema schema, JsonGenerator jg) throws IOException {
098        jg.writeStringField("name", schema.getName());
099        String prefix = schema.getNamespace().prefix;
100        if (StringUtils.isNotBlank(prefix)) {
101            jg.writeStringField("prefix", prefix);
102        }
103        jg.writeObjectFieldStart("fields");
104        for (Field field : schema.getFields()) {
105            writeField(jg, field);
106        }
107        jg.writeEndObject();
108    }
109
110    protected void writeField(JsonGenerator jg, Field field) throws IOException {
111        if (!field.getType().isComplexType()) {
112            if (field.getType().isListType()) {
113                ListType lt = (ListType) field.getType();
114                if (lt.getFieldType().isComplexType()) {
115                    if (lt.getFieldType().getName().equals("content")) {
116                        jg.writeStringField(field.getName().getLocalName(), "blob[]");
117                    } else {
118                        jg.writeObjectFieldStart(field.getName().getLocalName());
119                        jg.writeStringField("type", "complex[]");
120                        jg.writeObjectFieldStart("fields");
121                        ComplexType cplXType = (ComplexType) lt.getField().getType();
122                        for (Field subField : cplXType.getFields()) {
123                            writeField(jg, subField);
124                        }
125                        jg.writeEndObject();
126                        jg.writeEndObject();
127                    }
128                } else {
129                    Type type = lt.getFieldType();
130                    while (!(type instanceof PrimitiveType)) {
131                        type = type.getSuperType();
132                    }
133                    jg.writeStringField(field.getName().getLocalName(), type.getName() + "[]");
134                }
135            } else {
136                Type type = field.getType();
137                while (!(type instanceof PrimitiveType)) {
138                    type = type.getSuperType();
139                }
140                jg.writeStringField(field.getName().getLocalName(), type.getName());
141            }
142        } else {
143            if (field.getType().getName().equals("content")) {
144                jg.writeStringField(field.getName().getLocalName(), "blob");
145            } else {
146                jg.writeObjectFieldStart(field.getName().getLocalName());
147                ComplexType cplXType = (ComplexType) field.getType();
148                jg.writeObjectFieldStart("fields");
149                for (Field subField : cplXType.getFields()) {
150                    writeField(jg, subField);
151                }
152                jg.writeEndObject();
153                jg.writeStringField("type", "complex");
154                jg.writeEndObject();
155            }
156        }
157    }
158
159}