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