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

org.nakedobjects.metamodel.specloader.internal.facetprocessor.FacetProcessor Maven / Gradle / Ivy

The newest version!
package org.nakedobjects.metamodel.specloader.internal.facetprocessor;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.nakedobjects.metamodel.commons.ensure.Ensure.ensureThatState;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.nakedobjects.metamodel.commons.lang.ListUtils;
import org.nakedobjects.metamodel.config.NakedObjectConfiguration;
import org.nakedobjects.metamodel.facets.FacetFactory;
import org.nakedobjects.metamodel.facets.FacetHolder;
import org.nakedobjects.metamodel.facets.MethodFilteringFacetFactory;
import org.nakedobjects.metamodel.facets.MethodRemover;
import org.nakedobjects.metamodel.facets.MethodRemoverConstants;
import org.nakedobjects.metamodel.facets.PropertyOrCollectionIdentifyingFacetFactory;
import org.nakedobjects.metamodel.java5.MethodPrefixBasedFacetFactory;
import org.nakedobjects.metamodel.runtimecontext.RuntimeContext;
import org.nakedobjects.metamodel.runtimecontext.RuntimeContextAware;
import org.nakedobjects.metamodel.spec.feature.NakedObjectFeatureType;
import org.nakedobjects.metamodel.specloader.SpecificationLoader;
import org.nakedobjects.metamodel.specloader.collectiontyperegistry.CollectionTypeRegistry;
import org.nakedobjects.metamodel.specloader.internal.introspector.JavaIntrospector;
import org.nakedobjects.metamodel.specloader.progmodelfacets.ProgrammingModelFacets;


public class FacetProcessor implements RuntimeContextAware {

    private final NakedObjectConfiguration configuration;
    private final CollectionTypeRegistry collectionTypeRegistry;
    private final ProgrammingModelFacets programmingModelFacets;
    
    private final SpecificationLoader specificationLoader;
	private RuntimeContext runtimeContext;


    /**
     * Class => FacetFactory
     */
    private final Map, FacetFactory> factoryByFactoryType = new HashMap, FacetFactory>();

    /**
     * {@link FacetFactory Facet factories}, in order they were {@link #registerFactory(FacetFactory)
     * registered}.
     */
    private final List factories = new ArrayList();

    /**
     * All method prefixes to check in {@link #recognizes(Method)}.
     * 
     * 

* Derived from factories that implement {@link MethodPrefixBasedFacetFactory}. */ private List methodPrefixes; /** * All registered {@link FacetFactory factories} that implement {@link MethodFilteringFacetFactory}. * *

* Used within {@link #recognizes(Method)}. */ private List methodFilteringFactories; /** * All registered {@link FacetFactory factories} that implement * {@link PropertyOrCollectionIdentifyingFacetFactory}. * *

* Used within {@link #recognizes(Method)}. */ private List propertyOrCollectionIdentifyingFactories; /** * NakedObjectFeatureType => List * *

* Lazily initialized, then cached. The lists remain in the same order that the factories were * {@link #registerFactory(FacetFactory) registered}. */ private Map> factoryListByFeatureType = null; public FacetProcessor( final NakedObjectConfiguration configuration, final SpecificationLoader specificationLoader, final CollectionTypeRegistry collectionTypeRegistry, final ProgrammingModelFacets programmingModelFacets) { ensureThatState(configuration, is(notNullValue())); ensureThatState(collectionTypeRegistry, is(notNullValue())); ensureThatState(programmingModelFacets, is(notNullValue())); ensureThatState(specificationLoader, is(notNullValue())); this.configuration = configuration; this.specificationLoader = specificationLoader; this.programmingModelFacets = programmingModelFacets; this.collectionTypeRegistry = collectionTypeRegistry; } //////////////////////////////////////////////////// // init, shutdown (application scoped) //////////////////////////////////////////////////// public void init() { ensureThatState(runtimeContext, is(notNullValue())); programmingModelFacets.init(); final List facetFactoryList = programmingModelFacets.getList(); for (final FacetFactory facetFactory : facetFactoryList) { registerFactory(facetFactory); } } public void shutdown() { } public void registerFactory(final FacetFactory factory) { clearCaches(); factoryByFactoryType.put(factory.getClass(), factory); factories.add(factory); injectDependenciesInto(factory); } /** * This is public so that can be used for @Facets processing in * {@link JavaIntrospector}. * *

* See bug-517. */ public void injectDependenciesInto(final FacetFactory factory) { getCollectionTypeRepository().injectInto(factory); getSpecificationLoader().injectInto(factory); getRuntimeContext().injectInto(factory); getNakedObjectConfiguration().injectInto(factory); } public FacetFactory getFactoryByFactoryType(final Class factoryType) { return factoryByFactoryType.get(factoryType); } /** * Appends to the supplied {@link Set} all of the {@link Method}s that may represent a property or * collection. * *

* Delegates to all known {@link PropertyOrCollectionIdentifyingFacetFactory}s. */ public Set findPropertyOrCollectionCandidateAccessors(final Method[] methods, final Set candidates) { cachePropertyOrCollectionIdentifyingFacetFactoriesIfRequired(); for (int i = 0; i < methods.length; i++) { final Method method = methods[i]; if (method == null) { continue; } for (final PropertyOrCollectionIdentifyingFacetFactory facetFactory : propertyOrCollectionIdentifyingFactories) { if (facetFactory.isPropertyOrCollectionAccessorCandidate(method)) { candidates.add(method); } } } return candidates; } /** * Use the provided {@link MethodRemover} to have all known * {@link PropertyOrCollectionIdentifyingFacetFactory}s to remove all property accessors, and append them * to the supplied methodList. * *

* Intended to be called after {@link #findAndRemoveValuePropertyAccessors(MethodRemover, List)} once only * reference properties remain. * * @see PropertyOrCollectionIdentifyingFacetFactory#findAndRemoveValuePropertyAccessors(MethodRemover, * List) */ public void findAndRemovePropertyAccessors(final MethodRemover methodRemover, final List methodListToAppendTo) { for (final PropertyOrCollectionIdentifyingFacetFactory facetFactory : propertyOrCollectionIdentifyingFactories) { facetFactory.findAndRemovePropertyAccessors(methodRemover, methodListToAppendTo); } } /** * Use the provided {@link MethodRemover} to have all known * {@link PropertyOrCollectionIdentifyingFacetFactory}s to remove all property accessors, and append them * to the supplied methodList. * * @see PropertyOrCollectionIdentifyingFacetFactory#findAndRemoveCollectionAccessors(MethodRemover, List) */ public void findAndRemoveCollectionAccessors(final MethodRemover methodRemover, final List methodListToAppendTo) { cachePropertyOrCollectionIdentifyingFacetFactoriesIfRequired(); for (final PropertyOrCollectionIdentifyingFacetFactory facetFactory : propertyOrCollectionIdentifyingFactories) { facetFactory.findAndRemoveCollectionAccessors(methodRemover, methodListToAppendTo); } } /** * Whether this {@link Method method} is recognized by any of the {@link FacetFactory}s. * *

* Typically this is when method has a specific prefix, such as validate or hide. * Specifically, it checks: *

    *
  • the method's prefix against the prefixes supplied by any {@link MethodPrefixBasedFacetFactory}
  • *
  • the method against any {@link MethodFilteringFacetFactory}
  • *
* *

* The design of {@link MethodPrefixBasedFacetFactory} (whereby this facet factory set does the work) is a * slight performance optimization for when there are multiple facet factories that search for the same * prefix. */ public boolean recognizes(final Method method) { cacheMethodPrefixesIfRequired(); final String methodName = method.getName(); for (final String prefix : methodPrefixes) { if (methodName.startsWith(prefix)) { return true; } } cacheMethodFilteringFacetFactoriesIfRequired(); for (final MethodFilteringFacetFactory factory : methodFilteringFactories) { if (factory.recognizes(method)) { return true; } } return false; } /** * Attaches all facets applicable to the provided {@link NakedObjectFeatureType#OBJECT object}) to the * supplied {@link FacetHolder}. * *

* Delegates to {@link FacetFactory#process(Class, FacetHolder)} for each appropriate factory. * * @see FacetFactory#process(Class, MethodRemover, FacetHolder) * * @param cls * - class to process * @param facetHolder * - holder to attach facets to. * * @return true if any facets were added, false otherwise. */ public boolean process(final Class cls, final MethodRemover methodRemover, final FacetHolder facetHolder) { boolean facetsAdded = false; final List factoryList = getFactoryListByFeatureType(NakedObjectFeatureType.OBJECT); for (final FacetFactory facetFactory : factoryList) { facetsAdded = facetFactory.process(cls, removerElseNullRemover(methodRemover), facetHolder) | facetsAdded; } return facetsAdded; } /** * Attaches all facets applicable to the provided {@link NakedObjectFeatureType type of feature} to the * supplied {@link FacetHolder}. * *

* Delegates to {@link FacetFactory#process(Method, FacetHolder)} for each appropriate factory. * * @see FacetFactory#process(Method, FacetHolder) * * @param method * - method to process * @param facetHolder * - holder to attach facets to. * @param featureType * - what type of feature the method represents (property, action, collection etc) * * @return true if any facets were added, false otherwise. */ public boolean process( final Method method, final MethodRemover methodRemover, final FacetHolder facetHolder, final NakedObjectFeatureType featureType) { boolean facetsAdded = false; final List factoryList = getFactoryListByFeatureType(featureType); for (final FacetFactory facetFactory : factoryList) { facetsAdded = facetFactory.process(method, removerElseNullRemover(methodRemover), facetHolder) | facetsAdded; } return facetsAdded; } /** * Attaches all facets applicable to the provided {@link NakedObjectFeatureType#ACTION_PARAMETER * parameter}), to the supplied {@link FacetHolder}. * *

* Delegates to {@link FacetFactory#processParams(Method, int, FacetHolder)} for each appropriate factory. * * @see FacetFactory#processParams(Method, int, FacetHolder) * * @param method * - action method to process * @param paramNum * - 0-based * @param facetHolder * - holder to attach facets to. * * @return true if any facets were added, false otherwise. */ public boolean processParams(final Method method, final int paramNum, final FacetHolder facetHolder) { boolean facetsAdded = false; final List factoryList = getFactoryListByFeatureType(NakedObjectFeatureType.ACTION_PARAMETER); for (final FacetFactory facetFactory : factoryList) { facetsAdded = facetFactory.processParams(method, paramNum, facetHolder) | facetsAdded; } return facetsAdded; } private List getFactoryListByFeatureType(final NakedObjectFeatureType featureType) { cacheByFeatureTypeIfRequired(); return factoryListByFeatureType.get(featureType); } private void clearCaches() { factoryListByFeatureType = null; methodPrefixes = null; methodFilteringFactories = null; propertyOrCollectionIdentifyingFactories = null; } private synchronized void cacheByFeatureTypeIfRequired() { if (factoryListByFeatureType != null) { return; } factoryListByFeatureType = new HashMap>(); for (final FacetFactory factory : factories) { final NakedObjectFeatureType[] featureTypes = factory.getFeatureTypes(); for (int i = 0; i < featureTypes.length; i++) { final List factoryList = getList(factoryListByFeatureType, featureTypes[i]); factoryList.add(factory); } } } private synchronized void cacheMethodPrefixesIfRequired() { if (methodPrefixes != null) { return; } methodPrefixes = new ArrayList(); for (final FacetFactory facetFactory : factories) { if (facetFactory instanceof MethodPrefixBasedFacetFactory) { final MethodPrefixBasedFacetFactory methodPrefixBasedFacetFactory = (MethodPrefixBasedFacetFactory) facetFactory; ListUtils.combine(methodPrefixes, methodPrefixBasedFacetFactory.getPrefixes()); } } } private synchronized void cacheMethodFilteringFacetFactoriesIfRequired() { if (methodFilteringFactories != null) { return; } methodFilteringFactories = new ArrayList(); for (final FacetFactory factory : factories) { if (factory instanceof MethodFilteringFacetFactory) { final MethodFilteringFacetFactory methodFilteringFacetFactory = (MethodFilteringFacetFactory) factory; methodFilteringFactories.add(methodFilteringFacetFactory); } } } private synchronized void cachePropertyOrCollectionIdentifyingFacetFactoriesIfRequired() { if (propertyOrCollectionIdentifyingFactories != null) { return; } propertyOrCollectionIdentifyingFactories = new ArrayList(); final Iterator iter = factories.iterator(); while (iter.hasNext()) { final FacetFactory factory = iter.next(); if (factory instanceof PropertyOrCollectionIdentifyingFacetFactory) { final PropertyOrCollectionIdentifyingFacetFactory identifyingFacetFactory = (PropertyOrCollectionIdentifyingFacetFactory) factory; propertyOrCollectionIdentifyingFactories.add(identifyingFacetFactory); } } } @SuppressWarnings("unchecked") private static List getList(final Map map, final Object key) { List list = (List) map.get(key); if (list == null) { list = new ArrayList(); map.put(key, list); } return list; } private MethodRemover removerElseNullRemover(final MethodRemover methodRemover) { return methodRemover != null ? methodRemover : MethodRemoverConstants.NULL; } // //////////////////////////////////////////////////////////////////// // Dependencies (injected in constructor) // //////////////////////////////////////////////////////////////////// private NakedObjectConfiguration getNakedObjectConfiguration() { return configuration; } private SpecificationLoader getSpecificationLoader() { return specificationLoader; } private CollectionTypeRegistry getCollectionTypeRepository() { return collectionTypeRegistry; } // //////////////////////////////////////////////////////////////////// // Dependencies (injected via setter due to *Aware) // //////////////////////////////////////////////////////////////////// private RuntimeContext getRuntimeContext() { return runtimeContext; } /** * Injected so can propogate to any {@link #registerFactory(FacetFactory) registered} {@link FacetFactory} * s that are also {@link RuntimeContextAware}. */ public void setRuntimeContext(RuntimeContext runtimeContext) { this.runtimeContext = runtimeContext; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy