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

org.nakedobjects.metamodel.specloader.NakedObjectReflectorAbstract Maven / Gradle / Ivy

There is a newer version: 4.0-beta-1
Show newest version
package org.nakedobjects.metamodel.specloader;

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

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.Vector;

import org.apache.log4j.Logger;
import org.nakedobjects.metamodel.adapter.NakedObject;
import org.nakedobjects.metamodel.adapter.NakedObjectList;
import org.nakedobjects.metamodel.commons.debug.DebugInfo;
import org.nakedobjects.metamodel.commons.debug.DebugString;
import org.nakedobjects.metamodel.commons.ensure.Assert;
import org.nakedobjects.metamodel.commons.exceptions.NakedObjectException;
import org.nakedobjects.metamodel.commons.lang.JavaClassUtils;
import org.nakedobjects.metamodel.config.NakedObjectConfiguration;
import org.nakedobjects.metamodel.facetdecorator.FacetDecorator;
import org.nakedobjects.metamodel.facetdecorator.FacetDecoratorSet;
import org.nakedobjects.metamodel.facets.Facet;
import org.nakedobjects.metamodel.runtimecontext.RuntimeContext;
import org.nakedobjects.metamodel.runtimecontext.RuntimeContextAware;
import org.nakedobjects.metamodel.runtimecontext.noruntime.RuntimeContextNoRuntime;
import org.nakedobjects.metamodel.spec.IntrospectableSpecification;
import org.nakedobjects.metamodel.spec.JavaSpecification;
import org.nakedobjects.metamodel.spec.NakedObjectSpecification;
import org.nakedobjects.metamodel.spec.SpecificationFacets;
import org.nakedobjects.metamodel.specloader.classsubstitutor.ClassSubstitutor;
import org.nakedobjects.metamodel.specloader.collectiontyperegistry.CollectionTypeRegistry;
import org.nakedobjects.metamodel.specloader.collectiontyperegistry.CollectionTypeRegistryDefault;
import org.nakedobjects.metamodel.specloader.internal.TypeExtractorMethodReturn;
import org.nakedobjects.metamodel.specloader.internal.cache.SimpleSpecificationCache;
import org.nakedobjects.metamodel.specloader.internal.cache.SpecificationCache;
import org.nakedobjects.metamodel.specloader.internal.facetprocessor.FacetProcessor;
import org.nakedobjects.metamodel.specloader.internal.instances.InstanceCollectionSpecification;
import org.nakedobjects.metamodel.specloader.progmodelfacets.ProgrammingModelFacets;
import org.nakedobjects.metamodel.specloader.progmodelfacets.ProgrammingModelFacetsJava5;

