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.util.ArrayList;
024    import java.util.Arrays;
025    import java.util.List;
026    import java.util.Map;
027    import java.util.Set;
028    
029    import org.apache.camel.Exchange;
030    import org.apache.camel.spi.DataFormat;
031    import org.apache.camel.util.ExchangeHelper;
032    import org.apache.camel.util.ObjectHelper;
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: 3239 $
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    
055        public void marshal(Exchange exchange, Object object, OutputStream outputStream) throws Exception {
056            ObjectHelper.notNull(config, "config");
057    
058            Map map = ExchangeHelper.convertToMandatoryType(exchange, Map.class, object);
059            OutputStreamWriter out = new OutputStreamWriter(outputStream);
060            try {
061                if (autogenColumns) {
062                    // no specific config has been set so lets add fields
063                    Set set = map.keySet();
064                    updateFieldsInConfig(set, exchange);
065                }
066                CSVWriter writer = new CSVWriter(config);
067                writer.setWriter(out);
068                writer.writeRecord(map);
069            } finally {
070                out.close();
071            }
072        }
073    
074        public Object unmarshal(Exchange exchange, InputStream inputStream) throws Exception {
075            InputStreamReader in = new InputStreamReader(inputStream);
076            try {
077                CSVParser parser = new CSVParser(in, getStrategy());
078                List<List<String>> list = new ArrayList<List<String>>();
079                while (true) {
080                    String[] strings = parser.getLine();
081                    if (strings == null) {
082                        break;
083                    }
084                    List<String> line = Arrays.asList(strings);
085                    list.add(line);
086                }
087                if (list.size() == 1) {
088                    return list.get(0);
089                } else {
090                    return list;
091                }
092            } finally {
093                in.close();
094            }
095        }
096    
097        public void setConfig(CSVConfig config) {
098            this.config = config;
099        }
100    
101        public CSVStrategy getStrategy() {
102            return strategy;
103        }
104    
105        public void setStrategy(CSVStrategy strategy) {
106            this.strategy = strategy;
107        }
108    
109        public boolean isAutogenColumns() {
110            return autogenColumns;
111        }
112    
113        /**
114         * Auto generate columns.
115         *
116         * @param autogenColumns set to false to disallow column autogeneration (default true)
117         */
118        public void setAutogenColumns(boolean autogenColumns) {
119            this.autogenColumns = autogenColumns;
120        }
121    
122        protected CSVConfig createConfig() {
123            return new CSVConfig();
124        }
125    
126        private synchronized void updateFieldsInConfig(Set set, Exchange exchange) {
127            for (Object value : set) {
128                if (value != null) {
129                    String text = exchange.getContext().getTypeConverter().convertTo(String.class, value);
130                    // do not add field twice
131                    if (config.getField(text) == null) {
132                        CSVField field = new CSVField(text);
133                        config.addField(field);
134                    }
135                }
136            }
137        }
138    
139    }