1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.flatfile.dsl;
18
19 import java.io.InputStream;
20 import java.util.ArrayList;
21 import java.util.HashMap;
22 import java.util.Map;
23
24 import org.apache.commons.collections4.Transformer;
25 import org.apache.commons.flatfile.DynamicField;
26 import org.apache.commons.flatfile.Entity;
27 import org.apache.commons.flatfile.EntityFactory;
28 import org.apache.commons.flatfile.Field;
29 import org.apache.commons.flatfile.util.ApplyOptions;
30 import org.apache.commons.lang3.ObjectUtils;
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33 import org.apache.commons.pool.BasePoolableObjectFactory;
34 import org.apache.commons.pool.ObjectPool;
35 import org.apache.commons.pool.impl.StackObjectPool;
36
37 import antlr.TokenBuffer;
38 import antlr.collections.AST;
39
40
41
42
43
44 public class ParserEntityFactory implements EntityFactory {
45
46
47 public static final String OPTION_FIELD = "field";
48
49 public static final String OPTION_DYNAMIC_FIELD = "dynamicField";
50
51 private static final Log LOG = LogFactory.getLog(ParserEntityFactory.class);
52 private static final EntityNameStrategy DEFAULT_NAME_STRATEGY = new DefaultEntityNameStrategy();
53
54 private class EntityHolder {
55
56 private final EntityDefinition definition;
57 private Entity prototype;
58
59
60
61
62
63 EntityHolder(EntityDefinition definition) {
64 this.definition = definition;
65 }
66
67
68
69
70
71 Entity getPrototype() {
72 synchronized (this) {
73 if (prototype == null) {
74 prototype = doWithPooledTreeParser(new Transformer<EntityTreeParser, Entity>() {
75
76 public Entity transform(EntityTreeParser input) {
77 return input.createEntity(definition);
78 }
79 });
80 }
81 }
82 return prototype;
83 }
84 }
85
86 private EntityNameStrategy entityNameStrategy;
87 private Map<String, EntityHolder> entityMap;
88 private final Map<String, Map<String, ?>> defaultOptionMaps = new HashMap<String, Map<String, ?>>();
89 private boolean checked;
90 private InputStream[] sources;
91 private EntityFactory parent;
92
93 private final ObjectPool<EntityTreeParser> treeParserPool =
94 new StackObjectPool<EntityTreeParser>(new BasePoolableObjectFactory<EntityTreeParser>() {
95
96 @Override
97 public EntityTreeParser makeObject() throws Exception {
98 EntityTreeParser result = new EntityTreeParser();
99 result.setEntityFactory(ParserEntityFactory.this);
100 return result;
101 }
102 }, 1);
103
104
105
106
107 public ParserEntityFactory() {
108 }
109
110
111
112
113
114 public ParserEntityFactory(InputStream source) {
115 setSource(source);
116 }
117
118
119
120
121
122 public ParserEntityFactory(InputStream[] sources) {
123 setSources(sources);
124 }
125
126
127
128
129 public final Entity getEntity(Object cue) {
130 EntityHolder holder = getEntityMap().get(getEntityNameStrategy().getEntityName(cue));
131 if (holder != null) {
132 return holder.getPrototype().clone();
133 }
134 return getParent() == null ? null : getParent().getEntity(cue);
135 }
136
137
138
139
140 public final synchronized void validate() {
141 if (checked) {
142 return;
143 }
144 for (String name : getEntityMap().keySet()) {
145 getEntity(name);
146 }
147 }
148
149
150
151
152
153 public synchronized EntityNameStrategy getEntityNameStrategy() {
154 return entityNameStrategy == null ? DEFAULT_NAME_STRATEGY : entityNameStrategy;
155 }
156
157
158
159
160
161 public synchronized void setEntityNameStrategy(EntityNameStrategy entityNameStrategy) {
162 this.entityNameStrategy = entityNameStrategy;
163 }
164
165
166
167
168
169 public InputStream[] getSources() {
170 return sources;
171 }
172
173
174
175
176
177 public void setSources(InputStream[] sources) {
178 this.sources = sources;
179 }
180
181
182
183
184
185 public void setSource(InputStream source) {
186 setSources(new InputStream[] { source });
187 }
188
189
190
191
192
193 public EntityFactory getParent() {
194 return parent;
195 }
196
197
198
199
200
201 public void setParent(EntityFactory parent) {
202 this.parent = parent;
203 }
204
205
206
207
208
209
210 void add(String name, EntityDefinition def) {
211 entityMap.put(name, new EntityHolder(def));
212 }
213
214
215
216
217
218
219 void setDefaultOptions(String type, Map<String, ? extends Object> options) {
220 Map<String, ? extends Object> old = defaultOptionMaps.put(type, options);
221 if (!ObjectUtils.equals(old, options)) {
222 LOG.warn("Overriding " + type + " options");
223 }
224 }
225
226
227
228
229
230
231 Map<String, ? extends Object> getDefaultOptions(String type) {
232 return defaultOptionMaps.get(type);
233 }
234
235
236
237
238
239
240 Field createField(int length) {
241 return applyDefaultOptions(new Field(length), OPTION_FIELD);
242 }
243
244
245
246
247
248 DynamicField createDynamicField() {
249 return applyDefaultOptions(new DynamicField(), OPTION_DYNAMIC_FIELD);
250 }
251
252
253
254
255
256
257 Field createField(byte[] value) {
258 return applyDefaultOptions(new Field(value), OPTION_FIELD);
259 }
260
261
262
263
264
265
266
267
268 private <E extends Entity> E applyDefaultOptions(E e, String type) {
269 Map<String, ? extends Object> m = defaultOptionMaps.get(type);
270 return m == null ? e : ApplyOptions.apply(e, m);
271 }
272
273
274
275
276
277 private synchronized Map<String, EntityHolder> getEntityMap() {
278 if (entityMap == null) {
279 entityMap = new HashMap<String, EntityHolder>();
280 try {
281 EntityParser p = null;
282 final ArrayList<AST> trees = new ArrayList<AST>();
283 InputStream[] is = getSources();
284 for (InputStream element : is) {
285 TokenBuffer tb = new TokenBuffer(new EntityLexer(element));
286 if (p == null) {
287 p = new EntityParser(tb);
288 } else {
289 p.setTokenBuffer(tb);
290 }
291 p.parse();
292 trees.add(p.getAST());
293 }
294 doWithPooledTreeParser(new Transformer<EntityTreeParser, Void>() {
295
296 public Void transform(EntityTreeParser input) {
297 for (AST ast : trees) {
298 try {
299 input.load(ast);
300 } catch (Exception e) {
301 throw e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e);
302 }
303 }
304 return null;
305 }
306 });
307 } catch (Exception e) {
308 throw e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e);
309 }
310 }
311 return entityMap;
312 }
313
314
315
316
317
318
319
320 private <T> T doWithPooledTreeParser(Transformer<EntityTreeParser, T> xform) {
321 EntityTreeParser entityTreeParser;
322 try {
323 entityTreeParser = treeParserPool.borrowObject();
324 } catch (Exception e) {
325 throw e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e);
326 }
327 T result = xform.transform(entityTreeParser);
328 try {
329 treeParserPool.returnObject(entityTreeParser);
330 } catch (Exception e) {
331 LOG.error("Error returning EntityTreeParser to pool", e);
332 }
333 return result;
334 }
335 }