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