1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.xchain.framework.jsl;
17
18 import java.util.ArrayList;
19 import java.util.Iterator;
20 import java.util.LinkedList;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Set;
24
25 import java.util.regex.Pattern;
26 import java.util.regex.PatternSyntaxException;
27 import java.util.regex.Matcher;
28
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 import org.xml.sax.SAXException;
33
34
35
36
37
38
39
40
41 public class TemplateSourceBuilder
42 {
43 public static Logger log = LoggerFactory.getLogger(TemplateSourceBuilder.class);
44
45 public static final String TEMPLATE_PACKAGE = "org.xchain.namespaces.jsl";
46 public static final String BASE_TEMPLATE_NAME = "TemplateCommand";
47
48 public static final String FIXED_PART_REGEX = "((?:[^{]+|\\{\\{)+)";
49 public static final String DYNAMIC_PART_REGEX = "(?:\\{((?:[^\\}\'\"]*|\"[^\"]*\"|\'[^\']*\')*)\\})";
50 public static final String ENCODING_REGEX = "(?:([\u0000-\u007f]+)|([^\u0000-\u007f]+))";
51
52 public static Pattern ATTRIBUTE_VALUE_TEMPLATE_PATTERN = null;
53 public static Pattern ENCODING_PATTERN = null;
54
55 static {
56 try {
57 ATTRIBUTE_VALUE_TEMPLATE_PATTERN = Pattern.compile("\\G"+FIXED_PART_REGEX+"|"+DYNAMIC_PART_REGEX+"|\\Z");
58 }
59 catch( PatternSyntaxException pse ) {
60 log.error("Could not compile attribute value template pattern.", pse);
61 }
62 try {
63 ENCODING_PATTERN = Pattern.compile(ENCODING_REGEX);
64 }
65 catch( PatternSyntaxException pse ) {
66 log.error("Could not compile encoding pattern.", pse);
67 }
68 }
69
70
71 private LinkedList<Context> contextStack = new LinkedList<Context>();
72
73 private int commandId = 0;
74
75 public void pushContext( Context context )
76 {
77 contextStack.addFirst(context);
78 }
79
80 public Context popContext()
81 {
82 return contextStack.removeFirst();
83 }
84
85 public int nextCommandId()
86 {
87 return commandId++;
88 }
89
90 public void startSource(Map<String, String> transitionPrefixMapping, Set<String> transitionExcludeResultPrefixSet, boolean excludeResultPrefixBoundary)
91 {
92 Context context = new Context();
93 context.setTransitionPrefixMapping(transitionPrefixMapping);
94 context.setTransitionExcludeResultPrefixSet(transitionExcludeResultPrefixSet);
95 context.setExcludeResultPrefixBoundary(excludeResultPrefixBoundary);
96
97 pushContext(context);
98
99
100 context.setCommandIndex(nextCommandId());
101
102 startVirtualChain();
103 }
104
105 public SourceResult endSource()
106 {
107
108 Context context = contextStack.getFirst();
109 while( !context.getVirtualChainContextStack().isEmpty() ) {
110 endVirtualChain();
111 }
112
113
114 context = popContext();
115
116 StringBuilder sourceBuilder = new StringBuilder();
117
118 sourceBuilder.append("package ").append(TEMPLATE_PACKAGE).append(";\n");
119 sourceBuilder.append("\n");
120
121
122 sourceBuilder.append("import org.apache.commons.jxpath.JXPathContext;\n");
123 sourceBuilder.append("import org.xchain.framework.sax.CommandHandler;\n");
124 sourceBuilder.append("import org.xml.sax.Attributes;\n");
125 sourceBuilder.append("import org.xml.sax.ContentHandler;\n");
126 sourceBuilder.append("import org.xml.sax.SAXException;\n");
127 sourceBuilder.append("import org.xml.sax.helpers.AttributesImpl;\n");
128 sourceBuilder.append("import org.apache.commons.jxpath.JXPathContext;\n");
129 sourceBuilder.append("import javax.xml.namespace.QName;\n");
130 sourceBuilder.append("\n");
131
132
133 sourceBuilder.append("public class ").append(BASE_TEMPLATE_NAME).append(context.getCommandIndex()).append("\n");
134 sourceBuilder.append(" extends AbstractTemplateCommand\n");
135 sourceBuilder.append("{\n");
136
137
138 sourceBuilder.append(" public ").append(BASE_TEMPLATE_NAME).append(context.getCommandIndex()).append("()\n");
139 sourceBuilder.append(" {\n");
140 sourceBuilder.append(" super(").append(context.getElementCount()).append(");\n");
141 sourceBuilder.append(" }\n");
142 sourceBuilder.append(" public boolean executeTemplate(JXPathContext context)\n");
143 sourceBuilder.append(" throws Exception\n");
144 sourceBuilder.append(" {\n");
145 sourceBuilder.append(" boolean result = false;\n");
146 sourceBuilder.append(" Exception exception = null;\n");
147 sourceBuilder.append(" CommandHandler handler = getContentHandler();\n");
148
149 if( context.getExcludeResultPrefixBoundary() ) {
150 sourceBuilder.append(" handler.startExcludeResultPrefixContext();\n");
151 }
152
153
154
155 for( Map.Entry<String, String> mapping : context.getTransitionPrefixMapping().entrySet() ) {
156 sourceBuilder.append(" handler.startPrefixMapping("+stringConstant(mapping.getKey())+", "+stringConstant(mapping.getValue())+");\n");
157 }
158
159 for( String excludeResultPrefix : context.getTransitionExcludeResultPrefixSet() ) {
160 sourceBuilder.append(" handler.startExcludeResultPrefix(").append(stringConstant(excludeResultPrefix)).append(");\n");
161 }
162
163
164 sourceBuilder.append(" try {\n");
165 sourceBuilder.append(" result = virtualChain0(context);\n");
166 sourceBuilder.append(" }\n");
167 sourceBuilder.append(" catch( Exception e ) {\n");
168 sourceBuilder.append(" exception = e;\n");
169 sourceBuilder.append(" }\n");
170
171
172
173 for( String excludeResultPrefix : context.getTransitionExcludeResultPrefixSet() ) {
174 sourceBuilder.append(" handler.endExcludeResultPrefix(").append(stringConstant(excludeResultPrefix)).append(");\n");
175 }
176
177
178 for( Map.Entry<String, String> mapping : context.getTransitionPrefixMapping().entrySet() ) {
179 sourceBuilder.append(" handler.endPrefixMapping("+stringConstant(mapping.getKey())+");\n");
180 }
181
182 if( context.getExcludeResultPrefixBoundary() ) {
183 sourceBuilder.append(" handler.endExcludeResultPrefixContext();\n");
184 }
185
186 sourceBuilder.append(" if( exception != null ) {\n");
187 sourceBuilder.append(" throw exception;\n");
188 sourceBuilder.append(" }\n");
189
190
191 sourceBuilder.append(" return result;\n");
192 sourceBuilder.append(" }\n");
193
194
195
196
197 sourceBuilder.append(context.getMethodBuilder());
198
199 sourceBuilder.append("}\n");
200
201 SourceResult sourceResult = new SourceResult();
202 sourceResult.setSourceResourceName("org/xchain/namespaces/jsl/"+BASE_TEMPLATE_NAME+context.getCommandIndex()+".java");
203 sourceResult.setClassResourceName("org/xchain/namespaces/jsl/"+BASE_TEMPLATE_NAME+context.getCommandIndex()+".class");
204 sourceResult.setClassName("org.xchain.namespaces.jsl."+BASE_TEMPLATE_NAME+context.getCommandIndex());
205 sourceResult.setSource(sourceBuilder.toString());
206
207 return sourceResult;
208 }
209
210
211
212
213
214 public void startVirtualChain()
215 {
216
217 Context context = contextStack.getFirst();
218
219
220 int index = context.nextVirtualChainIndex();
221 String virtualChainName = "virtualChain"+index;
222
223
224 if( !contextStack.getFirst().getVirtualChainContextStack().isEmpty() ) {
225
226
227 changeBodyMode(BodyMode.VIRTUAL_CHAIN);
228
229
230 StringBuilder bodyBuilder = contextStack.getFirst().getVirtualChainContextStack().getFirst().getBodyBuilder();
231
232
233 indent(bodyBuilder).append(" result = ").append(virtualChainName).append("(context);\n");
234 }
235
236
237 contextStack.getFirst().getVirtualChainContextStack().addFirst(new VirtualChainContext(virtualChainName));
238 }
239
240
241
242
243
244 public void endVirtualChain()
245 {
246
247 changeBodyMode(BodyMode.TOP_LEVEL);
248
249
250 VirtualChainContext virtualChainContext = contextStack.getFirst().getVirtualChainContextStack().removeFirst();
251
252 StringBuilder methodBuilder = contextStack.getFirst().getMethodBuilder();
253
254 methodBuilder.append("private boolean ").append(virtualChainContext.getName()).append("(JXPathContext context)\n");
255 methodBuilder.append(" throws Exception\n");
256 methodBuilder.append("{\n");
257 methodBuilder.append(" // the result and exception for this virtual chain\n");
258 methodBuilder.append(" boolean result = false;\n");
259 methodBuilder.append(" Exception exception = null;\n");
260
261 methodBuilder.append(" // the target for content handler events.\n");
262 methodBuilder.append(" CommandHandler handler = getContentHandler();\n");
263
264 methodBuilder.append(" // variables for building attribute objects.\n");
265 methodBuilder.append(" AttributesImpl attributes = new AttributesImpl();\n");
266 methodBuilder.append(" StringBuilder attributeValueBuilder = new StringBuilder();\n");
267
268 methodBuilder.append(" // variables for processing value-of elements.\n");
269 methodBuilder.append(" Object valueOfObject = null;\n");
270 methodBuilder.append(" String attributeValueString = null;\n");
271
272
273 methodBuilder.append(" // variables for parsing dynamic qNames.\n");
274 methodBuilder.append(" QName qName = null;\n");
275
276 methodBuilder.append(" // variables for processing comment elements.\n");
277
278
279 methodBuilder.append(" int[] commandChildrenIndecies = {");
280 Iterator<Integer> childrenIndexIterator = virtualChainContext.getCommandIndexList().iterator();
281 while( childrenIndexIterator.hasNext() ) {
282 methodBuilder.append(childrenIndexIterator.next());
283 if( childrenIndexIterator.hasNext() ) {
284 methodBuilder.append(", ");
285 }
286 }
287 methodBuilder.append("};\n");
288
289
290 methodBuilder.append(" int[] elementChildrenIndecies = {");
291 Iterator<Integer> elementIndexIterator = virtualChainContext.getElementIndexList().iterator();
292 while( elementIndexIterator.hasNext() ) {
293 methodBuilder.append(elementIndexIterator.next());
294 if( elementIndexIterator.hasNext() ) {
295 methodBuilder.append(", ");
296 }
297 }
298 methodBuilder.append("};\n");
299
300
301 methodBuilder.append(virtualChainContext.getBodyBuilder());
302
303
304 methodBuilder.append(" return virtualPostProcess( context, exception, result, commandChildrenIndecies);\n");
305
306
307 methodBuilder.append("}\n");
308 }
309
310 public void appendCommandCall()
311 {
312 Context context = contextStack.getFirst();
313 VirtualChainContext virtualChainContext = context.getVirtualChainContextStack().getFirst();
314
315
316 Integer commandIndex = context.getCommandCount();
317 context.setCommandCount(commandIndex+1);
318
319
320 if( virtualChainContext.getElementDepth() > 0 ) {
321 startVirtualChain();
322 virtualChainContext = context.getVirtualChainContextStack().getFirst();
323 }
324
325
326 virtualChainContext.getCommandIndexList().add(commandIndex);
327
328
329 changeBodyMode(BodyMode.CHAIN);
330
331 virtualChainContext.getToExecuteIndexList().add(commandIndex);
332 }
333
334 public void startStartElement()
335 {
336
337 Context context = contextStack.getFirst();
338 VirtualChainContext virtualChainContext = context.getVirtualChainContextStack().getFirst();
339
340
341 Integer elementIndex = context.getElementCount();
342 context.setElementCount(elementIndex+1);
343
344
345 context.getElementIndexStack().addFirst(elementIndex);
346
347 changeBodyMode(BodyMode.START_ELEMENT_EVENTS);
348
349
350 virtualChainContext.getElementIndexList().add(elementIndex);
351 virtualChainContext.setElementDepth(virtualChainContext.getElementDepth()+1);
352 }
353
354 public void endStartElement()
355 {
356
357 }
358
359 public void startEndElement()
360 {
361
362 Context context = contextStack.getFirst();
363 VirtualChainContext virtualChainContext = context.getVirtualChainContextStack().getFirst();
364
365
366 while( virtualChainContext.getElementDepth() == 0 ) {
367 endVirtualChain();
368 virtualChainContext = context.getVirtualChainContextStack().getFirst();
369 }
370
371 changeBodyMode(BodyMode.END_ELEMENT_EVENTS);
372
373
374 Integer elementIndex = context.getElementIndexStack().getFirst();
375
376
377 StringBuilder bodyBuilder = virtualChainContext.getBodyBuilder();
378
379
380 indent(bodyBuilder).append("if( isElementStarted(").append(elementIndex).append(") ) {\n");
381 }
382
383 public void endEndElement()
384 {
385
386 Context context = contextStack.getFirst();
387 VirtualChainContext virtualChainContext = context.getVirtualChainContextStack().getFirst();
388
389
390 context.getElementIndexStack().removeFirst();
391
392
393 StringBuilder bodyBuilder = virtualChainContext.getBodyBuilder();
394
395
396 indent(bodyBuilder).append("}\n");
397
398 virtualChainContext.setElementDepth(virtualChainContext.getElementDepth()-1);
399 }
400
401 public void appendStartPrefixMapping( String prefix, String uri )
402 {
403 changeBodyMode(BodyMode.START_ELEMENT_EVENTS);
404 String escapedPrefix = stringConstant(prefix);
405 String escapedUri = stringConstant(uri);
406 StringBuilder bodyBuilder = contextStack.getFirst().getVirtualChainContextStack().getFirst().getBodyBuilder();
407 indent(bodyBuilder).append("handler.startPrefixMapping(").append(escapedPrefix).append(", ").append(escapedUri).append(");\n");
408
409 indent(bodyBuilder).append("context.registerNamespace(").append(escapedPrefix).append(", ").append(escapedUri).append(");\n");
410 }
411
412 public void appendEndPrefixMapping( String prefix )
413 {
414 String escapedPrefix = stringConstant(prefix);
415 changeBodyMode(BodyMode.END_ELEMENT_EVENTS);
416 StringBuilder bodyBuilder = contextStack.getFirst().getVirtualChainContextStack().getFirst().getBodyBuilder();
417
418 indent(bodyBuilder).append("context.registerNamespace(").append(escapedPrefix).append(", ").append(escapedPrefix).append(");\n");
419 indent(bodyBuilder).append("handler.endPrefixMapping(").append(escapedPrefix).append(");\n");
420 }
421
422 public void appendStartExcludeResultPrefix( String prefix )
423 {
424 changeBodyMode(BodyMode.START_ELEMENT_EVENTS);
425 String escapedPrefix = stringConstant(prefix);
426 StringBuilder bodyBuilder = contextStack.getFirst().getVirtualChainContextStack().getFirst().getBodyBuilder();
427 indent(bodyBuilder).append("handler.startExcludeResultPrefix(").append(escapedPrefix).append(");\n");
428 }
429
430 public void appendEndExcludeResultPrefix( String prefix )
431 {
432 changeBodyMode(BodyMode.END_ELEMENT_EVENTS);
433 String escapedPrefix = stringConstant(prefix);
434 StringBuilder bodyBuilder = contextStack.getFirst().getVirtualChainContextStack().getFirst().getBodyBuilder();
435 indent(bodyBuilder).append("handler.endExcludeResultPrefix(").append(escapedPrefix).append(");\n");
436 }
437
438 public void appendContextStartPrefixMapping( String prefix, String uri )
439 {
440 changeBodyMode(BodyMode.START_ELEMENT_EVENTS);
441 String escapedPrefix = stringConstant(prefix);
442 String escapedUri = stringConstant(uri);
443 StringBuilder bodyBuilder = contextStack.getFirst().getVirtualChainContextStack().getFirst().getBodyBuilder();
444 indent(bodyBuilder).append("context.registerNamespace(").append(escapedPrefix).append(", ").append(escapedUri).append(");\n");
445 }
446
447 public void appendContextEndPrefixMapping( String prefix )
448 {
449 String escapedPrefix = stringConstant(prefix);
450 changeBodyMode(BodyMode.END_ELEMENT_EVENTS);
451 StringBuilder bodyBuilder = contextStack.getFirst().getVirtualChainContextStack().getFirst().getBodyBuilder();
452 indent(bodyBuilder).append("context.registerNamespace(").append(escapedPrefix).append(", ").append(escapedPrefix).append(");\n");
453 }
454
455 public void appendAttributeValueTemplate( String uri, String localName, String qName, String attributeValueTemplate )
456 throws SAXException
457 {
458
459 String escapedUri = stringConstant(uri);
460 String escapedLocalName = stringConstant(localName);
461 String escapedQName = stringConstant(qName);
462
463
464 changeBodyMode(BodyMode.START_ELEMENT_EVENTS);
465
466
467 StringBuilder bodyBuilder = contextStack.getFirst().getVirtualChainContextStack().getFirst().getBodyBuilder();
468
469
470 Iterator<String> attributeValueIterator = parseAttributeValueTemplate(attributeValueTemplate).iterator();
471 while( attributeValueIterator.hasNext() ) {
472
473 indent(bodyBuilder).append("attributeValueBuilder.append(").append(stringConstant(attributeValueIterator.next())).append(");\n");
474
475
476 if( attributeValueIterator.hasNext() ) {
477 indent(bodyBuilder).append("attributeValueString = (String)context.getValue(").append(stringConstant(attributeValueIterator.next())).append(", String.class);\n");
478 indent(bodyBuilder).append("attributeValueBuilder.append(attributeValueString != null ? attributeValueString : \"\");\n");
479 }
480 }
481
482
483 indent(bodyBuilder).append("attributes.addAttribute(").append(escapedUri).append(", ").append(escapedLocalName).append(", ").append(escapedQName).append(", \"CDATA\", attributeValueBuilder.toString());\n");
484 indent(bodyBuilder).append("attributeValueBuilder = new StringBuilder();\n");
485 }
486
487
488
489
490 public void appendStartElement( String uri, String localName, String qName )
491 {
492 Context context = contextStack.getFirst();
493
494 Integer elementIndex = context.getElementIndexStack().getFirst();
495
496
497 String escapedUri = stringConstant(uri);
498 String escapedLocalName = stringConstant(localName);
499 String escapedQName = stringConstant(qName);
500
501 changeBodyMode(BodyMode.START_ELEMENT_EVENTS);
502
503
504 VirtualChainContext virtualChainContext = context.getVirtualChainContextStack().getFirst();
505 virtualChainContext.setElementDepth(virtualChainContext.getElementDepth()+1);
506 StringBuilder bodyBuilder = virtualChainContext.getBodyBuilder();
507
508
509 indent(bodyBuilder).append("trackStartElement(").append(elementIndex).append(");\n");
510 indent(bodyBuilder).append("handler.startElement(").append(escapedUri).append(", ").append(escapedLocalName).append(", ").append(escapedQName).append(", attributes);\n");
511 indent(bodyBuilder).append("attributes.clear();\n");
512 }
513
514
515
516
517 public void appendEndElement( String uri, String localName, String qName )
518 {
519 Context context = contextStack.getFirst();
520 VirtualChainContext virtualChainContext = context.getVirtualChainContextStack().getFirst();
521 virtualChainContext.setElementDepth(virtualChainContext.getElementDepth()-1);
522
523
524 Integer elementIndex = context.getElementIndexStack().getFirst();
525
526
527
528
529
530 String escapedUri = stringConstant(uri);
531 String escapedLocalName = stringConstant(localName);
532 String escapedQName = stringConstant(qName);
533
534 changeBodyMode(BodyMode.END_ELEMENT_EVENTS);
535
536
537 StringBuilder bodyBuilder = context.getVirtualChainContextStack().getFirst().getBodyBuilder();
538
539
540 indent(bodyBuilder).append("trackEndElement(").append(elementIndex).append(");\n");
541 indent(bodyBuilder).append("handler.endElement(").append(escapedUri).append(", ").append(escapedLocalName).append(", ").append(escapedQName).append(");\n");
542 }
543
544
545
546
547 public void appendCharacters( String characters )
548 {
549 String escapedCharacters = stringConstant(characters);
550
551 changeBodyMode(BodyMode.START_ELEMENT_EVENTS);
552
553 StringBuilder bodyBuilder = contextStack.getFirst().getVirtualChainContextStack().getFirst().getBodyBuilder();
554 indent(bodyBuilder).append("handler.characters(").append(escapedCharacters).append(".toCharArray(), 0, ").append(characters.length()).append(");\n");
555 }
556
557 public void appendIgnorableWhitespace( String ignorableWhitespace )
558 {
559 String escapedWhitespace = stringConstant(ignorableWhitespace);
560
561
562
563 StringBuilder bodyBuilder = contextStack.getFirst().getVirtualChainContextStack().getFirst().getBodyBuilder();
564 indent(bodyBuilder).append("handler.ignorableWhitespace(").append(escapedWhitespace).append(".toCharArray(), 0, ").append(ignorableWhitespace.length()).append(");\n");
565 }
566
567
568
569
570
571
572 public void appendValueOf( String jxpath )
573 {
574 String escapedJXPath = stringConstant(jxpath);
575
576 changeBodyMode(BodyMode.START_ELEMENT_EVENTS);
577
578 StringBuilder bodyBuilder = contextStack.getFirst().getVirtualChainContextStack().getFirst().getBodyBuilder();
579 indent(bodyBuilder).append("valueOfObject = context.getValue(").append(escapedJXPath).append(");\n");
580 indent(bodyBuilder).append("if( valueOfObject != null ) {\n");
581 indent(bodyBuilder).append(" char[] valueOfChars = valueOfObject.toString().toCharArray();\n");
582 indent(bodyBuilder).append(" handler.characters(valueOfChars, 0, valueOfChars.length);\n");
583 indent(bodyBuilder).append("}\n");
584 }
585
586 public void appendStartComment()
587 {
588 Context context = contextStack.getFirst();
589
590 Integer elementIndex = context.getElementCount();
591 context.setElementCount(elementIndex+1);
592 context.getElementIndexStack().addFirst(elementIndex);
593 context.getVirtualChainContextStack().getFirst().getElementIndexList().add(elementIndex);
594
595 changeBodyMode(BodyMode.START_ELEMENT_EVENTS);
596
597
598 VirtualChainContext virtualChainContext = context.getVirtualChainContextStack().getFirst();
599 virtualChainContext.setElementDepth(virtualChainContext.getElementDepth()+1);
600 StringBuilder bodyBuilder = virtualChainContext.getBodyBuilder();
601
602 indent(bodyBuilder).append("trackStartElement(").append(elementIndex).append(");\n");
603 indent(bodyBuilder).append("handler.startComment();\n");
604 }
605
606 public void appendEndComment()
607 {
608 Context context = contextStack.getFirst();
609 VirtualChainContext virtualChainContext = context.getVirtualChainContextStack().getFirst();
610
611
612 Integer elementIndex = context.getElementIndexStack().getFirst();
613
614 changeBodyMode(BodyMode.END_ELEMENT_EVENTS);
615
616
617 StringBuilder bodyBuilder = virtualChainContext.getBodyBuilder();
618
619
620 indent(bodyBuilder).append("if( isElementStarted(").append(elementIndex).append(") ) {\n");
621 indent(bodyBuilder).append(" trackEndElement(").append(elementIndex).append(");\n");
622 indent(bodyBuilder).append(" handler.endComment();\n");
623 indent(bodyBuilder).append("}\n");
624
625
626 context.getElementIndexStack().removeFirst();
627 virtualChainContext.setElementDepth(virtualChainContext.getElementDepth()-1);
628 }
629
630
631
632
633
634
635
636 public void appendStartDynamicElement( String name, String namespace )
637 {
638 Context context = contextStack.getFirst();
639
640 Integer elementIndex = context.getElementIndexStack().getFirst();
641
642 changeBodyMode(BodyMode.START_ELEMENT_EVENTS);
643
644
645 VirtualChainContext virtualChainContext = context.getVirtualChainContextStack().getFirst();
646
647
648
649
650 StringBuilder bodyBuilder = virtualChainContext.getBodyBuilder();
651
652
653 indent(bodyBuilder).append("trackStartElement(").append(elementIndex).append(");\n");
654
655
656 indent(bodyBuilder).append("qName = dynamicQName(context, ").append(stringConstant(name)).append(", ").append(stringConstant(namespace)).append(", true);\n");
657 indent(bodyBuilder).append("getDynamicElementStack().addFirst(qName);\n");
658 indent(bodyBuilder).append("handler.startElement(qName.getNamespaceURI(), qName.getLocalPart(), toPrefixedQName(qName), attributes);\n");
659 indent(bodyBuilder).append("attributes.clear();\n");
660 }
661
662
663
664
665 public void appendEndDynamicElement()
666 {
667 Context context = contextStack.getFirst();
668 VirtualChainContext virtualChainContext = context.getVirtualChainContextStack().getFirst();
669
670
671 Integer elementIndex = context.getElementIndexStack().getFirst();
672
673 changeBodyMode(BodyMode.END_ELEMENT_EVENTS);
674
675
676 StringBuilder bodyBuilder = virtualChainContext.getBodyBuilder();
677
678
679 indent(bodyBuilder).append("trackEndElement(").append(elementIndex).append(");\n");
680 indent(bodyBuilder).append("qName = getDynamicElementStack().removeFirst();\n");
681 indent(bodyBuilder).append("handler.endElement(qName.getNamespaceURI(), qName.getLocalPart(), toPrefixedQName(qName));\n");
682
683
684
685 }
686
687
688
689
690
691
692
693 public void appendStartDynamicAttribute( String name, String namespace )
694 {
695 Context context = contextStack.getFirst();
696 VirtualChainContext virtualChainContext = context.getVirtualChainContextStack().getFirst();
697 virtualChainContext.setElementDepth(virtualChainContext.getElementDepth()+1);
698
699 changeBodyMode(BodyMode.START_ELEMENT_EVENTS);
700
701
702 StringBuilder bodyBuilder = context.getVirtualChainContextStack().getFirst().getBodyBuilder();
703
704
705 indent(bodyBuilder).append("qName = dynamicQName(context, ").append(stringConstant(name)).append(", ").append(stringConstant(namespace)).append(", false);\n");
706 indent(bodyBuilder).append("getDynamicElementStack().addFirst(qName);\n");
707 indent(bodyBuilder).append("handler.startAttribute(qName.getNamespaceURI(), qName.getLocalPart(), toPrefixedQName(qName) );\n");
708 indent(bodyBuilder).append("attributes.clear();\n");
709 }
710
711
712
713
714 public void appendEndDynamicAttribute()
715 {
716 Context context = contextStack.getFirst();
717 VirtualChainContext virtualChainContext = context.getVirtualChainContextStack().getFirst();
718
719 changeBodyMode(BodyMode.END_ELEMENT_EVENTS);
720
721
722 StringBuilder bodyBuilder = context.getVirtualChainContextStack().getFirst().getBodyBuilder();
723
724
725 indent(bodyBuilder).append("qName = getDynamicElementStack().removeFirst();\n");
726 indent(bodyBuilder).append("handler.endAttribute(qName.getNamespaceURI(), qName.getLocalPart(), toPrefixedQName(qName) );\n");
727
728 virtualChainContext.setElementDepth(virtualChainContext.getElementDepth()-1);
729 }
730
731 public void changeBodyMode( BodyMode newMode )
732 {
733 VirtualChainContext virtualChainContext = contextStack.getFirst().getVirtualChainContextStack().getFirst();
734
735
736
737 if( newMode != virtualChainContext.getBodyMode() ) {
738 StringBuilder bodyBuilder = virtualChainContext.getBodyBuilder();
739
740
741 switch( virtualChainContext.getBodyMode() ) {
742 case CHAIN:
743 indent(bodyBuilder).append(" result = executeChildren(context, new int[]{");
744 Iterator<Integer> toExecuteIndexIterator = virtualChainContext.getToExecuteIndexList().iterator();
745 while( toExecuteIndexIterator.hasNext() ) {
746 Integer toExecuteIndex = toExecuteIndexIterator.next();
747 bodyBuilder.append(toExecuteIndex);
748 if( toExecuteIndexIterator.hasNext() ) {
749 bodyBuilder.append(", ");
750 }
751 }
752 bodyBuilder.append("});\n");
753 virtualChainContext.getToExecuteIndexList().clear();
754 case VIRTUAL_CHAIN:
755 decrementIndent();
756 indent(bodyBuilder).append(" }\n");
757 indent(bodyBuilder).append(" catch( Exception e ) {\n");
758 indent(bodyBuilder).append(" exception = e;\n");
759 indent(bodyBuilder).append(" }\n");
760 indent(bodyBuilder).append("}\n");
761 break;
762 case START_ELEMENT_EVENTS:
763 decrementIndent();
764 indent(bodyBuilder).append(" }\n");
765 indent(bodyBuilder).append(" catch( SAXException e ) {\n");
766 indent(bodyBuilder).append(" registerSaxException(e);\n");
767 indent(bodyBuilder).append(" }\n");
768 indent(bodyBuilder).append(" catch( Exception e ) {\n");
769 indent(bodyBuilder).append(" registerSaxException(new SAXException(e));\n");
770 indent(bodyBuilder).append(" }\n");
771 indent(bodyBuilder).append(" finally {\n");
772 indent(bodyBuilder).append(" attributes.clear();\n");
773 indent(bodyBuilder).append(" attributeValueBuilder = new StringBuilder();\n");
774 indent(bodyBuilder).append(" }\n");
775 indent(bodyBuilder).append("}\n");
776 break;
777 case END_ELEMENT_EVENTS:
778 decrementIndent();
779 indent(bodyBuilder).append(" }\n");
780 indent(bodyBuilder).append(" catch( SAXException e ) {\n");
781 indent(bodyBuilder).append(" registerSaxException(e);\n");
782 indent(bodyBuilder).append(" }\n");
783 indent(bodyBuilder).append(" catch( Exception e ) {\n");
784 indent(bodyBuilder).append(" registerSaxException(new SAXException(e));\n");
785 indent(bodyBuilder).append(" }\n");
786 indent(bodyBuilder).append("}\n");
787 case TOP_LEVEL:
788 break;
789 default:
790 throw new IllegalStateException("Unknown virtual chain body mode encountered.");
791 }
792
793
794 switch( newMode ) {
795 case CHAIN:
796 case VIRTUAL_CHAIN:
797 case START_ELEMENT_EVENTS:
798 indent(bodyBuilder).append("if( exception == null && !result && !hasSaxExceptionFired() ) {\n");
799 indent(bodyBuilder).append(" try {\n");
800 incrementIndent();
801 break;
802 case END_ELEMENT_EVENTS:
803 indent(bodyBuilder).append("if( !hasSaxExceptionFired() ) {\n");
804 indent(bodyBuilder).append(" try {\n");
805 incrementIndent();
806 break;
807 case TOP_LEVEL:
808 break;
809 default:
810 throw new IllegalStateException("Unknown virtual chain body mode encountered.");
811 }
812 }
813
814 virtualChainContext.setBodyMode(newMode);
815 }
816
817 public StringBuilder indent(StringBuilder builder)
818 {
819 int indent = contextStack.getFirst().getIndent();
820
821 for( int i = 0; i < indent; i++ ) {
822 builder.append(" ");
823 }
824
825 return builder;
826 }
827
828 public void incrementIndent()
829 {
830 contextStack.getFirst().setIndent(contextStack.getFirst().getIndent()+1);
831 }
832
833 public void decrementIndent()
834 {
835 contextStack.getFirst().setIndent(contextStack.getFirst().getIndent()-1);
836 }
837
838
839
840
841
842 public static List<String> parseAttributeValueTemplate( String attributeValueTemplate )
843 throws SAXException
844 {
845
846 ArrayList<String> result = new ArrayList<String>();
847
848
849 Matcher matcher = ATTRIBUTE_VALUE_TEMPLATE_PATTERN.matcher(attributeValueTemplate);
850
851 while( matcher.find() ) {
852 String fixedPart = matcher.group(1);
853 String dynamicPart = matcher.group(2);
854
855 if( result.isEmpty() && fixedPart == null ) {
856 result.add("");
857 }
858
859 if( fixedPart != null ) {
860 result.add(fixedPart.replaceAll("\\{\\{", "{").replaceAll("\\}\\}", "}"));
861 }
862 if( dynamicPart != null ) {
863 result.add(dynamicPart);
864 }
865 }
866
867 if( !matcher.hitEnd() ) {
868 throw new SAXException("The attribute value template '"+attributeValueTemplate+"' has an error between characters "+matcher.regionStart()+" and "+matcher.regionEnd()+".");
869 }
870
871 return result;
872 }
873
874
875
876
877 public static class Context
878 {
879 private LinkedList<VirtualChainContext> virtualChainContextStack = new LinkedList<VirtualChainContext>();
880 private StringBuilder methodBuilder = new StringBuilder();
881 private int commandCount = 0;
882 private int elementCount = 0;
883 private StringBuilder headerBuilder = new StringBuilder();
884 private StringBuilder footerBuilder = new StringBuilder();
885 private int indent = 0;
886 private int commandIndex = 0;
887 private int nextVirtualChainIndex = 0;
888 private Map<String, String> transitionPrefixMapping;
889 private Set<String> transitionExcludeResultPrefixSet;
890 private boolean excludeResultPrefixBoundary = false;
891 private LinkedList<Integer> elementIndexStack = new LinkedList<Integer>();
892
893
894 public LinkedList<VirtualChainContext> getVirtualChainContextStack() { return virtualChainContextStack; }
895
896
897 public StringBuilder getMethodBuilder() { return methodBuilder; }
898
899 public void setCommandCount( int commandCount ) { this.commandCount = commandCount; }
900 public int getCommandCount() { return this.commandCount; }
901
902 public void setElementCount( int elementCount ) { this.elementCount = elementCount; }
903 public int getElementCount() { return this.elementCount; }
904
905 public StringBuilder getHeaderBuilder() { return this.headerBuilder; }
906 public StringBuilder getFooterBuilder() { return this.footerBuilder; }
907
908 public void setIndent( int indent ) { this.indent = indent; }
909 public int getIndent() { return this.indent; }
910
911 public void setCommandIndex( int commandIndex ) { this.commandIndex = commandIndex; }
912 public int getCommandIndex() { return this.commandIndex; }
913
914 public int nextVirtualChainIndex() {
915 return nextVirtualChainIndex++;
916 }
917
918 public Map<String, String> getTransitionPrefixMapping() { return transitionPrefixMapping; }
919 public void setTransitionPrefixMapping( Map<String, String> transitionPrefixMapping ) { this.transitionPrefixMapping = transitionPrefixMapping; }
920
921 public Set<String> getTransitionExcludeResultPrefixSet() { return transitionExcludeResultPrefixSet; }
922 public void setTransitionExcludeResultPrefixSet( Set<String> transitionExcludeResultPrefixSet ) { this.transitionExcludeResultPrefixSet = transitionExcludeResultPrefixSet; }
923
924 public boolean getExcludeResultPrefixBoundary() { return excludeResultPrefixBoundary; }
925 public void setExcludeResultPrefixBoundary( boolean excludeResultPrefixBoundary ) { this.excludeResultPrefixBoundary = excludeResultPrefixBoundary; }
926
927 public LinkedList<Integer> getElementIndexStack() { return elementIndexStack; }
928 }
929
930 public static enum BodyMode
931 {
932
933 TOP_LEVEL,
934
935 CHAIN,
936
937 START_ELEMENT_EVENTS,
938
939 END_ELEMENT_EVENTS,
940 VIRTUAL_CHAIN
941 }
942
943
944
945
946 public static class VirtualChainContext
947 {
948 private String name = null;
949 private StringBuilder bodyBuilder = new StringBuilder();
950 private List<Integer> commandIndexList = new ArrayList<Integer>();
951 private List<Integer> elementIndexList = new ArrayList<Integer>();
952 private List<Integer> toExecuteIndexList = new ArrayList<Integer>();
953 private int elementDepth = 0;
954 private BodyMode bodyMode = BodyMode.TOP_LEVEL;
955
956 public VirtualChainContext( String name )
957 {
958 this.name = name;
959 }
960
961
962 public String getName() { return name; }
963
964
965 public StringBuilder getBodyBuilder() { return bodyBuilder; }
966
967
968 public List<Integer> getCommandIndexList() { return commandIndexList; }
969
970 public List<Integer> getElementIndexList() { return elementIndexList; }
971
972 public List<Integer> getToExecuteIndexList() { return toExecuteIndexList; }
973
974
975 public BodyMode getBodyMode() { return this.bodyMode; }
976
977
978 public void setBodyMode( BodyMode bodyMode ) { this.bodyMode = bodyMode; };
979
980 public int getElementDepth() { return this.elementDepth; }
981 public void setElementDepth( int elementDepth ) { this.elementDepth = elementDepth; }
982 }
983
984 public static String stringConstant( String source )
985 {
986
987 if( source == null ) {
988 return "((String)null)";
989 }
990
991
992 StringBuilder builder = new StringBuilder();
993
994
995 builder.append('\"');
996
997
998 Matcher matcher = ENCODING_PATTERN.matcher(source);
999
1000 while(matcher.find()) {
1001 if( matcher.group(1) != null ) {
1002 builder.append(matcher.group(1)
1003 .replaceAll("\\\\", "\\\\\\\\")
1004 .replaceAll("\\\"", "\\\\\"")
1005 .replaceAll("\\\'", "\\\\\'")
1006 .replaceAll("\r", "\\\\r")
1007 .replaceAll("\t", "\\\\t")
1008 .replaceAll("\b", "\\\\b")
1009 .replaceAll("\n", "\\\\n")
1010 .replaceAll("\f", "\\\\f"));
1011 }
1012 else {
1013
1014 String toUnicode = matcher.group(2);
1015 for( int i = 0; i < toUnicode.length(); i++ ) {
1016 builder.append("\\u");
1017 String codePoint = Integer.toHexString(matcher.group(2).codePointAt(i));
1018 for( int j = codePoint.length(); j < 4; j++ ) { builder.append("0"); }
1019 builder.append(codePoint);
1020 }
1021 }
1022 }
1023
1024
1025 builder.append('\"');
1026
1027 return builder.toString();
1028 }
1029 }