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} -&gt; MyService
+     * <p>
+     * {@code @Entity Iterable<Foo> fooList} -&gt; Iterable
+     * <p>
+     * {@code @Entity Query<Foo> fooQuery} -&gt; 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 );
+    }
+}