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 2016/12/17 10:27:49 UTC
[13/81] [abbrv] [partial] zest-java git commit: ZEST-195 ;
Replace all "zest" with "polygene"
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/composite/AbstractModifierModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/AbstractModifierModel.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/AbstractModifierModel.java
new file mode 100644
index 0000000..4a00359
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/AbstractModifierModel.java
@@ -0,0 +1,184 @@
+/*
+ * 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.polygene.runtime.composite;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.stream.Stream;
+import org.apache.polygene.api.common.ConstructionException;
+import org.apache.polygene.api.structure.ModuleDescriptor;
+import org.apache.polygene.api.util.HierarchicalVisitor;
+import org.apache.polygene.api.util.VisitableHierarchy;
+import org.apache.polygene.runtime.injection.Dependencies;
+import org.apache.polygene.runtime.injection.DependencyModel;
+import org.apache.polygene.runtime.injection.InjectedFieldsModel;
+import org.apache.polygene.runtime.injection.InjectedMethodsModel;
+import org.apache.polygene.runtime.injection.InjectionContext;
+
+import static org.apache.polygene.api.util.Classes.RAW_CLASS;
+import static org.apache.polygene.api.util.Classes.interfacesOf;
+
+/**
+ * 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<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 = interfacesOf( declaredModifierClass )
+ .map( RAW_CLASS )
+ .distinct()
+ .toArray( size -> (Class<Class<?>>[]) Array.newInstance( componentType, size ) );
+ }
+
+ public Class<?> modifierClass()
+ {
+ return modifierClass;
+ }
+
+ @Override
+ @SuppressWarnings( "unchecked" )
+ public Stream<DependencyModel> dependencies()
+ {
+ Stream<? extends Dependencies> models = Stream.of( this.constructorsModel, injectedFieldsModel, injectedMethodsModel );
+ return models.flatMap( Dependencies::dependencies );
+ }
+
+ 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( ModuleDescriptor module,
+ InvocationHandler next,
+ ProxyReferenceInvocationHandler proxyHandler,
+ Method method
+ )
+ {
+ InjectionContext injectionContext = new InjectionContext( module, 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/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/composite/AtomicInstancePool.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/AtomicInstancePool.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/AtomicInstancePool.java
new file mode 100644
index 0000000..28ee8b2
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/AtomicInstancePool.java
@@ -0,0 +1,59 @@
+/*
+ * 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.polygene.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/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompactLevel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompactLevel.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompactLevel.java
new file mode 100644
index 0000000..5c44e98
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompactLevel.java
@@ -0,0 +1,41 @@
+/*
+ * 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.polygene.runtime.composite;
+
+/**
+ * Compaction Level of the StackTrace clenaup operation.
+ *
+ * <pre>
+ * <b>off</b> = Do not modify the stack trace.
+ * <b>proxy</b> = Remove all Polygene 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 Polygene internal and JDK internal classes from the entire stack.
+ * </pre>
+ *
+ * <p>
+ * The Compaction is set through the System Property "<code><b>polygene.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/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeConstraintModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeConstraintModel.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeConstraintModel.java
new file mode 100644
index 0000000..5345594
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeConstraintModel.java
@@ -0,0 +1,74 @@
+/*
+ * 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.polygene.runtime.composite;
+
+import java.lang.annotation.Annotation;
+import org.apache.polygene.api.common.ConstructionException;
+import org.apache.polygene.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/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeMethodInstance.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeMethodInstance.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeMethodInstance.java
new file mode 100644
index 0000000..1867bf1
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeMethodInstance.java
@@ -0,0 +1,83 @@
+/*
+ * 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.polygene.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/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeMethodModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeMethodModel.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeMethodModel.java
new file mode 100644
index 0000000..267c065
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeMethodModel.java
@@ -0,0 +1,324 @@
+/*
+ * 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.polygene.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 java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.apache.polygene.api.common.ConstructionException;
+import org.apache.polygene.api.composite.MethodDescriptor;
+import org.apache.polygene.api.structure.ModuleDescriptor;
+import org.apache.polygene.api.util.HierarchicalVisitor;
+import org.apache.polygene.api.util.NullArgumentException;
+import org.apache.polygene.api.util.VisitableHierarchy;
+import org.apache.polygene.runtime.injection.Dependencies;
+import org.apache.polygene.runtime.injection.DependencyModel;
+
+/**
+ * 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 Stream<DependencyModel> dependencies()
+ {
+ return Stream.of( this.concerns, sideEffects ).filter( Objects::nonNull ).flatMap( Dependencies::dependencies );
+ }
+
+ // Context
+ public Object invoke( Object composite, Object[] params, MixinsInstance mixins, ModuleDescriptor module )
+ throws Throwable
+ {
+ constraintsInstance.checkValid( composite, method, params );
+
+ CompositeMethodInstance methodInstance = getInstance( module );
+ try
+ {
+ return mixins.invoke( composite, params, methodInstance );
+ }
+ finally
+ {
+ instancePool.releaseInstance( methodInstance );
+ }
+ }
+
+ private CompositeMethodInstance getInstance( ModuleDescriptor module )
+ {
+ CompositeMethodInstance methodInstance = instancePool.obtainInstance();
+ if( methodInstance == null )
+ {
+ methodInstance = newCompositeMethodInstance( module );
+ }
+
+ return methodInstance;
+ }
+
+ private CompositeMethodInstance newCompositeMethodInstance( ModuleDescriptor module )
+ throws ConstructionException
+ {
+ FragmentInvocationHandler mixinInvocationHandler = mixins.newInvocationHandler( method );
+ InvocationHandler invoker = mixinInvocationHandler;
+ if( concerns != ConcernsModel.EMPTY_CONCERNS )
+ {
+ ConcernsInstance concernsInstance = concerns.newInstance( method, module, mixinInvocationHandler );
+ invoker = concernsInstance;
+ }
+ if( sideEffects != SideEffectsModel.EMPTY_SIDEEFFECTS )
+ {
+ SideEffectsInstance sideEffectsInstance = sideEffects.newInstance( method, module, 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 ).collect( Collectors.toList() );
+ }
+
+ 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( Genericpredicate.INSTANCE.test( 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( !Genericpredicate.INSTANCE.test( 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( !Genericpredicate.INSTANCE.test( 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/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeMethodsModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeMethodsModel.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeMethodsModel.java
new file mode 100644
index 0000000..8dc2495
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeMethodsModel.java
@@ -0,0 +1,134 @@
+/*
+ * 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.polygene.runtime.composite;
+
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.stream.Stream;
+import org.apache.polygene.api.composite.MissingMethodException;
+import org.apache.polygene.api.structure.ModuleDescriptor;
+import org.apache.polygene.api.util.HierarchicalVisitor;
+import org.apache.polygene.api.util.VisitableHierarchy;
+import org.apache.polygene.runtime.injection.Dependencies;
+import org.apache.polygene.runtime.injection.DependencyModel;
+
+/**
+ * Model for Composite methods. This includes both private and public methods.
+ */
+public final class CompositeMethodsModel
+ implements VisitableHierarchy<Object, Object>, Dependencies
+{
+ private final LinkedHashMap<Method, CompositeMethodModel> methods;
+ private final MixinsModel mixinsModel;
+
+ public CompositeMethodsModel( MixinsModel mixinsModel )
+ {
+ methods = new LinkedHashMap<>();
+ this.mixinsModel = mixinsModel;
+ }
+
+ public Stream<DependencyModel> dependencies()
+ {
+ Collection<CompositeMethodModel> compositeMethods = methods.values();
+ return compositeMethods.stream().flatMap( Dependencies.DEPENDENCIES_FUNCTION );
+ }
+
+ // Context
+ public Object invoke( MixinsInstance mixins,
+ Object proxy,
+ Method method,
+ Object[] args,
+ ModuleDescriptor moduleInstance
+ )
+ throws Throwable
+ {
+ CompositeMethodModel compositeMethod = methods.get( method );
+
+ if( compositeMethod == null )
+ {
+ if( method.getDeclaringClass().equals( Object.class ) )
+ {
+ return mixins.invokeObject( proxy, args, method );
+ }
+
+ // TODO: Figure out what was the intention of this code block, added by Rickard in 2009. It doesn't do anything useful.
+ if( !method.getDeclaringClass().isInterface() )
+ {
+ compositeMethod = mixinsModel.mixinTypes().map( aClass -> {
+ try
+ {
+ Method realMethod = aClass.getMethod( method.getName(), method.getParameterTypes() );
+ return methods.get( realMethod );
+ }
+ catch( NoSuchMethodException | SecurityException e )
+ {
+
+ }
+ return null;
+ }).filter( model -> model != null ).findFirst().orElse( null );
+ }
+ 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/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeModel.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeModel.java
new file mode 100644
index 0000000..2f1e81d
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/CompositeModel.java
@@ -0,0 +1,278 @@
+/*
+ * 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.polygene.runtime.composite;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Stream;
+import org.apache.polygene.api.common.ConstructionException;
+import org.apache.polygene.api.common.MetaInfo;
+import org.apache.polygene.api.common.Visibility;
+import org.apache.polygene.api.composite.Composite;
+import org.apache.polygene.api.composite.CompositeDescriptor;
+import org.apache.polygene.api.composite.InvalidCompositeException;
+import org.apache.polygene.api.structure.ModuleDescriptor;
+import org.apache.polygene.api.util.HierarchicalVisitor;
+import org.apache.polygene.api.util.VisitableHierarchy;
+import org.apache.polygene.runtime.injection.Dependencies;
+import org.apache.polygene.runtime.injection.DependencyModel;
+
+import static java.lang.reflect.Proxy.newProxyInstance;
+
+/**
+ * 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;
+ private volatile Class<?> primaryType;
+ protected Class<? extends Composite> proxyClass;
+ protected Constructor<? extends Composite> proxyConstructor;
+ protected ModuleDescriptor module;
+
+ protected CompositeModel( final ModuleDescriptor module,
+ final List<Class<?>> types,
+ final Visibility visibility,
+ final MetaInfo metaInfo,
+ final MixinsModel mixinsModel,
+ final StateModel stateModel,
+ final CompositeMethodsModel compositeMethodsModel
+ )
+ {
+ this.module = module;
+ this.types = new LinkedHashSet<>( types );
+ this.visibility = visibility;
+ this.metaInfo = metaInfo;
+ this.stateModel = stateModel;
+ this.compositeMethodsModel = compositeMethodsModel;
+ this.mixinsModel = mixinsModel;
+
+ // Create proxy class
+ createProxyClass();
+ primaryType = mixinTypes()
+ .reduce( null, ( primary, type ) ->
+ {
+ if( primary == null )
+ {
+ return type;
+ }
+ else if( primary.isAssignableFrom( type ) )
+ {
+ return type;
+ }
+ return primary;
+ } );
+ }
+
+ // Model
+ @Override
+ public Stream<Class<?>> types()
+ {
+ return types.stream();
+ }
+
+ 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()
+ {
+ return primaryType;
+ }
+
+ @Override
+ public Stream<Class<?>> mixinTypes()
+ {
+ return mixinsModel.mixinTypes();
+ }
+
+ @Override
+ public Stream<DependencyModel> dependencies()
+ {
+ Stream<Dependencies> models = Stream.of( this.mixinsModel, compositeMethodsModel );
+ return models.flatMap( Dependencies::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 = types.stream().findFirst().get();
+ if( mainType.isInterface() )
+ {
+ ClassLoader proxyClassloader = mainType.getClassLoader();
+
+ Class<?>[] interfaces = types.stream().map( Class.class::cast ).toArray( Class[]::new );
+ 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
+ )
+ throws Throwable
+ {
+ return compositeMethodsModel.invoke( mixins, proxy, method, args, module );
+ }
+
+ @Override
+ public ModuleDescriptor module()
+ {
+ return module;
+ }
+
+ public Composite newProxy( InvocationHandler invocationHandler )
+ throws ConstructionException
+ {
+ Class<?> mainType = types.stream().findFirst().get();
+ 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 types.toString();
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConcernModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConcernModel.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConcernModel.java
new file mode 100644
index 0000000..b583aaf
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConcernModel.java
@@ -0,0 +1,35 @@
+/*
+ * 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.polygene.runtime.composite;
+
+import org.apache.polygene.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/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConcernsInstance.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConcernsInstance.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConcernsInstance.java
new file mode 100644
index 0000000..da2fe20
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConcernsInstance.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.polygene.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/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConcernsModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConcernsModel.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConcernsModel.java
new file mode 100644
index 0000000..aa8d3ce
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConcernsModel.java
@@ -0,0 +1,89 @@
+/*
+ * 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.polygene.runtime.composite;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Stream;
+import org.apache.polygene.api.concern.ConcernsDescriptor;
+import org.apache.polygene.api.structure.ModuleDescriptor;
+import org.apache.polygene.api.util.HierarchicalVisitor;
+import org.apache.polygene.api.util.VisitableHierarchy;
+import org.apache.polygene.runtime.injection.Dependencies;
+import org.apache.polygene.runtime.injection.DependencyModel;
+
+/**
+ * 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 Stream<DependencyModel> dependencies()
+ {
+ return concernsFor.stream().flatMap( ConcernModel::dependencies );
+ }
+
+ // Context
+ public ConcernsInstance newInstance( Method method, ModuleDescriptor module,
+ 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( module, 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/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstraintDeclaration.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstraintDeclaration.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstraintDeclaration.java
new file mode 100644
index 0000000..9826681
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstraintDeclaration.java
@@ -0,0 +1,75 @@
+/*
+ * 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.polygene.runtime.composite;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import org.apache.polygene.api.constraint.Constraint;
+import org.apache.polygene.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.apply( valueType );
+ return constraintAnnotationType.equals( annotationType ) && constraintValueClass.isAssignableFrom( valueClass );
+ }
+ else if( constraintValueType instanceof ParameterizedType )
+ {
+ // TODO Handle nested generics
+ Class constraintValueClass = Classes.RAW_CLASS.apply( constraintValueType );
+ Class valueClass = Classes.RAW_CLASS.apply( 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/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstraintInstance.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstraintInstance.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstraintInstance.java
new file mode 100644
index 0000000..40645f9
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstraintInstance.java
@@ -0,0 +1,49 @@
+/*
+ * 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.polygene.runtime.composite;
+
+import java.lang.annotation.Annotation;
+import org.apache.polygene.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/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstraintModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstraintModel.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstraintModel.java
new file mode 100644
index 0000000..1452eeb
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstraintModel.java
@@ -0,0 +1,55 @@
+/*
+ * 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.polygene.runtime.composite;
+
+import java.lang.annotation.Annotation;
+import org.apache.polygene.api.common.ConstructionException;
+import org.apache.polygene.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/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstraintsCheck.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstraintsCheck.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstraintsCheck.java
new file mode 100644
index 0000000..1f72dc3
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstraintsCheck.java
@@ -0,0 +1,32 @@
+/*
+ * 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.polygene.runtime.composite;
+
+import org.apache.polygene.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/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstraintsInstance.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstraintsInstance.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstraintsInstance.java
new file mode 100644
index 0000000..23e8f98
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstraintsInstance.java
@@ -0,0 +1,84 @@
+/*
+ * 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.polygene.runtime.composite;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+import org.apache.polygene.api.composite.Composite;
+import org.apache.polygene.api.composite.CompositeInstance;
+import org.apache.polygene.api.constraint.ConstraintViolation;
+import org.apache.polygene.api.constraint.ConstraintViolationException;
+
+/**
+ * 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( ( (CompositeInstance) instance ).proxy(), method, violations );
+ }
+ Stream<Class<?>> types = Stream.of( instance.getClass() );
+ throw new ConstraintViolationException( instance.toString(), types, method, violations );
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstraintsModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstraintsModel.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstraintsModel.java
new file mode 100644
index 0000000..542217e
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstraintsModel.java
@@ -0,0 +1,82 @@
+/*
+ * 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.polygene.runtime.composite;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.apache.polygene.api.constraint.ConstraintsDescriptor;
+import org.apache.polygene.api.util.HierarchicalVisitor;
+import org.apache.polygene.api.util.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/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstructorModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstructorModel.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstructorModel.java
new file mode 100644
index 0000000..3df1ad5
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstructorModel.java
@@ -0,0 +1,112 @@
+/*
+ * 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.polygene.runtime.composite;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
+import java.util.stream.Stream;
+import org.apache.polygene.api.common.ConstructionException;
+import org.apache.polygene.api.composite.ConstructorDescriptor;
+import org.apache.polygene.api.composite.InvalidCompositeException;
+import org.apache.polygene.api.util.HierarchicalVisitor;
+import org.apache.polygene.api.util.VisitableHierarchy;
+import org.apache.polygene.runtime.injection.DependencyModel;
+import org.apache.polygene.runtime.injection.InjectedParametersModel;
+import org.apache.polygene.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 Stream<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/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstructorsModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstructorsModel.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstructorsModel.java
new file mode 100644
index 0000000..bc4be4a
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ConstructorsModel.java
@@ -0,0 +1,298 @@
+/*
+ * 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.polygene.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 java.util.stream.Stream;
+import org.apache.polygene.api.common.ConstructionException;
+import org.apache.polygene.api.composite.CompositeDescriptor;
+import org.apache.polygene.api.composite.InvalidCompositeException;
+import org.apache.polygene.api.injection.InjectionScope;
+import org.apache.polygene.api.injection.scope.Uses;
+import org.apache.polygene.api.util.Classes;
+import org.apache.polygene.api.util.HierarchicalVisitor;
+import org.apache.polygene.api.util.HierarchicalVisitorAdapter;
+import org.apache.polygene.api.util.VisitableHierarchy;
+import org.apache.polygene.bootstrap.BindingException;
+import org.apache.polygene.runtime.injection.Dependencies;
+import org.apache.polygene.runtime.injection.DependencyModel;
+import org.apache.polygene.runtime.injection.InjectedParametersModel;
+import org.apache.polygene.runtime.injection.InjectionContext;
+import org.apache.polygene.runtime.injection.ParameterizedTypeInstance;
+import org.apache.polygene.runtime.model.Binder;
+import org.apache.polygene.runtime.model.Resolution;
+
+import static org.apache.polygene.api.util.Annotations.typeHasAnnotation;
+
+/**
+ * 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 Stream<DependencyModel> dependencies()
+ {
+ if( boundConstructors == null )
+ {
+ return constructorModels.stream().flatMap( ConstructorModel::dependencies );
+ }
+ return boundConstructors.stream().flatMap( ConstructorModel::dependencies );
+ }
+
+ @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 = Stream.of( parameterAnnotations[ idx ] )
+ .filter( typeHasAnnotation( InjectionScope.class ) )
+ .findFirst().orElse( null );
+
+ 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;
+ }
+}