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.component.flatpack;
018
019 import java.io.IOException;
020 import java.io.InputStream;
021 import java.io.InputStreamReader;
022 import java.io.OutputStream;
023 import java.io.OutputStreamWriter;
024 import java.io.Reader;
025 import java.util.List;
026 import java.util.Map;
027
028 import net.sf.flatpack.DataSet;
029 import net.sf.flatpack.DefaultParserFactory;
030 import net.sf.flatpack.Parser;
031 import net.sf.flatpack.ParserFactory;
032 import net.sf.flatpack.writer.DelimiterWriterFactory;
033 import net.sf.flatpack.writer.FixedWriterFactory;
034 import net.sf.flatpack.writer.Writer;
035 import org.apache.camel.Exchange;
036 import org.apache.camel.converter.IOConverter;
037 import org.apache.camel.spi.DataFormat;
038 import org.apache.camel.util.ObjectHelper;
039 import org.apache.commons.logging.Log;
040 import org.apache.commons.logging.LogFactory;
041 import org.jdom.JDOMException;
042 import org.springframework.core.io.Resource;
043
044 /**
045 * Flatpack DataFormat.
046 * <p/>
047 * This data format supports two operations:
048 * <ul>
049 * <li>marshal = from <tt>List<Map<String, Object>></tt> to <tt>OutputStream</tt> (can be converted to String)</li>
050 * <li>unmarshal = from <tt>InputStream</tt> (such as a File) to {@link DataSetList}.
051 * </ul>
052 * <b>Notice:</b> The Flatpack library does currently not support header and trailers for the marshal operation.
053 *
054 * @version $Revision: 22872 $
055 */
056 public class FlatpackDataFormat implements DataFormat {
057 private static final transient Log LOG = LogFactory.getLog(FlatpackDataFormat.class);
058 private ParserFactory parserFactory = DefaultParserFactory.getInstance();
059 private char delimiter = ',';
060 private char textQualifier = '"';
061 private boolean ignoreFirstRecord = true;
062 private Resource definition;
063 private boolean fixed;
064
065 @SuppressWarnings("unchecked")
066 public void marshal(Exchange exchange, Object graph, OutputStream stream) throws Exception {
067 ObjectHelper.notNull(graph, "The object to marshal must be provided");
068
069 List<Map<String, Object>> data = (List<Map<String, Object>>) graph;
070 if (data.isEmpty()) {
071 LOG.warn("No data to marshal as the list is empty");
072 return;
073 }
074 Map<String, Object> firstRow = data.get(0);
075
076 Writer writer = createWriter(exchange, firstRow, stream);
077 try {
078 boolean first = true;
079 writer.printHeader();
080 for (Map<String, Object> row : data) {
081 if (ignoreFirstRecord && first) {
082 // skip first row
083 first = false;
084 continue;
085 }
086 for (String key : row.keySet()) {
087 writer.addRecordEntry(key, row.get(key));
088 }
089 writer.nextRecord();
090 }
091 writer.printFooter();
092 } finally {
093 writer.flush();
094 writer.close();
095 }
096 }
097
098 public Object unmarshal(Exchange exchange, InputStream stream) throws Exception {
099 InputStreamReader reader = new InputStreamReader(stream, IOConverter.getCharsetName(exchange));
100 try {
101 Parser parser = createParser(exchange, reader);
102 DataSet dataSet = parser.parse();
103 return new DataSetList(dataSet);
104 } finally {
105 reader.close();
106 }
107 }
108
109 // Properties
110 //-------------------------------------------------------------------------
111
112 public boolean isFixed() {
113 return fixed;
114 }
115
116 public void setFixed(boolean fixed) {
117 this.fixed = fixed;
118 }
119
120 public char getDelimiter() {
121 return delimiter;
122 }
123
124 public void setDelimiter(char delimiter) {
125 this.delimiter = delimiter;
126 }
127
128 public boolean isIgnoreFirstRecord() {
129 return ignoreFirstRecord;
130 }
131
132 public void setIgnoreFirstRecord(boolean ignoreFirstRecord) {
133 this.ignoreFirstRecord = ignoreFirstRecord;
134 }
135
136 public char getTextQualifier() {
137 return textQualifier;
138 }
139
140 public void setTextQualifier(char textQualifier) {
141 this.textQualifier = textQualifier;
142 }
143
144 public Resource getDefinition() {
145 return definition;
146 }
147
148 public void setDefinition(Resource definition) {
149 this.definition = definition;
150 }
151
152 public ParserFactory getParserFactory() {
153 return parserFactory;
154 }
155
156 public void setParserFactory(ParserFactory parserFactory) {
157 this.parserFactory = parserFactory;
158 }
159
160 // Implementation methods
161 //-------------------------------------------------------------------------
162
163 protected Parser createParser(Exchange exchange, Reader bodyReader) throws IOException {
164 if (isFixed()) {
165 Resource resource = getDefinition();
166 ObjectHelper.notNull(resource, "resource");
167 return getParserFactory().newFixedLengthParser(new InputStreamReader(resource.getInputStream(), IOConverter.getCharsetName(exchange)), bodyReader);
168 } else {
169 Resource resource = getDefinition();
170 if (resource == null) {
171 return getParserFactory().newDelimitedParser(bodyReader, delimiter, textQualifier);
172 } else {
173 return getParserFactory().newDelimitedParser(new InputStreamReader(resource.getInputStream(), IOConverter.getCharsetName(exchange)),
174 bodyReader, delimiter, textQualifier, ignoreFirstRecord);
175 }
176 }
177 }
178
179 private Writer createWriter(Exchange exchange, Map<String, Object> firstRow, OutputStream stream) throws JDOMException, IOException {
180 if (isFixed()) {
181 Resource resource = getDefinition();
182 ObjectHelper.notNull(resource, "resource");
183 FixedWriterFactory factory = new FixedWriterFactory(new InputStreamReader(resource.getInputStream(), IOConverter.getCharsetName(exchange)));
184 return factory.createWriter(new OutputStreamWriter(stream, IOConverter.getCharsetName(exchange)));
185 } else {
186 Resource resource = getDefinition();
187 if (resource == null) {
188 DelimiterWriterFactory factory = new DelimiterWriterFactory(delimiter, textQualifier);
189 // add coulmns from the keys in the data map as the columns must be known
190 for (String key : firstRow.keySet()) {
191 factory.addColumnTitle(key);
192 }
193 return factory.createWriter(new OutputStreamWriter(stream, IOConverter.getCharsetName(exchange)));
194 } else {
195 DelimiterWriterFactory factory = new DelimiterWriterFactory(new InputStreamReader(resource.getInputStream(), IOConverter.getCharsetName(exchange)), delimiter, textQualifier);
196 return factory.createWriter(new OutputStreamWriter(stream, IOConverter.getCharsetName(exchange)));
197 }
198 }
199 }
200 }