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