ItEr11S12ArquitecturaClientesItEr09S11: Moving links support classes to their own package and renaming several classes.

This commit is contained in:
Óscar González Fernández 2009-06-03 16:01:15 +02:00 committed by Javier Moran Rua
parent ef85e83794
commit 16591a86df
22 changed files with 107 additions and 124 deletions

View file

@ -1,12 +0,0 @@
package org.navalplanner.web.common;
/**
* Contract for {@link RedirectorRegistry} <br />
* @author Óscar González Fernández <ogonzalez@igalia.com>
*/
public interface IRedirectorRegistry {
public abstract <T> Redirector<T> getRedirectorFor(
Class<T> klassWithLinkableMetadata);
}

View file

@ -1,19 +0,0 @@
package org.navalplanner.web.common;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.annotation.Qualifier;
/**
* Marks a controller that redirects to the real controller <br />
* @author Óscar González Fernández <ogonzalez@igalia.com>
*/
@Qualifier("linked")
@Retention(RetentionPolicy.RUNTIME)
@Target( { ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE })
public @interface Linked {
}

View file

@ -1,4 +1,4 @@
package org.navalplanner.web.common;
package org.navalplanner.web.common.converters;
/**
* Converts from an object to an string representation, and converts the object

View file

@ -1,4 +1,4 @@
package org.navalplanner.web.common;
package org.navalplanner.web.common.converters;
import java.util.HashMap;
import java.util.List;

View file

@ -1,4 +1,5 @@
package org.navalplanner.web.common;
package org.navalplanner.web.common.converters;
/**
* Retrieves a Converter given a type <br />

View file

@ -1,4 +1,4 @@
package org.navalplanner.web.common;
package org.navalplanner.web.common.converters;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.resources.entities.Resource;

View file

@ -1,4 +1,4 @@
package org.navalplanner.web.common;
package org.navalplanner.web.common.entrypoints;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;

View file

@ -1,4 +1,4 @@
package org.navalplanner.web.common;
package org.navalplanner.web.common.entrypoints;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
@ -13,6 +13,6 @@ import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface LinkToState {
public @interface EntryPoint {
public String[] value();
}

View file

@ -1,4 +1,4 @@
package org.navalplanner.web.common;
package org.navalplanner.web.common.entrypoints;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
@ -10,10 +10,10 @@ import java.lang.annotation.RetentionPolicy;
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface LinksDefiner {
public @interface EntryPoints {
public String page();
public String beanName();
public String registerAs();
}

View file

@ -1,4 +1,4 @@
package org.navalplanner.web.common;
package org.navalplanner.web.common.entrypoints;
import org.zkoss.zk.ui.Execution;

View file

@ -0,0 +1,12 @@
package org.navalplanner.web.common.entrypoints;
/**
* Contract for {@link URLHandlerRegistry} <br />
* @author Óscar González Fernández <ogonzalez@igalia.com>
*/
public interface IURLHandlerRegistry {
public abstract <T> URLHandler<T> getRedirectorFor(
Class<T> klassWithLinkableMetadata);
}

View file

@ -1,4 +1,4 @@
package org.navalplanner.web.common;
package org.navalplanner.web.common.entrypoints;
import java.util.HashMap;
import java.util.Map;

View file

