001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.csv;
014
015import static org.apache.juneau.internal.CollectionUtils.*;
016
017import java.io.*;
018import java.lang.reflect.*;
019import java.nio.charset.*;
020import java.util.*;
021import java.util.function.*;
022import org.apache.juneau.*;
023import org.apache.juneau.httppart.*;
024import org.apache.juneau.internal.*;
025import org.apache.juneau.serializer.*;
026import org.apache.juneau.svl.*;
027
028/**
029 * Session object that lives for the duration of a single use of {@link CsvSerializer}.
030 *
031 * <h5 class='section'>Notes:</h5><ul>
032 *    <li class='warn'>This class is not thread safe and is typically discarded after one use.
033 * </ul>
034 *
035 * <h5 class='section'>See Also:</h5><ul>
036
037 * </ul>
038 */
039public final class CsvSerializerSession extends WriterSerializerSession {
040
041   //-----------------------------------------------------------------------------------------------------------------
042   // Static
043   //-----------------------------------------------------------------------------------------------------------------
044
045   /**
046    * Creates a new builder for this object.
047    *
048    * @param ctx The context creating this session.
049    * @return A new builder.
050    */
051   public static Builder create(CsvSerializer ctx) {
052      return new Builder(ctx);
053   }
054
055   //-----------------------------------------------------------------------------------------------------------------
056   // Builder
057   //-----------------------------------------------------------------------------------------------------------------
058
059   /**
060    * Builder class.
061    */
062   @FluentSetters
063   public static class Builder extends WriterSerializerSession.Builder {
064
065      CsvSerializer ctx;
066
067      /**
068       * Constructor
069       *
070       * @param ctx The context creating this session.
071       */
072      protected Builder(CsvSerializer ctx) {
073         super(ctx);
074         this.ctx = ctx;
075      }
076
077      @Override
078      public CsvSerializerSession build() {
079         return new CsvSerializerSession(this);
080      }
081
082      // <FluentSetters>
083
084      @Override /* GENERATED - org.apache.juneau.ContextSession.Builder */
085      public <T> Builder apply(Class<T> type, Consumer<T> apply) {
086         super.apply(type, apply);
087         return this;
088      }
089
090      @Override /* GENERATED - org.apache.juneau.ContextSession.Builder */
091      public Builder debug(Boolean value) {
092         super.debug(value);
093         return this;
094      }
095
096      @Override /* GENERATED - org.apache.juneau.ContextSession.Builder */
097      public Builder properties(Map<String,Object> value) {
098         super.properties(value);
099         return this;
100      }
101
102      @Override /* GENERATED - org.apache.juneau.ContextSession.Builder */
103      public Builder property(String key, Object value) {
104         super.property(key, value);
105         return this;
106      }
107
108      @Override /* GENERATED - org.apache.juneau.ContextSession.Builder */
109      public Builder unmodifiable() {
110         super.unmodifiable();
111         return this;
112      }
113
114      @Override /* GENERATED - org.apache.juneau.BeanSession.Builder */
115      public Builder locale(Locale value) {
116         super.locale(value);
117         return this;
118      }
119
120      @Override /* GENERATED - org.apache.juneau.BeanSession.Builder */
121      public Builder localeDefault(Locale value) {
122         super.localeDefault(value);
123         return this;
124      }
125
126      @Override /* GENERATED - org.apache.juneau.BeanSession.Builder */
127      public Builder mediaType(MediaType value) {
128         super.mediaType(value);
129         return this;
130      }
131
132      @Override /* GENERATED - org.apache.juneau.BeanSession.Builder */
133      public Builder mediaTypeDefault(MediaType value) {
134         super.mediaTypeDefault(value);
135         return this;
136      }
137
138      @Override /* GENERATED - org.apache.juneau.BeanSession.Builder */
139      public Builder timeZone(TimeZone value) {
140         super.timeZone(value);
141         return this;
142      }
143
144      @Override /* GENERATED - org.apache.juneau.BeanSession.Builder */
145      public Builder timeZoneDefault(TimeZone value) {
146         super.timeZoneDefault(value);
147         return this;
148      }
149
150      @Override /* GENERATED - org.apache.juneau.serializer.SerializerSession.Builder */
151      public Builder javaMethod(Method value) {
152         super.javaMethod(value);
153         return this;
154      }
155
156      @Override /* GENERATED - org.apache.juneau.serializer.SerializerSession.Builder */
157      public Builder resolver(VarResolverSession value) {
158         super.resolver(value);
159         return this;
160      }
161
162      @Override /* GENERATED - org.apache.juneau.serializer.SerializerSession.Builder */
163      public Builder schema(HttpPartSchema value) {
164         super.schema(value);
165         return this;
166      }
167
168      @Override /* GENERATED - org.apache.juneau.serializer.SerializerSession.Builder */
169      public Builder schemaDefault(HttpPartSchema value) {
170         super.schemaDefault(value);
171         return this;
172      }
173
174      @Override /* GENERATED - org.apache.juneau.serializer.SerializerSession.Builder */
175      public Builder uriContext(UriContext value) {
176         super.uriContext(value);
177         return this;
178      }
179
180      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializerSession.Builder */
181      public Builder fileCharset(Charset value) {
182         super.fileCharset(value);
183         return this;
184      }
185
186      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializerSession.Builder */
187      public Builder streamCharset(Charset value) {
188         super.streamCharset(value);
189         return this;
190      }
191
192      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializerSession.Builder */
193      public Builder useWhitespace(Boolean value) {
194         super.useWhitespace(value);
195         return this;
196      }
197
198      // </FluentSetters>
199   }
200
201   //-----------------------------------------------------------------------------------------------------------------
202   // Instance
203   //-----------------------------------------------------------------------------------------------------------------
204
205   /**
206    * Constructor.
207    *
208    * @param builder The builder for this object.
209    */
210   protected CsvSerializerSession(Builder builder) {
211      super(builder);
212   }
213
214   @SuppressWarnings("rawtypes")
215   @Override /* SerializerSession */
216   protected final void doSerialize(SerializerPipe pipe, Object o) throws IOException, SerializeException {
217
218      try (CsvWriter w = getCsvWriter(pipe)) {
219         ClassMeta<?> cm = getClassMetaForObject(o);
220         Collection<?> l = null;
221         if (cm.isArray()) {
222            l = alist((Object[])o);
223         } else if (cm.isCollection()) {
224            l = (Collection<?>)o;
225         } else {
226            l = Collections.singleton(o);
227         }
228
229         // TODO - Doesn't support DynaBeans.
230         if (l.size() > 0) {
231            ClassMeta<?> entryType = getClassMetaForObject(l.iterator().next());
232            if (entryType.isBean()) {
233               BeanMeta<?> bm = entryType.getBeanMeta();
234               Flag addComma = Flag.create();
235               bm.forEachProperty(x -> x.canRead(), x -> {
236                  addComma.ifSet(() -> w.w(',')).set();
237                  w.writeEntry(x.getName());
238               });
239               w.append('\n');
240               l.forEach(x -> {
241                  Flag addComma2 = Flag.create();
242                  BeanMap<?> bean = toBeanMap(x);
243                  bm.forEachProperty(y -> y.canRead(), y -> {
244                     addComma2.ifSet(() -> w.w(',')).set();
245                     w.writeEntry(y.get(bean, y.getName()));
246                  });
247                  w.w('\n');
248               });
249            } else if (entryType.isMap()) {
250               Flag addComma = Flag.create();
251               Map first = (Map)l.iterator().next();
252               first.keySet().forEach(x -> {
253                  addComma.ifSet(() -> w.w(',')).set();
254                  w.writeEntry(x);
255               });
256               w.append('\n');
257               l.stream().forEach(x -> {
258                  Flag addComma2 = Flag.create();
259                  Map map = (Map)x;
260                  map.values().forEach(y -> {
261                     addComma2.ifSet(() -> w.w(',')).set();
262                     w.writeEntry(y);
263                  });
264                  w.w('\n');
265               });
266            } else {
267               w.writeEntry("value");
268               w.append('\n');
269               l.stream().forEach(x -> {
270                  w.writeEntry(x);
271                  w.w('\n');
272               });
273            }
274         }
275      }
276   }
277
278   final CsvWriter getCsvWriter(SerializerPipe out) {
279      Object output = out.getRawOutput();
280      if (output instanceof CsvWriter)
281         return (CsvWriter)output;
282      CsvWriter w = new CsvWriter(out.getWriter(), isUseWhitespace(), getMaxIndent(), getQuoteChar(), isTrimStrings(), getUriResolver());
283      out.setWriter(w);
284      return w;
285   }
286}