All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cz.wicketstuff.boss.flow.processor.ext.AnnotationFlowFactory Maven / Gradle / Ivy

There is a newer version: 1.3.1
Show newest version
/*
 * Et netera, http://boss.etnetera.cz - Copyright (C) 2012 
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License (version 2.1) as published by the Free Software
 * Foundation.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * See the GNU Lesser General Public License for more details:
 * http://www.gnu.org/licenses/lgpl-3.0.txt
 * 
 */
package cz.wicketstuff.boss.flow.processor.ext;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cz.wicketstuff.boss.flow.annotation.FlowConditionProcessor;
import cz.wicketstuff.boss.flow.annotation.FlowStateEvent;
import cz.wicketstuff.boss.flow.annotation.FlowStateValidation;
import cz.wicketstuff.boss.flow.annotation.FlowSwitchProcessorExpression;
import cz.wicketstuff.boss.flow.annotation.FlowTransitionEvent;
import cz.wicketstuff.boss.flow.model.IFlowCarter;
import cz.wicketstuff.boss.flow.processor.condition.CannotProcessConditionException;
import cz.wicketstuff.boss.flow.util.listener.FlowStateChangeListenerCollection;
import cz.wicketstuff.boss.flow.util.listener.FlowStateValidationListenerCollection;
import cz.wicketstuff.boss.flow.util.listener.FlowTransitionChangeListenerCollection;
import cz.wicketstuff.boss.flow.util.processor.FlowConditionStateProcessorCollection;
import cz.wicketstuff.boss.flow.util.processor.FlowSwitchStateProcessorCollection;

public class AnnotationFlowFactory {

	protected static final Logger logger = LoggerFactory.getLogger(AnnotationFlowFactory.class);
	
	public AnnotationFlowFactory() {
	}
	
	public FlowStateChangeListenerCollection newFlowStateChangeListenerCollection() {
		return new FlowStateChangeListenerCollection();
	}  
	
	public FlowStateChangeListenerCollection getStateChangeListeners(Object bean) throws FlowAnnotationException {
		return getStateChangeListeners(bean, newFlowStateChangeListenerCollection());
	}

	public FlowStateChangeListenerCollection getStateChangeListeners(final Object bean, FlowStateChangeListenerCollection listeners) throws FlowAnnotationException {
		for(final Method method : findMethodCandidates(bean, FlowStateEvent.class)) {
			FlowStateEvent eventAnnotation = method.getAnnotation(FlowStateEvent.class);
			if(logger.isDebugEnabled()) {
				logger.debug("Adding annoted FlowStateEvent method '" + method.getName() + "' of bean '" + bean + "'");
			}
			listeners.add(new FilteredStateChangeListener(eventAnnotation.event(), "".equals(eventAnnotation.stateNameRegex()) ? null : eventAnnotation.stateNameRegex(), eventAnnotation.type(), eventAnnotation.priority()) {

				private static final long serialVersionUID = 1L;

				@Override
				protected void onStateEntryFiltered(IFlowCarter flow) {
					try {
						method.invoke(bean, flow);
					} catch ( IllegalAccessException
							| IllegalArgumentException
							| InvocationTargetException e) {
						throw new IllegalStateException("Cannot invoke annoted method '" + method.getName() + "' of bean '" + bean + "' because: " + e.getMessage(), e);
					}
					
				}

				@Override
				protected void onStateLeavingFiltered(IFlowCarter flow) {
					try {
						method.invoke(bean, flow);
					} catch ( IllegalAccessException
							| IllegalArgumentException
							| InvocationTargetException e) {
						throw new IllegalStateException("Cannot invoke annoted method of bean '" + bean + "' because: " + e.getMessage(), e);
					}
				}
				
			});
		}
		listeners.sort();
		return listeners;
	}

	public FlowStateValidationListenerCollection newFlowStateValidationListenerCollection() {
		return new FlowStateValidationListenerCollection();
	}
	
	public FlowStateValidationListenerCollection getStateValidationListeners(Object bean) throws FlowAnnotationException {
		return getStateValidationListeners(bean, newFlowStateValidationListenerCollection());
	}

