001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: * $Header:$
018: */
019: package org.apache.beehive.netui.compiler.grammar;
020:
021: import org.apache.beehive.netui.compiler.AnnotationMemberType;
022: import org.apache.beehive.netui.compiler.CompilerUtils;
023: import org.apache.beehive.netui.compiler.Diagnostics;
024: import org.apache.beehive.netui.compiler.FlowControllerInfo;
025: import org.apache.beehive.netui.compiler.RuntimeVersionChecker;
026: import org.apache.beehive.netui.compiler.typesystem.declaration.AnnotationInstance;
027: import org.apache.beehive.netui.compiler.typesystem.declaration.AnnotationTypeElementDeclaration;
028: import org.apache.beehive.netui.compiler.typesystem.declaration.AnnotationValue;
029: import org.apache.beehive.netui.compiler.typesystem.declaration.MemberDeclaration;
030: import org.apache.beehive.netui.compiler.typesystem.declaration.MethodDeclaration;
031: import org.apache.beehive.netui.compiler.typesystem.declaration.TypeDeclaration;
032: import org.apache.beehive.netui.compiler.typesystem.env.CoreAnnotationProcessorEnv;
033: import org.apache.beehive.netui.compiler.typesystem.type.DeclaredType;
034: import org.apache.beehive.netui.compiler.typesystem.type.TypeInstance;
035:
036: import java.util.ArrayList;
037: import java.util.Collection;
038: import java.util.Iterator;
039: import java.util.List;
040:
041: public class ForwardGrammar extends BaseFlowControllerGrammar {
042: private static final String[][] NAVIGATE_TO_VALS = new String[][] {
043: { NAVIGATE_TO_CURRENT_PAGE_STR, VERSION_8_SP2_STRING },
044: { NAVIGATE_TO_PREVIOUS_PAGE_STR, VERSION_8_SP2_STRING },
045: { NAVIGATE_TO_PAGE_LEGACY_STR, null },
046: { NAVIGATE_TO_PREVIOUS_ACTION_STR, VERSION_8_SP2_STRING }, };
047:
048: private static final String[][] DEPRECATED_NAVIGATE_TO_VALS = new String[][] { {
049: NAVIGATE_TO_PAGE_LEGACY_STR,
050: "warning.return-to-page-deprecated" }, };
051:
052: private static String[][] MUTUALLY_EXCLUSIVE_ATTRS = {
053: { PATH_ATTR, TILES_DEFINITION_ATTR, RETURN_ACTION_ATTR,
054: NAVIGATE_TO_ATTR, ACTION_ATTR },
055: { OUTPUT_FORM_BEAN_TYPE_ATTR, OUTPUT_FORM_BEAN_ATTR },
056: { REDIRECT_ATTR, EXTERNAL_REDIRECT_ATTR } };
057:
058: private static String[][] REQUIRED_ATTRS = {
059: { NAME_ATTR },
060: { PATH_ATTR, TILES_DEFINITION_ATTR, RETURN_ACTION_ATTR,
061: NAVIGATE_TO_ATTR, ACTION_ATTR } };
062:
063: private static String[][] ATTR_DEPENDENCIES = {
064: { REDIRECT_ATTR, PATH_ATTR, NAVIGATE_TO_ATTR, ACTION_ATTR },
065: { EXTERNAL_REDIRECT_ATTR, PATH_ATTR },
066: { RESTORE_QUERY_STRING_ATTR, NAVIGATE_TO_ATTR } };
067:
068: public ForwardGrammar(CoreAnnotationProcessorEnv env,
069: Diagnostics diags, String requiredRuntimeVersion,
070: RuntimeVersionChecker runtimeVersionChecker,
071: FlowControllerInfo fcInfo) {
072: super (env, diags, requiredRuntimeVersion,
073: runtimeVersionChecker, fcInfo);
074:
075: addMemberType(NAME_ATTR, getNameType());
076: addMemberType(OUTPUT_FORM_BEAN_TYPE_ATTR, new TypeNameType(
077: null, false, null, this ));
078: addMemberType(OUTPUT_FORM_BEAN_ATTR, new MemberFieldType(null,
079: null, this ));
080: addMemberType(RETURN_ACTION_ATTR, new JavaIdentifierType(null,
081: this , new char[] { '.' }));
082: addMemberType(PATH_ATTR, new ExternalPathOrActionType(false,
083: null, this , fcInfo));
084: addMemberType(ACTION_ATTR, new ValidActionType(null, this ,
085: fcInfo));
086: addMemberType(TILES_DEFINITION_ATTR, new AnnotationMemberType(
087: null, this ));
088: addMemberType(REDIRECT_ATTR, new AnnotationMemberType(null,
089: this ));
090: addMemberType(EXTERNAL_REDIRECT_ATTR, new AbsolutePathType(
091: null, this ));
092: addMemberType(NAVIGATE_TO_ATTR, new EnumType(NAVIGATE_TO_VALS,
093: DEPRECATED_NAVIGATE_TO_VALS, null, this ));
094: addMemberType(RESTORE_QUERY_STRING_ATTR,
095: new AnnotationMemberType(null, this ));
096:
097: addMemberArrayGrammar(ACTION_OUTPUTS_ATTR,
098: new ActionOutputGrammar(env, diags,
099: runtimeVersionChecker));
100: }
101:
102: protected AnnotationMemberType getNameType() {
103: return new ForwardNameType();
104: }
105:
106: public String[][] getMutuallyExclusiveAttrs() {
107: return MUTUALLY_EXCLUSIVE_ATTRS;
108: }
109:
110: public String[][] getRequiredAttrs() {
111: return REQUIRED_ATTRS;
112: }
113:
114: public String[][] getAttrDependencies() {
115: return ATTR_DEPENDENCIES;
116: }
117:
118: protected void onCheckMember(
119: AnnotationTypeElementDeclaration memberDecl,
120: AnnotationValue value, AnnotationInstance annotation,
121: AnnotationInstance[] parentAnnotations,
122: MemberDeclaration classMember) {
123: String valueName = memberDecl.getSimpleName();
124: boolean isReturnAction = valueName.equals(RETURN_ACTION_ATTR);
125:
126: if (isReturnAction) {
127: if (!getFlowControllerInfo().isNested()) {
128: addError(value, "error.only-valid-in-nested",
129: new Object[] { valueName });
130: }
131: }
132:
133: if (valueName.equals(ACTION_OUTPUTS_ATTR)
134: && ((List) value.getValue()).size() > 0) {
135: if (CompilerUtils.getBoolean(annotation, REDIRECT_ATTR,
136: false).booleanValue()) {
137: addError(value, "error.action-outputs-with-redirect",
138: REDIRECT_ATTR);
139: }
140:
141: String path = CompilerUtils.getString(annotation,
142: PATH_ATTR, true);
143: if (path != null && CompilerUtils.isAbsoluteURI(path)) {
144: addError(value,
145: "error.action-outputs-with-absolute-uri",
146: PATH_ATTR);
147: }
148: }
149:
150: //
151: // If this is a return-action, store its info in the FlowControllerInfo (which is eventually provided to tools).
152: //
153: if (isReturnAction) {
154: TypeDeclaration outerType = CompilerUtils
155: .getOuterClass(classMember);
156: TypeInstance formBeanType = getFlowControllerInfo()
157: .addReturnAction((String) value.getValue(),
158: annotation, outerType);
159:
160: if (formBeanType != null
161: && !(formBeanType instanceof DeclaredType)) {
162: addError(annotation,
163: "error.action-invalid-form-bean-type",
164: formBeanType.toString());
165: }
166: }
167: }
168:
169: protected class ForwardNameType extends UniqueValueType {
170: public ForwardNameType() {
171: this (FORWARDS_ATTR);
172: }
173:
174: protected ForwardNameType(String memberGroupName) {
175: super (memberGroupName, false, false, null,
176: ForwardGrammar.this );
177: }
178:
179: /**
180: * @return a List of AnnotationInstance
181: */
182: protected List getAdditionalAnnotationsToCheck(
183: MemberDeclaration classMember) {
184: //
185: // curEntity will be either the pageflow class or an action method, where we'll look
186: // for @Jpf.Catch annotations that refer to exception-handler methods, which also have
187: // forwards that get rolled onto this entity.
188: //
189: List additionalEntities = new ArrayList();
190:
191: TypeDeclaration outerType = CompilerUtils
192: .getOuterClass(classMember);
193:
194: Collection classLevelCatches = getFlowControllerInfo()
195: .getMergedControllerAnnotation().getCatches();
196: addAdditionalAnnotationsToCheck(classLevelCatches,
197: outerType, additionalEntities);
198:
199: if (classMember instanceof MethodDeclaration) {
200: Collection methodLevelCatches = CompilerUtils
201: .getAnnotationArrayValue(classMember,
202: ACTION_TAG_NAME, CATCHES_ATTR, true);
203: addAdditionalAnnotationsToCheck(methodLevelCatches,
204: outerType, additionalEntities);
205: }
206:
207: return additionalEntities;
208: }
209:
210: private void addAdditionalAnnotationsToCheck(
211: Collection catches, TypeDeclaration outerType,
212: List additionalEntities) {
213: //
214: // For each of the given @Jpf.Catch annotations, find the matching @Jpf.ExceptionHandler method and
215: // add all of its @Jpf.Forward annotations to the list.
216: //
217: if (catches != null) {
218: for (Iterator ii = catches.iterator(); ii.hasNext();) {
219: AnnotationInstance catchAnnotation = (AnnotationInstance) ii
220: .next();
221: String methodName = CompilerUtils.getString(
222: catchAnnotation, METHOD_ATTR, false);
223:
224: if (methodName.length() > 0) {
225: MethodDeclaration[] allMethods = CompilerUtils
226: .getClassMethods(outerType, null);
227:
228: for (int i = 0; i < allMethods.length; i++) {
229: MethodDeclaration method = allMethods[i];
230: AnnotationInstance exHandlerAnnotation = CompilerUtils
231: .getAnnotation(method,
232: EXCEPTION_HANDLER_TAG_NAME);
233:
234: if (exHandlerAnnotation != null
235: && method.getSimpleName().equals(
236: methodName)) {
237: Collection forwardAnnotations = CompilerUtils
238: .getAnnotationArray(
239: exHandlerAnnotation,
240: FORWARDS_ATTR, false);
241:
242: for (Iterator i3 = forwardAnnotations
243: .iterator(); i3.hasNext();) {
244: AnnotationInstance forwardAnnotation = (AnnotationInstance) i3
245: .next();
246: additionalEntities
247: .add(forwardAnnotation);
248: }
249: }
250: }
251: }
252:
253: }
254: }
255: }
256:
257: protected String getErrorMessageExtraInfo() {
258: return CATCH_TAG_NAME;
259: }
260:
261: protected boolean allowExactDuplicates() {
262: return true;
263: }
264: }
265: }
|