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.directory.api.DirectoryEntry;
049import org.nuxeo.ecm.platform.types.adapter.TypeInfo;
050import org.nuxeo.ecm.platform.url.DocumentViewImpl;
051import org.nuxeo.ecm.platform.url.api.DocumentView;
052import org.nuxeo.ecm.platform.url.api.DocumentViewCodecManager;
053import org.nuxeo.ecm.platform.web.common.vh.VirtualHostHelper;
054import org.nuxeo.ecm.webengine.jaxrs.coreiodelegate.JsonCoreIODelegate;
055import org.nuxeo.runtime.api.Framework;
056
057/**
058 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
059 * @deprecated since 7.10 The Nuxeo JSON marshalling was migrated to nuxeo-core-io. This class is replaced by
060 *             {@link DocumentModelListJsonWriter} which is registered by default and available to marshal
061 *             {@link DirectoryEntry} from the Nuxeo Rest API thanks to the JAX-RS marshaller {@link JsonCoreIODelegate}
062 */
063@Deprecated
064@Provider
065@Produces({ "application/json+nxentity", "application/json" })
066public class JsonDocumentListWriter extends EntityListWriter<DocumentModel> {
067
068    private static final Log log = LogFactory.getLog(JsonDocumentListWriter.class);
069
070    @Context
071    JsonFactory factory;
072
073    @Context
074    protected HttpHeaders headers;
075
076    @Context
077    protected HttpServletRequest request;
078
079    @Override
080    protected String getEntityType() {
081        return "documents";
082    }
083
084    @Override
085    protected void writeItem(JsonGenerator jg, DocumentModel item) throws IOException {
086        // do nothing, everything is done in #writeTo
087    }
088
089    @Override
090    public boolean isWriteable(Class<?> arg0, Type arg1, Annotation[] arg2, MediaType arg3) {
091        return DocumentModelList.class.isAssignableFrom(arg0);
092    }
093
094    @Override
095    public void writeTo(List<DocumentModel> docs, Class<?> type, Type genericType, Annotation[] annotations,
096            MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream)
097            throws IOException, WebApplicationException {
098        try {
099            List<String> props = headers.getRequestHeader(JsonDocumentWriter.DOCUMENT_PROPERTIES_HEADER);
100            String[] schemas = null;
101            if (props != null && !props.isEmpty()) {
102                schemas = StringUtils.split(props.get(0), ',', true);
103            }
104            writeDocuments(entityStream, docs, schemas, headers);
105        } catch (IOException e) {
106            log.error("Failed to serialize document list", e);
107            throw new WebApplicationException(500);
108        }
109    }
110
111    public void writeDocuments(OutputStream out, List<DocumentModel> docs, String[] schemas) throws IOException {
112        writeDocuments(factory.createJsonGenerator(out, JsonEncoding.UTF8), docs, schemas, request);
113    }
114
115    /**
116     * @since 5.9.5
117     */
118    public void writeDocuments(OutputStream out, List<DocumentModel> docs, String[] schemas, HttpHeaders headers)
119            throws IOException {
120        writeDocuments(factory.createJsonGenerator(out, JsonEncoding.UTF8), docs, schemas, headers, request);
121    }
122
123    public static void writeDocuments(JsonGenerator jg, List<DocumentModel> docs, String[] schemas,
124            ServletRequest request) throws IOException {
125        writeDocuments(jg, docs, schemas, null, request);
126    }
127
128    /**
129     * @since 5.9.5
130     */
131    public static void writeDocuments(JsonGenerator jg, List<DocumentModel> docs, String[] schemas,
132            HttpHeaders headers, ServletRequest request) throws IOException {
133        jg.writeStartObject();
134        jg.writeStringField("entity-type", "documents");
135
136        if (docs instanceof PaginableDocumentModelList) {
137            PaginableDocumentModelList provider = (PaginableDocumentModelList) docs;
138            jg.writeBooleanField("isPaginable", true);
139            jg.writeNumberField("resultsCount", provider.getResultsCount());
140            jg.writeNumberField("pageSize", provider.getPageSize());
141            jg.writeNumberField("maxPageSize", provider.getMaxPageSize());
142            jg.writeNumberField("currentPageSize", provider.getCurrentPageSize());
143            jg.writeNumberField("currentPageIndex", provider.getCurrentPageIndex());
144            jg.writeNumberField("numberOfPages", provider.getNumberOfPages());
145            jg.writeBooleanField("isPreviousPageAvailable", provider.isPreviousPageAvailable());
146            jg.writeBooleanField("isNextPageAvailable", provider.isNextPageAvailable());
147            jg.writeBooleanField("isLastPageAvailable", provider.isLastPageAvailable());
148            jg.writeBooleanField("isSortable", provider.isSortable());
149            jg.writeBooleanField("hasError", provider.hasError());
150            jg.writeStringField("errorMessage", provider.getErrorMessage());
151
152            // compat fields
153            jg.writeNumberField("totalSize", provider.totalSize());
154            jg.writeNumberField("pageIndex", provider.getCurrentPageIndex());
155            jg.writeNumberField("pageCount", provider.getNumberOfPages());
156
157            DocumentViewCodecManager documentViewCodecManager = Framework.getLocalService(DocumentViewCodecManager.class);
158            String codecName = null;
159            if (documentViewCodecManager == null) {
160                log.warn("Service 'DocumentViewCodecManager' not available : documentUrl won't be generated");
161            } else {
162                String documentLinkBuilder = provider.getDocumentLinkBuilder();
163                codecName = isBlank(documentLinkBuilder) ? documentViewCodecManager.getDefaultCodecName()
164                        : documentLinkBuilder;
165            }
166
167            jg.writeArrayFieldStart("entries");
168            for (DocumentModel doc : docs) {
169                DocumentLocation docLoc = new DocumentLocationImpl(doc);
170                Map<String, String> contextParameters = new HashMap<String, String>();
171                if (documentViewCodecManager != null) {
172                    DocumentView docView = new DocumentViewImpl(docLoc, doc.getAdapter(TypeInfo.class).getDefaultView());
173                    String documentURL = VirtualHostHelper.getContextPathProperty() + "/"
174                            + documentViewCodecManager.getUrlFromDocumentView(codecName, docView, false, null);
175                    contextParameters.put("documentURL", documentURL);
176                }
177                JsonDocumentWriter.writeDocument(jg, doc, schemas, contextParameters, headers, request);
178            }
179            jg.writeEndArray();
180            if (provider.hasAggregateSupport() && provider.getAggregates() != null
181                    && !provider.getAggregates().isEmpty()) {
182                jg.writeObjectField("aggregations", provider.getAggregates());
183            }
184        } else {
185            jg.writeArrayFieldStart("entries");
186            for (DocumentModel doc : docs) {
187                JsonDocumentWriter.writeDocument(jg, doc, schemas, new HashMap<String, String>(), headers, request);
188            }
189            jg.writeEndArray();
190        }
191
192        jg.writeEndObject();
193        jg.flush();
194    }
195
196}