KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > beehive > netui > compiler > grammar > ActionGrammar


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.grammar;
19
20 import org.apache.beehive.netui.compiler.AnnotationMemberType;
21 import org.apache.beehive.netui.compiler.CompilerUtils;
22 import org.apache.beehive.netui.compiler.Diagnostics;
23 import org.apache.beehive.netui.compiler.FlowControllerInfo;
24 import org.apache.beehive.netui.compiler.JpfLanguageConstants;
25 import org.apache.beehive.netui.compiler.RuntimeVersionChecker;
26 import org.apache.beehive.netui.compiler.FatalCompileTimeException;
27 import org.apache.beehive.netui.compiler.typesystem.declaration.*;
28 import org.apache.beehive.netui.compiler.typesystem.env.AnnotationProcessorEnvironment;
29 import org.apache.beehive.netui.compiler.typesystem.type.DeclaredType;
30 import org.apache.beehive.netui.compiler.typesystem.type.TypeInstance;
31
32
33 public class ActionGrammar
34         extends BaseFlowControllerGrammar
35         implements JpfLanguageConstants
36 {
37     public ActionGrammar( AnnotationProcessorEnvironment env, Diagnostics diags,
38                           RuntimeVersionChecker rvc, FlowControllerInfo fcInfo )
39     {
40         super( env, diags, null, rvc, fcInfo );
41         
42         addMemberType( LOGIN_REQUIRED_ATTR, new AnnotationMemberType( null, this ) );
43         addMemberType( ROLES_ALLOWED_ATTR, new RolesAllowedType( this ) );
44         addMemberType( READONLY_ATTR, new AnnotationMemberType( VERSION_8_SP2_STRING, this ) );
45         addMemberType( USE_FORM_BEAN_ATTR, new UseFormBeanType() );
46         addMemberType( PREVENT_DOUBLE_SUBMIT_ATTR, new AnnotationMemberType( null, this ) );
47         addMemberType( DO_VALIDATION_ATTR, new DoValidateType() );
48         
49         addMemberArrayGrammar( FORWARDS_ATTR, new ForwardGrammar( env, diags, null, rvc, fcInfo ) );
50         addMemberArrayGrammar( CATCHES_ATTR, new CatchGrammar( env, diags, null, rvc, ACTION_TAG_NAME, fcInfo ) );
51         addMemberArrayGrammar( VALIDATABLE_PROPERTIES_ATTR, new ValidatablePropertyGrammar( env, diags, rvc ) );
52         addMemberGrammar( VALIDATION_ERROR_FORWARD_ATTR, new ActionForwardGrammar() );
53     }
54
55     public String JavaDoc[][] getMutuallyExclusiveAttrs()
56     {
57         return null;
58     }
59
60     public String JavaDoc[][] getRequiredAttrs()
61     {
62         return null;
63     }
64
65     protected boolean onBeginCheck( AnnotationInstance annotation, AnnotationInstance[] parentAnnotations,
66                                     MemberDeclaration classMember )
67             throws FatalCompileTimeException
68     {
69         //
70
// First check the form bean type.
71
//
72
TypeInstance argType = getFormBeanType( annotation, classMember );
73         TypeDeclaration argTypeDecl = null;
74         
75         if ( ! ( argType instanceof DeclaredType ) )
76         {
77             if ( argType != null )
78             {
79                 getDiagnostics().addError( annotation, "error.action-invalid-form-bean-type", argType.toString() );
80                 argType = null;
81             }
82         }
83         else
84         {
85             argTypeDecl = CompilerUtils.getDeclaration( ( DeclaredType ) argType );
86             boolean isClass = argTypeDecl instanceof ClassDeclaration;
87             
88             if ( isClass && ! CompilerUtils.hasDefaultConstructor( argTypeDecl ) )
89             {
90                 getDiagnostics().addError( annotation, "error.action-form-bean-no-default-constructor",
91                                            argTypeDecl.getQualifiedName() );
92             }
93             
94             if ( ! argTypeDecl.hasModifier( Modifier.PUBLIC ) )
95             {
96                 getDiagnostics().addError( annotation, "error.action-form-bean-not-public",
97                                            argTypeDecl.getQualifiedName() );
98             }
99             
100             if ( isClass && argTypeDecl.getDeclaringType() != null && ! argTypeDecl.hasModifier( Modifier.STATIC ) )
101             {
102                 getDiagnostics().addError( annotation, "error.action-form-bean-not-static",
103                                            argTypeDecl.getQualifiedName() );
104             }
105             
106             //
107
// Give a warning if there is no validationErrorForward annotation and doValidation isn't set to false.
108
//
109
if ( CompilerUtils.getAnnotationValue( annotation, VALIDATION_ERROR_FORWARD_ATTR, true ) == null
110                  && hasValidationAnnotations( argTypeDecl ) )
111             {
112                 Boolean JavaDoc doValidation = CompilerUtils.getBoolean( annotation, DO_VALIDATION_ATTR, true );
113                 
114                 if ( doValidation == null || doValidation.booleanValue() )
115                 {
116                     getDiagnostics().addWarning(
117                             annotation, "warning.validatable-formbean-no-forward",
118                             ANNOTATION_INTERFACE_PREFIX + annotation.getAnnotationType().getDeclaration().getSimpleName(),
119                             VALIDATION_ERROR_FORWARD_ATTR, argTypeDecl.getQualifiedName() );
120                 }
121             }
122         }
123         
124         //
125
// Add this action to the FlowControllerInfo.
126
//
127
getFlowControllerInfo().addAction( getActionName( annotation, classMember ),
128                                            argTypeDecl != null ? argTypeDecl.getQualifiedName() : null );
129
130         //
131
// Check to make sure the 'useFormBean' attribute (reference to a member variable) matches the form declared as
132
// an argument to the action method.
133
//
134
TypeInstance useFormBeanType = getUseFormBeanType( annotation, classMember );
135         
136         if ( useFormBeanType != null && useFormBeanType instanceof DeclaredType )
137         {
138             if ( argType == null )
139             {
140                 String JavaDoc memberFormTypeName = CompilerUtils.getDeclaration( ( DeclaredType ) useFormBeanType ).getQualifiedName();
141                 getDiagnostics().addError( annotation, "error.action-mismatched-form", USE_FORM_BEAN_ATTR,
142                                            memberFormTypeName );
143             }
144             else if ( ! CompilerUtils.isAssignableFrom( argTypeDecl, useFormBeanType ))
145             {
146                 String JavaDoc memberFormTypeName = CompilerUtils.getDeclaration( ( DeclaredType ) useFormBeanType ).getQualifiedName();
147                 getDiagnostics().addError( annotation, "error.action-mismatched-form", USE_FORM_BEAN_ATTR,
148                                            memberFormTypeName );
149             }
150         }
151         
152         return true;
153     }
154
155     protected String JavaDoc getActionName( AnnotationInstance annotation, MemberDeclaration classMember )
156     {
157         assert classMember instanceof MethodDeclaration : classMember.getClass().getName();
158         return classMember.getSimpleName();
159     }
160     
161     private static boolean hasValidationAnnotations( TypeDeclaration type )
162     {
163         // Could cache this if it's a performance problem.
164

165         MethodDeclaration[] methods = type.getMethods();
166         
167         for ( int i = 0; i < methods.length; i++ )
168         {
169             MethodDeclaration method = methods[i];
170             AnnotationInstance[] annotations = method.getAnnotationInstances();
171             
172             for ( int j = 0; j < annotations.length; j++ )
173             {
174                 AnnotationInstance ann = annotations[j];
175                 String JavaDoc annotationName = CompilerUtils.getDeclaration( ann.getAnnotationType() ).getQualifiedName();
176                 int pos = annotationName.indexOf( ANNOTATION_QUALIFIER );
177                 
178                 if ( pos != -1 )
179                 {
180                     if ( annotationName.substring( pos + ANNOTATION_QUALIFIER.length() ).startsWith( "Validat" ) )
181                     {
182                         return true;
183                     }
184                 }
185             }
186         }
187         
188         return false;
189     }
190     
191     protected static TypeInstance getUseFormBeanType( AnnotationInstance annotation, MemberDeclaration classMember )
192     {
193         String JavaDoc formBeanFieldName = CompilerUtils.getString( annotation, USE_FORM_BEAN_ATTR, true );
194         
195         if ( formBeanFieldName != null )
196         {
197             FieldDeclaration formBeanField =
198                     CompilerUtils.findField( CompilerUtils.getOutermostClass( classMember ), formBeanFieldName );
199             
200             if ( formBeanField != null )
201             {
202                 return CompilerUtils.getGenericBoundsType( formBeanField.getType() );
203             }
204         }
205         
206         return null;
207     }
208     
209     protected TypeInstance getFormBeanType( AnnotationInstance annotation, MemberDeclaration classMember )
210     {
211         assert classMember instanceof MethodDeclaration : classMember.getClass().getName();
212         MethodDeclaration method = ( MethodDeclaration ) classMember;
213         ParameterDeclaration[] parameters = method.getParameters();
214         int nParameters = parameters.length;
215         
216         if ( nParameters > 1 ) getDiagnostics().addError( method, "error.action-method-wrong-arg" );
217         if ( nParameters > 0 ) return CompilerUtils.getGenericBoundsType( parameters[0].getType() );
218         
219         return null;
220     }
221     
222     private class DoValidateType
223         extends AnnotationMemberType
224     {
225         public DoValidateType()
226         {
227             super( null, ActionGrammar.this );
228         }
229         
230         
231         public Object JavaDoc onCheck( AnnotationTypeElementDeclaration valueDecl, AnnotationValue member,
232                                AnnotationInstance[] parentAnnotations, MemberDeclaration classMember,
233                                int annotationArrayIndex )
234         {
235             //
236
// If this value is set to true, there must be a value for validationErrorForward.
237
//
238
if ( ( ( Boolean JavaDoc ) member.getValue() ).booleanValue() )
239             {
240                 AnnotationInstance parentAnnotation = parentAnnotations[ parentAnnotations.length - 1 ];
241                 
242                 if ( CompilerUtils.getAnnotation( parentAnnotation, VALIDATION_ERROR_FORWARD_ATTR, true ) == null )
243                 {
244                     addError( member, "error.validate-with-no-validation-error-forward", DO_VALIDATION_ATTR,
245                               VALIDATION_ERROR_FORWARD_ATTR );
246                 }
247             }
248             
249             return null;
250         }
251     }
252     
253     private class ActionForwardGrammar
254         extends ForwardGrammar
255     {
256         public ActionForwardGrammar()
257         {
258             super( ActionGrammar.this.getEnv(), ActionGrammar.this.getDiagnostics(), null,
259                    ActionGrammar.this.getRuntimeVersionChecker(), ActionGrammar.this.getFlowControllerInfo() );
260             ExternalPathOrActionType baseForwardType =
261                     new ExternalPathOrActionType( false, null, this, ActionGrammar.this.getFlowControllerInfo() );
262             addMemberType( PATH_ATTR, new ForwardToExternalPathType( baseForwardType, null, ActionGrammar.this ) );
263         }
264     }
265     
266     private class UseFormBeanType
267         extends WritableFieldType
268     {
269         public UseFormBeanType()
270         {
271             super( OBJECT_CLASS_NAME, USE_FORM_BEAN_ATTR, null, ActionGrammar.this );
272         }
273
274         
275         public Object JavaDoc onCheck( AnnotationTypeElementDeclaration valueDecl, AnnotationValue value,
276                                AnnotationInstance[] parentAnnotations, MemberDeclaration classMember,
277                                int annotationArrayIndex )
278         {
279             FieldDeclaration memberField =
280                     ( FieldDeclaration ) super.onCheck( valueDecl, value, parentAnnotations, classMember,
281                                                         annotationArrayIndex );
282             
283             if ( memberField != null )
284             {
285                 //
286
// If this action is marked 'readOnly', print a warning about the 'useFormBean' attribute implicitly
287
// modifying member data.
288
//
289
AnnotationInstance parentAnnotation = parentAnnotations[parentAnnotations.length - 1];
290                 if ( CompilerUtils.getBoolean( parentAnnotation, READONLY_ATTR, false ).booleanValue() )
291                 {
292                     addWarning( value, "warning.use-form-bean-on-readonly-action", READONLY_ATTR, USE_FORM_BEAN_ATTR,
293                                 memberField.getSimpleName() );
294                 }
295             }
296             
297             return memberField;
298         }
299     }
300 }
301
Popular Tags