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 */
017package org.apache.camel.model.dataformat;
018
019import java.util.ArrayList;
020import java.util.List;
021import javax.xml.bind.annotation.XmlAccessType;
022import javax.xml.bind.annotation.XmlAccessorType;
023import javax.xml.bind.annotation.XmlAttribute;
024import javax.xml.bind.annotation.XmlElementRef;
025
026import org.apache.camel.CamelContext;
027import org.apache.camel.model.DataFormatDefinition;
028import org.apache.camel.spi.DataFormat;
029import org.apache.camel.spi.Metadata;
030
031/**
032 * Represents the common parts of all uniVocity {@link org.apache.camel.spi.DataFormat} parsers.
033 */
034@Metadata(label = "dataformat,transformation,csv", title = "uniVocity")
035@XmlAccessorType(XmlAccessType.FIELD)
036public abstract class UniVocityAbstractDataFormat extends DataFormatDefinition {
037
038    @XmlAttribute
039    protected String nullValue;
040    @XmlAttribute @Metadata(defaultValue = "true")
041    protected Boolean skipEmptyLines;
042    @XmlAttribute @Metadata(defaultValue = "true")
043    protected Boolean ignoreTrailingWhitespaces;
044    @XmlAttribute @Metadata(defaultValue = "true")
045    protected Boolean ignoreLeadingWhitespaces;
046    @XmlAttribute
047    protected Boolean headersDisabled;
048    @XmlElementRef
049    protected List<UniVocityHeader> headers;
050    @XmlAttribute
051    protected Boolean headerExtractionEnabled;
052    @XmlAttribute
053    protected Integer numberOfRecordsToRead;
054    @XmlAttribute
055    protected String emptyValue;
056    @XmlAttribute
057    protected String lineSeparator;
058    @XmlAttribute @Metadata(defaultValue = "\\n")
059    protected String normalizedLineSeparator;
060    @XmlAttribute @Metadata(defaultValue = "#")
061    protected String comment;
062    @XmlAttribute
063    protected Boolean lazyLoad;
064    @XmlAttribute
065    protected Boolean asMap;
066    
067    protected UniVocityAbstractDataFormat() {
068        // This constructor is needed by jaxb for schema generation
069    }
070
071    protected UniVocityAbstractDataFormat(String dataFormatName) {
072        super(dataFormatName);
073    }
074
075    public String getNullValue() {
076        return nullValue;
077    }
078
079    /**
080     * The string representation of a null value.
081     * <p/>
082     * The default value is null
083     */
084    public void setNullValue(String nullValue) {
085        this.nullValue = nullValue;
086    }
087
088    public Boolean getSkipEmptyLines() {
089        return skipEmptyLines;
090    }
091
092    /**
093     * Whether or not the empty lines must be ignored.
094     * <p/>
095     * The default value is true
096     */
097    public void setSkipEmptyLines(Boolean skipEmptyLines) {
098        this.skipEmptyLines = skipEmptyLines;
099    }
100
101    public Boolean getIgnoreTrailingWhitespaces() {
102        return ignoreTrailingWhitespaces;
103    }
104
105    /**
106     * Whether or not the trailing white spaces must ignored.
107     * <p/>
108     * The default value is true
109     */
110    public void setIgnoreTrailingWhitespaces(Boolean ignoreTrailingWhitespaces) {
111        this.ignoreTrailingWhitespaces = ignoreTrailingWhitespaces;
112    }
113
114    public Boolean getIgnoreLeadingWhitespaces() {
115        return ignoreLeadingWhitespaces;
116    }
117
118    /**
119     * Whether or not the leading white spaces must be ignored.
120     * <p/>
121     * The default value is true
122     */
123    public void setIgnoreLeadingWhitespaces(Boolean ignoreLeadingWhitespaces) {
124        this.ignoreLeadingWhitespaces = ignoreLeadingWhitespaces;
125    }
126
127    public Boolean getHeadersDisabled() {
128        return headersDisabled;
129    }
130
131    /**
132     * Whether or not the headers are disabled. When defined, this option explicitly sets the headers as null which indicates that there is no header.
133     * <p/>
134     * The default value is false
135     */
136    public void setHeadersDisabled(Boolean headersDisabled) {
137        this.headersDisabled = headersDisabled;
138    }
139
140    public List<UniVocityHeader> getHeaders() {
141        return headers;
142    }
143
144    /**
145     * The headers to use.
146     */
147    public void setHeaders(List<UniVocityHeader> headers) {
148        this.headers = headers;
149    }
150
151    public Boolean getHeaderExtractionEnabled() {
152        return headerExtractionEnabled;
153    }
154
155    /**
156     * Whether or not the header must be read in the first line of the test document
157     * <p/>
158     * The default value is false
159     */
160    public void setHeaderExtractionEnabled(Boolean headerExtractionEnabled) {
161        this.headerExtractionEnabled = headerExtractionEnabled;
162    }
163
164    public Integer getNumberOfRecordsToRead() {
165        return numberOfRecordsToRead;
166    }
167
168    /**
169     * The maximum number of record to read.
170     */
171    public void setNumberOfRecordsToRead(Integer numberOfRecordsToRead) {
172        this.numberOfRecordsToRead = numberOfRecordsToRead;
173    }
174
175    public String getEmptyValue() {
176        return emptyValue;
177    }
178
179    /**
180     * The String representation of an empty value
181     */
182    public void setEmptyValue(String emptyValue) {
183        this.emptyValue = emptyValue;
184    }
185
186    public String getLineSeparator() {
187        return lineSeparator;
188    }
189
190    /**
191     * The line separator of the files
192     * <p/>
193     * The default value is to use the JVM platform line separator
194     */
195    public void setLineSeparator(String lineSeparator) {
196        this.lineSeparator = lineSeparator;
197    }
198
199    public String getNormalizedLineSeparator() {
200        return normalizedLineSeparator;
201    }
202
203    /**
204     * The normalized line separator of the files
205     * <p/>
206     * The default value is a new line character.
207     */
208    public void setNormalizedLineSeparator(String normalizedLineSeparator) {
209        this.normalizedLineSeparator = normalizedLineSeparator;
210    }
211
212    public String getComment() {
213        return comment;
214    }
215
216    /**
217     * The comment symbol.
218     * <p/>
219     * The default value is #
220     */
221    public void setComment(String comment) {
222        this.comment = comment;
223    }
224
225    public Boolean getLazyLoad() {
226        return lazyLoad;
227    }
228
229    /**
230     * Whether the unmarshalling should produce an iterator that reads the lines on the fly or if all the lines must be read at one.
231     * <p/>
232     * The default value is false
233     */
234    public void setLazyLoad(Boolean lazyLoad) {
235        this.lazyLoad = lazyLoad;
236    }
237
238    public Boolean getAsMap() {
239        return asMap;
240    }
241
242    /**
243     * Whether the unmarshalling should produce maps for the lines values instead of lists.
244     * It requires to have header (either defined or collected).
245     * <p/>
246     * The default value is false
247     */
248    public void setAsMap(Boolean asMap) {
249        this.asMap = asMap;
250    }
251
252    @Override
253    protected void configureDataFormat(DataFormat dataFormat, CamelContext camelContext) {
254        super.configureDataFormat(dataFormat, camelContext);
255
256        if (nullValue != null) {
257            setProperty(camelContext, dataFormat, "nullValue", nullValue);
258        }
259        if (skipEmptyLines != null) {
260            setProperty(camelContext, dataFormat, "skipEmptyLines", skipEmptyLines);
261        }
262        if (ignoreTrailingWhitespaces != null) {
263            setProperty(camelContext, dataFormat, "ignoreTrailingWhitespaces", ignoreTrailingWhitespaces);
264        }
265        if (ignoreLeadingWhitespaces != null) {
266            setProperty(camelContext, dataFormat, "ignoreLeadingWhitespaces", ignoreLeadingWhitespaces);
267        }
268        if (headersDisabled != null) {
269            setProperty(camelContext, dataFormat, "headersDisabled", headersDisabled);
270        }
271        String[] validHeaderNames = getValidHeaderNames();
272        if (validHeaderNames != null) {
273            setProperty(camelContext, dataFormat, "headers", validHeaderNames);
274        }
275        if (headerExtractionEnabled != null) {
276            setProperty(camelContext, dataFormat, "headerExtractionEnabled", headerExtractionEnabled);
277        }
278        if (numberOfRecordsToRead != null) {
279            setProperty(camelContext, dataFormat, "numberOfRecordsToRead", numberOfRecordsToRead);
280        }
281        if (emptyValue != null) {
282            setProperty(camelContext, dataFormat, "emptyValue", emptyValue);
283        }
284        if (lineSeparator != null) {
285            setProperty(camelContext, dataFormat, "lineSeparator", lineSeparator);
286        }
287        if (normalizedLineSeparator != null) {
288            setProperty(camelContext, dataFormat, "normalizedLineSeparator", singleCharOf("normalizedLineSeparator", normalizedLineSeparator));
289        }
290        if (comment != null) {
291            setProperty(camelContext, dataFormat, "comment", singleCharOf("comment", comment));
292        }
293        if (lazyLoad != null) {
294            setProperty(camelContext, dataFormat, "lazyLoad", lazyLoad);
295        }
296        if (asMap != null) {
297            setProperty(camelContext, dataFormat, "asMap", asMap);
298        }
299    }
300
301    protected static Character singleCharOf(String attributeName, String string) {
302        if (string.length() != 1) {
303            throw new IllegalArgumentException("Only one character must be defined for " + attributeName);
304        }
305        return string.charAt(0);
306    }
307
308    /**
309     * Gets only the headers with non-null and non-empty names. It returns {@code null} if there's no such headers.
310     *
311     * @return The headers with non-null and non-empty names
312     */
313    private String[] getValidHeaderNames() {
314        if (headers == null) {
315            return null;
316        }
317        List<String> names = new ArrayList<String>(headers.size());
318        for (UniVocityHeader header : headers) {
319            if (header.getName() != null && !header.getName().isEmpty()) {
320                names.add(header.getName());
321            }
322        }
323        return names.isEmpty() ? null : names.toArray(new String[names.size()]);
324    }
325}