Csv.java

  1. /**
  2.  * Copyright (C) 2017 HttpBuilder-NG Project
  3.  *
  4.  * Licensed under the Apache License, Version 2.0 (the "License");
  5.  * you may not use this file except in compliance with the License.
  6.  * You may obtain a copy of the License at
  7.  *
  8.  *         http://www.apache.org/licenses/LICENSE-2.0
  9.  *
  10.  * Unless required by applicable law or agreed to in writing, software
  11.  * distributed under the License is distributed on an "AS IS" BASIS,
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13.  * See the License for the specific language governing permissions and
  14.  * limitations under the License.
  15.  */
  16. package groovyx.net.http.optional;

  17. import com.opencsv.CSVReader;
  18. import com.opencsv.CSVWriter;
  19. import groovyx.net.http.ChainedHttpConfig;
  20. import groovyx.net.http.FromServer;
  21. import groovyx.net.http.HttpConfig;
  22. import groovyx.net.http.ToServer;
  23. import groovyx.net.http.TransportingException;

  24. import java.io.IOException;
  25. import java.io.Reader;
  26. import java.io.StringWriter;
  27. import java.io.Writer;
  28. import java.util.function.BiConsumer;
  29. import java.util.function.BiFunction;
  30. import java.util.function.Supplier;

  31. import static groovyx.net.http.NativeHandlers.Encoders.*;

  32. /**
  33.  * Optional CSV encoder/parser implementation based on the [OpenCSV](http://opencsv.sourceforge.net/) library. It will be available when the OpenCsv
  34.  * library is on the classpath (an optional dependency).
  35.  */
  36. public class Csv {

  37.     public static final Supplier<BiConsumer<ChainedHttpConfig, ToServer>> encoderSupplier = () -> Csv::encode;
  38.     public static final Supplier<BiFunction<ChainedHttpConfig, FromServer, Object>> parserSupplier = () -> Csv::parse;

  39.     public static class Context {

  40.         public static final String ID = "3DOJ0FPjyD4GwLmpMjrCYnNJK60=";
  41.         public static final Context DEFAULT_CSV = new Context(',');
  42.         public static final Context DEFAULT_TSV = new Context('\t');

  43.         private final Character separator;
  44.         private final Character quoteChar;

  45.         public Context(final Character separator) {
  46.             this(separator, null);
  47.         }

  48.         public Context(final Character separator, final Character quoteChar) {
  49.             this.separator = separator;
  50.             this.quoteChar = quoteChar;
  51.         }

  52.         public char getSeparator() {
  53.             return separator;
  54.         }

  55.         public boolean hasQuoteChar() {
  56.             return quoteChar != null;
  57.         }

  58.         public char getQuoteChar() {
  59.             return quoteChar;
  60.         }

  61.         private CSVReader makeReader(final Reader reader) {
  62.             if (hasQuoteChar()) {
  63.                 return new CSVReader(reader, separator, quoteChar);
  64.             } else {
  65.                 return new CSVReader(reader, separator);
  66.             }
  67.         }

  68.         private CSVWriter makeWriter(final Writer writer) {
  69.             if (hasQuoteChar()) {
  70.                 return new CSVWriter(writer, separator, quoteChar);
  71.             } else {
  72.                 return new CSVWriter(writer, separator);
  73.             }
  74.         }
  75.     }

  76.     /**
  77.      * Used to parse the server response content using the OpenCsv parser.
  78.      *
  79.      * @param config the configuration
  80.      * @param fromServer the server content accessor
  81.      * @return the parsed object
  82.      */
  83.     public static Object parse(final ChainedHttpConfig config, final FromServer fromServer) {
  84.         try {
  85.             final Csv.Context ctx = (Csv.Context) config.actualContext(fromServer.getContentType(), Csv.Context.ID);
  86.             return ctx.makeReader(fromServer.getReader()).readAll();
  87.         } catch (IOException e) {
  88.             throw new TransportingException(e);
  89.         }
  90.     }

  91.     /**
  92.      * Used to encode the request content using the OpenCsv writer.
  93.      *
  94.      * @param config the configuration
  95.      * @param ts the server request content accessor
  96.      */
  97.     public static void encode(final ChainedHttpConfig config, final ToServer ts) {
  98.         if (handleRawUpload(config, ts)) {
  99.             return;
  100.         }

  101.         final ChainedHttpConfig.ChainedRequest request = config.getChainedRequest();
  102.         final Csv.Context ctx = (Csv.Context) config.actualContext(request.actualContentType(), Csv.Context.ID);
  103.         final Object body = checkNull(request.actualBody());
  104.         checkTypes(body, new Class[]{Iterable.class});
  105.         final StringWriter writer = new StringWriter();
  106.         final CSVWriter csvWriter = ctx.makeWriter(new StringWriter());

  107.         Iterable<?> iterable = (Iterable<?>) body;
  108.         for (Object o : iterable) {
  109.             csvWriter.writeNext((String[]) o);
  110.         }

  111.         ts.toServer(stringToStream(writer.toString(), request.actualCharset()));
  112.     }

  113.     /**
  114.      * Used to configure the OpenCsv encoder/parser in the configuration context for the specified content type.
  115.      *
  116.      * @param delegate the configuration object
  117.      * @param contentType the content type to be registered
  118.      * @param separator the CSV column separator character
  119.      * @param quote the CSV quote character
  120.      */
  121.     public static void toCsv(final HttpConfig delegate, final String contentType, final Character separator, final Character quote) {
  122.         delegate.context(contentType, Context.ID, new Context(separator, quote));
  123.         delegate.getRequest().encoder(contentType, Csv::encode);
  124.         delegate.getResponse().parser(contentType, Csv::parse);
  125.     }

  126.     /**
  127.      * Used to configure the OpenCsv encoder/parser in the configuration context for the `text/csv` content-type. No quote character will be provided.
  128.      *
  129.      * @param delegate the configuration object
  130.      * @param separator the CSV column separator character
  131.      */
  132.     public static void toCsv(final HttpConfig delegate, final char separator) {
  133.         toCsv(delegate, "text/csv", separator, null);
  134.     }

  135.     /**
  136.      * Used to configure the OpenCsv encoder/parser in the configuration context for the `text/csv` content-type.
  137.      *
  138.      * @param delegate the configuration object
  139.      * @param separator the CSV column separator character
  140.      * @param quote the CSV quote character
  141.      */
  142.     public static void toCsv(final HttpConfig delegate, final char separator, final char quote) {
  143.         toCsv(delegate, "text/csv", separator, quote);
  144.     }

  145.     /**
  146.      * Used to configure the OpenCsv encoder/parser in the configuration context for the `text/tab-separated-values` content type, with a tab as the
  147.      * column separator character.
  148.      *
  149.      * @param delegate the configuration object
  150.      * @param quote the quote character to be used
  151.      */
  152.     public static void toTsv(final HttpConfig delegate, final char quote) {
  153.         toCsv(delegate, "text/tab-separated-values", '\t', quote);
  154.     }
  155. }