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.commons.csv.CSVParser;
034 import org.apache.commons.csv.CSVStrategy;
035 import org.apache.commons.csv.writer.CSVConfig;
036 import org.apache.commons.csv.writer.CSVField;
037 import org.apache.commons.csv.writer.CSVWriter;
038
039 /**
040 * CSV Data format.
041 * <p/>
042 * By default, columns are autogenerated in the resulting CSV. Subsequent
043 * messages use the previously created columns with new fields being added at
044 * the end of the line. Thus, field order is the same from message to message.
045 * Autogeneration can be disabled. In this case, only the fields defined in
046 * csvConfig are written on the output.
047 *
048 * @version $Revision: 20034 $
049 */
050 public class CsvDataFormat implements DataFormat {
051 private CSVStrategy strategy = CSVStrategy.DEFAULT_STRATEGY;
052 private CSVConfig config = new CSVConfig();
053 private boolean autogenColumns = true;
054 private String delimiter;
055
056 public void marshal(Exchange exchange, Object object, OutputStream outputStream) throws Exception {
057 if (delimiter != null) {
058 config.setDelimiter(delimiter.charAt(0));
059 }
060
061 OutputStreamWriter out = new OutputStreamWriter(outputStream);
062 CSVWriter csv = new CSVWriter(config);
063 csv.setWriter(out);
064
065 try {
066 List list = ExchangeHelper.convertToType(exchange, List.class, object);
067 if (list != null) {
068 for (Object child : list) {
069 Map row = ExchangeHelper.convertToMandatoryType(exchange, Map.class, child);
070 doMarshalRecord(exchange, row, out, csv);
071 }
072 } else {
073 Map row = ExchangeHelper.convertToMandatoryType(exchange, Map.class, object);
074 doMarshalRecord(exchange, row, out, csv);
075 }
076 } finally {
077 out.close();
078 }
079 }
080
081 private void doMarshalRecord(Exchange exchange, Map row, Writer out, CSVWriter csv) throws Exception {
082 if (autogenColumns) {
083 // no specific config has been set so lets add fields
084 Set set = row.keySet();
085 updateFieldsInConfig(set, exchange);
086 }
087 csv.writeRecord(row);
088 }
089
090 public Object unmarshal(Exchange exchange, InputStream inputStream) throws Exception {
091 InputStreamReader in = new InputStreamReader(inputStream);
092 if (delimiter != null) {
093 strategy.setDelimiter(delimiter.charAt(0));
094 }
095
096 try {
097 CSVParser parser = new CSVParser(in, strategy);
098 List<List<String>> list = new ArrayList<List<String>>();
099 while (true) {
100 String[] strings = parser.getLine();
101 if (strings == null) {
102 break;
103 }
104 List<String> line = Arrays.asList(strings);
105 list.add(line);
106 }
107 if (list.size() == 1) {
108 return list.get(0);
109 } else {
110 return list;
111 }
112 } finally {
113 in.close();
114 }
115 }
116
117 public String getDelimiter() {
118 return delimiter;
119 }
120
121 public void setDelimiter(String delimiter) {
122 if (delimiter != null && delimiter.length() > 1) {
123 throw new IllegalArgumentException("Delimiter must have a length of one!");
124 }
125 this.delimiter = delimiter;
126 }
127
128 public CSVConfig getConfig() {
129 return config;
130 }
131
132 public void setConfig(CSVConfig config) {
133 this.config = config;
134 }
135
136 public CSVStrategy getStrategy() {
137 return strategy;
138 }
139
140 public void setStrategy(CSVStrategy strategy) {
141 this.strategy = strategy;
142 }
143
144 public boolean isAutogenColumns() {
145 return autogenColumns;
146 }
147
148 /**
149 * Auto generate columns.
150 *
151 * @param autogenColumns set to false to disallow column autogeneration (default true)
152 */
153 public void setAutogenColumns(boolean autogenColumns) {
154 this.autogenColumns = autogenColumns;
155 }
156
157 private synchronized void updateFieldsInConfig(Set set, Exchange exchange) {
158 for (Object value : set) {
159 if (value != null) {
160 String text = exchange.getContext().getTypeConverter().convertTo(String.class, value);
161 // do not add field twice
162 if (config.getField(text) == null) {
163 CSVField field = new CSVField(text);
164 config.addField(field);
165 }
166 }
167 }
168 }
169
170 }