polygene-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From nic...@apache.org
Subject [10/80] [partial] zest-java git commit: First round of changes to move to org.apache.zest namespace.
Date Thu, 30 Jul 2015 19:48:09 GMT
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/InvocationInjectionProviderFactory.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/InvocationInjectionProviderFactory.java b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/InvocationInjectionProviderFactory.java
new file mode 100644
index 0000000..d7348ff
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/InvocationInjectionProviderFactory.java
@@ -0,0 +1,117 @@
+/*
+ * 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.provider;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import org.apache.zest.api.util.Classes;
+import org.apache.zest.bootstrap.InvalidInjectionException;
+import org.apache.zest.runtime.composite.CompositeMethodModel;
+import org.apache.zest.runtime.injection.DependencyModel;
+import org.apache.zest.runtime.injection.InjectionContext;
+import org.apache.zest.runtime.injection.InjectionProvider;
+import org.apache.zest.runtime.injection.InjectionProviderFactory;
+import org.apache.zest.runtime.model.Resolution;
+
+/**
+ * JAVADOC
+ */
+public final class InvocationInjectionProviderFactory
+    implements InjectionProviderFactory
+{
+    @Override
+    @SuppressWarnings( "raw" )
+    public InjectionProvider newInjectionProvider( Resolution resolution, DependencyModel dependencyModel )
+        throws InvalidInjectionException
+    {
+        Class injectionClass = Classes.RAW_CLASS.map( dependencyModel.injectionType() );
+        if( injectionClass.equals( Method.class ) ||
+            injectionClass.equals( AnnotatedElement.class ) ||
+            injectionClass.equals( Iterable.class ) ||
+            Annotation.class.isAssignableFrom( injectionClass ) )
+        {
+            return new InvocationDependencyResolution( resolution, dependencyModel );
+        }
+        else
+        {
+            String injectedTo = dependencyModel.injectedClass().getName();
+            throw new InvalidInjectionException( "Invalid injection type " + injectionClass + " in " + injectedTo );
+        }
+    }
+
+    private static class InvocationDependencyResolution
+        implements InjectionProvider
+    {
+        private final Resolution resolution;
+        private final DependencyModel dependencyModel;
+
+        private InvocationDependencyResolution( Resolution resolution, DependencyModel dependencyModel )
+        {
+            this.resolution = resolution;
+            this.dependencyModel = dependencyModel;
+        }
+
+        @Override
+        @SuppressWarnings( {"raw", "unchecked"} )
+        public Object provideInjection( InjectionContext context )
+            throws InjectionProviderException
+        {
+            Class injectionClass = Classes.RAW_CLASS.map( dependencyModel.injectionType() );
+            final CompositeMethodModel methodModel = resolution.method();
+            if( injectionClass.equals( Method.class ) )
+            {
+                return methodModel.method();
+            }
+
+            final AnnotatedElement annotatedElement = methodModel.annotatedElement();
+            if( injectionClass.equals( AnnotatedElement.class ) )
+            {
+                return annotatedElement;
+            }
+            final Annotation annotation = annotatedElement.getAnnotation( injectionClass );
+            if( annotation != null )
+            {
+                return annotation;
+            }
+            if( dependencyModel.injectionType() instanceof Class<?> )
+            {
+                return annotatedElement.getAnnotation( (Class<Annotation>) dependencyModel.injectionType() );
+            }
+            if( dependencyModel.injectionType() instanceof ParameterizedType )
+            {
+                ParameterizedType injectionType = (ParameterizedType) dependencyModel.injectionType();
+                Type rawType = injectionType.getRawType();
+                Type[] actualTypeArguments = injectionType.getActualTypeArguments();
+                boolean isAnIterable = rawType.equals( Iterable.class );
+                boolean haveOneGenericType = actualTypeArguments.length == 1;
+                boolean thatIsOfTypeMethod = actualTypeArguments[ 0 ].equals( Method.class );
+                if( isAnIterable && haveOneGenericType && thatIsOfTypeMethod )
+                {
+                    Class<?> injectedClass = dependencyModel.injectedClass();
+                    Iterable<Method> result = methodModel.invocationsFor( injectedClass );
+                    return result;
+                }
+            }
+            return null;
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/ModifiesInjectionProviderFactory.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/ModifiesInjectionProviderFactory.java b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/ModifiesInjectionProviderFactory.java
new file mode 100644
index 0000000..fedb010
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/ModifiesInjectionProviderFactory.java
@@ -0,0 +1,70 @@
+/*
+ * 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.provider;
+
+import org.apache.zest.api.composite.CompositeDescriptor;
+import org.apache.zest.api.util.Classes;
+import org.apache.zest.bootstrap.InvalidInjectionException;
+import org.apache.zest.runtime.injection.DependencyModel;
+import org.apache.zest.runtime.injection.InjectionContext;
+import org.apache.zest.runtime.injection.InjectionProvider;
+import org.apache.zest.runtime.injection.InjectionProviderFactory;
+import org.apache.zest.runtime.model.Resolution;
+
+/**
+ * JAVADOC
+ */
+public final class ModifiesInjectionProviderFactory
+    implements InjectionProviderFactory
+{
+    @Override
+    public InjectionProvider newInjectionProvider( Resolution bindingContext, DependencyModel dependencyModel )
+        throws InvalidInjectionException
+    {
+        if( bindingContext.model() instanceof CompositeDescriptor )
+        {
+            Class<?> type = Classes.RAW_CLASS.map( dependencyModel.injectionType() );
+            if( type.isAssignableFrom( dependencyModel.injectedClass() ) )
+            {
+                return new ModifiedInjectionProvider();
+            }
+            else
+            {
+                throw new InvalidInjectionException( "Composite " + bindingContext.model() + " does not implement @ConcernFor type " + type
+                    .getName() + " in modifier " + dependencyModel.injectedClass().getName() );
+            }
+        }
+        else
+        {
+            throw new InvalidInjectionException( "The class " + dependencyModel.injectedClass()
+                .getName() + " is not a modifier" );
+        }
+    }
+
+    private static class ModifiedInjectionProvider
+        implements InjectionProvider
+    {
+        @Override
+        public Object provideInjection( InjectionContext context )
+            throws InjectionProviderException
+        {
+            return context.next();
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/ServiceInjectionProviderFactory.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/ServiceInjectionProviderFactory.java b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/ServiceInjectionProviderFactory.java
new file mode 100644
index 0000000..4c5bb26
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/ServiceInjectionProviderFactory.java
@@ -0,0 +1,225 @@
+/*
+ * 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.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import org.apache.zest.api.service.NoSuchServiceException;
+import org.apache.zest.api.service.ServiceReference;
+import org.apache.zest.api.service.qualifier.Qualifier;
+import org.apache.zest.api.util.Annotations;
+import org.apache.zest.api.util.Classes;
+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.Specifications;
+import org.apache.zest.runtime.injection.DependencyModel;
+import org.apache.zest.runtime.injection.InjectionContext;
+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.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.iterable;
+
+public final class ServiceInjectionProviderFactory
+    implements InjectionProviderFactory
+{
+    @Override
+    @SuppressWarnings( "unchecked" )
+    public InjectionProvider newInjectionProvider( Resolution resolution, DependencyModel dependencyModel )
+        throws InvalidInjectionException
+    {
+        // TODO This could be changed to allow multiple @Qualifier annotations
+        Annotation qualifierAnnotation = first( filter( Specifications.translate( Annotations.type(), hasAnnotation( Qualifier.class ) ), iterable( dependencyModel
+                                                                                                                                                        .annotations() ) ) );
+        Specification<ServiceReference<?>> serviceQualifier = null;
+        if( qualifierAnnotation != null )
+        {
+            Qualifier qualifier = qualifierAnnotation.annotationType().getAnnotation( Qualifier.class );
+            try
+            {
+                serviceQualifier = qualifier.value().newInstance().qualifier( qualifierAnnotation );
+            }
+            catch( Exception e )
+            {
+                throw new InvalidInjectionException( "Could not instantiate qualifier serviceQualifier", e );
+            }
+        }
+
+        if( dependencyModel.rawInjectionType().equals( Iterable.class ) )
+        {
+            Type iterableType = ( (ParameterizedType) dependencyModel.injectionType() ).getActualTypeArguments()[ 0 ];
+            if( Classes.RAW_CLASS.map( iterableType ).equals( ServiceReference.class ) )
+            {
+                // @Service Iterable<ServiceReference<MyService<Foo>> serviceRefs
+                Type serviceType = ( (ParameterizedType) iterableType ).getActualTypeArguments()[ 0 ];
+
+                return new IterableServiceReferenceProvider( serviceType, serviceQualifier );
+            }
+            else
+            {
+                // @Service Iterable<MyService<Foo>> services
+                return new IterableServiceProvider( iterableType, serviceQualifier );
+            }
+        }
+        else if( dependencyModel.rawInjectionType().equals( ServiceReference.class ) )
+        {
+            // @Service ServiceReference<MyService<Foo>> serviceRef
+            Type referencedType = ( (ParameterizedType) dependencyModel.injectionType() ).getActualTypeArguments()[ 0 ];
+            return new ServiceReferenceProvider( referencedType, serviceQualifier );
+        }
+        else
+        {
+            // @Service MyService<Foo> service
+            return new ServiceProvider( dependencyModel.injectionType(), serviceQualifier );
+        }
+    }
+
+    private static class IterableServiceReferenceProvider
+        extends ServiceInjectionProvider
+    {
+        private IterableServiceReferenceProvider( Type serviceType,
+                                                  Specification<ServiceReference<?>> serviceQualifier
+        )
+        {
+            super( serviceType, serviceQualifier );
+        }
+
+        @Override
+        public synchronized Object provideInjection( InjectionContext context )
+            throws InjectionProviderException
+        {
+            return getServiceReferences( context );
+        }
+    }
+
+    private static class IterableServiceProvider
+        extends ServiceInjectionProvider
+        implements Function<ServiceReference<?>, Object>
+    {
+        private IterableServiceProvider( Type serviceType,
+                                         Specification<ServiceReference<?>> serviceQualifier
+        )
+        {
+            super( serviceType, serviceQualifier );
+        }
+
+        @Override
+        public synchronized Object provideInjection( final InjectionContext context )
+            throws InjectionProviderException
+        {
+            return Iterables.map( this, getServiceReferences( context ) );
+        }
+
+        @Override
+        public Object map( ServiceReference<?> objectServiceReference )
+        {
+            return objectServiceReference.get();
+        }
+    }
+
+    private static class ServiceReferenceProvider
+        extends ServiceInjectionProvider
+    {
+        ServiceReferenceProvider( Type serviceType, Specification<ServiceReference<?>> qualifier )
+        {
+            super( serviceType, qualifier );
+        }
+
+        @Override
+        public synchronized Object provideInjection( InjectionContext context )
+            throws InjectionProviderException
+        {
+            return getServiceReference( context );
+        }
+    }
+
+    private static class ServiceProvider
+        extends ServiceInjectionProvider
+    {
+        ServiceProvider( Type serviceType, Specification<ServiceReference<?>> qualifier )
+        {
+            super( serviceType, qualifier );
+        }
+
+        @Override
+        public synchronized Object provideInjection( InjectionContext context )
+            throws InjectionProviderException
+        {
+            ServiceReference<?> ref = getServiceReference( context );
+
+            if( ref != null )
+            {
+                return ref.get();
+            }
+            else
+            {
+                return null;
+            }
+        }
+    }
+
+    private abstract static class ServiceInjectionProvider
+        implements InjectionProvider
+    {
+        private final Type serviceType;
+        private final Specification<ServiceReference<?>> serviceQualifier;
+
+        private ServiceInjectionProvider( Type serviceType,
+                                            Specification<ServiceReference<?>> serviceQualifier
+        )
+        {
+            this.serviceType = serviceType;
+            this.serviceQualifier = serviceQualifier;
+        }
+
+        protected ServiceReference<Object> getServiceReference( InjectionContext context )
+        {
+            try
+            {
+                if( serviceQualifier == null )
+                {
+                    return context.module().findService( serviceType );
+                }
+                else
+                {
+                    return Iterables.first( Iterables.filter( serviceQualifier, context.module()
+                        .findServices( serviceType ) ) );
+                }
+            }
+            catch( NoSuchServiceException e )
+            {
+                return null;
+            }
+        }
+
+        protected Iterable<ServiceReference<Object>> getServiceReferences( final InjectionContext context )
+        {
+            if( serviceQualifier == null )
+            {
+                return context.module().findServices( serviceType );
+            }
+            else
+            {
+                return Iterables.filter( serviceQualifier, context.module().findServices( serviceType ) );
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/StateInjectionProviderFactory.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/StateInjectionProviderFactory.java b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/StateInjectionProviderFactory.java
new file mode 100644
index 0000000..8d0bcc7
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/StateInjectionProviderFactory.java
@@ -0,0 +1,273 @@
+/*
+ * 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.injection.provider;
+
+import org.apache.zest.api.association.AbstractAssociation;
+import org.apache.zest.api.association.Association;
+import org.apache.zest.api.association.AssociationDescriptor;
+import org.apache.zest.api.association.AssociationStateDescriptor;
+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.composite.StateDescriptor;
+import org.apache.zest.api.composite.StatefulCompositeDescriptor;
+import org.apache.zest.api.entity.EntityDescriptor;
+import org.apache.zest.api.injection.scope.State;
+import org.apache.zest.api.property.Property;
+import org.apache.zest.api.property.PropertyDescriptor;
+import org.apache.zest.api.property.StateHolder;
+import org.apache.zest.api.unitofwork.UnitOfWork;
+import org.apache.zest.bootstrap.InvalidInjectionException;
+import org.apache.zest.runtime.entity.EntityInstance;
+import org.apache.zest.runtime.injection.DependencyModel;
+import org.apache.zest.runtime.injection.InjectionContext;
+import org.apache.zest.runtime.injection.InjectionProvider;
+import org.apache.zest.runtime.injection.InjectionProviderFactory;
+import org.apache.zest.runtime.model.Resolution;
+
+/**
+ * JAVADOC
+ */
+public final class StateInjectionProviderFactory
+    implements InjectionProviderFactory
+{
+    @Override
+    public InjectionProvider newInjectionProvider( Resolution resolution, DependencyModel dependencyModel )
+        throws InvalidInjectionException
+    {
+        if( StateHolder.class.isAssignableFrom( dependencyModel.rawInjectionType() ) )
+        {
+            // @State StateHolder properties;
+            return new StateInjectionProvider();
+        }
+        else if( UnitOfWork.class.isAssignableFrom( dependencyModel.rawInjectionType() ) )
+        {
+            if( !( resolution.model() instanceof EntityDescriptor ) )
+            {
+                throw new InvalidInjectionException( "Only EntityComposites can be injected with '@State UnitOfWork'" );
+            }
+            return new UnitOfWorkInjectionProvider();
+        }
+        else if( Property.class.isAssignableFrom( dependencyModel.rawInjectionType() ) )
+        {
+            // @State Property<String> name;
+            StateDescriptor descriptor;
+            descriptor = ( (StatefulCompositeDescriptor) resolution.model() ).state();
+
+            State annotation = (State) dependencyModel.injectionAnnotation();
+            String name;
+            if( annotation.value().isEmpty() )
+            {
+                name = resolution.field().getName();
+            }
+            else
+            {
+                name = annotation.value();
+            }
+
+            PropertyDescriptor propertyDescriptor = descriptor.findPropertyModelByName( name );
+            return new PropertyInjectionProvider( propertyDescriptor );
+        }
+        else if( Association.class.isAssignableFrom( dependencyModel.rawInjectionType() ) )
+        {
+            // @State Association<MyEntity> name;
+            AssociationStateDescriptor descriptor = ( (EntityDescriptor) resolution.model() ).state();
+            State annotation = (State) dependencyModel.injectionAnnotation();
+            String name;
+            if( annotation.value().isEmpty() )
+            {
+                name = resolution.field().getName();
+            }
+            else
+            {
+                name = annotation.value();
+            }
+            AssociationDescriptor model = descriptor.getAssociationByName( name );
+            return new AssociationInjectionProvider( model );
+        }
+        else if( ManyAssociation.class.isAssignableFrom( dependencyModel.rawInjectionType() ) )
+        {
+            // @State ManyAssociation<MyEntity> name;
+            AssociationStateDescriptor descriptor = ( (EntityDescriptor) resolution.model() ).state();
+            State annotation = (State) dependencyModel.injectionAnnotation();
+            String name;
+            if( annotation.value().isEmpty() )
+            {
+                name = resolution.field().getName();
+            }
+            else
+            {
+                name = annotation.value();
+            }
+            AssociationDescriptor model = descriptor.getManyAssociationByName( name );
+            return new ManyAssociationInjectionProvider( model );
+        }
+        else if( NamedAssociation.class.isAssignableFrom( dependencyModel.rawInjectionType() ) )
+        {
+            // @State NamedAssociation<MyEntity> name;
+            AssociationStateDescriptor descriptor = ( (EntityDescriptor) resolution.model() ).state();
+            State annotation = (State) dependencyModel.injectionAnnotation();
+            String name;
+            if( annotation.value().isEmpty() )
+            {
+                name = resolution.field().getName();
+            }
+            else
+            {
+                name = annotation.value();
+            }
+            AssociationDescriptor model = descriptor.getNamedAssociationByName( name );
+            return new NamedAssociationInjectionProvider( model );
+        }
+
+        throw new InjectionProviderException( "Injected value has invalid type" );
+    }
+
+    private static class PropertyInjectionProvider
+        implements InjectionProvider
+    {
+        private final PropertyDescriptor propertyDescriptor;
+
+        private PropertyInjectionProvider( PropertyDescriptor propertyDescriptor )
+        {
+            this.propertyDescriptor = propertyDescriptor;
+        }
+
+        @Override
+        public Object provideInjection( InjectionContext context )
+            throws InjectionProviderException
+        {
+            Property<?> value = context.state().propertyFor( propertyDescriptor.accessor() );
+            if( value != null )
+            {
+                return value;
+            }
+            else
+            {
+                throw new InjectionProviderException( "Non-optional property " + propertyDescriptor + " had no value" );
+            }
+        }
+    }
+
+    private static class AssociationInjectionProvider
+        implements InjectionProvider
+    {
+        private final AssociationDescriptor associationDescriptor;
+
+        private AssociationInjectionProvider( AssociationDescriptor associationDescriptor )
+        {
+            this.associationDescriptor = associationDescriptor;
+        }
+
+        @Override
+        public Object provideInjection( InjectionContext context )
+            throws InjectionProviderException
+        {
+            AbstractAssociation abstractAssociation = ( (AssociationStateHolder) context.state() ).
+                associationFor( associationDescriptor.accessor() );
+            if( abstractAssociation != null )
+            {
+                return abstractAssociation;
+            }
+            else
+            {
+                throw new InjectionProviderException( "Non-optional association " + associationDescriptor.qualifiedName() + " had no association" );
+            }
+        }
+    }
+
+    private static class ManyAssociationInjectionProvider
+        implements InjectionProvider
+    {
+        private final AssociationDescriptor manyAssociationDescriptor;
+
+        private ManyAssociationInjectionProvider( AssociationDescriptor manyAssociationDescriptor )
+        {
+            this.manyAssociationDescriptor = manyAssociationDescriptor;
+        }
+
+        @Override
+        public Object provideInjection( InjectionContext context )
+            throws InjectionProviderException
+        {
+            ManyAssociation<?> abstractAssociation = ( (AssociationStateHolder) context.state() ).
+                manyAssociationFor( manyAssociationDescriptor.accessor() );
+            if( abstractAssociation != null )
+            {
+                return abstractAssociation;
+            }
+            else
+            {
+                throw new InjectionProviderException( "Non-optional association " + manyAssociationDescriptor.qualifiedName() + " had no association" );
+            }
+        }
+    }
+
+    private static class NamedAssociationInjectionProvider
+        implements InjectionProvider
+    {
+        private final AssociationDescriptor namedAssociationDescriptor;
+
+        private NamedAssociationInjectionProvider( AssociationDescriptor namedAssociationDescriptor )
+        {
+            this.namedAssociationDescriptor = namedAssociationDescriptor;
+        }
+
+        @Override
+        public Object provideInjection( InjectionContext context )
+            throws InjectionProviderException
+        {
+            NamedAssociation<?> abstractAssociation = ( (AssociationStateHolder) context.state() ).
+                namedAssociationFor( namedAssociationDescriptor.accessor() );
+            if( abstractAssociation != null )
+            {
+                return abstractAssociation;
+            }
+            else
+            {
+                throw new InjectionProviderException( "Non-optional association " + namedAssociationDescriptor.qualifiedName() + " had no association" );
+            }
+        }
+    }
+
+    static private class StateInjectionProvider
+        implements InjectionProvider
+    {
+        @Override
+        public Object provideInjection( InjectionContext context )
+            throws InjectionProviderException
+        {
+            return context.state();
+        }
+    }
+
+    static private class UnitOfWorkInjectionProvider
+        implements InjectionProvider
+    {
+
+        @Override
+        public Object provideInjection( InjectionContext context )
+            throws InjectionProviderException
+        {
+            return ( (EntityInstance) context.compositeInstance() ).unitOfWork();
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/StructureInjectionProviderFactory.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/StructureInjectionProviderFactory.java b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/StructureInjectionProviderFactory.java
new file mode 100644
index 0000000..7ee3db0
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/StructureInjectionProviderFactory.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2007, 2008 Niclas Hedhman.
+ *
+ * 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.reflect.Type;
+import org.apache.zest.api.Qi4j;
+import org.apache.zest.api.composite.TransientBuilderFactory;
+import org.apache.zest.api.object.ObjectFactory;
+import org.apache.zest.api.query.QueryBuilderFactory;
+import org.apache.zest.api.service.ServiceFinder;
+import org.apache.zest.api.structure.Application;
+import org.apache.zest.api.structure.Layer;
+import org.apache.zest.api.structure.Module;
+import org.apache.zest.api.unitofwork.UnitOfWorkFactory;
+import org.apache.zest.api.value.ValueBuilderFactory;
+import org.apache.zest.bootstrap.InvalidInjectionException;
+import org.apache.zest.runtime.injection.DependencyModel;
+import org.apache.zest.runtime.injection.InjectionContext;
+import org.apache.zest.runtime.injection.InjectionProvider;
+import org.apache.zest.runtime.injection.InjectionProviderFactory;
+import org.apache.zest.runtime.model.Resolution;
+import org.apache.zest.runtime.structure.ModuleInstance;
+import org.apache.zest.spi.module.ModuleSpi;
+
+public final class StructureInjectionProviderFactory
+    implements InjectionProviderFactory
+{
+    @Override
+    public InjectionProvider newInjectionProvider( Resolution resolution, DependencyModel dependencyModel )
+        throws InvalidInjectionException
+    {
+        return new StructureInjectionProvider( dependencyModel );
+    }
+
+    private static class StructureInjectionProvider
+        implements InjectionProvider
+    {
+        private final DependencyModel dependencyModel;
+
+        private StructureInjectionProvider( DependencyModel dependencyModel )
+        {
+            this.dependencyModel = dependencyModel;
+        }
+
+        @Override
+        public Object provideInjection( InjectionContext context )
+            throws InjectionProviderException
+        {
+            Type type1 = dependencyModel.injectionType();
+            if( !( type1 instanceof Class ) )
+            {
+                throw new InjectionProviderException( "Type [" + type1 + "] can not be injected from the @Structure injection scope: " + context );
+            }
+            Class clazz = (Class) type1;
+            if( clazz.equals( TransientBuilderFactory.class ) )
+            {
+                return context.module();
+            }
+            else if( clazz.equals( ObjectFactory.class ) )
+            {
+                return context.module();
+            }
+            else if( clazz.equals( ValueBuilderFactory.class ) )
+            {
+                return context.module();
+            }
+            else if( clazz.equals( UnitOfWorkFactory.class ) )
+            {
+                return context.module();
+            }
+            else if( clazz.equals( QueryBuilderFactory.class ) )
+            {
+                return context.module();
+            }
+            else if( clazz.equals( ServiceFinder.class ) )
+            {
+                return context.module();
+            }
+            else if( Module.class.isAssignableFrom( clazz ) )
+            {
+                return context.module();
+            }
+            else if( ModuleSpi.class.isAssignableFrom( clazz ) )
+            {
+                return context.module();
+            }
+            else if( Layer.class.isAssignableFrom( clazz ) )
+            {
+                return (( ModuleInstance) context.module()).layerInstance();
+            }
+            else if( Application.class.isAssignableFrom( clazz ) )
+            {
+                return (( ModuleInstance) context.module()).layerInstance().applicationInstance();
+            }
+            else if( Qi4j.class.isAssignableFrom( clazz ) )
+            {
+                return (( ModuleInstance) context.module()).layerInstance().applicationInstance().runtime();
+            }
+
+            return null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/ThisInjectionProviderFactory.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/ThisInjectionProviderFactory.java b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/ThisInjectionProviderFactory.java
new file mode 100644
index 0000000..a7b53eb
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/ThisInjectionProviderFactory.java
@@ -0,0 +1,138 @@
+/*
+ * 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.provider;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Proxy;
+import org.apache.zest.api.composite.CompositeDescriptor;
+import org.apache.zest.api.util.Classes;
+import org.apache.zest.bootstrap.InvalidInjectionException;
+import org.apache.zest.functional.Iterables;
+import org.apache.zest.runtime.composite.ProxyGenerator;
+import org.apache.zest.runtime.injection.DependencyModel;
+import org.apache.zest.runtime.injection.InjectionContext;
+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;
+import static org.apache.zest.functional.Iterables.iterable;
+
+/**
+ * JAVADOC
+ */
+public final class ThisInjectionProviderFactory
+    implements InjectionProviderFactory
+{
+    @Override
+    @SuppressWarnings( "unchecked" )
+    public InjectionProvider newInjectionProvider( Resolution bindingContext, DependencyModel dependencyModel )
+        throws InvalidInjectionException
+    {
+        if( bindingContext.model() instanceof CompositeDescriptor )
+        {
+            // If Composite type then return real type, otherwise use the specified one
+            final Class<?> thisType = dependencyModel.rawInjectionType();
+
+            Iterable<Class<?>> injectionTypes = null;
+            if( Classes.assignableTypeSpecification( thisType ).satisfiedBy( bindingContext.model() ) )
+            {
+                injectionTypes = bindingContext.model().types();
+            }
+            else
+            {
+                CompositeDescriptor acd = ( (CompositeDescriptor) bindingContext.model() );
+                for( Class<?> mixinType : acd.mixinTypes() )
+                {
+                    if( thisType.isAssignableFrom( mixinType ) )
+                    {
+                        Iterable<? extends Class<?>> iterable = iterable( thisType );
+                        injectionTypes = (Iterable<Class<?>>) iterable;
+                        break;
+                    }
+                }
+
+                if( injectionTypes == null )
+                {
+                    throw new InvalidInjectionException( "Composite " + bindingContext.model()
+                                                         + " does not implement @This type " + thisType.getName() + " in fragment "
+                                                         + dependencyModel.injectedClass().getName() );
+                }
+            }
+
+            return new ThisInjectionProvider( injectionTypes );
+        }
+        else
+        {
+            throw new InvalidInjectionException( "Object " + dependencyModel.injectedClass() + " may not use @This" );
+        }
+    }
+
+    @SuppressWarnings( {"raw", "unchecked"} )
+    private static class ThisInjectionProvider
+        implements InjectionProvider
+    {
+        Constructor proxyConstructor;
+        private Class[] interfaces;
+
+        private ThisInjectionProvider( Iterable<Class<?>> types )
+        {
+            try
+            {
+                Class proxyClass;
+                if( Proxy.class.isAssignableFrom( first( types ) ) )
+                {
+                    proxyClass = first( types );
+                }
+                else
+                {
+                    Class<?> mainType = first( types );
+                    interfaces = Iterables.toArray( Class.class, Iterables.<Class>cast( types ) );
+                    proxyClass = ProxyGenerator.createProxyClass(mainType.getClassLoader(), interfaces);
+                }
+
+                proxyConstructor = proxyClass.getConstructor( InvocationHandler.class );
+            }
+            catch( Exception e )
+            {
+                // Ignore
+                e.printStackTrace();
+            }
+        }
+
+        @Override
+        public Object provideInjection( InjectionContext context )
+        {
+            try
+            {
+                InvocationHandler handler = context.compositeInstance();
+                if( handler == null )
+                {
+                    handler = context.proxyHandler();
+                }
+                return proxyConstructor.newInstance( handler );
+            }
+            catch( Exception e )
+            {
+                throw new InjectionProviderException( "Could not instantiate @This proxy", e );
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/UsesInjectionProviderFactory.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/UsesInjectionProviderFactory.java b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/UsesInjectionProviderFactory.java
new file mode 100644
index 0000000..0e5ed5a
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/UsesInjectionProviderFactory.java
@@ -0,0 +1,131 @@
+/*
+ * 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.provider;
+
+import java.lang.reflect.Constructor;
+import org.apache.zest.api.composite.NoSuchTransientException;
+import org.apache.zest.api.object.NoSuchObjectException;
+import org.apache.zest.api.structure.Module;
+import org.apache.zest.bootstrap.InvalidInjectionException;
+import org.apache.zest.runtime.composite.UsesInstance;
+import org.apache.zest.runtime.injection.DependencyModel;
+import org.apache.zest.runtime.injection.InjectionContext;
+import org.apache.zest.runtime.injection.InjectionProvider;
+import org.apache.zest.runtime.injection.InjectionProviderFactory;
+import org.apache.zest.runtime.model.Resolution;
+
+/**
+ * JAVADOC
+ */
+public final class UsesInjectionProviderFactory
+    implements InjectionProviderFactory
+{
+    public UsesInjectionProviderFactory()
+    {
+    }
+
+    @Override
+    public InjectionProvider newInjectionProvider( Resolution resolution, DependencyModel dependencyModel )
+        throws InvalidInjectionException
+    {
+        return new UsesInjectionProvider( dependencyModel );
+    }
+
+    private static class UsesInjectionProvider
+        implements InjectionProvider
+    {
+        private final DependencyModel dependency;
+
+        public UsesInjectionProvider( DependencyModel dependency )
+        {
+            this.dependency = dependency;
+        }
+
+        @SuppressWarnings( "unchecked" )
+        @Override
+        public Object provideInjection( InjectionContext context )
+            throws InjectionProviderException
+        {
+            UsesInstance uses = context.uses();
+
+            Class injectionType = dependency.rawInjectionType();
+            Object usesObject = uses.useForType( injectionType );
+
+            if( usesObject == null && !dependency.optional() )
+            {
+                // No @Uses object provided
+                // Try instantiating a Transient or Object for the given type
+                Module moduleInstance = context.module();
+
+                try
+                {
+                    if( context.instance() != null )
+                    {
+                        uses = uses.use( context.instance() );
+                    }
+                    usesObject = moduleInstance.newTransient( injectionType, uses.toArray() );
+                }
+                catch( NoSuchTransientException e )
+                {
+                    try
+                    {
+                        usesObject = moduleInstance.newObject( injectionType, uses.toArray() );
+                    }
+                    catch( NoSuchObjectException e1 )
+                    {
+                        // Could not instantiate an instance - to try instantiate as plain class
+                        try
+                        {
+                            usesObject = injectionType.newInstance();
+                        }
+                        catch( Throwable e2 )
+                        {
+                            // Could not instantiate - try with this as first argument
+                            try
+                            {
+                                Constructor constructor = injectionType.getDeclaredConstructor( context.instance()
+                                                                                                    .getClass() );
+                                if( !constructor.isAccessible() )
+                                {
+                                    constructor.setAccessible( true );
+                                }
+                                usesObject = constructor.newInstance( context.instance() );
+                            }
+                            catch( Throwable e3 )
+                            {
+                                // Really can't instantiate it - ignore
+                            }
+                        }
+                    }
+                }
+
+                if( usesObject != null )
+                {
+                    context.setUses( context.uses().use( usesObject ) ); // Use this for other injections in same graph
+                }
+
+                return usesObject;
+            }
+            else
+            {
+                return usesObject;
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/internal/Activator.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/internal/Activator.java b/core/runtime/src/main/java/org/apache/zest/runtime/internal/Activator.java
new file mode 100644
index 0000000..d94a67a
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/internal/Activator.java
@@ -0,0 +1,57 @@
+/*
+ * 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.internal;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.apache.zest.bootstrap.Qi4jRuntime;
+import org.apache.zest.bootstrap.RuntimeFactory;
+import org.apache.zest.runtime.Qi4jRuntimeImpl;
+
+/**
+ *
+ */
+public class Activator
+    implements BundleActivator
+{
+    private ServiceRegistration registration;
+
+    @Override
+    public void start( BundleContext bundleContext )
+        throws Exception
+    {
+        RuntimeFactory factory = new RuntimeFactory()
+        {
+            @Override
+            public Qi4jRuntime createRuntime()
+            {
+                return new Qi4jRuntimeImpl();
+            }
+        };
+        registration = bundleContext.registerService( RuntimeFactory.class.getName(), factory, null );
+    }
+
+    @Override
+    public void stop( BundleContext bundleContext )
+        throws Exception
+    {
+        registration.unregister();
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/model/Binder.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/model/Binder.java b/core/runtime/src/main/java/org/apache/zest/runtime/model/Binder.java
new file mode 100644
index 0000000..fdcbd2b
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/model/Binder.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.model;
+
+import org.apache.zest.bootstrap.BindingException;
+
+/**
+ * Interface for models that can understand binding of dependencies
+ */
+public interface Binder
+{
+    void bind( Resolution resolution )
+        throws BindingException;
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/model/Resolution.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/model/Resolution.java b/core/runtime/src/main/java/org/apache/zest/runtime/model/Resolution.java
new file mode 100644
index 0000000..db64211
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/model/Resolution.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.model;
+
+import java.lang.reflect.Field;
+import org.apache.zest.api.composite.ModelDescriptor;
+import org.apache.zest.runtime.composite.CompositeMethodModel;
+import org.apache.zest.runtime.structure.ApplicationModel;
+import org.apache.zest.runtime.structure.LayerModel;
+import org.apache.zest.runtime.structure.ModuleModel;
+
+/**
+ * JAVADOC
+ */
+public final class Resolution
+{
+    private final ApplicationModel application;
+    private final LayerModel layer;
+    private final ModuleModel module;
+    private final ModelDescriptor modelDescriptor;
+    private final CompositeMethodModel method;
+    private final Field field;
+
+    public Resolution( ApplicationModel application,
+                       LayerModel layer,
+                       ModuleModel module,
+                       ModelDescriptor modelDescriptor,
+                       CompositeMethodModel method,
+                       Field field
+    )
+    {
+        this.application = application;
+        this.layer = layer;
+        this.module = module;
+        this.modelDescriptor = modelDescriptor;
+        this.method = method;
+        this.field = field;
+    }
+
+    public ApplicationModel application()
+    {
+        return application;
+    }
+
+    public LayerModel layer()
+    {
+        return layer;
+    }
+
+    public ModuleModel module()
+    {
+        return module;
+    }
+
+    public ModelDescriptor model()
+    {
+        return modelDescriptor;
+    }
+
+    public CompositeMethodModel method()
+    {
+        return method;
+    }
+
+    public Field field()
+    {
+        return field;
+    }
+
+    public Resolution forField( final Field injectedField )
+    {
+        return new Resolution( application, layer, module, modelDescriptor, method, injectedField );
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/object/ObjectModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/object/ObjectModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/object/ObjectModel.java
new file mode 100644
index 0000000..e4df4e5
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/object/ObjectModel.java
@@ -0,0 +1,143 @@
+/*
+ * 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.object;
+
+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.mixin.Initializable;
+import org.apache.zest.api.mixin.InitializationException;
+import org.apache.zest.api.object.ObjectDescriptor;
+import org.apache.zest.functional.HierarchicalVisitor;
+import org.apache.zest.functional.VisitableHierarchy;
+import org.apache.zest.runtime.composite.ConstructorsModel;
+import org.apache.zest.runtime.injection.InjectedFieldsModel;
+import org.apache.zest.runtime.injection.InjectedMethodsModel;
+import org.apache.zest.runtime.injection.InjectionContext;
+
+import static org.apache.zest.functional.Iterables.iterable;
+
+/**
+ * JAVADOC
+ */
+public final class ObjectModel
+    implements ObjectDescriptor, VisitableHierarchy<Object, Object>
+{
+    private final Class<?> objectType;
+    private final Visibility visibility;
+    private final MetaInfo metaInfo;
+    private final ConstructorsModel constructorsModel;
+    private final InjectedFieldsModel injectedFieldsModel;
+    private final InjectedMethodsModel injectedMethodsModel;
+
+    public ObjectModel( Class<?> objectType,
+                        Visibility visibility,
+                        MetaInfo metaInfo
+    )
+    {
+        this.objectType = objectType;
+        this.visibility = visibility;
+        this.metaInfo = metaInfo;
+
+        constructorsModel = new ConstructorsModel( objectType );
+        injectedFieldsModel = new InjectedFieldsModel( objectType );
+        injectedMethodsModel = new InjectedMethodsModel( objectType );
+    }
+
+    @Override
+    @SuppressWarnings( "unchecked" )
+    public Iterable<Class<?>> types()
+    {
+        Iterable<? extends Class<?>> iterable = iterable( objectType );
+        return (Iterable<Class<?>>) iterable;
+    }
+
+    @Override
+    public Visibility visibility()
+    {
+        return visibility;
+    }
+
+    @Override
+    public <T> T metaInfo( Class<T> infoType )
+    {
+        return metaInfo.get( infoType );
+    }
+
+    @Override
+    public boolean isAssignableTo( Class<?> type )
+    {
+        return type.isAssignableFrom( objectType );
+    }
+
+    @Override
+    public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> visitor )
+        throws ThrowableType
+    {
+        if( visitor.visitEnter( this ) )
+        {
+            if( constructorsModel.accept( visitor ) )
+            {
+                if( injectedFieldsModel.accept( visitor ) )
+                {
+                    injectedMethodsModel.accept( visitor );
+                }
+            }
+        }
+        return visitor.visitLeave( this );
+    }
+
+    public Object newInstance( InjectionContext injectionContext )
+    {
+        Object instance;
+        try
+        {
+            instance = constructorsModel.newInstance( injectionContext );
+            injectionContext = new InjectionContext( injectionContext.module(), injectionContext.uses(), instance );
+            injectedFieldsModel.inject( injectionContext, instance );
+            injectedMethodsModel.inject( injectionContext, instance );
+        }
+        catch( Exception e )
+        {
+            throw new ConstructionException( "Could not instantiate " + objectType.getName(), e );
+        }
+
+        if( instance instanceof Initializable )
+        {
+            try
+            {
+                ( (Initializable) instance ).initialize();
+            }
+            catch( InitializationException e )
+            {
+                throw new ConstructionException( "Unable to initialize " + objectType, e );
+            }
+        }
+
+        return instance;
+    }
+
+    public void inject( InjectionContext injectionContext, Object instance )
+    {
+        injectedFieldsModel.inject( injectionContext, instance );
+        injectedMethodsModel.inject( injectionContext, instance );
+    }
+
+    @Override
+    public String toString()
+    {
+        return objectType.getName();
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/object/ObjectsModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/object/ObjectsModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/object/ObjectsModel.java
new file mode 100644
index 0000000..9f05074
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/object/ObjectsModel.java
@@ -0,0 +1,55 @@
+/*
+ * 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.object;
+
+import java.util.List;
+import org.apache.zest.functional.HierarchicalVisitor;
+import org.apache.zest.functional.VisitableHierarchy;
+
+/**
+ * JAVADOC
+ */
+public class ObjectsModel
+    implements VisitableHierarchy<Object, Object>
+{
+    private final List<ObjectModel> objectModels;
+
+    public ObjectsModel( List<ObjectModel> objectModels )
+    {
+        this.objectModels = objectModels;
+    }
+
+    @Override
+    public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> visitor )
+        throws ThrowableType
+    {
+        if( visitor.visitEnter( this ) )
+        {
+            for( ObjectModel objectModel : objectModels )
+            {
+                if( !objectModel.accept( visitor ) )
+                {
+                    break;
+                }
+            }
+        }
+        return visitor.visitLeave( this );
+    }
+
+    public Iterable<ObjectModel> models()
+    {
+        return objectModels;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/package.html
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/package.html b/core/runtime/src/main/java/org/apache/zest/runtime/package.html
new file mode 100644
index 0000000..612d1ae
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/package.html
@@ -0,0 +1,21 @@
+<!--
+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.
+-->
+<html>
+    <body>
+        <h2>Apache Zest™ Runtime.</h2>
+    </body>
+</html>

http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertiesModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertiesModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertiesModel.java
new file mode 100644
index 0000000..202fc89
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertiesModel.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2007-2011, 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.property;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Member;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import org.apache.zest.api.common.QualifiedName;
+import org.apache.zest.functional.HierarchicalVisitor;
+import org.apache.zest.functional.VisitableHierarchy;
+
+/**
+ * Base class for properties model
+ */
+public class PropertiesModel
+    implements VisitableHierarchy<Object, Object>
+{
+    protected final Map<AccessibleObject, PropertyModel> mapAccessiblePropertyModel = new LinkedHashMap<>();
+
+    public PropertiesModel()
+    {
+    }
+
+    public void addProperty( PropertyModel property )
+    {
+        mapAccessiblePropertyModel.put( property.accessor(), property );
+    }
+
+    @Override
+    public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> visitor )
+        throws ThrowableType
+    {
+        if( visitor.visitEnter( this ) )
+        {
+            for( PropertyModel propertyModel : mapAccessiblePropertyModel.values() )
+            {
+                if( !propertyModel.accept( visitor ) )
+                {
+                    break;
+                }
+            }
+        }
+
+        return visitor.visitLeave( this );
+    }
+
+    public Iterable<PropertyModel> properties()
+    {
+        return mapAccessiblePropertyModel.values();
+    }
+
+    public PropertyModel getProperty( AccessibleObject accessor )
+    {
+        PropertyModel propertyModel = mapAccessiblePropertyModel.get( accessor );
+        if( propertyModel == null )
+        {
+            throw new IllegalArgumentException( "No property found with name: " + ( (Member) accessor ).getName() );
+        }
+
+        return propertyModel;
+    }
+
+    public PropertyModel getPropertyByName( String name )
+        throws IllegalArgumentException
+    {
+        for( PropertyModel propertyModel : mapAccessiblePropertyModel.values() )
+        {
+            if( propertyModel.qualifiedName().name().equals( name ) )
+            {
+                return propertyModel;
+            }
+        }
+        throw new IllegalArgumentException( "No property found with name: " + name );
+    }
+
+    public PropertyModel getPropertyByQualifiedName( QualifiedName name )
+        throws IllegalArgumentException
+    {
+        for( PropertyModel propertyModel : mapAccessiblePropertyModel.values() )
+        {
+            if( propertyModel.qualifiedName().equals( name ) )
+            {
+                return propertyModel;
+            }
+        }
+        throw new IllegalArgumentException( "No property found with qualified name: " + name );
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertyInfo.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertyInfo.java b/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertyInfo.java
new file mode 100644
index 0000000..cb185cf
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertyInfo.java
@@ -0,0 +1,36 @@
+/*
+ * 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.property;
+
+import java.lang.reflect.Type;
+import org.apache.zest.api.common.QualifiedName;
+import org.apache.zest.runtime.composite.ConstraintsCheck;
+
+/**
+ * TODO
+ */
+public interface PropertyInfo
+    extends ConstraintsCheck
+{
+    boolean isImmutable();
+
+    QualifiedName qualifiedName();
+
+    Type type();
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertyInstance.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertyInstance.java b/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertyInstance.java
new file mode 100644
index 0000000..9bd2e9d
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertyInstance.java
@@ -0,0 +1,321 @@
+/*
+ * 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.property;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.zest.api.property.Property;
+import org.apache.zest.api.property.PropertyDescriptor;
+import org.apache.zest.api.property.PropertyWrapper;
+import org.apache.zest.api.type.CollectionType;
+import org.apache.zest.api.type.MapType;
+import org.apache.zest.api.type.ValueCompositeType;
+import org.apache.zest.api.value.ValueComposite;
+import org.apache.zest.runtime.value.ValueInstance;
+
+/**
+ * {@code PropertyInstance} represents a property.
+ */
+public class PropertyInstance<T>
+    implements Property<T>
+{
+    protected volatile T value;
+    protected PropertyInfo model;
+
+    /**
+     * Construct an instance of {@code PropertyInstance} with the specified arguments.
+     *
+     * @param model  The property model. This argument must not be {@code null}.
+     * @param aValue The property value.
+     */
+    public PropertyInstance( PropertyInfo model, T aValue )
+    {
+        this.model = model;
+        value = aValue;
+    }
+
+    public PropertyInfo propertyInfo()
+    {
+        return model;
+    }
+
+    /**
+     * @param model The property model. This argument must not be {@code null}.
+     */
+    public void setPropertyInfo( PropertyInfo model )
+    {
+        this.model = model;
+    }
+
+    /**
+     * Returns this property value.
+     *
+     * @return This property value.
+     */
+    @Override
+    public T get()
+    {
+        return value;
+    }
+
+    /**
+     * Sets this property value.
+     *
+     * @param aNewValue The new value.
+     */
+    @Override
+    public void set( T aNewValue )
+    {
+        if( model.isImmutable() )
+        {
+            throw new IllegalStateException( "Property [" + model.qualifiedName() + "] is immutable." );
+        }
+
+        model.checkConstraints( aNewValue );
+
+        value = aNewValue;
+    }
+
+    /**
+     * Perform equals with {@code o} argument.
+     * <p>
+     *     The definition of equals() for the Property is that if both the state and descriptor are equal,
+     *     then the properties are equal.
+     * </p>
+     *
+     * @param o The other object to compare.
+     * @return Returns a {@code boolean} indicator whether this object is equals the other.
+     */
+    @Override
+    public boolean equals( Object o )
+    {
+        if( this == o )
+        {
+            return true;
+        }
+        if( o == null || getClass() != o.getClass() )
+        {
+            return false;
+        }
+
+        Property<?> that = (Property<?>) o;
+        // Unwrap if needed
+        while( that instanceof PropertyWrapper )
+        {
+            that = ( (PropertyWrapper) that ).next();
+        }
+        // Descriptor equality
+        PropertyDescriptor thatDescriptor = (PropertyDescriptor) ( (PropertyInstance) that ).propertyInfo();
+        if( !model.equals( thatDescriptor ) )
+        {
+            return false;
+        }
+        // State equality
+        T value = get();
+        if( value == null )
+        {
+            return that.get() == null;
+        }
+        return value.equals( that.get() );
+    }
+
+    /**
+     * Calculate hash code.
+     *
+     * @return the hashcode of this instance.
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = model.hashCode() * 19; // Descriptor
+        T value = get();
+        if( value != null )
+        {
+            hash += value.hashCode() * 13; // State
+        }
+        return hash;
+    }
+
+    /**
+     * Returns the value as string.
+     *
+     * @return The value as string.
+     */
+    @Override
+    public String toString()
+    {
+        Object value = get();
+        return value == null ? "" : value.toString();
+    }
+
+    @SuppressWarnings( {"raw", "unchecked"} )
+    public void prepareToBuild( PropertyModel propertyDescriptor )
+    {
+        // Check if state has to be modified
+        model = propertyDescriptor.getBuilderInfo();
+        if( propertyDescriptor.valueType() instanceof ValueCompositeType )
+        {
+            Object value = get();
+            if( value != null )
+            {
+                ValueInstance.valueInstanceOf( (ValueComposite) value ).prepareToBuild();
+            }
+        }
+        else if( propertyDescriptor.valueType() instanceof CollectionType )
+        {
+            Object value = get();
+
+            if( value != null )
+            {
+                if( value instanceof List )
+                {
+                    value = new ArrayList( (Collection) value );
+                }
+                else if( value instanceof Set )
+                {
+                    value = new LinkedHashSet( (Collection) value );
+                }
+
+                // Check if items are Values
+                CollectionType collection = (CollectionType) propertyDescriptor.valueType();
+                if( collection.collectedType() instanceof ValueCompositeType )
+                {
+                    Collection coll = (Collection) value;
+                    for( Object instance : coll )
+                    {
+                        ValueInstance.valueInstanceOf( (ValueComposite) instance ).prepareToBuild();
+                    }
+                }
+
+                set( (T) value );
+            }
+        }
+        else if( propertyDescriptor.valueType() instanceof MapType )
+        {
+            Object value = get();
+
+            if( value != null )
+            {
+                Map map = new LinkedHashMap( (Map) value );
+
+                // Check if keys/values are Values
+                MapType mapType = (MapType) propertyDescriptor.valueType();
+                if( mapType.keyType() instanceof ValueCompositeType )
+                {
+                    for( Object instance : map.keySet() )
+                    {
+                        ValueInstance.valueInstanceOf( (ValueComposite) instance ).prepareToBuild();
+                    }
+                }
+                if( mapType.valueType() instanceof ValueCompositeType )
+                {
+                    for( Object instance : map.values() )
+                    {
+                        ValueInstance.valueInstanceOf( (ValueComposite) instance ).prepareToBuild();
+                    }
+                }
+
+                set( (T) value );
+            }
+        }
+    }
+
+    @SuppressWarnings( {"raw", "unchecked"} )
+    public void prepareBuilderState( PropertyModel propertyDescriptor )
+    {
+        // Check if state has to be modified
+        if( propertyDescriptor.valueType() instanceof ValueCompositeType )
+        {
+            Object value = get();
+            if( value != null )
+            {
+                ValueInstance.valueInstanceOf( (ValueComposite) value ).prepareBuilderState();
+            }
+        }
+        else if( propertyDescriptor.valueType() instanceof CollectionType )
+        {
+            T value = get();
+            if( value != null )
+            {
+                if( propertyDescriptor.isImmutable() )
+                {
+                    if( value instanceof List )
+                    {
+                        value = (T) Collections.unmodifiableList( (List<? extends Object>) value );
+                    }
+                    else if( value instanceof Set )
+                    {
+                        value = (T) Collections.unmodifiableSet( (Set<? extends Object>) value );
+                    }
+                    else
+                    {
+                        value = (T) Collections.unmodifiableCollection( (Collection<? extends Object>) value );
+                    }
+
+                    this.value = value;
+                }
+
+                CollectionType collection = (CollectionType) propertyDescriptor.valueType();
+                if( collection.collectedType() instanceof ValueCompositeType )
+                {
+                    Collection coll = (Collection) value;
+                    for( Object instance : coll )
+                    {
+                        ValueInstance.valueInstanceOf( (ValueComposite) instance ).prepareBuilderState();
+                    }
+                }
+            }
+        }
+        else if( propertyDescriptor.valueType() instanceof MapType )
+        {
+            T value = get();
+
+            if( value != null )
+            {
+                MapType mapType = (MapType) propertyDescriptor.valueType();
+                if( mapType.keyType() instanceof ValueCompositeType )
+                {
+                    Map map = (Map) value;
+                    for( Object instance : map.keySet() )
+                    {
+                        ValueInstance.valueInstanceOf( (ValueComposite) instance ).prepareBuilderState();
+                    }
+                }
+                if( mapType.valueType() instanceof ValueCompositeType )
+                {
+                    Map map = (Map) value;
+                    for( Object instance : map.values() )
+                    {
+                        ValueInstance.valueInstanceOf( (ValueComposite) instance ).prepareBuilderState();
+                    }
+                }
+                if( propertyDescriptor.isImmutable() )
+                {
+                    value = (T) Collections.unmodifiableMap( (Map<?, ?>) value );
+                }
+
+                this.value = value;
+            }
+        }
+
+        model = propertyDescriptor;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertyModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertyModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertyModel.java
new file mode 100644
index 0000000..9f37373
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertyModel.java
@@ -0,0 +1,309 @@
+/*
+ * 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.property;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.List;
+import org.apache.zest.api.common.MetaInfo;
+import org.apache.zest.api.common.QualifiedName;
+import org.apache.zest.api.constraint.ConstraintViolation;
+import org.apache.zest.api.constraint.ConstraintViolationException;
+import org.apache.zest.api.entity.Queryable;
+import org.apache.zest.api.property.DefaultValues;
+import org.apache.zest.api.property.GenericPropertyInfo;
+import org.apache.zest.api.property.InvalidPropertyTypeException;
+import org.apache.zest.api.property.Property;
+import org.apache.zest.api.property.PropertyDescriptor;
+import org.apache.zest.api.structure.Module;
+import org.apache.zest.api.type.Serialization;
+import org.apache.zest.api.type.ValueCompositeType;
+import org.apache.zest.api.type.ValueType;
+import org.apache.zest.api.util.Classes;
+import org.apache.zest.bootstrap.BindingException;
+import org.apache.zest.functional.Visitable;
+import org.apache.zest.functional.Visitor;
+import org.apache.zest.runtime.composite.ValueConstraintsInstance;
+import org.apache.zest.runtime.model.Binder;
+import org.apache.zest.runtime.model.Resolution;
+import org.apache.zest.runtime.types.ValueTypeFactory;
+
+import static org.apache.zest.functional.Iterables.empty;
+import static org.apache.zest.functional.Iterables.first;
+
+/**
+ * Model for a Property.
+ *
+ * <p>Equality is based on the Property accessor object (property type and name), not on the QualifiedName.</p>
+ */
+public class PropertyModel
+    implements PropertyDescriptor, PropertyInfo, Binder, Visitable<PropertyModel>
+{
+    private Type type;
+
+    private transient AccessibleObject accessor; // Interface accessor
+
+    private final QualifiedName qualifiedName;
+
+    private final ValueConstraintsInstance constraints; // May be null
+
+    protected final MetaInfo metaInfo;
+
+    private final Object initialValue;
+
+    private final boolean useDefaults;
+
+    private final boolean immutable;
+
+    private ValueType valueType;
+
+    protected PropertyInfo builderInfo;
+
+    private final boolean queryable;
+
+    public PropertyModel( AccessibleObject accessor,
+                          boolean immutable,
+                          boolean useDefaults,
+                          ValueConstraintsInstance constraints,
+                          MetaInfo metaInfo,
+                          Object initialValue
+    )
+    {
+        if( accessor instanceof Method )
+        {
+            Method m = (Method) accessor;
+            if( !m.getReturnType().equals( Property.class ) )
+            {
+                throw new InvalidPropertyTypeException( accessor );
+            }
+        }
+        this.immutable = immutable;
+        this.metaInfo = metaInfo;
+        type = GenericPropertyInfo.propertyTypeOf( accessor );
+        this.accessor = accessor;
+        qualifiedName = QualifiedName.fromAccessor( accessor );
+
+        this.useDefaults = useDefaults;
+
+        this.initialValue = initialValue;
+
+        this.constraints = constraints;
+
+        final Queryable queryable = accessor.getAnnotation( Queryable.class );
+        this.queryable = queryable == null || queryable.value();
+    }
+
+    @Override
+    public <T> T metaInfo( Class<T> infoType )
+    {
+        return metaInfo.get( infoType );
+    }
+
+    public String name()
+    {
+        return qualifiedName.name();
+    }
+
+    @Override
+    public QualifiedName qualifiedName()
+    {
+        return qualifiedName;
+    }
+
+    @Override
+    public Type type()
+    {
+        return type;
+    }
+
+    @Override
+    public AccessibleObject accessor()
+    {
+        return accessor;
+    }
+
+    @Override
+    public ValueType valueType()
+    {
+        return valueType;
+    }
+
+    @Override
+    public boolean isImmutable()
+    {
+        return immutable;
+    }
+
+    public PropertyInfo getBuilderInfo()
+    {
+        return builderInfo;
+    }
+
+    @Override
+    public boolean queryable()
+    {
+        return queryable;
+    }
+
+    @Override
+    public Object initialValue( Module module )
+    {
+        // Use supplied value from assembly
+        Object value = initialValue;
+
+        // Check for @UseDefaults annotation
+        if( value == null && useDefaults )
+        {
+            if( valueType instanceof ValueCompositeType )
+            {
+                return module.newValue( (Class<?>) first( valueType().types() ) );
+            }
+            else
+            {
+                value = DefaultValues.getDefaultValueOf( type );
+            }
+        }
+
+        return value;
+    }
+
+    @Override
+    public void bind( Resolution resolution )
+        throws BindingException
+    {
+        ValueTypeFactory factory = ValueTypeFactory.instance();
+        Class<?> declaringClass = ( (Member) accessor() ).getDeclaringClass();
+        Class<?> mainType = first( resolution.model().types() );
+        Serialization.Variant variant = findVariant();
+        valueType = factory.newValueType( type(), declaringClass, mainType, resolution.layer(), resolution.module(), variant );
+        builderInfo = new BuilderPropertyInfo();
+        if( type instanceof TypeVariable )
+        {
+            type = Classes.resolveTypeVariable( (TypeVariable) type, declaringClass, mainType );
+        }
+    }
+
+    private Serialization.Variant findVariant()
+    {
+        Serialization serialization = metaInfo.get( Serialization.class );
+        Serialization.Variant variant = null;
+        if( serialization != null )
+        {
+            variant = serialization.value();
+        }
+        if( variant == null )
+        {
+            variant = Serialization.Variant.entry;
+        }
+        return variant;
+    }
+
+    @Override
+    public <ThrowableType extends Throwable> boolean accept( Visitor<? super PropertyModel, ThrowableType> visitor )
+        throws ThrowableType
+    {
+        return visitor.visit( this );
+    }
+
+    @Override
+    public void checkConstraints( Object value )
+        throws ConstraintViolationException
+    {
+        if( constraints != null )
+        {
+            List<ConstraintViolation> violations = constraints.checkConstraints( value );
+            if( !violations.isEmpty() )
+            {
+                Iterable<Class<?>> empty = empty();
+                throw new ConstraintViolationException( "<new instance>", empty, ( (Member) accessor ), violations );
+            }
+        }
+    }
+
+    @Override
+    public boolean equals( Object o )
+    {
+        if( this == o )
+        {
+            return true;
+        }
+        if( o == null || getClass() != o.getClass() )
+        {
+            return false;
+        }
+
+        PropertyModel that = (PropertyModel) o;
+        return accessor.equals( that.accessor );
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return accessor.hashCode();
+    }
+
+    @Override
+    public String toString()
+    {
+        if( accessor instanceof Field )
+        {
+            return ( (Field) accessor ).toGenericString();
+        }
+        else
+        {
+            return ( (Method) accessor ).toGenericString();
+        }
+    }
+
+    private class BuilderPropertyInfo implements PropertyInfo
+    {
+        @Override
+        public boolean isImmutable()
+        {
+            return false;
+        }
+
+        @Override
+        public QualifiedName qualifiedName()
+        {
+            return qualifiedName;
+        }
+
+        @Override
+        public Type type()
+        {
+            return type;
+        }
+
+        @Override
+        public void checkConstraints( Object value )
+            throws ConstraintViolationException
+        {
+            if( constraints != null )
+            {
+                List<ConstraintViolation> violations = constraints.checkConstraints( value );
+                if( !violations.isEmpty() )
+                {
+                    Iterable<Class<?>> empty = empty();
+                    throw new ConstraintViolationException( "<new instance>", empty, ( (Member) accessor ), violations );
+                }
+            }
+        }
+    }
+}
\ No newline at end of file


Mime
View raw message