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.JpfLanguageConstants;
026: import org.apache.beehive.netui.compiler.RuntimeVersionChecker;
027: import org.apache.beehive.netui.compiler.typesystem.declaration.AnnotationInstance;
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.ParameterDeclaration;
032: import org.apache.beehive.netui.compiler.typesystem.declaration.TypeDeclaration;
033: import org.apache.beehive.netui.compiler.typesystem.env.CoreAnnotationProcessorEnv;
034: import org.apache.beehive.netui.compiler.typesystem.type.DeclaredType;
035: import org.apache.beehive.netui.compiler.typesystem.type.TypeInstance;
036:
037: import java.util.Collection;
038: import java.util.Map;
039: import java.util.Iterator;
040:
041: public class CatchGrammar extends BaseFlowControllerGrammar implements
042: JpfLanguageConstants {
043: private static String[][] MUTUALLY_EXCLUSIVE_ATTRS = { { PATH_ATTR,
044: METHOD_ATTR } };
045: private static String[][] REQUIRED_ATTRS = { { TYPE_ATTR },
046: { PATH_ATTR, METHOD_ATTR } };
047:
048: private String _annotationRootName;
049:
050: public CatchGrammar(CoreAnnotationProcessorEnv env,
051: Diagnostics diags, String requiredRuntimeVersion,
052: RuntimeVersionChecker runtimeVersionChecker,
053: String annotationRootName, FlowControllerInfo fcInfo) {
054: super (env, diags, requiredRuntimeVersion,
055: runtimeVersionChecker, fcInfo);
056:
057: _annotationRootName = annotationRootName; // the parent of the list of @Jpf.Catch annotations.
058: addMemberType(METHOD_ATTR, new CatchTagMethodType());
059: AnnotationMemberType typeAttrType = new UniqueValueType(
060: CATCHES_ATTR, false, false, null, this ,
061: new TypeNameType(THROWABLE_CLASS_NAME, false, null,
062: this ));
063: addMemberType(TYPE_ATTR, typeAttrType);
064: addMemberType(PATH_ATTR, new ForwardToExternalPathType(
065: new WebappPathOrActionType(false, null, this , fcInfo),
066: null, this ));
067: addMemberType(MESSAGE_ATTR,
068: new AnnotationMemberType(null, this ));
069: addMemberType(MESSAGE_KEY_ATTR, new AnnotationMemberType(null,
070: this ));
071: }
072:
073: public String[][] getMutuallyExclusiveAttrs() {
074: return MUTUALLY_EXCLUSIVE_ATTRS;
075: }
076:
077: public String[][] getRequiredAttrs() {
078: return REQUIRED_ATTRS;
079: }
080:
081: /**
082: * @param checkResults map of member-name (String) -> result-from-checking (Object)
083: * @return a result (any Object) that will be passed back to the parent checker. May be null</code>.
084: */
085: protected Object onEndCheck(AnnotationInstance annotation,
086: AnnotationInstance[] parentAnnotations,
087: MemberDeclaration classMember, Map checkResults) {
088: MethodDeclaration handlerMethod = (MethodDeclaration) checkResults
089: .get(METHOD_ATTR);
090: DeclaredType exceptionType = (DeclaredType) checkResults
091: .get(TYPE_ATTR);
092:
093: //
094: // If either of these are null, then there was another already-reported error (e.g., type was unresolved).
095: //
096: if (handlerMethod == null || exceptionType == null) {
097: return null;
098: }
099:
100: //
101: // Make sure the given handler method can catch the right kind of exception.
102: //
103: ParameterDeclaration[] parameters = handlerMethod
104: .getParameters();
105:
106: //
107: // If the method's arguments are wrong in any way, don't worry about it -- the exception-handler checker will
108: // report an error.
109: //
110: if (parameters.length > 0) {
111: TypeInstance handledExceptionType = parameters[0].getType();
112:
113: if (!CompilerUtils.isAssignableFrom(handledExceptionType,
114: CompilerUtils.getDeclaration(exceptionType))) {
115: addError(annotation,
116: "error.incompatible-exception-handler",
117: handlerMethod.getSimpleName(), CompilerUtils
118: .getDeclaration(exceptionType)
119: .getQualifiedName());
120: }
121: }
122:
123: return null;
124: }
125:
126: private class CatchTagMethodType extends MemberMethodType {
127: public CatchTagMethodType() {
128: super (EXCEPTION_HANDLER_TAG_NAME,
129: "error.unresolved-exception-handler", null,
130: CatchGrammar.this );
131: }
132:
133: /**
134: * Derived classes can plug in here to do additional checks.
135: */
136: protected void checkMethod(
137: MethodDeclaration methodBeingChecked,
138: AnnotationValue value,
139: AnnotationInstance[] parentAnnotations,
140: MemberDeclaration classMember) {
141: //
142: // Make sure the current entity (class or action method) doesn't have two @Jpf.Catch annotations
143: // that refer to methods with duplicate @Jpf.Forwards.
144: //
145: Collection catches = CompilerUtils.getAnnotationArrayValue(
146: classMember, _annotationRootName, CATCHES_ATTR,
147: true);
148: TypeDeclaration outerType = CompilerUtils
149: .getOuterClass(classMember);
150:
151: if (catches == null) {
152: return;
153: }
154:
155: for (Iterator ii = catches.iterator(); ii.hasNext();) {
156: AnnotationInstance catchAnnotation = (AnnotationInstance) ii
157: .next();
158: //
159: // Find the method referred to in this annotation. If we can't find it, do nothing -- this
160: // will get caught elsewhere in the checking.
161: //
162: String methodName = CompilerUtils.getString(
163: catchAnnotation, METHOD_ATTR, false);
164:
165: if (methodName.length() > 0
166: && !methodName.equals(methodBeingChecked
167: .getSimpleName())) {
168: MethodDeclaration otherMethod = findMethod(
169: methodName, outerType);
170:
171: if (otherMethod != null) {
172: //
173: // Look through this other method's forwards. None may have the same name (and different path)
174: // as the current one.
175: //
176: Collection otherForwards = CompilerUtils
177: .getAnnotationArrayValue(otherMethod,
178: EXCEPTION_HANDLER_TAG_NAME,
179: FORWARDS_ATTR, false);
180:
181: for (Iterator i2 = otherForwards.iterator(); i2
182: .hasNext();) {
183: AnnotationInstance otherForward = (AnnotationInstance) i2
184: .next();
185: String otherForwardName = CompilerUtils
186: .getString(otherForward, NAME_ATTR,
187: true);
188: String otherForwardPath = CompilerUtils
189: .getString(otherForward, PATH_ATTR,
190: true);
191: String otherFwdNavigateTo = CompilerUtils
192: .getEnumFieldName(otherForward,
193: NAVIGATE_TO_ATTR, true);
194:
195: Collection forwards = CompilerUtils
196: .getAnnotationArrayValue(
197: methodBeingChecked,
198: EXCEPTION_HANDLER_TAG_NAME,
199: FORWARDS_ATTR, false);
200:
201: for (Iterator i3 = forwards.iterator(); i3
202: .hasNext();) {
203: AnnotationInstance forward = (AnnotationInstance) i3
204: .next();
205: String forwardName = CompilerUtils
206: .getString(forward, NAME_ATTR,
207: true);
208: String forwardPath = CompilerUtils
209: .getString(forward, PATH_ATTR,
210: true);
211: String fwdNavigateTo = CompilerUtils
212: .getEnumFieldName(forward,
213: NAVIGATE_TO_ATTR, true);
214:
215: if (forwardName != null
216: && forwardName
217: .equals(otherForwardName)) {
218: if ((forwardPath == null || !forwardPath
219: .equals(otherForwardPath))
220: && (fwdNavigateTo == null || !fwdNavigateTo
221: .equals(otherFwdNavigateTo))) {
222: addError(
223: value,
224: "error.duplicate-exception-handler-forwards",
225: new Object[] {
226: methodBeingChecked
227: .getSimpleName(),
228: methodName,
229: forwardName });
230: }
231: }
232: }
233: }
234: }
235: }
236: }
237: }
238: }
239: }
|