001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.camel.dataformat.csv;
018
019 import java.io.InputStream;
020 import java.io.InputStreamReader;
021 import java.io.OutputStream;
022 import java.io.OutputStreamWriter;
023 import java.io.Writer;
024 import java.util.ArrayList;
025 import java.util.Arrays;
026 import java.util.List;
027 import java.util.Map;
028 import java.util.Set;
029
030 import org.apache.camel.Exchange;
031 import org.apache.camel.spi.DataFormat;
032 import org.apache.camel.util.ExchangeHelper;
033 import org.apache.camel.util.ObjectHelper;
034 import org.apache.commons.csv.CSVParser;
035 import org.apache.commons.csv.CSVStrategy;
036 import org.apache.commons.csv.writer.CSVConfig;
037 import org.apache.commons.csv.writer.CSVField;
038 import org.apache.commons.csv.writer.CSVWriter;
039
040 /**
041 * CSV Data format.
042 * <p/>
043 * By default, columns are autogenerated in the resulting CSV. Subsequent
044 * messages use the previously created columns with new fields being added at
045 * the end of the line. Thus, field order is the same from message to message.
046 * Autogeneration can be disabled. In this case, only the fields defined in
047 * csvConfig are written on the output.
048 *
049 * @version $Revision: 15125 $
050 */
051 public class CsvDataFormat implements DataFormat {
052 private CSVStrategy strategy = CSVStrategy.DEFAULT_STRATEGY;
053 private CSVConfig config = new CSVConfig();
054 private boolean autogenColumns = true;
055
056 public void marshal(Exchange exchange, Object object, OutputStream outputStream) throws Exception {
057 ObjectHelper.notNull(config, "config");
058
059 OutputStreamWriter out = new OutputStreamWriter(outputStream);
060 CSVWriter csv = new CSVWriter(config);
061 csv.setWriter(out);
062
063 try {
064 List list = ExchangeHelper.convertToType(exchange, List.class, object);
065 if (list != null) {
066 for (Object child : list) {
067 Map row = ExchangeHelper.convertToMandatoryType(exchange, Map.class, child);
068 doMarshalRecord(exchange, row, out, csv);
069 }
070 } else {
071 Map row = ExchangeHelper.convertToMandatoryType(exchange, Map.class, object);
072 doMarshalRecord(exchange, row, out, csv);
073 }
074 } finally {
075 out.close();
076 }
077 }
078
079 private void doMarshalRecord(Exchange exchange, Map row, Writer out, CSVWriter csv) throws Exception {
080 if (autogenColumns) {
081 // no specific config has been set so lets add fields
082 Set set = row.keySet();
083 updateFieldsInConfig(set, exchange);
084 }
085 csv.writeRecord(row);
086 }
087
088 public Object unmarshal(Exchange exchange, InputStream inputStream) throws Exception {
089 InputStreamReader in = new InputStreamReader(inputStream);
090 try {
091 CSVParser parser = new CSVParser(in, getStrategy());
092 List<List<String>> list = new ArrayList<List<String>>();
093 while (true) {
094 String[] strings = parser.getLine();
095 if (strings == null) {
096 break;
097 }
098 List<String> line = Arrays.asList(strings);
099 list.add(line);
100 }
101 if (list.size() == 1) {
102 return list.get(0);
103 } else {
104 return list;
105 }
106 } finally {
107 in.close();
108 }
109 }
110
111 public void setConfig(CSVConfig config) {
112 this.config = config;
113 }
114
115 public CSVStrategy getStrategy() {
116 return strategy;
117 }
118
119 public void setStrategy(CSVStrategy strategy) {
120 this.strategy = strategy;
121 }
122
123 public boolean isAutogenColumns() {
124 return autogenColumns;
125 }
126
127 /**
128 * Auto generate columns.
129 *
130 * @param autogenColumns set to false to disallow column autogeneration (default true)
131 */
132 public void setAutogenColumns(boolean autogenColumns) {
133 this.autogenColumns = autogenColumns;
134 }
135
136 protected CSVConfig createConfig() {
137 return new CSVConfig();
138 }
139
140 private synchronized void updateFieldsInConfig(Set set, Exchange exchange) {
141 for (Object value : set) {
142 if (value != null) {
143 String text = exchange.getContext().getTypeConverter().convertTo(String.class, value);
144 // do not add field twice
145 if (config.getField(text) == null) {
146 CSVField field = new CSVField(text);
147 config.addField(field);
148 }
149 }
150 }
151 }
152
153 }