You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@polygene.apache.org by ni...@apache.org on 2015/07/30 21:48:15 UTC
[16/80] [partial] zest-java git commit: First round of changes to
move to org.apache.zest namespace.
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/CompositeAssemblyImpl.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/CompositeAssemblyImpl.java b/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/CompositeAssemblyImpl.java
new file mode 100644
index 0000000..458ff79
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/CompositeAssemblyImpl.java
@@ -0,0 +1,837 @@
+/*
+ * Copyright (c) 2007-2011, Rickard Öberg. All Rights Reserved.
+ * Copyright (c) 2008-2013, Niclas Hedhman. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zest.runtime.bootstrap;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.apache.zest.api.common.MetaInfo;
+import org.apache.zest.api.common.Optional;
+import org.apache.zest.api.common.QualifiedName;
+import org.apache.zest.api.common.UseDefaults;
+import org.apache.zest.api.common.Visibility;
+import org.apache.zest.api.composite.InvalidCompositeException;
+import org.apache.zest.api.concern.Concerns;
+import org.apache.zest.api.constraint.Constraint;
+import org.apache.zest.api.constraint.ConstraintDeclaration;
+import org.apache.zest.api.constraint.Constraints;
+import org.apache.zest.api.constraint.Name;
+import org.apache.zest.api.entity.Lifecycle;
+import org.apache.zest.api.injection.scope.State;
+import org.apache.zest.api.injection.scope.This;
+import org.apache.zest.api.mixin.Initializable;
+import org.apache.zest.api.mixin.Mixins;
+import org.apache.zest.api.property.GenericPropertyInfo;
+import org.apache.zest.api.property.Immutable;
+import org.apache.zest.api.property.Property;
+import org.apache.zest.api.sideeffect.SideEffects;
+import org.apache.zest.api.type.HasTypes;
+import org.apache.zest.api.util.Annotations;
+import org.apache.zest.api.util.Classes;
+import org.apache.zest.api.util.Fields;
+import org.apache.zest.bootstrap.StateDeclarations;
+import org.apache.zest.functional.ForEach;
+import org.apache.zest.functional.Function;
+import org.apache.zest.functional.HierarchicalVisitorAdapter;
+import org.apache.zest.functional.Iterables;
+import org.apache.zest.functional.Specification;
+import org.apache.zest.functional.Visitor;
+import org.apache.zest.runtime.composite.AbstractConstraintModel;
+import org.apache.zest.runtime.composite.CompositeConstraintModel;
+import org.apache.zest.runtime.composite.CompositeMethodModel;
+import org.apache.zest.runtime.composite.CompositeMethodsModel;
+import org.apache.zest.runtime.composite.ConcernModel;
+import org.apache.zest.runtime.composite.ConcernsModel;
+import org.apache.zest.runtime.composite.ConstraintModel;
+import org.apache.zest.runtime.composite.ConstraintsModel;
+import org.apache.zest.runtime.composite.GenericSpecification;
+import org.apache.zest.runtime.composite.MixinModel;
+import org.apache.zest.runtime.composite.MixinsModel;
+import org.apache.zest.runtime.composite.SideEffectModel;
+import org.apache.zest.runtime.composite.SideEffectsModel;
+import org.apache.zest.runtime.composite.StateModel;
+import org.apache.zest.runtime.composite.ValueConstraintsInstance;
+import org.apache.zest.runtime.composite.ValueConstraintsModel;
+import org.apache.zest.runtime.injection.DependencyModel;
+import org.apache.zest.runtime.property.PropertiesModel;
+import org.apache.zest.runtime.property.PropertyModel;
+
+import static java.util.Arrays.asList;
+import static org.apache.zest.api.util.Annotations.hasAnnotation;
+import static org.apache.zest.api.util.Annotations.isType;
+import static org.apache.zest.api.util.Annotations.type;
+import static org.apache.zest.api.util.Classes.classHierarchy;
+import static org.apache.zest.api.util.Classes.interfacesOf;
+import static org.apache.zest.api.util.Classes.isAssignableFrom;
+import static org.apache.zest.api.util.Classes.typeOf;
+import static org.apache.zest.api.util.Classes.typesOf;
+import static org.apache.zest.api.util.Classes.wrapperClass;
+import static org.apache.zest.functional.Iterables.addAll;
+import static org.apache.zest.functional.Iterables.cast;
+import static org.apache.zest.functional.Iterables.empty;
+import static org.apache.zest.functional.Iterables.filter;
+import static org.apache.zest.functional.Iterables.first;
+import static org.apache.zest.functional.Iterables.flatten;
+import static org.apache.zest.functional.Iterables.flattenIterables;
+import static org.apache.zest.functional.Iterables.iterable;
+import static org.apache.zest.functional.Iterables.map;
+import static org.apache.zest.functional.Iterables.matchesAny;
+import static org.apache.zest.functional.Iterables.toList;
+import static org.apache.zest.functional.Specifications.and;
+import static org.apache.zest.functional.Specifications.in;
+import static org.apache.zest.functional.Specifications.not;
+import static org.apache.zest.functional.Specifications.or;
+import static org.apache.zest.functional.Specifications.translate;
+
+/**
+ * Declaration of a Composite.
+ */
+public abstract class CompositeAssemblyImpl
+ implements HasTypes
+{
+ protected List<Class<?>> concerns = new ArrayList<>();
+ protected List<Class<?>> sideEffects = new ArrayList<>();
+ protected List<Class<?>> mixins = new ArrayList<>();
+ protected List<Class<?>> types = new ArrayList<>();
+ protected MetaInfo metaInfo = new MetaInfo();
+ protected Visibility visibility = Visibility.module;
+
+ protected boolean immutable;
+ protected PropertiesModel propertiesModel;
+ protected StateModel stateModel;
+ protected MixinsModel mixinsModel;
+ protected CompositeMethodsModel compositeMethodsModel;
+ private AssemblyHelper helper;
+ protected StateDeclarations stateDeclarations;
+
+ protected Set<String> registeredStateNames = new HashSet<>();
+
+ public CompositeAssemblyImpl( Class<?> mainType )
+ {
+ types.add( mainType );
+ }
+
+ @Override
+ public Iterable<Class<?>> types()
+ {
+ return types;
+ }
+
+ protected StateModel createStateModel()
+ {
+ return new StateModel( propertiesModel );
+ }
+
+ protected MixinsModel createMixinsModel()
+ {
+ return new MixinsModel();
+ }
+
+ protected void buildComposite( AssemblyHelper helper,
+ StateDeclarations stateDeclarations
+ )
+ {
+ this.stateDeclarations = stateDeclarations;
+ this.helper = helper;
+ for( Class<?> compositeType : types )
+ {
+ metaInfo = new MetaInfo( metaInfo ).withAnnotations( compositeType );
+ addAnnotationsMetaInfo( compositeType, metaInfo );
+ }
+
+ immutable = metaInfo.get( Immutable.class ) != null;
+ propertiesModel = new PropertiesModel();
+ stateModel = createStateModel();
+ mixinsModel = createMixinsModel();
+ compositeMethodsModel = new CompositeMethodsModel( mixinsModel );
+
+ // Implement composite methods
+ ArrayList<Type> allTypes = getTypes( this.types );
+ Iterable<Class<? extends Constraint<?, ?>>> constraintClasses = constraintDeclarations( getTypes( this.types ) );
+ Iterable<Class<?>> concernClasses = flatten( concerns, concernDeclarations( allTypes ) );
+ Iterable<Class<?>> sideEffectClasses = flatten( sideEffects, sideEffectDeclarations( allTypes ) );
+ Iterable<Class<?>> mixinClasses = flatten( mixins, mixinDeclarations( this.types ) );
+ implementMixinType( types, constraintClasses, concernClasses, sideEffectClasses, mixinClasses );
+
+ // Add state from methods and fields
+ addState( constraintClasses );
+ }
+
+ protected void addAnnotationsMetaInfo( Class<?> type, MetaInfo compositeMetaInfo )
+ {
+ Class[] declaredInterfaces = type.getInterfaces();
+ for( int i = declaredInterfaces.length - 1; i >= 0; i-- )
+ {
+ addAnnotationsMetaInfo( declaredInterfaces[ i], compositeMetaInfo );
+ }
+ compositeMetaInfo.withAnnotations( type );
+ }
+
+ protected void implementMixinType( Iterable<? extends Class<?>> types,
+ Iterable<Class<? extends Constraint<?, ?>>> constraintClasses,
+ Iterable<Class<?>> concernClasses,
+ Iterable<Class<?>> sideEffectClasses,
+ Iterable<Class<?>> mixinClasses
+ )
+ {
+ Set<Class<?>> thisDependencies = new HashSet<>();
+ for( Class<?> mixinType : types )
+ {
+ for( Method method : mixinType.getMethods() )
+ {
+ if( !compositeMethodsModel.isImplemented( method )
+ && !Proxy.class.equals( method.getDeclaringClass().getSuperclass() )
+ && !Proxy.class.equals( method.getDeclaringClass() )
+ && !Modifier.isStatic( method.getModifiers() ) )
+ {
+ MixinModel mixinModel = implementMethod( method, mixinClasses );
+ ConcernsModel concernsModel = concernsFor(
+ method,
+ mixinModel.mixinClass(),
+ Iterables.<Class<?>>flatten( concernDeclarations( mixinModel.mixinClass() ),
+ concernClasses )
+ );
+ SideEffectsModel sideEffectsModel = sideEffectsFor(
+ method,
+ mixinModel.mixinClass(),
+ Iterables.<Class<?>>flatten( sideEffectDeclarations( mixinModel.mixinClass() ),
+ sideEffectClasses )
+ );
+ method.setAccessible( true );
+ ConstraintsModel constraints = constraintsFor(
+ method,
+ Iterables.<Class<? extends Constraint<?, ?>>>flatten( constraintDeclarations( mixinModel.mixinClass() ),
+ constraintClasses )
+ );
+ CompositeMethodModel methodComposite = new CompositeMethodModel(
+ method,
+ constraints,
+ concernsModel,
+ sideEffectsModel,
+ mixinsModel
+ );
+
+ // Implement @This references
+ Iterable<Class<?>> map = map( new DependencyModel.InjectionTypeFunction(),
+ filter( new DependencyModel.ScopeSpecification( This.class ),
+ methodComposite.dependencies() ) );
+ Iterable<Class<?>> map1 = map( new DependencyModel.InjectionTypeFunction(),
+ filter( new DependencyModel.ScopeSpecification( This.class ),
+ mixinModel.dependencies() ) );
+ @SuppressWarnings( "unchecked" )
+ Iterable<Class<?>> filter = filter(
+ not( in( Initializable.class, Lifecycle.class, InvocationHandler.class ) ),
+ map( Classes.RAW_CLASS, interfacesOf( mixinModel.mixinClass() ) )
+ );
+ Iterable<? extends Class<?>> flatten = flatten( map, map1, filter );
+ addAll( thisDependencies, flatten );
+
+ compositeMethodsModel.addMethod( methodComposite );
+ }
+ }
+ // Add type to set of mixin types
+ mixinsModel.addMixinType( mixinType );
+ }
+
+ // Implement all @This dependencies that were found
+ for( Class<?> thisDependency : thisDependencies )
+ {
+ // Add additional declarations from the @This type
+ Iterable<Class<? extends Constraint<?, ?>>> typeConstraintClasses = flatten(
+ constraintClasses,
+ constraintDeclarations( thisDependency ) );
+ Iterable<Class<?>> typeConcernClasses = flatten(
+ concernClasses,
+ concernDeclarations( thisDependency ) );
+ Iterable<Class<?>> typeSideEffectClasses = flatten(
+ sideEffectClasses,
+ sideEffectDeclarations( thisDependency ) );
+ Iterable<Class<?>> typeMixinClasses = flatten(
+ mixinClasses,
+ mixinDeclarations( thisDependency ) );
+
+ @SuppressWarnings( "unchecked" )
+ Iterable<? extends Class<?>> singleton = iterable( thisDependency );
+ implementMixinType( singleton, typeConstraintClasses, typeConcernClasses, typeSideEffectClasses, typeMixinClasses );
+ }
+ }
+
+ @SuppressWarnings( "raw" )
+ protected MixinModel implementMethod( Method method, Iterable<Class<?>> mixinDeclarations )
+ {
+ MixinModel implementationModel = mixinsModel.mixinFor( method );
+ if( implementationModel != null )
+ {
+ return implementationModel;
+ }
+ Class mixinClass = findTypedImplementation( method, mixinDeclarations );
+ if( mixinClass != null )
+ {
+ return implementMethodWithClass( method, mixinClass );
+ }
+
+ // Check generic implementations
+ mixinClass = findGenericImplementation( method, mixinDeclarations );
+ if( mixinClass != null )
+ {
+ return implementMethodWithClass( method, mixinClass );
+ }
+
+ throw new InvalidCompositeException( "No implementation found for method \n " + method.toGenericString()
+ + "\nin\n " + types );
+ }
+
+ @SuppressWarnings( {"raw", "unchecked"} )
+ private Class findTypedImplementation( final Method method, Iterable<Class<?>> mixins )
+ {
+ // Check if mixinClass implements the method. If so, check if the mixinClass is generic or if the filter passes.
+ // If a mixinClass is both generic AND non-generic at the same time, then the filter applies to the non-generic
+ // side only.
+ Specification<Class<?>> appliesToSpec = new Specification<Class<?>>()
+ {
+ @Override
+ public boolean satisfiedBy( Class<?> item )
+ {
+ return helper.appliesTo( item, method, types, item );
+ }
+ };
+ return first( filter( and( isAssignableFrom( method.getDeclaringClass() ),
+ or( GenericSpecification.INSTANCE, appliesToSpec ) ),
+ mixins ) );
+ }
+
+ @SuppressWarnings( "unchecked" )
+ private Class<?> findGenericImplementation( final Method method, Iterable<Class<?>> mixins )
+ {
+ // Check if mixinClass is generic and the applies-to filter passes
+ return first( filter( and( GenericSpecification.INSTANCE, new Specification<Class<?>>()
+ {
+ @Override
+ public boolean satisfiedBy( Class<?> item )
+ {
+ return helper.appliesTo( item, method, types, item );
+ }
+ } ), mixins ) );
+ }
+
+ private MixinModel implementMethodWithClass( Method method, Class mixinClass )
+ {
+ MixinModel mixinModel = mixinsModel.getMixinModel( mixinClass );
+ if( mixinModel == null )
+ {
+ mixinModel = helper.getMixinModel( mixinClass );
+ mixinsModel.addMixinModel( mixinModel );
+ }
+
+ mixinsModel.addMethodMixin( method, mixinModel );
+
+ return mixinModel;
+ }
+
+ protected void addState( final Iterable<Class<? extends Constraint<?, ?>>> constraintClasses )
+ {
+ // Add method state
+ compositeMethodsModel.accept( new HierarchicalVisitorAdapter<Object, Object, RuntimeException>()
+ {
+ @Override
+ public boolean visitEnter( Object visited )
+ throws RuntimeException
+ {
+ if( visited instanceof CompositeMethodModel )
+ {
+ CompositeMethodModel methodModel = (CompositeMethodModel) visited;
+ if( methodModel.method().getParameterTypes().length == 0 )
+ {
+ addStateFor( methodModel.method(), constraintClasses );
+ }
+
+ return false;
+ }
+
+ return super.visitEnter( visited );
+ }
+ } );
+
+ // Add field state
+ mixinsModel.accept( new HierarchicalVisitorAdapter<Object, Object, RuntimeException>()
+ {
+ @Override
+ public boolean visitEnter( Object visited )
+ throws RuntimeException
+ {
+ if( visited instanceof MixinModel )
+ {
+ MixinModel model = (MixinModel) visited;
+ Visitor<Field, RuntimeException> addState = new Visitor<Field, RuntimeException>()
+ {
+ @Override
+ public boolean visit( Field visited )
+ throws RuntimeException
+ {
+ addStateFor( visited, constraintClasses );
+ return true;
+ }
+ };
+ ForEach.forEach( Fields.FIELDS_OF.map( model.mixinClass() ) ).
+ filter( Annotations.hasAnnotation( State.class ) ).
+ visit( addState );
+ return false;
+ }
+ return super.visitEnter( visited );
+ }
+ } );
+ }
+
+ protected void addStateFor( AccessibleObject accessor,
+ Iterable<Class<? extends Constraint<?, ?>>> constraintClasses
+ )
+ {
+ String stateName = QualifiedName.fromAccessor( accessor ).name();
+
+ if( registeredStateNames.contains( stateName ) )
+ {
+ return; // Skip already registered names
+ }
+
+ if( Property.class.isAssignableFrom( Classes.RAW_CLASS.map( typeOf( accessor ) ) ) )
+ {
+ propertiesModel.addProperty( newPropertyModel( accessor, constraintClasses ) );
+ registeredStateNames.add( stateName );
+ }
+ }
+
+ protected PropertyModel newPropertyModel( AccessibleObject accessor,
+ Iterable<Class<? extends Constraint<?, ?>>> constraintClasses
+ )
+ {
+ Iterable<Annotation> annotations = Annotations.findAccessorAndTypeAnnotationsIn( accessor );
+ boolean optional = first( filter( isType( Optional.class ), annotations ) ) != null;
+ ValueConstraintsModel valueConstraintsModel = constraintsFor(
+ annotations,
+ GenericPropertyInfo.propertyTypeOf( accessor ),
+ ( (Member) accessor ).getName(),
+ optional,
+ constraintClasses,
+ accessor );
+ ValueConstraintsInstance valueConstraintsInstance = null;
+ if( valueConstraintsModel.isConstrained() )
+ {
+ valueConstraintsInstance = valueConstraintsModel.newInstance();
+ }
+ MetaInfo metaInfo = stateDeclarations.metaInfoFor( accessor );
+ Object initialValue = stateDeclarations.initialValueOf( accessor );
+ boolean useDefaults = metaInfo.get( UseDefaults.class ) != null || stateDeclarations.useDefaults( accessor );
+ boolean immutable = this.immutable || metaInfo.get( Immutable.class ) != null;
+ PropertyModel propertyModel = new PropertyModel(
+ accessor,
+ immutable,
+ useDefaults,
+ valueConstraintsInstance,
+ metaInfo,
+ initialValue );
+ return propertyModel;
+ }
+
+ // Model
+ private ConstraintsModel constraintsFor( Method method,
+ Iterable<Class<? extends Constraint<?, ?>>> constraintClasses
+ )
+ {
+ List<ValueConstraintsModel> parameterConstraintModels = Collections.emptyList();
+ Annotation[][] parameterAnnotations = method.getParameterAnnotations();
+ Type[] parameterTypes = method.getGenericParameterTypes();
+ boolean constrained = false;
+ for( int i = 0; i < parameterAnnotations.length; i++ )
+ {
+ Annotation[] parameterAnnotation = parameterAnnotations[i];
+
+ Name nameAnnotation = (Name) first( filter( isType( Name.class ), iterable( parameterAnnotation ) ) );
+ String name = nameAnnotation == null ? "param" + ( i + 1 ) : nameAnnotation.value();
+
+ boolean optional = first( filter( isType( Optional.class ), iterable( parameterAnnotation ) ) ) != null;
+ ValueConstraintsModel parameterConstraintsModel = constraintsFor(
+ asList( parameterAnnotation ),
+ parameterTypes[i],
+ name,
+ optional,
+ constraintClasses,
+ method );
+ if( parameterConstraintsModel.isConstrained() )
+ {
+ constrained = true;
+ }
+
+ if( parameterConstraintModels.isEmpty() )
+ {
+ parameterConstraintModels = new ArrayList<>();
+ }
+ parameterConstraintModels.add( parameterConstraintsModel );
+ }
+
+ if( !constrained )
+ {
+ return new ConstraintsModel( Collections.<ValueConstraintsModel>emptyList() );
+ }
+ else
+ {
+ return new ConstraintsModel( parameterConstraintModels );
+ }
+ }
+
+ protected ValueConstraintsModel constraintsFor(
+ Iterable<Annotation> constraintAnnotations,
+ Type valueType,
+ String name,
+ boolean optional,
+ Iterable<Class<? extends Constraint<?, ?>>> constraintClasses,
+ AccessibleObject accessor
+ )
+ {
+ valueType = wrapperClass( valueType );
+
+ List<AbstractConstraintModel> constraintModels = new ArrayList<>();
+ nextConstraint:
+ for( Annotation constraintAnnotation : filter( translate( type(), hasAnnotation( ConstraintDeclaration.class ) ),
+ constraintAnnotations ) )
+ {
+ // Check composite declarations first
+ Class<? extends Annotation> annotationType = constraintAnnotation.annotationType();
+ for( Class<? extends Constraint<?, ?>> constraint : constraintClasses )
+ {
+ if( helper.appliesTo( constraint, annotationType, valueType ) )
+ {
+ constraintModels.add( new ConstraintModel( constraintAnnotation, constraint ) );
+ continue nextConstraint;
+ }
+ }
+
+ // Check the annotation itself
+ Constraints constraints = annotationType.getAnnotation( Constraints.class );
+ if( constraints != null )
+ {
+ for( Class<? extends Constraint<?, ?>> constraintClass : constraints.value() )
+ {
+ if( helper.appliesTo( constraintClass, annotationType, valueType ) )
+ {
+ constraintModels.add( new ConstraintModel( constraintAnnotation, constraintClass ) );
+ continue nextConstraint;
+ }
+ }
+ }
+
+ // No implementation found!
+ // Check if if it's a composite constraints
+ Iterable<Annotation> annotations = iterable( annotationType.getAnnotations() );
+ if( matchesAny( translate( type(), hasAnnotation( ConstraintDeclaration.class ) ), annotations ) )
+ {
+ ValueConstraintsModel valueConstraintsModel = constraintsFor(
+ annotations,
+ valueType,
+ name,
+ optional,
+ constraintClasses,
+ accessor );
+ CompositeConstraintModel compositeConstraintModel = new CompositeConstraintModel(
+ constraintAnnotation,
+ valueConstraintsModel );
+ constraintModels.add( compositeConstraintModel );
+ continue nextConstraint;
+ }
+
+ throw new InvalidCompositeException(
+ "Cannot find implementation of constraint @"
+ + annotationType.getSimpleName()
+ + " for "
+ + valueType
+ + " in method "
+ + ( (Member) accessor ).getName()
+ + " of composite " + types );
+ }
+
+ return new ValueConstraintsModel( constraintModels, name, optional );
+ }
+
+ private ConcernsModel concernsFor( Method method,
+ Class<?> mixinClass,
+ Iterable<Class<?>> concernClasses
+ )
+ {
+ List<ConcernModel> concernsFor = new ArrayList<>();
+ for( Class<?> concern : concernClasses )
+ {
+ if( helper.appliesTo( concern, method, types, mixinClass ) )
+ {
+ concernsFor.add( helper.getConcernModel( concern ) );
+ }
+ else
+ {
+ // Lookup method in mixin
+ if( !InvocationHandler.class.isAssignableFrom( mixinClass ) )
+ {
+ try
+ {
+ Method mixinMethod = mixinClass.getMethod( method.getName(), method.getParameterTypes() );
+ if( helper.appliesTo( concern, mixinMethod, types, mixinClass ) )
+ {
+ concernsFor.add( helper.getConcernModel( concern ) );
+ }
+ }
+ catch( NoSuchMethodException e )
+ {
+ // Ignore
+ }
+ }
+ }
+ }
+
+ // Check annotations on method that have @Concerns annotations themselves
+ for( Annotation annotation : method.getAnnotations() )
+ {
+ @SuppressWarnings( "raw" )
+ Concerns concerns = annotation.annotationType().getAnnotation( Concerns.class );
+ if( concerns != null )
+ {
+ for( Class<?> concern : concerns.value() )
+ {
+ if( helper.appliesTo( concern, method, types, mixinClass ) )
+ {
+ concernsFor.add( helper.getConcernModel( concern ) );
+ }
+ }
+ }
+ }
+
+ if( concernsFor.isEmpty() )
+ {
+ return ConcernsModel.EMPTY_CONCERNS;
+ }
+ else
+ {
+ return new ConcernsModel( concernsFor );
+ }
+ }
+
+ private SideEffectsModel sideEffectsFor( Method method,
+ Class<?> mixinClass,
+ Iterable<Class<?>> sideEffectClasses
+ )
+ {
+ List<SideEffectModel> sideEffectsFor = new ArrayList<>();
+ for( Class<?> sideEffect : sideEffectClasses )
+ {
+ if( helper.appliesTo( sideEffect, method, types, mixinClass ) )
+ {
+ sideEffectsFor.add( helper.getSideEffectModel( sideEffect ) );
+ }
+ else
+ {
+ // Lookup method in mixin
+ if( !InvocationHandler.class.isAssignableFrom( mixinClass ) )
+ {
+ try
+ {
+ Method mixinMethod = mixinClass.getMethod( method.getName(), method.getParameterTypes() );
+ if( helper.appliesTo( sideEffect, mixinMethod, types, mixinClass ) )
+ {
+ sideEffectsFor.add( helper.getSideEffectModel( sideEffect ) );
+ }
+ }
+ catch( NoSuchMethodException e )
+ {
+ // Ignore
+ }
+ }
+ }
+ }
+
+ if( sideEffectsFor.isEmpty() )
+ {
+ return SideEffectsModel.EMPTY_SIDEEFFECTS;
+ }
+ else
+ {
+ return new SideEffectsModel( sideEffectsFor );
+ }
+ }
+
+ @SuppressWarnings( "unchecked" )
+ private Iterable<Class<? extends Constraint<?, ?>>> constraintDeclarations( Class<?> type )
+ {
+ ArrayList<Type> allTypes = getTypes( type );
+ return constraintDeclarations( allTypes );
+ }
+
+ private Iterable<Class<? extends Constraint<?, ?>>> constraintDeclarations( ArrayList<Type> allTypes )
+ {
+ // Find all constraints and flatten them into an iterable
+ Function<Type, Iterable<Class<? extends Constraint<?, ?>>>> function = new Function<Type, Iterable<Class<? extends Constraint<?, ?>>>>()
+ {
+ @Override
+ public Iterable<Class<? extends Constraint<?, ?>>> map( Type type )
+ {
+ Constraints constraints = Annotations.annotationOn( type, Constraints.class );
+ if( constraints == null )
+ {
+ return empty();
+ }
+ else
+ {
+ return iterable( constraints.value() );
+ }
+ }
+ };
+ Iterable<Class<? extends Constraint<?, ?>>> flatten = flattenIterables( map( function, allTypes ) );
+ return toList( flatten );
+ }
+
+ @SuppressWarnings( "unchecked" )
+ private Iterable<Class<?>> concernDeclarations( Class<?> type )
+ {
+ Iterable<? extends Class<?>> iterable = iterable( type );
+ return concernDeclarations( getTypes( iterable ) );
+ }
+
+ private Iterable<Class<?>> concernDeclarations( ArrayList<Type> allTypes )
+ {
+ // Find all concerns and flattern them into an iterable
+ Function<Type, Iterable<Class<?>>> function = new Function<Type, Iterable<Class<?>>>()
+ {
+ @Override
+ public Iterable<Class<?>> map( Type type )
+ {
+ Concerns concerns = Annotations.annotationOn( type, Concerns.class );
+ if( concerns == null )
+ {
+ return empty();
+ }
+ else
+ {
+ return iterable( concerns.value() );
+ }
+ }
+ };
+ Iterable<Class<?>> flatten = flattenIterables( map( function, allTypes ) );
+ return toList( flatten );
+ }
+
+ @SuppressWarnings( "unchecked" )
+ protected Iterable<Class<?>> sideEffectDeclarations( Class<?> type )
+ {
+ Iterable<? extends Class<?>> iterable = iterable( type );
+ return sideEffectDeclarations( getTypes( iterable ) );
+ }
+
+ protected Iterable<Class<?>> sideEffectDeclarations( ArrayList<Type> allTypes )
+ {
+ // Find all side-effects and flattern them into an iterable
+ Function<Type, Iterable<Class<?>>> function = new Function<Type, Iterable<Class<?>>>()
+ {
+ @Override
+ public Iterable<Class<?>> map( Type type )
+ {
+ SideEffects sideEffects = Annotations.annotationOn( type, SideEffects.class );
+ if( sideEffects == null )
+ {
+ return empty();
+ }
+ else
+ {
+ return iterable( sideEffects.value() );
+ }
+ }
+ };
+ Iterable<Class<?>> flatten = flattenIterables( map( function, allTypes ) );
+ return toList( flatten );
+ }
+
+ private ArrayList<Type> getTypes( Class<?> type )
+ {
+ Iterable<? extends Class<?>> iterable = iterable( type );
+ return getTypes( iterable );
+ }
+
+ private ArrayList<Type> getTypes( Iterable<? extends Class<?>> typess )
+ {
+ // Find side-effect declarations
+ ArrayList<Type> allTypes = new ArrayList<>();
+ for( Class<?> type : typess )
+ {
+ Iterable<Type> types;
+ if( type.isInterface() )
+ {
+ types = typesOf( type );
+ }
+ else
+ {
+ types = cast( classHierarchy( type ) );
+ }
+ addAll( allTypes, types );
+ }
+ return allTypes;
+ }
+
+ @SuppressWarnings( "unchecked" )
+ protected Iterable<Class<?>> mixinDeclarations( Class<?> type )
+ {
+ Iterable<? extends Class<?>> iterable = iterable( type );
+ return mixinDeclarations( iterable );
+ }
+
+ protected Iterable<Class<?>> mixinDeclarations( Iterable<? extends Class<?>> typess )
+ {
+ // Find mixin declarations
+ ArrayList<Type> allTypes = new ArrayList<>();
+ for( Class<?> type : typess )
+ {
+ Iterable<Type> types = typesOf( type );
+ addAll( allTypes, types );
+ }
+
+ // Find all mixins and flattern them into an iterable
+ Function<Type, Iterable<Class<?>>> function = new Function<Type, Iterable<Class<?>>>()
+ {
+ @Override
+ public Iterable<Class<?>> map( Type type )
+ {
+ Mixins mixins = Annotations.annotationOn( type, Mixins.class );
+ if( mixins == null )
+ {
+ return empty();
+ }
+ else
+ {
+ return iterable( mixins.value() );
+ }
+ }
+ };
+ Iterable<Class<?>> flatten = flattenIterables( map( function, allTypes ) );
+ return toList( flatten );
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ConfigurationAssemblyImpl.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ConfigurationAssemblyImpl.java b/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ConfigurationAssemblyImpl.java
new file mode 100644
index 0000000..f755d85
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ConfigurationAssemblyImpl.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.zest.runtime.bootstrap;
+
+import org.apache.zest.bootstrap.ConfigurationAssembly;
+
+/**
+ * Declaration of a EntityComposite.
+ */
+public final class ConfigurationAssemblyImpl
+ implements ConfigurationAssembly
+{
+ private ValueAssemblyImpl value;
+ private EntityAssemblyImpl entity;
+
+ public ConfigurationAssemblyImpl( Class<?> mainType )
+ {
+ value = new ValueAssemblyImpl( mainType );
+ entity = new EntityAssemblyImpl( mainType );
+ }
+
+ @Override
+ public Iterable<Class<?>> types()
+ {
+ return value.types();
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ConfigurationDeclarationImpl.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ConfigurationDeclarationImpl.java b/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ConfigurationDeclarationImpl.java
new file mode 100644
index 0000000..1076390
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ConfigurationDeclarationImpl.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.zest.runtime.bootstrap;
+
+import org.apache.zest.api.common.Visibility;
+import org.apache.zest.bootstrap.ConfigurationDeclaration;
+
+import static java.util.Arrays.asList;
+
+/**
+ * Declaration of a Composite. Created by {@link org.apache.zest.bootstrap.ModuleAssembly#configurations(Class[])}.
+ */
+public final class ConfigurationDeclarationImpl
+ implements ConfigurationDeclaration
+{
+ private final Iterable<EntityAssemblyImpl> entities;
+ private final Iterable<ValueAssemblyImpl> values;
+
+ public ConfigurationDeclarationImpl( Iterable<EntityAssemblyImpl> entities, Iterable<ValueAssemblyImpl> values )
+ {
+ this.entities = entities;
+ this.values = values;
+ }
+
+ @Override
+ public ConfigurationDeclaration setMetaInfo( Object info )
+ {
+ for( EntityAssemblyImpl entity : entities )
+ {
+ entity.metaInfo.set( info );
+ }
+ for( ValueAssemblyImpl value : values )
+ {
+ value.metaInfo.set( info );
+ }
+ return this;
+ }
+
+ @Override
+ public ConfigurationDeclaration visibleIn( Visibility visibility )
+ {
+ for( EntityAssemblyImpl entity : entities )
+ {
+ entity.visibility = visibility;
+ }
+ for( ValueAssemblyImpl value : values )
+ {
+ value.visibility = visibility;
+ }
+ return this;
+ }
+
+ @Override
+ public ConfigurationDeclaration withConcerns( Class<?>... concerns )
+ {
+ for( EntityAssemblyImpl entity : entities )
+ {
+ entity.concerns.addAll( asList( concerns ) );
+ }
+ for( ValueAssemblyImpl value : values )
+ {
+ value.concerns.addAll( asList( concerns ) );
+ }
+ return this;
+ }
+
+ @Override
+ public ConfigurationDeclaration withSideEffects( Class<?>... sideEffects )
+ {
+ for( EntityAssemblyImpl entity : entities )
+ {
+ entity.sideEffects.addAll( asList( sideEffects ) );
+ }
+ for( ValueAssemblyImpl value : values )
+ {
+ value.sideEffects.addAll( asList( sideEffects ) );
+ }
+ return this;
+ }
+
+ @Override
+ public ConfigurationDeclaration withMixins( Class<?>... mixins )
+ {
+ for( EntityAssemblyImpl entity : entities )
+ {
+ entity.mixins.addAll( asList( mixins ) );
+ }
+ for( ValueAssemblyImpl value : values )
+ {
+ value.mixins.addAll( asList( mixins ) );
+ }
+ return this;
+ }
+
+ @Override
+ public ConfigurationDeclaration withTypes( Class<?>... types )
+ {
+ for( EntityAssemblyImpl entity : entities )
+ {
+ entity.types.addAll( asList( types ) );
+ }
+ for( ValueAssemblyImpl value : values )
+ {
+ value.types.addAll( asList( types ) );
+ }
+ return this;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/EntityAssemblyImpl.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/EntityAssemblyImpl.java b/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/EntityAssemblyImpl.java
new file mode 100644
index 0000000..6daba43
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/EntityAssemblyImpl.java
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2007-2011, Rickard Öberg. All Rights Reserved.
+ * Copyright (c) 2014, Paul Merlin. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zest.runtime.bootstrap;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Member;
+import org.apache.zest.api.association.Association;
+import org.apache.zest.api.association.GenericAssociationInfo;
+import org.apache.zest.api.association.ManyAssociation;
+import org.apache.zest.api.association.NamedAssociation;
+import org.apache.zest.api.common.InvalidApplicationException;
+import org.apache.zest.api.common.MetaInfo;
+import org.apache.zest.api.common.Optional;
+import org.apache.zest.api.common.QualifiedName;
+import org.apache.zest.api.common.UseDefaults;
+import org.apache.zest.api.constraint.Constraint;
+import org.apache.zest.api.entity.EntityComposite;
+import org.apache.zest.api.property.GenericPropertyInfo;
+import org.apache.zest.api.property.Immutable;
+import org.apache.zest.api.property.Property;
+import org.apache.zest.api.util.Annotations;
+import org.apache.zest.api.util.Classes;
+import org.apache.zest.bootstrap.AssociationDeclarations;
+import org.apache.zest.bootstrap.EntityAssembly;
+import org.apache.zest.bootstrap.ManyAssociationDeclarations;
+import org.apache.zest.bootstrap.NamedAssociationDeclarations;
+import org.apache.zest.bootstrap.StateDeclarations;
+import org.apache.zest.runtime.association.AssociationModel;
+import org.apache.zest.runtime.association.AssociationsModel;
+import org.apache.zest.runtime.association.ManyAssociationModel;
+import org.apache.zest.runtime.association.ManyAssociationsModel;
+import org.apache.zest.runtime.association.NamedAssociationModel;
+import org.apache.zest.runtime.association.NamedAssociationsModel;
+import org.apache.zest.runtime.composite.MixinsModel;
+import org.apache.zest.runtime.composite.StateModel;
+import org.apache.zest.runtime.composite.ValueConstraintsInstance;
+import org.apache.zest.runtime.composite.ValueConstraintsModel;
+import org.apache.zest.runtime.entity.EntityMixinsModel;
+import org.apache.zest.runtime.entity.EntityModel;
+import org.apache.zest.runtime.entity.EntityStateModel;
+import org.apache.zest.runtime.property.PropertyModel;
+
+import static org.apache.zest.api.util.Annotations.isType;
+import static org.apache.zest.api.util.Classes.typeOf;
+import static org.apache.zest.functional.Iterables.filter;
+import static org.apache.zest.functional.Iterables.first;
+
+/**
+ * Declaration of a EntityComposite.
+ */
+public final class EntityAssemblyImpl
+ extends CompositeAssemblyImpl
+ implements EntityAssembly
+{
+ private AssociationDeclarations associationDeclarations;
+ private ManyAssociationDeclarations manyAssociationDeclarations;
+ private NamedAssociationDeclarations namedAssociationDeclarations;
+ private AssociationsModel associationsModel;
+ private ManyAssociationsModel manyAssociationsModel;
+ private NamedAssociationsModel namedAssociationsModel;
+
+ public EntityAssemblyImpl( Class<?> entityType )
+ {
+ super( entityType );
+ // The composite must always implement EntityComposite, as a marker interface
+ if( !EntityComposite.class.isAssignableFrom( entityType ) )
+ {
+ types.add( EntityComposite.class );
+ }
+ }
+
+ @Override
+ protected MixinsModel createMixinsModel()
+ {
+ return new EntityMixinsModel();
+ }
+
+ @Override
+ protected StateModel createStateModel()
+ {
+ return new EntityStateModel( propertiesModel, associationsModel, manyAssociationsModel, namedAssociationsModel );
+ }
+
+ EntityModel newEntityModel(
+ StateDeclarations stateDeclarations,
+ AssociationDeclarations associationDecs,
+ ManyAssociationDeclarations manyAssociationDecs,
+ NamedAssociationDeclarations namedAssociationDecs,
+ AssemblyHelper helper
+ )
+ {
+ this.associationDeclarations = associationDecs;
+ this.manyAssociationDeclarations = manyAssociationDecs;
+ this.namedAssociationDeclarations = namedAssociationDecs;
+ try
+ {
+ associationsModel = new AssociationsModel();
+ manyAssociationsModel = new ManyAssociationsModel();
+ namedAssociationsModel = new NamedAssociationsModel();
+ buildComposite( helper, stateDeclarations );
+
+ EntityModel entityModel = new EntityModel(
+ types, visibility, metaInfo, (EntityMixinsModel) mixinsModel, (EntityStateModel) stateModel, compositeMethodsModel );
+
+ return entityModel;
+ }
+ catch( Exception e )
+ {
+ throw new InvalidApplicationException( "Could not register " + types, e );
+ }
+ }
+
+ @Override
+ protected void addStateFor( AccessibleObject accessor,
+ Iterable<Class<? extends Constraint<?, ?>>> constraintClasses
+ )
+ {
+ String stateName = QualifiedName.fromAccessor( accessor ).name();
+
+ if( registeredStateNames.contains( stateName ) )
+ {
+ return; // Skip already registered names
+ }
+
+ Class<?> accessorType = Classes.RAW_CLASS.map( typeOf( accessor ) );
+ if( Property.class.isAssignableFrom( accessorType ) )
+ {
+ propertiesModel.addProperty( newPropertyModel( accessor, constraintClasses ) );
+ registeredStateNames.add( stateName );
+ }
+ else if( Association.class.isAssignableFrom( accessorType ) )
+ {
+ associationsModel.addAssociation( newAssociationModel( accessor, constraintClasses ) );
+ registeredStateNames.add( stateName );
+ }
+ else if( ManyAssociation.class.isAssignableFrom( accessorType ) )
+ {
+ manyAssociationsModel.addManyAssociation( newManyAssociationModel( accessor, constraintClasses ) );
+ registeredStateNames.add( stateName );
+ }
+ else if( NamedAssociation.class.isAssignableFrom( accessorType ) )
+ {
+ namedAssociationsModel.addNamedAssociation( newNamedAssociationModel( accessor, constraintClasses ) );
+ registeredStateNames.add( stateName );
+ }
+ }
+
+ @Override
+ protected PropertyModel newPropertyModel( AccessibleObject accessor,
+ Iterable<Class<? extends Constraint<?, ?>>> constraintClasses
+ )
+ {
+ Iterable<Annotation> annotations = Annotations.findAccessorAndTypeAnnotationsIn( accessor );
+ boolean optional = first( filter( isType( Optional.class ), annotations ) ) != null;
+ ValueConstraintsModel valueConstraintsModel = constraintsFor( annotations, GenericPropertyInfo.propertyTypeOf( accessor ), ( (Member) accessor )
+ .getName(), optional, constraintClasses, accessor );
+ ValueConstraintsInstance valueConstraintsInstance = null;
+ if( valueConstraintsModel.isConstrained() )
+ {
+ valueConstraintsInstance = valueConstraintsModel.newInstance();
+ }
+ MetaInfo metaInfo = stateDeclarations.metaInfoFor( accessor );
+ Object defaultValue = stateDeclarations.initialValueOf( accessor );
+ boolean useDefaults = metaInfo.get( UseDefaults.class ) != null || stateDeclarations.useDefaults( accessor );
+ boolean immutable = this.immutable || metaInfo.get( Immutable.class ) != null;
+ PropertyModel propertyModel = new PropertyModel( accessor, immutable, useDefaults, valueConstraintsInstance, metaInfo, defaultValue );
+ return propertyModel;
+ }
+
+ public AssociationModel newAssociationModel( AccessibleObject accessor,
+ Iterable<Class<? extends Constraint<?, ?>>> constraintClasses
+ )
+ {
+ Iterable<Annotation> annotations = Annotations.findAccessorAndTypeAnnotationsIn( accessor );
+ boolean optional = first( filter( isType( Optional.class ), annotations ) ) != null;
+
+ // Constraints for Association references
+ ValueConstraintsModel valueConstraintsModel = constraintsFor( annotations, GenericAssociationInfo
+ .associationTypeOf( accessor ), ( (Member) accessor ).getName(), optional, constraintClasses, accessor );
+ ValueConstraintsInstance valueConstraintsInstance = null;
+ if( valueConstraintsModel.isConstrained() )
+ {
+ valueConstraintsInstance = valueConstraintsModel.newInstance();
+ }
+
+ // Constraints for the Association itself
+ valueConstraintsModel = constraintsFor( annotations, Association.class, ( (Member) accessor ).getName(), optional, constraintClasses, accessor );
+ ValueConstraintsInstance associationValueConstraintsInstance = null;
+ if( valueConstraintsModel.isConstrained() )
+ {
+ associationValueConstraintsInstance = valueConstraintsModel.newInstance();
+ }
+
+ MetaInfo metaInfo = associationDeclarations.metaInfoFor( accessor );
+ AssociationModel associationModel = new AssociationModel( accessor, valueConstraintsInstance, associationValueConstraintsInstance, metaInfo );
+ return associationModel;
+ }
+
+ public ManyAssociationModel newManyAssociationModel( AccessibleObject accessor,
+ Iterable<Class<? extends Constraint<?, ?>>> constraintClasses
+ )
+ {
+ Iterable<Annotation> annotations = Annotations.findAccessorAndTypeAnnotationsIn( accessor );
+ boolean optional = first( filter( isType( Optional.class ), annotations ) ) != null;
+
+ // Constraints for entities in ManyAssociation
+ ValueConstraintsModel valueConstraintsModel = constraintsFor( annotations, GenericAssociationInfo
+ .associationTypeOf( accessor ), ( (Member) accessor ).getName(), optional, constraintClasses, accessor );
+ ValueConstraintsInstance valueConstraintsInstance = null;
+ if( valueConstraintsModel.isConstrained() )
+ {
+ valueConstraintsInstance = valueConstraintsModel.newInstance();
+ }
+
+ // Constraints for the ManyAssociation itself
+ valueConstraintsModel = constraintsFor( annotations, ManyAssociation.class, ( (Member) accessor ).getName(), optional, constraintClasses, accessor );
+ ValueConstraintsInstance manyValueConstraintsInstance = null;
+ if( valueConstraintsModel.isConstrained() )
+ {
+ manyValueConstraintsInstance = valueConstraintsModel.newInstance();
+ }
+ MetaInfo metaInfo = manyAssociationDeclarations.metaInfoFor( accessor );
+ ManyAssociationModel associationModel = new ManyAssociationModel( accessor, valueConstraintsInstance, manyValueConstraintsInstance, metaInfo );
+ return associationModel;
+ }
+
+ public NamedAssociationModel newNamedAssociationModel( AccessibleObject accessor,
+ Iterable<Class<? extends Constraint<?, ?>>> constraintClasses
+ )
+ {
+ Iterable<Annotation> annotations = Annotations.findAccessorAndTypeAnnotationsIn( accessor );
+ boolean optional = first( filter( isType( Optional.class ), annotations ) ) != null;
+
+ // Constraints for entities in NamedAssociation
+ ValueConstraintsModel valueConstraintsModel = constraintsFor( annotations, GenericAssociationInfo
+ .associationTypeOf( accessor ), ( (Member) accessor ).getName(), optional, constraintClasses, accessor );
+ ValueConstraintsInstance valueConstraintsInstance = null;
+ if( valueConstraintsModel.isConstrained() )
+ {
+ valueConstraintsInstance = valueConstraintsModel.newInstance();
+ }
+
+ // Constraints for the NamedAssociation itself
+ valueConstraintsModel = constraintsFor( annotations, NamedAssociation.class, ( (Member) accessor ).getName(), optional, constraintClasses, accessor );
+ ValueConstraintsInstance namedValueConstraintsInstance = null;
+ if( valueConstraintsModel.isConstrained() )
+ {
+ namedValueConstraintsInstance = valueConstraintsModel.newInstance();
+ }
+ MetaInfo metaInfo = namedAssociationDeclarations.metaInfoFor( accessor );
+ NamedAssociationModel associationModel = new NamedAssociationModel( accessor, valueConstraintsInstance, namedValueConstraintsInstance, metaInfo );
+ return associationModel;
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/EntityDeclarationImpl.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/EntityDeclarationImpl.java b/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/EntityDeclarationImpl.java
new file mode 100644
index 0000000..ada560e
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/EntityDeclarationImpl.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2007, Rickard Öberg. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.zest.runtime.bootstrap;
+
+import org.apache.zest.api.common.Visibility;
+import org.apache.zest.bootstrap.EntityDeclaration;
+
+import static java.util.Arrays.asList;
+
+/**
+ * Declaration of a Composite. Created by {@link org.apache.zest.bootstrap.ModuleAssembly#transients(Class[])}.
+ */
+public final class EntityDeclarationImpl
+ implements EntityDeclaration
+{
+ private final Iterable<EntityAssemblyImpl> entities;
+
+ public EntityDeclarationImpl( Iterable<EntityAssemblyImpl> entities )
+ {
+ this.entities = entities;
+ }
+
+ @Override
+ public EntityDeclaration setMetaInfo( Object info )
+ {
+ for( EntityAssemblyImpl entity : entities )
+ {
+ entity.metaInfo.set( info );
+ }
+ return this;
+ }
+
+ @Override
+ public EntityDeclaration visibleIn( Visibility visibility )
+ {
+ for( EntityAssemblyImpl entity : entities )
+ {
+ entity.visibility = visibility;
+ }
+ return this;
+ }
+
+ @Override
+ public EntityDeclaration withConcerns( Class<?>... concerns )
+ {
+ for( EntityAssemblyImpl entity : entities )
+ {
+ entity.concerns.addAll( asList( concerns ) );
+ }
+ return this;
+ }
+
+ @Override
+ public EntityDeclaration withSideEffects( Class<?>... sideEffects )
+ {
+ for( EntityAssemblyImpl entity : entities )
+ {
+ entity.sideEffects.addAll( asList( sideEffects ) );
+ }
+ return this;
+ }
+
+ @Override
+ public EntityDeclaration withMixins( Class<?>... mixins )
+ {
+ for( EntityAssemblyImpl entity : entities )
+ {
+ entity.mixins.addAll( asList( mixins ) );
+ }
+ return this;
+ }
+
+ @Override
+ public EntityDeclaration withTypes( Class<?>... types )
+ {
+ for( EntityAssemblyImpl entity : entities )
+ {
+ entity.types.addAll( asList( types ) );
+ }
+ return this;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ImplementsMethodAppliesToFilter.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ImplementsMethodAppliesToFilter.java b/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ImplementsMethodAppliesToFilter.java
new file mode 100644
index 0000000..f7ec1ec
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ImplementsMethodAppliesToFilter.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2008, Rickard Öberg. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.zest.runtime.bootstrap;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import org.apache.zest.api.common.AppliesToFilter;
+
+/**
+ * JAVADOC
+ */
+final class ImplementsMethodAppliesToFilter
+ implements AppliesToFilter
+{
+ @Override
+ public boolean appliesTo( Method method, Class<?> mixin, Class<?> compositeType, Class<?> fragmentClass )
+ {
+ try
+ {
+ return !Modifier.isAbstract( fragmentClass.getMethod( method.getName(), method.getParameterTypes() )
+ .getModifiers() );
+ }
+ catch( NoSuchMethodException e )
+ {
+ return false;
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ImportedServiceAssemblyImpl.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ImportedServiceAssemblyImpl.java b/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ImportedServiceAssemblyImpl.java
new file mode 100644
index 0000000..a07b4f8
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ImportedServiceAssemblyImpl.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2007, Rickard Öberg. All Rights Reserved.
+ * Copyright (c) 2012, Paul Merlin.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.zest.runtime.bootstrap;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.zest.api.activation.Activator;
+import org.apache.zest.api.common.InvalidApplicationException;
+import org.apache.zest.api.common.MetaInfo;
+import org.apache.zest.api.common.Visibility;
+import org.apache.zest.api.service.ServiceImporter;
+import org.apache.zest.api.service.importer.InstanceImporter;
+import org.apache.zest.bootstrap.ImportedServiceAssembly;
+import org.apache.zest.functional.Iterables;
+import org.apache.zest.runtime.activation.ActivatorsModel;
+import org.apache.zest.runtime.service.ImportedServiceModel;
+
+/**
+ * Declaration of an imported Service.
+ *
+ * Created by {@link org.apache.zest.runtime.bootstrap.ModuleAssemblyImpl#importedServices(Class[])}.
+ */
+public final class ImportedServiceAssemblyImpl
+ implements ImportedServiceAssembly
+{
+ private final Class<?> serviceType;
+ private final ModuleAssemblyImpl moduleAssembly;
+ @SuppressWarnings( "raw" )
+ Class<? extends ServiceImporter> serviceProvider = InstanceImporter.class;
+ String identity;
+ boolean importOnStartup = false;
+ MetaInfo metaInfo = new MetaInfo();
+ Visibility visibility = Visibility.module;
+ List<Class<? extends Activator<?>>> activators = new ArrayList<>();
+
+ public ImportedServiceAssemblyImpl( Class<?> serviceType, ModuleAssemblyImpl moduleAssembly )
+ {
+ this.serviceType = serviceType;
+ this.moduleAssembly = moduleAssembly;
+ }
+
+ @Override
+ public Iterable<Class<?>> types()
+ {
+ return Iterables.<Class<?>>iterable( serviceType );
+ }
+
+ @SuppressWarnings( {"raw", "unchecked"} )
+ void addImportedServiceModel( List<ImportedServiceModel> serviceModels )
+ {
+ try
+ {
+ String id = identity;
+ if( id == null )
+ {
+ id = generateId( serviceModels, serviceType );
+ }
+
+ ImportedServiceModel serviceModel = new ImportedServiceModel( serviceType,
+ visibility,
+ serviceProvider,
+ id,
+ importOnStartup,
+ new MetaInfo( metaInfo ).withAnnotations( serviceType ),
+ new ActivatorsModel( activators ),
+ moduleAssembly.name() );
+ serviceModels.add( serviceModel );
+ }
+ catch( Exception e )
+ {
+ throw new InvalidApplicationException( "Could not register " + serviceType.getName(), e );
+ }
+ }
+
+ @SuppressWarnings( "raw" )
+ private String generateId( List<ImportedServiceModel> serviceModels, Class serviceType )
+ {
+ // Find identity that is not yet used
+ int idx = 0;
+ String id = serviceType.getSimpleName();
+ boolean invalid;
+ do
+ {
+ invalid = false;
+ for( ImportedServiceModel serviceModel : serviceModels )
+ {
+ if( serviceModel.identity().equals( id ) )
+ {
+ idx++;
+ id = serviceType.getSimpleName() + "_" + idx;
+ invalid = true;
+ break;
+ }
+ }
+ }
+ while( invalid );
+ return id;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ImportedServiceDeclarationImpl.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ImportedServiceDeclarationImpl.java b/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ImportedServiceDeclarationImpl.java
new file mode 100644
index 0000000..d1263e1
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/bootstrap/ImportedServiceDeclarationImpl.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2007, Rickard Öberg. All Rights Reserved.
+ * Copyright (c) 2012, Paul Merlin.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.zest.runtime.bootstrap;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import org.apache.zest.api.activation.Activator;
+import org.apache.zest.api.common.Visibility;
+import org.apache.zest.api.service.ServiceImporter;
+import org.apache.zest.api.service.qualifier.ServiceTags;
+import org.apache.zest.bootstrap.ImportedServiceDeclaration;
+
+/**
+ * Declaration of an imported Service.
+ */
+public final class ImportedServiceDeclarationImpl
+ implements ImportedServiceDeclaration
+{
+ private final Iterable<ImportedServiceAssemblyImpl> assemblies;
+
+ public ImportedServiceDeclarationImpl( Iterable<ImportedServiceAssemblyImpl> assemblies )
+ {
+ this.assemblies = assemblies;
+ }
+
+ @Override
+ public ImportedServiceDeclaration importOnStartup()
+ {
+ for( ImportedServiceAssemblyImpl assembly : assemblies )
+ {
+ assembly.importOnStartup = true;
+ }
+ return this;
+ }
+
+ @Override
+ public ImportedServiceDeclaration visibleIn( Visibility visibility )
+ {
+ for( ImportedServiceAssemblyImpl assembly : assemblies )
+ {
+ assembly.visibility = visibility;
+ }
+ return this;
+ }
+
+ @Override
+ @SuppressWarnings( "raw" )
+ public ImportedServiceDeclaration importedBy( Class<? extends ServiceImporter> sip )
+ {
+ for( ImportedServiceAssemblyImpl assembly : assemblies )
+ {
+ assembly.serviceProvider = sip;
+ }
+ return this;
+ }
+
+ @Override
+ public ImportedServiceDeclaration identifiedBy( String identity )
+ {
+ for( ImportedServiceAssemblyImpl assembly : assemblies )
+ {
+ assembly.identity = identity;
+ }
+ return this;
+ }
+
+ @Override
+ public ImportedServiceDeclaration taggedWith( String... tags )
+ {
+ for( ImportedServiceAssemblyImpl serviceAssembly : assemblies )
+ {
+ ServiceTags previousTags = serviceAssembly.metaInfo.get( ServiceTags.class );
+ if( previousTags != null )
+ {
+ List<String> tagList = new ArrayList<>();
+ Collections.addAll( tagList, previousTags.tags() );
+ Collections.addAll( tagList, tags );
+ serviceAssembly.metaInfo.set( new ServiceTags( tagList.toArray( new String[ tagList.size() ] ) ) );
+ }
+ else
+ {
+ serviceAssembly.metaInfo.set( new ServiceTags( tags ) );
+ }
+ }
+
+ return this;
+ }
+
+ @Override
+ public ImportedServiceDeclaration setMetaInfo( Object serviceAttribute )
+ {
+ for( ImportedServiceAssemblyImpl assembly : assemblies )
+ {
+ assembly.metaInfo.set( serviceAttribute );
+ }
+ return this;
+ }
+
+ @Override
+ @SafeVarargs
+ public final ImportedServiceDeclaration withActivators( Class<? extends Activator<?>>... activators )
+ {
+ for ( ImportedServiceAssemblyImpl serviceAssembly : assemblies ) {
+ serviceAssembly.activators.addAll( Arrays.asList( activators ) );
+ }
+ return this;
+ }
+}
\ No newline at end of file