/*
* Copyright 2005-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.strecks.navigate.internal;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import org.strecks.controller.NavigableControllerAction;
import org.strecks.controller.internal.ActionBeanAnnotationReader;
import org.strecks.exceptions.ApplicationConfigurationException;
import org.strecks.navigate.NavigationHandler;
import org.strecks.navigate.NavigationHandlerFactory;
import org.strecks.navigate.NavigationHolder;
import org.strecks.navigate.annotation.NavigationInfo;
import org.strecks.util.Assert;
import org.strecks.util.ReflectHelper;
/**
* <code>ActionBeanAnnotationReader</code> which reads navigation information using annotations,
* themselves identified using the marker annotation <code>NavigationInfo</code>
* @author Phil Zoio
*/
public class BeanNavigationReader implements ActionBeanAnnotationReader<NavigableControllerAction>
{
private NavigationHolder navigationHolder;
public boolean readAnnotations(Class actionBeanClass)
{
NavigationHandlerInfo navigationInfo = readNavigationHandlerFactory(actionBeanClass);
if (navigationInfo != null)
{
NavigationHandler navigationHandler = getNavigationHandler(actionBeanClass, navigationInfo);
checkTypes(navigationHandler.getClass(), navigationInfo.getMethod());
navigationHolder = new NavigationHolder(navigationHandler, navigationInfo.getFactory(), navigationInfo
.getMethod());
return true;
}
else
{
throw new ApplicationConfigurationException("No annotation using the @"
+ NavigationInfo.class.getSimpleName()
+ " annotation found. This is needed to determine the navigation for the action bean "
+ actionBeanClass);
}
}
public void populateController(NavigableControllerAction controller)
{
controller.setNavigationHolder(navigationHolder);
}
public NavigationHolder getNavigationHolder()
{
return navigationHolder;
}
void checkTypes(Class navigationHandlerClass, Method extractionMethod)
{
Class<Object> genericType = getGenericType(navigationHandlerClass);
if (genericType != null)
{
Class returnType = extractionMethod.getReturnType();
if (!genericType.isAssignableFrom(returnType))
{
throw new ApplicationConfigurationException("The return type of " + extractionMethod.getName()
+ "() in " + extractionMethod.getDeclaringClass().getName()
+ " is not compatible with the parameterized generic type " + genericType
+ " of the navigation handler " + navigationHandlerClass.getName());
}
}
}
@SuppressWarnings("unchecked")
private Class<Object> getGenericType(Class navigationHandlerClass)
{
Class<Object> genericType = ReflectHelper.getGenericType(navigationHandlerClass, NavigationHandler.class);
return genericType;
}
NavigationHandlerInfo readNavigationHandlerFactory(Class actionClass)
{
Method[] methods = actionClass.getMethods();
NavigationReader reader = null;
Method containingMethod = null;
Annotation annotationFound = null;
boolean found = false;
for (Method method : methods)
{
NavigationReader tempReader = null;
Annotation tempAnnotation = null;
Annotation[] annotations = method.getAnnotations();
for (Annotation annotation : annotations)
{
Class<? extends Annotation> annotationType = annotation.annotationType();
NavigationInfo navigationInfo = annotationType.getAnnotation(NavigationInfo.class);
if (navigationInfo != null)
{
tempReader = ReflectHelper.createInstance(navigationInfo.value(), NavigationReader.class);
tempAnnotation = annotation;
}
}
if (tempReader != null)
{
if (found)
{
throw new ApplicationConfigurationException(actionClass.getName()
+ " violates rule that only one method containing an annotation which uses the @"
+ NavigationInfo.class.getSimpleName() + " annotation is permitted");
}
ReflectHelper.checkParameterTypeLength(method, 0);
if (!ReflectHelper.hasReturnValue(method))
{
throw new ApplicationConfigurationException(actionClass.getName()
+ " contains an annotation which uses the @" + NavigationInfo.class.getSimpleName()
+ " annotation but returns void");
}
reader = tempReader;
containingMethod = method;
annotationFound = tempAnnotation;
found = true;
}
}
if (reader != null)
{
return reader.getNavigationHandlerFactory(annotationFound, actionClass, containingMethod);
}
else
return null;
}
NavigationHandler getNavigationHandler(Class actionClass, NavigationHandlerInfo info)
{
NavigationHandlerFactory factory = info.getFactory();
Class type = info.getMethod().getReturnType();
NavigationHandler navigationHandler = factory.getNavigationHandler(actionClass.getName(), type);
// make sure that navigationHandler is not null
Assert.notNull(navigationHandler);
return navigationHandler;
}
}