|
1 |
| |
|
2 |
| package org.objectledge.pico.xml; |
|
3 |
| |
|
4 |
| import java.lang.reflect.Constructor; |
|
5 |
| import java.util.ArrayList; |
|
6 |
| import java.util.EnumSet; |
|
7 |
| import java.util.HashMap; |
|
8 |
| import java.util.LinkedList; |
|
9 |
| import java.util.List; |
|
10 |
| import java.util.Map; |
|
11 |
| import java.util.Set; |
|
12 |
| |
|
13 |
| import org.objectledge.pico.AliasComponentAdapter; |
|
14 |
| import org.objectledge.pico.SequenceParameter; |
|
15 |
| import org.objectledge.pico.StringParameter; |
|
16 |
| import org.objectledge.pico.customization.CustomizingComponentParameter; |
|
17 |
| import org.picocontainer.ComponentAdapter; |
|
18 |
| import org.picocontainer.MutablePicoContainer; |
|
19 |
| import org.picocontainer.Parameter; |
|
20 |
| import org.picocontainer.PicoContainer; |
|
21 |
| import org.picocontainer.defaults.ComponentAdapterFactory; |
|
22 |
| import org.picocontainer.defaults.DefaultComponentAdapterFactory; |
|
23 |
| import org.picocontainer.defaults.DefaultPicoContainer; |
|
24 |
| import org.xml.sax.Attributes; |
|
25 |
| import org.xml.sax.Locator; |
|
26 |
| import org.xml.sax.SAXException; |
|
27 |
| import org.xml.sax.SAXParseException; |
|
28 |
| import org.xml.sax.helpers.DefaultHandler; |
|
29 |
| |
|
30 |
| |
|
31 |
| |
|
32 |
| |
|
33 |
| class CompositionContentHandler extends DefaultHandler |
|
34 |
| { |
|
35 |
| private static final Class[] NO_ARG = new Class[] { }; |
|
36 |
| private static final Class[] PICOCONTAINER_ARGS = new Class[] { ComponentAdapterFactory.class, |
|
37 |
| PicoContainer.class }; |
|
38 |
| private static final Class[] COMPONENT_ADAPTER_FACTORY_ARG = |
|
39 |
| new Class[] { ComponentAdapterFactory.class }; |
|
40 |
| private static final Class DEFAULT_CONTAINER_IMPL = DefaultPicoContainer.class; |
|
41 |
| private static final Parameter[] NO_PARAMETERS = new Parameter[] { }; |
|
42 |
| |
|
43 |
| private final PicoContainer topLevelParentContainer; |
|
44 |
| private final ClassLoader classLoader; |
|
45 |
| |
|
46 |
| private PicoContainer result; |
|
47 |
| |
|
48 |
| private final LinkedList<State> stateStack = |
|
49 |
| new LinkedList<State>(); |
|
50 |
| private final LinkedList<MutablePicoContainer> containerStack = |
|
51 |
| new LinkedList<MutablePicoContainer>(); |
|
52 |
| private final LinkedList<ComponentAdapterFactory> factoryStack = |
|
53 |
| new LinkedList<ComponentAdapterFactory>(); |
|
54 |
| private final LinkedList<ComponentInfo> componentStack = |
|
55 |
| new LinkedList<ComponentInfo>(); |
|
56 |
| private final LinkedList<SequenceInfo> sequenceStack = |
|
57 |
| new LinkedList<SequenceInfo>(); |
|
58 |
| private Locator locator; |
|
59 |
| |
|
60 |
| |
|
61 |
| |
|
62 |
| |
|
63 |
| |
|
64 |
| |
|
65 |
| |
|
66 |
1204
| public CompositionContentHandler(final PicoContainer parentContainer,
|
|
67 |
| final ClassLoader classLoader, final Object assemblyScope) |
|
68 |
| { |
|
69 |
1204
| this.topLevelParentContainer = parentContainer;
|
|
70 |
1204
| this.classLoader = classLoader;
|
|
71 |
| |
|
72 |
1204
| stateStack.add(State.TOP);
|
|
73 |
1204
| ComponentAdapterFactory factory = (ComponentAdapterFactory)parentContainer.
|
|
74 |
| getComponentInstance(ComponentAdapterFactory.class); |
|
75 |
1204
| if(factory == null)
|
|
76 |
| { |
|
77 |
1032
| factory = new DefaultComponentAdapterFactory();
|
|
78 |
| } |
|
79 |
1204
| factoryStack.add(factory);
|
|
80 |
| } |
|
81 |
| |
|
82 |
| |
|
83 |
| |
|
84 |
| |
|
85 |
| |
|
86 |
| |
|
87 |
946
| public PicoContainer getResult()
|
|
88 |
| { |
|
89 |
946
| return result;
|
|
90 |
| } |
|
91 |
| |
|
92 |
| |
|
93 |
| |
|
94 |
| |
|
95 |
| |
|
96 |
| |
|
97 |
14448
| public void startElement(String uri, String localName, String qName, Attributes attributes)
|
|
98 |
| throws SAXException |
|
99 |
| { |
|
100 |
14448
| State current = stateStack.getLast();
|
|
101 |
14448
| State target = State.fromTag(localName);
|
|
102 |
14448
| if(target == null)
|
|
103 |
| { |
|
104 |
0
| throw new SAXParseException("unknown tag " + localName, locator);
|
|
105 |
| } |
|
106 |
14448
| if(State.allowedTransition(current, target))
|
|
107 |
| { |
|
108 |
14448
| target.start(this, attributes);
|
|
109 |
14448
| stateStack.add(target);
|
|
110 |
| } |
|
111 |
| else |
|
112 |
| { |
|
113 |
0
| throw new SAXParseException("unexpected opening tag " + target.getTag() + " inside " +
|
|
114 |
| current.getTag(), locator); |
|
115 |
| } |
|
116 |
| } |
|
117 |
| |
|
118 |
| |
|
119 |
| |
|
120 |
| |
|
121 |
14448
| public void endElement(String uri, String localName, String qName)
|
|
122 |
| throws SAXException |
|
123 |
| { |
|
124 |
14448
| State current = stateStack.removeLast();
|
|
125 |
14448
| if(State.fromTag(localName).equals(current))
|
|
126 |
| { |
|
127 |
14448
| current.end(this);
|
|
128 |
| } |
|
129 |
| else |
|
130 |
| { |
|
131 |
0
| throw new SAXParseException("expecting closing tag " + current.getTag(), locator);
|
|
132 |
| } |
|
133 |
| } |
|
134 |
| |
|
135 |
| |
|
136 |
| |
|
137 |
| |
|
138 |
1204
| public void setDocumentLocator(final Locator locator)
|
|
139 |
| { |
|
140 |
1204
| this.locator = locator;
|
|
141 |
| } |
|
142 |
| |
|
143 |
| |
|
144 |
| |
|
145 |
1462
| void startContainer(Attributes attributes)
|
|
146 |
| throws SAXException |
|
147 |
| { |
|
148 |
1462
| if(result != null)
|
|
149 |
| { |
|
150 |
0
| throw new SAXParseException("top level container already defined", locator);
|
|
151 |
| } |
|
152 |
1462
| MutablePicoContainer container;
|
|
153 |
1462
| if(containerStack.isEmpty())
|
|
154 |
| { |
|
155 |
1204
| container = makeContainer(topLevelParentContainer, factoryStack.getLast(), attributes);
|
|
156 |
| } |
|
157 |
| else |
|
158 |
| { |
|
159 |
258
| container = makeContainer(containerStack.getLast(), factoryStack.getLast(), attributes);
|
|
160 |
258
| containerStack.getLast().addChildContainer(container);
|
|
161 |
258
| Object key = makeKey(attributes, false);
|
|
162 |
258
| if(key != null)
|
|
163 |
| { |
|
164 |
172
| containerStack.getLast().registerComponentInstance(key, container);
|
|
165 |
| } |
|
166 |
| } |
|
167 |
1462
| containerStack.add(container);
|
|
168 |
| } |
|
169 |
| |
|
170 |
1462
| void endContainer()
|
|
171 |
| throws SAXException |
|
172 |
| { |
|
173 |
1462
| PicoContainer container = containerStack.removeLast();
|
|
174 |
1462
| if(containerStack.isEmpty())
|
|
175 |
| { |
|
176 |
1204
| result = container;
|
|
177 |
| } |
|
178 |
| } |
|
179 |
| |
|
180 |
688
| void startFactory(Attributes attributes) throws SAXException
|
|
181 |
| { |
|
182 |
688
| Object key = makeKey(attributes, false);
|
|
183 |
688
| Object factory = containerStack.getLast().getComponentInstance(key);
|
|
184 |
688
| if(factory == null)
|
|
185 |
| { |
|
186 |
0
| new SAXParseException("component "+key+" not found", locator);
|
|
187 |
| } |
|
188 |
688
| if(ComponentAdapterFactory.class.isAssignableFrom(factory.getClass()))
|
|
189 |
| { |
|
190 |
688
| new SAXParseException(factory.getClass() + " does not implement " +
|
|
191 |
| ComponentAdapterFactory.class, locator); |
|
192 |
| } |
|
193 |
688
| factoryStack.add((ComponentAdapterFactory)factory);
|
|
194 |
| } |
|
195 |
| |
|
196 |
688
| void endFactory()
|
|
197 |
| throws SAXException |
|
198 |
| { |
|
199 |
688
| factoryStack.removeLast();
|
|
200 |
| } |
|
201 |
| |
|
202 |
5762
| void startComponent(Attributes attributes)
|
|
203 |
| throws SAXException |
|
204 |
| { |
|
205 |
5762
| Object key = makeKey(attributes, true);
|
|
206 |
5762
| Class implClass = loadClass(attributes, null);
|
|
207 |
5762
| if(implClass == null)
|
|
208 |
| { |
|
209 |
0
| throw new SAXParseException("missing class attribute", locator);
|
|
210 |
| } |
|
211 |
5762
| componentStack.add(new ComponentInfo(key, implClass));
|
|
212 |
| } |
|
213 |
| |
|
214 |
5762
| void endComponent()
|
|
215 |
| throws SAXException |
|
216 |
| { |
|
217 |
5762
| ComponentInfo info = componentStack.removeLast();
|
|
218 |
5762
| ComponentAdapter adapter = info.makeAdapter(factoryStack.getLast());
|
|
219 |
5762
| if(ComponentAdapter.class.isAssignableFrom(adapter.getComponentImplementation()))
|
|
220 |
| { |
|
221 |
344
| adapter = (ComponentAdapter)adapter.getComponentInstance(containerStack.getLast());
|
|
222 |
| } |
|
223 |
5762
| containerStack.getLast().registerComponent(adapter);
|
|
224 |
5762
| int i = stateStack.size() - 1;
|
|
225 |
5762
| while(true)
|
|
226 |
| { |
|
227 |
6278
| switch(stateStack.get(i))
|
|
228 |
| { |
|
229 |
516
| case FACTORY:
|
|
230 |
516
| i--;
|
|
231 |
516
| continue;
|
|
232 |
4902
| case CONTAINER:
|
|
233 |
4902
| break;
|
|
234 |
344
| case COMPONENT:
|
|
235 |
344
| componentStack.getLast().addParameter(makeComponentParameter(info.getKey()));
|
|
236 |
344
| break;
|
|
237 |
516
| case SEQUENCE:
|
|
238 |
516
| sequenceStack.getLast().addParameter(makeComponentParameter(info.getKey()));
|
|
239 |
516
| break;
|
|
240 |
0
| default:
|
|
241 |
0
| throw new SAXParseException("unexpected tag parent tag " +
|
|
242 |
| stateStack.get(i).getTag(), locator); |
|
243 |
| } |
|
244 |
5762
| return;
|
|
245 |
| } |
|
246 |
| } |
|
247 |
| |
|
248 |
5590
| void startParameter(Attributes attributes)
|
|
249 |
| throws SAXException |
|
250 |
| { |
|
251 |
5590
| Parameter parameter;
|
|
252 |
5590
| String value = attributes.getValue("value");
|
|
253 |
5590
| if(value != null)
|
|
254 |
| { |
|
255 |
3440
| Class valueClass = loadClass(attributes, null);
|
|
256 |
3440
| parameter = new StringParameter(value, valueClass);
|
|
257 |
| } |
|
258 |
| else |
|
259 |
| { |
|
260 |
2150
| Object key = makeKey(attributes, false);
|
|
261 |
2150
| parameter = makeComponentParameter(key);
|
|
262 |
| } |
|
263 |
5590
| switch(stateStack.getLast())
|
|
264 |
| { |
|
265 |
4472
| case COMPONENT:
|
|
266 |
4472
| componentStack.getLast().addParameter(parameter);
|
|
267 |
4472
| break;
|
|
268 |
1118
| case SEQUENCE:
|
|
269 |
1118
| sequenceStack.getLast().addParameter(parameter);
|
|
270 |
1118
| break;
|
|
271 |
0
| default:
|
|
272 |
0
| throw new SAXParseException("unexpected parent tag "+stateStack.getLast().getTag(),
|
|
273 |
| locator); |
|
274 |
| } |
|
275 |
| } |
|
276 |
| |
|
277 |
5590
| void endParameter()
|
|
278 |
| { |
|
279 |
| |
|
280 |
| } |
|
281 |
| |
|
282 |
774
| void startSequence(Attributes attributes)
|
|
283 |
| throws SAXException |
|
284 |
| { |
|
285 |
774
| SequenceInfo info = new SequenceInfo(loadClass(attributes, null));
|
|
286 |
774
| sequenceStack.add(info);
|
|
287 |
| } |
|
288 |
| |
|
289 |
774
| void endSequence()
|
|
290 |
| throws SAXException |
|
291 |
| { |
|
292 |
774
| SequenceInfo info = sequenceStack.removeLast();
|
|
293 |
774
| Parameter sequence = info.makeSequence();
|
|
294 |
774
| switch(stateStack.getLast())
|
|
295 |
| { |
|
296 |
602
| case COMPONENT:
|
|
297 |
602
| componentStack.getLast().addParameter(sequence);
|
|
298 |
602
| break;
|
|
299 |
172
| case SEQUENCE:
|
|
300 |
172
| sequenceStack.getLast().addParameter(sequence);
|
|
301 |
172
| break;
|
|
302 |
0
| default:
|
|
303 |
0
| throw new SAXParseException("unexpected parent tag "+stateStack.getLast().getTag(),
|
|
304 |
| locator); |
|
305 |
| } |
|
306 |
| } |
|
307 |
| |
|
308 |
172
| void startAlias(Attributes attributes)
|
|
309 |
| throws SAXException |
|
310 |
| { |
|
311 |
172
| Object key = makeKey(attributes, false);
|
|
312 |
172
| if(key == null)
|
|
313 |
| { |
|
314 |
0
| throw new SAXParseException("class-key or key expected", locator);
|
|
315 |
| } |
|
316 |
172
| Object ref = makeRef(attributes);
|
|
317 |
172
| ComponentAdapter adapter = containerStack.getLast().getComponentAdapter(ref);
|
|
318 |
172
| if(adapter == null)
|
|
319 |
| { |
|
320 |
0
| throw new SAXParseException("missing component " + ref, locator);
|
|
321 |
| } |
|
322 |
172
| ComponentAdapter alias = new AliasComponentAdapter(key, adapter);
|
|
323 |
172
| containerStack.getLast().registerComponent(alias);
|
|
324 |
| } |
|
325 |
| |
|
326 |
172
| void endAlias()
|
|
327 |
| { |
|
328 |
| |
|
329 |
| } |
|
330 |
| |
|
331 |
| |
|
332 |
| |
|
333 |
| |
|
334 |
| |
|
335 |
| |
|
336 |
| |
|
337 |
| |
|
338 |
| |
|
339 |
| |
|
340 |
| |
|
341 |
1462
| private MutablePicoContainer makeContainer(PicoContainer parent,
|
|
342 |
| ComponentAdapterFactory factory, Attributes attributes) |
|
343 |
| throws SAXException |
|
344 |
| { |
|
345 |
1462
| Class<? extends MutablePicoContainer> implClass = loadClass(attributes,
|
|
346 |
| DEFAULT_CONTAINER_IMPL); |
|
347 |
1462
| Constructor<? extends MutablePicoContainer> ctor;
|
|
348 |
1462
| try
|
|
349 |
| { |
|
350 |
1462
| ctor = implClass.getConstructor(PICOCONTAINER_ARGS);
|
|
351 |
| } |
|
352 |
| catch(NoSuchMethodException e) |
|
353 |
| { |
|
354 |
0
| throw new SAXParseException("constructor " + implClass.getName()
|
|
355 |
| + ".<init>(PicoContainer) not found", locator, e); |
|
356 |
| } |
|
357 |
1462
| try
|
|
358 |
| { |
|
359 |
1462
| return ctor.newInstance(factory, parent);
|
|
360 |
| } |
|
361 |
| catch(Exception e) |
|
362 |
| { |
|
363 |
0
| throw new SAXParseException("constructor invocation failed", locator, e);
|
|
364 |
| } |
|
365 |
| } |
|
366 |
| |
|
367 |
| |
|
368 |
| |
|
369 |
| |
|
370 |
| |
|
371 |
| |
|
372 |
| |
|
373 |
| |
|
374 |
| |
|
375 |
9030
| private Object makeKey(Attributes attributes, boolean useClass)
|
|
376 |
| throws SAXException |
|
377 |
| { |
|
378 |
9030
| String classKey = attributes.getValue("class-key");
|
|
379 |
9030
| if(classKey != null)
|
|
380 |
| { |
|
381 |
1720
| return loadClass(classKey);
|
|
382 |
| } |
|
383 |
7310
| String key = attributes.getValue("key");
|
|
384 |
7310
| if(key != null)
|
|
385 |
| { |
|
386 |
3010
| return key;
|
|
387 |
| } |
|
388 |
4300
| if(attributes.getValue("anon") != null)
|
|
389 |
| { |
|
390 |
860
| return new AnonymousKey();
|
|
391 |
| } |
|
392 |
3440
| String implicitClassKey = attributes.getValue("class");
|
|
393 |
3440
| if(useClass && implicitClassKey != null)
|
|
394 |
| { |
|
395 |
2666
| return loadClass(implicitClassKey);
|
|
396 |
| } |
|
397 |
774
| return null;
|
|
398 |
| } |
|
399 |
| |
|
400 |
172
| private Object makeRef(Attributes attributes)
|
|
401 |
| throws SAXException |
|
402 |
| { |
|
403 |
172
| String classRef = attributes.getValue("class-ref");
|
|
404 |
172
| if(classRef != null)
|
|
405 |
| { |
|
406 |
86
| return loadClass(classRef);
|
|
407 |
| } |
|
408 |
86
| String ref = attributes.getValue("ref");
|
|
409 |
86
| if(ref != null)
|
|
410 |
| { |
|
411 |
86
| return ref;
|
|
412 |
| } |
|
413 |
0
| throw new SAXParseException("class-ref or ref attribute expected", locator);
|
|
414 |
| } |
|
415 |
| |
|
416 |
| |
|
417 |
| |
|
418 |
| |
|
419 |
| |
|
420 |
| |
|
421 |
| |
|
422 |
3010
| private Parameter makeComponentParameter(Object key)
|
|
423 |
| { |
|
424 |
3010
| if(key != null)
|
|
425 |
| { |
|
426 |
2322
| return new CustomizingComponentParameter(key);
|
|
427 |
| } |
|
428 |
| else |
|
429 |
| { |
|
430 |
688
| return new CustomizingComponentParameter();
|
|
431 |
| } |
|
432 |
| } |
|
433 |
| |
|
434 |
| |
|
435 |
| |
|
436 |
| |
|
437 |
| |
|
438 |
| |
|
439 |
| |
|
440 |
| |
|
441 |
| |
|
442 |
11438
| private Class loadClass(Attributes attributes, Class defaultClass)
|
|
443 |
| throws SAXException |
|
444 |
| { |
|
445 |
11438
| String className = attributes.getValue("class");
|
|
446 |
11438
| if(className == null)
|
|
447 |
| { |
|
448 |
4300
| return defaultClass;
|
|
449 |
| } |
|
450 |
7138
| return loadClass(className);
|
|
451 |
| } |
|
452 |
| |
|
453 |
| private static final Map<String,String> PRIMITIVE_TO_BOXED = new HashMap<String,String>(); |
|
454 |
| static |
|
455 |
| { |
|
456 |
258
| PRIMITIVE_TO_BOXED.put("int", Integer.class.getName());
|
|
457 |
258
| PRIMITIVE_TO_BOXED.put("byte", Byte.class.getName());
|
|
458 |
258
| PRIMITIVE_TO_BOXED.put("short", Short.class.getName());
|
|
459 |
258
| PRIMITIVE_TO_BOXED.put("long", Long.class.getName());
|
|
460 |
258
| PRIMITIVE_TO_BOXED.put("float", Float.class.getName());
|
|
461 |
258
| |