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