View Javadoc
1   /*
2    * (c) Copyright 2006-2020 by rapiddweller GmbH & Volker Bergmann. All rights reserved.
3    *
4    * Redistribution and use in source and binary forms, with or without
5    * modification, is permitted under the terms of the
6    * GNU General Public License.
7    *
8    * For redistributing this software or a derivative work under a license other
9    * than the GPL-compatible Free Software License as defined by the Free
10   * Software Foundation or approved by OSI, you must first obtain a commercial
11   * license to this software product from rapiddweller GmbH & Volker Bergmann.
12   *
13   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14   * WITHOUT A WARRANTY OF ANY KIND. ALL EXPRESS OR IMPLIED CONDITIONS,
15   * REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF
16   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE
17   * HEREBY EXCLUDED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24   * POSSIBILITY OF SUCH DAMAGE.
25   */
26  
27  package com.rapiddweller.platform.fixedwidth;
28  
29  import com.rapiddweller.benerator.InvalidGeneratorSetupException;
30  import com.rapiddweller.common.ArrayUtil;
31  import com.rapiddweller.common.Converter;
32  import com.rapiddweller.common.Escalator;
33  import com.rapiddweller.common.LoggerEscalator;
34  import com.rapiddweller.common.SystemInfo;
35  import com.rapiddweller.common.bean.ArrayPropertyExtractor;
36  import com.rapiddweller.common.converter.ArrayConverter;
37  import com.rapiddweller.common.converter.ConverterChain;
38  import com.rapiddweller.common.converter.NoOpConverter;
39  import com.rapiddweller.common.format.PadFormat;
40  import com.rapiddweller.format.DataIterator;
41  import com.rapiddweller.format.DataSource;
42  import com.rapiddweller.format.fixedwidth.FixedWidthColumnDescriptor;
43  import com.rapiddweller.format.fixedwidth.FixedWidthLineSource;
44  import com.rapiddweller.format.fixedwidth.FixedWidthRowTypeDescriptor;
45  import com.rapiddweller.format.fixedwidth.FixedWidthUtil;
46  import com.rapiddweller.format.util.ConvertingDataIterator;
47  import com.rapiddweller.model.data.ComplexTypeDescriptor;
48  import com.rapiddweller.model.data.Entity;
49  import com.rapiddweller.model.data.FileBasedEntitySource;
50  import com.rapiddweller.platform.array.Array2EntityConverter;
51  
52  import java.text.ParseException;
53  import java.util.Locale;
54  
55  /**
56   * Reads Entities from a fixed-width file.<br/>
57   * <br/>
58   * Created at 07.11.2008 18:18:24
59   *
60   * @author Volker Bergmann
61   * @since 0.5.6
62   */
63  public class FixedWidthEntitySource extends FileBasedEntitySource {
64  
65    private static final Escalator escalator = new LoggerEscalator();
66    /**
67     * The Source.
68     */
69    protected DataSource<String[]> source;
70    /**
71     * The Converter.
72     */
73    protected Converter<String[], Entity> converter;
74    private Locale locale;
75    private String encoding;
76    private String entityTypeName;
77    private ComplexTypeDescriptor entityDescriptor;
78    private FixedWidthColumnDescriptor[] descriptors;
79    private String lineFilter;
80    private final boolean initialized;
81    private final Converter<String, String> preprocessor;
82  
83    /**
84     * Instantiates a new Fixed width entity source.
85     */
86    public FixedWidthEntitySource() {
87      this(null, null, SystemInfo.getFileEncoding(), null);
88    }
89  
90    /**
91     * Instantiates a new Fixed width entity source.
92     *
93     * @param uri              the uri
94     * @param entityDescriptor the entity descriptor
95     * @param encoding         the encoding
96     * @param lineFilter       the line filter
97     * @param descriptors      the descriptors
98     */
99    public FixedWidthEntitySource(String uri, ComplexTypeDescriptor entityDescriptor,
100                                 String encoding, String lineFilter, FixedWidthColumnDescriptor... descriptors) {
101     this(uri, entityDescriptor, new NoOpConverter<>(), encoding, lineFilter, descriptors);
102   }
103 
104   /**
105    * Instantiates a new Fixed width entity source.
106    *
107    * @param uri              the uri
108    * @param entityDescriptor the entity descriptor
109    * @param preprocessor     the preprocessor
110    * @param encoding         the encoding
111    * @param lineFilter       the line filter
112    * @param descriptors      the descriptors
113    */
114   public FixedWidthEntitySource(String uri, ComplexTypeDescriptor entityDescriptor,
115                                 Converter<String, String> preprocessor, String encoding, String lineFilter,
116                                 FixedWidthColumnDescriptor... descriptors) {
117     super(uri);
118     this.locale = Locale.getDefault();
119     this.encoding = encoding;
120     this.entityDescriptor = entityDescriptor;
121     this.entityTypeName = (entityDescriptor != null ? entityDescriptor.getName() : null);
122     this.descriptors = descriptors;
123     this.preprocessor = preprocessor;
124     this.initialized = false;
125     this.lineFilter = lineFilter;
126   }
127 
128   // properties ------------------------------------------------------------------------------------------------------
129 
130   /**
131    * Sets locale.
132    *
133    * @param locale the locale
134    */
135   public void setLocale(Locale locale) {
136     this.locale = locale;
137   }
138 
139   /**
140    * Sets encoding.
141    *
142    * @param encoding the encoding
143    */
144   public void setEncoding(String encoding) {
145     this.encoding = encoding;
146   }
147 
148   /**
149    * Gets entity.
150    *
151    * @return the entity
152    */
153   public String getEntity() {
154     return entityTypeName;
155   }
156 
157   /**
158    * Sets entity.
159    *
160    * @param entity the entity
161    */
162   public void setEntity(String entity) {
163     this.entityTypeName = entity;
164   }
165 
166   /**
167    * Sets properties.
168    *
169    * @param properties the properties
170    * @throws ParseException if something went wrong while parsing
171    * @deprecated use {@link #setColumns(String)}
172    */
173   @Deprecated
174   public void setProperties(String properties) throws ParseException {
175     escalator.escalate("The property 'properties' of class " + getClass() + "' has been renamed to 'columns'. " +
176         "Please fix the property name in your configuration", this.getClass(), "setProperties()");
177     setColumns(properties);
178   }
179 
180   /**
181    * Sets columns.
182    *
183    * @param columns the columns
184    * @throws ParseException the parse exception
185    */
186   public void setColumns(String columns) throws ParseException {
187     FixedWidthRowTypeDescriptor rowTypeDescriptor = FixedWidthUtil.parseBeanColumnsSpec(
188         columns, entityTypeName, null, this.locale);
189     this.descriptors = rowTypeDescriptor.getColumnDescriptors();
190   }
191 
192   // Iterable interface ----------------------------------------------------------------------------------------------
193 
194   /**
195    * Sets line filter.
196    *
197    * @param lineFilter the line filter
198    */
199   public void setLineFilter(String lineFilter) {
200     this.lineFilter = lineFilter;
201   }
202 
203   @Override
204   public Class<Entity> getType() {
205     if (!initialized) {
206       init();
207     }
208     return Entity.class;
209   }
210 
211   @Override
212   public DataIterator<Entity> iterator() {
213     if (!initialized) {
214       init();
215     }
216     return new ConvertingDataIterator<>(this.source.iterator(), converter);
217   }
218 
219   // private helpers -------------------------------------------------------------------------------------------------
220 
221   private void init() {
222     if (this.entityDescriptor == null) {
223       this.entityDescriptor = new ComplexTypeDescriptor(entityTypeName, context.getLocalDescriptorProvider());
224     }
225     if (ArrayUtil.isEmpty(descriptors)) {
226       throw new InvalidGeneratorSetupException("Missing column descriptors. " +
227           "Use the 'columns' property of the " + getClass().getSimpleName() + " to define them.");
228     }
229     this.source = createSource();
230     this.converter = createConverter();
231   }
232 
233   private DataSource<String[]> createSource() {
234     PadFormat[] formats = ArrayPropertyExtractor.convert(descriptors, "format", PadFormat.class);
235     return new FixedWidthLineSource(resolveUri(), formats, true, encoding, lineFilter);
236   }
237 
238   @SuppressWarnings("unchecked")
239   private Converter<String[], Entity> createConverter() {
240     String[] featureNames = ArrayPropertyExtractor.convert(descriptors, "name", String.class);
241     Array2EntityConverterrter.html#Array2EntityConverter">Array2EntityConverter a2eConverter = new Array2EntityConverter(entityDescriptor, featureNames, true);
242     Converter<String[], String[]> aConv = new ArrayConverter<>(String.class, String.class, preprocessor);
243     return new ConverterChain<>(aConv, a2eConverter);
244   }
245 
246 }