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