You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@polygene.apache.org by ni...@apache.org on 2015/07/30 21:48:13 UTC
[14/80] [partial] zest-java git commit: First round of changes to
move to org.apache.zest namespace.
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/composite/AbstractConstraintModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/composite/AbstractConstraintModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/composite/AbstractConstraintModel.java
new file mode 100644
index 0000000..d8c9ff6
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/composite/AbstractConstraintModel.java
@@ -0,0 +1,49 @@
+/*
+ * 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.composite;
+
+import java.lang.annotation.Annotation;
+import org.apache.zest.api.constraint.ConstraintDescriptor;
+import org.apache.zest.functional.Visitable;
+import org.apache.zest.functional.Visitor;
+
+/**
+ * JAVADOC
+ */
+public abstract class AbstractConstraintModel
+ implements ConstraintDescriptor, Visitable<ConstraintDescriptor>
+{
+ protected final Annotation annotation;
+
+ public AbstractConstraintModel( Annotation annotation )
+ {
+ this.annotation = annotation;
+ }
+
+ @Override
+ public Annotation annotation()
+ {
+ return annotation;
+ }
+
+ public abstract ConstraintInstance<?, ?> newInstance();
+
+ @Override
+ public <ThrowableType extends Throwable> boolean accept( Visitor<? super ConstraintDescriptor, ThrowableType> modelVisitor )
+ throws ThrowableType
+ {
+ return modelVisitor.visit( this );
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/composite/AbstractModifierModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/composite/AbstractModifierModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/composite/AbstractModifierModel.java
new file mode 100644
index 0000000..a2478ce
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/composite/AbstractModifierModel.java
@@ -0,0 +1,177 @@
+/*
+ * 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.composite;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import org.apache.zest.api.common.ConstructionException;
+import org.apache.zest.functional.HierarchicalVisitor;
+import org.apache.zest.functional.VisitableHierarchy;
+import org.apache.zest.runtime.injection.Dependencies;
+import org.apache.zest.runtime.injection.DependencyModel;
+import org.apache.zest.runtime.injection.InjectedFieldsModel;
+import org.apache.zest.runtime.injection.InjectedMethodsModel;
+import org.apache.zest.runtime.injection.InjectionContext;
+import org.apache.zest.spi.module.ModuleSpi;
+
+import static org.apache.zest.api.util.Classes.RAW_CLASS;
+import static org.apache.zest.api.util.Classes.interfacesOf;
+import static org.apache.zest.functional.Iterables.flattenIterables;
+import static org.apache.zest.functional.Iterables.iterable;
+import static org.apache.zest.functional.Iterables.map;
+import static org.apache.zest.functional.Iterables.toArray;
+import static org.apache.zest.functional.Iterables.unique;
+
+/**
+ * JAVADOC
+ */
+public abstract class AbstractModifierModel
+ implements Dependencies, VisitableHierarchy<Object, Object>
+{
+ private final Class<?> modifierClass;
+
+ private final ConstructorsModel constructorsModel;
+ private final InjectedFieldsModel injectedFieldsModel;
+ private final InjectedMethodsModel injectedMethodsModel;
+
+ private final Class<?>[] nextInterfaces;
+
+ @SuppressWarnings( "unchecked" )
+ public AbstractModifierModel( Class<?> declaredModifierClass, Class<?> instantiationClass )
+ {
+ this.modifierClass = instantiationClass;
+ constructorsModel = new ConstructorsModel( modifierClass );
+ injectedFieldsModel = new InjectedFieldsModel( declaredModifierClass );
+ injectedMethodsModel = new InjectedMethodsModel( declaredModifierClass );
+ Class<Class<?>> componentType = (Class<Class<?>>) Class.class.cast( Class.class );
+ nextInterfaces = toArray( componentType, unique( map( RAW_CLASS, interfacesOf( declaredModifierClass ) ) ) );
+ }
+
+ public Class<?> modifierClass()
+ {
+ return modifierClass;
+ }
+
+ @Override
+ @SuppressWarnings( "unchecked" )
+ public Iterable<DependencyModel> dependencies()
+ {
+ return flattenIterables( map( DEPENDENCIES_FUNCTION, iterable( constructorsModel, injectedFieldsModel, injectedMethodsModel ) ) );
+ }
+
+ public boolean isGeneric()
+ {
+ return InvocationHandler.class.isAssignableFrom( modifierClass );
+ }
+
+ @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 );
+ }
+
+ // Context
+ public InvocationHandler newInstance( ModuleSpi moduleInstance,
+ InvocationHandler next,
+ ProxyReferenceInvocationHandler proxyHandler,
+ Method method
+ )
+ {
+ InjectionContext injectionContext = new InjectionContext( moduleInstance, wrapNext( next ), proxyHandler );
+
+ Object modifier = constructorsModel.newInstance( injectionContext );
+
+ try
+ {
+ if( FragmentClassLoader.isGenerated( modifier ) )
+ {
+ modifier.getClass().getField( "_instance" ).set( modifier, proxyHandler );
+ }
+ }
+ catch( IllegalAccessException | NoSuchFieldException e )
+ {
+ e.printStackTrace();
+ }
+
+ injectedFieldsModel.inject( injectionContext, modifier );
+ injectedMethodsModel.inject( injectionContext, modifier );
+
+ if( isGeneric() )
+ {
+ return (InvocationHandler) modifier;
+ }
+ else
+ {
+ try
+ {
+ Method invocationMethod = modifierClass.getMethod( "_" + method.getName(), method.getParameterTypes() );
+ TypedModifierInvocationHandler handler = new TypedModifierInvocationHandler();
+ handler.setFragment( modifier );
+ handler.setMethod( invocationMethod );
+ return handler;
+ }
+ catch( NoSuchMethodException e )
+ {
+ throw new ConstructionException( "Could not find modifier method", e );
+ }
+ }
+ }
+
+ private Object wrapNext( InvocationHandler next )
+ {
+ if( isGeneric() )
+ {
+ return next;
+ }
+ else
+ {
+ return Proxy.newProxyInstance( modifierClass.getClassLoader(), nextInterfaces, next );
+ }
+ }
+
+ @Override
+ public boolean equals( Object o )
+ {
+ if( this == o )
+ {
+ return true;
+ }
+ if( o == null || getClass() != o.getClass() )
+ {
+ return false;
+ }
+ AbstractModifierModel that = (AbstractModifierModel) o;
+ return modifierClass.equals( that.modifierClass );
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return modifierClass.hashCode();
+ }
+}
\ 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/composite/AtomicInstancePool.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/composite/AtomicInstancePool.java b/core/runtime/src/main/java/org/apache/zest/runtime/composite/AtomicInstancePool.java
new file mode 100644
index 0000000..4929297
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/composite/AtomicInstancePool.java
@@ -0,0 +1,53 @@
+/*
+ * 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.composite;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Method instance pool that keeps a linked list. Uses atomic reference
+ * to ensure that instances are acquired and returned in a thread-safe
+ * manner.
+ */
+public final class AtomicInstancePool
+ implements InstancePool<CompositeMethodInstance>
+{
+ private final AtomicReference<CompositeMethodInstance> first = new AtomicReference<CompositeMethodInstance>();
+
+ @Override
+ public CompositeMethodInstance obtainInstance()
+ {
+ CompositeMethodInstance firstInstance;
+ do
+ {
+ firstInstance = first.get();
+ }
+ while( firstInstance != null && !first.compareAndSet( firstInstance, firstInstance.getNext() ) );
+
+ return firstInstance;
+ }
+
+ @Override
+ public void releaseInstance( CompositeMethodInstance compositeMethodInstance )
+ {
+ CompositeMethodInstance firstInstance;
+ do
+ {
+ firstInstance = first.get();
+ compositeMethodInstance.setNext( firstInstance );
+ }
+ while( !first.compareAndSet( firstInstance, compositeMethodInstance ) );
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/composite/CompactLevel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/composite/CompactLevel.java b/core/runtime/src/main/java/org/apache/zest/runtime/composite/CompactLevel.java
new file mode 100644
index 0000000..42a0dee
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/composite/CompactLevel.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2007, Rickard Öberg. All Rights Reserved.
+ * Copyright (c) 2007, 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.composite;
+
+/**
+ * Compaction Level of the StackTrace clenaup operation.
+ *
+ * <pre>
+ * <b>off</b> = Do not modify the stack trace.
+ * <b>proxy</b> = Remove all Zest internal classes and all JDK internal classes from
+ * the originating method call.
+ * <b>semi</b> = Remove all JDK internal classes on the entire stack.
+ * <b>extensive</b> = Remove all Zest internal and JDK internal classes from the entire stack.
+ * </pre>
+ *
+ * <p>
+ * The Compaction is set through the System Property "<code><b>qi4j.compacttrace</b></code>" to
+ * any of the above values.
+ * </p>
+ */
+enum CompactLevel
+{
+ off, proxy, semi, extensive
+}
\ 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/composite/CompositeConstraintModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/composite/CompositeConstraintModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/composite/CompositeConstraintModel.java
new file mode 100644
index 0000000..bcf068c
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/composite/CompositeConstraintModel.java
@@ -0,0 +1,68 @@
+/*
+ * 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.composite;
+
+import java.lang.annotation.Annotation;
+import org.apache.zest.api.common.ConstructionException;
+import org.apache.zest.api.constraint.Constraint;
+
+/**
+ * JAVADOC
+ */
+public final class CompositeConstraintModel
+ extends AbstractConstraintModel
+{
+ private final ValueConstraintsModel constraintsModel;
+
+ public CompositeConstraintModel( Annotation annotation, ValueConstraintsModel constraintsModel )
+ {
+ super( annotation );
+ this.constraintsModel = constraintsModel;
+ }
+
+ @Override
+ @SuppressWarnings( {"raw", "unchecked"} )
+ public ConstraintInstance<?, ?> newInstance()
+ {
+ try
+ {
+ ValueConstraintsInstance compositeConstraintsInstance = constraintsModel.newInstance();
+ Constraint<?, ?> constraint = new CompositeConstraintInstance( compositeConstraintsInstance );
+ return new ConstraintInstance( constraint, annotation );
+ }
+ catch( Exception e )
+ {
+ throw new ConstructionException( "Could not instantiate constraint implementation", e );
+ }
+ }
+
+ private static class CompositeConstraintInstance
+ implements Constraint<Annotation, Object>
+ {
+ private final ValueConstraintsInstance valueConstraintsInstance;
+
+ private CompositeConstraintInstance( ValueConstraintsInstance valueConstraintsInstance )
+ {
+ this.valueConstraintsInstance = valueConstraintsInstance;
+ }
+
+ @Override
+ public boolean isValid( Annotation annotation, Object value )
+ throws NullPointerException
+ {
+ return valueConstraintsInstance.checkConstraints( value ).isEmpty();
+ }
+ }
+}
\ 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/composite/CompositeMethodInstance.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/composite/CompositeMethodInstance.java b/core/runtime/src/main/java/org/apache/zest/runtime/composite/CompositeMethodInstance.java
new file mode 100644
index 0000000..ae3f706
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/composite/CompositeMethodInstance.java
@@ -0,0 +1,77 @@
+/*
+ * 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.composite;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+
+/**
+ * JAVADOC
+ */
+public final class CompositeMethodInstance
+{
+ private final InvocationHandler invoker;
+ private final FragmentInvocationHandler mixinInvoker;
+ private final Method method;
+ private final int methodIdx;
+
+ private CompositeMethodInstance next;
+
+ public CompositeMethodInstance( InvocationHandler invoker,
+ FragmentInvocationHandler mixinInvoker,
+ Method method, int methodIdx
+ )
+ {
+ this.invoker = invoker;
+ this.method = method;
+ this.mixinInvoker = mixinInvoker;
+ this.methodIdx = methodIdx;
+ }
+
+ public Method method()
+ {
+ return method;
+ }
+
+ public Object getMixinFrom( Object[] mixins )
+ {
+ return mixins[ methodIdx ];
+ }
+
+ public Object invoke( Object composite, Object[] params, Object mixin )
+ throws Throwable
+ {
+ mixinInvoker.setFragment( mixin );
+
+ try
+ {
+ return invoker.invoke( composite, method, params );
+ }
+ finally
+ {
+ mixinInvoker.setFragment( null );
+ }
+ }
+
+ public CompositeMethodInstance getNext()
+ {
+ return next;
+ }
+
+ public void setNext( CompositeMethodInstance next )
+ {
+ this.next = next;
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/composite/CompositeMethodModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/composite/CompositeMethodModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/composite/CompositeMethodModel.java
new file mode 100644
index 0000000..9258dbc
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/composite/CompositeMethodModel.java
@@ -0,0 +1,321 @@
+/*
+ * 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.composite;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.apache.zest.api.common.ConstructionException;
+import org.apache.zest.api.composite.MethodDescriptor;
+import org.apache.zest.api.util.NullArgumentException;
+import org.apache.zest.functional.HierarchicalVisitor;
+import org.apache.zest.functional.VisitableHierarchy;
+import org.apache.zest.runtime.injection.Dependencies;
+import org.apache.zest.runtime.injection.DependencyModel;
+import org.apache.zest.spi.module.ModuleSpi;
+
+import static org.apache.zest.functional.Iterables.filter;
+import static org.apache.zest.functional.Iterables.flattenIterables;
+import static org.apache.zest.functional.Iterables.iterable;
+import static org.apache.zest.functional.Specifications.notNull;
+
+/**
+ * JAVADOC
+ */
+public final class CompositeMethodModel
+ implements MethodDescriptor, Dependencies, VisitableHierarchy<Object, Object>
+{
+ // Model
+ private final Method method;
+ private Method invocationMethod; // This will be the _ prefixed method on typed mixins
+ private final ConstraintsModel constraints;
+ private final ConcernsModel concerns;
+ private final SideEffectsModel sideEffects;
+ private final MixinsModel mixins;
+ private AnnotatedElement annotations;
+
+ // Context
+// private final SynchronizedCompositeMethodInstancePool instancePool = new SynchronizedCompositeMethodInstancePool();
+ private final AtomicInstancePool instancePool = new AtomicInstancePool();
+ private final ConstraintsInstance constraintsInstance;
+
+ public CompositeMethodModel( Method method,
+ ConstraintsModel constraintsModel,
+ ConcernsModel concernsModel,
+ SideEffectsModel sideEffectsModel,
+ MixinsModel mixinsModel
+ )
+ {
+ this.method = method;
+ mixins = mixinsModel;
+ concerns = concernsModel;
+ sideEffects = sideEffectsModel;
+ constraints = constraintsModel;
+ constraintsInstance = constraints.newInstance();
+ initialize();
+ }
+
+ private void initialize()
+ {
+ annotations = new CompositeMethodAnnotatedElement();
+ this.method.setAccessible( true );
+// instancePool = new SynchronizedCompositeMethodInstancePool();
+ }
+
+ // Model
+
+ @Override
+ public Method method()
+ {
+ return method;
+ }
+
+ public MixinModel mixin()
+ {
+ return mixins.mixinFor( method );
+ }
+
+ @Override
+ @SuppressWarnings( "unchecked" )
+ public Iterable<DependencyModel> dependencies()
+ {
+ return flattenIterables( filter( notNull(), iterable( concerns != null ? concerns.dependencies() : null,
+ sideEffects != null ? sideEffects.dependencies() : null ) ) );
+ }
+
+ // Context
+ public Object invoke( Object composite, Object[] params, MixinsInstance mixins, ModuleSpi moduleInstance )
+ throws Throwable
+ {
+ constraintsInstance.checkValid( composite, method, params );
+
+ CompositeMethodInstance methodInstance = getInstance( moduleInstance );
+ try
+ {
+ return mixins.invoke( composite, params, methodInstance );
+ }
+ finally
+ {
+ instancePool.releaseInstance( methodInstance );
+ }
+ }
+
+ private CompositeMethodInstance getInstance( ModuleSpi moduleInstance )
+ {
+ CompositeMethodInstance methodInstance = instancePool.obtainInstance();
+ if( methodInstance == null )
+ {
+ methodInstance = newCompositeMethodInstance( moduleInstance );
+ }
+
+ return methodInstance;
+ }
+
+ private CompositeMethodInstance newCompositeMethodInstance( ModuleSpi moduleInstance )
+ throws ConstructionException
+ {
+ FragmentInvocationHandler mixinInvocationHandler = mixins.newInvocationHandler( method );
+ InvocationHandler invoker = mixinInvocationHandler;
+ if( concerns != ConcernsModel.EMPTY_CONCERNS )
+ {
+ ConcernsInstance concernsInstance = concerns.newInstance( method, moduleInstance, mixinInvocationHandler );
+ invoker = concernsInstance;
+ }
+ if( sideEffects != SideEffectsModel.EMPTY_SIDEEFFECTS )
+ {
+ SideEffectsInstance sideEffectsInstance = sideEffects.newInstance( method, moduleInstance, invoker );
+ invoker = sideEffectsInstance;
+ }
+
+ if( invocationMethod == null )
+ {
+ MixinModel model = mixins.mixinFor( method );
+ if( !InvocationHandler.class.isAssignableFrom( model.mixinClass() ) )
+ {
+ try
+ {
+ invocationMethod = model.instantiationClass()
+ .getMethod( "_" + method.getName(), method.getParameterTypes() );
+ }
+ catch( NoSuchMethodException e )
+ {
+ invocationMethod = method;
+// throw new ConstructionException( "Could not find the subclass method", e );
+ }
+ }
+ else
+ {
+ invocationMethod = method;
+ }
+ }
+
+ mixinInvocationHandler.setMethod( invocationMethod );
+
+ return new CompositeMethodInstance( invoker, mixinInvocationHandler, method, mixins.methodIndex.get( method ) );
+ }
+
+ public AnnotatedElement annotatedElement()
+ {
+ return annotations;
+ }
+
+ @Override
+ public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> modelVisitor )
+ throws ThrowableType
+ {
+ if( modelVisitor.visitEnter( this ) )
+ {
+ constraints.accept( modelVisitor );
+ concerns.accept( modelVisitor );
+ sideEffects.accept( modelVisitor );
+ }
+ return modelVisitor.visitLeave( this );
+ }
+
+ @Override
+ public String toString()
+ {
+ return method.toGenericString();
+ }
+
+ public Iterable<Method> invocationsFor( Class<?> mixinClass )
+ {
+ return mixins.invocationsFor( mixinClass );
+ }
+
+ public class CompositeMethodAnnotatedElement
+ implements AnnotatedElement
+ {
+ @Override
+ public boolean isAnnotationPresent( Class<? extends Annotation> annotationClass )
+ {
+ // Check method
+ if( method.isAnnotationPresent( annotationClass ) )
+ {
+ return true;
+ }
+
+ // Check mixin
+ try
+ {
+ MixinModel model = mixins.mixinFor( method );
+ if( GenericSpecification.INSTANCE.satisfiedBy( model.mixinClass() ) )
+ {
+ return false;
+ }
+ return ( model.mixinClass()
+ .getMethod( method.getName(), method.getParameterTypes() )
+ .isAnnotationPresent( annotationClass ) );
+ }
+ catch( NoSuchMethodException e )
+ {
+ return false;
+ }
+ }
+
+ @Override
+ public <T extends Annotation> T getAnnotation( Class<T> annotationClass )
+ {
+ // Check mixin
+ try
+ {
+ MixinModel model = mixins.mixinFor( method );
+ if( !GenericSpecification.INSTANCE.satisfiedBy( model.mixinClass() ) )
+ {
+ T annotation = annotationClass.cast( model.mixinClass()
+ .getMethod( method.getName(), method.getParameterTypes() )
+ .getAnnotation( annotationClass ) );
+ if( annotation != null )
+ {
+ return annotation;
+ }
+ }
+ }
+ catch( NoSuchMethodException e )
+ {
+ // Ignore
+ }
+
+ // Check method
+ return method.getAnnotation( annotationClass );
+ }
+
+ @Override
+ public Annotation[] getAnnotations()
+ {
+ // Add mixin annotations
+ List<Annotation> annotations = new ArrayList<Annotation>();
+ MixinModel model = mixins.mixinFor( method );
+ Annotation[] mixinAnnotations = new Annotation[ 0 ];
+ if( !GenericSpecification.INSTANCE.satisfiedBy( model.mixinClass() ) )
+ {
+ mixinAnnotations = model.mixinClass().getAnnotations();
+ annotations.addAll( Arrays.asList( mixinAnnotations ) );
+ }
+
+ // Add method annotations, but don't include duplicates
+ Annotation[] methodAnnotations = method.getAnnotations();
+ next:
+ for( Annotation methodAnnotation : methodAnnotations )
+ {
+ for( int i = 0; i < mixinAnnotations.length; i++ )
+ {
+ if( annotations.get( i ).annotationType().equals( methodAnnotation.annotationType() ) )
+ {
+ continue next;
+ }
+ }
+
+ annotations.add( methodAnnotation );
+ }
+
+ return annotations.toArray( new Annotation[ annotations.size() ] );
+ }
+
+ @Override
+ public Annotation[] getDeclaredAnnotations()
+ {
+ return new Annotation[ 0 ];
+ }
+
+ // @Override (Since JDK 8)
+ @SuppressWarnings( "unchecked" )
+ public <T extends Annotation> T[] getAnnotationsByType( Class<T> annotationClass )
+ {
+ NullArgumentException.validateNotNull( "annotationClass", annotationClass );
+ return (T[]) Array.newInstance( annotationClass, 0 );
+ }
+
+ // @Override (Since JDK 8)
+ public <T extends Annotation> T getDeclaredAnnotation( Class<T> annotationClass )
+ {
+ NullArgumentException.validateNotNull( "annotationClass", annotationClass );
+ return null;
+ }
+
+ // @Override (Since JDK 8)
+ @SuppressWarnings( "unchecked" )
+ public <T extends Annotation> T[] getDeclaredAnnotationsByType( Class<T> annotationClass )
+ {
+ NullArgumentException.validateNotNull( "annotationClass", annotationClass );
+ return (T[]) Array.newInstance( annotationClass, 0 );
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/composite/CompositeMethodsModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/composite/CompositeMethodsModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/composite/CompositeMethodsModel.java
new file mode 100644
index 0000000..62d44c2
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/composite/CompositeMethodsModel.java
@@ -0,0 +1,132 @@
+/*
+ * 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.composite;
+
+import java.lang.reflect.Method;
+import java.util.LinkedHashMap;
+import org.apache.zest.api.composite.MissingMethodException;
+import org.apache.zest.functional.HierarchicalVisitor;
+import org.apache.zest.functional.Iterables;
+import org.apache.zest.functional.VisitableHierarchy;
+import org.apache.zest.runtime.injection.Dependencies;
+import org.apache.zest.runtime.injection.DependencyModel;
+import org.apache.zest.spi.module.ModuleSpi;
+
+import static org.apache.zest.functional.Iterables.map;
+
+/**
+ * Model for Composite methods. This includes both private and public methods.
+ */
+public final class CompositeMethodsModel
+ implements VisitableHierarchy<Object, Object>
+{
+ private final LinkedHashMap<Method, CompositeMethodModel> methods;
+ private final MixinsModel mixinsModel;
+
+ public CompositeMethodsModel( MixinsModel mixinsModel )
+ {
+ methods = new LinkedHashMap<>();
+ this.mixinsModel = mixinsModel;
+ }
+
+ public Iterable<DependencyModel> dependencies()
+ {
+ return Iterables.flattenIterables( map( Dependencies.DEPENDENCIES_FUNCTION, methods.values() ) );
+ }
+
+ // Context
+ public Object invoke( MixinsInstance mixins,
+ Object proxy,
+ Method method,
+ Object[] args,
+ ModuleSpi moduleInstance
+ )
+ throws Throwable
+ {
+ CompositeMethodModel compositeMethod = methods.get( method );
+
+ if( compositeMethod == null )
+ {
+ if( method.getDeclaringClass().equals( Object.class ) )
+ {
+ return mixins.invokeObject( proxy, args, method );
+ }
+
+ if( !method.getDeclaringClass().isInterface() )
+ {
+ Iterable<Class<?>> types = mixinsModel.mixinTypes();
+ for( Class<?> aClass : types )
+ {
+ try
+ {
+ Method realMethod = aClass.getMethod( method.getName(), method.getParameterTypes() );
+ compositeMethod = methods.get( realMethod );
+ break;
+ }
+ catch( NoSuchMethodException e )
+ {
+ }
+ catch( SecurityException e )
+ {
+ }
+ }
+ }
+// return mixins.invokeObject( proxy, args, method );
+ throw new MissingMethodException( "Method '" + method + "' is not implemented" );
+ }
+ else
+ {
+ return compositeMethod.invoke( proxy, args, mixins, moduleInstance );
+ }
+ }
+
+ public void addMethod( CompositeMethodModel methodModel )
+ {
+ methods.put( methodModel.method(), methodModel );
+ }
+
+ public boolean isImplemented( Method method )
+ {
+ return methods.containsKey( method );
+ }
+
+ public Iterable<Method> methods()
+ {
+ return methods.keySet();
+ }
+
+ @Override
+ public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> modelVisitor )
+ throws ThrowableType
+ {
+ if( modelVisitor.visitEnter( this ) )
+ {
+ for( CompositeMethodModel compositeMethodModel : methods.values() )
+ {
+ if( !compositeMethodModel.accept( modelVisitor ) )
+ {
+ break;
+ }
+ }
+ }
+ return modelVisitor.visitLeave( this );
+ }
+
+ @Override
+ public String toString()
+ {
+ return methods().toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/composite/CompositeModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/composite/CompositeModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/composite/CompositeModel.java
new file mode 100644
index 0000000..a9554f3
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/composite/CompositeModel.java
@@ -0,0 +1,267 @@
+/*
+ * 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.composite;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.util.LinkedHashSet;
+import java.util.Set;
+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.Composite;
+import org.apache.zest.api.composite.CompositeDescriptor;
+import org.apache.zest.api.composite.InvalidCompositeException;
+import org.apache.zest.functional.HierarchicalVisitor;
+import org.apache.zest.functional.Iterables;
+import org.apache.zest.functional.VisitableHierarchy;
+import org.apache.zest.runtime.injection.Dependencies;
+import org.apache.zest.runtime.injection.DependencyModel;
+import org.apache.zest.spi.module.ModuleSpi;
+
+import static java.lang.reflect.Proxy.newProxyInstance;
+import static org.apache.zest.functional.Iterables.first;
+import static org.apache.zest.functional.Iterables.toList;
+
+/**
+ * JAVADOC
+ */
+public abstract class CompositeModel
+ implements VisitableHierarchy<Object, Object>, Dependencies, CompositeDescriptor
+{
+ protected final MixinsModel mixinsModel;
+ protected final CompositeMethodsModel compositeMethodsModel;
+ private final Set<Class<?>> types;
+ private final Visibility visibility;
+ private final MetaInfo metaInfo;
+ protected final StateModel stateModel;
+ protected Class<? extends Composite> proxyClass;
+ protected Constructor<? extends Composite> proxyConstructor;
+
+ protected CompositeModel( final Iterable<Class<?>> types,
+ final Visibility visibility,
+ final MetaInfo metaInfo,
+ final MixinsModel mixinsModel,
+ final StateModel stateModel,
+ final CompositeMethodsModel compositeMethodsModel
+ )
+ {
+ this.types = Iterables.addAll( new LinkedHashSet<Class<?>>(), types );
+ this.visibility = visibility;
+ this.metaInfo = metaInfo;
+ this.stateModel = stateModel;
+ this.compositeMethodsModel = compositeMethodsModel;
+ this.mixinsModel = mixinsModel;
+
+ // Create proxy class
+ createProxyClass();
+ }
+
+ // Model
+ @Override
+ public Iterable<Class<?>> types()
+ {
+ return types;
+ }
+
+ public StateModel state()
+ {
+ return stateModel;
+ }
+
+ @Override
+ public <T> T metaInfo( Class<T> infoType )
+ {
+ return metaInfo.get( infoType );
+ }
+
+ @Override
+ public Visibility visibility()
+ {
+ return visibility;
+ }
+
+ @Override
+ public boolean isAssignableTo( Class<?> type )
+ {
+ for( Class<?> aClass : types )
+ {
+ if( type.isAssignableFrom( aClass ) )
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public MixinsModel mixinsModel()
+ {
+ return mixinsModel;
+ }
+
+ @Override
+ @SuppressWarnings( { "raw", "unchecked" } )
+ public Class<?> primaryType()
+ {
+ Class primaryType = null;
+ for( Class type : mixinTypes() )
+ {
+ if( type.getName().equals( "scala.ScalaObject" ) )
+ {
+ continue;
+ }
+ if( primaryType == null )
+ {
+ primaryType = type;
+ }
+ else if( primaryType.isAssignableFrom( type ) )
+ {
+ primaryType = type;
+ }
+ }
+ return primaryType;
+ }
+
+ @Override
+ public Iterable<Class<?>> mixinTypes()
+ {
+ return mixinsModel.mixinTypes();
+ }
+
+ @Override
+ public Iterable<DependencyModel> dependencies()
+ {
+ return Iterables.flatten( mixinsModel.dependencies(), compositeMethodsModel.dependencies() );
+ }
+
+ @Override
+ public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> visitor )
+ throws ThrowableType
+ {
+ if( visitor.visitEnter( this ) )
+ {
+ if( compositeMethodsModel.accept( visitor ) )
+ {
+ if( stateModel.accept( visitor ) )
+ {
+ mixinsModel.accept( visitor );
+ }
+ }
+ }
+ return visitor.visitLeave( this );
+ }
+
+ @SuppressWarnings( { "raw", "unchecked" } )
+ private void createProxyClass()
+ {
+ Class<?> mainType = first( types );
+ if( mainType.isInterface() )
+ {
+ ClassLoader proxyClassloader = mainType.getClassLoader();
+
+ Class<?>[] interfaces = Iterables.toArray( Class.class, Iterables.<Class>cast( types ) );
+ proxyClass = (Class<? extends Composite>) ProxyGenerator.createProxyClass( proxyClassloader, interfaces );
+
+ try
+ {
+ proxyConstructor = proxyClass.getConstructor( InvocationHandler.class );
+ }
+ catch( NoSuchMethodException e )
+ {
+ throw (InvalidCompositeException) new InvalidCompositeException( "Could not get proxy constructor" ).initCause( e );
+ }
+ proxyConstructor.setAccessible( true );
+ }
+ else
+ {
+ try
+ {
+ proxyClass = new TransientClassLoader( getClass().getClassLoader() ).loadFragmentClass( mainType );
+ proxyConstructor = (Constructor<? extends Composite>) proxyClass.getConstructors()[ 0 ];
+ }
+ catch( ClassNotFoundException e )
+ {
+ throw (InvalidCompositeException) new InvalidCompositeException( "Could not get proxy constructor" ).initCause( e );
+ }
+ }
+ }
+
+ // Context
+ public final Object invoke( MixinsInstance mixins,
+ Object proxy,
+ Method method,
+ Object[] args,
+ ModuleSpi moduleInstance
+ )
+ throws Throwable
+ {
+ return compositeMethodsModel.invoke( mixins, proxy, method, args, moduleInstance );
+ }
+
+ public Composite newProxy( InvocationHandler invocationHandler )
+ throws ConstructionException
+ {
+ Class<?> mainType = first( types() );
+ if( mainType.isInterface() )
+ {
+
+ try
+ {
+ return Composite.class.cast( proxyConstructor.newInstance( invocationHandler ) );
+ }
+ catch( Exception e )
+ {
+ throw new ConstructionException( e );
+ }
+ }
+ else
+ {
+ try
+ {
+ Object[] args = new Object[ proxyConstructor.getParameterTypes().length ];
+ Composite composite = Composite.class.cast( proxyConstructor.newInstance( args ) );
+ proxyClass.getField( "_instance" ).set( composite, invocationHandler );
+ return composite;
+ }
+ catch( Exception e )
+ {
+ throw new ConstructionException( e );
+ }
+ }
+ }
+
+ @SuppressWarnings( "raw" )
+ public <T> T newProxy( InvocationHandler invocationHandler, Class<T> mixinType )
+ throws IllegalArgumentException
+ {
+
+// if (!matchesAny( isAssignableFrom( mixinType ), types ))
+ if( !mixinsModel.isImplemented( mixinType ) )
+ {
+ String message = "Composite " + primaryType().getName() + " does not implement type " + mixinType.getName();
+ throw new IllegalArgumentException( message );
+ }
+
+ // Instantiate proxy for given mixin interface
+ return mixinType.cast( newProxyInstance( mixinType.getClassLoader(), new Class[]{ mixinType }, invocationHandler ) );
+ }
+
+ @Override
+ public String toString()
+ {
+ return toList( types ).toString();
+ }
+}
\ 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/composite/ConcernModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConcernModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConcernModel.java
new file mode 100644
index 0000000..4de8f64
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConcernModel.java
@@ -0,0 +1,29 @@
+/*
+ * 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.composite;
+
+import org.apache.zest.api.concern.ConcernDescriptor;
+
+/**
+ * JAVADOC
+ */
+public final class ConcernModel extends AbstractModifierModel
+ implements ConcernDescriptor
+{
+ public ConcernModel( Class concernClass, Class instantiationClass )
+ {
+ super( concernClass, instantiationClass );
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConcernsInstance.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConcernsInstance.java b/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConcernsInstance.java
new file mode 100644
index 0000000..eeecc8f
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConcernsInstance.java
@@ -0,0 +1,64 @@
+/*
+ * 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.composite;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * JAVADOC
+ */
+public final class ConcernsInstance
+ implements InvocationHandler
+{
+ private final InvocationHandler firstConcern;
+ private final FragmentInvocationHandler mixinInvocationHandler;
+ private final ProxyReferenceInvocationHandler proxyHandler;
+
+ public ConcernsInstance( InvocationHandler firstConcern,
+ FragmentInvocationHandler mixinInvocationHandler,
+ ProxyReferenceInvocationHandler proxyHandler
+ )
+ {
+ this.firstConcern = firstConcern;
+ this.mixinInvocationHandler = mixinInvocationHandler;
+ this.proxyHandler = proxyHandler;
+ }
+
+ public boolean isEmpty()
+ {
+ return firstConcern == mixinInvocationHandler;
+ }
+
+ @Override
+ public Object invoke( Object proxy, Method method, Object[] params )
+ throws Throwable
+ {
+ proxyHandler.setProxy( proxy );
+ try
+ {
+ return firstConcern.invoke( proxy, method, params );
+ }
+ catch( InvocationTargetException e )
+ {
+ throw e.getTargetException();
+ }
+ finally
+ {
+ proxyHandler.clearProxy();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConcernsModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConcernsModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConcernsModel.java
new file mode 100644
index 0000000..22092fc
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConcernsModel.java
@@ -0,0 +1,83 @@
+/*
+ * 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.composite;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.List;
+import org.apache.zest.api.concern.ConcernsDescriptor;
+import org.apache.zest.functional.HierarchicalVisitor;
+import org.apache.zest.functional.Iterables;
+import org.apache.zest.functional.VisitableHierarchy;
+import org.apache.zest.runtime.injection.Dependencies;
+import org.apache.zest.runtime.injection.DependencyModel;
+import org.apache.zest.spi.module.ModuleSpi;
+
+/**
+ * JAVADOC
+ */
+public final class ConcernsModel
+ implements ConcernsDescriptor, Dependencies, VisitableHierarchy<Object, Object>
+{
+ public static final ConcernsModel EMPTY_CONCERNS = new ConcernsModel( Collections.<ConcernModel>emptyList() );
+
+ private List<ConcernModel> concernsFor;
+
+ public ConcernsModel( List<ConcernModel> concernsFor )
+ {
+ this.concernsFor = concernsFor;
+ }
+
+ @Override
+ public Iterable<DependencyModel> dependencies()
+ {
+ return Iterables.flattenIterables( Iterables.map( Dependencies.DEPENDENCIES_FUNCTION, concernsFor ) );
+ }
+
+ // Context
+ public ConcernsInstance newInstance( Method method, ModuleSpi moduleInstance,
+ FragmentInvocationHandler mixinInvocationHandler
+ )
+ {
+ ProxyReferenceInvocationHandler proxyHandler = new ProxyReferenceInvocationHandler();
+ InvocationHandler nextConcern = mixinInvocationHandler;
+ for( int i = concernsFor.size() - 1; i >= 0; i-- )
+ {
+ ConcernModel concernModel = concernsFor.get( i );
+
+ nextConcern = concernModel.newInstance( moduleInstance, nextConcern, proxyHandler, method );
+ }
+
+ return new ConcernsInstance( nextConcern, mixinInvocationHandler, proxyHandler );
+ }
+
+ @Override
+ public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> modelVisitor )
+ throws ThrowableType
+ {
+ if( modelVisitor.visitEnter( this ) )
+ {
+ for( ConcernModel concernModel : concernsFor )
+ {
+ if( !concernModel.accept( modelVisitor ) )
+ {
+ break;
+ }
+ }
+ }
+ return modelVisitor.visitLeave( this );
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstraintDeclaration.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstraintDeclaration.java b/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstraintDeclaration.java
new file mode 100644
index 0000000..18184cc
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstraintDeclaration.java
@@ -0,0 +1,69 @@
+/*
+ * 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.composite;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import org.apache.zest.api.constraint.Constraint;
+import org.apache.zest.api.util.Classes;
+
+/**
+ * JAVADOC
+ */
+public final class ConstraintDeclaration
+{
+ private final Class<? extends Constraint<?, ?>> constraintClass;
+ @SuppressWarnings( "raw" )
+ private final Class constraintAnnotationType;
+ private final Type constraintValueType;
+
+ @SuppressWarnings( "unchecked" )
+ public ConstraintDeclaration( Class<? extends Constraint<?, ?>> constraintClass )
+ {
+ this.constraintClass = constraintClass;
+
+ constraintAnnotationType = (Class<? extends Annotation>) ( (ParameterizedType) constraintClass.getGenericInterfaces()[ 0 ] )
+ .getActualTypeArguments()[ 0 ];
+ constraintValueType = ( (ParameterizedType) constraintClass.getGenericInterfaces()[ 0 ] ).getActualTypeArguments()[ 1 ];
+ }
+
+ public Class<? extends Constraint<?, ?>> constraintClass()
+ {
+ return constraintClass;
+ }
+
+ @SuppressWarnings( {"raw", "unchecked"} )
+ public boolean appliesTo( Class annotationType, Type valueType )
+ {
+ if( constraintValueType instanceof Class )
+ {
+ Class constraintValueClass = (Class) constraintValueType;
+ Class valueClass = Classes.RAW_CLASS.map( valueType );
+ return constraintAnnotationType.equals( annotationType ) && constraintValueClass.isAssignableFrom( valueClass );
+ }
+ else if( constraintValueType instanceof ParameterizedType )
+ {
+ // TODO Handle nested generics
+ Class constraintValueClass = Classes.RAW_CLASS.map( constraintValueType );
+ Class valueClass = Classes.RAW_CLASS.map( valueType );
+ return constraintAnnotationType.equals( annotationType ) && constraintValueClass.isAssignableFrom( valueClass );
+ }
+ else
+ {
+ return false; // TODO Handles more cases. What are they?
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstraintInstance.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstraintInstance.java b/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstraintInstance.java
new file mode 100644
index 0000000..3f855be
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstraintInstance.java
@@ -0,0 +1,43 @@
+/*
+ * 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.composite;
+
+import java.lang.annotation.Annotation;
+import org.apache.zest.api.constraint.Constraint;
+
+/**
+ * JAVADOC
+ */
+public final class ConstraintInstance<A extends Annotation, T>
+{
+ private final Constraint<A, T> constraint;
+ private final A annotation;
+
+ public ConstraintInstance( Constraint<A, T> constraint, A annotation )
+ {
+ this.constraint = constraint;
+ this.annotation = annotation;
+ }
+
+ public A annotation()
+ {
+ return annotation;
+ }
+
+ public boolean isValid( T value )
+ {
+ return constraint.isValid( annotation, value );
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstraintModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstraintModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstraintModel.java
new file mode 100644
index 0000000..f73f8d7
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstraintModel.java
@@ -0,0 +1,49 @@
+/*
+ * 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.composite;
+
+import java.lang.annotation.Annotation;
+import org.apache.zest.api.common.ConstructionException;
+import org.apache.zest.api.constraint.Constraint;
+
+/**
+ * JAVADOC
+ */
+public final class ConstraintModel
+ extends AbstractConstraintModel
+{
+ private final Class<? extends Constraint<?, ?>> constraintClass;
+
+ public ConstraintModel( Annotation annotation, Class<? extends Constraint<?, ?>> constraintClass )
+ {
+ super( annotation );
+ this.constraintClass = constraintClass;
+ }
+
+ @Override
+ @SuppressWarnings( "unchecked" )
+ public ConstraintInstance<?, ?> newInstance()
+ {
+ try
+ {
+ Constraint<?, ?> constraint = constraintClass.newInstance();
+ return new ConstraintInstance( constraint, annotation );
+ }
+ catch( Exception e )
+ {
+ throw new ConstructionException( "Could not instantiate constraint implementation", e );
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstraintsCheck.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstraintsCheck.java b/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstraintsCheck.java
new file mode 100644
index 0000000..096c8cd
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstraintsCheck.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.composite;
+
+import org.apache.zest.api.constraint.ConstraintViolationException;
+
+/**
+ * Call this to perform a value constraint check
+ */
+public interface ConstraintsCheck
+{
+ public void checkConstraints( Object value )
+ throws ConstraintViolationException;
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstraintsInstance.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstraintsInstance.java b/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstraintsInstance.java
new file mode 100644
index 0000000..4e3b313
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstraintsInstance.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2008, Rickard Öberg. All Rights Reserved.
+ * Copyright (c) 2009, 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.composite;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.zest.api.composite.Composite;
+import org.apache.zest.api.composite.CompositeInstance;
+import org.apache.zest.api.constraint.ConstraintViolation;
+import org.apache.zest.api.constraint.ConstraintViolationException;
+
+import static org.apache.zest.functional.Iterables.iterable;
+
+/**
+ * JAVADOC
+ */
+public final class ConstraintsInstance
+{
+ private final List<ValueConstraintsInstance> valueConstraintsInstances;
+
+ public ConstraintsInstance( List<ValueConstraintsInstance> parameterConstraints )
+ {
+ valueConstraintsInstances = parameterConstraints;
+ }
+
+ @SuppressWarnings( "unchecked" )
+ public void checkValid( Object instance, Method method, Object[] params )
+ throws ConstraintViolationException
+ {
+ if( valueConstraintsInstances.isEmpty() )
+ {
+ return; // No constraints to check
+ }
+
+ // Check constraints
+ List<ConstraintViolation> violations = null;
+ for( int i = 0; i < params.length; i++ )
+ {
+ Object param = params[ i ];
+ List<ConstraintViolation> paramViolations = valueConstraintsInstances.get( i ).checkConstraints( param );
+ if( !paramViolations.isEmpty() )
+ {
+ if( violations == null )
+ {
+ violations = new ArrayList<>();
+ }
+ violations.addAll( paramViolations );
+ }
+ }
+
+ // Check if any constraint failed
+ if( violations != null )
+ {
+ if( instance instanceof Composite )
+ {
+ throw new ConstraintViolationException( (Composite) instance, method, violations );
+ }
+ if( instance instanceof CompositeInstance )
+ {
+ throw new ConstraintViolationException( (Composite) ( (CompositeInstance) instance ).proxy(), method, violations );
+ }
+ Iterable<? extends Class<?>> types = iterable( instance.getClass() );
+ throw new ConstraintViolationException( instance.toString(), (Iterable<Class<?>>) types, method, violations );
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstraintsModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstraintsModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstraintsModel.java
new file mode 100644
index 0000000..0ea5139
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstraintsModel.java
@@ -0,0 +1,76 @@
+/*
+ * 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.composite;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.apache.zest.api.constraint.ConstraintsDescriptor;
+import org.apache.zest.functional.HierarchicalVisitor;
+import org.apache.zest.functional.VisitableHierarchy;
+
+/**
+ * JAVADOC
+ */
+public final class ConstraintsModel
+ implements ConstraintsDescriptor, VisitableHierarchy<Object, Object>
+{
+ private List<ValueConstraintsModel> parameterConstraintModels;
+
+ private static ConstraintsInstance EMPTY_CONSTRAINTS = new ConstraintsInstance( Collections.<ValueConstraintsInstance>emptyList() );
+
+ public ConstraintsModel( List<ValueConstraintsModel> parameterConstraintModels )
+ {
+ this.parameterConstraintModels = parameterConstraintModels;
+ }
+
+ public ConstraintsInstance newInstance()
+ {
+ if( parameterConstraintModels.isEmpty() )
+ {
+ return EMPTY_CONSTRAINTS;
+ }
+ else
+ {
+ List<ValueConstraintsInstance> parameterConstraintsInstances = new ArrayList<ValueConstraintsInstance>( parameterConstraintModels
+ .size() );
+ for( ValueConstraintsModel parameterConstraintModel : parameterConstraintModels )
+ {
+ parameterConstraintsInstances.add( parameterConstraintModel.newInstance() );
+ }
+ return new ConstraintsInstance( parameterConstraintsInstances );
+ }
+ }
+
+ @Override
+ public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> modelVisitor )
+ throws ThrowableType
+ {
+ if( modelVisitor.visitEnter( this ) )
+ {
+ if( parameterConstraintModels != null )
+ {
+ for( ValueConstraintsModel parameterConstraintModel : parameterConstraintModels )
+ {
+ if( !parameterConstraintModel.accept( modelVisitor ) )
+ {
+ break;
+ }
+ }
+ }
+ }
+ return modelVisitor.visitLeave( this );
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstructorModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstructorModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstructorModel.java
new file mode 100644
index 0000000..e78481f
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstructorModel.java
@@ -0,0 +1,105 @@
+/*
+ * 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.composite;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
+import org.apache.zest.api.common.ConstructionException;
+import org.apache.zest.api.composite.ConstructorDescriptor;
+import org.apache.zest.api.composite.InvalidCompositeException;
+import org.apache.zest.functional.HierarchicalVisitor;
+import org.apache.zest.functional.VisitableHierarchy;
+import org.apache.zest.runtime.injection.DependencyModel;
+import org.apache.zest.runtime.injection.InjectedParametersModel;
+import org.apache.zest.runtime.injection.InjectionContext;
+
+/**
+ * JAVADOC
+ */
+public final class ConstructorModel
+ implements ConstructorDescriptor, VisitableHierarchy<Object, Object>
+{
+ private Constructor<?> constructor;
+
+ private InjectedParametersModel parameters;
+
+ public ConstructorModel( Constructor<?> constructor, InjectedParametersModel parameters )
+ {
+ this.constructor = constructor;
+ this.parameters = parameters;
+ this.constructor.setAccessible( true );
+ }
+
+ @Override
+ public Constructor<?> constructor()
+ {
+ return constructor;
+ }
+
+ public Iterable<DependencyModel> dependencies()
+ {
+ return parameters.dependencies();
+ }
+
+ @Override
+ public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> modelVisitor )
+ throws ThrowableType
+ {
+ if( modelVisitor.visitEnter( this ) )
+ {
+ parameters.accept( modelVisitor );
+ }
+
+ return modelVisitor.visitLeave( this );
+ }
+
+ // Context
+
+ public Object newInstance( InjectionContext context )
+ throws ConstructionException
+ {
+ // Create parameters
+ Object[] parametersInstance = parameters.newParametersInstance( context );
+ // Invoke constructor
+ try
+ {
+ return constructor.newInstance( parametersInstance );
+ }
+ catch( InvocationTargetException e )
+ {
+ Throwable targetException = e.getTargetException();
+ if( targetException instanceof InvalidCompositeException )
+ {
+ throw (InvalidCompositeException) targetException;
+ }
+ String message = "Could not instantiate \n " + constructor.getDeclaringClass() + "\nusing constructor:\n " + constructor
+ .toGenericString();
+ throw new ConstructionException( message, targetException );
+ }
+ catch( Throwable e )
+ {
+ System.err.println( constructor.toGenericString() );
+ System.err.println( Arrays.asList( parametersInstance ) );
+ throw new ConstructionException( "Could not instantiate " + constructor.getDeclaringClass(), e );
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ return constructor.toGenericString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstructorsModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstructorsModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstructorsModel.java
new file mode 100644
index 0000000..4b14cc3
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/composite/ConstructorsModel.java
@@ -0,0 +1,301 @@
+/*
+ * 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.composite;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import org.apache.zest.api.common.ConstructionException;
+import org.apache.zest.api.composite.CompositeDescriptor;
+import org.apache.zest.api.composite.InvalidCompositeException;
+import org.apache.zest.api.injection.InjectionScope;
+import org.apache.zest.api.injection.scope.Uses;
+import org.apache.zest.api.util.Annotations;
+import org.apache.zest.api.util.Classes;
+import org.apache.zest.bootstrap.BindingException;
+import org.apache.zest.functional.Function;
+import org.apache.zest.functional.HierarchicalVisitor;
+import org.apache.zest.functional.HierarchicalVisitorAdapter;
+import org.apache.zest.functional.Iterables;
+import org.apache.zest.functional.Specifications;
+import org.apache.zest.functional.VisitableHierarchy;
+import org.apache.zest.runtime.injection.Dependencies;
+import org.apache.zest.runtime.injection.DependencyModel;
+import org.apache.zest.runtime.injection.InjectedParametersModel;
+import org.apache.zest.runtime.injection.InjectionContext;
+import org.apache.zest.runtime.injection.ParameterizedTypeInstance;
+import org.apache.zest.runtime.model.Binder;
+import org.apache.zest.runtime.model.Resolution;
+
+import static org.apache.zest.functional.Iterables.filter;
+import static org.apache.zest.functional.Iterables.first;
+import static org.apache.zest.functional.Iterables.iterable;
+
+/**
+ * JAVADOC
+ */
+public final class ConstructorsModel
+ implements Binder, Dependencies, VisitableHierarchy<Object, Object>
+{
+ @SuppressWarnings( "raw" )
+ private final Class fragmentClass;
+ private final List<ConstructorModel> constructorModels;
+ private List<ConstructorModel> boundConstructors;
+
+ @SuppressWarnings( { "raw", "unchecked" } )
+ public ConstructorsModel( Class fragmentClass )
+ {
+ this.fragmentClass = fragmentClass;
+ validate( fragmentClass );
+ constructorModels = new ArrayList<>();
+ Constructor[] realConstructors = this.fragmentClass.getDeclaredConstructors();
+ Class injectionClass = FragmentClassLoader.getSourceClass( fragmentClass );
+ for( Constructor constructor : realConstructors )
+ {
+ constructor.setAccessible( true );
+ try
+ {
+ Constructor injectionConstructor = injectionClass.getDeclaredConstructor( constructor.getParameterTypes() );
+ injectionConstructor.setAccessible( true );
+ ConstructorModel constructorModel = newConstructorModel( this.fragmentClass, constructor,
+ injectionConstructor );
+ if( constructorModel != null )
+ {
+ constructorModels.add( constructorModel );
+ }
+ }
+ catch( NoSuchMethodException e )
+ {
+ // Ignore and continue
+ e.printStackTrace();
+ }
+ }
+ }
+
+ @SuppressWarnings( "raw" )
+ private void validate( Class fragmentClass )
+ {
+ // Ensure that the fragment class is not an inner class, in which case we should give a reasonable exception
+ if( fragmentClass.getDeclaringClass() == null )
+ {
+ return;
+ }
+ if( Modifier.isStatic( fragmentClass.getModifiers() ) )
+ {
+ return;
+ }
+ throw new InvalidCompositeException( "Inner classes can not be used. Use static nested classes instead: " + fragmentClass );
+ }
+
+ @Override
+ public Iterable<DependencyModel> dependencies()
+ {
+ Function<ConstructorModel, Iterable<DependencyModel>> constructorDependencies = new Function<ConstructorModel, Iterable<DependencyModel>>()
+ {
+ @Override
+ public Iterable<DependencyModel> map( ConstructorModel constructorModel )
+ {
+ return constructorModel.dependencies();
+ }
+ };
+
+ return Iterables.flattenIterables( Iterables.map( constructorDependencies, boundConstructors == null ? constructorModels : boundConstructors ) );
+ }
+
+ @SuppressWarnings( "raw" )
+ private ConstructorModel newConstructorModel( Class fragmentClass,
+ Constructor realConstructor,
+ Constructor injectedConstructor
+ )
+ {
+ int idx = 0;
+ InjectedParametersModel parameters = new InjectedParametersModel();
+ Annotation[][] parameterAnnotations = injectedConstructor.getParameterAnnotations();
+ for( Type type : injectedConstructor.getGenericParameterTypes() )
+ {
+ Annotation injectionAnnotation = first(
+ filter( Specifications.translate( Annotations.type(), Annotations.hasAnnotation( InjectionScope.class ) ), iterable( parameterAnnotations[ idx ] ) ) );
+
+ if( injectionAnnotation == null )
+ {
+ if( fragmentClass.getSuperclass().isMemberClass() )
+ {
+ injectionAnnotation = new Uses()
+ {
+ @Override
+ public Class<? extends Annotation> annotationType()
+ {
+ return Uses.class;
+ }
+ };
+ }
+ else
+ {
+ return null; // invalid constructor parameter
+ }
+ }
+
+ boolean optional = DependencyModel.isOptional( injectionAnnotation, parameterAnnotations[ idx ] );
+
+ Type genericType = type;
+ 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 typeArg = ( (ParameterizedType) genericType ).getActualTypeArguments()[ i ];
+ if( typeArg instanceof TypeVariable )
+ {
+ typeArg = Classes.resolveTypeVariable( (TypeVariable) typeArg, realConstructor.getDeclaringClass(), fragmentClass );
+ ( (ParameterizedType) genericType ).getActualTypeArguments()[ i ] = typeArg;
+ }
+ }
+ }
+
+ DependencyModel dependencyModel = new DependencyModel( injectionAnnotation, genericType, fragmentClass, optional,
+ parameterAnnotations[ idx ] );
+ parameters.addDependency( dependencyModel );
+ idx++;
+ }
+ return new ConstructorModel( realConstructor, parameters );
+ }
+
+ @Override
+ public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> visitor )
+ throws ThrowableType
+ {
+ if( visitor.visitEnter( this ) )
+ {
+ if( boundConstructors != null )
+ {
+ for( ConstructorModel constructorModel : boundConstructors )
+ {
+ if( !constructorModel.accept( visitor ) )
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ for( ConstructorModel constructorModel : constructorModels )
+ {
+ if( !constructorModel.accept( visitor ) )
+ {
+ break;
+ }
+ }
+ }
+ }
+ return visitor.visitLeave( this );
+ }
+
+ // Binding
+ @Override
+ public void bind( final Resolution resolution )
+ throws BindingException
+ {
+ boundConstructors = new ArrayList<>();
+ for( ConstructorModel constructorModel : constructorModels )
+ {
+ try
+ {
+ constructorModel.accept( new HierarchicalVisitorAdapter<Object, Object, BindingException>()
+ {
+ @Override
+ public boolean visit( Object visitor )
+ throws BindingException
+ {
+ if( visitor instanceof Binder )
+ {
+ ( (Binder) visitor ).bind( resolution );
+ }
+ return true;
+ }
+ } );
+ boundConstructors.add( constructorModel );
+ }
+ catch( Exception e )
+ {
+ // Ignore
+ e.printStackTrace();
+ }
+ }
+
+ if( boundConstructors.isEmpty() )
+ {
+ StringBuilder messageBuilder = new StringBuilder( "Found no constructor that could be bound: " );
+ if( resolution.model() instanceof CompositeDescriptor )
+ {
+ messageBuilder.append( fragmentClass.getName() )
+ .append( " in " )
+ .append( resolution.model().toString() );
+ }
+ else
+ {
+ messageBuilder.append( resolution.model().toString() );
+ }
+
+ if( messageBuilder.indexOf( "$" ) >= 0 )
+ {
+ // This could be ok if instance is created manually
+ return;
+// messageBuilder.append( "\nInner classes can not be used." );
+ }
+ String message = messageBuilder.toString();
+ throw new BindingException( message );
+ }
+
+ // Sort based on parameter count
+ Collections.sort( boundConstructors, new Comparator<ConstructorModel>()
+ {
+ @Override
+ public int compare( ConstructorModel o1, ConstructorModel o2 )
+ {
+ Integer model2ParametersCount = o2.constructor().getParameterTypes().length;
+ int model1ParametersCount = o1.constructor().getParameterTypes().length;
+ return model2ParametersCount.compareTo( model1ParametersCount );
+ }
+ } );
+ }
+
+ public Object newInstance( InjectionContext injectionContext )
+ {
+ // Try all bound constructors, in order
+ ConstructionException exception = null;
+ for( ConstructorModel constructorModel : boundConstructors )
+ {
+ try
+ {
+ return constructorModel.newInstance( injectionContext );
+ }
+ catch( ConstructionException e )
+ {
+ exception = e;
+ }
+ }
+
+ throw exception;
+ }
+}