001/*
002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     bstefanescu
011 *     Thierry Delprat
012 */
013package org.nuxeo.ecm.automation.jaxrs.io.documents;
014
015import static org.apache.commons.lang.StringUtils.isBlank;
016
017import java.io.IOException;
018import java.io.OutputStream;
019import java.lang.annotation.Annotation;
020import java.lang.reflect.Type;
021import java.util.HashMap;
022import java.util.List;
023import java.util.Map;
024
025import javax.servlet.ServletRequest;
026import javax.servlet.http.HttpServletRequest;
027import javax.ws.rs.Produces;
028import javax.ws.rs.WebApplicationException;
029import javax.ws.rs.core.Context;
030import javax.ws.rs.core.HttpHeaders;
031import javax.ws.rs.core.MediaType;
032import javax.ws.rs.core.MultivaluedMap;
033import javax.ws.rs.ext.Provider;
034
035import org.apache.commons.logging.Log;
036import org.apache.commons.logging.LogFactory;
037import org.codehaus.jackson.JsonEncoding;
038import org.codehaus.jackson.JsonFactory;
039import org.codehaus.jackson.JsonGenerator;
040import org.nuxeo.common.utils.StringUtils;
041import org.nuxeo.ecm.automation.core.util.PaginableDocumentModelList;
042import org.nuxeo.ecm.automation.jaxrs.io.EntityListWriter;
043import org.nuxeo.ecm.core.api.DocumentLocation;
044import org.nuxeo.ecm.core.api.DocumentModel;
045import org.nuxeo.ecm.core.api.DocumentModelList;
046import org.nuxeo.ecm.core.api.impl.DocumentLocationImpl;
047import org.nuxeo.ecm.core.io.marshallers.json.document.DocumentModelListJsonWriter;
048import org.nuxeo.ecm.core.io.registry.MarshallerHelper;
049import org.nuxeo.ecm.core.io.registry.MarshallerRegistry;
050import org.nuxeo.ecm.platform.types.adapter.TypeInfo;
051import org.nuxeo.ecm.platform.url.DocumentViewImpl;
052import org.nuxeo.ecm.platform.url.api.DocumentView;
053import org.nuxeo.ecm.platform.url.api.DocumentViewCodecManager;
054import org.nuxeo.ecm.platform.web.common.vh.VirtualHostHelper;
055import org.nuxeo.ecm.webengine.jaxrs.coreiodelegate.JsonCoreIODelegate;
056import org.nuxeo.runtime.api.Framework;
057
058/**
059 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
060 * @deprecated this JAX-RS marshaller was migrated to {@link DocumentModelListJsonWriter}. To use it in JAX-RS, use
061 *             {@link JsonCoreIODelegate} to forward JAX-RS marshalling to core io. To use it your code, please refer to
062 *             {@link MarshallerRegistry} service or use {@link MarshallerHelper}.
063 */
064@Deprecated
065@Provider
066@Produces({ "application/json+nxentity", "application/json" })
067public class JsonDocumentListWriter extends EntityListWriter<DocumentModel> {
068
069    private static final Log log = LogFactory.getLog(JsonDocumentListWriter.class);
070
071    @Context
072    JsonFactory factory;
073
074    @Context
075    protected HttpHeaders headers;
076
077    @Context
078    protected HttpServletRequest request;
079
080    @Override
081    protected String getEntityType() {
082        return "documents";
083    }
084
085    @Override
086    protected void writeItem(JsonGenerator jg, DocumentModel item) throws IOException {
087        // do nothing, everything is done in #writeTo
088    }
089
090    @Override
091    public boolean isWriteable(Class<?> arg0, Type arg1, Annotation[] arg2, MediaType arg3) {
092        return DocumentModelList.class.isAssignableFrom(arg0);
093    }
094
095    @Override
096    public void writeTo(List<DocumentModel> docs, Class<?> type, Type genericType, Annotation[] annotations,
097            MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream)
098            throws IOException, WebApplicationException {
099        try {
100            List<String> props = headers.getRequestHeader(JsonDocumentWriter.DOCUMENT_PROPERTIES_HEADER);
101            String[] schemas = null;
102            if (props != null && !props.isEmpty()) {
103                schemas = StringUtils.split(props.get(0), ',', true);
104            }
105            writeDocuments(entityStream, docs, schemas, headers);
106        } catch (IOException e) {
107            log.error("Failed to serialize document list", e);
108            throw new WebApplicationException(500);
109        }
110    }
111
112    public void writeDocuments(OutputStream out, List<DocumentModel> docs, String[] schemas) throws IOException {
113        writeDocuments(factory.createJsonGenerator(out, JsonEncoding.UTF8), docs, schemas, request);
114    }
115
116    /**
117     * @since 5.9.5
118     */
119    public void writeDocuments(OutputStream out, List<DocumentModel> docs, String[] schemas, HttpHeaders headers)
120            throws IOException {
121        writeDocuments(factory.createJsonGenerator(out, JsonEncoding.UTF8), docs, schemas, headers, request);
122    }
123
124    public static void writeDocuments(JsonGenerator jg, List<DocumentModel> docs, String[] schemas,
125            ServletRequest request) throws IOException {
126        writeDocuments(jg, docs, schemas, null, request);
127    }
128
129    /**
130     * @since 5.9.5
131     */
132    public static void writeDocuments(JsonGenerator jg, List<DocumentModel> docs, String[] schemas,
133            HttpHeaders headers, ServletRequest request) throws IOException {
134        jg.writeStartObject();
135        jg.writeStringField("entity-type", "documents");
136
137        if (docs instanceof PaginableDocumentModelList) {
138            PaginableDocumentModelList provider = (PaginableDocumentModelList) docs;
139            jg.writeBooleanField("isPaginable", true);
140            jg.writeNumberField("resultsCount", provider.getResultsCount());
141            jg.writeNumberField("pageSize", provider.getPageSize());
142            jg.writeNumberField("maxPageSize", provider.getMaxPageSize());
143            jg.writeNumberField("currentPageSize", provider.getCurrentPageSize());
144            jg.writeNumberField("currentPageIndex", provider.getCurrentPageIndex());
145            jg.writeNumberField("numberOfPages", provider.getNumberOfPages());
146            jg.writeBooleanField("isPreviousPageAvailable", provider.isPreviousPageAvailable());
147            jg.writeBooleanField("isNextPageAvailable", provider.isNextPageAvailable());
148            jg.writeBooleanField("isLastPageAvailable", provider.isLastPageAvailable());
149            jg.writeBooleanField("isSortable", provider.isSortable());
150            jg.writeBooleanField("hasError", provider.hasError());
151            jg.writeStringField("errorMessage", provider.getErrorMessage());
152
153            // compat fields
154            jg.writeNumberField("totalSize", provider.totalSize());
155            jg.writeNumberField("pageIndex", provider.getCurrentPageIndex());
156            jg.writeNumberField("pageCount", provider.getNumberOfPages());
157
158            DocumentViewCodecManager documentViewCodecManager = Framework.getLocalService(DocumentViewCodecManager.class);
159            String codecName = null;
160            if (documentViewCodecManager == null) {
161                log.warn("Service 'DocumentViewCodecManager' not available : documentUrl won't be generated");
162            } else {
163                String documentLinkBuilder = provider.getDocumentLinkBuilder();
164                codecName = isBlank(documentLinkBuilder) ? documentViewCodecManager.getDefaultCodecName()
165                        : documentLinkBuilder;
166            }
167
168            jg.writeArrayFieldStart("entries");
169            for (DocumentModel doc : docs) {
170                DocumentLocation docLoc = new DocumentLocationImpl(doc);
171                Map<String, String> contextParameters = new HashMap<String, String>();
172                if (documentViewCodecManager != null) {
173                    DocumentView docView = new DocumentViewImpl(docLoc, doc.getAdapter(TypeInfo.class).getDefaultView());
174                    String documentURL = VirtualHostHelper.getContextPathProperty() + "/"
175                            + documentViewCodecManager.getUrlFromDocumentView(codecName, docView, false, null);
176                    contextParameters.put("documentURL", documentURL);
177                }
178                JsonDocumentWriter.writeDocument(jg, doc, schemas, contextParameters, headers, request);
179            }
180            jg.writeEndArray();
181            if (provider.hasAggregateSupport() && provider.getAggregates() != null
182                    && !provider.getAggregates().isEmpty()) {
183                jg.writeObjectField("aggregations", provider.getAggregates());
184            }
185        } else {
186            jg.writeArrayFieldStart("entries");
187            for (DocumentModel doc : docs) {
188                JsonDocumentWriter.writeDocument(jg, doc, schemas, new HashMap<String, String>(), headers, request);
189            }
190            jg.writeEndArray();
191        }
192
193        jg.writeEndObject();
194        jg.flush();
195    }
196
197}