/**
 * Builds the meta-model for Java 5 programming model.
 * 
 * 

* The implementation provides for a degree of pluggability: *

    *
  • The most important plug-in point is {@link ProgrammingModelFacets} that * specifies the set of {@link Facet} that make up programming model. If not * specified then defaults to {@link ProgrammingModelFacetsJava5} (which should * be used as a starting point for your own customizations). *
  • The only mandatory plug-in point is {@link ClassSubstitutor}, which * allows the class to be loaded to be substituted if required. This is used in * conjunction with some PersistenceMechanisms that do class * enhancement. *
  • The {@link CollectionTypeRegistry} specifies the types that should be * considered as collections. If not specified then will * {@link CollectionTypeRegistryDefault default}. (Note: this extension point * has not been tested, so should be considered more of a "statement of * intent" than actual API. Also, we may use annotations (similar to the * way in which Values are specified) as an alternative mechanism). *
* *

* In addition, the {@link RuntimeContext} can optionally be injected, but will * default to {@link RuntimeContextNoRuntime} if not provided prior to * {@link #init() initialization}. The purpose of {@link RuntimeContext} is to * allow the metamodel to be used standalone, for example in a Maven plugin. The * {@link RuntimeContextNoRuntime} implementation will through an exception for * any methods (such as finding an {@link NakedObject adapter}) because there is * no runtime session. In the case of the metamodel being used by the framework * (that is, when there is a runtime), then the framework injects an * implementation of {@link RuntimeContext} that acts like a bridge to its * NakedObjectsContext. */ public abstract class NakedObjectReflectorAbstract implements NakedObjectReflector, DebugInfo { private final static Logger LOG = Logger .getLogger(NakedObjectReflectorAbstract.class); /** * Injected in the constructor. */ private final NakedObjectConfiguration configuration; /** * Injected in the constructor. */ private final ClassSubstitutor classSubstitutor; /** * Injected in the constructor. */ private final CollectionTypeRegistry collectionTypeRegistry; /** * Injected in the constructor. */ private final ProgrammingModelFacets programmingModelFacets; /** * Defaulted in the constructor. */ private final FacetProcessor facetProcessor; /** * Defaulted in the constructor. */ private final SpecificationCache cache; /** * Defaulted in the constructor, so can be added to via * {@link #setFacetDecorators(FacetDecoratorSet)} or * {@link #addFacetDecorator(FacetDecorator)}. * *

* {@link FacetDecorator}s must be added prior to {@link #init() * initialization.} */ private final FacetDecoratorSet facetDecoratorSet; /** * Can optionally be injected, but will default (to * {@link RuntimeContextNoRuntime}) otherwise. * *

* Should be injected when used by framework, but will default to a no-op * implementation if the metamodel is being used standalone (eg for a * code-generator). */ private RuntimeContext runtimeContext; // ///////////////////////////////////////////////////////////// // Constructor // ///////////////////////////////////////////////////////////// public NakedObjectReflectorAbstract( final NakedObjectConfiguration configuration, final ClassSubstitutor classSubstitutor, final CollectionTypeRegistry collectionTypeRegistry, final ProgrammingModelFacets programmingModelFacets, final Set facetDecorators) { ensureThatArg(configuration, is(notNullValue())); ensureThatArg(classSubstitutor, is(notNullValue())); ensureThatArg(collectionTypeRegistry, is(notNullValue())); ensureThatArg(programmingModelFacets, is(notNullValue())); ensureThatArg(facetDecorators, is(notNullValue())); this.configuration = configuration; this.classSubstitutor = classSubstitutor; this.collectionTypeRegistry = collectionTypeRegistry; this.programmingModelFacets = programmingModelFacets; this.facetDecoratorSet = new FacetDecoratorSet(); for (final FacetDecorator facetDecorator : facetDecorators) { this.facetDecoratorSet.add(facetDecorator); } this.facetProcessor = new FacetProcessor(configuration, this, collectionTypeRegistry, programmingModelFacets); this.cache = new SimpleSpecificationCache(); } @Override protected void finalize() throws Throwable { super.finalize(); LOG.info("finalizing reflector factory " + this); } // ///////////////////////////////////////////////////////////// // init, shutdown // ///////////////////////////////////////////////////////////// /** * Initializes and wires up */ public void init() { LOG.debug("initialising " + this); // default subcomponents if (runtimeContext == null) { runtimeContext = new RuntimeContextNoRuntime(); } injectInto(runtimeContext); // wire subcomponents into each other runtimeContext.injectInto(facetProcessor); // initialize subcomponents facetDecoratorSet.init(); classSubstitutor.init(); collectionTypeRegistry.init(); facetProcessor.init(); } public void shutdown() { LOG.info("shutting down " + this); getCache().clear(); facetDecoratorSet.shutdown(); } // ///////////////////////////////////////////////////////////// // install, load, allSpecifications // ///////////////////////////////////////////////////////////// public NakedObjectSpecification loadSpecification(final Class type) { Class substitutedType = getClassSubstitutor().getClass(type); return substitutedType != null ? loadSpecificationFromCache(substitutedType) : null; } private NakedObjectSpecification loadSpecificationFromCache( final Class type) { Assert.assertNotNull(type); final NakedObjectSpecification spec = getCache().get(type.getName()); if (spec != null) { return spec; } return loadSpecificationAndCache(type); } private NakedObjectSpecification loadSpecificationAndCache( final Class type) { final SpecificationCache specificationCache = getCache(); synchronized (specificationCache) { NakedObjectSpecification specification = createSpecification(type); if (specification == null) { throw new NakedObjectException( "Failed to create specification for class " + type.getName()); } specificationCache.cache(type.getName(), specification); if (specification instanceof IntrospectableSpecification) { final IntrospectableSpecification introspectableSpecification = (IntrospectableSpecification) specification; introspectableSpecification.introspect(facetDecoratorSet); } return specification; } } // ///////////////////////////////////////////////////////////// // loadSpecificationForReturnTypes // (not API) // ///////////////////////////////////////////////////////////// /** * Loads the specifications of the return types of all {@link Method}s in * the provided {@link Vector}. * *

* If the provided {@link Class} is non-null, then it will not * loaded. This prevents us going into an infinite loop. * * @param methods * - the methods whose return types are to be ignored * @param classToIgnore * - ignore this class if is a return type (higher up the stack) * @param objectFactory */ public void loadSpecificationForReturnTypes(final Set methods, final Class classToIgnore) { for (final Method method : methods) { for (Class returnType : new TypeExtractorMethodReturn(method)) { if (returnType != classToIgnore) { loadSpecification(returnType); } } } } /** * Overridable method for language-specific subclass to create the * appropriate type of {@link NakedObjectSpecification}. */ protected NakedObjectSpecification createSpecification(final Class cls) { if (NakedObjectList.class.isAssignableFrom(cls)) { return new InstanceCollectionSpecification(this, getRuntimeContext()); } return new JavaSpecification(cls, this, getRuntimeContext()); } /** * Return the specification for the specified class of object. */ public final NakedObjectSpecification loadSpecification( final String className) { ensureThatArg(className, is(notNullValue()), "specification class name must be specified"); try { final Class cls = loadClass(className); return loadSpecification(cls); } catch (final ClassNotFoundException e) { final NakedObjectSpecification spec = getCache().get(className); if (spec == null) { throw new NakedObjectException( "No such class available: " + className); } return spec; } } private Class loadClass(final String className) throws ClassNotFoundException { Class builtIn = JavaClassUtils.getBuiltIn(className); if (builtIn != null) { return builtIn; } return Class.forName(className); } /** * Return all the loaded specifications. */ public NakedObjectSpecification[] allSpecifications() { return getCache().allSpecifications(); } public boolean loaded(Class cls) { return loaded(cls.getName()); } public boolean loaded(String fullyQualifiedClassName) { return getCache().get(fullyQualifiedClassName) != null; } // //////////////////////////////////////////////////////////////////// // injectInto // //////////////////////////////////////////////////////////////////// /** * Injects self into candidate if required, and instructs its subcomponents * to do so also. */ public void injectInto(Object candidate) { Class candidateClass = candidate.getClass(); if (SpecificationLoaderAware.class.isAssignableFrom(candidateClass)) { SpecificationLoaderAware cast = SpecificationLoaderAware.class .cast(candidate); cast.setSpecificationLoader(this); } getClassSubstitutor().injectInto(candidate); getCollectionTypeRegistry().injectInto(candidate); } // ///////////////////////////////////////////////////////////// // Debugging // ///////////////////////////////////////////////////////////// public void debugData(final DebugString str) { facetDecoratorSet.debugData(str); str.appendln(); str.appendTitle("Specifications"); final NakedObjectSpecification[] specs = allSpecifications(); Arrays.sort(specs, new Comparator() { public int compare(final NakedObjectSpecification s1, final NakedObjectSpecification s2) { return s1.getShortName().compareToIgnoreCase(s2.getShortName()); } }); for (int i = 0; i < specs.length; i++) { final NakedObjectSpecification specification = specs[i]; str.append(specification.isAbstract() ? "A" : "."); str.append(specification.isService() ? "S" : "."); str.append(SpecificationFacets.isBoundedSet(specification) ? "B" : "."); str.append(specification.isCollection() ? "C" : "."); str.append(specification.isObject() ? "O" : "."); str.append("."); // placeholder for future support of maps str.append(specification.isParseable() ? "P" : "."); str.append(specification.isEncodeable() ? "E" : "."); str.append(specification.isAggregated() ? "A" : "."); str.append(!specification.isMutableAggregated() ? "I" : "."); str.append(" "); str.append(specification.getShortName()); str.append(" [fqc="); str.append(specification.getFullName()); str.append(",type="); str.append(specification.getClass().getName()); str.appendln("]"); } } public String debugTitle() { return "Reflector"; } // ///////////////////////////////////////////////////////////// // Helpers (were previously injected, but no longer required) // ///////////////////////////////////////////////////////////// /** * Provides access to the registered {@link Facet}s. */ public FacetProcessor getFacetProcessor() { return facetProcessor; } private SpecificationCache getCache() { return cache; } // //////////////////////////////////////////////////////////////////// // Dependencies (injected by setter due to *Aware) // //////////////////////////////////////////////////////////////////// /** * As per {@link #setRuntimeContext(RuntimeContext)}. */ public RuntimeContext getRuntimeContext() { return runtimeContext; } /** * Due to {@link RuntimeContextAware}. */ public void setRuntimeContext(RuntimeContext runtimeContext) { this.runtimeContext = runtimeContext; } // //////////////////////////////////////////////////////////////////// // Dependencies (injected from constructor) // //////////////////////////////////////////////////////////////////// public NakedObjectConfiguration getNakedObjectConfiguration() { return configuration; } public ClassSubstitutor getClassSubstitutor() { return classSubstitutor; } public CollectionTypeRegistry getCollectionTypeRegistry() { return collectionTypeRegistry; } public ProgrammingModelFacets getProgrammingModelFacets() { return programmingModelFacets; } public Set getFacetDecoratorSet() { return facetDecoratorSet.getFacetDecorators(); } } // Copyright (c) Naked Objects Group Ltd.





© 2015 - 2024 Weber Informatics LLC | Privacy Policy