1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.asn1.ber.digester ;
18
19
20 import java.nio.ByteBuffer;
21 import java.util.Collections;
22 import java.util.EmptyStackException;
23 import java.util.HashSet;
24 import java.util.Iterator;
25 import java.util.List;
26
27 import org.apache.asn1.ber.BERDecoder;
28 import org.apache.asn1.ber.BERDecoderCallback;
29 import org.apache.asn1.ber.Tuple;
30 import org.apache.asn1.ber.TypeClass;
31 import org.apache.asn1.codec.DecoderException;
32 import org.apache.asn1.codec.stateful.AbstractStatefulDecoder;
33 import org.apache.asn1.codec.stateful.StatefulDecoder;
34 import org.apache.commons.collections.ArrayStack;
35 import org.apache.commons.collections.primitives.BooleanStack;
36 import org.apache.commons.collections.primitives.ByteStack;
37 import org.apache.commons.collections.primitives.CharStack;
38 import org.apache.commons.collections.primitives.DoubleStack;
39 import org.apache.commons.collections.primitives.FloatStack;
40 import org.apache.commons.collections.primitives.IntStack;
41 import org.apache.commons.collections.primitives.LongStack;
42 import org.apache.commons.collections.primitives.ShortStack;
43
44
45 /***
46 * A special BER TLV event rulesBase. This class was inspired by the XML
47 * rulesBase in Jakarta Commons.
48 *
49 * @author <a href="mailto:dev@directory.apache.org">
50 * Apache Directory Project</a>
51 * @version $Rev: 157644 $
52 */
53 public class BERDigester extends AbstractStatefulDecoder
54 {
55 /***
56 * For now this corresponds to a tag of class Universal with an id
57 * of 15. This has been reserved for future use but to my knowledge
58 * currently it is not being used for anything specifically. Hence
59 * we use it as the return value instead of throwing an empty stack
60 * exception when the top of the tag stack is requested.
61 */
62 public static final int NO_TOP_TAG = 0x0f000000 ;
63
64 /*** the underlying decoder used by this rulesBase */
65 private BERDecoder decoder ;
66 /*** the object stack where rules push and pop ASN.1 POJO stubs */
67 private ArrayStack objectStack ;
68 /*** the primitive boolean stack where rules push and pop booleans */
69 private BooleanStack booleanStack ;
70 /*** the primitive char stack where rules push and pop chars */
71 private CharStack charStack ;
72 /*** the primitive float stack where rules push and pop floats */
73 private FloatStack floatStack ;
74 /*** the primitive double stack where rules push and pop doubles */
75 private DoubleStack doubleStack ;
76 /*** the primitive int stack where rules push and pop ints */
77 private IntStack intStack ;
78 /*** the primitive byte stack where rules push and pop bytes */
79 private ByteStack byteStack ;
80 /*** the primitive long stack where rules push and pop longs */
81 private LongStack longStack ;
82 /*** the primitive short stack where rules push and shorts */
83 private ShortStack shortStack ;
84 /*** the tag stack used to store the nesting pattern */
85 private IntStack tagStack ;
86 /*** the rules base used by this digester */
87 private Rules rules ;
88 /*** the currently matched rules */
89 private List matched ;
90 /***
91 * The class loader to use for instantiating application objects.
92 * If not specified, the context class loader, or the class loader
93 * used to load Digester itself, is used, based on the value of the
94 * <code>useContextClassLoader</code> variable.
95 */
96 private ClassLoader classLoader = null ;
97 /***
98 * Do we want to use the Context ClassLoader when loading classes
99 * for instantiating new objects. Default is <code>false</code>.
100 */
101 private boolean useContextClassLoader = false ;
102 /***
103 * The "root" element of the stack (in other words, the last object
104 * that was popped.
105 */
106 private Object root = null ;
107 /*** The monitor used by this digester */
108 private BERDigesterMonitor monitor = null ;
109
110
111 /***
112 * Creates a BER TLV event rulesBase.
113 */
114 public BERDigester()
115 {
116 this.rules = new RulesBase() ;
117 this.rules.setDigester( this ) ;
118 this.tagStack = new IntStack() ;
119 this.objectStack = new ArrayStack() ;
120 this.booleanStack = new BooleanStack() ;
121 this.charStack = new CharStack() ;
122 this.byteStack = new ByteStack() ;
123 this.shortStack = new ShortStack() ;
124 this.intStack = new IntStack() ;
125 this.longStack = new LongStack() ;
126 this.floatStack = new FloatStack() ;
127 this.doubleStack = new DoubleStack() ;
128 this.decoder = new BERDecoder() ;
129 this.decoder.setCallback( new DigesterCallback() ) ;
130 this.monitor = new BERDigesterLoggingMonitor() ;
131 }
132
133
134
135
136
137
138
139
140
141
142
143 public void decode( Object encoded ) throws DecoderException
144 {
145 decoder.decode( encoded ) ;
146 }
147
148
149
150
151
152
153
154 class DigesterCallback implements BERDecoderCallback
155 {
156
157
158
159
160 public void tagDecoded( Tuple tlv )
161 {
162 tagStack.push( tlv.getRawPrimitiveTag() ) ;
163 matched = rules.match( tagStack ) ;
164 fireTagEvent( tlv.getId(), tlv.isPrimitive(), tlv.getTypeClass() ) ;
165 }
166
167
168
169
170
171
172 public void lengthDecoded( Tuple tlv )
173 {
174 fireLengthEvent( tlv.getLength() ) ;
175 }
176
177
178
179
180
181
182 public void partialValueDecoded( Tuple tlv )
183 {
184 fireValueEvent( tlv.getLastValueChunk() ) ;
185 }
186
187
188
189
190
191
192 public void decodeOccurred( StatefulDecoder decoder, Object decoded )
193 {
194
195
196
197
198
199 matched = rules.match( tagStack ) ;
200 fireFinishEvent() ;
201 tagStack.pop() ;
202
203 if ( BERDigester.this.tagStack.empty() )
204 {
205 BERDigester.this.decodeOccurred( getRoot() ) ;
206 }
207 }
208 }
209
210
211
212
213
214
215
216 /***
217 * Register a new <code>Rule</code> matching the specified pattern.
218 *
219 * @param pattern tag nesting pattern
220 * @param rule the Rule to add to this BERDigester
221 */
222 public void addRule( int[] pattern, Rule rule )
223 {
224 rules.add( pattern, rule ) ;
225 rule.setDigester( this ) ;
226 }
227
228
229 /***
230 * Return the Rules implementation object containing our rules collection
231 * and associated matching policy.
232 *
233 * @return the entire set of rules
234 */
235 public Rules getRules()
236 {
237 return rules ;
238 }
239
240
241 /***
242 * Clear the current contents of the object stack.
243 */
244 public void clear()
245 {
246 root = null ;
247 tagStack.clear() ;
248 objectStack.clear() ;
249 booleanStack.clear() ;
250 byteStack.clear() ;
251 shortStack.clear() ;
252 intStack.clear() ;
253 longStack.clear() ;
254 floatStack.clear() ;
255 doubleStack.clear() ;
256 }
257
258
259
260
261
262
263
264 /***
265 * Return the current depth of the object stack.
266 *
267 * @return the size of the object stack
268 */
269 public int getCount()
270 {
271 return objectStack.size() ;
272 }
273
274
275 /***
276 * Return the top object on the stack without removing it.
277 *
278 * @return the top object
279 * @throws EmptyStackException if there are no objects on the stack
280 */
281 public Object peek()
282 {
283 return ( objectStack.peek() ) ;
284 }
285
286
287 /***
288 * Return the n'th object down the stack, where 0 is the top element and
289 * [getCount()-1] is the bottom element.
290 *
291 * @param n the element index
292 * @return the element at the index
293 * @throws EmptyStackException if there are no objects on the stack
294 * @throws IndexOutOfBoundsException if the index is out of bounds
295 */
296 public Object peek( int n )
297 {
298 return ( objectStack.peek( n ) ) ;
299 }
300
301
302 /***
303 * Pop the top object off of the stack, and return it.
304 *
305 * @return the top object off of the stack
306 * @throws EmptyStackException if there are no objects on the stack
307 */
308 public Object pop()
309 {
310 return ( objectStack.pop() ) ;
311 }
312
313
314 /***
315 * Push a new object onto the top of the object stack.
316 *
317 * @param object the object to push onto the stack
318 */
319 public void push( Object object )
320 {
321 if ( objectStack.size() == 0 )
322 {
323 root = object ;
324 }
325
326 objectStack.push( object ) ;
327 }
328
329
330
331
332
333
334
335 /***
336 * Return the current depth of the boolean stack.
337 *
338 * @return the size of the boolean stack
339 */
340 public int getBooleanCount()
341 {
342 return booleanStack.size() ;
343 }
344
345
346 /***
347 * Return the top boolean on the stack without removing it.
348 *
349 * @return the top boolean
350 * @throws EmptyStackException if there are no more boolean elements left
351 */
352 public boolean peekBoolean()
353 {
354 return ( booleanStack.peek() ) ;
355 }
356
357
358 /***
359 * Return the n'th boolean down the stack, where 0 is the top element and
360 * [getCount()-1] is the bottom element.
361 *
362 * @param n the element index
363 * @return the element at the index
364 * @throws EmptyStackException if there are no more boolean elements left
365 * @throws IndexOutOfBoundsException if the index is out of bounds
366 */
367 public boolean peekBoolean( int n )
368 {
369 return ( booleanStack.peek( n ) ) ;
370 }
371
372
373 /***
374 * Pop the top boolean off of the stack, and return it.
375 *
376 * @return the top boolean off of the stack
377 * @throws EmptyStackException if the stack is empty
378 */
379 public boolean popBoolean()
380 {
381 return ( booleanStack.pop() ) ;
382 }
383
384
385 /***
386 * Push a new boolean onto the top of the boolean stack.
387 *
388 * @param bit the boolean to push onto the stack
389 */
390 public void pushBoolean( boolean bit )
391 {
392 booleanStack.push( bit ) ;
393 }
394
395
396
397
398
399
400
401 /***
402 * Return the current depth of the char stack.
403 *
404 * @return the size of the char stack
405 */
406 public int getCharCount()
407 {
408 return charStack.size() ;
409 }
410
411
412 /***
413 * Return the top char on the stack without removing it.
414 *
415 * @return the top char
416 * @throws EmptyStackException if there are no more char elements left
417 */
418 public char peekChar()
419 {
420 return ( charStack.peek() ) ;
421 }
422
423
424 /***
425 * Return the n'th char down the stack, where 0 is the top element and
426 * [getCount()-1] is the bottom element.
427 *
428 * @param n the element index
429 * @return the element at the index
430 * @throws EmptyStackException if there are no more char elements left
431 * @throws IndexOutOfBoundsException if the index is out of bounds
432 */
433 public char peekChar( int n )
434 {
435 return ( charStack.peek( n ) ) ;
436 }
437
438
439 /***
440 * Pop the top char off of the stack, and return it.
441 *
442 * @return the top char off of the stack
443 * @throws EmptyStackException if the stack is empty
444 */
445 public char popChar()
446 {
447 return ( charStack.pop() ) ;
448 }
449
450
451 /***
452 * Push a new char onto the top of the char stack.
453 *
454 * @param ch the char to push onto the stack
455 */
456 public void pushChar( char ch )
457 {
458 charStack.push( ch ) ;
459 }
460
461
462
463
464
465
466
467 /***
468 * Return the current depth of the byte stack.
469 *
470 * @return the size of the byte stack
471 */
472 public int getByteCount()
473 {
474 return byteStack.size() ;
475 }
476
477
478 /***
479 * Return the top byte on the stack without removing it.
480 *
481 * @return the top byte
482 * @throws EmptyStackException if there are no more byte elements left
483 */
484 public byte peekByte()
485 {
486 return ( byteStack.peek() ) ;
487 }
488
489
490 /***
491 * Return the n'th byte down the stack, where 0 is the top element and
492 * [getCount()-1] is the bottom element.
493 *
494 * @param n the element index
495 * @return the element at the index
496 * @throws EmptyStackException if there are no more byte elements left
497 * @throws IndexOutOfBoundsException if the index is out of bounds
498 */
499 public byte peekByte( int n )
500 {
501 return ( byteStack.peek( n ) ) ;
502 }
503
504
505 /***
506 * Pop the top byte off of the stack, and return it.
507 *
508 * @return the top byte off of the stack
509 * @throws EmptyStackException if the stack is empty
510 */
511 public byte popByte()
512 {
513 return ( byteStack.pop() ) ;
514 }
515
516
517 /***
518 * Push a new byte onto the top of the byte stack.
519 *
520 * @param bite the byte to push onto the stack
521 */
522 public void pushByte( byte bite )
523 {
524 byteStack.push( bite ) ;
525 }
526
527
528
529
530
531
532
533 /***
534 * Return the current depth of the short stack.
535 *
536 * @return the size of the short stack
537 */
538 public int getShortCount()
539 {
540 return shortStack.size() ;
541 }
542
543
544 /***
545 * Return the top short on the stack without removing it.
546 *
547 * @return the top short
548 * @throws EmptyStackException if there are no more short elements left
549 */
550 public short peekShort()
551 {
552 return ( shortStack.peek() ) ;
553 }
554
555
556 /***
557 * Return the n'th short down the stack, where 0 is the top element and
558 * [getCount()-1] is the bottom element.
559 *
560 * @param n the element index
561 * @return the element at the index
562 * @throws EmptyStackException if there are no more short elements left
563 * @throws IndexOutOfBoundsException if the index is out of bounds
564 */
565 public short peekShort( int n )
566 {
567 return ( shortStack.peek( n ) ) ;
568 }
569
570
571 /***
572 * Pop the top short off of the stack, and return it.
573 *
574 * @return the top short off of the stack
575 * @throws EmptyStackException if the stack is empty
576 */
577 public short popShort()
578 {
579 return ( shortStack.pop() ) ;
580 }
581
582
583 /***
584 * Push a new short onto the top of the short stack.
585 *
586 * @param element the short to push onto the stack
587 */
588 public void pushShort( short element )
589 {
590 shortStack.push( element ) ;
591 }
592
593
594
595
596
597
598
599 /***
600 * Return the current depth of the int stack.
601 *
602 * @return the size of the int stack
603 */
604 public int getIntCount()
605 {
606 return intStack.size() ;
607 }
608
609
610 /***
611 * Return the top int on the stack without removing it.
612 *
613 * @return the top int
614 * @throws EmptyStackException if there are no more int elements left
615 */
616 public int peekInt()
617 {
618 return ( intStack.peek() ) ;
619 }
620
621
622 /***
623 * Return the n'th int down the stack, where 0 is the top element and
624 * [getCount()-1] is the bottom element.
625 *
626 * @param n the element index
627 * @return the element at the index
628 * @throws EmptyStackException if there are no more int elements left
629 * @throws IndexOutOfBoundsException if the index is out of bounds
630 */
631 public int peekInt( int n )
632 {
633 return ( intStack.peek( n ) ) ;
634 }
635
636
637 /***
638 * Pop the top int off of the stack, and return it.
639 *
640 * @return the top int off of the stack
641 * @throws EmptyStackException if the stack is empty
642 */
643 public int popInt()
644 {
645 return ( intStack.pop() ) ;
646 }
647
648
649 /***
650 * Push a new int onto the top of the int stack.
651 *
652 * @param element the int to push onto the stack
653 */
654 public void pushInt( int element )
655 {
656 intStack.push( element ) ;
657 }
658
659
660
661
662
663
664
665 /***
666 * Return the current depth of the long stack.
667 *
668 * @return the size of the long stack
669 */
670 public int getLongCount()
671 {
672 return longStack.size() ;
673 }
674
675
676 /***
677 * Return the top long on the stack without removing it.
678 *
679 * @return the top long
680 * @throws EmptyStackException if there are no more long elements left
681 */
682 public long peekLong()
683 {
684 return ( longStack.peek() ) ;
685 }
686
687
688 /***
689 * Return the n'th long down the stack, where 0 is the top element and
690 * [getCount()-1] is the bottom element.
691 *
692 * @param n the element index
693 * @return the element at the index
694 * @throws EmptyStackException if there are no more long elements left
695 * @throws IndexOutOfBoundsException if the index is out of bounds
696 */
697 public long peekLong( int n )
698 {
699 return ( longStack.peek( n ) ) ;
700 }
701
702
703 /***
704 * Pop the top long off of the stack, and return it.
705 *
706 * @return the top long off of the stack
707 * @throws EmptyStackException if the stack is empty
708 */
709 public long popLong()
710 {
711 return ( longStack.pop() ) ;
712 }
713
714
715 /***
716 * Push a new long onto the top of the long stack.
717 *
718 * @param element the long to push onto the stack
719 */
720 public void pushLong( long element )
721 {
722 longStack.push( element ) ;
723 }
724
725
726
727
728
729
730
731 /***
732 * Return the current depth of the float stack.
733 *
734 * @return the size of the float stack
735 */
736 public int getFloatCount()
737 {
738 return floatStack.size() ;
739 }
740
741
742 /***
743 * Return the top float on the stack without removing it.
744 *
745 * @return the top float
746 * @throws EmptyStackException if there are no more float elements left
747 */
748 public float peekFloat()
749 {
750 return ( floatStack.peek() ) ;
751 }
752
753
754 /***
755 * Return the n'th float down the stack, where 0 is the top element and
756 * [getCount()-1] is the bottom element.
757 *
758 * @param n the element index
759 * @return the element at the index
760 * @throws EmptyStackException if there are no more float elements left
761 * @throws IndexOutOfBoundsException if the index is out of bounds
762 */
763 public float peekFloat( int n )
764 {
765 return ( floatStack.peek( n ) ) ;
766 }
767
768
769 /***
770 * Pop the top float off of the stack, and return it.
771 *
772 * @return the top float off of the stack
773 * @throws EmptyStackException if the stack is empty
774 */
775 public float popFloat()
776 {
777 return ( floatStack.pop() ) ;
778 }
779
780
781 /***
782 * Push a new float onto the top of the float stack.
783 *
784 * @param element the float to push onto the stack
785 */
786 public void pushFloat( float element )
787 {
788 floatStack.push( element ) ;
789 }
790
791
792
793
794
795
796
797 /***
798 * Return the current depth of the double stack.
799 *
800 * @return the size of the double stack
801 */
802 public int getDoubleCount()
803 {
804 return doubleStack.size() ;
805 }
806
807
808 /***
809 * Return the top double on the stack without removing it.
810 *
811 * @return the top double
812 * @throws EmptyStackException if there are no more double elements left
813 */
814 public double peekDouble()
815 {
816 return ( doubleStack.peek() ) ;
817 }
818
819
820 /***
821 * Return the n'th double down the stack, where 0 is the top element and
822 * [getCount()-1] is the bottom element.
823 *
824 * @param n the element index
825 * @return the element at the index
826 * @throws EmptyStackException if there are no more double elements left
827 * @throws IndexOutOfBoundsException if the index is out of bounds
828 */
829 public double peekDouble( int n )
830 {
831 return ( doubleStack.peek( n ) ) ;
832 }
833
834
835 /***
836 * Pop the top double off of the stack, and return it.
837 *
838 * @return the top double off of the stack
839 * @throws EmptyStackException if the stack is empty
840 */
841 public double popDouble()
842 {
843 return ( doubleStack.pop() ) ;
844 }
845
846
847 /***
848 * Push a new double onto the top of the double stack.
849 *
850 * @param element the double to push onto the stack
851 */
852 public void pushDouble( double element )
853 {
854 doubleStack.push( element ) ;
855 }
856
857
858 /***
859 * This method allows you to access the root object that has been
860 * created after decoding.
861 *
862 * @return the root object that has been created after decoding or null if
863 * the rulesBase has not decoded any PDUs yet.
864 */
865 public Object getRoot()
866 {
867 return this.root ;
868 }
869
870
871 /***
872 * Set the Rules implementation object containing our rules collection
873 * and associated matching policy.
874 *
875 * @param rules the rules to add to this rulesBase
876 */
877 public void setRules( Rules rules )
878 {
879 this.rules = rules ;
880 this.rules.setDigester( this ) ;
881 }
882
883
884
885
886
887
888
889 /***
890 * Return the current depth of the Tag stack.
891 *
892 * @return the size of the Tag stack
893 */
894 public int getTagCount()
895 {
896 return tagStack.size() ;
897 }
898
899
900 /***
901 * Return the n'th tag down the Tag stack, where 0 is the top element and
902 * [getCount()-1] is the bottom element.
903 *
904 * @param n the Tag index
905 * @return the Tag at the index
906 * @throws EmptyStackException if there are no more int Tags left
907 * @throws IndexOutOfBoundsException if the index is out of bounds
908 */
909 public int getTag( int n )
910 {
911 return ( tagStack.peek( n ) ) ;
912 }
913
914
915 /***
916 * Gets the raw int for the tag of the TLV currently being processed hence
917 * the tag on the top of the stack. The tag's int has the primitive flag
918 * dubbed out so it appears to represent a primitive TLV even when the TLV
919 * may be constructed.
920 *
921 * @return the raw int for the tag of the TLV currently being processed, or
922 * NO_TOP_TAG if there is no TLV currently being processed.
923 */
924 public int getTopTag()
925 {
926 if ( tagStack.size() <= 0 )
927 {
928 return NO_TOP_TAG ;
929 }
930
931 return tagStack.peek() ;
932 }
933
934
935
936
937
938
939
940 /***
941 * Return the class loader to be used for instantiating application objects
942 * when required. This is determined based upon the following rules:
943 * <ul>
944 * <li>The class loader set by <code>setClassLoader()</code>, if any</li>
945 * <li>The thread context class loader, if it exists and the
946 * <code>useContextClassLoader</code> property is set to true</li>
947 * <li>The class loader used to load the Digester class itself.
948 * </ul>
949 */
950 public ClassLoader getClassLoader()
951 {
952 if ( classLoader != null )
953 {
954 return ( classLoader ) ;
955 }
956
957 if ( useContextClassLoader)
958 {
959 ClassLoader classLoader = Thread.currentThread()
960 .getContextClassLoader() ;
961
962 if ( classLoader != null )
963 {
964 return ( classLoader ) ;
965 }
966 }
967
968 return ( getClass().getClassLoader() ) ;
969 }
970
971
972 /***
973 * Set the class loader to be used for instantiating application objects
974 * when required.
975 *
976 * @param classLoader The new class loader to use, or <code>null</code>
977 * to revert to the standard rules
978 */
979 public void setClassLoader( ClassLoader classLoader )
980 {
981 this.classLoader = classLoader ;
982 }
983
984
985 /***
986 * Return the boolean as to whether the context classloader should be used.
987 */
988 public boolean getUseContextClassLoader()
989 {
990 return useContextClassLoader ;
991 }
992
993
994 /***
995 * Determine whether to use the Context ClassLoader (the one found by
996 * calling <code>Thread.currentThread().getContextClassLoader()</code>)
997 * to resolve/load classes that are defined in various rules. If not
998 * using Context ClassLoader, then the class-loading defaults to
999 * using the calling-class' ClassLoader.
1000 *
1001 * @param use determines whether to use Context ClassLoader.
1002 */
1003 public void setUseContextClassLoader( boolean use )
1004 {
1005 useContextClassLoader = use ;
1006 }
1007
1008
1009
1010
1011
1012
1013
1014 void fireTagEvent( int id, boolean isPrimitive, TypeClass typeClass )
1015 {
1016 Iterator rules = null ;
1017
1018 if ( matched == null )
1019 {
1020 rules = Collections.EMPTY_LIST.iterator() ;
1021 }
1022 else
1023 {
1024 rules = matched.iterator() ;
1025 }
1026
1027 while ( rules.hasNext() )
1028 {
1029 Rule rule = ( Rule ) rules.next() ;
1030
1031 try
1032 {
1033 rule.tag( id, isPrimitive, typeClass ) ;
1034 }
1035 catch ( RuntimeException e )
1036 {
1037 monitor.ruleFailed( this, rule, "Rule.tag() threw exception", e ) ;
1038 throw e ;
1039 }
1040 catch ( Error e )
1041 {
1042 monitor.ruleFailed( this, rule, "Rule.tag() threw error", e ) ;
1043 throw e ;
1044 }
1045 }
1046 }
1047
1048
1049 void fireLengthEvent( int length )
1050 {
1051 Iterator rules = null ;
1052
1053 if ( matched == null )
1054 {
1055 rules = Collections.EMPTY_LIST.iterator() ;
1056 }
1057 else
1058 {
1059 rules = matched.iterator() ;
1060 }
1061
1062 while ( rules.hasNext() )
1063 {
1064 Rule rule = ( Rule ) rules.next() ;
1065
1066 try
1067 {
1068 rule.length( length ) ;
1069 }
1070 catch ( RuntimeException e )
1071 {
1072 monitor.ruleFailed( this, rule, "Rule.length() threw exception", e ) ;
1073 throw e ;
1074 }
1075 catch ( Error e )
1076 {
1077 monitor.ruleFailed( this, rule, "Rule.length() threw error", e ) ;
1078 throw e ;
1079 }
1080 }
1081 }
1082
1083
1084 void fireValueEvent( ByteBuffer buf )
1085 {
1086 Iterator rules = null ;
1087
1088 if ( matched == null )
1089 {
1090 rules = Collections.EMPTY_LIST.iterator() ;
1091 }
1092 else
1093 {
1094 rules = matched.iterator() ;
1095 }
1096
1097 while ( rules.hasNext() )
1098 {
1099 Rule rule = ( Rule ) rules.next() ;
1100
1101 try
1102 {
1103 rule.value( buf ) ;
1104
1105
1106 buf.rewind() ;
1107 }
1108 catch ( RuntimeException e )
1109 {
1110 monitor.ruleFailed( this, rule, "Rule.value() threw exception", e ) ;
1111 throw e ;
1112 }
1113 catch ( Error e )
1114 {
1115 monitor.ruleFailed( this, rule, "Rule.value() threw exception", e ) ;
1116 throw e ;
1117 }
1118 }
1119 }
1120
1121
1122 void fireFinishEvent()
1123 {
1124 Rule rule = null ;
1125 HashSet seen = null ;
1126
1127 if ( matched != null )
1128 {
1129 seen = new HashSet() ;
1130
1131 for ( int i = 0; i < matched.size(); i++ )
1132 {
1133 try
1134 {
1135 rule = ( Rule ) matched.get( i ) ;
1136 rule.finish() ;
1137 monitor.ruleCompleted( this, rule ) ;
1138 seen.add( rule ) ;
1139 }
1140 catch ( RuntimeException e )
1141 {
1142 monitor.ruleFailed( this, rule, "Rule.finish() threw exception", e ) ;
1143 throw e ;
1144 }
1145 catch ( Error e )
1146 {
1147 monitor.ruleFailed( this, rule, "Rule.finish() threw error", e ) ;
1148 throw e ;
1149 }
1150 }
1151 }
1152 }
1153 }