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/31 04:58:51 UTC
[11/81] [abbrv] [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/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/entity/EntityModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/entity/EntityModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/entity/EntityModel.java
new file mode 100644
index 0000000..aa45b18
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/entity/EntityModel.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2008, Rickard Öberg. All Rights Reserved.
+ * Copyright (c) 2008, 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.entity;
+
+import java.lang.reflect.Method;
+import org.apache.zest.api.association.AssociationDescriptor;
+import org.apache.zest.api.common.ConstructionException;
+import org.apache.zest.api.common.MetaInfo;
+import org.apache.zest.api.common.Visibility;
+import org.apache.zest.api.composite.CompositeInstance;
+import org.apache.zest.api.constraint.ConstraintViolationException;
+import org.apache.zest.api.entity.EntityDescriptor;
+import org.apache.zest.api.entity.EntityReference;
+import org.apache.zest.api.entity.Identity;
+import org.apache.zest.api.entity.Queryable;
+import org.apache.zest.api.property.PropertyDescriptor;
+import org.apache.zest.api.property.StateHolder;
+import org.apache.zest.api.unitofwork.EntityCompositeAlreadyExistsException;
+import org.apache.zest.api.util.Annotations;
+import org.apache.zest.functional.Iterables;
+import org.apache.zest.runtime.composite.CompositeMethodsModel;
+import org.apache.zest.runtime.composite.CompositeModel;
+import org.apache.zest.runtime.property.PropertyModel;
+import org.apache.zest.runtime.structure.ModuleUnitOfWork;
+import org.apache.zest.spi.entity.EntityState;
+import org.apache.zest.spi.entitystore.EntityAlreadyExistsException;
+import org.apache.zest.spi.entitystore.EntityStoreException;
+import org.apache.zest.spi.entitystore.EntityStoreUnitOfWork;
+import org.apache.zest.spi.module.ModuleSpi;
+
+import static org.apache.zest.functional.Iterables.filter;
+import static org.apache.zest.functional.Iterables.first;
+import static org.apache.zest.functional.Iterables.flattenIterables;
+import static org.apache.zest.functional.Iterables.map;
+
+/**
+ * JAVADOC
+ */
+public final class EntityModel
+ extends CompositeModel
+ implements EntityDescriptor
+{
+ private static final Method IDENTITY_METHOD;
+
+ static
+ {
+ try
+ {
+ IDENTITY_METHOD = Identity.class.getMethod( "identity" );
+ }
+ catch( NoSuchMethodException e )
+ {
+ throw new InternalError( "Zest Core Runtime codebase is corrupted. Contact Zest team: ModuleUnitOfWork" );
+ }
+ }
+
+ private final boolean queryable;
+
+ public EntityModel( Iterable<Class<?>> types,
+ Visibility visibility,
+ MetaInfo info,
+ EntityMixinsModel mixinsModel,
+ EntityStateModel stateModel,
+ CompositeMethodsModel compositeMethodsModel
+ )
+ {
+ super( types, visibility, info, mixinsModel, stateModel, compositeMethodsModel );
+
+ final Queryable queryable = first( Iterables.<Queryable>cast(
+ filter( Annotations.isType( Queryable.class ),
+ flattenIterables( map( Annotations.ANNOTATIONS_OF, types ) ) ) ) );
+ this.queryable = queryable == null || queryable.value();
+ }
+
+ @Override
+ public boolean queryable()
+ {
+ return queryable;
+ }
+
+ @Override
+ public EntityStateModel state()
+ {
+ return (EntityStateModel) super.state();
+ }
+
+ public EntityInstance newInstance( ModuleUnitOfWork uow, ModuleSpi moduleInstance, EntityState state )
+ {
+ EntityInstance instance = new EntityInstance( uow, moduleInstance, this, state );
+ return instance;
+ }
+
+ public Object[] newMixinHolder()
+ {
+ return mixinsModel.newMixinHolder();
+ }
+
+ public Object newMixin( Object[] mixins,
+ EntityStateInstance entityState,
+ EntityInstance entityInstance,
+ Method method
+ )
+ {
+ return ( (EntityMixinsModel) mixinsModel ).newMixin( entityInstance, entityState, mixins, method );
+ }
+
+ public EntityState newEntityState( EntityStoreUnitOfWork store, ModuleSpi module, EntityReference identity )
+ throws ConstraintViolationException, EntityStoreException
+ {
+ try
+ {
+ // New EntityState
+ EntityState entityState = store.newEntityState( module, identity, this );
+
+ // Set identity property
+ PropertyDescriptor persistentPropertyDescriptor = state().propertyModelFor( IDENTITY_METHOD );
+ entityState.setPropertyValue( persistentPropertyDescriptor.qualifiedName(), identity.identity() );
+
+ return entityState;
+ }
+ catch( EntityAlreadyExistsException e )
+ {
+ throw new EntityCompositeAlreadyExistsException( identity );
+ }
+ catch( EntityStoreException e )
+ {
+ throw new ConstructionException( "Could not create new entity in store", e );
+ }
+ }
+
+ public void initState( ModuleSpi module, EntityState entityState )
+ {
+ // Set new properties to default value
+ for( PropertyModel propertyDescriptor : state().properties() )
+ {
+ entityState.setPropertyValue( propertyDescriptor.qualifiedName(), propertyDescriptor.initialValue( module ) );
+ }
+
+ // Set new associations to null
+ for( AssociationDescriptor associationDescriptor : state().associations() )
+ {
+ entityState.setAssociationValue( associationDescriptor.qualifiedName(), null );
+ }
+
+ // Set new many-associations to empty
+ for( AssociationDescriptor associationDescriptor : state().manyAssociations() )
+ {
+ entityState.manyAssociationValueOf( associationDescriptor.qualifiedName() );
+ }
+
+ // Set new named-associations to empty
+ for( AssociationDescriptor associationDescriptor : state().namedAssociations() )
+ {
+ entityState.namedAssociationValueOf( associationDescriptor.qualifiedName() );
+ }
+ }
+
+ public void invokeLifecycle( boolean create, Object[] mixins, CompositeInstance instance, StateHolder state )
+ {
+ ( (EntityMixinsModel) mixinsModel ).invokeLifecycle( create, mixins, instance, state );
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/entity/EntityPropertyInstance.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/entity/EntityPropertyInstance.java b/core/runtime/src/main/java/org/apache/zest/runtime/entity/EntityPropertyInstance.java
new file mode 100644
index 0000000..5ac473f
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/entity/EntityPropertyInstance.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2007, Rickard Öberg. All Rights Reserved.
+ * Copyright (c) 2008, Edward Yakop. 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.entity;
+
+import org.apache.zest.runtime.property.PropertyInfo;
+import org.apache.zest.runtime.property.PropertyInstance;
+import org.apache.zest.spi.entity.EntityState;
+
+/**
+ * {@code EntityPropertyInstance} represents a property whose value must be backed by an EntityState.
+ */
+public class EntityPropertyInstance<T>
+ extends PropertyInstance<T>
+{
+ private final EntityState entityState;
+
+ /**
+ * Construct an instance of {@code PropertyInstance} with the specified arguments.
+ *
+ * @param aPropertyInfo The property info. This argument must not be {@code null}.
+ * @param entityState EntityState
+ */
+ @SuppressWarnings( "unchecked" )
+ public EntityPropertyInstance( PropertyInfo aPropertyInfo, EntityState entityState )
+ {
+ super( aPropertyInfo, (T) entityState.propertyValueOf( aPropertyInfo.qualifiedName() ) );
+ this.entityState = entityState;
+ }
+
+ /**
+ * Sets this property value.
+ *
+ * @param aNewValue The new value.
+ */
+ @Override
+ public void set( T aNewValue )
+ {
+ super.set( aNewValue );
+ entityState.setPropertyValue( model.qualifiedName(), aNewValue );
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/entity/EntityStateInstance.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/entity/EntityStateInstance.java b/core/runtime/src/main/java/org/apache/zest/runtime/entity/EntityStateInstance.java
new file mode 100644
index 0000000..fe528b3
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/entity/EntityStateInstance.java
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2008-2011, Rickard Öberg. All Rights Reserved.
+ * Copyright (c) 2008-2013, Niclas Hedhman. 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.entity;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.zest.api.association.Association;
+import org.apache.zest.api.association.AssociationDescriptor;
+import org.apache.zest.api.association.AssociationStateHolder;
+import org.apache.zest.api.association.ManyAssociation;
+import org.apache.zest.api.association.NamedAssociation;
+import org.apache.zest.api.entity.EntityReference;
+import org.apache.zest.api.property.Property;
+import org.apache.zest.api.property.PropertyDescriptor;
+import org.apache.zest.api.unitofwork.UnitOfWork;
+import org.apache.zest.api.util.Classes;
+import org.apache.zest.functional.Function;
+import org.apache.zest.functional.Function2;
+import org.apache.zest.functional.Iterables;
+import org.apache.zest.runtime.association.AssociationInstance;
+import org.apache.zest.runtime.association.AssociationModel;
+import org.apache.zest.runtime.association.ManyAssociationInstance;
+import org.apache.zest.runtime.association.ManyAssociationModel;
+import org.apache.zest.runtime.association.NamedAssociationInstance;
+import org.apache.zest.runtime.association.NamedAssociationModel;
+import org.apache.zest.runtime.composite.ConstraintsCheck;
+import org.apache.zest.runtime.property.PropertyModel;
+import org.apache.zest.runtime.unitofwork.BuilderEntityState;
+import org.apache.zest.spi.entity.EntityState;
+
+/**
+ * TODO
+ */
+public final class EntityStateInstance
+ implements AssociationStateHolder
+{
+ private Map<AccessibleObject, Object> state;
+
+ private final EntityStateModel stateModel;
+ private EntityState entityState;
+ private final Function2<EntityReference, Type, Object> entityFunction;
+
+ public EntityStateInstance( EntityStateModel stateModel, final UnitOfWork uow, EntityState entityState )
+ {
+ this.stateModel = stateModel;
+ this.entityState = entityState;
+
+ entityFunction = new Function2<EntityReference, Type, Object>()
+ {
+ @Override
+ public Object map( EntityReference entityReference, Type type )
+ {
+ return uow.get( Classes.RAW_CLASS.map( type ), entityReference.identity() );
+ }
+ };
+ }
+
+ @Override
+ @SuppressWarnings( "unchecked" )
+ public <T> Property<T> propertyFor( AccessibleObject accessor )
+ throws IllegalArgumentException
+ {
+ Map<AccessibleObject, Object> state = state();
+
+ Property<T> property = (Property<T>) state.get( accessor );
+
+ if( property == null )
+ {
+ PropertyModel entityPropertyModel = stateModel.propertyModelFor( accessor );
+ property = new EntityPropertyInstance<>(
+ entityState instanceof BuilderEntityState
+ ? entityPropertyModel.getBuilderInfo()
+ : entityPropertyModel,
+ entityState );
+ state.put( accessor, property );
+ }
+
+ return property;
+ }
+
+ @Override
+ public Iterable<Property<?>> properties()
+ {
+ return Iterables.map( new Function<PropertyDescriptor, Property<?>>()
+ {
+ @Override
+ public Property<?> map( PropertyDescriptor propertyDescriptor )
+ {
+ return propertyFor( propertyDescriptor.accessor() );
+ }
+ }, stateModel.properties() );
+ }
+
+ @Override
+ @SuppressWarnings( "unchecked" )
+ public <T> Association<T> associationFor( AccessibleObject accessor )
+ throws IllegalArgumentException
+ {
+ Map<AccessibleObject, Object> state = state();
+ Association<T> association = (Association<T>) state.get( accessor );
+
+ if( association == null )
+ {
+ final AssociationModel associationModel = stateModel.getAssociation( accessor );
+ association = new AssociationInstance<>(
+ entityState instanceof BuilderEntityState
+ ? associationModel.getBuilderInfo()
+ : associationModel,
+ entityFunction,
+ new Property<EntityReference>()
+ {
+ @Override
+ public EntityReference get()
+ {
+ return entityState.associationValueOf( associationModel.qualifiedName() );
+ }
+
+ @Override
+ public void set( EntityReference newValue )
+ throws IllegalArgumentException, IllegalStateException
+ {
+ entityState.setAssociationValue( associationModel.qualifiedName(), newValue );
+ }
+ } );
+ state.put( accessor, association );
+ }
+
+ return association;
+ }
+
+ @Override
+ public Iterable<Association<?>> allAssociations()
+ {
+ return Iterables.map( new Function<AssociationDescriptor, Association<?>>()
+ {
+ @Override
+ public Association<?> map( AssociationDescriptor associationDescriptor )
+ {
+ return associationFor( associationDescriptor.accessor() );
+ }
+ }, stateModel.associations() );
+ }
+
+ @Override
+ @SuppressWarnings( "unchecked" )
+ public <T> ManyAssociation<T> manyAssociationFor( AccessibleObject accessor )
+ {
+ Map<AccessibleObject, Object> state = state();
+
+ ManyAssociation<T> manyAssociation = (ManyAssociation<T>) state.get( accessor );
+
+ if( manyAssociation == null )
+ {
+ ManyAssociationModel associationModel = stateModel.getManyAssociation( accessor );
+ manyAssociation = new ManyAssociationInstance<>(
+ entityState instanceof BuilderEntityState
+ ? associationModel.getBuilderInfo()
+ : associationModel,
+ entityFunction,
+ entityState.manyAssociationValueOf( associationModel.qualifiedName() ) );
+ state.put( accessor, manyAssociation );
+ }
+
+ return manyAssociation;
+ }
+
+ @Override
+ public Iterable<ManyAssociation<?>> allManyAssociations()
+ {
+ return Iterables.map( new Function<AssociationDescriptor, ManyAssociation<?>>()
+ {
+ @Override
+ public ManyAssociation<?> map( AssociationDescriptor associationDescriptor )
+ {
+ return manyAssociationFor( associationDescriptor.accessor() );
+ }
+ }, stateModel.manyAssociations() );
+ }
+
+ @Override
+ @SuppressWarnings( "unchecked" )
+ public <T> NamedAssociation<T> namedAssociationFor( AccessibleObject accessor )
+ {
+ Map<AccessibleObject, Object> state = state();
+
+ NamedAssociation<T> namedAssociation = (NamedAssociation<T>) state.get( accessor );
+
+ if( namedAssociation == null )
+ {
+ NamedAssociationModel associationModel = stateModel.getNamedAssociation( accessor );
+ namedAssociation = new NamedAssociationInstance<>(
+ entityState instanceof BuilderEntityState
+ ? associationModel.getBuilderInfo()
+ : associationModel,
+ entityFunction,
+ entityState.namedAssociationValueOf( associationModel.qualifiedName() ) );
+ state.put( accessor, namedAssociation );
+ }
+
+ return namedAssociation;
+ }
+
+ @Override
+ public Iterable<? extends NamedAssociation<?>> allNamedAssociations()
+ {
+ return Iterables.map( new Function<AssociationDescriptor, NamedAssociation<?>>()
+ {
+ @Override
+ public NamedAssociation<?> map( AssociationDescriptor associationDescriptor )
+ {
+ return namedAssociationFor( associationDescriptor.accessor() );
+ }
+ }, stateModel.namedAssociations() );
+ }
+
+ public void checkConstraints()
+ {
+ for( PropertyDescriptor propertyDescriptor : stateModel.properties() )
+ {
+ ConstraintsCheck constraints = (ConstraintsCheck) propertyDescriptor;
+ Property<Object> property = this.propertyFor( propertyDescriptor.accessor() );
+ constraints.checkConstraints( property.get() );
+ }
+
+ for( AssociationDescriptor associationDescriptor : stateModel.associations() )
+ {
+ ConstraintsCheck constraints = (ConstraintsCheck) associationDescriptor;
+ Association<Object> association = this.associationFor( associationDescriptor.accessor() );
+ constraints.checkConstraints( association.get() );
+ }
+
+ // TODO Should ManyAssociations and NamedAssociations be checked too?
+ }
+
+ private Map<AccessibleObject, Object> state()
+ {
+ if( state == null )
+ {
+ state = new HashMap<>();
+ }
+
+ return state;
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/entity/EntityStateModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/entity/EntityStateModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/entity/EntityStateModel.java
new file mode 100644
index 0000000..8b9b56e
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/entity/EntityStateModel.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2008-2011, Rickard Öberg. All Rights Reserved.
+ * Copyright (c) 2008-2013, Niclas Hedhman. 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.entity;
+
+import java.lang.reflect.AccessibleObject;
+import org.apache.zest.api.association.AssociationDescriptor;
+import org.apache.zest.api.association.AssociationStateDescriptor;
+import org.apache.zest.api.common.QualifiedName;
+import org.apache.zest.functional.HierarchicalVisitor;
+import org.apache.zest.functional.VisitableHierarchy;
+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.StateModel;
+import org.apache.zest.runtime.property.PropertiesModel;
+
+/**
+ * Model for EntityComposite state.
+ */
+public final class EntityStateModel
+ extends StateModel
+ implements AssociationStateDescriptor
+{
+ private final AssociationsModel associationsModel;
+ private final ManyAssociationsModel manyAssociationsModel;
+ private final NamedAssociationsModel namedAssociationsModel;
+
+ public EntityStateModel( PropertiesModel propertiesModel,
+ AssociationsModel associationsModel,
+ ManyAssociationsModel manyAssociationsModel,
+ NamedAssociationsModel namedAssociationsModel )
+ {
+ super( propertiesModel );
+ this.associationsModel = associationsModel;
+ this.manyAssociationsModel = manyAssociationsModel;
+ this.namedAssociationsModel = namedAssociationsModel;
+ }
+
+ public AssociationModel getAssociation( AccessibleObject accessor )
+ throws IllegalArgumentException
+ {
+ return associationsModel.getAssociation( accessor );
+ }
+
+ @Override
+ public AssociationDescriptor getAssociationByName( String name )
+ throws IllegalArgumentException
+ {
+ return associationsModel.getAssociationByName( name );
+ }
+
+ @Override
+ public AssociationDescriptor getAssociationByQualifiedName( QualifiedName name )
+ throws IllegalArgumentException
+ {
+ return associationsModel.getAssociationByQualifiedName( name );
+ }
+
+ public ManyAssociationModel getManyAssociation( AccessibleObject accessor )
+ throws IllegalArgumentException
+ {
+ return manyAssociationsModel.getManyAssociation( accessor );
+ }
+
+ @Override
+ public AssociationDescriptor getManyAssociationByName( String name )
+ throws IllegalArgumentException
+ {
+ return manyAssociationsModel.getManyAssociationByName( name );
+ }
+
+ @Override
+ public AssociationDescriptor getManyAssociationByQualifiedName( QualifiedName name )
+ throws IllegalArgumentException
+ {
+ return manyAssociationsModel.getManyAssociationByQualifiedName( name );
+ }
+
+ public NamedAssociationModel getNamedAssociation( AccessibleObject accessor )
+ throws IllegalArgumentException
+ {
+ return namedAssociationsModel.getNamedAssociation( accessor );
+ }
+
+ @Override
+ public AssociationDescriptor getNamedAssociationByName( String name )
+ throws IllegalArgumentException
+ {
+ return namedAssociationsModel.getNamedAssociationByName( name );
+ }
+
+ @Override
+ public AssociationDescriptor getNamedAssociationByQualifiedName( QualifiedName name )
+ throws IllegalArgumentException
+ {
+ return namedAssociationsModel.getNamedAssociationByQualifiedName( name );
+ }
+
+ @Override
+ public Iterable<AssociationModel> associations()
+ {
+ return associationsModel.associations();
+ }
+
+ @Override
+ public Iterable<ManyAssociationModel> manyAssociations()
+ {
+ return manyAssociationsModel.manyAssociations();
+ }
+
+ @Override
+ public Iterable<NamedAssociationModel> namedAssociations()
+ {
+ return namedAssociationsModel.namedAssociations();
+ }
+
+ @Override
+ public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> visitor )
+ throws ThrowableType
+ {
+ if( visitor.visitEnter( this ) )
+ {
+ if( ( (VisitableHierarchy<Object, Object>) propertiesModel ).accept( visitor ) )
+ {
+ if( ( (VisitableHierarchy<AssociationsModel, AssociationModel>) associationsModel ).accept( visitor ) )
+ {
+ if( ( (VisitableHierarchy<ManyAssociationsModel, ManyAssociationModel>) manyAssociationsModel ).accept( visitor ) )
+ {
+ ( (VisitableHierarchy<NamedAssociationsModel, NamedAssociationModel>) namedAssociationsModel ).accept( visitor );
+ }
+ }
+ }
+ }
+ return visitor.visitLeave( this );
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/injection/Dependencies.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/injection/Dependencies.java b/core/runtime/src/main/java/org/apache/zest/runtime/injection/Dependencies.java
new file mode 100644
index 0000000..f2b3cf5
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/injection/Dependencies.java
@@ -0,0 +1,38 @@
+/*
+ * 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.injection;
+
+import org.apache.zest.functional.Function;
+
+/**
+ * TODO
+ */
+public interface Dependencies
+{
+ public static Function<Dependencies, Iterable<DependencyModel>> DEPENDENCIES_FUNCTION = new Function<Dependencies, Iterable<DependencyModel>>()
+ {
+ @Override
+ public Iterable<DependencyModel> map( Dependencies dependencies )
+ {
+ return dependencies.dependencies();
+ }
+ };
+
+ Iterable<DependencyModel> dependencies();
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/injection/DependencyModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/injection/DependencyModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/injection/DependencyModel.java
new file mode 100644
index 0000000..8ceecba
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/injection/DependencyModel.java
@@ -0,0 +1,412 @@
+/*
+ * 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.injection;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.Collections;
+import org.apache.zest.api.common.ConstructionException;
+import org.apache.zest.api.common.Optional;
+import org.apache.zest.api.composite.DependencyDescriptor;
+import org.apache.zest.bootstrap.BindingException;
+import org.apache.zest.bootstrap.InvalidInjectionException;
+import org.apache.zest.functional.Function;
+import org.apache.zest.functional.Iterables;
+import org.apache.zest.functional.Specification;
+import org.apache.zest.functional.Visitable;
+import org.apache.zest.functional.Visitor;
+import org.apache.zest.runtime.injection.provider.InjectionProviderException;
+import org.apache.zest.runtime.model.Binder;
+import org.apache.zest.runtime.model.Resolution;
+
+import static org.apache.zest.api.util.Annotations.isType;
+import static org.apache.zest.functional.Iterables.iterable;
+
+/**
+ * JAVADOC
+ * move all the extraction code to a TypeUtils class
+ */
+public final class DependencyModel
+ implements Binder, DependencyDescriptor, Visitable<DependencyModel>
+{
+ public static boolean isOptional( Annotation injectionAnnotation, Annotation[] annotations )
+ {
+ if( Iterables.matchesAny( isType( Optional.class ), iterable( annotations ) ) )
+ {
+ return true;
+ }
+
+ Method[] methods = injectionAnnotation.annotationType().getMethods();
+ for( Method method : methods )
+ {
+ if( method.getName().equals( "optional" ) )
+ {
+ try
+ {
+ return (Boolean) method.invoke( injectionAnnotation );
+ }
+ catch( Throwable e )
+ {
+ return false;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ // Model
+ private final Annotation injectionAnnotation;
+ private final Type injectionType;
+ private final Class<?> injectedClass;
+ private final Class<?> rawInjectionClass;
+ private final boolean optional;
+ private final Annotation[] annotations;
+
+ // Binding
+ private InjectionProvider injectionProvider;
+
+ public DependencyModel( Annotation injectionAnnotation,
+ Type genericType,
+ Class<?> injectedClass,
+ boolean optional,
+ Annotation[] annotations
+ )
+ {
+ this.injectionAnnotation = injectionAnnotation;
+ this.injectedClass = injectedClass;
+
+ this.injectionType = genericType;
+ this.optional = optional;
+ this.annotations = annotations;
+ this.rawInjectionClass = mapPrimitiveTypes( extractRawInjectionClass( injectedClass, injectionType ) );
+ }
+
+ @Override
+ public <ThrowableType extends Throwable> boolean accept( Visitor<? super DependencyModel, ThrowableType> visitor )
+ throws ThrowableType
+ {
+ return visitor.visit( this );
+ }
+
+ private Class<?> extractRawInjectionClass( Class<?> injectedClass, final Type injectionType )
+ {
+ // Calculate raw injection type
+ if( injectionType instanceof Class )
+ {
+ return (Class<?>) injectionType;
+ }
+ else if( injectionType instanceof ParameterizedType )
+ {
+ return (Class<?>) ( (ParameterizedType) injectionType ).getRawType();
+ }
+ else if( injectionType instanceof TypeVariable )
+ {
+ return extractRawInjectionClass( injectedClass, (TypeVariable<?>) injectionType );
+ }
+ throw new IllegalArgumentException(
+ "Could not extract the rawInjectionClass of " + injectedClass + " and " + injectionType );
+ }
+
+ private Class<?> extractRawInjectionClass( Class<?> injectedClass, TypeVariable<?> injectionTypeVariable )
+ {
+ int index = 0;
+ for( TypeVariable<?> typeVariable : injectionTypeVariable.getGenericDeclaration().getTypeParameters() )
+ {
+ if( injectionTypeVariable.getName().equals( typeVariable.getName() ) )
+ {
+ return (Class<?>) getActualType( injectedClass, index );
+ }
+ index++;
+ }
+ throw new IllegalArgumentException(
+ "Could not extract the rawInjectionClass of " + injectedClass + " and " + injectionTypeVariable );
+ }
+
+ // todo continue refactoring
+
+ private Type getActualType( Class<?> injectedClass, int index )
+ {
+ // Type index found - map it to actual type
+ Type genericType = injectedClass;
+ Type type = null;
+
+ while( !Object.class.equals( genericType ) && type == null )
+ {
+ genericType = ( (Class<?>) genericType ).getGenericSuperclass();
+ if( genericType instanceof ParameterizedType )
+ {
+ type = ( (ParameterizedType) genericType ).getActualTypeArguments()[ index ];
+ }
+ else
+ {
+ Type[] genericInterfaces = ( (Class<?>) genericType ).getGenericInterfaces();
+ if( genericInterfaces.length > index )
+ {
+ type = genericInterfaces[ index ];
+ if( type instanceof ParameterizedType )
+ {
+ type = ( (ParameterizedType) type ).getActualTypeArguments()[ index ];
+ }
+ // TODO type may still be one of the generic interfaces???
+ }
+ }
+ }
+
+ if( type == null )
+ {
+ type = Object.class; // Generic type with no constraints so Object is fine
+ }
+
+ return type;
+ }
+
+ // FIXME This method is unused, remove it.
+ private Type extractDependencyType( Type injectionType )
+ {
+ if( injectionType instanceof ParameterizedType )
+ {
+ return ( (ParameterizedType) injectionType ).getActualTypeArguments()[ 0 ];
+ }
+ else if( injectionType instanceof TypeVariable )
+ {
+ return ( (TypeVariable) injectionType ).getBounds()[ 0 ];
+ }
+ return injectionType;
+ }
+
+ // Model
+ @Override
+ public Annotation injectionAnnotation()
+ {
+ return injectionAnnotation;
+ }
+
+ @Override
+ public Type injectionType()
+ {
+ return injectionType;
+ }
+
+ @Override
+ public Class<?> injectedClass()
+ {
+ return injectedClass;
+ }
+
+ /**
+ * Get the raw dependency type.
+ * <p>
+ * If the dependency uses generics this is the raw type,
+ * and otherwise it is the type of the field.
+ * <p>
+ * Examples:
+ * <p>
+ * {@code @Service MyService service} -> MyService
+ * <p>
+ * {@code @Entity Iterable<Foo> fooList} -> Iterable
+ * <p>
+ * {@code @Entity Query<Foo> fooQuery} -> Query
+ *
+ * @return raw injection type.
+ */
+ @Override
+ public Class<?> rawInjectionType()
+ {
+ return rawInjectionClass;
+ }
+
+ @Override
+ public boolean optional()
+ {
+ return optional;
+ }
+
+ @Override
+ public Annotation[] annotations()
+ {
+ return annotations;
+ }
+
+ @Override
+ public void bind( Resolution resolution )
+ throws BindingException
+ {
+ InjectionProviderFactory providerFactory = resolution.application().injectionProviderFactory();
+
+ try
+ {
+ injectionProvider = providerFactory.newInjectionProvider( resolution, this );
+
+ if( injectionProvider == null && !optional )
+ {
+ String message =
+ "[Module " + resolution.module()
+ .name() + "] Non-optional @" + rawInjectionClass.getName() + " was not bound in " + injectedClass
+ .getName();
+ throw new ConstructionException( message );
+ }
+ }
+ catch( InvalidInjectionException e )
+ {
+ throw new BindingException( "Could not bind dependency injection", e );
+ }
+ }
+
+ // Context
+ public Object inject( InjectionContext context )
+ {
+ if( injectionProvider == null )
+ {
+ return null;
+ }
+ Object injectedValue;
+ try
+ {
+ injectedValue = injectionProvider.provideInjection( context );
+ }
+ catch( InjectionProviderException e )
+ {
+ Throwable ex = e;
+ if( ex.getCause() != null )
+ {
+ ex = ex.getCause();
+ }
+
+ String message = "[Module " + context.module().name() + "] InjectionProvider unable to resolve @" +
+ injectionAnnotation.annotationType().getSimpleName() + " " + injectionType.toString();
+ throw new ConstructionException( message, ex );
+ }
+ if( injectedValue == null && !optional )
+ {
+ String simpleName = injectionAnnotation.annotationType().getSimpleName();
+ String message = "[Module " + context.module().name() + "] Non-optional @" +
+ simpleName + " " + injectionType.toString() +
+ " was null in " + injectedClass.getName();
+ if( simpleName.toLowerCase().contains( "service" ) )
+ {
+ message = message + ". Did you mean the @Service injection scope?";
+ }
+ throw new ConstructionException( message );
+ }
+ return getInjectedValue( injectedValue );
+ }
+
+ @SuppressWarnings( "unchecked" )
+ private Object getInjectedValue( Object injectionResult )
+ {
+ if( injectionResult == null )
+ {
+ return null;
+ }
+
+ if( injectionResult instanceof Iterable )
+ {
+ if( Iterable.class.isAssignableFrom( rawInjectionClass ) || rawInjectionClass.isInstance(
+ injectionResult ) )
+ {
+ return injectionResult;
+ }
+ else
+ {
+ return Iterables.first( (Iterable) injectionResult );
+ }
+ }
+ else
+ {
+ if( Iterable.class.equals( injectionType ) )
+ {
+ return Collections.singleton( injectionResult );
+ }
+ }
+ return injectionResult;
+ }
+
+ private final static Class<?>[] primitiveTypeMapping = {
+ boolean.class, Boolean.class,
+ byte.class, Byte.class,
+ short.class, Short.class,
+ char.class, Character.class,
+ long.class, Long.class,
+ double.class, Double.class,
+ float.class, Float.class,
+ int.class, Integer.class,
+ };
+
+ private Class<?> mapPrimitiveTypes( Class<?> rawInjectionType )
+ {
+ if( rawInjectionType == null || !rawInjectionType.isPrimitive() )
+ {
+ return rawInjectionType;
+ }
+ for( int i = 0; i < primitiveTypeMapping.length; i += 2 )
+ {
+ if( primitiveTypeMapping[ i ].equals( rawInjectionType ) )
+ {
+ return primitiveTypeMapping[ i + 1 ];
+ }
+ }
+ return rawInjectionType;
+ }
+
+ public boolean hasScope( final Class<? extends Annotation> scope )
+ {
+ return scope == null || scope.equals( injectionAnnotation().annotationType() );
+ }
+
+ public Class<? extends Annotation> injectionAnnotationType()
+ {
+ if( injectionAnnotation == null )
+ {
+ return null;
+ }
+ return injectionAnnotation.annotationType();
+ }
+
+ @Override
+ public String toString()
+ {
+ return injectionAnnotation + " for " + injectionType + " in " + injectedClass.getName();
+ }
+
+ public static class ScopeSpecification
+ implements Specification<DependencyModel>
+ {
+ private final Class<? extends Annotation> scope;
+
+ public ScopeSpecification( Class<? extends Annotation> scope )
+ {
+ this.scope = scope;
+ }
+
+ @Override
+ public boolean satisfiedBy( DependencyModel model )
+ {
+ return model.hasScope( scope );
+ }
+ }
+
+ public static class InjectionTypeFunction
+ implements Function<DependencyModel, Class<?>>
+ {
+ @Override
+ public Class<?> map( DependencyModel dependencyModel )
+ {
+ return dependencyModel.rawInjectionType();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectedFieldModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectedFieldModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectedFieldModel.java
new file mode 100644
index 0000000..60977a5
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectedFieldModel.java
@@ -0,0 +1,147 @@
+/*
+ * 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.injection;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Proxy;
+import java.util.Collection;
+import org.apache.zest.api.composite.InjectedFieldDescriptor;
+import org.apache.zest.api.util.Classes;
+import org.apache.zest.bootstrap.BindingException;
+import org.apache.zest.bootstrap.InjectionException;
+import org.apache.zest.functional.HierarchicalVisitor;
+import org.apache.zest.functional.Specification;
+import org.apache.zest.functional.VisitableHierarchy;
+import org.apache.zest.runtime.composite.TransientInstance;
+import org.apache.zest.runtime.model.Resolution;
+
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singleton;
+
+/**
+ * JAVADOC
+ */
+public final class InjectedFieldModel
+ implements InjectedFieldDescriptor, VisitableHierarchy<InjectedFieldModel, DependencyModel>
+{
+ private DependencyModel dependencyModel;
+ private Field injectedField;
+
+ public InjectedFieldModel( Field injectedField, DependencyModel dependencyModel )
+ {
+ injectedField.setAccessible( true );
+ this.injectedField = injectedField;
+ this.dependencyModel = dependencyModel;
+ }
+
+ @Override
+ public DependencyModel dependency()
+ {
+ return dependencyModel;
+ }
+
+ @Override
+ public Field field()
+ {
+ return injectedField;
+ }
+
+ public void bind( Resolution resolution )
+ throws BindingException
+ {
+ dependencyModel.bind( resolution.forField( injectedField ) );
+ }
+
+ public void inject( InjectionContext context, Object instance )
+ {
+ Object value = dependencyModel.inject( context );
+ try
+ {
+ injectedField.set( instance, value );
+ }
+ catch( IllegalAccessException e )
+ {
+ throw new InjectionException( e );
+ }
+ catch( IllegalArgumentException e )
+ {
+ String valueClassName;
+ if( Proxy.isProxyClass( value.getClass() ) )
+ {
+ InvocationHandler invocationHandler = Proxy.getInvocationHandler( value );
+ if( invocationHandler instanceof TransientInstance )
+ {
+ TransientInstance handler = (TransientInstance) invocationHandler;
+ valueClassName = Classes.toString( handler.descriptor().types() )
+ + " in [" + handler.module().name() + "] of [" + handler.layer().name() + "]";
+ }
+ else
+ {
+ valueClassName = invocationHandler.toString();
+ }
+ }
+ else
+ {
+ valueClassName = value.getClass().getName();
+ }
+ StringBuilder annotBuilder = new StringBuilder();
+ for( Annotation annot : injectedField.getAnnotations() )
+ {
+ String s = annot.toString();
+ annotBuilder.append( "@" ).append( s.substring( s.lastIndexOf( '.' ) + 1, s.length() - 2 ) );
+ annotBuilder.append( " " );
+ }
+ String annots = annotBuilder.toString();
+ String message = "Can not inject the field\n "
+ + injectedField.getDeclaringClass()
+ + "\n {\n " + annots + "\n "
+ + injectedField.getType().getSimpleName() + " " + injectedField.getName()
+ + "\n }\nwith value \n " + value + "\nof type\n "
+ + valueClassName;
+ throw new InjectionException( message, e );
+ }
+ }
+
+ @Override
+ public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super InjectedFieldModel, ? super DependencyModel, ThrowableType> visitor )
+ throws ThrowableType
+ {
+ if( visitor.visitEnter( this ) )
+ {
+ visitor.visit( dependencyModel );
+ }
+ return visitor.visitLeave( this );
+ }
+
+ public Collection<DependencyModel> filter( Specification<DependencyModel> specification )
+ {
+ if( specification.satisfiedBy( dependencyModel ) )
+ {
+ return singleton( dependencyModel );
+ }
+ else
+ {
+ return emptyList();
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ return "InjectedFieldModel{" + ", injectedField=" + injectedField + '}';
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectedFieldsModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectedFieldsModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectedFieldsModel.java
new file mode 100644
index 0000000..e61bc39
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectedFieldsModel.java
@@ -0,0 +1,124 @@
+/*
+ * 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.injection;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.zest.api.injection.InjectionScope;
+import org.apache.zest.api.util.Classes;
+import org.apache.zest.api.util.Fields;
+import org.apache.zest.functional.Function;
+import org.apache.zest.functional.HierarchicalVisitor;
+import org.apache.zest.functional.Iterables;
+import org.apache.zest.functional.VisitableHierarchy;
+
+import static org.apache.zest.api.util.Annotations.hasAnnotation;
+import static org.apache.zest.api.util.Annotations.type;
+import static org.apache.zest.functional.Iterables.filter;
+import static org.apache.zest.functional.Iterables.first;
+import static org.apache.zest.functional.Iterables.iterable;
+import static org.apache.zest.functional.Specifications.translate;
+
+/**
+ * JAVADOC
+ */
+public final class InjectedFieldsModel
+ implements Dependencies, VisitableHierarchy<Object, Object>
+{
+ private final List<InjectedFieldModel> fields = new ArrayList<InjectedFieldModel>();
+
+ public InjectedFieldsModel( Class fragmentClass )
+ {
+ Iterable<Field> mappedFields = Fields.FIELDS_OF.map( fragmentClass );
+ for( Field field : mappedFields )
+ {
+ Annotation injectionAnnotation = first( filter( translate( type(), hasAnnotation( InjectionScope.class ) ), iterable( field
+ .getAnnotations() ) ) );
+ if( injectionAnnotation != null )
+ {
+ addModel( fragmentClass, field, injectionAnnotation );
+ }
+ }
+ }
+
+ private void addModel( Class fragmentClass, Field field, Annotation injectionAnnotation )
+ {
+ Type genericType = field.getGenericType();
+ if( genericType instanceof ParameterizedType )
+ {
+ genericType = new ParameterizedTypeInstance( ( (ParameterizedType) genericType ).getActualTypeArguments(), ( (ParameterizedType) genericType )
+ .getRawType(), ( (ParameterizedType) genericType ).getOwnerType() );
+
+ for( int i = 0; i < ( (ParameterizedType) genericType ).getActualTypeArguments().length; i++ )
+ {
+ Type type = ( (ParameterizedType) genericType ).getActualTypeArguments()[ i ];
+ if( type instanceof TypeVariable )
+ {
+ type = Classes.resolveTypeVariable( (TypeVariable) type, field.getDeclaringClass(), fragmentClass );
+ ( (ParameterizedType) genericType ).getActualTypeArguments()[ i ] = type;
+ }
+ }
+ }
+
+ boolean optional = DependencyModel.isOptional( injectionAnnotation, field.getAnnotations() );
+ DependencyModel dependencyModel = new DependencyModel( injectionAnnotation, genericType, fragmentClass, optional, field
+ .getAnnotations() );
+ InjectedFieldModel injectedFieldModel = new InjectedFieldModel( field, dependencyModel );
+ this.fields.add( injectedFieldModel );
+ }
+
+ @Override
+ public Iterable<DependencyModel> dependencies()
+ {
+ return Iterables.map( new Function<InjectedFieldModel, DependencyModel>()
+ {
+ @Override
+ public DependencyModel map( InjectedFieldModel injectedFieldModel )
+ {
+ return injectedFieldModel.dependency();
+ }
+ }, fields );
+ }
+
+ @Override
+ public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> modelVisitor )
+ throws ThrowableType
+ {
+ if( modelVisitor.visitEnter( this ) )
+ {
+ for( InjectedFieldModel field : fields )
+ {
+ if( !field.accept( modelVisitor ) )
+ {
+ break;
+ }
+ }
+ }
+ return modelVisitor.visitLeave( this );
+ }
+
+ public void inject( InjectionContext context, Object instance )
+ {
+ for( InjectedFieldModel field : fields )
+ {
+ field.inject( context, instance );
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectedMethodModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectedMethodModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectedMethodModel.java
new file mode 100644
index 0000000..b0ec660
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectedMethodModel.java
@@ -0,0 +1,86 @@
+/*
+ * 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.injection;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import org.apache.zest.api.composite.InjectedMethodDescriptor;
+import org.apache.zest.bootstrap.InjectionException;
+import org.apache.zest.functional.HierarchicalVisitor;
+import org.apache.zest.functional.VisitableHierarchy;
+
+/**
+ * JAVADOC
+ */
+public final class InjectedMethodModel
+ implements InjectedMethodDescriptor, Dependencies, VisitableHierarchy<Object, Object>
+{
+ // Model
+ private Method method;
+ private InjectedParametersModel parameters;
+
+ public InjectedMethodModel( Method method, InjectedParametersModel parameters )
+ {
+ this.method = method;
+ this.method.setAccessible( true );
+ this.parameters = parameters;
+ }
+
+ @Override
+ public Method method()
+ {
+ return method;
+ }
+
+ @Override
+ public Iterable<DependencyModel> dependencies()
+ {
+ return parameters.dependencies();
+ }
+
+ // Context
+ public void inject( InjectionContext context, Object instance )
+ throws InjectionException
+ {
+ Object[] params = parameters.newParametersInstance( context );
+ try
+ {
+ if( !method.isAccessible() )
+ {
+ method.setAccessible( true );
+ }
+ method.invoke( instance, params );
+ }
+ catch( IllegalAccessException e )
+ {
+ throw new InjectionException( e );
+ }
+ catch( InvocationTargetException e )
+ {
+ throw new InjectionException( e.getTargetException() );
+ }
+ }
+
+ @Override
+ public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> visitor )
+ throws ThrowableType
+ {
+ if( visitor.visitEnter( this ) )
+ {
+ parameters.accept( visitor );
+ }
+ return visitor.visitLeave( this );
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectedMethodsModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectedMethodsModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectedMethodsModel.java
new file mode 100644
index 0000000..82121a4
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectedMethodsModel.java
@@ -0,0 +1,124 @@
+/*
+ * 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.injection;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.zest.api.injection.InjectionScope;
+import org.apache.zest.api.util.Annotations;
+import org.apache.zest.api.util.Classes;
+import org.apache.zest.api.util.Methods;
+import org.apache.zest.functional.HierarchicalVisitor;
+import org.apache.zest.functional.Specifications;
+import org.apache.zest.functional.VisitableHierarchy;
+
+import static org.apache.zest.api.util.Annotations.hasAnnotation;
+import static org.apache.zest.functional.Iterables.filter;
+import static org.apache.zest.functional.Iterables.first;
+import static org.apache.zest.functional.Iterables.flattenIterables;
+import static org.apache.zest.functional.Iterables.iterable;
+import static org.apache.zest.functional.Iterables.map;
+
+/**
+ * JAVADOC
+ */
+public final class InjectedMethodsModel
+ implements Dependencies, VisitableHierarchy<Object, Object>
+{
+ // Model
+ private final List<InjectedMethodModel> methodModels = new ArrayList<InjectedMethodModel>();
+
+ public InjectedMethodsModel( Class fragmentClass )
+ {
+ nextMethod:
+ for( Method method : Methods.METHODS_OF.map( fragmentClass ) )
+ {
+ Annotation[][] parameterAnnotations = method.getParameterAnnotations();
+ if( parameterAnnotations.length > 0 )
+ {
+ InjectedParametersModel parametersModel = new InjectedParametersModel();
+ final Type[] genericParameterTypes = method.getGenericParameterTypes();
+ for( int i = 0; i < parameterAnnotations.length; i++ )
+ {
+ Annotation injectionAnnotation = first( filter( Specifications.translate( Annotations.type(), hasAnnotation( InjectionScope.class ) ), iterable( parameterAnnotations[ i ] ) ) );
+ if( injectionAnnotation == null )
+ {
+ continue nextMethod;
+ }
+
+ Type genericType = genericParameterTypes[ i ];
+ if( genericType instanceof ParameterizedType )
+ {
+ genericType = new ParameterizedTypeInstance( ( (ParameterizedType) genericType ).getActualTypeArguments(), ( (ParameterizedType) genericType )
+ .getRawType(), ( (ParameterizedType) genericType ).getOwnerType() );
+
+ for( int j = 0; j < ( (ParameterizedType) genericType ).getActualTypeArguments().length; j++ )
+ {
+ Type type = ( (ParameterizedType) genericType ).getActualTypeArguments()[ j ];
+ if( type instanceof TypeVariable )
+ {
+ type = Classes.resolveTypeVariable( (TypeVariable) type, method.getDeclaringClass(), fragmentClass );
+ ( (ParameterizedType) genericType ).getActualTypeArguments()[ j ] = type;
+ }
+ }
+ }
+
+ boolean optional = DependencyModel.isOptional( injectionAnnotation, parameterAnnotations[ i ] );
+ DependencyModel dependencyModel = new DependencyModel( injectionAnnotation, genericType, fragmentClass, optional, parameterAnnotations[ i ] );
+ parametersModel.addDependency( dependencyModel );
+ }
+ InjectedMethodModel methodModel = new InjectedMethodModel( method, parametersModel );
+ methodModels.add( methodModel );
+ }
+ }
+ }
+
+ @Override
+ public Iterable<DependencyModel> dependencies()
+ {
+ return flattenIterables( map( Dependencies.DEPENDENCIES_FUNCTION, methodModels ) );
+ }
+
+ // Context
+ public void inject( InjectionContext context, Object instance )
+ {
+ for( InjectedMethodModel methodModel : methodModels )
+ {
+ methodModel.inject( context, instance );
+ }
+ }
+
+ @Override
+ public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> visitor )
+ throws ThrowableType
+ {
+ if( visitor.visitEnter( this ) )
+ {
+ for( InjectedMethodModel methodModel : methodModels )
+ {
+ if( !methodModel.accept( visitor ) )
+ {
+ break;
+ }
+ }
+ }
+ return visitor.visitLeave( this );
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectedParametersModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectedParametersModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectedParametersModel.java
new file mode 100644
index 0000000..2bb8360
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectedParametersModel.java
@@ -0,0 +1,103 @@
+/*
+ * 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.injection;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.apache.zest.api.composite.InjectedParametersDescriptor;
+import org.apache.zest.functional.HierarchicalVisitor;
+import org.apache.zest.functional.Specification;
+import org.apache.zest.functional.VisitableHierarchy;
+
+/**
+ * JAVADOC
+ */
+public final class InjectedParametersModel
+ implements InjectedParametersDescriptor, Dependencies, VisitableHierarchy<Object, Object>
+{
+ private final List<DependencyModel> parameterDependencies;
+
+ public InjectedParametersModel()
+ {
+ parameterDependencies = new ArrayList<DependencyModel>();
+ }
+
+ @Override
+ public Iterable<DependencyModel> dependencies()
+ {
+ return parameterDependencies;
+ }
+
+ // Context
+ public Object[] newParametersInstance( InjectionContext context )
+ {
+ Object[] parametersInstance = new Object[ parameterDependencies.size() ];
+
+ // Inject parameterDependencies
+ for( int j = 0; j < parameterDependencies.size(); j++ )
+ {
+ DependencyModel dependencyModel = parameterDependencies.get( j );
+ Object parameter = dependencyModel.inject( context );
+ parametersInstance[ j ] = parameter;
+ }
+
+ return parametersInstance;
+ }
+
+ public void addDependency( DependencyModel dependency )
+ {
+ parameterDependencies.add( dependency );
+ }
+
+ @Override
+ public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> visitor )
+ throws ThrowableType
+ {
+ if( visitor.visitEnter( this ) )
+ {
+ for( DependencyModel parameterDependency : parameterDependencies )
+ {
+ if( !visitor.visit( parameterDependency ) )
+ {
+ break;
+ }
+ }
+ }
+ return visitor.visitLeave( this );
+ }
+
+ public Collection<DependencyModel> filter( Specification<DependencyModel> specification )
+ {
+ ArrayList<DependencyModel> result = new ArrayList<DependencyModel>();
+ for( DependencyModel model : parameterDependencies )
+ {
+ if( specification.satisfiedBy( model ) )
+ {
+ result.add( model );
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "InjectedParametersModel{" +
+ "parameterDependencies=" + parameterDependencies +
+ '}';
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectionContext.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectionContext.java b/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectionContext.java
new file mode 100644
index 0000000..f9cefac
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectionContext.java
@@ -0,0 +1,121 @@
+/*
+ * 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.injection;
+
+import org.apache.zest.api.composite.CompositeInstance;
+import org.apache.zest.api.property.StateHolder;
+import org.apache.zest.runtime.composite.ProxyReferenceInvocationHandler;
+import org.apache.zest.runtime.composite.UsesInstance;
+import org.apache.zest.runtime.structure.ModuleInstance;
+import org.apache.zest.spi.module.ModuleSpi;
+
+/**
+ * JAVADOC
+ */
+public final class InjectionContext
+{
+ private final ModuleSpi moduleInstance;
+ private CompositeInstance compositeInstance;
+ private UsesInstance uses;
+ private StateHolder state;
+ private Object next; // Only used for concerns and side-effects
+ private ProxyReferenceInvocationHandler proxyHandler;
+ private Object instance; // Only used for inner classes
+
+ // For mixins
+
+ public InjectionContext( CompositeInstance compositeInstance, UsesInstance uses, StateHolder state )
+ {
+ this.moduleInstance = (ModuleInstance) compositeInstance.module();
+ this.compositeInstance = compositeInstance;
+ this.uses = uses;
+ this.state = state;
+ }
+
+ // For concerns and side-effects
+ public InjectionContext( ModuleSpi moduleInstance, Object next, ProxyReferenceInvocationHandler proxyHandler )
+ {
+ this.moduleInstance = moduleInstance;
+ this.next = next;
+ this.proxyHandler = proxyHandler;
+ }
+
+ public InjectionContext( ModuleSpi moduleInstance, UsesInstance uses )
+ {
+ this.moduleInstance = moduleInstance;
+ this.uses = uses;
+ }
+
+ // For inner classes
+ public InjectionContext( ModuleSpi moduleInstance, UsesInstance uses, Object instance )
+ {
+ this.moduleInstance = moduleInstance;
+ this.uses = uses;
+ this.instance = instance;
+ }
+
+ public ModuleSpi module()
+ {
+ return moduleInstance;
+ }
+
+ public CompositeInstance compositeInstance()
+ {
+ return compositeInstance;
+ }
+
+ public UsesInstance uses()
+ {
+ return uses;
+ }
+
+ public StateHolder state()
+ {
+ return state;
+ }
+
+ public Object next()
+ {
+ return next;
+ }
+
+ public Object instance()
+ {
+ return instance;
+ }
+
+ public ProxyReferenceInvocationHandler proxyHandler()
+ {
+ return proxyHandler;
+ }
+
+ public void setUses( UsesInstance uses )
+ {
+ this.uses = uses;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "InjectionContext{" +
+ "compositeInstance=" + compositeInstance +
+ ", module=" + moduleInstance +
+ ", uses=" + uses +
+ ", state=" + state +
+ ", next=" + next +
+ ", proxyHandler=" + proxyHandler +
+ '}';
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectionProvider.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectionProvider.java b/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectionProvider.java
new file mode 100644
index 0000000..f69c24e
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectionProvider.java
@@ -0,0 +1,26 @@
+/*
+ * 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.injection;
+
+import org.apache.zest.runtime.injection.provider.InjectionProviderException;
+
+/**
+ * JAVADOC
+ */
+public interface InjectionProvider
+{
+ Object provideInjection( InjectionContext context )
+ throws InjectionProviderException;
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectionProviderFactory.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectionProviderFactory.java b/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectionProviderFactory.java
new file mode 100644
index 0000000..a993367
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/injection/InjectionProviderFactory.java
@@ -0,0 +1,37 @@
+/*
+ * 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.injection;
+
+import org.apache.zest.bootstrap.InvalidInjectionException;
+import org.apache.zest.runtime.model.Resolution;
+
+/**
+ * JAVADOC
+ */
+public interface InjectionProviderFactory
+{
+ /**
+ * Binding a dependency given an injection resolution. If no binding
+ * can be found, return null. If the dependency is optional the dependency will
+ * then be explicitly set to null.
+ *
+ * @param resolution Injection resolution
+ * @param dependencyModel Dependency model
+ * @return InjectionProvider
+ * @throws InvalidInjectionException if the injection is invalid
+ */
+ InjectionProvider newInjectionProvider( Resolution resolution, DependencyModel dependencyModel )
+ throws InvalidInjectionException;
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/injection/ParameterizedTypeInstance.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/injection/ParameterizedTypeInstance.java b/core/runtime/src/main/java/org/apache/zest/runtime/injection/ParameterizedTypeInstance.java
new file mode 100644
index 0000000..6a161b0
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/injection/ParameterizedTypeInstance.java
@@ -0,0 +1,65 @@
+/*
+ * 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.injection;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+
+/**
+ * TODO
+ */
+public class ParameterizedTypeInstance
+ implements ParameterizedType
+{
+ private Type[] actualTypeArguments;
+ private Type rawType;
+ private Type ownerType;
+
+ public ParameterizedTypeInstance( Type[] actualTypeArguments, Type rawType, Type ownerType )
+ {
+ this.actualTypeArguments = actualTypeArguments;
+ this.rawType = rawType;
+ this.ownerType = ownerType;
+ }
+
+ @Override
+ public Type[] getActualTypeArguments()
+ {
+ return actualTypeArguments;
+ }
+
+ @Override
+ public Type getRawType()
+ {
+ return rawType;
+ }
+
+ @Override
+ public Type getOwnerType()
+ {
+ return ownerType;
+ }
+
+ @Override
+ public String toString()
+ {
+ return rawType.toString() + Arrays.asList( actualTypeArguments );
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/CachingInjectionProviderDecorator.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/CachingInjectionProviderDecorator.java b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/CachingInjectionProviderDecorator.java
new file mode 100644
index 0000000..300e1d7
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/CachingInjectionProviderDecorator.java
@@ -0,0 +1,57 @@
+/*
+ * 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.injection.provider;
+
+import org.apache.zest.runtime.injection.InjectionContext;
+import org.apache.zest.runtime.injection.InjectionProvider;
+
+/**
+ * If a dependency resolution should be a singleton, wrap it with this
+ * to provide a single instance "cache".
+ */
+public final class CachingInjectionProviderDecorator
+ implements InjectionProvider
+{
+ private final InjectionProvider decoratedProvider;
+ private volatile Object singletonInstance;
+
+ public CachingInjectionProviderDecorator( InjectionProvider injectionProvider )
+ {
+ this.decoratedProvider = injectionProvider;
+ }
+
+ public InjectionProvider decoratedProvider()
+ {
+ return decoratedProvider;
+ }
+
+ @Override
+ public Object provideInjection( InjectionContext context )
+ throws InjectionProviderException
+ {
+ if( singletonInstance == null )
+ {
+ synchronized( this )
+ {
+ if( singletonInstance == null )
+ {
+ singletonInstance = decoratedProvider.provideInjection( context );
+ }
+ }
+ }
+
+ return singletonInstance;
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/CachingInjectionProviderFactoryDecorator.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/CachingInjectionProviderFactoryDecorator.java b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/CachingInjectionProviderFactoryDecorator.java
new file mode 100644
index 0000000..cdb4f5a
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/CachingInjectionProviderFactoryDecorator.java
@@ -0,0 +1,50 @@
+/*
+ * 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.injection.provider;
+
+import org.apache.zest.bootstrap.InvalidInjectionException;
+import org.apache.zest.runtime.injection.DependencyModel;
+import org.apache.zest.runtime.injection.InjectionProvider;
+import org.apache.zest.runtime.injection.InjectionProviderFactory;
+import org.apache.zest.runtime.model.Resolution;
+
+/**
+ * JAVADOC
+ */
+public class CachingInjectionProviderFactoryDecorator
+ implements InjectionProviderFactory
+{
+ private final InjectionProviderFactory decoratedFactory;
+
+ public CachingInjectionProviderFactoryDecorator( InjectionProviderFactory decoratedFactory )
+ {
+ this.decoratedFactory = decoratedFactory;
+ }
+
+ @Override
+ public InjectionProvider newInjectionProvider( Resolution resolution, DependencyModel dependencyModel )
+ throws InvalidInjectionException
+ {
+ InjectionProvider injectionProvider = decoratedFactory.newInjectionProvider( resolution, dependencyModel );
+ if( injectionProvider != null )
+ {
+ return new CachingInjectionProviderDecorator( injectionProvider );
+ }
+ else
+ {
+ return null;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/InjectionProviderException.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/InjectionProviderException.java b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/InjectionProviderException.java
new file mode 100644
index 0000000..abdae00
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/InjectionProviderException.java
@@ -0,0 +1,32 @@
+/*
+ * 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.injection.provider;
+
+/**
+ * JAVADOC
+ */
+public class InjectionProviderException
+ extends RuntimeException
+{
+ public InjectionProviderException( String string )
+ {
+ super( string );
+ }
+
+ public InjectionProviderException( String string, Throwable throwable )
+ {
+ super( string, throwable );
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/InjectionProviderFactoryStrategy.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/InjectionProviderFactoryStrategy.java b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/InjectionProviderFactoryStrategy.java
new file mode 100644
index 0000000..8d87bb9
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/InjectionProviderFactoryStrategy.java
@@ -0,0 +1,102 @@
+/*
+ * 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.injection.provider;
+
+import java.lang.annotation.Annotation;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.zest.api.common.MetaInfo;
+import org.apache.zest.api.composite.InvalidValueCompositeException;
+import org.apache.zest.api.composite.ModelDescriptor;
+import org.apache.zest.api.concern.internal.ConcernFor;
+import org.apache.zest.api.injection.scope.Invocation;
+import org.apache.zest.api.injection.scope.Service;
+import org.apache.zest.api.injection.scope.State;
+import org.apache.zest.api.injection.scope.Structure;
+import org.apache.zest.api.injection.scope.This;
+import org.apache.zest.api.injection.scope.Uses;
+import org.apache.zest.api.sideeffect.internal.SideEffectFor;
+import org.apache.zest.api.value.ValueComposite;
+import org.apache.zest.bootstrap.InvalidInjectionException;
+import org.apache.zest.runtime.injection.DependencyModel;
+import org.apache.zest.runtime.injection.InjectionProvider;
+import org.apache.zest.runtime.injection.InjectionProviderFactory;
+import org.apache.zest.runtime.model.Resolution;
+
+import static org.apache.zest.functional.Iterables.first;
+
+/**
+ * JAVADOC
+ */
+public final class InjectionProviderFactoryStrategy
+ implements InjectionProviderFactory
+{
+ private final Map<Class<? extends Annotation>, InjectionProviderFactory> generalProviderFactories = new HashMap<Class<? extends Annotation>, InjectionProviderFactory>();
+ private final Map<Class<? extends Annotation>, InjectionProviderFactory> valuesProviderFactories = new HashMap<Class<? extends Annotation>, InjectionProviderFactory>();
+ private MetaInfo metaInfo;
+
+ public InjectionProviderFactoryStrategy( MetaInfo metaInfo )
+ {
+ this.metaInfo = metaInfo;
+ valuesProviderFactories.put( This.class, new ThisInjectionProviderFactory() );
+ ModifiesInjectionProviderFactory modifiesInjectionProviderFactory = new ModifiesInjectionProviderFactory();
+ valuesProviderFactories.put( ConcernFor.class, modifiesInjectionProviderFactory );
+ valuesProviderFactories.put( SideEffectFor.class, modifiesInjectionProviderFactory );
+ valuesProviderFactories.put( State.class, new StateInjectionProviderFactory() );
+
+ valuesProviderFactories.put( Structure.class, new CachingInjectionProviderFactoryDecorator( new StructureInjectionProviderFactory() ) );
+ valuesProviderFactories.put( Service.class, new CachingInjectionProviderFactoryDecorator( new ServiceInjectionProviderFactory() ) );
+ generalProviderFactories.put( Invocation.class, new InvocationInjectionProviderFactory() );
+ generalProviderFactories.put( Uses.class, new UsesInjectionProviderFactory() );
+ }
+
+ @Override
+ public InjectionProvider newInjectionProvider( Resolution resolution, DependencyModel dependencyModel )
+ throws InvalidInjectionException
+ {
+ Class<? extends Annotation> injectionAnnotationType = dependencyModel.injectionAnnotation().annotationType();
+ InjectionProviderFactory factory1 = generalProviderFactories.get( injectionAnnotationType );
+ InjectionProviderFactory factory2 = valuesProviderFactories.get( injectionAnnotationType );
+ if( factory1 == null && factory2 == null )
+ {
+ InjectionProviderFactory factory = metaInfo.get( InjectionProviderFactory.class );
+ if( factory != null )
+ {
+ return factory.newInjectionProvider( resolution, dependencyModel );
+ }
+ else
+ {
+ throw new InvalidInjectionException( "Unknown injection annotation @" + injectionAnnotationType.getSimpleName() );
+ }
+ }
+ ModelDescriptor composite = resolution.model();
+ Class<?> compositeType = first( composite.types() );
+ if( factory1 != null && ValueComposite.class.isAssignableFrom( compositeType ) )
+ {
+ throw new InvalidValueCompositeException( "@" + injectionAnnotationType.getSimpleName() + " is not allowed in ValueComposites: " + compositeType );
+ }
+
+ InjectionProviderFactory factory;
+ if( factory1 == null )
+ {
+ factory = factory2;
+ }
+ else
+ {
+ factory = factory1;
+ }
+ return factory.newInjectionProvider( resolution, dependencyModel );
+ }
+}