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.genmodel.GenValidationModel;
023: import org.apache.beehive.netui.compiler.typesystem.declaration.ClassDeclaration;
024: import org.apache.beehive.netui.compiler.typesystem.declaration.AnnotationInstance;
025: import org.apache.beehive.netui.compiler.typesystem.declaration.FieldDeclaration;
026: import org.apache.beehive.netui.compiler.typesystem.declaration.TypeDeclaration;
027: import org.apache.beehive.netui.compiler.typesystem.env.CoreAnnotationProcessorEnv;
028: import org.apache.beehive.netui.compiler.typesystem.type.ClassType;
029: import org.apache.beehive.netui.compiler.model.XmlModelWriterException;
030:
031: import java.io.File;
032: import java.io.FileNotFoundException;
033: import java.io.IOException;
034:
035: abstract class FlowControllerGenerator extends BaseGenerator {
036: private static long _compilerJarTimestamp = -1;
037: private static final boolean ALWAYS_GENERATE = true; // TODO: this turns stale checking off. Do we need it?
038: private static final String CONTROL_ANNOTATION = JpfLanguageConstants.BEEHIVE_PACKAGE
039: + ".controls.api.bean.Control";
040:
041: protected FlowControllerGenerator(CoreAnnotationProcessorEnv env,
042: FlowControllerInfo fcInfo, Diagnostics diagnostics) {
043: super (env, fcInfo, diagnostics);
044: }
045:
046: protected abstract GenStrutsApp createStrutsApp(ClassDeclaration cl)
047: throws IOException, FatalCompileTimeException;
048:
049: public void generate(ClassDeclaration publicClass) {
050: GenStrutsApp app = null;
051: getFCSourceFileInfo().startBuild(getEnv(), publicClass);
052:
053: try {
054: // Write the Struts config XML, and the Validator config XML if appropriate.
055: app = createStrutsApp(publicClass);
056: GenValidationModel validationModel = new GenValidationModel(
057: publicClass, app, getEnv());
058:
059: if (!validationModel.isEmpty()) {
060: app.setValidationModel(validationModel);
061: validationModel.writeToFile();
062: }
063:
064: generateStrutsConfig(app, publicClass);
065:
066: // First, write out XML for any fields annotated with @Jpf.SharedFlowField or @Control.
067: writeFieldAnnotations(publicClass, app);
068: } catch (FatalCompileTimeException e) {
069: e.printDiagnostic(getDiagnostics());
070: } catch (Exception e) {
071: e.printStackTrace(); // @TODO log
072: assert e instanceof IOException : e.getClass().getName();
073: getDiagnostics().addError(publicClass,
074: "error.could-not-generate",
075: app != null ? app.getStrutsConfigFile() : null,
076: e.getMessage());
077: } finally {
078: getFCSourceFileInfo().endBuild();
079: }
080: }
081:
082: private void writeFieldAnnotations(ClassDeclaration classDecl,
083: GenStrutsApp app) {
084: try {
085: // We always write out the annotations XML file, even if there are no annotated elements.
086: // This is to prevent problems in iterative dev -- imagine compiling a file that has
087: // annotated elements, then removing those annotated elements, then recompiling. If
088: // we didn't write the (empty) file out, the old one would still be there, with stale
089: // data in it.
090: AnnotationToXML atx = new AnnotationToXML(classDecl);
091:
092: includeFieldAnnotations(atx, classDecl, null);
093: atx.writeXml(getDiagnostics(), getEnv());
094: } catch (Exception e) {
095: getDiagnostics().addError(classDecl,
096: "error.could-not-generate",
097: AnnotationToXML.getFilePath(classDecl),
098: e.getMessage());
099: e.printStackTrace(); // TODO: log instead
100: }
101: }
102:
103: /*
104: * Gets all the public, protected, default (package) access,
105: * and private fields, including inherited fields, that have
106: * desired annotations.
107: */
108: static boolean includeFieldAnnotations(AnnotationToXML atx,
109: TypeDeclaration typeDecl, String additionalAnnotation) {
110: boolean hasFieldAnnotations = false;
111:
112: if (!(typeDecl instanceof ClassDeclaration)) {
113: return hasFieldAnnotations;
114: }
115:
116: ClassDeclaration jclass = (ClassDeclaration) typeDecl;
117: FieldDeclaration[] fields = jclass.getFields();
118:
119: for (int i = 0; i < fields.length; i++) {
120: AnnotationInstance fieldAnnotation = CompilerUtils
121: .getAnnotation(
122: fields[i],
123: JpfLanguageConstants.SHARED_FLOW_FIELD_TAG_NAME);
124:
125: if (fieldAnnotation == null) {
126: fieldAnnotation = CompilerUtils
127: .getAnnotationFullyQualified(fields[i],
128: CONTROL_ANNOTATION);
129: }
130:
131: if (fieldAnnotation == null && additionalAnnotation != null) {
132: fieldAnnotation = CompilerUtils.getAnnotation(
133: fields[i], additionalAnnotation);
134: }
135:
136: if (fieldAnnotation != null) {
137: atx.include(fields[i], fieldAnnotation);
138: hasFieldAnnotations = true;
139: }
140: }
141:
142: ClassType super class = jclass.getSuperclass();
143: boolean super classHasFieldAnns = false;
144: if (super class != null) {
145: super classHasFieldAnns = includeFieldAnnotations(atx,
146: CompilerUtils.getDeclaration(super class),
147: additionalAnnotation);
148: }
149:
150: return hasFieldAnnotations || super classHasFieldAnns;
151: }
152:
153: protected void generateStrutsConfig(GenStrutsApp app,
154: ClassDeclaration publicClass) {
155: File strutsConfigFile = null;
156:
157: try {
158: strutsConfigFile = app.getStrutsConfigFile();
159:
160: if (ALWAYS_GENERATE || app.isStale()) {
161: // @TODO logger.info( "Writing Struts module: " + _strutsConfig.getStrutsConfigFile() );
162: app.writeToFile();
163: } else if (_compilerJarTimestamp > strutsConfigFile
164: .lastModified()) {
165: // @TODO logger.info( _compilerJarName + " has been updated; writing Struts module "
166: // + _strutsConfig.getStrutsConfigFile() );
167: app.writeToFile();
168: } else {
169: // @TODO logger.info( "Struts module " + _strutsConfig.getStrutsConfigFile() + " is up-to-date." );
170: }
171: } catch (FatalCompileTimeException e) {
172: e.printDiagnostic(getDiagnostics());
173: } catch (FileNotFoundException e) {
174: getDiagnostics().addError(
175: publicClass,
176: "error.could-not-generate",
177: strutsConfigFile != null ? strutsConfigFile
178: .getPath() : null, e.getMessage());
179: } catch (IOException e) {
180: getDiagnostics().addError(
181: publicClass,
182: "error.could-not-generate",
183: strutsConfigFile != null ? strutsConfigFile
184: .getPath() : null, e.getMessage());
185: } catch (XmlModelWriterException e) {
186: getDiagnostics().addError(
187: publicClass,
188: "error.could-not-generate",
189: strutsConfigFile != null ? strutsConfigFile
190: .getPath() : null, e.getMessage());
191: }
192: }
193:
194: protected FlowControllerInfo getFCSourceFileInfo() {
195: return (FlowControllerInfo) super.getSourceFileInfo();
196: }
197: }
|