	public FlowStateValidationListenerCollection getStateValidationListeners(final Object bean, FlowStateValidationListenerCollection listeners) throws FlowAnnotationException {
		for(final Method method : findMethodCandidates(bean, FlowStateValidation.class)) {
			FlowStateValidation eventAnnotation = method.getAnnotation(FlowStateValidation.class);
			if(logger.isDebugEnabled()) {
				logger.debug("Adding annoted FlowStateValidation method '" + method.getName() + "' of bean '" + bean + "'");
			}
			listeners.add(new FilteredStateValidationListener(eventAnnotation.event(), "".equals(eventAnnotation.stateNameRegex()) ? null : eventAnnotation.stateNameRegex(), eventAnnotation.type(), eventAnnotation.priority()) {

				private static final long serialVersionUID = 1L;

				@Override
				protected void onStateValidFiltered(IFlowCarter flow) {
					try {
						method.invoke(bean, flow);
					} catch ( IllegalAccessException
							| IllegalArgumentException
							| InvocationTargetException e) {
						throw new IllegalStateException("Cannot invoke annoted method '" + method.getName() + "' of bean '" + bean + "' because: " + e.getMessage(), e);
					}					
				}

				@Override
				protected void onStateInvalidFiltered(IFlowCarter flow) {
					try {
						method.invoke(bean, flow);
					} catch ( IllegalAccessException
							| IllegalArgumentException
							| InvocationTargetException e) {
						throw new IllegalStateException("Cannot invoke annoted method '" + method.getName() + "' of bean '" + bean + "' because: " + e.getMessage(), e);
					}
				}
				
			});
		}
		listeners.sort();
		return listeners;
	}

	public FlowTransitionChangeListenerCollection newFlowTransitionChangeListenerCollection() {
		return new FlowTransitionChangeListenerCollection();
	}
	
	public FlowTransitionChangeListenerCollection getTransitionChangeListeners(Object bean) throws FlowAnnotationException {
		return getTransitionChangeListeners(bean, newFlowTransitionChangeListenerCollection());
	}

	public FlowTransitionChangeListenerCollection getTransitionChangeListeners(final Object bean, FlowTransitionChangeListenerCollection listeners) throws FlowAnnotationException {
		for(final Method method : findMethodCandidates(bean, FlowTransitionEvent.class)) {
			FlowTransitionEvent eventAnnotation = method.getAnnotation(FlowTransitionEvent.class);
			if(logger.isDebugEnabled()) {
				logger.debug("Adding annoted FlowTransitionEvent change listener method '" + method.getName() + "' of bean '" + bean + "'");
			}
			listeners.add(new FilteredTransitionChangeListener(eventAnnotation.event(), "".equals(eventAnnotation.transitionNameRegex()) ? null : eventAnnotation.transitionNameRegex(), eventAnnotation.priority()) {

				private static final long serialVersionUID = 1L;

				@Override
				protected void onTransitionStartFiltered(IFlowCarter flow) {
					try {
						method.invoke(bean, flow);
					} catch ( IllegalAccessException
							| IllegalArgumentException
							| InvocationTargetException e) {
						throw new IllegalStateException("Cannot invoke annoted method '" + method.getName() + "' of bean '" + bean + "' because: " + e.getMessage(), e);
					}
				}

				@Override
				protected void onTransitionFinishedFiltered(IFlowCarter flow) {
					try {
						method.invoke(bean, flow);
					} catch ( IllegalAccessException
							| IllegalArgumentException
							| InvocationTargetException e) {
						throw new IllegalStateException("Cannot invoke annoted method '" + method.getName() + "' of bean '" + bean + "' because: " + e.getMessage(), e);
					}
				}
				
			});
			
		}
		listeners.sort();
		return listeners;
	}

	public FlowConditionStateProcessorCollection newFlowConditionStateCollection() {
		return new FlowConditionStateProcessorCollection();
	}
	
	public FlowConditionStateProcessorCollection getFlowConditionProcessors(Object bean) throws FlowAnnotationException {
		return getFlowConditionProcessors(bean, newFlowConditionStateCollection());
	}
	
