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 java.io.*;
016import java.util.*;
017
018import org.apache.juneau.*;
019import org.apache.juneau.serializer.*;
020
021/**
022 * Session object that lives for the duration of a single use of {@link CsvSerializer}.
023 *
024 * <p>
025 * This class is NOT thread safe.
026 * It is typically discarded after one-time use although it can be reused within the same thread.
027 */
028public final class CsvSerializerSession extends WriterSerializerSession {
029
030   /**
031    * Create a new session using properties specified in the context.
032    *
033    * @param ctx
034    *    The context creating this session object.
035    *    The context contains all the configuration settings for this object.
036    * @param args
037    *    Runtime arguments.
038    *    These specify session-level information such as locale and URI context.
039    *    It also include session-level properties that override the properties defined on the bean and
040    *    serializer contexts.
041    */
042   protected CsvSerializerSession(CsvSerializer ctx, SerializerSessionArgs args) {
043      super(ctx, args);
044   }
045
046   @Override /* SerializerSession */
047   protected final void doSerialize(SerializerPipe pipe, Object o) throws Exception {
048      try (Writer w = pipe.getWriter()) {
049         ClassMeta<?> cm = getClassMetaForObject(o);
050         Collection<?> l = null;
051         if (cm.isArray()) {
052            l = Arrays.asList((Object[])o);
053         } else {
054            l = (Collection<?>)o;
055         }
056         // TODO - Doesn't support DynaBeans.
057         if (l.size() > 0) {
058            ClassMeta<?> entryType = getClassMetaForObject(l.iterator().next());
059            if (entryType.isBean()) {
060               BeanMeta<?> bm = entryType.getBeanMeta();
061               int i = 0;
062               for (BeanPropertyMeta pm : bm.getPropertyMetas()) {
063                  if (pm.canRead()) {
064                     if (i++ > 0)
065                        w.append(',');
066                     append(w, pm.getName());
067                  }
068               }
069               w.append('\n');
070               for (Object o2 : l) {
071                  i = 0;
072                  BeanMap<?> bean = toBeanMap(o2);
073                  for (BeanPropertyMeta pm : bm.getPropertyMetas()) {
074                     if (pm.canRead()) {
075                        if (i++ > 0)
076                           w.append(',');
077                        append(w, pm.get(bean, pm.getName()));
078                     }
079                  }
080                  w.append('\n');
081               }
082            }
083         }
084      }
085   }
086
087   private static void append(Writer w, Object o) throws IOException {
088      if (o == null)
089         w.append("null");
090      else {
091         String s = o.toString();
092         boolean mustQuote = false;
093         for (int i = 0; i < s.length() && ! mustQuote; i++) {
094            char c = s.charAt(i);
095            if (Character.isWhitespace(c) || c == ',')
096               mustQuote = true;
097         }
098         if (mustQuote)
099            w.append('"').append(s).append('"');
100         else
101            w.append(s);
102      }
103   }
104}