@ -1,4 +1,4 @@
package org.navalplanner.web.common;
package org.navalplanner.web.common.entrypoints;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
@ -10,6 +10,7 @@ import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.io.Resource;
@ -34,7 +35,7 @@ public class RedirectorSynthetiser implements BeanFactoryPostProcessor {
private final Class<?> pageInterface;
private Redirector<?> redirector;
private URLHandler<?> urlHandler;
private SynthetizedImplementation(
ConfigurableListableBeanFactory beanFactory,
@ -46,26 +47,25 @@ public class RedirectorSynthetiser implements BeanFactoryPostProcessor {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Redirector<?> redirector = getRedirector();
redirector.doRedirect(method.getName(), args);
URLHandler<?> redirector = getHandler();
redirector.doTransition(method.getName(), args);
return null;
}
private Redirector<?> getRedirector() {
if (redirector != null)
return redirector;
RedirectorRegistry redirectorRegistry = (RedirectorRegistry) beanFactory
.getBean(getSpringDefaultName(RedirectorRegistry.class),
RedirectorRegistry.class);
redirector = redirectorRegistry.getRedirectorFor(pageInterface);
return redirector;
private URLHandler<?> getHandler() {
if (urlHandler != null)
return urlHandler;
URLHandlerRegistry registry = (URLHandlerRegistry) BeanFactoryUtils
.beanOfType(beanFactory, URLHandlerRegistry.class);
urlHandler = registry.getRedirectorFor(pageInterface);
return urlHandler;
}
}
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) throws BeansException {
long elapsedTime = System.currentTimeMillis();
for (Class<?> pageInterface : findInterfacesMarkedWithLinkable()) {
for (Class<?> pageInterface : findInterfacesMarkedEntryPoints()) {
beanFactory.registerSingleton(getBeanName(pageInterface),
createRedirectorImplementationFor(beanFactory,
pageInterface));
@ -73,10 +73,10 @@ public class RedirectorSynthetiser implements BeanFactoryPostProcessor {
elapsedTime = System.currentTimeMillis() - elapsedTime;
LOG.debug("Took " + elapsedTime
+ " ms to search for interfaces annotated with "
+ LinksDefiner.class.getSimpleName());
+ EntryPoints.class.getSimpleName());
}
private List<Class<?>> findInterfacesMarkedWithLinkable() {
private List<Class<?>> findInterfacesMarkedEntryPoints() {
List<Class<?>> result = new ArrayList<Class<?>>();
PathMatchingResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
CachingMetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(
@ -112,7 +112,7 @@ public class RedirectorSynthetiser implements BeanFactoryPostProcessor {
ClassMetadata classMetadata = metadataReader.getClassMetadata();
if (classMetadata.isInterface()
&& annotationMetadata.getAnnotationTypes().contains(
LinksDefiner.class.getName())) {
EntryPoints.class.getName())) {
Class<?> klass = Class
.forName(classMetadata.getClassName());
if (klass.isInterface()) {
@ -134,14 +134,8 @@ public class RedirectorSynthetiser implements BeanFactoryPostProcessor {
beanFactory, pageInterface));
}
private static String getSpringDefaultName(Class<?> klass) {
String simpleName = klass.getSimpleName();
return simpleName.substring(0, 1).toLowerCase()
+ simpleName.substring(1);
}
private static String getBeanName(Class<?> pageInterface) {
LinksDefiner annotation = pageInterface.getAnnotation(LinksDefiner.class);
return annotation.beanName();
EntryPoints annotation = pageInterface.getAnnotation(EntryPoints.class);
return annotation.registerAs();
}
}

View file

@ -1,4 +1,4 @@
package org.navalplanner.web.common;
package org.navalplanner.web.common.entrypoints;
import java.lang.reflect.Method;
import java.util.Arrays;
@ -13,22 +13,24 @@ import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.Validate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.navalplanner.web.common.converters.Converter;
import org.navalplanner.web.common.converters.IConverterFactory;
import org.zkoss.zk.ui.Execution;
/**
* <br />
* @author Óscar González Fernández <ogonzalez@igalia.com>
*/
public class Redirector<T> {
public class URLHandler<T> {
private static final Log LOG = LogFactory.getLog(Redirector.class);
private static final Log LOG = LogFactory.getLog(URLHandler.class);
private static class LinkMetadata {
private static class EntryPointMetadata {
private final Method method;
private final LinkToState annotation;
private final EntryPoint annotation;
private LinkMetadata(Method method, LinkToState annotation) {
private EntryPointMetadata(Method method, EntryPoint annotation) {
this.method = method;
this.annotation = annotation;
}
@ -36,42 +38,42 @@ public class Redirector<T> {
private final ExecutorRetriever executorRetriever;
private Map<String, LinkMetadata> metadata = new HashMap<String, LinkMetadata>();
private Map<String, EntryPointMetadata> metadata = new HashMap<String, EntryPointMetadata>();
private final String page;
private final IConverterFactory converterFactory;
public Redirector(IConverterFactory converterFactory,
ExecutorRetriever executorRetriever, Class<T> interfaceDefiningLinks) {
Validate.isTrue(interfaceDefiningLinks.isInterface());
public URLHandler(IConverterFactory converterFactory,
ExecutorRetriever executorRetriever,
Class<T> interfaceDefiningEntryPoints) {
Validate.isTrue(interfaceDefiningEntryPoints.isInterface());
this.converterFactory = converterFactory;
this.executorRetriever = executorRetriever;
LinksDefiner linkDefiner = interfaceDefiningLinks
.getAnnotation(LinksDefiner.class);
Validate
.notNull(linkDefiner, LinksDefiner.class.getName()
EntryPoints entryPoints = interfaceDefiningEntryPoints
.getAnnotation(EntryPoints.class);
Validate.notNull(entryPoints, EntryPoints.class.getName()
+ " annotation required on "
+ interfaceDefiningLinks.getName());
this.page = linkDefiner.page();
for (Method method : interfaceDefiningLinks.getMethods()) {
LinkToState linkToState = method.getAnnotation(LinkToState.class);
if (linkToState != null) {
metadata.put(method.getName(), new LinkMetadata(method,
linkToState));
+ interfaceDefiningEntryPoints.getName());
this.page = entryPoints.page();
for (Method method : interfaceDefiningEntryPoints.getMethods()) {
EntryPoint entryPoint = method.getAnnotation(EntryPoint.class);
if (entryPoint != null) {
metadata.put(method.getName(), new EntryPointMetadata(method,
entryPoint));
}
}
}
public void doRedirect(String methodName, Object... values) {
public void doTransition(String methodName, Object... values) {
if (!metadata.containsKey(methodName)) {
LOG.error("Method " + methodName
+ "doesn't represent a state(It doesn't have a "
+ LinkToState.class.getSimpleName()
+ EntryPoint.class.getSimpleName()
+ " annotation). Nothing will be done");
return;
}
LinkMetadata linkableMetadata = metadata.get(methodName);
EntryPointMetadata linkableMetadata = metadata.get(methodName);
Class<?>[] types = linkableMetadata.method.getParameterTypes();
String[] parameterNames = linkableMetadata.annotation.value();
String[] stringRepresentations = new String[parameterNames.length];
@ -102,28 +104,28 @@ public class Redirector<T> {
}
}
public <S extends T> void applyTo(S controller) {
public <S extends T> void applyIfMatches(S controller) {
Execution current = executorRetriever.getCurrent();
Map<String, String> matrixParams = MatrixParameters
.extract((HttpServletRequest) current.getNativeRequest());
Set<String> matrixParamsNames = matrixParams.keySet();
for (Entry<String, LinkMetadata> entry : metadata.entrySet()) {
LinkMetadata linkMetadata = entry.getValue();
LinkToState linkToStateAnnotation = linkMetadata.annotation;
for (Entry<String, EntryPointMetadata> entry : metadata.entrySet()) {
EntryPointMetadata entryPointMetadata = entry.getValue();
EntryPoint entryPointAnnotation = entryPointMetadata.annotation;
HashSet<String> requiredParams = new HashSet<String>(Arrays
.asList(linkToStateAnnotation.value()));
.asList(entryPointAnnotation.value()));
if (matrixParamsNames.equals(requiredParams)) {
Object[] arguments = retrieveArguments(matrixParams,
linkToStateAnnotation, linkMetadata.method
entryPointAnnotation, entryPointMetadata.method
.getParameterTypes());
callMethod(controller, linkMetadata.method, arguments);
callMethod(controller, entryPointMetadata.method, arguments);
return;
}
}
}
private Object[] retrieveArguments(Map<String, String> matrixParams,
LinkToState linkToStateAnnotation, Class<?>[] parameterTypes) {
EntryPoint linkToStateAnnotation, Class<?>[] parameterTypes) {
Object[] result = new Object[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i++) {
Object argumentName = linkToStateAnnotation.value()[i];

View file

@ -1,20 +1,21 @@
package org.navalplanner.web.common;
package org.navalplanner.web.common.entrypoints;
import java.util.HashMap;
import java.util.Map;
import org.navalplanner.web.common.converters.IConverterFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
/**
* Registry of {@link Redirector} <br />
* Registry of {@link URLHandler} <br />
* @author Óscar González Fernández <ogonzalez@igalia.com>
*/
@Component
@Scope(BeanDefinition.SCOPE_SINGLETON)
public class RedirectorRegistry implements IRedirectorRegistry {
public class URLHandlerRegistry implements IURLHandlerRegistry {
@Autowired
private ExecutorRetriever executorRetriever;
@ -22,12 +23,13 @@ public class RedirectorRegistry implements IRedirectorRegistry {
@Autowired
private IConverterFactory converterFactory;
private Map<Class<?>, Redirector> cached = new HashMap<Class<?>, Redirector>();;
private Map<Class<?>, URLHandler<?>> cached = new HashMap<Class<?>, URLHandler<?>>();;
public <T> Redirector<T> getRedirectorFor(Class<T> klassWithLinkableMetadata) {
@SuppressWarnings("unchecked")
public <T> URLHandler<T> getRedirectorFor(Class<T> klassWithLinkableMetadata) {
if (cached.containsKey(klassWithLinkableMetadata))
return cached.get(klassWithLinkableMetadata);
Redirector<T> result = new Redirector<T>(converterFactory,
return (URLHandler<T>) cached.get(klassWithLinkableMetadata);
URLHandler<T> result = new URLHandler<T>(converterFactory,
executorRetriever, klassWithLinkableMetadata);
cached.put(klassWithLinkableMetadata, result);
return result;

View file

@ -9,7 +9,7 @@ import java.util.Set;
import org.navalplanner.business.resources.entities.Resource;
import org.navalplanner.business.resources.entities.Worker;
import org.navalplanner.web.common.Util;
import org.navalplanner.web.resources.worker.WorkerCRUDLinks;
import org.navalplanner.web.resources.worker.IWorkerCRUDControllerEntryPoints;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
@ -34,7 +34,7 @@ public class CriterionWorkersController extends GenericForwardComposer {
private Button cancelListButton;
private WorkerCRUDLinks workerCRUD;
private IWorkerCRUDControllerEntryPoints workerCRUD;
public void showList(Event event) {
loadDataToList();

View file

@ -1,23 +1,23 @@
package org.navalplanner.web.resources.worker;
import org.navalplanner.business.resources.entities.Worker;
import org.navalplanner.web.common.LinksDefiner;
import org.navalplanner.web.common.LinkToState;
import org.navalplanner.web.common.entrypoints.EntryPoint;
import org.navalplanner.web.common.entrypoints.EntryPoints;
/**
* Contract for {@link WorkerCRUDController}. <br />
* @author Óscar González Fernández <ogonzalez@igalia.com>
*/
@LinksDefiner(page = "/resources/worker/worker.zul", beanName = "workerCRUD")
public interface WorkerCRUDLinks {
@EntryPoints(page = "/resources/worker/worker.zul", registerAs = "workerCRUD")
public interface IWorkerCRUDControllerEntryPoints {
@LinkToState("edit")
@EntryPoint("edit")
public abstract void goToEditForm(Worker worker);
@LinkToState("workRelationships")
@EntryPoint("workRelationships")
public abstract void goToWorkRelationshipsForm(Worker worker);
@LinkToState("create")
@EntryPoint("create")
public abstract void goToCreateForm();
}

View file

@ -14,12 +14,12 @@ import org.navalplanner.business.resources.entities.Worker;
import org.navalplanner.business.resources.entities.WorkingRelationship;
import org.navalplanner.business.resources.services.CriterionService;
import org.navalplanner.web.common.IMessagesForUser;
import org.navalplanner.web.common.IRedirectorRegistry;
import org.navalplanner.web.common.Level;
import org.navalplanner.web.common.MessagesForUser;
import org.navalplanner.web.common.OnlyOneVisible;
import org.navalplanner.web.common.Redirector;
import org.navalplanner.web.common.Util;
import org.navalplanner.web.common.entrypoints.IURLHandlerRegistry;
import org.navalplanner.web.common.entrypoints.URLHandler;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.api.Window;
@ -29,7 +29,7 @@ import org.zkoss.zul.api.Window;
* @author Óscar González Fernández <ogonzalez@igalia.com>
*/
public class WorkerCRUDController extends GenericForwardComposer implements
WorkerCRUDLinks {
IWorkerCRUDControllerEntryPoints {
private Window createWindow;
@ -45,7 +45,7 @@ public class WorkerCRUDController extends GenericForwardComposer implements
private IWorkerModel workerModel;
private IRedirectorRegistry redirectorRegistry;
private IURLHandlerRegistry URLHandlerRegistry;
private OnlyOneVisible visibility;
@ -179,9 +179,9 @@ public class WorkerCRUDController extends GenericForwardComposer implements
new WorkRelationshipsController(this.workerModel,this);
this.workRelationship.doAfterCompose(
comp.getFellow("addWorkRelationshipWindow"));
Redirector<WorkerCRUDLinks> redirector = redirectorRegistry
.getRedirectorFor(WorkerCRUDLinks.class);
redirector.applyTo(this);
URLHandler<IWorkerCRUDControllerEntryPoints> handler = URLHandlerRegistry
.getRedirectorFor(IWorkerCRUDControllerEntryPoints.class);
handler.applyIfMatches(this);
}
private LocalizationsController createLocalizationsController(

View file

@ -13,7 +13,7 @@
required for "@Autowired")
-->
<context:annotation-config />
<bean class="org.navalplanner.web.common.RedirectorSynthetiser"></bean>
<bean class="org.navalplanner.web.common.entrypoints.RedirectorSynthetiser"></bean>
<context:component-scan base-package="org.navalplanner.web"/>
</beans>

View file

@ -9,6 +9,7 @@ import org.junit.experimental.theories.DataPoint;
import org.junit.experimental.theories.Theories;
import org.junit.experimental.theories.Theory;
import org.junit.runner.RunWith;
import org.navalplanner.web.common.entrypoints.MatrixParameters;
/**
* Tests that {@link MatrixParameters} supports extracting several

View file

@ -9,6 +9,7 @@ import org.junit.experimental.theories.DataPoint;
import org.junit.experimental.theories.Theories;
import org.junit.experimental.theories.Theory;
import org.junit.runner.RunWith;
import org.navalplanner.web.common.entrypoints.MatrixParameters;
/**
* Test that {@link MatrixParameters} support one parameter<br />

View file

@ -11,6 +11,7 @@ import org.junit.experimental.theories.DataPoint;
import org.junit.experimental.theories.Theories;
import org.junit.experimental.theories.Theory;
import org.junit.runner.RunWith;
import org.navalplanner.web.common.entrypoints.MatrixParameters;
/**
* Tests that {@link MatrixParameters} supports matrix parameters