	public FlowConditionStateProcessorCollection getFlowConditionProcessors(final Object bean, FlowConditionStateProcessorCollection processorCollection) throws FlowAnnotationException {
		for(final Method method : findMethodConditionCandidates(bean, FlowConditionProcessor.class)) {
			FlowConditionProcessor conditionAnnotation = method.getAnnotation(FlowConditionProcessor.class);
			if(logger.isDebugEnabled()) {
				logger.debug("Adding annoted FlowConditionProcessor method '" + method.getName() + "' of bean '" + bean + "'");
			}
			processorCollection.add(
					new FilteredStateConditionProcessor(
							"".equals(conditionAnnotation.conditionExpressionRegex()) ? null : conditionAnnotation.conditionExpressionRegex(),
							"".equals(conditionAnnotation.stateNameRegex()) ? null : conditionAnnotation.stateNameRegex(), 
							conditionAnnotation.type()) {

						private static final long serialVersionUID = 1L;

						@Override
						public boolean ifCondition(String conditionExpression,
								IFlowCarter flow)
								throws CannotProcessConditionException {
							try {
								return (boolean) method.invoke(bean, conditionExpression, flow);
							} catch ( IllegalAccessException
									| IllegalArgumentException
									| InvocationTargetException e) {
								throw new IllegalStateException("Cannot invoke annoted method '" + method.getName() + "', condition '" + conditionExpression + ", of bean " + bean + "' because: " + e.getMessage(), e);
							}
						}
			});
		}
		return processorCollection;
	}

	public FlowSwitchStateProcessorCollection newFlowSwitchStateProcessorCollection() {
		return new FlowSwitchStateProcessorCollection();
	}
	
	public FlowSwitchStateProcessorCollection getFlowSwitchProcessors(Object bean) throws FlowAnnotationException {
		return getFlowSwitchProcessors(bean, newFlowSwitchStateProcessorCollection());
	}
	
	public FlowSwitchStateProcessorCollection getFlowSwitchProcessors(final Object bean, FlowSwitchStateProcessorCollection processorCollection) throws FlowAnnotationException {
		for(final Method method : findMethodSwitchCandidates(bean, FlowSwitchProcessorExpression.class)) {
			FlowSwitchProcessorExpression conditionAnnotation = method.getAnnotation(FlowSwitchProcessorExpression.class);
			if(logger.isDebugEnabled()) {
				logger.debug("Adding annoted FlowSwitchProcessorExpression method '" + method.getName() + "' of bean '" + bean + "'");
			}
			processorCollection.add(
					new FilteredStateSwitchProcessor(
							"".equals(conditionAnnotation.switchExpressionRegex()) ? null : conditionAnnotation.switchExpressionRegex(),
							"".equals(conditionAnnotation.stateNameRegex()) ? null : conditionAnnotation.stateNameRegex(), 
							conditionAnnotation.type()) {

						private static final long serialVersionUID = 1L;

						@Override
						public String resolveSwitchExpression(
								IFlowCarter flow, String switchExpression) {
							try {
								return (String) method.invoke(bean, switchExpression, flow);
							} catch ( IllegalAccessException
									| IllegalArgumentException
									| InvocationTargetException e) {
								throw new IllegalStateException("Cannot invoke annoted method '" + method.getName() + "', condition '" + switchExpression + ", of bean '" + bean + "' because: " + e.getMessage(), e);
							}
						}

			});
		}
		return processorCollection;
	}
	
	public List findMethodCandidates(Object bean, Class annotation) throws FlowAnnotationException {
		List list = new ArrayList();
		for(final Method method : bean.getClass().getMethods()) {
			if(method.isAnnotationPresent(annotation)) {
				checkFlowMethod(method, bean);
				list.add(method);
			}
		}
		return list;
	}

	public List findMethodConditionCandidates(Object bean, Class annotation) throws FlowAnnotationException {
		List list = new ArrayList();
		for(final Method method : bean.getClass().getMethods()) {
			if(method.isAnnotationPresent(annotation)) {
				checkConditionMethod(method, bean);
				list.add(method);
			}
		}
		return list;
	}

	public List findMethodSwitchCandidates(Object bean, Class annotation) throws FlowAnnotationException {
		List list = new ArrayList();
		for(final Method method : bean.getClass().getMethods()) {
			if(method.isAnnotationPresent(annotation)) {
				checkSwitchMethod(method, bean);
				list.add(method);
			}
		}
		return list;
	}
	
	public void checkFlowMethod(Method method, Object bean) throws FlowAnnotationException {
		Class[] parameters = method.getParameterTypes();
		if(parameters.length != 1) {
			throw new FlowAnnotationException("The method '" + method.getName() + "' of bean '" + bean + "' has to have just one parameter, not more, not less!");
		}
		try {
			if(parameters[0].asSubclass(IFlowCarter.class) == null) {
				throw new FlowAnnotationException("The paremeter of method '" + method.getName() + "' of bean '" + bean + "' is not a type of IFlowCarter!");
			}					
		} catch (ClassCastException e) {					
			throw new FlowAnnotationException("The paremeter of method '" + method.getName() + "' of bean '" + bean + "' is not a type of IFlowCarter!", e);
		}
		if(!Modifier.isPublic(method.getModifiers())) {
			throw new FlowAnnotationException("The paremeter of method '" + method.getName() + "' of bean '" + bean + "' is not public!");					
		}
	}

	public void checkConditionMethod(Method method, Object bean) throws FlowAnnotationException {
		Class[] parameters = method.getParameterTypes();
		if(parameters.length != 2) {
			throw new FlowAnnotationException("The method '" + method.getName() + "' of bean '" + bean + "' has to have just one parameter, not more, not less! Correct parameters are String, IFlowCarter");
		}
		try {
			if(method.getReturnType().asSubclass(boolean.class) == null) {
				throw new FlowAnnotationException("The return type of method '" + method.getName() + "' of bean '" + bean + "' is not a type of boolean!");
			}					
		} catch (ClassCastException e) {					
			throw new FlowAnnotationException("The return type method '" + method.getName() + "' of bean '" + bean + "' is not a type of boolean!", e);
		}
		try {
			if(parameters[0].asSubclass(String.class) == null) {
				throw new FlowAnnotationException("The first paremeter of method '" + method.getName() + "' of bean '" + bean + "' is not a type of String!");
			}					
		} catch (ClassCastException e) {					
			throw new FlowAnnotationException("The first paremeter of method '" + method.getName() + "' of bean '" + bean + "' is not a type of String!", e);
		}
		try {
			if(parameters[1].asSubclass(IFlowCarter.class) == null) {
				throw new FlowAnnotationException("The second paremeter of method '" + method.getName() + "' of bean '" + bean + "' is not a type of IFlowCarter!");
			}					
		} catch (ClassCastException e) {					
			throw new FlowAnnotationException("The second paremeter of method '" + method.getName() + "' of bean '" + bean + "' is not a type of IFlowCarter!", e);
		}
		if(!Modifier.isPublic(method.getModifiers())) {
			throw new FlowAnnotationException("The method '" + method.getName() + "' of bean '" + bean + "' is not public!");					
		}
	}


	public void checkSwitchMethod(Method method, Object bean) throws FlowAnnotationException {
		Class[] parameters = method.getParameterTypes();
		if(parameters.length != 2) {
			throw new FlowAnnotationException("The method '" + method.getName() + "' of bean '" + bean + "' has to have just one parameter, not more, not less! Correct parameters are String, IFlowCarter");
		}
		try {
			if(method.getReturnType().asSubclass(String.class) == null) {
				throw new FlowAnnotationException("The return type of method '" + method.getName() + "' of bean '" + bean + "' is not a type of String!");
			}					
		} catch (ClassCastException e) {					
			throw new FlowAnnotationException("The return type method '" + method.getName() + "' of bean '" + bean + "' is not a type of boolean!", e);
		}
		try {
			if(parameters[0].asSubclass(String.class) == null) {
				throw new FlowAnnotationException("The first paremeter of method '" + method.getName() + "' of bean '" + bean + "' is not a type of String!");
			}					
		} catch (ClassCastException e) {					
			throw new FlowAnnotationException("The first paremeter of method '" + method.getName() + "' of bean '" + bean + "' is not a type of String!", e);
		}
		try {
			if(parameters[1].asSubclass(IFlowCarter.class) == null) {
				throw new FlowAnnotationException("The second paremeter of method '" + method.getName() + "' of bean '" + bean + "' is not a type of IFlowCarter!");
			}					
		} catch (ClassCastException e) {					
			throw new FlowAnnotationException("The second paremeter of method '" + method.getName() + "' of bean '" + bean + "' is not a type of IFlowCarter!", e);
		}
		if(!Modifier.isPublic(method.getModifiers())) {
			throw new FlowAnnotationException("The method '" + method.getName() + "' of bean '" + bean + "' is not public!");					
		}
	}


}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy