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

com.talk2object.plum.interaction.viewgeneneration.ViewFactoryImpl Maven / Gradle / Ivy

package com.talk2object.plum.interaction.viewgeneneration;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.filter.AssignableTypeFilter;

import com.talk2object.plum.interaction.viewbuilder.AnnotationViewBuilder;
import com.talk2object.plum.interaction.viewbuilder.ObjectViewBuilder;
import com.talk2object.plum.interaction.viewbuilder.SelfViewBuilder;
import com.talk2object.plum.interaction.viewbuilder.bean.BeanViewBuilder;
import com.talk2object.plum.view._abstract.window.UIComponent;
import com.talk2object.util.ClassAssignmentUtils;

/**
 * TODO add similarModelClass cache for later lookup.
 * 
 * @author jack
 *
 */

public class ViewFactoryImpl implements ViewFactory {

	private static Logger logger = Logger.getLogger(ViewFactoryImpl.class);

	private String basePackage;

	// key is full class name
	private Map builderMap = new HashMap();

	// special builders
	private ViewBuilder annotationViewBuilder = new AnnotationViewBuilder();
	private ViewBuilder beanViewBuilder = new BeanViewBuilder();
	private ViewBuilder objectViewBuilder = new ObjectViewBuilder();

	// private ModelAdapterRegistry modelAdapterRegistry = new
	// ModelAdapterRegistry();

 
	public void scanDomainObjects() {

		ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(
				false);

		// provider.addIncludeFilter(new AssignableTypeFilter(forClass));

		// Had to add this line
		provider.setResourceLoader(new PathMatchingResourcePatternResolver());

		provider.addIncludeFilter(new AssignableTypeFilter(ViewBuilder.class));

		Set candidates = provider
				.findCandidateComponents(basePackage);

		for (BeanDefinition def : candidates) {

			try {
				Class clazz = Class.forName(def.getBeanClassName());
				AbstractViewBuilder builder = (AbstractViewBuilder) clazz
						.newInstance();

				if (builder.getModelClass() != null) {
					logger.info("find view builder: " + builder);

					register(builder.getModelClass(), builder);
				}
			} catch (Exception e) {
				throw new RuntimeException(e);
			}

		}
	}

	public String getBasePackage() {
		return basePackage;
	}

	public void setBasePackage(String basePackage) {
		this.basePackage = basePackage;
	}

	public static void main(String[] args) {
		ViewFactoryImpl fact = new ViewFactoryImpl();
		fact.setBasePackage("com/talk2object/plum");
		fact.scanDomainObjects();
	}

	@Override
	public void register(Class modelClass, AbstractViewBuilder builder) {

		builderMap.put(modelClass, builder);
	}

	@Override
	public UIComponent create(Object model, Class modelClass,
			String viewClassExpressions, ViewBuildContext context,
			UIComponent parentView) {

		String[] viewClassExprs = viewClassExpressions.split(" ");

		ViewBuilder builder = builderMap.get(modelClass);
		if (builder == null)
			throw new RuntimeException("No view builder is found for model:"
					+ modelClass);

		return build(builder, model, viewClassExprs, context, parentView);
	}

	@Override
	public UIComponent create(Object model, BuilderMatchPolicy policy,
			String viewClassExpressions, ViewBuildContext context,
			UIComponent parentView) {

		ViewBuilder builder = findViewBuilder(model, policy);
		if (builder == null)
			throw new RuntimeException("No view builder is found for model:"
					+ model.getClass());

		String[] viewClassExprs = viewClassExpressions.split(" ");

		return build(builder, model, viewClassExprs, context, parentView);
	}

	@Override
	public UIComponent create(Object model, BuilderMatchPolicy policy,
			String[] viewClassExpressionArray, ViewBuildContext context,
			UIComponent parentView) {
		ViewBuilder builder = findViewBuilder(model, policy);
		if (builder == null)
			throw new RuntimeException("No view builder is found for model:"
					+ model.getClass());

		return build(builder, model, viewClassExpressionArray, context,
				parentView);

	}

	private ViewBuilder findViewBuilder(Object model, BuilderMatchPolicy policy) {

		Class modelClass = model.getClass();

		ViewBuilder builder = null;

		ViewBuilder registeredBuilder = builderMap.get(model.getClass());

		// 1 registered and important
		if (registeredBuilder != null && registeredBuilder.isImportant())
			return registeredBuilder;

		// 2. Visible interface
		if (model instanceof Visible) {
			ViewBuilder selfBuilder = new SelfViewBuilder();
			return selfBuilder;
		}

		// 3. annotated
		if (AnnotationViewBuilder.hasViewAnnotation(modelClass)) {
			return annotationViewBuilder;
		}

		// registered
		if (registeredBuilder != null)
			return registeredBuilder;

		// still not found
		switch (policy) {
		case SUBCLASS_OBJECT:
			modelClass = findMostSimilarModelClass(model.getClass(), true);

			builder = builderMap.get(modelClass);

			if (builder == null)
				builder = objectViewBuilder;

			break;
		case SUBCLASS_BEAN_OBJECT:
			modelClass = findMostSimilarModelClass(model.getClass(), true);

			builder = builderMap.get(modelClass);

			if (builder == null)
				builder = beanViewBuilder;

			if (builder == null)
				builder = objectViewBuilder;

			break;

		case BEAN:
			builder = beanViewBuilder;
			break;

		}

		return builder;
	}

	private UIComponent build(ViewBuilder builder, Object model,
			String[] viewClassExpressions, ViewBuildContext context,
			UIComponent parentView) {
		for (String viewClassExpr : viewClassExpressions) {
			UIComponent view = builder.build(model, viewClassExpr, context,
					parentView);
			if (view != null)
			{
				
				return view;
			}
		}

		return null;
	}

	private Class findMostSimilarModelClass(Class clazz,
			boolean excludeObjectClass) {
		// find the smallest cost
		Class mostSimilarModelClass = null;
		int smallestCost = Integer.MAX_VALUE;

		try {
			for (Class targetClass : builderMap.keySet()) {

				if (excludeObjectClass && targetClass.equals(Object.class))
					continue;

				int cost = ClassAssignmentUtils.getAssignmentCost(targetClass,
						clazz);

				if (cost >= 0 && cost < smallestCost) {
					smallestCost = cost;
					mostSimilarModelClass = targetClass;
				}
			}
			return mostSimilarModelClass;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy