001/*
002 * (C) Copyright 2011 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 *     Anahide Tchertchian
018 */
019package org.nuxeo.ecm.platform.contentview.json;
020
021import java.io.Serializable;
022import java.util.Calendar;
023import java.util.TimeZone;
024
025import org.apache.commons.lang3.time.FastDateFormat;
026import org.apache.commons.logging.Log;
027import org.apache.commons.logging.LogFactory;
028import org.nuxeo.ecm.core.api.DocumentModel;
029import org.nuxeo.ecm.core.api.PropertyException;
030import org.nuxeo.ecm.core.api.model.PropertyVisitor;
031import org.nuxeo.ecm.core.api.model.impl.ListProperty;
032import org.nuxeo.ecm.core.api.model.impl.MapProperty;
033import org.nuxeo.ecm.core.api.model.impl.ScalarProperty;
034import org.nuxeo.ecm.core.api.model.impl.primitives.BlobProperty;
035
036import net.sf.json.JSONArray;
037import net.sf.json.JSONException;
038import net.sf.json.JSONObject;
039
040/**
041 * Transforms a document model properties into a json object.
042 * <p>
043 * Only non-null properties are exported.
044 *
045 * @since 5.4.2
046 */
047public class DocumentModelToJSON implements PropertyVisitor {
048
049    Log log = LogFactory.getLog(DocumentModelToJSON.class);
050
051    protected static final FastDateFormat dateFormat = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ssZ",
052            TimeZone.getTimeZone("UTC"));
053
054    protected JSONObject result;
055
056    public JSONObject getResult() {
057        return result;
058    }
059
060    public JSONObject run(DocumentModel doc) {
061        result = new JSONObject();
062        doc.accept(this, result);
063        return result;
064    }
065
066    @Override
067    public boolean acceptPhantoms() {
068        return false;
069    }
070
071    @Override
072    public Object visit(MapProperty property, Object arg) throws PropertyException {
073        Object value;
074        if (property.isContainer()) {
075            value = new JSONObject();
076        } else {
077            value = property.getValue();
078        }
079        if (property instanceof BlobProperty) {
080            log.warn("Property '"
081                    + property.getName()
082                    + "' ignored during serialization. Blob and blob related properties are not written to json object.");
083        } else if (property.getParent() instanceof BlobProperty) {
084            log.warn("Property '"
085                    + property.getName()
086                    + "' ignored during serialization. Blob and blob related properties are not written to json object.");
087        } else if (property.getParent().isList()) {
088            ((JSONArray) arg).add(value);
089        } else {
090            try {
091                ((JSONObject) arg).put(property.getField().getName().getPrefixedName(), value);
092            } catch (JSONException e) {
093                throw new PropertyException("Failed to put value", e);
094            }
095        }
096        return value;
097    }
098
099    @Override
100    public Object visit(ListProperty property, Object arg) throws PropertyException {
101        Object value;
102        if (property.isContainer()) {
103            value = new JSONArray();
104        } else {
105            value = property.getValue();
106        }
107        if (property.getParent() instanceof BlobProperty) {
108            log.warn("Property '"
109                    + property.getName()
110                    + "' ignored during serialization. Blob and blob related properties are not written to json object.");
111        } else if (property.getParent().isList()) {
112            ((JSONArray) arg).add(value);
113        } else {
114            try {
115                ((JSONObject) arg).put(property.getField().getName().getPrefixedName(), value);
116            } catch (JSONException e) {
117                throw new PropertyException("Failed to put value", e);
118            }
119        }
120        return value;
121    }
122
123    @Override
124    public Object visit(ScalarProperty property, Object arg) throws PropertyException {
125        if (property.getParent() instanceof BlobProperty) {
126            log.warn("Property '"
127                    + property.getName()
128                    + "' ignored during serialization. Blob and blob related properties are not written to json object.");
129            return null;
130        }
131
132        // convert values if needed
133        Serializable value = property.getValue();
134        if (value instanceof Calendar) {
135            value = dateFormat.format(((Calendar) value).getTime());
136        }
137        // build json
138        if (property.getParent().isList()) {
139            ((JSONArray) arg).add(value);
140        } else {
141            try {
142                ((JSONObject) arg).put(property.getField().getName().getPrefixedName(), value);
143            } catch (JSONException e) {
144                throw new PropertyException("Failed to put value", e);
145            }
146        }
147        return null;
148    }
149
150}