/* * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * bstefanescu */ package org.eclipse.ecr.automation.server.jaxrs.io; import java.io.IOException; import java.io.OutputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Type; import java.net.URLEncoder; import java.util.Calendar; import java.util.List; import javax.ws.rs.Produces; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Context; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.ext.MessageBodyWriter; import javax.ws.rs.ext.Provider; import net.sf.json.JSONArray; import net.sf.json.JSONNull; import net.sf.json.JSONObject; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.ecr.core.api.Blob; import org.eclipse.ecr.core.api.DocumentModel; import org.eclipse.ecr.core.api.Lock; import org.eclipse.ecr.core.api.model.DocumentPart; import org.eclipse.ecr.core.api.model.Property; import org.eclipse.ecr.core.api.model.impl.ArrayProperty; import org.eclipse.ecr.core.api.model.impl.ComplexProperty; import org.eclipse.ecr.core.api.model.impl.ListProperty; import org.eclipse.ecr.core.api.model.impl.primitives.BlobProperty; import org.eclipse.ecr.core.schema.types.ListType; import org.eclipse.ecr.core.schema.utils.DateParser; import org.joda.time.DateTime; import org.joda.time.format.ISODateTimeFormat; import org.nuxeo.common.utils.StringUtils; /** * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> */ @Provider @Produces({ "application/json+nxentity", "application/json" }) public class JsonDocumentWriter implements MessageBodyWriter<DocumentModel> { private static final Log log = LogFactory.getLog(JsonDocumentWriter.class); @Context protected HttpHeaders headers; public long getSize(DocumentModel arg0, Class<?> arg1, Type arg2, Annotation[] arg3, MediaType arg4) { return -1L; } public boolean isWriteable(Class<?> arg0, Type arg1, Annotation[] arg2, MediaType arg3) { return DocumentModel.class.isAssignableFrom(arg0); } public void writeTo(DocumentModel doc, Class<?> arg1, Type arg2, Annotation[] arg3, MediaType arg4, MultivaluedMap<String, Object> arg5, OutputStream arg6) throws IOException, WebApplicationException { try { // schema names: dublincore, file, ... or * List<String> props = headers.getRequestHeader("X-NXDocumentProperties"); JSONObject obj = null; if (props == null || props.isEmpty()) { obj = getJSON(doc, null); } else { obj = getJSON(doc, StringUtils.split(props.get(0), ',', true)); } arg6.write(obj.toString(2).getBytes("UTF-8")); } catch (Exception e) { log.error("Failed to serialize document", e); throw new WebApplicationException(500); } } public static JSONObject getJSON(DocumentModel doc, String[] schemas) throws Exception { JSONObject json = new JSONObject(); json.element("entity-type", "document"); json.element("repository", doc.getRepositoryName()); json.element("uid", doc.getId()); json.element("path", doc.getPathAsString()); json.element("type", doc.getType()); json.element("state", doc.getCurrentLifeCycleState()); json.element("lock", doc.getLock()); // old Lock lock = doc.getLockInfo(); if (lock != null) { json.element("lockOwner", lock.getOwner()); json.element( "lockCreated", ISODateTimeFormat.dateTime().print( new DateTime(lock.getCreated()))); } json.element("title", doc.getTitle()); Calendar cal = (Calendar) doc.getPart("dublincore").getValue("modified"); if (cal != null) { json.element("lastModified", DateParser.formatW3CDateTime(cal.getTime())); } if (schemas == null || schemas.length == 0) { return json; } JSONObject props = new JSONObject(); if (schemas.length == 1 && "*".equals(schemas[0])) { // full // document for (String schema : doc.getSchemas()) { addSchema(props, doc, schema); } } else { for (String schema : schemas) { addSchema(props, doc, schema); } } json.element("properties", props); return json; } protected static void addSchema(JSONObject json, DocumentModel doc, String schema) throws Exception { DocumentPart part = doc.getPart(schema); if (part==null) { return; } String prefix = part.getSchema().getNamespace().prefix; if (prefix == null || prefix.length() == 0) { prefix = schema; } prefix += ':'; String filesBaseUrl = "files/" + doc.getId() + "?path="; for (Property p : part.getChildren()) { json.element(prefix + p.getField().getName().getLocalName(), propertyToJsonValue(filesBaseUrl, p)); } } /** * Converts the given core property to JSON format. The given filesBaseUrl * is the baseUrl that can be used to locate blob content and is useful to * generate blob urls. */ protected static Object propertyToJsonValue(final String filesBaseUrl, Property prop) throws Exception { org.eclipse.ecr.core.schema.types.Type type = prop.getType(); if (prop.isScalar()) { Object v = prop.getValue(); if (v == null) { return JSONNull.getInstance(); } return type.encode(v); } else if (prop.isList()) { if (prop instanceof ArrayProperty) { Object[] ar = (Object[]) prop.getValue(); if (ar == null) { return new JSONArray(); } JSONArray jsar = new JSONArray(); for (Object o : ar) { jsar.add(((ListType)type).getFieldType().encode(o)); } return jsar; } else { ListProperty listp = (ListProperty) prop; JSONArray jsar = new JSONArray(); for (Property p : listp.getChildren()) { jsar.add(propertyToJsonValue(filesBaseUrl, p)); } return jsar; } } else { if (prop.isPhantom()) { return JSONNull.getInstance(); } if (prop instanceof BlobProperty) { // a blob Blob blob = (Blob) ((BlobProperty) prop).getValue(); JSONObject jsob = new JSONObject(); String v = blob.getFilename(); jsob.element("name", v == null ? JSONNull.getInstance() : v); v = blob.getMimeType(); jsob.element("mime-type", v == null ? JSONNull.getInstance() : v); v = blob.getEncoding(); jsob.element("encoding", v == null ? JSONNull.getInstance() : v); v = blob.getDigest(); jsob.element("digest", v == null ? JSONNull.getInstance() : v); v = Long.toString(blob.getLength()); jsob.element("length", v); jsob.element( "data", filesBaseUrl + URLEncoder.encode(prop.getPath(), "UTF-8")); return jsob; } else { // a complex property ComplexProperty cp = (ComplexProperty) prop; if (prop.isPhantom()) { return JSONNull.getInstance(); } JSONObject jsob = new JSONObject(); for (Property p : cp.getChildren()) { jsob.put(p.getName(), propertyToJsonValue(filesBaseUrl, p)); } return jsob; } } } }