001/*
002 * (C) Copyright 2006-2012 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 *     Nuxeo
018 */
019
020package org.nuxeo.ecm.automation.jaxrs.io;
021
022import java.io.IOException;
023import java.io.OutputStream;
024import java.io.Serializable;
025import java.lang.annotation.Annotation;
026import java.lang.reflect.Type;
027import java.util.Map;
028
029import javax.ws.rs.Produces;
030import javax.ws.rs.WebApplicationException;
031import javax.ws.rs.core.Context;
032import javax.ws.rs.core.MediaType;
033import javax.ws.rs.core.MultivaluedMap;
034import javax.ws.rs.ext.MessageBodyWriter;
035import javax.ws.rs.ext.Provider;
036
037import org.apache.commons.logging.Log;
038import org.apache.commons.logging.LogFactory;
039import org.nuxeo.ecm.automation.core.util.PaginableRecordSet;
040import org.nuxeo.ecm.automation.core.util.RecordSet;
041
042import com.fasterxml.jackson.core.JsonEncoding;
043import com.fasterxml.jackson.core.JsonFactory;
044import com.fasterxml.jackson.core.JsonGenerator;
045
046/**
047 * Manage JSON Marshalling for {@link RecordSet} objects
048 *
049 * @author <a href="mailto:tdelprat@nuxeo.com">Tiry</a>
050 * @since 5.7
051 */
052@Provider
053@Produces(MediaType.APPLICATION_JSON)
054public class JsonRecordSetWriter implements MessageBodyWriter<RecordSet> {
055
056    protected static Log log = LogFactory.getLog(JsonRecordSetWriter.class);
057
058    @Context
059    JsonFactory factory;
060
061    @Override
062    public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
063        boolean canUse = RecordSet.class.isAssignableFrom(type);
064        return canUse;
065    }
066
067    @Override
068    public long getSize(RecordSet t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
069        return -1L;
070    }
071
072    @Override
073    public void writeTo(RecordSet records, Class<?> type, Type genericType, Annotation[] annotations,
074            MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream out) throws IOException,
075            WebApplicationException {
076        try {
077            writeRecords(out, records);
078        } catch (IOException e) {
079            log.error("Failed to serialize recordset", e);
080            throw new WebApplicationException(500);
081        }
082
083    }
084
085    protected void writeRecords(OutputStream out, RecordSet records) throws IOException {
086
087        try (JsonGenerator jg = factory.createGenerator(out, JsonEncoding.UTF8)) {
088
089            jg.writeStartObject();
090            jg.writeStringField("entity-type", "recordSet");
091
092            if (records instanceof PaginableRecordSet) {
093                PaginableRecordSet pRecord = (PaginableRecordSet) records;
094                jg.writeBooleanField("isPaginable", true);
095                jg.writeNumberField("resultsCount", pRecord.getResultsCount());
096                jg.writeNumberField("pageSize", pRecord.getPageSize());
097                jg.writeNumberField("maxPageSize", pRecord.getMaxPageSize());
098                jg.writeNumberField("currentPageSize", pRecord.getCurrentPageSize());
099                jg.writeNumberField("currentPageIndex", pRecord.getCurrentPageIndex());
100                jg.writeNumberField("numberOfPages", pRecord.getNumberOfPages());
101                jg.writeBooleanField("isPreviousPageAvailable", pRecord.isPreviousPageAvailable());
102                jg.writeBooleanField("isNextPageAvailable", pRecord.isNextPageAvailable());
103                jg.writeBooleanField("isLastPageAvailable", pRecord.isLastPageAvailable());
104                jg.writeBooleanField("isSortable", pRecord.isSortable());
105                jg.writeBooleanField("hasError", pRecord.hasError());
106                jg.writeStringField("errorMessage", pRecord.getErrorMessage());
107            }
108
109            jg.writeArrayFieldStart("entries");
110            for (Map<String, Serializable> entry : records) {
111                jg.writeObject(entry);
112            }
113
114            if (records instanceof PaginableRecordSet) {
115                PaginableRecordSet pRecord = (PaginableRecordSet) records;
116                if (pRecord.hasAggregateSupport() && pRecord.getAggregates() != null
117                        && !pRecord.getAggregates().isEmpty()) {
118                    jg.writeObjectField("aggregations", pRecord.getAggregates());
119                }
120            }
121
122            jg.writeEndArray();
123            jg.writeEndObject();
124        }
125    }
126
127}