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:47 UTC
[11/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/StateResolver.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/StateResolver.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/StateResolver.java
new file mode 100644
index 0000000..64bc165
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/StateResolver.java
@@ -0,0 +1,40 @@
+/*
+ * 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.Map;
+import java.util.stream.Stream;
+import org.apache.polygene.api.association.AssociationDescriptor;
+import org.apache.polygene.api.entity.EntityReference;
+import org.apache.polygene.api.property.PropertyDescriptor;
+
+/**
+ * StateResolver.
+ */
+public interface StateResolver
+{
+ Object getPropertyState( PropertyDescriptor propertyDescriptor );
+
+ EntityReference getAssociationState( AssociationDescriptor associationDescriptor );
+
+ Stream<EntityReference> getManyAssociationState( AssociationDescriptor associationDescriptor );
+
+ Stream<Map.Entry<String, EntityReference>> getNamedAssociationState( AssociationDescriptor associationDescriptor );
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/composite/SynchronizedCompositeMethodInstancePool.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/SynchronizedCompositeMethodInstancePool.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/SynchronizedCompositeMethodInstancePool.java
new file mode 100644
index 0000000..01025cf
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/SynchronizedCompositeMethodInstancePool.java
@@ -0,0 +1,50 @@
+/*
+ * 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;
+
+/**
+ * Method instance pool that keeps a linked list. Uses synchronization
+ * to ensure that instances are acquired and returned in a thread-safe
+ * manner.
+ */
+public final class SynchronizedCompositeMethodInstancePool
+ implements InstancePool<CompositeMethodInstance>
+{
+ private CompositeMethodInstance first = null;
+
+ @Override
+ public synchronized CompositeMethodInstance obtainInstance()
+ {
+ CompositeMethodInstance instance = first;
+ if( instance != null )
+ {
+ first = instance.getNext();
+ }
+ return instance;
+ }
+
+ @Override
+ public synchronized void releaseInstance( CompositeMethodInstance instance )
+ {
+ instance.setNext( first );
+ first = instance;
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/composite/TransientBuilderInstance.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/TransientBuilderInstance.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/TransientBuilderInstance.java
new file mode 100644
index 0000000..a622a57
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/TransientBuilderInstance.java
@@ -0,0 +1,102 @@
+/*
+ * 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.common.ConstructionException;
+import org.apache.polygene.api.composite.CompositeInstance;
+import org.apache.polygene.api.composite.TransientBuilder;
+import org.apache.polygene.api.composite.TransientDescriptor;
+import org.apache.polygene.runtime.property.PropertyInstance;
+
+/**
+ * JAVADOC
+ */
+public final class TransientBuilderInstance<T>
+ implements TransientBuilder<T>
+{
+ private TransientModel model;
+
+ // lazy initialized in accessor
+ private UsesInstance uses = UsesInstance.EMPTY_USES;
+
+ // lazy initialized in accessor
+ private CompositeInstance prototypeInstance;
+
+ private TransientStateInstance state;
+
+ public TransientBuilderInstance( TransientDescriptor model,
+ TransientStateInstance state,
+ UsesInstance uses
+ )
+ {
+ this.model = (TransientModel) model;
+ this.state = state;
+ this.uses = uses;
+ }
+
+ @Override
+ public TransientBuilder<T> use( Object... usedObjects )
+ {
+ uses = uses.use( usedObjects );
+ return this;
+ }
+
+ @Override
+ public T prototype()
+ {
+ // Instantiate given value type
+ if( prototypeInstance == null )
+ {
+ prototypeInstance = model.newInstance( uses, state );
+ }
+
+ return prototypeInstance.<T>proxy();
+ }
+
+ @Override
+ public <K> K prototypeFor( Class<K> mixinType )
+ {
+ // Instantiate given value type
+ if( prototypeInstance == null )
+ {
+ prototypeInstance = model.newInstance( uses, state );
+ }
+
+ return prototypeInstance.newProxy( mixinType );
+ }
+
+ @Override
+ public T newInstance()
+ throws ConstructionException
+ {
+ // Set correct info's (immutable) on the state
+ model.state().properties()
+ .forEach(
+ propertyDescriptor ->
+ ( (PropertyInstance<Object>) state.propertyFor( propertyDescriptor.accessor() ) )
+ .setPropertyInfo( propertyDescriptor ) );
+
+ model.checkConstraints( state );
+
+ CompositeInstance compositeInstance = model.newInstance( uses, state );
+ return compositeInstance.<T>proxy();
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/composite/TransientClassLoader.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/TransientClassLoader.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/TransientClassLoader.java
new file mode 100644
index 0000000..c909e33
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/TransientClassLoader.java
@@ -0,0 +1,789 @@
+/*
+ * 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.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.polygene.api.entity.Lifecycle;
+import org.apache.polygene.api.mixin.Initializable;
+import org.apache.polygene.api.util.Methods;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+import static org.apache.polygene.api.util.Classes.RAW_CLASS;
+import static org.apache.polygene.api.util.Classes.interfacesOf;
+import static org.objectweb.asm.Opcodes.AASTORE;
+import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
+import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
+import static org.objectweb.asm.Opcodes.ACC_STATIC;
+import static org.objectweb.asm.Opcodes.ACC_SUPER;
+import static org.objectweb.asm.Opcodes.ACONST_NULL;
+import static org.objectweb.asm.Opcodes.ALOAD;
+import static org.objectweb.asm.Opcodes.ANEWARRAY;
+import static org.objectweb.asm.Opcodes.ARETURN;
+import static org.objectweb.asm.Opcodes.ASTORE;
+import static org.objectweb.asm.Opcodes.ATHROW;
+import static org.objectweb.asm.Opcodes.BIPUSH;
+import static org.objectweb.asm.Opcodes.CHECKCAST;
+import static org.objectweb.asm.Opcodes.DLOAD;
+import static org.objectweb.asm.Opcodes.DRETURN;
+import static org.objectweb.asm.Opcodes.DUP;
+import static org.objectweb.asm.Opcodes.FLOAD;
+import static org.objectweb.asm.Opcodes.FRETURN;
+import static org.objectweb.asm.Opcodes.GETFIELD;
+import static org.objectweb.asm.Opcodes.GETSTATIC;
+import static org.objectweb.asm.Opcodes.GOTO;
+import static org.objectweb.asm.Opcodes.ICONST_0;
+import static org.objectweb.asm.Opcodes.ICONST_1;
+import static org.objectweb.asm.Opcodes.ICONST_2;
+import static org.objectweb.asm.Opcodes.ICONST_3;
+import static org.objectweb.asm.Opcodes.ICONST_4;
+import static org.objectweb.asm.Opcodes.ICONST_5;
+import static org.objectweb.asm.Opcodes.ILOAD;
+import static org.objectweb.asm.Opcodes.INVOKEINTERFACE;
+import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
+import static org.objectweb.asm.Opcodes.INVOKESTATIC;
+import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
+import static org.objectweb.asm.Opcodes.IRETURN;
+import static org.objectweb.asm.Opcodes.LLOAD;
+import static org.objectweb.asm.Opcodes.LRETURN;
+import static org.objectweb.asm.Opcodes.POP;
+import static org.objectweb.asm.Opcodes.PUTSTATIC;
+import static org.objectweb.asm.Opcodes.RETURN;
+import static org.objectweb.asm.Type.getInternalName;
+
+/**
+ * Generate subclasses of classes used for transients. All methods delegate to CompositeInvoker.
+ */
+@SuppressWarnings( "raw" )
+/* package */ final class TransientClassLoader
+ extends ClassLoader
+{
+ private static final int JDK_VERSION;
+ public static final String GENERATED_POSTFIX = "_Proxy";
+
+ static
+ {
+ String jdkString = System.getProperty( "java.specification.version" );
+ switch( jdkString )
+ {
+ case "1.8":
+ JDK_VERSION = Opcodes.V1_8;
+ break;
+ case "1.7":
+ default:
+ JDK_VERSION = Opcodes.V1_7;
+ break;
+ }
+ }
+
+ /* package */ TransientClassLoader( ClassLoader parent )
+ {
+ super( parent );
+ }
+
+ @Override
+ protected Class findClass( String name )
+ throws ClassNotFoundException
+ {
+ if( name.endsWith( GENERATED_POSTFIX ) )
+ {
+ Class baseClass;
+ String baseName = name.substring( 0, name.length() - 6 );
+ try
+ {
+ baseClass = loadClass( baseName );
+ }
+ catch( ClassNotFoundException e )
+ {
+ // Try replacing the last _ with $
+ while( true )
+ {
+ int idx = baseName.lastIndexOf( "_" );
+ if( idx != -1 )
+ {
+ baseName = baseName.substring( 0, idx ) + "$" + baseName.substring( idx + 1 );
+ try
+ {
+ baseClass = loadClass( baseName );
+ break;
+ }
+ catch( ClassNotFoundException e1 )
+ {
+ // Try again
+ }
+ }
+ else
+ {
+ throw e;
+ }
+ }
+ }
+
+ byte[] b = generateClass( name, baseClass );
+ return defineClass( name, b, 0, b.length, baseClass.getProtectionDomain() );
+ }
+
+ // Try the classloader of this classloader -> get classes in Polygene such as CompositeInvoker
+ return getClass().getClassLoader().loadClass( name );
+ }
+
+ public static byte[] generateClass( String name, Class baseClass )
+ throws ClassNotFoundException
+ {
+ String classSlash = name.replace( '.', '/' );
+ String baseClassSlash = getInternalName( baseClass );
+
+ ClassWriter cw = new ClassWriter( ClassWriter.COMPUTE_MAXS );
+
+ // Class definition start
+ cw.visit( JDK_VERSION, ACC_PUBLIC + ACC_SUPER, classSlash, null, baseClassSlash, new String[] { "org/apache/zest/api/composite/Composite" } );
+
+ // Composite reference
+ {
+ cw.visitField( ACC_PUBLIC, "_instance", "Lorg/apache/polygene/api/composite/CompositeInvoker;", null, null )
+ .visitEnd();
+ }
+
+ // Static Method references
+ {
+ int idx = 1;
+ for( Method method : baseClass.getMethods() )
+ {
+ if( isOverloaded( method, baseClass ) )
+ {
+ cw.visitField( ACC_PRIVATE + ACC_STATIC, "m" + idx++, "Ljava/lang/reflect/Method;", null, null )
+ .visitEnd();
+ }
+ }
+ }
+
+ // Constructors
+ for( Constructor constructor : baseClass.getDeclaredConstructors() )
+ {
+ if( Modifier.isPublic( constructor.getModifiers() ) || Modifier.isProtected( constructor.getModifiers() ) )
+ {
+ String desc = org.objectweb.asm.commons.Method.getMethod( constructor ).getDescriptor();
+ MethodVisitor mv = cw.visitMethod( ACC_PUBLIC, "<init>", desc, null, null );
+ mv.visitCode();
+ mv.visitVarInsn( ALOAD, 0 );
+
+ int idx = 1;
+ for( Class aClass : constructor.getParameterTypes() )
+ {
+ // TODO Handle other types than objects (?)
+ mv.visitVarInsn( ALOAD, idx++ );
+ }
+
+ mv.visitMethodInsn( INVOKESPECIAL, baseClassSlash, "<init>", desc, false );
+ mv.visitInsn( RETURN );
+ mv.visitMaxs( idx, idx );
+ mv.visitEnd();
+ }
+ }
+
+ // Overloaded and unimplemented methods
+ Method[] methods = baseClass.getMethods();
+ int idx = 0;
+ List<Label> exceptionLabels = new ArrayList<>();
+ for( Method method : methods )
+ {
+ if( isOverloaded( method, baseClass ) )
+ {
+ idx++;
+ String methodName = method.getName();
+ String desc = org.objectweb.asm.commons.Method.getMethod( method ).getDescriptor();
+
+ String[] exceptions = null;
+ {
+ MethodVisitor mv = cw.visitMethod( ACC_PUBLIC, methodName, desc, null, exceptions );
+ if( isInternalPolygeneMethod( method, baseClass ) )
+ {
+ // generate a NoOp method...
+ mv.visitInsn( RETURN );
+ }
+ else
+ {
+ Label endLabel = null; // Use this if return type is void
+ if( method.getExceptionTypes().length > 0 )
+ {
+ exceptions = new String[ method.getExceptionTypes().length ];
+ for( int i = 0; i < method.getExceptionTypes().length; i++ )
+ {
+ Class<?> aClass = method.getExceptionTypes()[ i ];
+ exceptions[ i ] = getInternalName( aClass );
+ }
+ }
+ mv.visitCode();
+ Label l0 = new Label();
+ Label l1 = new Label();
+
+ exceptionLabels.clear();
+ for( Class<?> declaredException : method.getExceptionTypes() )
+ {
+ Label ld = new Label();
+ mv.visitTryCatchBlock( l0, l1, ld, getInternalName( declaredException ) );
+ exceptionLabels.add( ld ); // Reuse this further down for the catch
+ }
+
+ Label lruntime = new Label();
+ mv.visitTryCatchBlock( l0, l1, lruntime, "java/lang/RuntimeException" );
+ Label lerror = new Label();
+ mv.visitTryCatchBlock( l0, l1, lerror, "java/lang/Throwable" );
+
+ mv.visitLabel( l0 );
+ mv.visitVarInsn( ALOAD, 0 );
+ mv.visitFieldInsn( GETFIELD, classSlash, "_instance",
+ "Lorg/apache/polygene/api/composite/CompositeInvoker;" );
+ mv.visitFieldInsn( GETSTATIC, classSlash, "m" + idx, "Ljava/lang/reflect/Method;" );
+
+ int paramCount = method.getParameterTypes().length;
+ int stackIdx = 0;
+ if( paramCount == 0 )
+ {
+ // Send in null as parameter
+ mv.visitInsn( ACONST_NULL );
+ }
+ else
+ {
+ insn( mv, paramCount );
+ mv.visitTypeInsn( ANEWARRAY, "java/lang/Object" );
+ int pidx = 0;
+ for( Class<?> aClass : method.getParameterTypes() )
+ {
+ mv.visitInsn( DUP );
+ insn( mv, pidx++ );
+ stackIdx = wrapParameter( mv, aClass, stackIdx + 1 );
+ mv.visitInsn( AASTORE );
+ }
+ }
+
+ // Call method
+ mv.visitMethodInsn( INVOKEINTERFACE, "org/apache/zest/api/composite/CompositeInvoker",
+ "invokeComposite",
+ "(Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;", true );
+
+ // Return value
+ if( !method.getReturnType().equals( Void.TYPE ) )
+ {
+ unwrapResult( mv, method.getReturnType(), l1 );
+ }
+ else
+ {
+ mv.visitInsn( POP );
+ mv.visitLabel( l1 );
+ endLabel = new Label();
+ mv.visitJumpInsn( GOTO, endLabel );
+ }
+
+ // Increase stack to beyond method args
+ stackIdx++;
+
+ // Declared exceptions
+ int exceptionIdx = 0;
+ for( Class<?> aClass : method.getExceptionTypes() )
+ {
+ mv.visitLabel( exceptionLabels.get( exceptionIdx++ ) );
+ mv.visitFrame( Opcodes.F_SAME1, 0, null, 1, new Object[]{ getInternalName( aClass ) } );
+ mv.visitVarInsn( ASTORE, stackIdx );
+ mv.visitVarInsn( ALOAD, stackIdx );
+ mv.visitInsn( ATHROW );
+ }
+
+ // RuntimeException and Error catch-all
+ mv.visitLabel( lruntime );
+ mv.visitFrame( Opcodes.F_SAME1, 0, null, 1, new Object[]{ "java/lang/RuntimeException" } );
+ mv.visitVarInsn( ASTORE, stackIdx );
+ mv.visitVarInsn( ALOAD, stackIdx );
+ mv.visitInsn( ATHROW );
+
+ mv.visitLabel( lerror );
+ mv.visitFrame( Opcodes.F_SAME1, 0, null, 1, new Object[]{ "java/lang/Throwable" } );
+ mv.visitVarInsn( ASTORE, stackIdx );
+ mv.visitVarInsn( ALOAD, stackIdx );
+ mv.visitTypeInsn( CHECKCAST, "java/lang/Error" );
+ mv.visitInsn( ATHROW );
+
+ // Return type = void
+ if( endLabel != null )
+ {
+ mv.visitLabel( endLabel );
+ mv.visitFrame( Opcodes.F_SAME, 0, null, 0, null );
+ mv.visitInsn( RETURN );
+ }
+
+ mv.visitMaxs( 0, 0 );
+ mv.visitEnd();
+ }
+ }
+
+ if( !Modifier.isAbstract( method.getModifiers() ) )
+ {
+ // Add method with _ as prefix
+ MethodVisitor mv = cw.visitMethod( ACC_PUBLIC, "_" + method.getName(), desc, null, exceptions );
+ mv.visitCode();
+ mv.visitVarInsn( ALOAD, 0 );
+
+ // Parameters
+ int stackIdx = 1;
+ for( Class<?> aClass : method.getParameterTypes() )
+ {
+ stackIdx = loadParameter( mv, aClass, stackIdx ) + 1;
+ }
+
+ // Call method
+ mv.visitMethodInsn( INVOKESPECIAL, baseClassSlash, method.getName(), desc, false );
+
+ // Return value
+ if( !method.getReturnType().equals( Void.TYPE ) )
+ {
+ returnResult( mv, method.getReturnType() );
+ }
+ else
+ {
+ mv.visitInsn( RETURN );
+ }
+
+ mv.visitMaxs( 1, 1 );
+ mv.visitEnd();
+ }
+ }
+ }
+
+ // Class initializer
+ {
+ MethodVisitor mv = cw.visitMethod( ACC_STATIC, "<clinit>", "()V", null, null );
+ mv.visitCode();
+ Label l0 = new Label();
+ Label l1 = new Label();
+ Label l2 = new Label();
+ mv.visitTryCatchBlock( l0, l1, l2, "java/lang/NoSuchMethodException" );
+ mv.visitLabel( l0 );
+
+ // Lookup methods and store in static variables
+ int midx = 0;
+ for( Method method : methods )
+ {
+ if( isOverloaded( method, baseClass ) )
+ {
+ method.setAccessible( true );
+ Class methodClass = method.getDeclaringClass();
+
+ midx++;
+
+ mv.visitLdcInsn( Type.getType( methodClass ) );
+ mv.visitLdcInsn( method.getName() );
+ insn( mv, method.getParameterTypes().length );
+ mv.visitTypeInsn( ANEWARRAY, "java/lang/Class" );
+
+ int pidx = 0;
+ for( Class<?> aClass : method.getParameterTypes() )
+ {
+ mv.visitInsn( DUP );
+ insn( mv, pidx++ );
+ type( mv, aClass );
+ mv.visitInsn( AASTORE );
+ }
+
+ mv.visitMethodInsn( INVOKEVIRTUAL, "java/lang/Class", "getMethod",
+ "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false );
+ mv.visitFieldInsn( PUTSTATIC, classSlash, "m" + midx, "Ljava/lang/reflect/Method;" );
+ }
+ }
+
+ mv.visitLabel( l1 );
+ Label l3 = new Label();
+ mv.visitJumpInsn( GOTO, l3 );
+ mv.visitLabel( l2 );
+ mv.visitFrame( Opcodes.F_SAME1, 0, null, 1, new Object[]{ "java/lang/NoSuchMethodException" } );
+ mv.visitVarInsn( ASTORE, 0 );
+ mv.visitVarInsn( ALOAD, 0 );
+ mv.visitMethodInsn( INVOKEVIRTUAL, "java/lang/NoSuchMethodException", "printStackTrace", "()V", false );
+ mv.visitLabel( l3 );
+ mv.visitFrame( Opcodes.F_SAME, 0, null, 0, null );
+ mv.visitInsn( RETURN );
+ mv.visitMaxs( 6, 1 );
+ mv.visitEnd();
+ }
+ cw.visitEnd();
+ return cw.toByteArray();
+ }
+
+ private static boolean isOverloaded( Method method, Class baseClass )
+ {
+ return !Modifier.isFinal( method.getModifiers() );
+ }
+
+ private static boolean isInternalPolygeneMethod( Method method, Class baseClass )
+ {
+ return isDeclaredIn( method, Initializable.class, baseClass )
+ || isDeclaredIn( method, Lifecycle.class, baseClass );
+ }
+
+ private static boolean isDeclaredIn( Method method, Class<?> clazz, Class<?> baseClass )
+ {
+ if( !clazz.isAssignableFrom( baseClass ) )
+ {
+ return false;
+ }
+
+ try
+ {
+ clazz.getMethod( method.getName(), method.getParameterTypes() );
+ return true;
+ }
+ catch( NoSuchMethodException e )
+ {
+ return false;
+ }
+ }
+
+ private static Class<?> getInterfaceMethodDeclaration( Method method, Class clazz )
+ throws NoSuchMethodException
+ {
+ return interfacesOf( clazz ).map( RAW_CLASS ).filter( intFace -> {
+ try
+ {
+ intFace.getMethod( method.getName(), method.getParameterTypes() );
+ return true;
+ }
+ catch( NoSuchMethodException e )
+ {
+ // Try next
+ return false;
+ }
+ } ).findFirst().orElseThrow( () -> new NoSuchMethodException( method.getName() ) );
+ }
+
+ private static boolean isInterfaceMethod( Method method, Class<?> baseClass )
+ {
+ return interfacesOf( baseClass ).map( RAW_CLASS ).filter( Methods.HAS_METHODS ).anyMatch( clazz -> {
+ try
+ {
+ Method m = clazz.getMethod( method.getName(), method.getParameterTypes() );
+ m.setAccessible( true );
+ return true;
+ }
+ catch( NoSuchMethodException e )
+ {
+ // Ignore
+ }
+ return false;
+ } );
+ }
+
+ private static void type( MethodVisitor mv, Class<?> aClass )
+ {
+ if( aClass.equals( Integer.TYPE ) )
+ {
+ mv.visitFieldInsn( GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;" );
+ }
+ else if( aClass.equals( Long.TYPE ) )
+ {
+ mv.visitFieldInsn( GETSTATIC, "java/lang/Long", "TYPE", "Ljava/lang/Class;" );
+ }
+ else if( aClass.equals( Short.TYPE ) )
+ {
+ mv.visitFieldInsn( GETSTATIC, "java/lang/Short", "TYPE", "Ljava/lang/Class;" );
+ }
+ else if( aClass.equals( Byte.TYPE ) )
+ {
+ mv.visitFieldInsn( GETSTATIC, "java/lang/Byte", "TYPE", "Ljava/lang/Class;" );
+ }
+ else if( aClass.equals( Double.TYPE ) )
+ {
+ mv.visitFieldInsn( GETSTATIC, "java/lang/Double", "TYPE", "Ljava/lang/Class;" );
+ }
+ else if( aClass.equals( Float.TYPE ) )
+ {
+ mv.visitFieldInsn( GETSTATIC, "java/lang/Float", "TYPE", "Ljava/lang/Class;" );
+ }
+ else if( aClass.equals( Boolean.TYPE ) )
+ {
+ mv.visitFieldInsn( GETSTATIC, "java/lang/Boolean", "TYPE", "Ljava/lang/Class;" );
+ }
+ else if( aClass.equals( Character.TYPE ) )
+ {
+ mv.visitFieldInsn( GETSTATIC, "java/lang/Character", "TYPE", "Ljava/lang/Class;" );
+ }
+ else
+ {
+ mv.visitLdcInsn( Type.getType( aClass ) );
+ }
+ }
+
+ private static int wrapParameter( MethodVisitor mv, Class<?> aClass, int idx )
+ {
+ if( aClass.equals( Integer.TYPE ) )
+ {
+ mv.visitVarInsn( ILOAD, idx );
+ mv.visitMethodInsn( INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false );
+ }
+ else if( aClass.equals( Long.TYPE ) )
+ {
+ mv.visitVarInsn( LLOAD, idx );
+ mv.visitMethodInsn( INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false );
+ idx++; // Extra jump
+ }
+ else if( aClass.equals( Short.TYPE ) )
+ {
+ mv.visitVarInsn( ILOAD, idx );
+ mv.visitMethodInsn( INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false );
+ }
+ else if( aClass.equals( Byte.TYPE ) )
+ {
+ mv.visitVarInsn( ILOAD, idx );
+ mv.visitMethodInsn( INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false );
+ }
+ else if( aClass.equals( Double.TYPE ) )
+ {
+ mv.visitVarInsn( DLOAD, idx );
+ idx++; // Extra jump
+ mv.visitMethodInsn( INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false );
+ }
+ else if( aClass.equals( Float.TYPE ) )
+ {
+ mv.visitVarInsn( FLOAD, idx );
+ mv.visitMethodInsn( INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false );
+ }
+ else if( aClass.equals( Boolean.TYPE ) )
+ {
+ mv.visitVarInsn( ILOAD, idx );
+ mv.visitMethodInsn( INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false );
+ }
+ else if( aClass.equals( Character.TYPE ) )
+ {
+ mv.visitVarInsn( ILOAD, idx );
+ mv.visitMethodInsn( INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false );
+ }
+ else
+ {
+ mv.visitVarInsn( ALOAD, idx );
+ }
+
+ return idx;
+ }
+
+ private static void unwrapResult( MethodVisitor mv, Class<?> aClass, Label label )
+ {
+ if( aClass.equals( Integer.TYPE ) )
+ {
+ mv.visitTypeInsn( CHECKCAST, "java/lang/Integer" );
+ mv.visitMethodInsn( INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false );
+ mv.visitLabel( label );
+ mv.visitInsn( IRETURN );
+ }
+ else if( aClass.equals( Long.TYPE ) )
+ {
+ mv.visitTypeInsn( CHECKCAST, "java/lang/Long" );
+ mv.visitMethodInsn( INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false );
+ mv.visitLabel( label );
+ mv.visitInsn( LRETURN );
+ }
+ else if( aClass.equals( Short.TYPE ) )
+ {
+ mv.visitTypeInsn( CHECKCAST, "java/lang/Short" );
+ mv.visitMethodInsn( INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false );
+ mv.visitLabel( label );
+ mv.visitInsn( IRETURN );
+ }
+ else if( aClass.equals( Byte.TYPE ) )
+ {
+ mv.visitTypeInsn( CHECKCAST, "java/lang/Byte" );
+ mv.visitMethodInsn( INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false );
+ mv.visitLabel( label );
+ mv.visitInsn( IRETURN );
+ }
+ else if( aClass.equals( Double.TYPE ) )
+ {
+ mv.visitTypeInsn( CHECKCAST, "java/lang/Double" );
+ mv.visitMethodInsn( INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false );
+ mv.visitLabel( label );
+ mv.visitInsn( DRETURN );
+ }
+ else if( aClass.equals( Float.TYPE ) )
+ {
+ mv.visitTypeInsn( CHECKCAST, "java/lang/Float" );
+ mv.visitMethodInsn( INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false );
+ mv.visitLabel( label );
+ mv.visitInsn( FRETURN );
+ }
+ else if( aClass.equals( Boolean.TYPE ) )
+ {
+ mv.visitTypeInsn( CHECKCAST, "java/lang/Boolean" );
+ mv.visitMethodInsn( INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false );
+ mv.visitLabel( label );
+ mv.visitInsn( IRETURN );
+ }
+ else if( aClass.equals( Character.TYPE ) )
+ {
+ mv.visitTypeInsn( CHECKCAST, "java/lang/Character" );
+ mv.visitMethodInsn( INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false );
+ mv.visitLabel( label );
+ mv.visitInsn( IRETURN );
+ }
+ else
+ {
+ mv.visitTypeInsn( CHECKCAST, getInternalName( aClass ) );
+ mv.visitLabel( label );
+ mv.visitInsn( ARETURN );
+ }
+ }
+
+ private static int loadParameter( MethodVisitor mv, Class<?> aClass, int idx )
+ {
+ if( aClass.equals( Integer.TYPE ) )
+ {
+ mv.visitVarInsn( ILOAD, idx );
+ }
+ else if( aClass.equals( Long.TYPE ) )
+ {
+ mv.visitVarInsn( LLOAD, idx );
+ idx++; // Extra jump
+ }
+ else if( aClass.equals( Short.TYPE ) )
+ {
+ mv.visitVarInsn( ILOAD, idx );
+ }
+ else if( aClass.equals( Byte.TYPE ) )
+ {
+ mv.visitVarInsn( ILOAD, idx );
+ }
+ else if( aClass.equals( Double.TYPE ) )
+ {
+ mv.visitVarInsn( DLOAD, idx );
+ idx++; // Extra jump
+ }
+ else if( aClass.equals( Float.TYPE ) )
+ {
+ mv.visitVarInsn( FLOAD, idx );
+ }
+ else if( aClass.equals( Boolean.TYPE ) )
+ {
+ mv.visitVarInsn( ILOAD, idx );
+ }
+ else if( aClass.equals( Character.TYPE ) )
+ {
+ mv.visitVarInsn( ILOAD, idx );
+ }
+ else
+ {
+ mv.visitVarInsn( ALOAD, idx );
+ }
+
+ return idx;
+ }
+
+ private static void returnResult( MethodVisitor mv, Class<?> aClass )
+ {
+ if( aClass.equals( Integer.TYPE ) )
+ {
+ mv.visitInsn( IRETURN );
+ }
+ else if( aClass.equals( Long.TYPE ) )
+ {
+ mv.visitInsn( LRETURN );
+ }
+ else if( aClass.equals( Short.TYPE ) )
+ {
+ mv.visitInsn( IRETURN );
+ }
+ else if( aClass.equals( Byte.TYPE ) )
+ {
+ mv.visitInsn( IRETURN );
+ }
+ else if( aClass.equals( Double.TYPE ) )
+ {
+ mv.visitInsn( DRETURN );
+ }
+ else if( aClass.equals( Float.TYPE ) )
+ {
+ mv.visitInsn( FRETURN );
+ }
+ else if( aClass.equals( Boolean.TYPE ) )
+ {
+ mv.visitInsn( IRETURN );
+ }
+ else if( aClass.equals( Character.TYPE ) )
+ {
+ mv.visitInsn( IRETURN );
+ }
+ else
+ {
+ mv.visitTypeInsn( CHECKCAST, getInternalName( aClass ) );
+ mv.visitInsn( ARETURN );
+ }
+ }
+
+ private static void insn( MethodVisitor mv, int length )
+ {
+ switch( length )
+ {
+ case 0:
+ mv.visitInsn( ICONST_0 );
+ return;
+ case 1:
+ mv.visitInsn( ICONST_1 );
+ return;
+ case 2:
+ mv.visitInsn( ICONST_2 );
+ return;
+ case 3:
+ mv.visitInsn( ICONST_3 );
+ return;
+ case 4:
+ mv.visitInsn( ICONST_4 );
+ return;
+ case 5:
+ mv.visitInsn( ICONST_5 );
+ return;
+ default:
+ mv.visitIntInsn( BIPUSH, length );
+ }
+ }
+
+ public static boolean isGenerated( Class clazz )
+ {
+ return clazz.getName().endsWith( GENERATED_POSTFIX );
+ }
+
+ public static boolean isGenerated( Object object )
+ {
+ return object.getClass().getName().endsWith( GENERATED_POSTFIX );
+ }
+
+ public Class loadFragmentClass( Class fragmentClass )
+ throws ClassNotFoundException
+ {
+ return loadClass( fragmentClass.getName().replace( '$', '_' ) + GENERATED_POSTFIX );
+ }
+
+ public static Class getSourceClass( Class fragmentClass )
+ {
+ return fragmentClass.getName().endsWith( GENERATED_POSTFIX ) ? fragmentClass.getSuperclass() : fragmentClass;
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/composite/TransientInstance.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/TransientInstance.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/TransientInstance.java
new file mode 100644
index 0000000..a251349
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/TransientInstance.java
@@ -0,0 +1,224 @@
+/*
+ * 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.lang.reflect.Proxy;
+import java.util.Arrays;
+import java.util.stream.Stream;
+import org.apache.polygene.api.PolygeneAPI;
+import org.apache.polygene.api.composite.Composite;
+import org.apache.polygene.api.composite.CompositeInstance;
+import org.apache.polygene.api.property.StateHolder;
+import org.apache.polygene.api.structure.LayerDescriptor;
+import org.apache.polygene.api.structure.ModuleDescriptor;
+
+/**
+ * InvocationHandler for proxy objects.
+ */
+public class TransientInstance
+ implements CompositeInstance, MixinsInstance
+{
+ public static TransientInstance compositeInstanceOf( Composite composite )
+ {
+ InvocationHandler handler = Proxy.getInvocationHandler( composite );
+ return (TransientInstance) handler;
+ }
+
+ private final Composite proxy;
+ protected final Object[] mixins;
+ protected StateHolder state;
+ protected final CompositeModel compositeModel;
+
+ public TransientInstance( CompositeModel compositeModel,
+ Object[] mixins,
+ StateHolder state
+ )
+ {
+ this.compositeModel = compositeModel;
+ this.mixins = mixins;
+ this.state = state;
+
+ proxy = compositeModel.newProxy( this );
+ }
+
+ @Override
+ public Object invoke( Object proxy, Method method, Object[] args )
+ throws Throwable
+ {
+ return compositeModel.invoke( this, proxy, method, args );
+ }
+
+ @Override
+ @SuppressWarnings( "unchecked" )
+ public <T> T proxy()
+ {
+ return (T) proxy;
+ }
+
+ @Override
+ public <T> T newProxy( Class<T> mixinType )
+ throws IllegalArgumentException
+ {
+ return compositeModel.newProxy( this, mixinType );
+ }
+
+ @Override
+ public Object invokeComposite( Method method, Object[] args )
+ throws Throwable
+ {
+ return compositeModel.invoke( this, proxy, method, args );
+ }
+
+ @Override
+ public CompositeModel descriptor()
+ {
+ return compositeModel;
+ }
+
+ @Override
+ public <T> T metaInfo( Class<T> infoType )
+ {
+ return compositeModel.metaInfo( infoType );
+ }
+
+ @Override
+ public Stream<Class<?>> types()
+ {
+ return compositeModel.types();
+ }
+
+ @Override
+ public ModuleDescriptor module()
+ {
+ return compositeModel.module();
+ }
+
+ public LayerDescriptor layer()
+ {
+ return compositeModel.module().layer();
+ }
+
+ @Override
+ public StateHolder state()
+ {
+ return state;
+ }
+
+ @Override
+ public Object invoke( Object composite, Object[] params, CompositeMethodInstance methodInstance )
+ throws Throwable
+ {
+ Object mixin = methodInstance.getMixinFrom( mixins );
+ return methodInstance.invoke( proxy, params, mixin );
+ }
+
+ @Override
+ public Object invokeObject( Object proxy, Object[] args, Method method )
+ throws Throwable
+ {
+ return method.invoke( this, args );
+ }
+
+ @Override
+ public boolean equals( Object o )
+ {
+ if( o == null )
+ {
+ return false;
+ }
+ if( !Proxy.isProxyClass( o.getClass() ) )
+ {
+ return false;
+ }
+ TransientInstance other = (TransientInstance) PolygeneAPI.FUNCTION_COMPOSITE_INSTANCE_OF.apply( (Composite) o );
+ if( other.mixins.length != mixins.length )
+ {
+ return false;
+ }
+
+ for( int i = 0; i < mixins.length; i++ )
+ {
+ if( !mixins[ i ].equals( other.mixins[ i ] ) )
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ int hashCode = 0;
+ for( Object mixin : mixins )
+ {
+ hashCode = hashCode * 31 + mixin.hashCode();
+ }
+ return hashCode;
+ }
+
+ @Override
+ public String toString()
+ {
+ StringBuilder buffer = new StringBuilder();
+ boolean first = true;
+ for( Object mixin : mixins )
+ {
+ try
+ {
+ if( mixin != null ) // Can happen during construction of incorrect composites, during exception creation.
+ {
+ Class<?> type = mixin.getClass();
+ Method toStringMethod = type.getMethod( "toString" );
+ Class<?> declaringClass = toStringMethod.getDeclaringClass();
+ if( !declaringClass.equals( Object.class ) )
+ {
+ if( !first )
+ {
+ buffer.append( ", " );
+ }
+ first = false;
+ buffer.append( mixin.toString() );
+ }
+ }
+ }
+ catch( NoSuchMethodException e )
+ {
+ // Can not happen??
+ e.printStackTrace();
+ }
+ }
+ if( first )
+ {
+ String modelTypeName = compositeModel.getClass().getSimpleName();
+ String metaTypeModel = modelTypeName.substring( 0, modelTypeName.length() - 5 );
+ return metaTypeModel + "Instance{" +
+ "mixins=" + Arrays.asList( mixins ) +
+ ", state=" + state +
+ ", compositeModel=" + compositeModel +
+ ", module=" + module() +
+ '}';
+ }
+ return buffer.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/TransientModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/TransientModel.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/TransientModel.java
new file mode 100644
index 0000000..4aedb47
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/TransientModel.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.util.List;
+import org.apache.polygene.api.common.MetaInfo;
+import org.apache.polygene.api.common.Visibility;
+import org.apache.polygene.api.composite.TransientDescriptor;
+import org.apache.polygene.api.constraint.ConstraintViolationException;
+import org.apache.polygene.api.structure.ModuleDescriptor;
+import org.apache.polygene.runtime.injection.InjectionContext;
+
+/**
+ * Model for Transient Composites
+ */
+public class TransientModel extends CompositeModel
+ implements TransientDescriptor
+{
+ public TransientModel( ModuleDescriptor module,
+ List<Class<?>> types, final Visibility visibility,
+ final MetaInfo metaInfo,
+ final MixinsModel mixinsModel,
+ final StateModel stateModel,
+ final CompositeMethodsModel compositeMethodsModel
+ )
+ {
+ super( module, types, visibility, metaInfo, mixinsModel, stateModel, compositeMethodsModel );
+ }
+
+ public TransientInstance newInstance( UsesInstance uses,
+ TransientStateInstance state
+ )
+ {
+ Object[] mixins = mixinsModel.newMixinHolder();
+ TransientInstance compositeInstance = new TransientInstance( this, mixins, state );
+
+ // Instantiate all mixins
+ int i = 0;
+ InjectionContext injectionContext = new InjectionContext( compositeInstance, uses, state );
+ for( MixinModel mixinModel : mixinsModel.mixinModels() )
+ {
+ mixins[ i++ ] = mixinModel.newInstance( injectionContext );
+ }
+
+ // Return
+ return compositeInstance;
+ }
+
+ public void checkConstraints( TransientStateInstance instanceState )
+ throws ConstraintViolationException
+ {
+ stateModel.properties().forEach( propertyModel ->
+ propertyModel.checkConstraints( instanceState.propertyFor( propertyModel.accessor() ).get() )
+ );
+ }
+}
\ 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/TransientStateInstance.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/TransientStateInstance.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/TransientStateInstance.java
new file mode 100644
index 0000000..c70c3b8
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/TransientStateInstance.java
@@ -0,0 +1,62 @@
+/*
+ * 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.AccessibleObject;
+import java.util.Map;
+import java.util.stream.Stream;
+import org.apache.polygene.api.property.Property;
+import org.apache.polygene.api.property.StateHolder;
+
+/**
+ * TODO
+ */
+public final class TransientStateInstance
+ implements StateHolder
+{
+ private final Map<AccessibleObject, Property<?>> properties;
+
+ public TransientStateInstance( Map<AccessibleObject, Property<?>> properties
+ )
+ {
+ this.properties = properties;
+ }
+
+ @Override
+ @SuppressWarnings( "unchecked" )
+ public <T> Property<T> propertyFor( AccessibleObject accessor )
+ throws IllegalArgumentException
+ {
+ Property<T> property = (Property<T>) properties.get( accessor );
+
+ if( property == null )
+ {
+ throw new IllegalArgumentException( "No such property:" + accessor );
+ }
+
+ return property;
+ }
+
+ @Override
+ public Stream<Property<?>> properties()
+ {
+ return properties.values().stream();
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/composite/TransientsModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/TransientsModel.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/TransientsModel.java
new file mode 100644
index 0000000..a18ef09
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/TransientsModel.java
@@ -0,0 +1,68 @@
+/*
+ * 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.List;
+import java.util.stream.Stream;
+import org.apache.polygene.api.composite.TransientDescriptor;
+import org.apache.polygene.api.util.HierarchicalVisitor;
+import org.apache.polygene.api.util.VisitableHierarchy;
+
+/**
+ * JAVADOC
+ */
+public class TransientsModel
+ implements VisitableHierarchy<Object, Object>
+{
+ private final List<TransientModel> transientModels;
+
+ public TransientsModel( List<TransientModel> transientModels )
+ {
+ this.transientModels = transientModels;
+ }
+
+ public Stream<TransientModel> models()
+ {
+ return transientModels.stream();
+ }
+
+ @Override
+ public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> modelVisitor )
+ throws ThrowableType
+ {
+ if( modelVisitor.visitEnter( this ) )
+ {
+ for( TransientModel transientModel : transientModels )
+ {
+ if( !transientModel.accept( modelVisitor ) )
+ {
+ break;
+ }
+ }
+ }
+ return modelVisitor.visitLeave( this );
+ }
+
+ public Stream<? extends TransientDescriptor> stream()
+ {
+ return transientModels.stream();
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/composite/TypedModifierInvocationHandler.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/TypedModifierInvocationHandler.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/TypedModifierInvocationHandler.java
new file mode 100644
index 0000000..399e3f2
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/TypedModifierInvocationHandler.java
@@ -0,0 +1,53 @@
+/*
+ * 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.InvocationTargetException;
+import java.lang.reflect.Method;
+import org.apache.polygene.api.composite.InvalidCompositeException;
+
+/**
+ * JAVADOC
+ */
+public final class TypedModifierInvocationHandler
+ extends FragmentInvocationHandler
+{
+ @Override
+ public Object invoke( Object proxy, Method method, Object[] args )
+ throws Throwable
+ {
+ try
+ {
+ return this.method.invoke( fragment, args );
+ }
+ catch( InvocationTargetException e )
+ {
+ throw cleanStackTrace( e.getTargetException(), proxy, method );
+ }
+ catch( Throwable e )
+ {
+ if( fragment == null )
+ {
+ throw new InvalidCompositeException( "No fragment available for method " + method.getName() );
+ }
+ throw cleanStackTrace( e, proxy, method );
+ }
+ }
+}
\ 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/UnsynchronizedCompositeMethodInstancePool.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/UnsynchronizedCompositeMethodInstancePool.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/UnsynchronizedCompositeMethodInstancePool.java
new file mode 100644
index 0000000..56bfce5
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/UnsynchronizedCompositeMethodInstancePool.java
@@ -0,0 +1,50 @@
+/*
+ * 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;
+
+/**
+ * Method instance pool that keeps a linked list. Uses synchronization
+ * to ensure that instances are acquired and returned in a thread-safe
+ * manner.
+ */
+public final class UnsynchronizedCompositeMethodInstancePool
+ implements InstancePool<CompositeMethodInstance>
+{
+ private CompositeMethodInstance first = null;
+
+ @Override
+ public CompositeMethodInstance obtainInstance()
+ {
+ CompositeMethodInstance instance = first;
+ if( instance != null )
+ {
+ first = instance.getNext();
+ }
+ return instance;
+ }
+
+ @Override
+ public void releaseInstance( CompositeMethodInstance instance )
+ {
+ instance.setNext( first );
+ first = instance;
+ }
+}
\ 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/UsageGraph.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/UsageGraph.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/UsageGraph.java
new file mode 100644
index 0000000..c0a0b35
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/UsageGraph.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.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import org.apache.polygene.bootstrap.BindingException;
+
+/**
+ * This class is NOT thread-safe.
+ * //TODO: Algorithm need to be optimized.
+ */
+public final class UsageGraph<K>
+{
+ private final Collection<K> data;
+ private final Use<K> use;
+ private final boolean allowCyclic;
+ private List<K> resolved;
+ private HashMap<K, List<K>> transitive;
+
+ public UsageGraph( Collection<K> data, Use<K> use, boolean allowCyclic )
+ {
+ this.data = data;
+ this.use = use;
+ this.allowCyclic = allowCyclic;
+ }
+
+ public boolean transitiveUse( K source, K other )
+ throws BindingException
+ {
+ if( transitive == null )
+ {
+ buildUsageGraph();
+ }
+ return transitive.containsKey( source ) && transitive.get( source ).contains( other );
+ }
+
+ private void checkCyclic( List<K> visited, K sourceItem, K used )
+ throws BindingException
+ {
+ Collection<K> nextLevel = use.uses( used );
+ for( K next : nextLevel )
+ {
+ if( next == sourceItem )
+ {
+ if( !allowCyclic )
+ {
+ visited.add( next );
+ throw new BindingException( "Cyclic usage detected: " + sourceItem + " -> " + visited );
+ }
+ }
+ if( !visited.contains( next ) )
+ {
+ visited.add( next );
+ checkCyclic( visited, sourceItem, next );
+ }
+ }
+ }
+
+ /**
+ * Must be called if the data set has been modified.
+ */
+ public void invalidate()
+ {
+ resolved = null;
+ transitive = null;
+ }
+
+ public List<K> resolveOrder()
+ throws BindingException
+ {
+ if( resolved == null )
+ {
+ buildUsageGraph();
+ resolved = new LinkedList<K>();
+ for( K item : data )
+ {
+ int pos = resolved.size();
+ for( K entry : resolved )
+ {
+ if( transitiveUse( entry, item ) )
+ {
+ pos = resolved.indexOf( entry );
+ break;
+ }
+ }
+ resolved.add( pos, item );
+ }
+ }
+ return resolved;
+ }
+
+ private void buildUsageGraph()
+ throws BindingException
+ {
+ transitive = new HashMap<K, List<K>>();
+ for( K sourceItem : data )
+ {
+ LinkedList<K> visited = new LinkedList<K>();
+ checkCyclic( visited, sourceItem, sourceItem );
+ transitive.put( sourceItem, visited );
+ }
+ }
+
+ public interface Use<K>
+ {
+
+ /**
+ * @param source The item to be queried.
+ *
+ * @return A list of items it uses.
+ */
+ Collection<K> uses( K source );
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/composite/UsesInstance.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/UsesInstance.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/UsesInstance.java
new file mode 100644
index 0000000..0fc8eb3
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/UsesInstance.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.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * JAVADOC
+ */
+public final class UsesInstance
+{
+ public static final UsesInstance EMPTY_USES;
+ private final Set<Object> uses;
+
+ static
+ {
+ EMPTY_USES = new UsesInstance( new HashSet<>() );
+ }
+
+ private UsesInstance( HashSet<Object> uses )
+ {
+ this.uses = Collections.unmodifiableSet( uses );
+ }
+
+ public UsesInstance use( Object... objects )
+ {
+ HashSet<Object> useObjects = new HashSet<>();
+ if( !uses.isEmpty() )
+ {
+ useObjects.addAll( uses );
+ for( Object object : objects )
+ {
+ Object oldUseForType = useForType( object.getClass() );
+ if( oldUseForType != null )
+ {
+ useObjects.remove( oldUseForType );
+ }
+ }
+ }
+ useObjects.addAll( Arrays.asList( objects ) );
+ return new UsesInstance( useObjects );
+ }
+
+ public Object useForType( Class<?> type )
+ {
+ // Check instances first
+ for( Object use : uses )
+ {
+ if( type.isInstance( use ) )
+ {
+ return use;
+ }
+ }
+
+ return null;
+ }
+
+ public Object[] toArray()
+ {
+ return uses.toArray();
+ }
+
+ @Override
+ public boolean equals( Object o )
+ {
+ if( this == o )
+ {
+ return true;
+ }
+ if( o == null || getClass() != o.getClass() )
+ {
+ return false;
+ }
+ UsesInstance that = (UsesInstance) o;
+ return uses.equals( that.uses );
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return uses.hashCode();
+ }
+
+ @Override
+ public String toString()
+ {
+ return "UsesInstance{" +
+ "uses=" + uses +
+ '}';
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ValueConstraintsInstance.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ValueConstraintsInstance.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ValueConstraintsInstance.java
new file mode 100644
index 0000000..783a4ef
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ValueConstraintsInstance.java
@@ -0,0 +1,145 @@
+/*
+ * 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.AccessibleObject;
+import java.lang.reflect.Member;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Stream;
+import org.apache.polygene.api.common.Optional;
+import org.apache.polygene.api.constraint.ConstraintViolation;
+import org.apache.polygene.api.constraint.ConstraintViolationException;
+
+/**
+ * JAVADOC
+ */
+public final class ValueConstraintsInstance
+{
+ private static final Optional OPTIONAL;
+
+ static
+ {
+ OPTIONAL = new OptionalDummy();
+ }
+
+ @SuppressWarnings( "raw" )
+ private final List<ConstraintInstance> constraints;
+ private String name;
+ private boolean optional;
+
+ public ValueConstraintsInstance( List<AbstractConstraintModel> constraintModels, String name, boolean optional )
+ {
+ this.name = name;
+ this.optional = optional;
+ constraints = new ArrayList<>();
+ for( AbstractConstraintModel constraintModel : constraintModels )
+ {
+ constraints.add( constraintModel.newInstance() );
+ }
+ }
+
+ @SuppressWarnings( { "raw", "unchecked" } )
+ public List<ConstraintViolation> checkConstraints( Object value )
+ {
+ List<ConstraintViolation> violations = null;
+
+ // Check optional first - this avoids NPE's in constraints
+ if( optional )
+ {
+ if( value == null )
+ {
+ violations = Collections.emptyList();
+ }
+ }
+ else
+ {
+ if( value == null )
+ {
+ violations = new ArrayList<>();
+ violations.add( new ConstraintViolation( name, OPTIONAL, null ) );
+ }
+ }
+
+ if( violations == null && value != null )
+ {
+ for( ConstraintInstance constraint : constraints )
+ {
+ boolean valid;
+ try
+ {
+ valid = constraint.isValid( value );
+ }
+ catch( NullPointerException e )
+ {
+ // A NPE is the same as a failing constraint
+ valid = false;
+ }
+
+ if( !valid )
+ {
+ if( violations == null )
+ {
+ violations = new ArrayList<>();
+ }
+ ConstraintViolation violation = new ConstraintViolation( name, constraint.annotation(), value );
+ violations.add( violation );
+ }
+ }
+ }
+
+ if( violations == null )
+ {
+ violations = Collections.emptyList();
+ }
+
+ return violations;
+ }
+
+ public void checkConstraints( Object value, AccessibleObject accessor )
+ {
+ List<ConstraintViolation> violations = checkConstraints( value );
+ if( !violations.isEmpty() )
+ {
+ Stream<Class<?>> empty = Stream.empty();
+ throw new ConstraintViolationException( "", empty, (Member) accessor, violations );
+ }
+ }
+
+ @SuppressWarnings( "AnnotationAsSuperInterface" )
+ private static class OptionalDummy
+ implements Optional
+ {
+ @Override
+ public Class<? extends Annotation> annotationType()
+ {
+ return Optional.class;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "not optional";
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ValueConstraintsModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ValueConstraintsModel.java b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ValueConstraintsModel.java
new file mode 100644
index 0000000..5568881
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/composite/ValueConstraintsModel.java
@@ -0,0 +1,72 @@
+/*
+ * 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.List;
+import org.apache.polygene.api.util.HierarchicalVisitor;
+import org.apache.polygene.api.util.VisitableHierarchy;
+
+/**
+ * JAVADOC
+ */
+public final class ValueConstraintsModel
+ implements VisitableHierarchy<Object, Object>
+{
+ private final List<AbstractConstraintModel> constraintModels;
+ private String name;
+ private boolean optional;
+
+ public ValueConstraintsModel( List<AbstractConstraintModel> constraintModels, String name, boolean optional )
+ {
+ this.constraintModels = constraintModels;
+ this.name = name;
+ this.optional = optional;
+ }
+
+ public ValueConstraintsInstance newInstance()
+ {
+ return new ValueConstraintsInstance( constraintModels, name, optional );
+ }
+
+ public boolean isConstrained()
+ {
+ if( !constraintModels.isEmpty() )
+ {
+ return true;
+ }
+
+ return !optional;
+ }
+
+ @Override
+ public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> modelVisitor )
+ throws ThrowableType
+ {
+ for( AbstractConstraintModel constraintModel : constraintModels )
+ {
+ if( constraintModel.accept( modelVisitor ) )
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/entity/EntitiesModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/entity/EntitiesModel.java b/core/runtime/src/main/java/org/apache/polygene/runtime/entity/EntitiesModel.java
new file mode 100644
index 0000000..ebb3d78
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/entity/EntitiesModel.java
@@ -0,0 +1,68 @@
+/*
+ * 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.entity;
+
+import java.util.List;
+import java.util.stream.Stream;
+import org.apache.polygene.api.entity.EntityDescriptor;
+import org.apache.polygene.api.util.HierarchicalVisitor;
+import org.apache.polygene.api.util.VisitableHierarchy;
+
+/**
+ * Model of entities in a particular Module.
+ */
+public class EntitiesModel
+ implements VisitableHierarchy<Object, Object>
+{
+ private final List<EntityModel> entityModels;
+
+ public EntitiesModel( List<EntityModel> entityModels )
+ {
+ this.entityModels = entityModels;
+ }
+
+ public Stream<EntityModel> models()
+ {
+ return entityModels.stream();
+ }
+
+ @Override
+ public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> modelVisitor )
+ throws ThrowableType
+ {
+ if( modelVisitor.visitEnter( this ) )
+ {
+ for( EntityModel entityModel : entityModels )
+ {
+ if( !entityModel.accept( modelVisitor ) )
+ {
+ break;
+ }
+ }
+ }
+ return modelVisitor.visitLeave( this );
+ }
+
+ public Stream<? extends EntityDescriptor> stream()
+ {
+ return entityModels.stream();
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/entity/EntityInstance.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/entity/EntityInstance.java b/core/runtime/src/main/java/org/apache/polygene/runtime/entity/EntityInstance.java
new file mode 100644
index 0000000..a58cee9
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/entity/EntityInstance.java
@@ -0,0 +1,317 @@
+/*
+ * 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.entity;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.Type;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.apache.polygene.api.association.AssociationDescriptor;
+import org.apache.polygene.api.association.AssociationStateDescriptor;
+import org.apache.polygene.api.composite.CompositeDescriptor;
+import org.apache.polygene.api.composite.CompositeInstance;
+import org.apache.polygene.api.constraint.ConstraintViolationException;
+import org.apache.polygene.api.entity.EntityComposite;
+import org.apache.polygene.api.entity.EntityReference;
+import org.apache.polygene.api.identity.HasIdentity;
+import org.apache.polygene.api.structure.ModuleDescriptor;
+import org.apache.polygene.api.unitofwork.NoSuchEntityException;
+import org.apache.polygene.api.unitofwork.UnitOfWork;
+import org.apache.polygene.api.unitofwork.UnitOfWorkException;
+import org.apache.polygene.runtime.composite.CompositeMethodInstance;
+import org.apache.polygene.runtime.composite.MixinsInstance;
+import org.apache.polygene.spi.entity.EntityState;
+import org.apache.polygene.spi.entity.EntityStatus;
+
+import static java.util.stream.Collectors.toList;
+
+/**
+ * Entity instance
+ */
+public final class EntityInstance
+ implements CompositeInstance, MixinsInstance
+{
+ public static EntityInstance entityInstanceOf( EntityComposite composite )
+ {
+ return (EntityInstance) Proxy.getInvocationHandler( composite );
+ }
+
+ private final EntityComposite proxy;
+ private final UnitOfWork uow;
+ private final EntityModel entityModel;
+ private final EntityReference reference;
+ private final EntityState entityState;
+
+ private Object[] mixins;
+ private EntityStateInstance state;
+
+ public EntityInstance( UnitOfWork uow,
+ EntityModel entityModel,
+ EntityState entityState
+ )
+ {
+ this.uow = uow;
+ this.entityModel = entityModel;
+ this.reference = entityState.entityReference();
+ this.entityState = entityState;
+
+ proxy = (EntityComposite) entityModel.newProxy( this );
+ }
+
+ @Override
+ public Object invoke( Object proxy, Method method, Object[] args )
+ throws Throwable
+ {
+ return entityModel.invoke( this, this.proxy, method, args );
+ }
+
+ public EntityReference reference()
+ {
+ return reference;
+ }
+
+ @Override
+ @SuppressWarnings( "unchecked" )
+ public <T> T proxy()
+ {
+ return (T) proxy;
+ }
+
+ @Override
+ public CompositeDescriptor descriptor()
+ {
+ return entityModel;
+ }
+
+ @Override
+ public <T> T newProxy( Class<T> mixinType )
+ throws IllegalArgumentException
+ {
+ return entityModel.newProxy( this, mixinType );
+ }
+
+ @Override
+ public Object invokeComposite( Method method, Object[] args )
+ throws Throwable
+ {
+ return entityModel.invoke( this, proxy, method, args );
+ }
+
+ @Override
+ public <T> T metaInfo( Class<T> infoType )
+ {
+ return entityModel.metaInfo( infoType );
+ }
+
+ public EntityModel entityModel()
+ {
+ return entityModel;
+ }
+
+ @Override
+ public Stream<Class<?>> types()
+ {
+ return entityModel.types();
+ }
+
+ @Override
+ public ModuleDescriptor module()
+ {
+ return entityModel.module();
+ }
+
+ public UnitOfWork unitOfWork()
+ {
+ return uow;
+ }
+
+ public EntityState entityState()
+ {
+ return entityState;
+ }
+
+ @Override
+ public EntityStateInstance state()
+ {
+ if( state == null )
+ {
+ initState();
+ }
+
+ return state;
+ }
+
+ public EntityStatus status()
+ {
+ return entityState.status();
+ }
+
+ @Override
+ public Object invoke( Object composite, Object[] params, CompositeMethodInstance methodInstance )
+ throws Throwable
+ {
+ if( mixins == null )
+ {
+ initState();
+ }
+
+ Object mixin = methodInstance.getMixinFrom( mixins );
+
+ if( mixin == null )
+ {
+ mixin = entityModel.newMixin( mixins, state, this, methodInstance.method() );
+ }
+
+ return methodInstance.invoke( proxy, params, mixin );
+ }
+
+ @Override
+ public Object invokeObject( Object proxy, Object[] args, Method method )
+ throws Throwable
+ {
+ return method.invoke( this, args );
+ }
+
+ private void initState()
+ {
+ if( !uow.isOpen() )
+ {
+ throw new UnitOfWorkException( "Unit of work has been closed" );
+ }
+
+ if( status() == EntityStatus.REMOVED )
+ {
+ throw new NoSuchEntityException(reference, entityModel.types(), unitOfWork().usecase() );
+ }
+
+ mixins = entityModel.newMixinHolder();
+ state = new EntityStateInstance( entityModel.state(), uow, entityState );
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return reference.hashCode();
+ }
+
+ @Override
+ public boolean equals( Object o )
+ {
+ try
+ {
+ HasIdentity other = ( (HasIdentity) o );
+ return other != null && other.identity().get().equals( reference.identity() );
+ }
+ catch( ClassCastException e )
+ {
+ return false;
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ if( Boolean.getBoolean( "polygene.entity.print.state" ) )
+ {
+ return state.toString();
+ }
+ else
+ {
+ return reference.toString();
+ }
+ }
+
+ public void remove( UnitOfWork unitOfWork )
+ {
+ invokeRemove();
+
+ removeAggregatedEntities( unitOfWork );
+
+ entityState.remove();
+ mixins = null;
+ }
+
+ public void invokeCreate()
+ {
+ lifecyleInvoke( true );
+ }
+
+ private void invokeRemove()
+ {
+ lifecyleInvoke( false );
+ }
+
+ private void lifecyleInvoke( boolean create )
+ {
+ if( mixins == null )
+ {
+ initState();
+ }
+
+ entityModel.invokeLifecycle( create, mixins, this, state );
+ }
+
+ private void removeAggregatedEntities( UnitOfWork unitOfWork )
+ {
+ // Calculate aggregated Entities
+ AssociationStateDescriptor stateDescriptor = entityModel.state();
+ Stream.concat(
+ stateDescriptor.associations()
+ .filter( AssociationDescriptor::isAggregated )
+ .map( association -> state.associationFor( association.accessor() ).get() )
+ .filter( Objects::nonNull ),
+
+ Stream.concat(
+ stateDescriptor.manyAssociations()
+ .filter( AssociationDescriptor::isAggregated )
+ .flatMap( association -> state.manyAssociationFor( association.accessor() ).toList().stream() )
+ .filter( Objects::nonNull ),
+
+ stateDescriptor.namedAssociations()
+ .filter( AssociationDescriptor::isAggregated )
+ .flatMap( association -> state.namedAssociationFor( association.accessor() )
+ .toMap()
+ .values()
+ .stream() )
+ .filter( Objects::nonNull )
+ )
+ ).distinct().collect( Collectors.toList() ).forEach( unitOfWork::remove );
+ }
+
+ public void checkConstraints()
+ {
+ try
+ {
+ state.checkConstraints();
+ }
+ catch( ConstraintViolationException e )
+ {
+ List<? extends Type> entityModelList = entityModel.types().collect( toList() );
+ throw new ConstraintViolationException( reference.identity(),
+ entityModelList,
+ e.mixinTypeName(),
+ e.methodName(),
+ e.constraintViolations() );
+ }
+ }
+}