001: /*
002: * Copyright 2005-2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005: * in compliance with the License. You may obtain a copy of the License at
006: *
007: * http://www.apache.org/licenses/LICENSE-2.0
008: *
009: * Unless required by applicable law or agreed to in writing, software distributed under the License
010: * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
011: * or implied. See the License for the specific language governing permissions and limitations under
012: * the License.
013: */
014:
015: package org.strecks.navigate.internal;
016:
017: import java.lang.annotation.Annotation;
018: import java.lang.reflect.Method;
019:
020: import org.strecks.controller.NavigableControllerAction;
021: import org.strecks.controller.internal.ActionBeanAnnotationReader;
022: import org.strecks.exceptions.ApplicationConfigurationException;
023: import org.strecks.navigate.NavigationHandler;
024: import org.strecks.navigate.NavigationHandlerFactory;
025: import org.strecks.navigate.NavigationHolder;
026: import org.strecks.navigate.annotation.NavigationInfo;
027: import org.strecks.util.Assert;
028: import org.strecks.util.ReflectHelper;
029:
030: /**
031: * <code>ActionBeanAnnotationReader</code> which reads navigation information using annotations,
032: * themselves identified using the marker annotation <code>NavigationInfo</code>
033: * @author Phil Zoio
034: */
035: public class BeanNavigationReader implements
036: ActionBeanAnnotationReader<NavigableControllerAction> {
037:
038: private NavigationHolder navigationHolder;
039:
040: public boolean readAnnotations(Class actionBeanClass) {
041:
042: NavigationHandlerInfo navigationInfo = readNavigationHandlerFactory(actionBeanClass);
043:
044: if (navigationInfo != null) {
045: NavigationHandler navigationHandler = getNavigationHandler(
046: actionBeanClass, navigationInfo);
047:
048: checkTypes(navigationHandler.getClass(), navigationInfo
049: .getMethod());
050:
051: navigationHolder = new NavigationHolder(navigationHandler,
052: navigationInfo.getFactory(), navigationInfo
053: .getMethod());
054:
055: return true;
056: } else {
057: throw new ApplicationConfigurationException(
058: "No annotation using the @"
059: + NavigationInfo.class.getSimpleName()
060: + " annotation found. This is needed to determine the navigation for the action bean "
061: + actionBeanClass);
062: }
063:
064: }
065:
066: public void populateController(NavigableControllerAction controller) {
067: controller.setNavigationHolder(navigationHolder);
068: }
069:
070: public NavigationHolder getNavigationHolder() {
071: return navigationHolder;
072: }
073:
074: void checkTypes(Class navigationHandlerClass,
075: Method extractionMethod) {
076: Class<Object> genericType = getGenericType(navigationHandlerClass);
077:
078: if (genericType != null) {
079: Class returnType = extractionMethod.getReturnType();
080:
081: if (!genericType.isAssignableFrom(returnType)) {
082: throw new ApplicationConfigurationException(
083: "The return type of "
084: + extractionMethod.getName()
085: + "() in "
086: + extractionMethod.getDeclaringClass()
087: .getName()
088: + " is not compatible with the parameterized generic type "
089: + genericType
090: + " of the navigation handler "
091: + navigationHandlerClass.getName());
092:
093: }
094: }
095: }
096:
097: @SuppressWarnings("unchecked")
098: private Class<Object> getGenericType(Class navigationHandlerClass) {
099: Class<Object> genericType = ReflectHelper.getGenericType(
100: navigationHandlerClass, NavigationHandler.class);
101: return genericType;
102: }
103:
104: NavigationHandlerInfo readNavigationHandlerFactory(Class actionClass) {
105:
106: Method[] methods = actionClass.getMethods();
107:
108: NavigationReader reader = null;
109: Method containingMethod = null;
110: Annotation annotationFound = null;
111:
112: boolean found = false;
113:
114: for (Method method : methods) {
115:
116: NavigationReader tempReader = null;
117: Annotation tempAnnotation = null;
118:
119: Annotation[] annotations = method.getAnnotations();
120:
121: for (Annotation annotation : annotations) {
122: Class<? extends Annotation> annotationType = annotation
123: .annotationType();
124: NavigationInfo navigationInfo = annotationType
125: .getAnnotation(NavigationInfo.class);
126:
127: if (navigationInfo != null) {
128: tempReader = ReflectHelper.createInstance(
129: navigationInfo.value(),
130: NavigationReader.class);
131: tempAnnotation = annotation;
132: }
133: }
134:
135: if (tempReader != null) {
136: if (found) {
137: throw new ApplicationConfigurationException(
138: actionClass.getName()
139: + " violates rule that only one method containing an annotation which uses the @"
140: + NavigationInfo.class
141: .getSimpleName()
142: + " annotation is permitted");
143: }
144:
145: ReflectHelper.checkParameterTypeLength(method, 0);
146:
147: if (!ReflectHelper.hasReturnValue(method)) {
148: throw new ApplicationConfigurationException(
149: actionClass.getName()
150: + " contains an annotation which uses the @"
151: + NavigationInfo.class
152: .getSimpleName()
153: + " annotation but returns void");
154: }
155:
156: reader = tempReader;
157: containingMethod = method;
158: annotationFound = tempAnnotation;
159: found = true;
160: }
161: }
162:
163: if (reader != null) {
164: return reader.getNavigationHandlerFactory(annotationFound,
165: actionClass, containingMethod);
166: } else
167: return null;
168:
169: }
170:
171: NavigationHandler getNavigationHandler(Class actionClass,
172: NavigationHandlerInfo info) {
173: NavigationHandlerFactory factory = info.getFactory();
174: Class type = info.getMethod().getReturnType();
175:
176: NavigationHandler navigationHandler = factory
177: .getNavigationHandler(actionClass.getName(), type);
178:
179: // make sure that navigationHandler is not null
180: Assert.notNull(navigationHandler);
181: return navigationHandler;
182: }
183:
184: }
|