View Javadoc

1   /*
2    *   Copyright 2004 The Apache Software Foundation
3    *
4    *   Licensed under the Apache License, Version 2.0 (the "License");
5    *   you may not use this file except in compliance with the License.
6    *   You may obtain a copy of the License at
7    *
8    *       http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *   Unless required by applicable law or agreed to in writing, software
11   *   distributed under the License is distributed on an "AS IS" BASIS,
12   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *   See the License for the specific language governing permissions and
14   *   limitations under the License.
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     // StatefulDecoder implementation
136     // ------------------------------------------------------------------------
137 
138 
139     /* (non-Javadoc)
140      * @see org.apache.asn1.codec.stateful.StatefulDecoder
141      * #decode(java.lang.Object)
142      */
143     public void decode( Object encoded ) throws DecoderException
144     {
145         decoder.decode( encoded ) ;
146     }
147 
148 
149     // ------------------------------------------------------------------------
150     // BERDecoderCallback implementation
151     // ------------------------------------------------------------------------
152 
153 
154     class DigesterCallback implements BERDecoderCallback
155     {
156         /* (non-Javadoc)
157          * @see org.apache.asn1.ber.BERDecoderCallback#tagDecoded(
158          * org.apache.asn1.ber.Tuple)
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         /* (non-Javadoc)
169          * @see org.apache.asn1.ber.BERDecoderCallback#lengthDecoded(
170          * org.apache.asn1.ber.Tuple)
171          */
172         public void lengthDecoded( Tuple tlv )
173         {
174             fireLengthEvent( tlv.getLength() ) ;
175         }
176 
177 
178         /* (non-Javadoc)
179          * @see org.apache.asn1.ber.BERDecoderCallback#partialValueDecoded(
180          * org.apache.asn1.ber.Tuple)
181          */
182         public void partialValueDecoded( Tuple tlv )
183         {
184             fireValueEvent( tlv.getLastValueChunk() ) ;
185         }
186 
187 
188         /* (non-Javadoc)
189          * @see org.apache.asn1.codec.stateful.DecoderCallback#decodeOccurred(
190          * org.apache.asn1.codec.stateful.StatefulDecoder, java.lang.Object)
191          */
192         public void decodeOccurred( StatefulDecoder decoder, Object decoded )
193         {
194             /*
195              * must reset the matched rules here because the nested TLVs
196              * overwrite the matched rules of a constructed TLV so it must
197              * be set once again
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     // Digester like methods
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     // Stack Operations
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     // Primitive boolean Stack Operations
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     // Primitive char Stack Operations
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     // Primitive byte Stack Operations
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     // Primitive short Stack Operations
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     // Primitive int Stack Operations
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     // Primitive long Stack Operations
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     // Primitive float Stack Operations
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     // Primitive double Stack Operations
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     // Read Only Tag Stack (Primitive IntStack) Operations
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     // ClassLoader Related Methods
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     // Event fireing routines that trigger rules
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                 // need to rewind the buffer after rule exhausts it
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 }