001/*
002 * (C) Copyright 2018 Nuxeo (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 *     pierre
018 */
019package org.nuxeo.ecm.core.io.marshallers.csv;
020
021import java.io.IOException;
022import java.io.OutputStream;
023import java.io.OutputStreamWriter;
024import java.lang.reflect.Type;
025import java.util.Calendar;
026import java.util.GregorianCalendar;
027
028import javax.inject.Inject;
029import javax.ws.rs.core.MediaType;
030
031import org.apache.commons.csv.CSVFormat;
032import org.apache.commons.csv.CSVPrinter;
033import org.nuxeo.ecm.core.io.registry.MarshallerRegistry;
034import org.nuxeo.ecm.core.io.registry.Writer;
035import org.nuxeo.ecm.core.io.registry.context.RenderingContext;
036import org.nuxeo.ecm.core.io.registry.reflect.Supports;
037import org.nuxeo.ecm.core.schema.SchemaManager;
038
039/**
040 * Base class for CSV {@link Writer}.
041 * <p>
042 * It provides you a {@link CSVPrinter} to manage the marshalling.
043 *
044 * @param <T> The Java type to marshall as CSV.
045 * @since 10.3
046 */
047@Supports(AbstractCSVWriter.TEXT_CSV)
048public abstract class AbstractCSVWriter<T> implements Writer<T> {
049
050    public static final String TEXT_CSV = "text/csv";
051
052    public static final MediaType TEXT_CSV_TYPE = new MediaType("text", "csv");
053
054    /**
055     * The current {@link RenderingContext}.
056     */
057    @Inject
058    protected RenderingContext ctx;
059
060    @Inject
061    protected SchemaManager schemaManager;
062
063    @Inject
064    protected MarshallerRegistry registry;
065
066    @Override
067    public boolean accept(Class<?> clazz, Type genericType, MediaType mediatype) {
068        return TEXT_CSV_TYPE.equals(mediatype);
069    }
070
071    @Override
072    public void write(T entity, Class<?> clazz, Type genericType, MediaType mediatype, OutputStream out)
073            throws IOException {
074        @SuppressWarnings("resource") // closing CSVPrinter would close underlying out which isn't ours
075        CSVPrinter printer = getCSVPrinter(entity, out);
076        write(entity, printer);
077        printer.flush();
078    }
079
080    protected abstract void write(T entity, CSVPrinter printer) throws IOException;
081
082    protected abstract void writeHeader(T entity, CSVPrinter printer) throws IOException;
083
084    protected CSVPrinter getCSVPrinter(T entity, OutputStream out) throws IOException {
085        CSVPrinter printer;
086        if (out instanceof OutputStreamWithCSVWriter) {
087            OutputStreamWithCSVWriter oscsv = (OutputStreamWithCSVWriter) out;
088            if (oscsv.getCsvPrinter() != null) {
089                return oscsv.getCsvPrinter();
090            } else {
091                printer = new CSVPrinter(new StringBuilder(), CSVFormat.DEFAULT);
092                oscsv.setCSVPrinter(printer);
093            }
094        } else {
095            printer = new CSVPrinter(new OutputStreamWriter(out), CSVFormat.DEFAULT);
096        }
097        writeHeader(entity, printer);
098        return printer;
099    }
100
101    protected void printCalendar(Calendar value, CSVPrinter printer) throws IOException {
102        if (value != null) {
103            printer.print(((GregorianCalendar) value).toZonedDateTime());
104        } else {
105            printer.print(null);
106        }
107    }
108
109}