KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > beehive > netui > compiler > xdoclet > typesystem > impl > declaration > DeclarationImpl


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  * $Header:$
17  */

18 package org.apache.beehive.netui.compiler.xdoclet.typesystem.impl.declaration;
19
20 import org.apache.beehive.netui.compiler.JpfLanguageConstants;
21 import org.apache.beehive.netui.compiler.typesystem.declaration.AnnotationInstance;
22 import org.apache.beehive.netui.compiler.typesystem.declaration.AnnotationTypeDeclaration;
23 import org.apache.beehive.netui.compiler.typesystem.declaration.AnnotationTypeElementDeclaration;
24 import org.apache.beehive.netui.compiler.typesystem.declaration.AnnotationValue;
25 import org.apache.beehive.netui.compiler.typesystem.declaration.Declaration;
26 import org.apache.beehive.netui.compiler.typesystem.declaration.Modifier;
27 import org.apache.beehive.netui.compiler.typesystem.type.AnnotationType;
28 import org.apache.beehive.netui.compiler.typesystem.type.ClassType;
29 import org.apache.beehive.netui.compiler.typesystem.type.PrimitiveType;
30 import org.apache.beehive.netui.compiler.typesystem.type.TypeInstance;
31 import org.apache.beehive.netui.compiler.typesystem.type.ArrayType;
32 import org.apache.beehive.netui.compiler.typesystem.type.DeclaredType;
33 import org.apache.beehive.netui.compiler.typesystem.util.SourcePosition;
34 import org.apache.beehive.netui.compiler.xdoclet.typesystem.impl.DelegatingImpl;
35 import org.apache.beehive.netui.compiler.xdoclet.typesystem.impl.env.SourcePositionImpl;
36 import org.apache.beehive.netui.compiler.xdoclet.typesystem.impl.type.AnnotationTypeImpl;
37 import org.apache.beehive.netui.xdoclet.XDocletCompilerUtils;
38 import xjavadoc.XDoc;
39 import xjavadoc.XProgramElement;
40 import xjavadoc.XTag;
41
42 import java.io.BufferedReader JavaDoc;
43 import java.io.IOException JavaDoc;
44 import java.io.InputStream JavaDoc;
45 import java.io.InputStreamReader JavaDoc;
46 import java.io.Reader JavaDoc;
47 import java.io.StreamTokenizer JavaDoc;
48 import java.util.ArrayList JavaDoc;
49 import java.util.Collection JavaDoc;
50 import java.util.HashMap JavaDoc;
51 import java.util.HashSet JavaDoc;
52 import java.util.Iterator JavaDoc;
53 import java.util.List JavaDoc;
54 import java.util.Set JavaDoc;
55 import java.util.StringTokenizer JavaDoc;
56
57 public class DeclarationImpl
58         extends DelegatingImpl
59         implements Declaration, JpfLanguageConstants
60 {
61     private static final String JavaDoc VALIDATION_ERROR_FORWARD_TAG_NAME = "ValidationErrorForward";
62     private static final HashMap JavaDoc MODIFIERS = new HashMap JavaDoc();
63     private static final HashMap JavaDoc MEMBER_ARRAY_ANNOTATIONS = new HashMap JavaDoc();
64     private static final HashMap JavaDoc MEMBER_ANNOTATIONS = new HashMap JavaDoc();
65     private static final HashSet JavaDoc MEMBER_OR_TOPLEVEL_ANNOTATIONS = new HashSet JavaDoc();
66     
67     static
68     {
69         MODIFIERS.put( "abstract", Modifier.ABSTRACT );
70         MODIFIERS.put( "private", Modifier.PRIVATE );
71         MODIFIERS.put( "protected", Modifier.PROTECTED );
72         MODIFIERS.put( "public", Modifier.PUBLIC );
73         MODIFIERS.put( "static", Modifier.STATIC );
74         MODIFIERS.put( "transient", Modifier.TRANSIENT );
75         MODIFIERS.put( "final", Modifier.FINAL );
76         MODIFIERS.put( "synchronized", Modifier.SYNCHRONIZED );
77         MODIFIERS.put( "native", Modifier.NATIVE );
78         
79         MEMBER_ARRAY_ANNOTATIONS.put( ANNOTATION_INTERFACE_PREFIX + FORWARD_TAG_NAME, FORWARDS_ATTR );
80         MEMBER_ARRAY_ANNOTATIONS.put( ANNOTATION_INTERFACE_PREFIX + CATCH_TAG_NAME, CATCHES_ATTR );
81         MEMBER_ARRAY_ANNOTATIONS.put( ANNOTATION_INTERFACE_PREFIX + SIMPLE_ACTION_TAG_NAME, SIMPLE_ACTIONS_ATTR );
82         MEMBER_ARRAY_ANNOTATIONS.put( ANNOTATION_INTERFACE_PREFIX + ACTION_OUTPUT_TAG_NAME, ACTION_OUTPUTS_ATTR );
83         MEMBER_ARRAY_ANNOTATIONS.put( ANNOTATION_INTERFACE_PREFIX + CONDITIONAL_FORWARD_TAG_NAME, CONDITIONAL_FORWARDS_ATTR );
84         MEMBER_ARRAY_ANNOTATIONS.put( ANNOTATION_INTERFACE_PREFIX + MESSAGE_BUNDLE_TAG_NAME, MESSAGE_BUNDLES_ATTR );
85         MEMBER_ARRAY_ANNOTATIONS.put( ANNOTATION_INTERFACE_PREFIX + MESSAGE_ARG_TAG_NAME, MESSAGE_ARGS_ATTR );
86         MEMBER_ARRAY_ANNOTATIONS.put( ANNOTATION_INTERFACE_PREFIX + VALIDATE_CUSTOM_RULE_TAG_NAME, VALIDATE_CUSTOM_ATTR );
87         MEMBER_ARRAY_ANNOTATIONS.put( ANNOTATION_INTERFACE_PREFIX + VALIDATE_CUSTOM_VARIABLE_TAG_NAME, VARIABLES_ATTR );
88         MEMBER_ARRAY_ANNOTATIONS.put( ANNOTATION_INTERFACE_PREFIX + VALIDATION_LOCALE_RULES_TAG_NAME, LOCALE_RULES_ATTR );
89         MEMBER_ARRAY_ANNOTATIONS.put( ANNOTATION_INTERFACE_PREFIX + VALIDATABLE_PROPERTY_TAG_NAME, VALIDATABLE_PROPERTIES_ATTR );
90         MEMBER_ARRAY_ANNOTATIONS.put( ANNOTATION_INTERFACE_PREFIX + VALIDATABLE_BEAN_TAG_NAME, VALIDATABLE_BEANS_ATTR );
91         MEMBER_ARRAY_ANNOTATIONS.put( ANNOTATION_INTERFACE_PREFIX + RAISE_ACTION_TAG_NAME, RAISE_ACTIONS_ATTR );
92         MEMBER_ARRAY_ANNOTATIONS.put( ANNOTATION_INTERFACE_PREFIX + SHARED_FLOW_REF_TAG_NAME, SHARED_FLOW_REFS_ATTR );
93         
94         MEMBER_ANNOTATIONS.put( ANNOTATION_INTERFACE_PREFIX + VALIDATION_ERROR_FORWARD_TAG_NAME, VALIDATION_ERROR_FORWARD_ATTR );
95         MEMBER_ANNOTATIONS.put( ANNOTATION_INTERFACE_PREFIX + VALIDATE_REQUIRED_TAG_NAME, VALIDATE_REQUIRED_ATTR );
96         MEMBER_ANNOTATIONS.put( ANNOTATION_INTERFACE_PREFIX + VALIDATE_MIN_LENGTH_TAG_NAME, VALIDATE_MIN_LENGTH_ATTR );
97         MEMBER_ANNOTATIONS.put( ANNOTATION_INTERFACE_PREFIX + VALIDATE_MAX_LENGTH_TAG_NAME, VALIDATE_MAX_LENGTH_ATTR );
98         MEMBER_ANNOTATIONS.put( ANNOTATION_INTERFACE_PREFIX + VALIDATE_MASK_TAG_NAME, VALIDATE_MASK_ATTR );
99         MEMBER_ANNOTATIONS.put( ANNOTATION_INTERFACE_PREFIX + VALIDATE_TYPE_TAG_NAME, VALIDATE_TYPE_ATTR );
100         MEMBER_ANNOTATIONS.put( ANNOTATION_INTERFACE_PREFIX + VALIDATE_DATE_TAG_NAME, VALIDATE_DATE_ATTR );
101         MEMBER_ANNOTATIONS.put( ANNOTATION_INTERFACE_PREFIX + VALIDATE_RANGE_TAG_NAME, VALIDATE_RANGE_ATTR );
102         MEMBER_ANNOTATIONS.put( ANNOTATION_INTERFACE_PREFIX + VALIDATE_CREDIT_CARD_TAG_NAME, VALIDATE_CREDIT_CARD_ATTR );
103         MEMBER_ANNOTATIONS.put( ANNOTATION_INTERFACE_PREFIX + VALIDATE_EMAIL_TAG_NAME, VALIDATE_EMAIL_ATTR );
104         MEMBER_ANNOTATIONS.put( ANNOTATION_INTERFACE_PREFIX + VALIDATE_VALID_WHEN_TAG_NAME, VALIDATE_VALID_WHEN_ATTR );
105         
106         MEMBER_OR_TOPLEVEL_ANNOTATIONS.add( ANNOTATION_INTERFACE_PREFIX + VALIDATABLE_PROPERTY_TAG_NAME );
107     }
108     
109     private HashSet JavaDoc _modifiers;
110     private AnnotationInstance[] _annotations;
111     
112     public DeclarationImpl( XProgramElement delegate )
113     {
114         super( delegate );
115         ArrayList JavaDoc annotations = getAnnotations( delegate );
116         _annotations = ( AnnotationInstance[] ) annotations.toArray( new AnnotationInstance[ annotations.size() ] );
117     }
118
119     public String JavaDoc getDocComment()
120     {
121         return getDelegateXProgramElement().getDoc().getCommentText();
122     }
123
124     public AnnotationInstance[] getAnnotationInstances()
125     {
126         return _annotations;
127     }
128
129     public Set JavaDoc getModifiers()
130     {
131         if ( _modifiers == null )
132         {
133             HashSet JavaDoc modifiers = new HashSet JavaDoc();
134             StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc( getDelegateXProgramElement().getModifiers() );
135             
136             while ( tok.hasMoreTokens() )
137             {
138                 String JavaDoc modifierString = tok.nextToken();
139                 Modifier modifier = ( Modifier ) MODIFIERS.get( modifierString );
140                 assert modifier != null : "unrecognized modifier: " + modifierString;
141                 modifiers.add( modifier );
142             }
143             
144             _modifiers = modifiers;
145         }
146         
147         return _modifiers;
148     }
149
150     public String JavaDoc getSimpleName()
151     {
152         String JavaDoc name = getDelegateXProgramElement().getName();
153         int lastDot = name.lastIndexOf( '.' );
154         return lastDot != -1 ? name.substring( lastDot + 1 ) : name;
155     }
156
157     public SourcePosition getPosition()
158     {
159         return SourcePositionImpl.get( getDelegateXProgramElement() );
160     }
161
162     public boolean hasModifier( Modifier modifier )
163     {
164         return getModifiers().contains( modifier );
165     }
166
167     protected XProgramElement getDelegateXProgramElement()
168     {
169         return ( XProgramElement ) super.getDelegate();
170     }
171     
172     /** Map of String intermediate-name (e.g., "Jpf.Action") to AnnotationTypeDeclaration */
173     private static HashMap JavaDoc ANNOTATIONS = new HashMap JavaDoc();
174     private static AnnotationTypeDeclaration[] ALL_ANNOTATIONS;
175     
176     static
177     {
178         parseAnnotations();
179         ALL_ANNOTATIONS = ( AnnotationTypeDeclaration[] )
180                 ANNOTATIONS.values().toArray( new AnnotationTypeDeclaration[ ANNOTATIONS.size() ] );
181     }
182     
183     public static AnnotationTypeDeclaration[] getAllAnnotations()
184     {
185         return ALL_ANNOTATIONS;
186     }
187     
188     private static StreamTokenizer JavaDoc getJavaTokenizer( Reader JavaDoc reader )
189     {
190         StreamTokenizer JavaDoc tok = new StreamTokenizer JavaDoc( reader );
191         tok.eolIsSignificant( false );
192         tok.lowerCaseMode( false );
193         tok.parseNumbers();
194         tok.slashSlashComments( true );
195         tok.slashStarComments( true );
196         tok.wordChars( '_', '_' );
197         tok.wordChars( '@', '@' );
198         tok.wordChars( '[', '[' );
199         tok.wordChars( ']', ']' );
200         tok.wordChars( '.', '.' );
201         tok.wordChars( '"', '"' );
202         tok.wordChars( '-', '-' );
203         return tok;
204     }
205     
206     private static void parseAnnotations()
207     {
208         try
209         {
210             String JavaDoc annotationsSource = ANNOTATIONS_CLASSNAME.replace( '.', '/' ) + ".java";
211             InputStream JavaDoc in = DeclarationImpl.class.getClassLoader().getResourceAsStream( annotationsSource );
212             assert in != null : "annotations source not found: " + annotationsSource;
213             BufferedReader JavaDoc reader = new BufferedReader JavaDoc( new InputStreamReader JavaDoc( in ) );
214             HashMap JavaDoc enums = new HashMap JavaDoc(); // String enumTypeName -> HashSet values
215
StreamTokenizer JavaDoc tok = getJavaTokenizer( reader );
216             
217             
218             String JavaDoc interfaceQualifier = null;
219             String JavaDoc packageName = null;
220             
221             while ( tok.nextToken() != StreamTokenizer.TT_EOF )
222             {
223                 switch ( tok.ttype )
224                 {
225                     case StreamTokenizer.TT_WORD:
226                         String JavaDoc str = tok.sval;
227                         
228                         if ( packageName == null && str.equals( "package" ) )
229                         {
230                             packageName = assertWord( tok );
231                         }
232                         else if ( str.equals( "public" ) )
233                         {
234                             str = assertWord( tok );
235                             
236                             if ( str.equals( "interface" ) )
237                             {
238                                 interfaceQualifier = assertWord( tok ) + '.';
239                                 assertChar( tok, '{' );
240                             }
241                             else if ( str.equals( "@interface" ) )
242                             {
243                                 AnnotationTypeDeclarationImpl ann =
244                                         readAnnotation( tok, interfaceQualifier, packageName, enums );
245                                 ANNOTATIONS.put( ann.getIntermediateName(), ann );
246                                 
247                                 //
248
// Special case:
249
// validationErrorForward=@Jpf.Forward(...)
250
// looks like this in our world:
251
// @Jpf.ValidationErrorForward(...)
252
// Here we dynamically create a new ValidationErrorForward annotation based on Forward.
253
//
254
if ( ann.getSimpleName().equals( FORWARD_TAG_NAME ) )
255                                 {
256                                     AnnotationTypeDeclarationImpl validationErrorForwardAnn =
257                                         new AnnotationTypeDeclarationImpl( ann, VALIDATION_ERROR_FORWARD_TAG_NAME,
258                                                                            interfaceQualifier );
259                                     ANNOTATIONS.put( ANNOTATION_INTERFACE_PREFIX + VALIDATION_ERROR_FORWARD_TAG_NAME,
260                                                      validationErrorForwardAnn );
261                                 }
262                             }
263                             else if ( str.equals( "enum" ) )
264                             {
265                                 readEnum( tok, enums );
266                             }
267                         }
268                         else if ( str.charAt( 0 ) == '@' )
269                         {
270                             ignoreAnnotation( tok );
271                         }
272                         break;
273                     
274                     case StreamTokenizer.TT_NUMBER:
275                         break;
276                         
277                     default:
278                         char c = ( char ) tok.ttype;
279                         
280                         if ( c == '}' )
281                         {
282                             assert interfaceQualifier != null;
283                             interfaceQualifier = null;
284                         }
285                 }
286             }
287             
288             reader.close();
289         }
290         catch ( IOException JavaDoc e )
291         {
292             assert false : e;
293         }
294     }
295     
296     private static String JavaDoc assertWord( StreamTokenizer JavaDoc tok )
297             throws IOException JavaDoc
298     {
299         tok.nextToken();
300         assert tok.ttype == StreamTokenizer.TT_WORD : tok.ttype;
301         return tok.sval;
302     }
303     
304     private static void assertChar( StreamTokenizer JavaDoc tok, char c )
305         throws IOException JavaDoc
306     {
307         tok.nextToken();
308         assert tok.ttype == c : tok.ttype;
309     }
310     
311     private static AnnotationTypeDeclarationImpl readAnnotation( StreamTokenizer JavaDoc tok, String JavaDoc interfaceQualifier,
312                                                                  String JavaDoc packageName, HashMap JavaDoc enums )
313         throws IOException JavaDoc
314     {
315         String JavaDoc annotationName = assertWord( tok );
316         ArrayList JavaDoc memberDecls = new ArrayList JavaDoc();
317         assertChar( tok, '{' );
318         
319         while ( tok.nextToken() == StreamTokenizer.TT_WORD )
320         {
321             String JavaDoc memberType = tok.sval;
322             HashSet JavaDoc enumVals = ( HashSet JavaDoc ) enums.get( memberType );
323             
324             tok.nextToken();
325             if ( tok.ttype == '<' ) // ignore generics
326
{
327                 while ( tok.nextToken() != '>' )
328                 {
329                     assert tok.ttype != StreamTokenizer.TT_EOF;
330                     assert tok.ttype != ';';
331                 }
332                 tok.nextToken();
333             }
334             assert tok.ttype == StreamTokenizer.TT_WORD;
335             String JavaDoc memberName = tok.sval;
336             assertChar( tok, '(' );
337             assertChar( tok, ')' );
338             
339             Object JavaDoc defaultVal = null;
340             
341             if ( tok.nextToken() == StreamTokenizer.TT_WORD )
342             {
343                 assert tok.sval.equals( "default" );
344                 
345                 tok.nextToken();
346                 if ( tok.ttype == '{' )
347                 {
348                     assertChar( tok, '}' );
349                     defaultVal = new ArrayList JavaDoc();
350                 }
351                 else
352                 {
353                     assert tok.ttype == StreamTokenizer.TT_WORD || tok.ttype == StreamTokenizer.TT_NUMBER : tok.ttype;
354                     
355                     if ( tok.ttype == StreamTokenizer.TT_NUMBER )
356                     {
357                         defaultVal = getNumericDefaultVal( memberType, tok.nval );
358                     }
359                     else
360                     {
361                         String JavaDoc defaultString = tok.sval;
362                         
363                         if ( defaultString.charAt( 0 ) == '@' )
364                         {
365                             // It's a default value that is an annotation. We ignore these for now.
366
ignoreAnnotation( tok );
367                         }
368                         else
369                         {
370                             if ( memberType.equals( "String" ) )
371                             {
372                                 assert defaultString.charAt( 0 ) == '"' : defaultString;
373                                 int len = defaultString.length();
374                                 assert len > 1 && defaultString.charAt( len - 1 ) == '"' : defaultString;
375                                 defaultVal = defaultString.substring( 0, len - 1 );
376                             }
377                             else if ( memberType.equals( "boolean" ) )
378                             {
379                                 defaultVal = Boolean.valueOf( defaultString );
380                             }
381                             else if ( memberType.equals( "Class") )
382                             {
383                                 assert defaultString.endsWith( ".class" );
384                                 defaultVal = defaultString.substring( 0, defaultString.indexOf( ".class" ) );
385                             }
386                             else
387                             {
388                                 defaultVal = readDefaultEnumVal( defaultString, memberType, enumVals );
389                             }
390                         }
391                     }
392                 }
393                 
394                 tok.nextToken();
395             }
396             
397             assert tok.ttype == ';';
398             
399             if ( enumVals != null ) memberType = "String";
400             memberDecls.add( new AnnotationTypeElementDeclarationImpl( memberName, memberType, defaultVal, enumVals ) );
401         }
402         
403         assert tok.ttype == '}';
404         
405         AnnotationTypeElementDeclaration[] memberArray = ( AnnotationTypeElementDeclaration[] )
406                 memberDecls.toArray( new AnnotationTypeElementDeclaration[ memberDecls.size() ] );
407         return new AnnotationTypeDeclarationImpl( annotationName, interfaceQualifier, packageName, memberArray );
408     }
409     
410     private static String JavaDoc readDefaultEnumVal( String JavaDoc defaultString, String JavaDoc memberType, HashSet JavaDoc enumVals )
411     {
412         int dot = defaultString.indexOf( '.' );
413         assert dot != -1 : "expected an enum value: " + defaultString;
414         String JavaDoc type = defaultString.substring( 0, dot );
415         assert type.equals( memberType ) : "expected enum " + memberType + ", got " + type;
416         assert enumVals != null : "no enum " + memberType
417                                   + " defined; currently, enum must be defined before its use";
418         String JavaDoc defaultVal = defaultString.substring( dot + 1 );
419         assert enumVals.contains( defaultVal ) :
420                 "invalid enum field " + defaultVal + " on enum " + type;
421         return defaultVal;
422     }
423     
424     private static Object JavaDoc getNumericDefaultVal( String JavaDoc expectedType, double defaultNumber )
425     {
426         if ( expectedType.equals( "int" ) )
427         {
428             return new Integer JavaDoc( ( int ) defaultNumber );
429         }
430         else if ( expectedType.equals( "long" ) )
431         {
432             return new Long JavaDoc( ( long ) defaultNumber );
433         }
434         else if ( expectedType.equals( "float" ) )
435         {
436             return new Float JavaDoc( ( float ) defaultNumber );
437         }
438         else if ( expectedType.equals( "double" ) )
439         {
440             return new Double JavaDoc( defaultNumber );
441         }
442         
443         assert false : "type " + expectedType + " cannot accept value " + defaultNumber;
444         return null;
445     }
446     
447     private static void ignoreAnnotation( StreamTokenizer JavaDoc tok )
448         throws IOException JavaDoc
449     {
450         while ( tok.nextToken() != ')' )
451         {
452             assert tok.ttype != StreamTokenizer.TT_EOF;
453             assert tok.ttype != ';';
454         }
455     }
456     
457     private static void readEnum( StreamTokenizer JavaDoc tok, HashMap JavaDoc enums )
458             throws IOException JavaDoc
459     {
460         String JavaDoc enumName = assertWord( tok );
461         
462         assertChar( tok, '{' );
463         HashSet JavaDoc fieldNames = new HashSet JavaDoc();
464         
465         while ( true )
466         {
467             fieldNames.add( assertWord( tok ) );
468             tok.nextToken();
469             if ( tok.ttype == '}' ) break;
470             assert tok.ttype == ',' : tok.ttype; // for now, we only do very simple enums.
471
}
472         
473         enums.put( enumName, fieldNames );
474     }
475     
476     /**
477      * Get all the annotations for the given element.
478      * @param element the element (class, method, etc.) to examine
479      * @return an ArrayList of AnnotationInstances.
480      */

481     private static ArrayList JavaDoc getAnnotations( XProgramElement element )
482     {
483         XDoc doc = element.getDoc();
484         ArrayList JavaDoc annotations = new ArrayList JavaDoc();
485         List JavaDoc tags = doc != null ? doc.getTags() : null;
486         ArrayList JavaDoc parentAnnotations = new ArrayList JavaDoc(); // hierarchy of parent annotations, e.g., Action -> Forward -> ...
487

488         if ( tags == null ) return annotations;
489         
490         for ( Iterator JavaDoc i = tags.iterator(); i.hasNext(); )
491         {
492             XTag tag = ( XTag ) i.next();
493             AnnotationTypeDeclaration decl = ( AnnotationTypeDeclaration ) ANNOTATIONS.get( tag.getName() );
494             
495             if ( decl != null )
496             {
497                 AnnotationType type = new AnnotationTypeImpl( decl );
498                 Collection JavaDoc attrNames = tag.getAttributeNames();
499                 HashMap JavaDoc elementValues = new HashMap JavaDoc();
500                 
501                 for ( Iterator JavaDoc j = attrNames.iterator(); j.hasNext(); )
502                 {
503                     String JavaDoc attrName = ( String JavaDoc ) j.next();
504                     AnnotationTypeElementDeclaration memberDecl = decl.getMember( attrName );
505                     SourcePositionImpl pos = SourcePositionImpl.get( tag, attrName, element );
506                     Object JavaDoc val = parseValue( memberDecl, tag.getAttributeValue( attrName ), pos );
507                     AnnotationValue value = new AnnotationValueImpl( val, pos, memberDecl );
508                     elementValues.put( memberDecl, value );
509                 }
510                 
511                 AnnotationInstanceImpl ann = new AnnotationInstanceImpl( tag, element, type, elementValues );
512                 
513                 String JavaDoc memberName = ( String JavaDoc ) MEMBER_ARRAY_ANNOTATIONS.get( tag.getName() );
514                 
515                 if ( memberName != null )
516                 {
517                     if ( ! addAnnotationToParent( annotations, ann, memberName, true, parentAnnotations ) )
518                     {
519                         annotations.add( ann );
520                     }
521                 }
522                 else if ( ( memberName = ( String JavaDoc ) MEMBER_ANNOTATIONS.get( tag.getName() ) ) != null )
523                 {
524                     if ( ! addAnnotationToParent( annotations, ann, memberName, false, parentAnnotations ) )
525                     {
526                         annotations.add( ann );
527                     }
528                 }
529                 else
530                 {
531                     annotations.add( ann );
532                 }
533                 
534                 for ( int j = 0, len = parentAnnotations.size(); j < len; ++j )
535                 {
536                     AnnotationInstanceImpl parentAnn = ( AnnotationInstanceImpl ) parentAnnotations.get( j );
537                     
538                     if ( parentAnn.getAnnotationType().equals( ann.getAnnotationType() ) )
539                     {
540                         // We found an annotation of this type in the hierarchy of parent annotations.
541
// Replace it and blow away everything after it.
542
for ( int k = j; k < len; ++k )
543                         {
544                             parentAnnotations.remove( j );
545                         }
546                         break;
547                     }
548                 }
549                 
550                 parentAnnotations.add( ann );
551             }
552         }
553         
554         return annotations;
555     }
556     
557     private static boolean addAnnotationToParent( ArrayList JavaDoc annotations, AnnotationInstanceImpl ann, String JavaDoc memberArrayName,
558                                                   boolean memberIsArray, ArrayList JavaDoc parentAnnotations )
559     {
560         if ( annotations.size() == 0 )
561         {
562             String JavaDoc annName = ann.getDelegateXTag().getName();
563             if ( MEMBER_OR_TOPLEVEL_ANNOTATIONS.contains( annName ) ) return false;
564             
565             XDocletCompilerUtils.addError( ann.getPosition(), "error.no-parent-annotation",
566                                            new String JavaDoc[]{ ann.getAnnotationType().getAnnotationTypeDeclaration().getQualifiedName() } );
567         }
568         else
569         {
570             AnnotationInstanceImpl foundTheRightParent = null;
571             
572             //
573
// Look through the hierarchy of parent annotations, for the first one that can accept the given annotation
574
// as a child.
575
//
576
for ( int i = parentAnnotations.size() - 1; i >= 0; --i )
577             {
578                 AnnotationInstanceImpl parentAnnotation = ( AnnotationInstanceImpl ) parentAnnotations.get( i );
579                 AnnotationTypeElementDeclaration elementDecl =
580                         parentAnnotation.getAnnotationType().getAnnotationTypeDeclaration().getMember( memberArrayName );
581                 
582                 if ( elementDecl != null )
583                 {
584                     foundTheRightParent = parentAnnotation;
585                     
586                     //
587
// Blow away everything past the found parent annotation in the hierarchy.
588
//
589
for ( int j = i + 1, len = parentAnnotations.size(); j < len; ++j )
590                     {
591                         parentAnnotations.remove( i + 1 );
592                     }
593                     
594                     break;
595                 }
596             }
597             
598             if ( foundTheRightParent != null )
599             {
600                 foundTheRightParent.addElementValue( memberArrayName, memberIsArray, ann, ann.getPosition() );
601             }
602             else
603             {
604                 String JavaDoc annName = ann.getDelegateXTag().getName();
605                 if ( MEMBER_OR_TOPLEVEL_ANNOTATIONS.contains( annName ) ) return false;
606                 
607                 XDocletCompilerUtils.addError( ann.getPosition(), "error.no-parent-annotation",
608                                                new String JavaDoc[]{ ann.getAnnotationType().getAnnotationTypeDeclaration().getQualifiedName() } );
609             }
610         }
611         
612         return true;
613     }
614     
615     private static Object JavaDoc parseValue( AnnotationTypeElementDeclaration memberDecl, String JavaDoc strValue, SourcePositionImpl pos )
616     {
617         TypeInstance type = memberDecl.getReturnType();
618     
619         if ( type instanceof ClassType )
620         {
621             ClassType classType = ( ClassType ) type;
622             String JavaDoc typeName = classType.getClassTypeDeclaration().getQualifiedName();
623             
624             if ( typeName.equals( "java.lang.String" ) )
625             {
626                 return strValue;
627             }
628             else if ( typeName.equals( "java.lang.Class" ) )
629             {
630                 TypeInstance retVal = XDocletCompilerUtils.resolveType( strValue, false, pos.getOuterClass() );
631                 
632                 if ( retVal == null )
633                 {
634                     XDocletCompilerUtils.addError( pos, "error.unknown-class",
635                                                    new String JavaDoc[]{ strValue, memberDecl.getSimpleName() } );
636                 }
637                 
638                 return XDocletCompilerUtils.resolveType( strValue, true, pos.getOuterClass() );
639             }
640             else
641             {
642                 assert false : "unexpected type in annotation declaration: " + typeName;
643             }
644         }
645         else if ( type instanceof ArrayType )
646         {
647             ArrayType arrayType = ( ArrayType ) type;
648             TypeInstance componentType = arrayType.getComponentType();
649             
650             // We only handle an array of strings -- nothing else at this point.
651
assert componentType instanceof DeclaredType : componentType.getClass().getName();
652             assert ( ( DeclaredType ) componentType ).getDeclaration().getQualifiedName().equals( String JavaDoc.class.getName() )
653                     : ( ( DeclaredType ) componentType ).getDeclaration().getQualifiedName();
654             StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc( strValue, "," );
655             ArrayList JavaDoc arrayValues = new ArrayList JavaDoc();
656             while ( tok.hasMoreTokens() )
657             {
658                 arrayValues.add( new AnnotationValueImpl( tok.nextToken().trim(), pos, memberDecl ) );
659             }
660             return arrayValues;
661         }
662         
663         assert type instanceof PrimitiveType : type.getClass().getName();
664         switch ( ( ( PrimitiveType ) type ).getKind().asInt() )
665         {
666             case PrimitiveType.Kind.INT_BOOLEAN:
667                 return Boolean.valueOf( strValue );
668                 
669             case PrimitiveType.Kind.INT_BYTE:
670                 return new Byte JavaDoc( strValue );
671                 
672             case PrimitiveType.Kind.INT_SHORT:
673                 return new Short JavaDoc( strValue );
674                 
675             case PrimitiveType.Kind.INT_INT:
676                 return new Integer JavaDoc( strValue );
677                 
678             case PrimitiveType.Kind.INT_LONG:
679                 return new Long JavaDoc( strValue );
680                 
681             case PrimitiveType.Kind.INT_FLOAT:
682                 return new Float JavaDoc( strValue );
683                 
684             case PrimitiveType.Kind.INT_DOUBLE:
685                 return new Double JavaDoc( strValue );
686         }
687     
688         assert false : "unrecognized type: " + type.toString();
689         return null;
690     }
691 }
692
Popular Tags