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;
020:
021: import org.apache.beehive.netui.compiler.genmodel.GenStrutsApp;
022: import org.apache.beehive.netui.compiler.grammar.ControllerGrammar;
023: import org.apache.beehive.netui.compiler.grammar.WebappPathOrActionType;
024: import org.apache.beehive.netui.compiler.typesystem.declaration.AnnotationInstance;
025: import org.apache.beehive.netui.compiler.typesystem.declaration.ClassDeclaration;
026: import org.apache.beehive.netui.compiler.typesystem.declaration.FieldDeclaration;
027: import org.apache.beehive.netui.compiler.typesystem.declaration.Modifier;
028: import org.apache.beehive.netui.compiler.typesystem.declaration.PackageDeclaration;
029: import org.apache.beehive.netui.compiler.typesystem.declaration.TypeDeclaration;
030: import org.apache.beehive.netui.compiler.typesystem.env.CoreAnnotationProcessorEnv;
031: import org.apache.beehive.netui.compiler.typesystem.type.DeclaredType;
032: import org.apache.beehive.netui.compiler.typesystem.type.TypeInstance;
033:
034: import java.io.File;
035: import java.io.IOException;
036: import java.util.Collection;
037: import java.util.Iterator;
038:
039: public class PageFlowChecker extends FlowControllerChecker implements
040: JpfLanguageConstants {
041: public PageFlowChecker(CoreAnnotationProcessorEnv env,
042: Diagnostics diagnostics, FlowControllerInfo fcInfo) {
043: super (env, fcInfo, diagnostics);
044: }
045:
046: protected void checkField(FieldDeclaration field,
047: TypeDeclaration jclass) {
048: //
049: // Check to make sure that if this is a Shared Flow field, its type matches up with the type declared
050: // for the shared flow of that name.
051: //
052: AnnotationInstance sfFieldAnn = CompilerUtils.getAnnotation(
053: field, SHARED_FLOW_FIELD_TAG_NAME);
054:
055: if (sfFieldAnn != null) {
056: String sharedFlowName = CompilerUtils.getString(sfFieldAnn,
057: NAME_ATTR, true);
058:
059: // sharedFlow name is a required attribute, if not defined return and let apt error.
060: if (sharedFlowName == null) {
061: return;
062: }
063:
064: Collection sharedFlowRefs = getFCSourceFileInfo()
065: .getMergedControllerAnnotation()
066: .getSharedFlowRefs();
067:
068: boolean foundOne = false;
069:
070: if (sharedFlowRefs != null) {
071: for (Iterator ii = sharedFlowRefs.iterator(); ii
072: .hasNext();) {
073: AnnotationInstance sharedFlowRef = (AnnotationInstance) ii
074: .next();
075: if (sharedFlowName.equals(CompilerUtils.getString(
076: sharedFlowRef, NAME_ATTR, true))) {
077: foundOne = true;
078:
079: TypeInstance sfType = CompilerUtils
080: .getTypeInstance(sharedFlowRef,
081: TYPE_ATTR, true);
082: TypeInstance ft = field.getType();
083:
084: if (!(sfType instanceof DeclaredType)
085: || !CompilerUtils.isAssignableFrom(ft,
086: ((DeclaredType) sfType)
087: .getDeclaration())) {
088: getDiagnostics().addError(
089: field,
090: "error.field-not-assignable",
091: CompilerUtils.getDeclaration(
092: (DeclaredType) sfType)
093: .getQualifiedName());
094: }
095: }
096: }
097: }
098:
099: if (!foundOne) {
100: getDiagnostics().addError(sfFieldAnn,
101: "error.no-matching-shared-flow-declared",
102: SHARED_FLOW_REF_TAG_NAME, sharedFlowName);
103: }
104: } else if (CompilerUtils.isAssignableFrom(
105: SHARED_FLOW_BASE_CLASS, field.getType(), getEnv())
106: && !CompilerUtils
107: .isAssignableFrom(GLOBALAPP_BASE_CLASS, field
108: .getType(), getEnv())) {
109: // Output a warning if the field type extends SharedFlowController but there's no @Jpf.SharedFlowField
110: // annotation (in which case the field won't get auto-initialized at runtime.
111: getDiagnostics().addWarning(
112: field,
113: "warning.shared-flow-field-no-annotation",
114: field.getSimpleName(),
115: SHARED_FLOW_BASE_CLASS,
116: ANNOTATION_INTERFACE_PREFIX
117: + SHARED_FLOW_FIELD_TAG_NAME);
118: }
119:
120: super .checkField(field, jclass);
121: }
122:
123: protected void doAdditionalClassChecks(ClassDeclaration jpfClass) {
124: // Make sure there are no other page flows in this package/directory.
125: checkForOverlappingClasses(jpfClass, JPF_BASE_CLASS,
126: JPF_FILE_EXTENSION_DOT, "error.overlapping-pageflows");
127:
128: PackageDeclaration pkg = jpfClass.getPackage();
129: File jpfFile = CompilerUtils.getSourceFile(jpfClass, true);
130: File parentDir = jpfFile.getParentFile();
131:
132: //
133: // Check the package name.
134: //
135: String jpfPackageName = pkg.getQualifiedName();
136:
137: if (jpfPackageName != null && jpfPackageName.length() > 0) {
138: String expectedPackage = parentDir.getAbsolutePath()
139: .replace('\\', '/').replace('/', '.');
140:
141: if (!expectedPackage.endsWith(jpfPackageName)) {
142: getDiagnostics().addError(jpfClass,
143: "error.wrong-package-for-directory",
144: parentDir.getPath());
145: }
146: }
147:
148: //
149: // Issue a warning if the class name is the same as the parent package name.
150: // This causes ambiguity when resolving inner classes.
151: //
152: if (jpfClass.getSimpleName().equals(pkg.getQualifiedName())) {
153: getDiagnostics().addWarning(jpfClass,
154: "warning.classname-same-as-package");
155: }
156:
157: //
158: // Make sure every .jpf has a begin action if the class isn't abstract.
159: //
160: boolean isAbstract = jpfClass.hasModifier(Modifier.ABSTRACT);
161: FlowControllerInfo fcInfo = getFCSourceFileInfo();
162:
163: if (!WebappPathOrActionType.actionExists(BEGIN_ACTION_NAME,
164: jpfClass, null, getEnv(), fcInfo, true)
165: && !isAbstract) {
166: getDiagnostics()
167: .addError(jpfClass, "error.no-begin-action");
168: }
169:
170: //
171: // Make sure every nested pageflow has a returnAction. Return actions are added by ForwardGrammar, but
172: // here we also need to add them for inherited Forwards and SimpleActions.
173: //
174: if (fcInfo.isNested()) {
175: MergedControllerAnnotation mca = fcInfo
176: .getMergedControllerAnnotation();
177: addReturnActions(mca.getSimpleActions(), fcInfo, jpfClass,
178: CONDITIONAL_FORWARDS_ATTR);
179: addReturnActions(mca.getForwards(), fcInfo, jpfClass, null);
180:
181: if (!isAbstract && fcInfo.countReturnActions() == 0) {
182: getDiagnostics().addError(jpfClass,
183: "error.no-return-action",
184: ANNOTATION_INTERFACE_PREFIX + FORWARD_TAG_NAME,
185: RETURN_ACTION_ATTR);
186: }
187: }
188: }
189:
190: private void addReturnActions(Collection forwardAnnotations,
191: FlowControllerInfo fcInfo, TypeDeclaration outerType,
192: String childArrayAttr) {
193: for (Iterator ii = forwardAnnotations.iterator(); ii.hasNext();) {
194: AnnotationInstance ann = (AnnotationInstance) ii.next();
195: String returnAction = CompilerUtils.getString(ann,
196: RETURN_ACTION_ATTR, true);
197: if (returnAction != null)
198: fcInfo.addReturnAction(returnAction, ann, outerType);
199:
200: if (childArrayAttr != null) {
201: Collection children = CompilerUtils.getAnnotationArray(
202: ann, childArrayAttr, true);
203: if (children != null)
204: addReturnActions(children, fcInfo, outerType, null);
205: }
206: }
207: }
208:
209: protected String getDesiredBaseClass(ClassDeclaration jclass) {
210: return JPF_BASE_CLASS;
211: }
212:
213: protected GenStrutsApp createStrutsApp(ClassDeclaration jclass)
214: throws IOException, FatalCompileTimeException {
215: File sourceFile = CompilerUtils.getSourceFile(jclass, true);
216: return new GenStrutsApp(sourceFile, jclass, getEnv(),
217: getFCSourceFileInfo(), true, getDiagnostics());
218: }
219:
220: protected AnnotationGrammar getControllerGrammar() {
221: return new JpfControllerGrammar();
222: }
223:
224: private class JpfControllerGrammar extends ControllerGrammar {
225: public JpfControllerGrammar() {
226: super (PageFlowChecker.this .getEnv(), PageFlowChecker.this
227: .getDiagnostics(), PageFlowChecker.this
228: .getRuntimeVersionChecker(), PageFlowChecker.this
229: .getFCSourceFileInfo());
230: addMemberType(NESTED_ATTR, new AnnotationMemberType(null,
231: this ));
232: addMemberType(LONGLIVED_ATTR, new AnnotationMemberType(
233: null, this));
234: }
235: }
236: }
|