KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > beehive > netui > compiler > FlowControllerChecker


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;
19
20 import org.apache.beehive.netui.compiler.genmodel.GenStrutsApp;
21 import org.apache.beehive.netui.compiler.grammar.ActionGrammar;
22 import org.apache.beehive.netui.compiler.grammar.ExceptionHandlerGrammar;
23 import org.apache.beehive.netui.compiler.grammar.WebappPathType;
24 import org.apache.beehive.netui.compiler.typesystem.declaration.AnnotationInstance;
25 import org.apache.beehive.netui.compiler.typesystem.declaration.AnnotationValue;
26 import org.apache.beehive.netui.compiler.typesystem.declaration.ClassDeclaration;
27 import org.apache.beehive.netui.compiler.typesystem.declaration.FieldDeclaration;
28 import org.apache.beehive.netui.compiler.typesystem.declaration.MethodDeclaration;
29 import org.apache.beehive.netui.compiler.typesystem.declaration.Modifier;
30 import org.apache.beehive.netui.compiler.typesystem.declaration.PackageDeclaration;
31 import org.apache.beehive.netui.compiler.typesystem.declaration.ParameterDeclaration;
32 import org.apache.beehive.netui.compiler.typesystem.declaration.TypeDeclaration;
33 import org.apache.beehive.netui.compiler.typesystem.env.AnnotationProcessorEnvironment;
34 import org.apache.beehive.netui.compiler.typesystem.type.ClassType;
35 import org.apache.beehive.netui.compiler.typesystem.type.TypeInstance;
36 import org.apache.xmlbeans.XmlException;
37
38 import java.io.File JavaDoc;
39 import java.io.FilenameFilter JavaDoc;
40 import java.io.IOException JavaDoc;
41 import java.util.ArrayList JavaDoc;
42 import java.util.Collection JavaDoc;
43 import java.util.HashMap JavaDoc;
44 import java.util.HashSet JavaDoc;
45 import java.util.Iterator JavaDoc;
46 import java.util.List JavaDoc;
47 import java.util.Map JavaDoc;
48 import java.util.Set JavaDoc;
49
50
51 public abstract class FlowControllerChecker
52         extends BaseChecker
53         implements JpfLanguageConstants
54 {
55     private AnnotationGrammar _controllerGrammar;
56     private AnnotationGrammar _actionGrammar;
57     private AnnotationGrammar _exceptionHandlerGrammar;
58     private FormBeanChecker _formBeanChecker;
59     private Map JavaDoc _checkResultMap;
60     
61     protected FlowControllerChecker( AnnotationProcessorEnvironment env, FlowControllerInfo fcInfo, Diagnostics diags )
62     {
63         super( env, fcInfo, diags );
64     }
65     
66     protected void doAdditionalClassChecks( ClassDeclaration jpfClass )
67     {
68     }
69     
70     protected Map JavaDoc getCheckResultMap()
71     {
72         return _checkResultMap;
73     }
74     
75     protected abstract String JavaDoc getDesiredBaseClass( ClassDeclaration jclass );
76     
77     protected abstract AnnotationGrammar getControllerGrammar();
78     
79     public Map JavaDoc onCheck( ClassDeclaration jclass )
80             throws FatalCompileTimeException
81     {
82         FlowControllerInfo fcInfo = getFCSourceFileInfo();
83         
84         _checkResultMap = new HashMap JavaDoc();
85         _controllerGrammar = getControllerGrammar();
86         _actionGrammar = new ActionGrammar( getEnv(), getDiagnostics(), getRuntimeVersionChecker(), fcInfo );
87         _exceptionHandlerGrammar =
88         new ExceptionHandlerGrammar( getEnv(), getDiagnostics(), getRuntimeVersionChecker(), fcInfo );
89         _formBeanChecker = new FormBeanChecker( getEnv(), getDiagnostics() );
90         
91         fcInfo.startBuild( getEnv(), jclass );
92         
93         try
94         {
95             return onCheckInternal( jclass );
96         }
97         finally
98         {
99             fcInfo.endBuild();
100         }
101     }
102     
103     private Map JavaDoc onCheckInternal( ClassDeclaration jclass )
104             throws FatalCompileTimeException
105     {
106         FlowControllerInfo fcInfo = getFCSourceFileInfo();
107         
108         //
109
// Check the base class.
110
//
111
String JavaDoc desiredBaseClass = getDesiredBaseClass( jclass );
112         if ( desiredBaseClass != null && ! CompilerUtils.isAssignableFrom( desiredBaseClass, jclass, getEnv() ) )
113         {
114             getDiagnostics().addError( jclass, "error.does-not-extend-base", desiredBaseClass );
115         }
116         
117         //
118
// Check the annotations on the class.
119
//
120
startCheckClass( jclass );
121         
122         //
123
// Check the fields. Note that we're checking public and protected inherited fields, too.
124
//
125
Collection JavaDoc fields = CompilerUtils.getClassFields( jclass );
126         
127         for ( Iterator JavaDoc ii = fields.iterator(); ii.hasNext(); )
128         {
129             FieldDeclaration field = ( FieldDeclaration ) ii.next();
130             checkField( field, jclass );
131         }
132
133         //
134
// Check the methods. Note that we're checking public and protected inherited methods, too.
135
//
136
MethodDeclaration[] methods = CompilerUtils.getClassMethods( jclass, null );
137         
138         for ( int i = 0; i < methods.length; i++ )
139         {
140             MethodDeclaration method = methods[i];
141             TypeDeclaration declaringType = method.getDeclaringType();
142             
143             //
144
// Only check the method if it's in this class, or if it's inherited from a class that's *not* on sourcepath
145
// (i.e., its SourcePosition is null).
146
//
147
if ( declaringType.equals( jclass ) || declaringType.getPosition() == null )
148             checkMethod( method, jclass );
149         }
150
151         //
152
// Check the inner classes.
153
//
154
Collection JavaDoc innerTypes = CompilerUtils.getClassNestedTypes( jclass );
155         
156         for ( Iterator JavaDoc ii = innerTypes.iterator(); ii.hasNext(); )
157         {
158             TypeDeclaration innerType = ( TypeDeclaration ) ii.next();
159             if ( innerType instanceof ClassDeclaration ) checkInnerClass( ( ClassDeclaration ) innerType );
160         }
161         
162         //
163
// Run additional .jpf- or .app-specific checks.
164
//
165
doAdditionalClassChecks( jclass );
166         
167         //
168
// Runtime performance enhancement: enable saving of previous-page and previous-action information based on
169
// whether there were Forwards that contained navigateTo attributes.
170
//
171
enableNavigateTo( jclass, fcInfo.getMergedControllerAnnotation(), fcInfo );
172         Map JavaDoc sharedFlowTypes = fcInfo.getSharedFlowTypes();
173         
174         if ( sharedFlowTypes != null )
175         {
176             for ( Iterator JavaDoc ii = sharedFlowTypes.values().iterator(); ii.hasNext(); )
177             {
178                 TypeDeclaration sharedFlowType = ( TypeDeclaration ) ii.next();
179                 //
180
// Saving of previous-page/previous-action info must be enabled if any of the referenced shared flows
181
// use this feature.
182
//
183
enableNavigateTo( sharedFlowType, new MergedControllerAnnotation( sharedFlowType ), fcInfo );
184             }
185         }
186         
187         endCheckClass( jclass );
188         _checkResultMap.put( JpfLanguageConstants.ExtraInfoKeys.flowControllerInfo, fcInfo );
189         return _checkResultMap;
190     }
191     
192     private static void enableNavigateTo( TypeDeclaration flowControllerClass, MergedControllerAnnotation controllerAnn,
193                                           FlowControllerInfo fcInfo )
194     {
195         //
196
// Look through Forwards and SimpleActions in the Controller annotation.
197
//
198
enableNavigateTo( controllerAnn.getForwards(), fcInfo );
199         enableNavigateTo( controllerAnn.getSimpleActions(), fcInfo );
200         
201         //
202
// Look through Forwards on Action and ExceptionHandler methods.
203
//
204
MethodDeclaration[] methods = CompilerUtils.getClassMethods( flowControllerClass, null );
205         
206         for ( int i = 0; i < methods.length; i++ )
207         {
208             MethodDeclaration method = methods[i];
209             AnnotationInstance ann = CompilerUtils.getAnnotation( method, ACTION_TAG_NAME );
210             
211             if ( ann != null )
212             {
213                 enableNavigateTo( CompilerUtils.getAnnotation( ann, VALIDATION_ERROR_FORWARD_ATTR, true ), fcInfo );
214             }
215             
216             if ( ann == null ) ann = CompilerUtils.getAnnotation( method, EXCEPTION_HANDLER_TAG_NAME );
217             if ( ann != null ) enableNavigateTo( CompilerUtils.getAnnotationArray( ann, FORWARDS_ATTR, true ), fcInfo );
218         }
219     }
220     
221     private static void enableNavigateTo( Collection JavaDoc childAnnotations, FlowControllerInfo fcInfo )
222     {
223         if ( childAnnotations != null )
224         {
225             for ( Iterator JavaDoc ii = childAnnotations.iterator(); ii.hasNext(); )
226             {
227                 AnnotationInstance childAnnotation = ( AnnotationInstance ) ii.next();
228                 enableNavigateTo( childAnnotation, fcInfo );
229             }
230         }
231     }
232     
233     private static void enableNavigateTo( AnnotationInstance ann, FlowControllerInfo fcInfo )
234     {
235         if ( ann == null ) return;
236         String JavaDoc val = CompilerUtils.getEnumFieldName( ann, NAVIGATE_TO_ATTR, true );
237         
238         if ( val != null )
239         {
240             if ( val.equals( NAVIGATE_TO_CURRENT_PAGE_STR ) || val.equals( NAVIGATE_TO_PREVIOUS_PAGE_STR )
241                  || val.equals( NAVIGATE_TO_PAGE_LEGACY_STR ) )
242             {
243                 fcInfo.enableNavigateToPage();
244             }
245             else if ( val.equals( NAVIGATE_TO_PREVIOUS_ACTION_STR ) )
246             {
247                 fcInfo.enableNavigateToAction();
248             }
249         }
250     }
251     
252     protected void endCheckClass( ClassDeclaration jclass )
253     {
254     }
255     
256     protected abstract GenStrutsApp createStrutsApp( ClassDeclaration jclass )
257         throws XmlException, IOException JavaDoc, FatalCompileTimeException;
258     
259     protected void startCheckClass( ClassDeclaration jclass )
260             throws FatalCompileTimeException
261     {
262         //
263
// Check for basic things like writability of the struts-config file.
264
//
265
GenStrutsApp strutsApp = null;
266         File JavaDoc strutsConfigFile = null;
267         
268         //
269
// Make sure we can write to the struts-config XML file.
270
//
271
try
272         {
273             strutsApp = createStrutsApp( jclass );
274             strutsConfigFile = strutsApp.getStrutsConfigFile();
275         }
276         catch ( XmlException e )
277         {
278             // will be reported at generate time
279
}
280         catch ( IOException JavaDoc e )
281         {
282             // will be reported at generate time
283
}
284         
285         if ( strutsConfigFile != null )
286         {
287             File JavaDoc parentDir = strutsConfigFile.getParentFile();
288     
289             getFCSourceFileInfo().addReferencedFile( strutsConfigFile );
290             
291             if ( ! parentDir.isDirectory() )
292             {
293                 //
294
// The second call to isDirectory below accounts for the possibility that another thread has created
295
// the directory. Filesystem-based double-checked-locking... works. We don't need to have
296
// compiler-wide contention around this check.
297
//
298
if ( ! parentDir.mkdirs() && ! parentDir.isDirectory() )
299                 {
300                     getDiagnostics().addError( jclass, "error.invalid-parent-directory", parentDir );
301                 }
302             }
303     
304             if ( strutsConfigFile.exists() && strutsApp != null && ! strutsApp.canWrite() )
305             {
306                 getDiagnostics().addError( jclass, "error.struts-config-not-writable", strutsConfigFile );
307             }
308         }
309         
310         getRuntimeVersionChecker().checkRuntimeVersion( VERSION_8_SP2_STRING, jclass, getDiagnostics(),
311                                                         "warning.runtime-version", new Object JavaDoc[]{ PAGEFLOW_RUNTIME_JAR } );
312
313         //
314
// Check the Jpf.Controller annotation on this class.
315
//
316
AnnotationInstance controllerAnnotation = CompilerUtils.getAnnotation( jclass, CONTROLLER_TAG_NAME );
317         if ( controllerAnnotation != null ) _controllerGrammar.check( controllerAnnotation, null, jclass );
318         
319         //
320
// Check relative paths on Jpf.Catch, Jpf.Forward, and Jpf.SimpleAction annotations on superclasses.
321
//
322
checkInheritedRelativePaths( jclass );
323     }
324     
325     /**
326      * Check relative paths in annotations inherited from a base class.
327      */

328     private void checkInheritedRelativePaths( ClassDeclaration jclass )
329             throws FatalCompileTimeException
330     {
331         for ( ClassType type = jclass.getSuperclass();
332               type != null && CompilerUtils.isAssignableFrom( FLOWCONTROLLER_BASE_CLASS, type, getEnv() );
333               type = type.getSuperclass() )
334         {
335             TypeDeclaration decl = CompilerUtils.getDeclaration( type );
336             
337             //
338
// Check simple actions in the Controller annotation.
339
//
340
List JavaDoc simpleActions =
341                     CompilerUtils.getAnnotationArrayValue( decl, CONTROLLER_TAG_NAME, SIMPLE_ACTIONS_ATTR, true );
342             
343             if ( simpleActions != null )
344             {
345                 for ( Iterator JavaDoc j = simpleActions.iterator(); j.hasNext(); )
346                 {
347                     AnnotationInstance i = ( AnnotationInstance ) j.next();
348                     checkRelativePath( i, PATH_ATTR, jclass, decl, false );
349                     List JavaDoc conditionalForwards = CompilerUtils.getAnnotationArray( i, CONDITIONAL_FORWARDS_ATTR, true );
350                     
351                     if ( conditionalForwards != null )
352                     {
353                         for ( Iterator JavaDoc k = conditionalForwards.iterator(); k.hasNext(); )
354                         {
355                             AnnotationInstance ann = ( AnnotationInstance ) k.next();
356                             checkRelativePath( ann, PATH_ATTR, jclass, decl, false );
357                         }
358                     }
359                 }
360             }
361             
362             //
363
// Check Forwards in the Controller annotation.
364
//
365
List JavaDoc forwards = CompilerUtils.getAnnotationArrayValue( decl, CONTROLLER_TAG_NAME, FORWARDS_ATTR, true );
366             
367             if ( forwards != null )
368             {
369                 for ( Iterator JavaDoc ii = forwards.iterator(); ii.hasNext(); )
370                 {
371                     AnnotationInstance i = ( AnnotationInstance ) ii.next();
372                     checkRelativePath( i, PATH_ATTR, jclass, decl, false );
373                 }
374             }
375             
376             //
377
// Check Catches in the Controller annotation.
378
//
379
List JavaDoc catches = CompilerUtils.getAnnotationArrayValue( decl, CONTROLLER_TAG_NAME, CATCHES_ATTR, true );
380             
381             if ( catches != null )
382             {
383                 for ( Iterator JavaDoc j = catches.iterator(); j.hasNext(); )
384                 {
385                     AnnotationInstance i = ( AnnotationInstance ) j.next();
386                     checkRelativePath( i, PATH_ATTR, jclass, decl, false );
387                 }
388             }
389
390             //
391
// Check strutsMerge and validatorMerge in the Controller annotation.
392
//
393
AnnotationInstance controllerAnnotation = CompilerUtils.getAnnotation( decl, CONTROLLER_TAG_NAME );
394
395             if ( controllerAnnotation != null )
396             {
397                 checkRelativePath( controllerAnnotation, VALIDATOR_MERGE_ATTR, jclass, decl, true );
398                 checkRelativePath( controllerAnnotation, STRUTSMERGE_ATTR, jclass, decl, true );
399             }
400             
401             //
402
// Check Forwards and Catches on action methods and exception-handler methods.
403
//
404
MethodDeclaration[] methods = decl.getMethods();
405             for ( int i = 0; i < methods.length; i++ )
406             {
407                 MethodDeclaration method = methods[i];
408                 AnnotationInstance ann = CompilerUtils.getAnnotation( method, ACTION_TAG_NAME);
409                 if ( ann == null ) ann = CompilerUtils.getAnnotation( method, EXCEPTION_HANDLER_TAG_NAME );
410                 
411                 if ( ann != null )
412                 {
413                     List JavaDoc methodForwards = CompilerUtils.getAnnotationArray( ann, FORWARDS_ATTR, true );
414                     String JavaDoc methodName = method.getSimpleName();
415                     
416                     if ( methodForwards != null )
417                     {
418                         for ( Iterator JavaDoc j = methodForwards.iterator(); j.hasNext(); )
419                         {
420                             AnnotationInstance methodForward = ( AnnotationInstance ) j.next();
421                             checkRelativePath( methodName, methodForward, PATH_ATTR, jclass, decl, false );
422                         }
423                     }
424                     
425                     List JavaDoc methodCatches = CompilerUtils.getAnnotationArray( ann, CATCHES_ATTR, true );
426                     
427                     if ( methodCatches != null )
428                     {
429                         for ( Iterator JavaDoc j = methodCatches.iterator(); j.hasNext(); )
430                         {
431                             AnnotationInstance methodCatch = ( AnnotationInstance ) j.next();
432                             checkRelativePath( methodName, methodCatch, PATH_ATTR, jclass, decl, false );
433                         }
434                     }
435                 }
436             }
437         }
438     }
439     
440     private void checkRelativePath( AnnotationInstance ann, String JavaDoc memberName, TypeDeclaration jclass,
441                                     TypeDeclaration baseType, boolean isError )
442             throws FatalCompileTimeException
443     {
444         if ( ann != null )
445         {
446             AnnotationValue pathVal = CompilerUtils.getAnnotationValue( ann, memberName, true );
447             
448             if ( pathVal != null )
449             {
450                 String JavaDoc path = ( String JavaDoc ) pathVal.getValue();
451                 
452                 if ( path.charAt( 0 ) != '/' && ! WebappPathType.relativePathExists( path, jclass, getEnv() ) )
453                 {
454                     String JavaDoc[] args = {
455                         path,
456                         ANNOTATION_INTERFACE_PREFIX + ann.getAnnotationType().getDeclaration().getSimpleName(),
457                         baseType.getQualifiedName()
458                     };
459                     
460                     if ( isError )
461                     {
462                         getDiagnostics().addErrorArrayArgs( ann, "message.inherited-file-not-found", args );
463                     }
464                     else
465                     {
466                         getDiagnostics().addWarningArrayArgs( ann, "message.inherited-file-not-found", args );
467                     }
468                 }
469             }
470         }
471     }
472     
473     private void checkRelativePath( String JavaDoc methodName, AnnotationInstance ann, String JavaDoc memberName,
474                                     TypeDeclaration jclass, TypeDeclaration baseType, boolean isError )
475             throws FatalCompileTimeException
476     {
477         if ( ann != null )
478         {
479             AnnotationValue pathVal = CompilerUtils.getAnnotationValue( ann, memberName, true );
480             
481             if ( pathVal != null )
482             {
483                 String JavaDoc path = ( String JavaDoc ) pathVal.getValue();
484                 
485                 if ( path.charAt( 0 ) != '/' && ! WebappPathType.relativePathExists( path, jclass, getEnv() ) )
486                 {
487                     String JavaDoc[] args = {
488                         path,
489                         ANNOTATION_INTERFACE_PREFIX + ann.getAnnotationType().getDeclaration().getSimpleName(),
490                         methodName,
491                         baseType.getQualifiedName()
492                     };
493                     
494                     if ( isError )
495                     {
496                         getDiagnostics().addErrorArrayArgs( jclass, "message.method-inherited-file-not-found", args );
497                     }
498                     else
499                     {
500                         getDiagnostics().addWarningArrayArgs( jclass, "message.method-inherited-file-not-found", args );
501                     }
502                 }
503             }
504         }
505     }
506     
507     
508
509     protected void checkField( FieldDeclaration field, TypeDeclaration jclass )
510     {
511         //
512
// Only warn about nonserializable member data that's defined in this particular class.
513
//
514
if ( CompilerUtils.typesAreEqual( jclass, field.getDeclaringType() ) )
515         {
516             TypeInstance type = field.getType();
517             
518             if ( ! field.hasModifier( Modifier.TRANSIENT ) && ! field.hasModifier( Modifier.STATIC )
519                  && type instanceof ClassType
520                  && ! CompilerUtils.isAssignableFrom( SERIALIZABLE_CLASS_NAME, type, getEnv() ) )
521             {
522                 getDiagnostics().addWarning( field, "warning.nonserializable-member-data" );
523             }
524         }
525     }
526     
527     protected void checkMethod( MethodDeclaration method, ClassDeclaration jclass )
528             throws FatalCompileTimeException
529     {
530         AnnotationInstance[] annotations = method.getAnnotationInstances();
531         
532         for ( int i = 0; i < annotations.length; i++ )
533         {
534             AnnotationInstance annotation = annotations[i];
535             String JavaDoc annotationName = CompilerUtils.getDeclaration( annotation.getAnnotationType() ).getSimpleName();
536             
537             if ( annotationName.equals( ACTION_TAG_NAME ) )
538             {
539                 _actionGrammar.check( annotation, null, method );
540                 
541                 if ( ! CompilerUtils.isAssignableFrom( FORWARD_CLASS_NAME, method.getReturnType(), getEnv() ) )
542                 {
543                     getDiagnostics().addError( method, "error.method-wrong-return-type", FORWARD_CLASS_NAME );
544                 }
545             }
546             else if ( annotationName.equals( EXCEPTION_HANDLER_TAG_NAME ) )
547             {
548                 _exceptionHandlerGrammar.check( annotation, null, method );
549                 checkExceptionHandlerMethod( method );
550             }
551         }
552     }
553     
554     protected void checkInnerClass( ClassDeclaration innerClass )
555             throws FatalCompileTimeException
556     {
557         _formBeanChecker.check( innerClass );
558     }
559     
560     private void checkExceptionHandlerMethod( MethodDeclaration method )
561     {
562         if ( ! CompilerUtils.isAssignableFrom( FORWARD_CLASS_NAME, method.getReturnType(), getEnv() ) )
563         {
564             getDiagnostics().addError( method, "error.method-wrong-return-type", FORWARD_CLASS_NAME );
565         }
566
567         ParameterDeclaration[] parameters = method.getParameters();
568         
569         if ( parameters.length == 4 )
570         {
571             if ( ! CompilerUtils.isAssignableFrom( THROWABLE_CLASS_NAME, parameters[0].getType(), getEnv() ) )
572             {
573                 getDiagnostics().addError( method, "error.exception-method-wrong-exception-arg", THROWABLE_CLASS_NAME );
574             }
575
576             checkExceptionHandlerArgType( method, parameters, 1, STRING_CLASS_NAME );
577             checkExceptionHandlerArgType( method, parameters, 2, STRING_CLASS_NAME );
578
579             //
580
// The use of org.apache.struts.action.ActionForm or org.apache.beehive.netui.pageflow.FormData as the
581
// fourth argument is deprecated. Forms can be any Object type now.
582
//
583
if ( CompilerUtils.isAssignableFrom( STRUTS_FORM_CLASS_NAME, parameters[3].getType(), getEnv() ) )
584             {
585                 getDiagnostics().addWarning( method, "warning.exception-method-deprecated-form-arg" );
586             }
587             else
588             {
589                 checkExceptionHandlerArgType( method, parameters, 3, OBJECT_CLASS_NAME );
590             }
591         }
592         else
593         {
594             getDiagnostics().addError( method, "error.exception-method-wrong-arg-count", new Integer JavaDoc( 4 ) );
595         }
596     }
597     
598     private void checkExceptionHandlerArgType( MethodDeclaration method, ParameterDeclaration[] parameters,
599                                                int index, String JavaDoc className )
600     {
601         if ( ! CompilerUtils.isOfClass( parameters[ index ].getType(), className, getEnv() ) )
602         {
603             getDiagnostics().addError( method, "error.exception-method-wrong-arg-type", new Integer JavaDoc( index + 1 ),
604                                        className );
605         }
606     }
607     
608     protected void checkForOverlappingClasses( ClassDeclaration jpfClass, String JavaDoc baseClass, String JavaDoc fileExtension,
609                                                String JavaDoc errorKey )
610     {
611         File JavaDoc jpfFile = CompilerUtils.getSourceFile( jpfClass, true );
612         File JavaDoc parentDir = jpfFile.getParentFile();
613         PackageDeclaration pkg = jpfClass.getPackage();
614         ClassDeclaration[] packageClasses = pkg.getClasses();
615         Set JavaDoc overlapping = new HashSet JavaDoc();
616         List JavaDoc overlappingFiles = new ArrayList JavaDoc();
617         
618         //
619
// First go through the other classes in this package to look for other classes of this type. Only one per
620
// directory is allowed.
621
//
622
for ( int i = 0; i < packageClasses.length; i++ )
623         {
624             ClassDeclaration classDecl = packageClasses[i];
625             if ( CompilerUtils.getAnnotation( classDecl, CONTROLLER_TAG_NAME ) != null
626                  && CompilerUtils.isAssignableFrom( baseClass, classDecl, getEnv() ) )
627             {
628                 File JavaDoc file = CompilerUtils.getSourceFile( classDecl, false );
629                 
630                 //
631
// Add the dependency if it's a different file and if the file exists (it may have been deleted
632
// sometime after the list of classes in this package got built.
633
//
634
if ( ! jpfFile.equals( file ) && file != null && file.exists() )
635                 {
636                     overlapping.add( file.getName() );
637                     overlappingFiles.add( file );
638                 }
639             }
640         }
641         
642         //
643
// Additionally, we'll go through the parent directory to make sure there are no other files of this type.
644
// This is a double-check for the case where duplicate files have the same class names inside them, which means
645
// that iterating through the list of package classes is hit or miss (only one of them will show up, and it may
646
// be this class or the duplicate class).
647
//
648
File JavaDoc[] peers = parentDir.listFiles( new ExtensionFileFilter( fileExtension ) );
649         
650         if ( peers != null ) // make sure the directory hasn't been deleted while we're running
651
{
652             for ( int i = 0; i < peers.length; i++ )
653             {
654                 File JavaDoc peer = peers[i];
655                 if ( ! peer.equals( jpfFile ) )
656                 {
657                     String JavaDoc name = peer.getName();
658                     
659                     if ( ! overlapping.contains( name ) )
660                     {
661                         overlapping.add( name );
662                         overlappingFiles.add( peer );
663                     }
664                 }
665             }
666         }
667         
668         int len = overlapping.size();
669         if ( len > 0 )
670         {
671             if ( len > 3 )
672             {
673                 getDiagnostics().addErrorArrayArgs( jpfClass, errorKey, overlapping.toArray() );
674             }
675             else
676             {
677                 getDiagnostics().addErrorArrayArgs( jpfClass, errorKey + len, overlapping.toArray() );
678             }
679         }
680         
681         getCheckResultMap().put( JpfLanguageConstants.ExtraInfoKeys.overlappingPageFlowFiles, overlappingFiles );
682     }
683     
684     private static class ExtensionFileFilter implements FilenameFilter JavaDoc
685     {
686         private String JavaDoc _extension;
687         
688         public ExtensionFileFilter( String JavaDoc extension )
689         {
690             _extension = extension;
691         }
692         
693         public boolean accept( File JavaDoc dir, String JavaDoc name )
694         {
695             return name.endsWith( _extension );
696         }
697     }
698
699     protected FlowControllerInfo getFCSourceFileInfo()
700     {
701         return ( FlowControllerInfo ) super.getSourceFileInfo();
702     }
703 }
704
Popular Tags