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.typesystem.declaration.TypeDeclaration;
022: import org.apache.beehive.netui.compiler.typesystem.declaration.ClassDeclaration;
023: import org.apache.beehive.netui.compiler.typesystem.declaration.AnnotationInstance;
024: import org.apache.beehive.netui.compiler.typesystem.declaration.FieldDeclaration;
025: import org.apache.beehive.netui.compiler.typesystem.type.TypeInstance;
026: import org.apache.beehive.netui.compiler.typesystem.type.DeclaredType;
027: import org.apache.beehive.netui.compiler.typesystem.env.CoreAnnotationProcessorEnv;
028:
029: import java.util.*;
030: import java.io.File;
031:
032: public class FlowControllerInfo extends SourceFileInfo implements
033: JpfLanguageConstants {
034: private static final ActionInfo[] EMPTY_ACTION_INFO_ARRAY = new ActionInfo[0];
035:
036: private Set _actions = new HashSet();
037: private Set _returnActions = null;
038: private Map _sharedFlowTypes = Collections.EMPTY_MAP;
039: private Map _sharedFlowTypeNames = Collections.EMPTY_MAP;
040: private Map _sharedFlowFiles = Collections.EMPTY_MAP;
041: private List _referencedFiles = new ArrayList();
042: private boolean _isBuilding = false;
043: private Map _messageBundlesByName = new HashMap();
044: private boolean _navigateToActionEnabled = false;
045: private boolean _navigateToPageEnabled = false;
046: private boolean _isNested;
047: private MergedControllerAnnotation _mergedControllerAnnotation;
048:
049: public static class ActionInfo {
050: private String _name;
051: private String _beanType = null;
052:
053: public ActionInfo(String name) {
054: _name = name;
055: }
056:
057: public ActionInfo(String name, String beanType) {
058: _name = name;
059: _beanType = beanType;
060: }
061:
062: public void setBeanType(String beanType) {
063: _beanType = beanType;
064: }
065:
066: public String getName() {
067: return _name;
068: }
069:
070: public String getBeanType() {
071: return _beanType;
072: }
073:
074: public boolean equals(Object o) {
075: if (o == null || !(o instanceof ActionInfo)) {
076: return false;
077: }
078:
079: ActionInfo other = (ActionInfo) o;
080: if (!_name.equals(other.getName()))
081: return false;
082: String otherBeanType = other.getBeanType();
083: return ((_beanType == null && otherBeanType == null) || (_beanType != null
084: && otherBeanType != null && _beanType
085: .equals(otherBeanType)));
086: }
087:
088: public int hashCode() {
089: int nameHash = _name.hashCode();
090: if (_beanType == null)
091: return nameHash;
092: return nameHash != 0 ? _beanType.hashCode() % nameHash
093: : _beanType.hashCode();
094: }
095: }
096:
097: public FlowControllerInfo(ClassDeclaration jclass) {
098: super (CompilerUtils.getSourceFile(jclass, true), jclass
099: .getQualifiedName());
100: }
101:
102: void startBuild(CoreAnnotationProcessorEnv env,
103: ClassDeclaration jclass) {
104: _isBuilding = true;
105: _mergedControllerAnnotation = new MergedControllerAnnotation(
106: jclass);
107: _isNested = _mergedControllerAnnotation.isNested();
108: setSharedFlowInfo(env);
109: }
110:
111: void endBuild() {
112: _isBuilding = false;
113: _sharedFlowTypes = null; // don't hang onto ClassDeclarations
114: _mergedControllerAnnotation = null;
115: }
116:
117: public ActionInfo[] getActions() {
118: return (ActionInfo[]) _actions.toArray(new ActionInfo[_actions
119: .size()]);
120: }
121:
122: public boolean isNested() {
123: return _isNested;
124: }
125:
126: public ActionInfo[] getReturnActions() {
127: if (_returnActions == null) {
128: return EMPTY_ACTION_INFO_ARRAY;
129: }
130:
131: return (ActionInfo[]) _returnActions
132: .toArray(new ActionInfo[_returnActions.size()]);
133: }
134:
135: public String getFormBeanType(String actionName) {
136: String bestType = null;
137:
138: for (Iterator ii = _actions.iterator(); ii.hasNext();) {
139: ActionInfo actionInfo = (ActionInfo) ii.next();
140: if (actionInfo.getName().equals(actionName)) {
141: String beanType = actionInfo.getBeanType();
142:
143: //
144: // In the case of overloaded actions, the non-form-bean action takes precedence. Otherwise,
145: // we look at the bean type names in alphabetical order.
146: //
147: if (beanType == null)
148: return null;
149: else if (bestType == null)
150: bestType = beanType;
151: else if (beanType.compareTo(bestType) < 0)
152: bestType = beanType;
153: }
154: }
155:
156: return bestType;
157: }
158:
159: int countReturnActions() {
160: return _returnActions != null ? _returnActions.size() : 0;
161: }
162:
163: public void addAction(String actionName, String formBeanType) {
164: _actions.add(new ActionInfo(actionName, formBeanType));
165: }
166:
167: public void addReturnAction(String returnActionName,
168: String formBeanType) {
169: if (_returnActions == null)
170: _returnActions = new HashSet();
171: _returnActions.add(new ActionInfo(returnActionName,
172: formBeanType));
173: }
174:
175: /**
176: * Get a list of referenced files (files that appear in Jpf.Forward paths).
177: */
178: public List getReferencedFiles() {
179: return _referencedFiles;
180: }
181:
182: public void addReferencedFile(File file) {
183: if (!file.equals(getSourceFile())) {
184: _referencedFiles.add(file);
185: }
186: }
187:
188: private void setSharedFlowInfo(CoreAnnotationProcessorEnv env) {
189: //
190: // First, find all referenced Shared Flow types.
191: //
192: _sharedFlowTypes = new LinkedHashMap();
193:
194: Collection sharedFlowRefs = _mergedControllerAnnotation
195: .getSharedFlowRefs();
196:
197: if (sharedFlowRefs != null) {
198: for (Iterator i = sharedFlowRefs.iterator(); i.hasNext();) {
199: AnnotationInstance sharedFlowRef = (AnnotationInstance) i
200: .next();
201: String name = CompilerUtils.getString(sharedFlowRef,
202: NAME_ATTR, true);
203: TypeInstance type = CompilerUtils.getTypeInstance(
204: sharedFlowRef, TYPE_ATTR, true);
205:
206: if (type instanceof DeclaredType) // if it's not a DeclaredType, the error will be caught elsewhere.
207: {
208: TypeDeclaration typeDecl = ((DeclaredType) type)
209: .getDeclaration();
210:
211: if (typeDecl != null) // If the declaration is null, it's an error type.
212: {
213: _sharedFlowTypes.put(name, typeDecl);
214: }
215: }
216: }
217: }
218:
219: //
220: // If there's no SharedFlowController, fall back to the deprecated Global.app.
221: //
222: if (_sharedFlowTypes.isEmpty()) {
223: TypeDeclaration type = env
224: .getTypeDeclaration(GLOBALAPP_FULL_CLASSNAME);
225: if (type != null)
226: _sharedFlowTypes.put(GLOBALAPP_SHARED_FLOW_NAME, type);
227: }
228:
229: _sharedFlowTypeNames = new LinkedHashMap();
230: _sharedFlowFiles = new LinkedHashMap();
231:
232: for (Iterator i = _sharedFlowTypes.entrySet().iterator(); i
233: .hasNext();) {
234: Map.Entry entry = (Map.Entry) i.next();
235: TypeDeclaration type = (TypeDeclaration) entry.getValue();
236: _sharedFlowTypeNames.put(entry.getKey(), type
237: .getQualifiedName());
238: File file = CompilerUtils.getSourceFile(type, false);
239:
240: if (file != null) {
241: _sharedFlowFiles.put(entry.getKey(), file);
242: _referencedFiles.add(file);
243: }
244: }
245: }
246:
247: public Map getSharedFlowTypes() {
248: assert _isBuilding : "use getSharedFlowTypeNames after check or generate phases";
249: return _sharedFlowTypes;
250: }
251:
252: public Map getSharedFlowTypeNames() {
253: return _sharedFlowTypeNames;
254: }
255:
256: public MergedControllerAnnotation getMergedControllerAnnotation() {
257: assert _isBuilding : "only valid during the check or generate phases";
258: return _mergedControllerAnnotation;
259: }
260:
261: public Map getMessageBundlesByName() {
262: return _messageBundlesByName;
263: }
264:
265: public void addMessageBundle(String bundleName, String bundlePath) {
266: _messageBundlesByName.put(bundleName, bundlePath);
267: }
268:
269: public String getControllerClassName() {
270: return getClassName();
271: }
272:
273: public Map getSharedFlowFiles() {
274: return _sharedFlowFiles;
275: }
276:
277: public void enableNavigateToAction() {
278: _navigateToActionEnabled = true;
279: }
280:
281: public void enableNavigateToPage() {
282: _navigateToPageEnabled = true;
283: }
284:
285: public boolean isNavigateToActionEnabled() {
286: return _navigateToActionEnabled;
287: }
288:
289: public boolean isNavigateToPageEnabled() {
290: return _navigateToPageEnabled;
291: }
292:
293: /**
294: * Add a return-action from an annotation.
295: * @return the form bean type, or null</code> if there is no form bean.
296: */
297: public TypeInstance addReturnAction(String returnActionName,
298: AnnotationInstance annotation, TypeDeclaration outerType) {
299: TypeInstance formBeanType = CompilerUtils.getTypeInstance(
300: annotation, OUTPUT_FORM_BEAN_TYPE_ATTR, true);
301:
302: if (formBeanType == null) {
303: String memberFieldName = CompilerUtils.getString(
304: annotation, OUTPUT_FORM_BEAN_ATTR, true);
305:
306: if (memberFieldName != null) {
307: FieldDeclaration field = CompilerUtils.findField(
308: outerType, memberFieldName);
309: if (field != null)
310: formBeanType = field.getType();
311: }
312: }
313:
314: String formTypeName = formBeanType != null
315: && formBeanType instanceof DeclaredType ? CompilerUtils
316: .getDeclaration((DeclaredType) formBeanType)
317: .getQualifiedName() : null;
318: addReturnAction(returnActionName, formTypeName);
319: return formBeanType;
320: }
321: }
|