You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@polygene.apache.org by ni...@apache.org on 2015/07/30 21:48:17 UTC
[18/80] [partial] zest-java git commit: First round of changes to
move to org.apache.zest namespace.
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/io/src/test/java/org/qi4j/io/InputOutputTest.java
----------------------------------------------------------------------
diff --git a/core/io/src/test/java/org/qi4j/io/InputOutputTest.java b/core/io/src/test/java/org/qi4j/io/InputOutputTest.java
deleted file mode 100644
index 220e856..0000000
--- a/core/io/src/test/java/org/qi4j/io/InputOutputTest.java
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * Copyright (c) 2010, Rickard Öberg. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-package org.qi4j.io;
-
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-import java.io.Writer;
-import java.net.URL;
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.rmi.RemoteException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-import java.util.logging.Logger;
-import org.hamcrest.CoreMatchers;
-import org.junit.Assert;
-import org.junit.Test;
-import org.qi4j.functional.Function;
-import org.qi4j.functional.Visitor;
-
-import static java.util.Arrays.asList;
-import static org.qi4j.functional.Iterables.iterable;
-import static org.qi4j.io.Inputs.text;
-import static org.qi4j.io.Transforms.lock;
-import static org.qi4j.test.util.Assume.assumeConnectivity;
-
-/**
- * Test Input/Output.
- */
-public class InputOutputTest
-{
- @Test
- public void testCopyFileNoAPI()
- throws IOException
- {
- File source = sourceFile();
- File destination = File.createTempFile( "test", ".txt" );
- destination.deleteOnExit();
-
- BufferedReader reader = new BufferedReader( new FileReader( source ) );
- long count = 0;
- try
- {
- BufferedWriter writer = new BufferedWriter( new FileWriter( destination ) );
- try
- {
- String line;
- while( ( line = reader.readLine() ) != null )
- {
- count++;
- writer.append( line ).append( '\n' );
- }
- writer.close();
- }
- catch( IOException e )
- {
- writer.close();
- destination.delete();
- }
- }
- finally
- {
- reader.close();
- }
- System.out.println( count );
- }
-
- @Test
- public void testInputOutput()
- throws IOException
- {
- URL source = getClass().getResource( "/iotest.txt" );
- File destination = File.createTempFile( "test", ".txt" );
- destination.deleteOnExit();
- text( source ).transferTo( Outputs.text( destination ) );
- }
-
- @Test
- public void testCopyFile()
- throws IOException
- {
- File source = sourceFile();
- File tempFile = File.createTempFile( "test", ".txt" );
- tempFile.deleteOnExit();
-
- Inputs.byteBuffer( source, 1024 ).transferTo( Outputs.byteBuffer( tempFile ) );
-
- Assert.assertThat( tempFile.length(), CoreMatchers.equalTo( source.length() ) );
- }
-
- @Test
- public void testCopyURL()
- throws IOException
- {
- assumeConnectivity( "www.google.com", 80 );
-
- File tempFile = File.createTempFile( "test", ".txt" );
- tempFile.deleteOnExit();
-
- Inputs.text( new URL( "http://www.google.com" ) ).transferTo( Outputs.text( tempFile ) );
-
-// Uncomment to check output Inputs.text( tempFile ).transferTo( Outputs.systemOut() );
- }
-
- @Test
- public void testCopyFileStreams()
- throws IOException
- {
- File source = sourceFile();
- File tempFile = File.createTempFile( "test", ".txt" );
- tempFile.deleteOnExit();
-
- Inputs.byteBuffer( new FileInputStream( source ), 1024 ).transferTo(
- Outputs.byteBuffer( new FileOutputStream( tempFile ) ) );
-
- Assert.assertThat( tempFile.length(), CoreMatchers.equalTo( source.length() ) );
- }
-
- @Test
- public void testLog()
- throws IOException
- {
- File source = sourceFile();
-
- text( source ).transferTo(
- Transforms.map( new Transforms.Log<String>( Logger.getLogger( getClass().getName() ), "Line: {0}" ),
- Outputs.<String>noop() ) );
- }
-
- @Test
- public void testProgressLog()
- throws Throwable
- {
- Integer[] data = new Integer[ 105 ];
- Arrays.fill( data, 42 );
-
- Inputs.iterable( iterable( data ) ).transferTo(
- Transforms.map(
- new Transforms.ProgressLog<Integer>(
- Logger.getLogger( InputOutputTest.class.getName() ), "Data transferred: {0}", 10 ),
- Outputs.<Integer>noop() ) );
- }
-
- @Test
- public void testTextInputsOutputs()
- throws IOException
- {
- File tempFile = File.createTempFile( "test", ".txt" );
- tempFile.deleteOnExit();
- File sourceFile = sourceFile();
- Transforms.Counter<String> stringCounter = new Transforms.Counter<>();
- text( sourceFile ).transferTo(
- Transforms.map(
- stringCounter,
- Transforms.map( new Function<String, String>()
- {
- public String map( String s )
- {
- System.out.println( s );
- return s;
- }
- }, Outputs.text( tempFile ) )
- )
- );
-
- Assert.assertThat( tempFile.length(), CoreMatchers.equalTo( sourceFile.length() ) );
- Assert.assertThat( stringCounter.count(), CoreMatchers.equalTo( 4L ) );
- }
-
- @Test
- public void testCombineInputs()
- throws IOException
- {
- File tempFile = File.createTempFile( "test", ".txt" );
- tempFile.deleteOnExit();
- File sourceFile = sourceFile();
- Transforms.Counter<String> stringCounter = new Transforms.Counter<>();
- Input<String, IOException> text1 = text( sourceFile );
- Input<String, IOException> text2 = text( sourceFile );
- List<Input<String, IOException>> list = createList( text1, text2 );
- Inputs.combine( list ).transferTo(
- Transforms.map(
- stringCounter,
- Transforms.map( new Function<String, String>()
- {
- public String map( String s )
- {
- System.out.println( s );
- return s;
- }
- }, Outputs.text( tempFile ) )
- )
- );
-
- Assert.assertThat( tempFile.length(), CoreMatchers.equalTo( sourceFile.length() * 2 ) );
- Assert.assertThat( stringCounter.count(), CoreMatchers.equalTo( 8L ) );
- }
-
- @SuppressWarnings( "unchecked" )
- private List<Input<String, IOException>> createList( Input<String, IOException> text1,
- Input<String, IOException> text2
- )
- {
- return asList( text1, text2 );
- }
-
- @Test( expected = IOException.class )
- public void testInputOutputOutputException()
- throws IOException
- {
-
- text( sourceFile() ).
- transferTo( writerOutput( new Writer()
- {
- @Override
- public void write( char[] cbuf, int off, int len )
- throws IOException
- {
- throw new IOException();
- }
-
- @Override
- public void flush()
- throws IOException
- {
- throw new IOException();
- }
-
- @Override
- public void close()
- throws IOException
- {
- throw new IOException();
- }
- } ) );
- }
-
- @Test( expected = RemoteException.class )
- public void testInputOutputInputException()
- throws IOException
- {
-
- Input<String, RemoteException> input = new Input<String, RemoteException>()
- {
- @Override
- public <OutputThrowableType extends Throwable> void transferTo( Output<? super String, OutputThrowableType> output )
- throws RemoteException, OutputThrowableType
- {
- output.receiveFrom( new Sender<String, RemoteException>()
- {
- @Override
- public <ReceiverThrowableType extends Throwable> void sendTo( Receiver<? super String, ReceiverThrowableType> receiverThrowableTypeReceiver )
- throws ReceiverThrowableType, RemoteException
- {
- throw new RemoteException();
- }
- } );
- }
- };
-
- input.transferTo(
- Transforms.map(
- new Transforms.Log<String>( Logger.getLogger( getClass().getName() ), "Line: {0}" ),
- Outputs.systemOut()
- )
- );
- }
-
- @Test
- public void testLock()
- throws IOException
- {
- Lock inputLock = new ReentrantLock();
- Lock outputLock = new ReentrantLock();
-
- URL source = getClass().getResource( "/iotest.txt" );
- File destination = File.createTempFile( "test", ".txt" );
- destination.deleteOnExit();
- lock( inputLock, text( source ) ).transferTo( lock( outputLock, Outputs.text( destination ) ) );
- }
-
- @Test
- public void testGenerics()
- {
- ArrayList<Object> objects = new ArrayList<>( 3 );
- Inputs.iterable( Arrays.asList( "Foo", "Bar", "Xyzzy" ) ).transferTo( Outputs.collection( objects ) );
-
- Inputs.iterable( objects ).transferTo( Outputs.systemOut() );
- }
-
- @Test
- public void testOutputstreamInput()
- throws Throwable
- {
- Input<ByteBuffer, IOException> input = Inputs.output( new Visitor<OutputStream, IOException>()
- {
- @Override
- public boolean visit( OutputStream visited )
- throws IOException
- {
- try( PrintWriter writer = new PrintWriter( visited ) )
- {
- writer.print( "Hello World!" );
- }
- return true;
- }
- }, 256 );
-
- input.transferTo( Transforms.map( new Transforms.ByteBuffer2String( Charset.defaultCharset() ), Outputs.systemOut() ) );
- input.transferTo( Transforms.map( new Transforms.ByteBuffer2String( Charset.defaultCharset() ), Outputs.systemOut() ) );
- }
-
- public Output<String, IOException> writerOutput( final Writer writer )
- {
- return new Output<String, IOException>()
- {
- @Override
- public <SenderThrowableType extends Throwable> void receiveFrom( Sender<? extends String, SenderThrowableType> sender )
- throws IOException, SenderThrowableType
- {
- // Here we initiate the transfer
- System.out.println( "Open output" );
- final StringBuilder builder = new StringBuilder();
- try
- {
- sender.sendTo( new Receiver<String, IOException>()
- {
- @Override
- public void receive( String item )
- throws IOException
- {
- System.out.println( "Receive input" );
-
- // Here we can do batch writes if needed
- builder.append( item ).append( "\n" );
- }
- } );
-
- // If transfer went well, do something with it
- writer.write( builder.toString() );
- writer.flush();
- System.out.println( "Output written" );
- }
- catch( IOException e )
- {
- // If transfer failed, potentially rollback writes
- System.out.println( "Input failed" );
- throw e;
- }
- }
- };
- }
-
- private File sourceFile()
- {
- String path = getClass().getResource( "/iotest.txt" ).getFile();
- return new File( path.replaceAll( "%20", " " ) );
- }
-}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/io/src/test/java/org/qi4j/io/docsupport/IoDocs.java
----------------------------------------------------------------------
diff --git a/core/io/src/test/java/org/qi4j/io/docsupport/IoDocs.java b/core/io/src/test/java/org/qi4j/io/docsupport/IoDocs.java
deleted file mode 100644
index 6028886..0000000
--- a/core/io/src/test/java/org/qi4j/io/docsupport/IoDocs.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.qi4j.io.docsupport;
-
-import java.io.File;
-import java.io.IOException;
-import org.qi4j.io.Inputs;
-import org.qi4j.io.Outputs;
-
-// START SNIPPET: io2
-import org.qi4j.io.Transforms.Counter;
-import static org.qi4j.io.Transforms.map;
-// END SNIPPET: io2
-
-public class IoDocs
-{
- public static void main( String[] args )
- throws IOException
- {
- {
-// START SNIPPET: io1
- File source = new File( "source.txt" );
- File destination = new File( "destination.txt" );
- Inputs.text( source ).transferTo( Outputs.text( destination ) );
-// END SNIPPET: io1
- }
- {
-// START SNIPPET: io2
- File source = new File( "source.txt" );
- File destination = new File( "destination.txt" );
- Counter<String> counter = new Counter<String>();
- Inputs.text( source ).transferTo( map(counter, Outputs.text(destination) ));
- System.out.println( "Lines: " + counter.count() );
-// END SNIPPET: io2
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/Qi4jRuntimeImpl.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/Qi4jRuntimeImpl.java b/core/runtime/src/main/java/org/apache/zest/runtime/Qi4jRuntimeImpl.java
new file mode 100644
index 0000000..bbab6cb
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/Qi4jRuntimeImpl.java
@@ -0,0 +1,358 @@
+/*
+ * Copyright (c) 2007, Rickard Öberg. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.zest.runtime;
+
+import java.lang.reflect.InvocationHandler;
+import java.util.Arrays;
+import java.util.Map;
+import org.apache.zest.api.Qi4j;
+import org.apache.zest.api.association.AbstractAssociation;
+import org.apache.zest.api.association.Association;
+import org.apache.zest.api.association.AssociationDescriptor;
+import org.apache.zest.api.association.AssociationStateHolder;
+import org.apache.zest.api.association.AssociationWrapper;
+import org.apache.zest.api.association.ManyAssociation;
+import org.apache.zest.api.association.ManyAssociationWrapper;
+import org.apache.zest.api.association.NamedAssociation;
+import org.apache.zest.api.association.NamedAssociationWrapper;
+import org.apache.zest.api.composite.Composite;
+import org.apache.zest.api.composite.CompositeDescriptor;
+import org.apache.zest.api.composite.CompositeInstance;
+import org.apache.zest.api.composite.ModelDescriptor;
+import org.apache.zest.api.composite.TransientComposite;
+import org.apache.zest.api.composite.TransientDescriptor;
+import org.apache.zest.api.entity.EntityComposite;
+import org.apache.zest.api.entity.EntityDescriptor;
+import org.apache.zest.api.entity.EntityReference;
+import org.apache.zest.api.property.Property;
+import org.apache.zest.api.property.PropertyDescriptor;
+import org.apache.zest.api.property.PropertyWrapper;
+import org.apache.zest.api.property.StateHolder;
+import org.apache.zest.api.service.ServiceComposite;
+import org.apache.zest.api.service.ServiceDescriptor;
+import org.apache.zest.api.service.ServiceReference;
+import org.apache.zest.api.structure.Module;
+import org.apache.zest.api.unitofwork.UnitOfWork;
+import org.apache.zest.api.value.ValueComposite;
+import org.apache.zest.api.value.ValueDescriptor;
+import org.apache.zest.bootstrap.ApplicationAssemblyFactory;
+import org.apache.zest.bootstrap.ApplicationModelFactory;
+import org.apache.zest.bootstrap.Qi4jRuntime;
+import org.apache.zest.runtime.association.AbstractAssociationInstance;
+import org.apache.zest.runtime.association.AssociationInstance;
+import org.apache.zest.runtime.association.ManyAssociationInstance;
+import org.apache.zest.runtime.association.NamedAssociationInstance;
+import org.apache.zest.runtime.bootstrap.ApplicationAssemblyFactoryImpl;
+import org.apache.zest.runtime.bootstrap.ApplicationModelFactoryImpl;
+import org.apache.zest.runtime.composite.ProxyReferenceInvocationHandler;
+import org.apache.zest.runtime.composite.TransientInstance;
+import org.apache.zest.runtime.entity.EntityInstance;
+import org.apache.zest.runtime.property.PropertyInstance;
+import org.apache.zest.runtime.service.ImportedServiceReferenceInstance;
+import org.apache.zest.runtime.service.ServiceInstance;
+import org.apache.zest.runtime.service.ServiceReferenceInstance;
+import org.apache.zest.runtime.structure.ModuleUnitOfWork;
+import org.apache.zest.runtime.value.ValueInstance;
+import org.apache.zest.spi.Qi4jSPI;
+import org.apache.zest.spi.entity.EntityState;
+
+import static java.lang.reflect.Proxy.getInvocationHandler;
+import static org.apache.zest.runtime.composite.TransientInstance.compositeInstanceOf;
+
+/**
+ * Incarnation of Zest.
+ */
+public final class Qi4jRuntimeImpl
+ implements Qi4jSPI, Qi4jRuntime
+{
+ private final ApplicationAssemblyFactory applicationAssemblyFactory;
+ private final ApplicationModelFactory applicationModelFactory;
+
+ public Qi4jRuntimeImpl()
+ {
+ applicationAssemblyFactory = new ApplicationAssemblyFactoryImpl();
+ applicationModelFactory = new ApplicationModelFactoryImpl();
+ }
+
+ @Override
+ public ApplicationAssemblyFactory applicationAssemblyFactory()
+ {
+ return applicationAssemblyFactory;
+ }
+
+ @Override
+ public ApplicationModelFactory applicationModelFactory()
+ {
+ return applicationModelFactory;
+ }
+
+ @Override
+ public Qi4j api()
+ {
+ return this;
+ }
+
+ @Override
+ public Qi4jSPI spi()
+ {
+ return this;
+ }
+
+ // API
+
+ @Override
+ @SuppressWarnings( "unchecked" )
+ public <T> T dereference( T composite )
+ {
+ InvocationHandler handler = getInvocationHandler( composite );
+ if( handler instanceof ProxyReferenceInvocationHandler )
+ {
+ return (T) ( (ProxyReferenceInvocationHandler) handler ).proxy();
+ }
+ if( handler instanceof CompositeInstance )
+ {
+ return composite;
+ }
+ return null;
+ }
+
+ @Override
+ public Module moduleOf( Object compositeOrServiceReferenceOrUow )
+ {
+ if( compositeOrServiceReferenceOrUow instanceof TransientComposite )
+ {
+ TransientComposite composite = (TransientComposite) compositeOrServiceReferenceOrUow;
+ return TransientInstance.compositeInstanceOf( composite ).module();
+ }
+ else if( compositeOrServiceReferenceOrUow instanceof EntityComposite )
+ {
+ EntityComposite composite = (EntityComposite) compositeOrServiceReferenceOrUow;
+ return EntityInstance.entityInstanceOf( composite ).module();
+ }
+ else if( compositeOrServiceReferenceOrUow instanceof ValueComposite )
+ {
+ ValueComposite composite = (ValueComposite) compositeOrServiceReferenceOrUow;
+ return ValueInstance.valueInstanceOf( composite ).module();
+ }
+ else if( compositeOrServiceReferenceOrUow instanceof ServiceComposite )
+ {
+ ServiceComposite composite = (ServiceComposite) compositeOrServiceReferenceOrUow;
+ InvocationHandler handler = getInvocationHandler( composite );
+ if( handler instanceof ServiceInstance )
+ {
+ return ( (ServiceInstance) handler ).module();
+ }
+ return ( (ServiceReferenceInstance.ServiceInvocationHandler) handler ).module();
+ }
+ else if( compositeOrServiceReferenceOrUow instanceof UnitOfWork )
+ {
+ ModuleUnitOfWork unitOfWork = (ModuleUnitOfWork) compositeOrServiceReferenceOrUow;
+ return unitOfWork.module();
+ }
+ else if( compositeOrServiceReferenceOrUow instanceof ServiceReferenceInstance )
+ {
+ ServiceReferenceInstance<?> reference = (ServiceReferenceInstance<?>) compositeOrServiceReferenceOrUow;
+ return reference.module();
+ }
+ else if( compositeOrServiceReferenceOrUow instanceof ImportedServiceReferenceInstance )
+ {
+ ImportedServiceReferenceInstance<?> importedServiceReference
+ = (ImportedServiceReferenceInstance<?>) compositeOrServiceReferenceOrUow;
+ return importedServiceReference.module();
+ }
+ throw new IllegalArgumentException( "Wrong type. Must be one of "
+ + Arrays.asList( TransientComposite.class, ValueComposite.class,
+ ServiceComposite.class, ServiceReference.class,
+ UnitOfWork.class ) );
+ }
+
+ @Override
+ public ModelDescriptor modelDescriptorFor( Object compositeOrServiceReference )
+ {
+ if( compositeOrServiceReference instanceof TransientComposite )
+ {
+ TransientComposite composite = (TransientComposite) compositeOrServiceReference;
+ return TransientInstance.compositeInstanceOf( composite ).descriptor();
+ }
+ else if( compositeOrServiceReference instanceof EntityComposite )
+ {
+ EntityComposite composite = (EntityComposite) compositeOrServiceReference;
+ return EntityInstance.entityInstanceOf( composite ).descriptor();
+ }
+ else if( compositeOrServiceReference instanceof ValueComposite )
+ {
+ ValueComposite composite = (ValueComposite) compositeOrServiceReference;
+ return ValueInstance.valueInstanceOf( composite ).descriptor();
+ }
+ else if( compositeOrServiceReference instanceof ServiceComposite )
+ {
+ ServiceComposite composite = (ServiceComposite) compositeOrServiceReference;
+ InvocationHandler handler = getInvocationHandler( composite );
+ if( handler instanceof ServiceInstance )
+ {
+ return ( (ServiceInstance) handler ).descriptor();
+ }
+ return ( (ServiceReferenceInstance.ServiceInvocationHandler) handler ).descriptor();
+ }
+ else if( compositeOrServiceReference instanceof ServiceReferenceInstance )
+ {
+ ServiceReferenceInstance<?> reference = (ServiceReferenceInstance<?>) compositeOrServiceReference;
+ return reference.serviceDescriptor();
+ }
+ else if( compositeOrServiceReference instanceof ImportedServiceReferenceInstance )
+ {
+ ImportedServiceReferenceInstance<?> importedServiceReference
+ = (ImportedServiceReferenceInstance<?>) compositeOrServiceReference;
+ return importedServiceReference.serviceDescriptor();
+ }
+ throw new IllegalArgumentException( "Wrong type. Must be one of "
+ + Arrays.asList( TransientComposite.class, ValueComposite.class,
+ ServiceComposite.class, ServiceReference.class ) );
+ }
+
+ @Override
+ public CompositeDescriptor compositeDescriptorFor( Object compositeOrServiceReference )
+ {
+ return (CompositeDescriptor) modelDescriptorFor( compositeOrServiceReference );
+ }
+
+ // Descriptors
+
+ @Override
+ public TransientDescriptor transientDescriptorFor( Object transsient )
+ {
+ if( transsient instanceof TransientComposite )
+ {
+ TransientInstance transientInstance = compositeInstanceOf( (Composite) transsient );
+ return (TransientDescriptor) transientInstance.descriptor();
+ }
+ throw new IllegalArgumentException( "Wrong type. Must be subtype of " + TransientComposite.class );
+ }
+
+ @Override
+ public StateHolder stateOf( TransientComposite composite )
+ {
+ return TransientInstance.compositeInstanceOf( composite ).state();
+ }
+
+ @Override
+ public EntityDescriptor entityDescriptorFor( Object entity )
+ {
+ if( entity instanceof EntityComposite )
+ {
+ EntityInstance entityInstance = (EntityInstance) getInvocationHandler( entity );
+ return entityInstance.entityModel();
+ }
+ throw new IllegalArgumentException( "Wrong type. Must be subtype of " + EntityComposite.class );
+ }
+
+ @Override
+ public AssociationStateHolder stateOf( EntityComposite composite )
+ {
+ return EntityInstance.entityInstanceOf( composite ).state();
+ }
+
+ @Override
+ public ValueDescriptor valueDescriptorFor( Object value )
+ {
+ if( value instanceof ValueComposite )
+ {
+ ValueInstance valueInstance = ValueInstance.valueInstanceOf( (ValueComposite) value );
+ return valueInstance.descriptor();
+ }
+ throw new IllegalArgumentException( "Wrong type. Must be subtype of " + ValueComposite.class );
+ }
+
+ @Override
+ public AssociationStateHolder stateOf( ValueComposite composite )
+ {
+ return ValueInstance.valueInstanceOf( composite ).state();
+ }
+
+ @Override
+ public ServiceDescriptor serviceDescriptorFor( Object service )
+ {
+ if( service instanceof ServiceReferenceInstance )
+ {
+ ServiceReferenceInstance<?> ref = (ServiceReferenceInstance<?>) service;
+ return ref.serviceDescriptor();
+ }
+ if( service instanceof ServiceComposite )
+ {
+ ServiceComposite composite = (ServiceComposite) service;
+ return (ServiceDescriptor) ServiceInstance.serviceInstanceOf( composite ).descriptor();
+ }
+ throw new IllegalArgumentException( "Wrong type. Must be subtype of "
+ + ServiceComposite.class + " or " + ServiceReference.class );
+ }
+
+ @Override
+ public PropertyDescriptor propertyDescriptorFor( Property<?> property )
+ {
+ while( property instanceof PropertyWrapper )
+ {
+ property = ( (PropertyWrapper) property ).next();
+ }
+
+ return (PropertyDescriptor) ( (PropertyInstance<?>) property ).propertyInfo();
+ }
+
+ @Override
+ public AssociationDescriptor associationDescriptorFor( AbstractAssociation association )
+ {
+ while( association instanceof AssociationWrapper )
+ {
+ association = ( (AssociationWrapper) association ).next();
+ }
+
+ while( association instanceof ManyAssociationWrapper )
+ {
+ association = ( (ManyAssociationWrapper) association ).next();
+ }
+
+ while( association instanceof NamedAssociationWrapper )
+ {
+ association = ( (NamedAssociationWrapper) association ).next();
+ }
+
+ return (AssociationDescriptor) ( (AbstractAssociationInstance) association ).associationInfo();
+ }
+
+ // SPI
+ @Override
+ public EntityState entityStateOf( EntityComposite composite )
+ {
+ return EntityInstance.entityInstanceOf( composite ).entityState();
+ }
+
+ @Override
+ public EntityReference entityReferenceOf( Association assoc )
+ {
+ @SuppressWarnings( "unchecked" )
+ Property<EntityReference> associationState = ( (AssociationInstance) assoc ).getAssociationState();
+ return associationState.get();
+ }
+
+ @Override
+ public Iterable<EntityReference> entityReferenceOf( ManyAssociation assoc )
+ {
+ return ( (ManyAssociationInstance) assoc ).getManyAssociationState();
+ }
+
+ @Override
+ public Iterable<Map.Entry<String, EntityReference>> entityReferenceOf( NamedAssociation assoc )
+ {
+ return ( (NamedAssociationInstance) assoc ).getEntityReferences();
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/activation/ActivationDelegate.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/activation/ActivationDelegate.java b/core/runtime/src/main/java/org/apache/zest/runtime/activation/ActivationDelegate.java
new file mode 100644
index 0000000..e7406b2
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/activation/ActivationDelegate.java
@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) 2008, Rickard Öberg. All Rights Reserved.
+ * Copyright (c) 2012, Paul Merlin.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.zest.runtime.activation;
+
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.Set;
+import org.apache.zest.api.activation.Activation;
+import org.apache.zest.api.activation.ActivationEvent;
+import org.apache.zest.api.activation.ActivationEventListener;
+import org.apache.zest.api.activation.ActivationException;
+import org.apache.zest.api.activation.PassivationException;
+import org.apache.zest.api.service.ServiceReference;
+
+import static org.apache.zest.api.activation.ActivationEvent.EventType.ACTIVATED;
+import static org.apache.zest.api.activation.ActivationEvent.EventType.ACTIVATING;
+import static org.apache.zest.api.activation.ActivationEvent.EventType.PASSIVATED;
+import static org.apache.zest.api.activation.ActivationEvent.EventType.PASSIVATING;
+
+/**
+ * This class manage Activation of a target and propagates to children.
+ */
+@SuppressWarnings( "raw" )
+public final class ActivationDelegate
+ extends ActivationEventListenerSupport
+{
+ private final Object target;
+ private final boolean fireEvents;
+ private ActivatorsInstance targetActivators = null;
+ private final LinkedList<Activation> activeChildren = new LinkedList<>();
+
+ /**
+ * Create a new ActivationDelegate that will fire events.
+ * @param target target of Activation
+ */
+ public ActivationDelegate( Object target )
+ {
+ this( target, true );
+ }
+
+ /**
+ * Create a new ActivationDelegate.
+ * @param target target of Activation
+ * @param fireEvents if {@link ActivationEvent}s should be fired
+ */
+ public ActivationDelegate( Object target, boolean fireEvents )
+ {
+ super();
+ this.target = target;
+ this.fireEvents = fireEvents;
+ }
+
+ public void activate( ActivatorsInstance targetActivators, Activation child )
+ throws Exception
+ {
+ activate( targetActivators, Collections.singleton( child ), null );
+ }
+
+ public void activate( ActivatorsInstance targetActivators, Activation child, Runnable callback )
+ throws Exception
+ {
+ activate( targetActivators, Collections.singleton( child ), callback );
+ }
+
+ public void activate( ActivatorsInstance targetActivators, Iterable<? extends Activation> children )
+ throws ActivationException
+ {
+ activate( targetActivators, children, null );
+ }
+
+ @SuppressWarnings( "unchecked" )
+ public void activate( ActivatorsInstance targetActivators, Iterable<? extends Activation> children, Runnable callback )
+ throws ActivationException
+ {
+ if( this.targetActivators != null )
+ {
+ throw new IllegalStateException( "Activation.activate() called multiple times "
+ + "or without calling passivate() first!" );
+ }
+
+ try
+ {
+ // Before Activation Events
+ if( fireEvents )
+ {
+ fireEvent( new ActivationEvent( target, ACTIVATING ) );
+ }
+
+ // Before Activation for Activators
+ targetActivators.beforeActivation( target instanceof ServiceReference
+ ? new PassiveServiceReference( (ServiceReference) target )
+ : target );
+
+ // Activation
+ for( Activation child : children )
+ {
+ if( !activeChildren.contains( child ) )
+ {
+ child.activate();
+ }
+ activeChildren.addFirst( child );
+ }
+
+ // Internal Activation Callback
+ if( callback != null )
+ {
+ callback.run();
+ }
+
+ // After Activation
+ targetActivators.afterActivation( target );
+
+ // After Activation Events
+ if( fireEvents )
+ {
+ fireEvent( new ActivationEvent( target, ACTIVATED ) );
+ }
+
+ // Activated
+ this.targetActivators = targetActivators;
+ }
+ catch( Exception e )
+ {
+ // Passivate actives
+ try
+ {
+ passivate();
+ }
+ catch( PassivationException e1 )
+ {
+ ActivationException activationEx = new ActivationException( "Unable to Activate application.", e );
+ activationEx.addSuppressed( e1 );
+ throw activationEx;
+ }
+ if( e instanceof ActivationException )
+ {
+ throw ( (ActivationException) e );
+ }
+ throw new ActivationException( "Unable to Activate application.", e );
+ }
+ }
+
+ public void passivate()
+ throws PassivationException
+ {
+ passivate( (Runnable) null );
+ }
+
+ @SuppressWarnings( "unchecked" )
+ public void passivate( Runnable callback )
+ throws PassivationException
+ {
+ Set<Exception> exceptions = new LinkedHashSet<>();
+
+ // Before Passivation Events
+ if( fireEvents )
+ {
+ ActivationEvent event = new ActivationEvent( target, PASSIVATING );
+ for( ActivationEventListener listener : listeners )
+ {
+ try
+ {
+ listener.onEvent( event );
+ }
+ catch( Exception ex )
+ {
+ if( ex instanceof PassivationException )
+ {
+ exceptions.addAll( ( (PassivationException) ex ).causes() );
+ }
+ else
+ {
+ exceptions.add( ex );
+ }
+ }
+ }
+ }
+
+ // Before Passivation for Activators
+ if( targetActivators != null )
+ {
+ try
+ {
+ targetActivators.beforePassivation( target );
+ }
+ catch( PassivationException ex )
+ {
+ exceptions.addAll( ex.causes() );
+ }
+ catch( Exception ex )
+ {
+ exceptions.add( ex );
+ }
+ }
+
+ // Passivation
+ while( !activeChildren.isEmpty() )
+ {
+ passivateOneChild( exceptions );
+ }
+
+ // Internal Passivation Callback
+ if( callback != null )
+ {
+ try
+ {
+ callback.run();
+ }
+ catch( Exception ex )
+ {
+ if( ex instanceof PassivationException )
+ {
+ exceptions.addAll( ( (PassivationException) ex ).causes() );
+ }
+ else
+ {
+ exceptions.add( ex );
+ }
+ }
+ }
+
+ // After Passivation for Activators
+ if( targetActivators != null )
+ {
+ try
+ {
+ targetActivators.afterPassivation( target instanceof ServiceReference
+ ? new PassiveServiceReference( (ServiceReference) target )
+ : target );
+ }
+ catch( PassivationException ex )
+ {
+ exceptions.addAll( ex.causes() );
+ }
+ catch( Exception ex )
+ {
+ exceptions.add( ex );
+ }
+ }
+ targetActivators = null;
+
+ // After Passivation Events
+ if( fireEvents )
+ {
+ ActivationEvent event = new ActivationEvent( target, PASSIVATED );
+ for( ActivationEventListener listener : listeners )
+ {
+ try
+ {
+ listener.onEvent( event );
+ }
+ catch( Exception ex )
+ {
+ if( ex instanceof PassivationException )
+ {
+ exceptions.addAll( ( (PassivationException) ex ).causes() );
+ }
+ else
+ {
+ exceptions.add( ex );
+ }
+ }
+ }
+ }
+
+ // Error handling
+ if( exceptions.isEmpty() )
+ {
+ return;
+ }
+ throw new PassivationException( exceptions );
+ }
+
+ @SuppressWarnings( "TooBroadCatch" )
+ private void passivateOneChild( Set<Exception> exceptions )
+ {
+ Activation activeChild = activeChildren.removeFirst();
+ try
+ {
+ activeChild.passivate();
+ }
+ catch( PassivationException ex )
+ {
+ exceptions.addAll( ex.causes() );
+ }
+ catch( Exception ex )
+ {
+ exceptions.add( ex );
+ }
+ }
+
+ @SuppressWarnings( "raw" )
+ private static class PassiveServiceReference
+ implements ServiceReference
+ {
+
+ private final ServiceReference reference;
+
+ private PassiveServiceReference( ServiceReference reference )
+ {
+ this.reference = reference;
+ }
+
+ @Override
+ public String identity()
+ {
+ return reference.identity();
+ }
+
+ @Override
+ public Object get()
+ {
+ throw new IllegalStateException( "Service is passive, either activating and"
+ + " cannot be used yet or passivating and cannot be used anymore." );
+ }
+
+ @Override
+ public boolean isActive()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isAvailable()
+ {
+ return false;
+ }
+
+ @Override
+ public Iterable<Class<?>> types()
+ {
+ return reference.types();
+ }
+
+ @Override
+ public <T> T metaInfo( Class<T> infoType )
+ {
+ return reference.metaInfo( infoType );
+ }
+
+ @Override
+ public void registerActivationEventListener( ActivationEventListener listener )
+ {
+ reference.registerActivationEventListener( listener );
+ }
+
+ @Override
+ public void deregisterActivationEventListener( ActivationEventListener listener )
+ {
+ reference.deregisterActivationEventListener( listener );
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return identity().hashCode();
+ }
+
+ @Override
+ public boolean equals( Object obj )
+ {
+ if( obj == null )
+ {
+ return false;
+ }
+ if( getClass() != obj.getClass() )
+ {
+ return false;
+ }
+ final ServiceReference other = (ServiceReference) obj;
+ return identity().equals( other.identity() );
+ }
+
+ @Override
+ public String toString()
+ {
+ return reference.toString();
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/activation/ActivationEventListenerSupport.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/activation/ActivationEventListenerSupport.java b/core/runtime/src/main/java/org/apache/zest/runtime/activation/ActivationEventListenerSupport.java
new file mode 100644
index 0000000..fb8a9b7
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/activation/ActivationEventListenerSupport.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2011, Rickard Öberg.
+ * Copyright (c) 2012, Niclas Hedhman.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.zest.runtime.activation;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.zest.api.activation.ActivationEvent;
+import org.apache.zest.api.activation.ActivationEventListener;
+import org.apache.zest.api.activation.ActivationEventListenerRegistration;
+
+/**
+ * Internal helper for managing registrations and firing events
+ */
+/* package */ class ActivationEventListenerSupport
+ implements ActivationEventListenerRegistration, ActivationEventListener
+{
+ protected List<ActivationEventListener> listeners = new ArrayList<>();
+
+ @Override
+ public void registerActivationEventListener( ActivationEventListener listener )
+ {
+ List<ActivationEventListener> newListeners = new ArrayList<>();
+ newListeners.addAll( listeners );
+ newListeners.add( listener );
+ listeners = newListeners;
+ }
+
+ @Override
+ public void deregisterActivationEventListener( ActivationEventListener listener )
+ {
+ List<ActivationEventListener> newListeners = new ArrayList<>();
+ newListeners.addAll( listeners );
+ newListeners.remove( listener );
+ listeners = newListeners;
+ }
+
+ /* package */ void fireEvent( ActivationEvent event )
+ throws Exception
+ {
+ for( ActivationEventListener listener : listeners )
+ {
+ listener.onEvent( event );
+ }
+ }
+
+ @Override
+ public void onEvent( ActivationEvent event )
+ throws Exception
+ {
+ fireEvent( event );
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/activation/ActivatorModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/activation/ActivatorModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/activation/ActivatorModel.java
new file mode 100644
index 0000000..034d3a6
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/activation/ActivatorModel.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2014, Paul Merlin. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zest.runtime.activation;
+
+import org.apache.zest.api.activation.Activator;
+import org.apache.zest.api.activation.ActivatorDescriptor;
+import org.apache.zest.api.common.ConstructionException;
+import org.apache.zest.functional.HierarchicalVisitor;
+import org.apache.zest.functional.VisitableHierarchy;
+import org.apache.zest.runtime.composite.ConstructorsModel;
+import org.apache.zest.runtime.injection.InjectedFieldsModel;
+import org.apache.zest.runtime.injection.InjectedMethodsModel;
+import org.apache.zest.runtime.injection.InjectionContext;
+
+/**
+ * Model for a single Activator.
+ *
+ * @param <ActivateeType> Type of the activation target
+ */
+public class ActivatorModel<ActivateeType>
+ implements ActivatorDescriptor, VisitableHierarchy<Object, Object>
+{
+ private final Class<? extends Activator<ActivateeType>> activatorType;
+ private final ConstructorsModel constructorsModel;
+ private final InjectedFieldsModel injectedFieldsModel;
+ private final InjectedMethodsModel injectedMethodsModel;
+
+ public ActivatorModel( Class<? extends Activator<ActivateeType>> activatorType )
+ {
+ this.activatorType = activatorType;
+ this.constructorsModel = new ConstructorsModel( activatorType );
+ this.injectedFieldsModel = new InjectedFieldsModel( activatorType );
+ this.injectedMethodsModel = new InjectedMethodsModel( activatorType );
+ }
+
+ @Override
+ public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> visitor )
+ throws ThrowableType
+ {
+ if( visitor.visitEnter( this ) )
+ {
+ if( constructorsModel.accept( visitor ) )
+ {
+ if( injectedFieldsModel.accept( visitor ) )
+ {
+ injectedMethodsModel.accept( visitor );
+ }
+ }
+ }
+ return visitor.visitLeave( this );
+ }
+
+ public Activator<ActivateeType> newInstance()
+ {
+ try
+ {
+ return activatorType.newInstance();
+ }
+ catch( InstantiationException | IllegalAccessException ex )
+ {
+ throw new ConstructionException( "Could not instantiate " + activatorType.getName(), ex );
+ }
+ }
+
+ @SuppressWarnings( "unchecked" )
+ public Activator<ActivateeType> newInstance( InjectionContext injectionContext )
+ {
+ try
+ {
+ Activator<ActivateeType> instance = (Activator<ActivateeType>) constructorsModel.newInstance( injectionContext );
+ injectionContext = new InjectionContext( injectionContext.module(), injectionContext.uses(), instance );
+ inject( injectionContext, instance );
+ return instance;
+ }
+ catch( Exception ex )
+ {
+ throw new ConstructionException( "Could not instantiate " + activatorType.getName(), ex );
+ }
+ }
+
+ public void inject( InjectionContext injectionContext, Activator<ActivateeType> instance )
+ {
+ injectedFieldsModel.inject( injectionContext, instance );
+ injectedMethodsModel.inject( injectionContext, instance );
+ }
+
+ @Override
+ public String toString()
+ {
+ return activatorType.getName();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/activation/ActivatorsInstance.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/activation/ActivatorsInstance.java b/core/runtime/src/main/java/org/apache/zest/runtime/activation/ActivatorsInstance.java
new file mode 100644
index 0000000..e8a6e49
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/activation/ActivatorsInstance.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2012, Paul Merlin.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.zest.runtime.activation;
+
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import org.apache.zest.api.activation.Activator;
+import org.apache.zest.api.activation.PassivationException;
+import org.apache.zest.functional.Iterables;
+
+/**
+ * Instance of a Zest Activators of one Activation target. Contains ordered
+ * Activators and roll the Activation on the target.
+ *
+ * @param <ActivateeType> Type of the activation target
+ */
+public class ActivatorsInstance<ActivateeType>
+ implements Activator<ActivateeType>
+{
+ @SuppressWarnings( {"raw", "unchecked"} )
+ public static final ActivatorsInstance EMPTY = new ActivatorsInstance( Collections.emptyList() );
+
+ private final Iterable<Activator<ActivateeType>> activators;
+
+ public ActivatorsInstance( Iterable<Activator<ActivateeType>> activators )
+ {
+ this.activators = activators;
+ }
+
+ @Override
+ public void beforeActivation( ActivateeType activating )
+ throws Exception
+ {
+ for( Activator<ActivateeType> activator : activators )
+ {
+ activator.beforeActivation( activating );
+ }
+ }
+
+ @Override
+ public void afterActivation( ActivateeType activated )
+ throws Exception
+ {
+ for( Activator<ActivateeType> activator : activators )
+ {
+ activator.afterActivation( activated );
+ }
+ }
+
+ @Override
+ public void beforePassivation( ActivateeType passivating )
+ throws Exception
+ {
+ Set<Exception> exceptions = new LinkedHashSet<>();
+ for( Activator<ActivateeType> activator : Iterables.reverse( activators ) )
+ {
+ try
+ {
+ activator.beforePassivation( passivating );
+ }
+ catch( Exception ex )
+ {
+ exceptions.add( ex );
+ }
+ }
+ if( !exceptions.isEmpty() )
+ {
+ throw new PassivationException( exceptions );
+ }
+ }
+
+ @Override
+ public void afterPassivation( ActivateeType passivated )
+ throws Exception
+ {
+ Set<Exception> exceptions = new LinkedHashSet<>();
+ for( Activator<ActivateeType> activator : Iterables.reverse( activators ) )
+ {
+ try
+ {
+ activator.afterPassivation( passivated );
+ }
+ catch( Exception ex )
+ {
+ exceptions.add( ex );
+ }
+ }
+ if( !exceptions.isEmpty() )
+ {
+ throw new PassivationException( exceptions );
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/activation/ActivatorsModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/activation/ActivatorsModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/activation/ActivatorsModel.java
new file mode 100644
index 0000000..2483461
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/activation/ActivatorsModel.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2012-2014, Paul Merlin. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zest.runtime.activation;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.zest.api.activation.ActivationException;
+import org.apache.zest.api.activation.Activator;
+import org.apache.zest.api.structure.Module;
+import org.apache.zest.functional.HierarchicalVisitor;
+import org.apache.zest.functional.VisitableHierarchy;
+import org.apache.zest.runtime.composite.UsesInstance;
+import org.apache.zest.runtime.injection.InjectionContext;
+import org.apache.zest.runtime.structure.ModuleInstance;
+
+/**
+ * Activators Model.
+ *
+ * @param <ActivateeType> Type of the activation target
+ */
+public class ActivatorsModel<ActivateeType>
+ implements VisitableHierarchy<Object, Object>
+{
+
+ private final List<ActivatorModel<ActivateeType>> activatorModels = new ArrayList<>();
+ private final Iterable<Class<? extends Activator<ActivateeType>>> activatorsClasses;
+
+ public ActivatorsModel( Iterable<Class<? extends Activator<ActivateeType>>> activatorsClasses )
+ {
+ this.activatorsClasses = activatorsClasses;
+ for( Class<? extends Activator<ActivateeType>> activatorClass : activatorsClasses )
+ {
+ activatorModels.add( new ActivatorModel<>( activatorClass ) );
+ }
+ }
+
+ @Override
+ public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> visitor )
+ throws ThrowableType
+ {
+ if( visitor.visitEnter( this ) )
+ {
+ for( ActivatorModel<ActivateeType> activatorModel : activatorModels )
+ {
+ if( !activatorModel.accept( visitor ) )
+ {
+ break;
+ }
+ }
+ }
+ return visitor.visitLeave( this );
+ }
+
+ public Iterable<ActivatorModel<ActivateeType>> models()
+ {
+ return activatorModels;
+ }
+
+ public Iterable<Activator<ActivateeType>> newInstances()
+ throws ActivationException
+ {
+ List<Activator<ActivateeType>> activators = new ArrayList<>();
+ for( ActivatorModel<ActivateeType> activatorModel : activatorModels )
+ {
+ activators.add( activatorModel.newInstance() );
+ }
+ return activators;
+ }
+
+ public Iterable<Activator<ActivateeType>> newInstances( Module module )
+ throws ActivationException
+ {
+ List<Activator<ActivateeType>> activators = new ArrayList<>();
+ for( ActivatorModel<ActivateeType> activatorModel : activatorModels )
+ {
+ InjectionContext injectionContext = new InjectionContext( (ModuleInstance) module, UsesInstance.EMPTY_USES );
+ activators.add( activatorModel.newInstance( injectionContext ) );
+ }
+ return activators;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/association/AbstractAssociationInstance.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/association/AbstractAssociationInstance.java b/core/runtime/src/main/java/org/apache/zest/runtime/association/AbstractAssociationInstance.java
new file mode 100644
index 0000000..f2ca0a3
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/association/AbstractAssociationInstance.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.zest.runtime.association;
+
+import java.lang.reflect.Type;
+import org.apache.zest.api.association.AbstractAssociation;
+import org.apache.zest.api.entity.EntityReference;
+import org.apache.zest.api.entity.Identity;
+import org.apache.zest.functional.Function2;
+
+/**
+ * Implementation of AbstractAssociation. Includes helper methods for subclasses
+ */
+public abstract class AbstractAssociationInstance<T>
+ implements AbstractAssociation
+{
+ protected AssociationInfo associationInfo;
+ private final Function2<EntityReference, Type, Object> entityFunction;
+
+ public AbstractAssociationInstance( AssociationInfo associationInfo,
+ Function2<EntityReference, Type, Object> entityFunction
+ )
+ {
+ this.associationInfo = associationInfo;
+ this.entityFunction = entityFunction;
+ }
+
+ public AssociationInfo associationInfo()
+ {
+ return associationInfo;
+ }
+
+ public void setAssociationInfo( AssociationInfo newInfo )
+ {
+ this.associationInfo = newInfo;
+ }
+
+ @SuppressWarnings( "unchecked" )
+ protected T getEntity( EntityReference entityId )
+ {
+ if( entityId == null )
+ {
+ return null;
+ }
+
+ return (T) entityFunction.map( entityId, associationInfo.type() );
+ }
+
+ protected EntityReference getEntityReference( Object composite )
+ {
+ if( composite == null )
+ {
+ return null;
+ }
+
+ return new EntityReference( ( (Identity) composite ).identity().get() );
+ }
+
+ protected void checkType( Object instance )
+ {
+
+ if( instance instanceof Identity || instance == null )
+ {
+ return;
+ }
+ throw new IllegalArgumentException( "Object must be a subtype of org.qi4j.api.identity.Identity: " + instance.getClass() );
+ }
+
+ protected void checkImmutable()
+ throws IllegalStateException
+ {
+ if( associationInfo.isImmutable() )
+ {
+ throw new IllegalStateException( "Association [" + associationInfo.qualifiedName() + "] is immutable." );
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/association/AssociationInfo.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/association/AssociationInfo.java b/core/runtime/src/main/java/org/apache/zest/runtime/association/AssociationInfo.java
new file mode 100644
index 0000000..1e70643
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/association/AssociationInfo.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.zest.runtime.association;
+
+import java.lang.reflect.Type;
+import org.apache.zest.api.common.QualifiedName;
+import org.apache.zest.runtime.composite.ConstraintsCheck;
+
+/**
+ * TODO
+ */
+public interface AssociationInfo
+ extends ConstraintsCheck
+{
+ boolean isImmutable();
+
+ QualifiedName qualifiedName();
+
+ Type type();
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/association/AssociationInstance.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/association/AssociationInstance.java b/core/runtime/src/main/java/org/apache/zest/runtime/association/AssociationInstance.java
new file mode 100644
index 0000000..84568d4
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/association/AssociationInstance.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2007, Rickard Öberg. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.zest.runtime.association;
+
+import java.lang.reflect.Type;
+import org.apache.zest.api.association.Association;
+import org.apache.zest.api.association.AssociationDescriptor;
+import org.apache.zest.api.association.AssociationWrapper;
+import org.apache.zest.api.entity.EntityReference;
+import org.apache.zest.api.entity.Identity;
+import org.apache.zest.api.property.Property;
+import org.apache.zest.functional.Function2;
+
+/**
+ * Implementation of Association to a single Entity.
+ */
+public final class AssociationInstance<T>
+ extends AbstractAssociationInstance<T>
+ implements Association<T>
+{
+ private Property<EntityReference> associationState;
+
+ public AssociationInstance( AssociationInfo associationInfo,
+ Function2<EntityReference, Type, Object> entityFunction,
+ Property<EntityReference> associationState
+ )
+ {
+ super( associationInfo, entityFunction );
+ this.associationState = associationState;
+ }
+
+ // Association implementation
+ @Override
+ public T get()
+ {
+ return getEntity( associationState.get() );
+ }
+
+ @Override
+ public void set( T newValue )
+ throws IllegalArgumentException
+ {
+ checkImmutable();
+ checkType( newValue );
+
+ associationInfo.checkConstraints( newValue );
+
+ // Change association
+ associationState.set( EntityReference.create( (Identity) newValue ));
+ }
+
+ @Override
+ public EntityReference reference()
+ {
+ return associationState.get();
+ }
+
+ public Property<EntityReference> getAssociationState()
+ {
+ return associationState;
+ }
+
+ @Override
+ public String toString()
+ {
+ if( associationState.get() == null )
+ {
+ return "";
+ }
+ else
+ {
+ return associationState.get().toString();
+ }
+ }
+
+ @Override
+ public int hashCode()
+ {
+ int hash = associationInfo.hashCode() * 39; // Descriptor
+ if( associationState.get() != null )
+ {
+ hash = hash * 997 + associationState.get().hashCode(); // State
+ }
+ return hash;
+ }
+
+ @Override
+ public boolean equals( Object o )
+ {
+ if( this == o )
+ {
+ return true;
+ }
+ if( o == null || getClass() != o.getClass() )
+ {
+ return false;
+ }
+ Association<?> that = (Association) o;
+ // Unwrap if needed
+ while( that instanceof AssociationWrapper )
+ {
+ that = ( (AssociationWrapper) that ).next();
+ }
+ // Descriptor equality
+ AssociationInstance<?> thatInstance = (AssociationInstance) that;
+ AssociationDescriptor thatDescriptor = (AssociationDescriptor) thatInstance.associationInfo();
+ if( !associationInfo.equals( thatDescriptor ) )
+ {
+ return false;
+ }
+ // State equality
+ if( associationState.get() != null
+ ? !associationState.get().equals( thatInstance.associationState.get() )
+ : thatInstance.associationState.get() != null )
+ {
+ return false;
+ }
+ return true;
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/association/AssociationModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/association/AssociationModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/association/AssociationModel.java
new file mode 100644
index 0000000..323b5aa
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/association/AssociationModel.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2008, Rickard Öberg. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.zest.runtime.association;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.List;
+import org.apache.zest.api.association.Association;
+import org.apache.zest.api.association.AssociationDescriptor;
+import org.apache.zest.api.association.GenericAssociationInfo;
+import org.apache.zest.api.common.MetaInfo;
+import org.apache.zest.api.common.QualifiedName;
+import org.apache.zest.api.composite.Composite;
+import org.apache.zest.api.constraint.ConstraintViolation;
+import org.apache.zest.api.constraint.ConstraintViolationException;
+import org.apache.zest.api.entity.Aggregated;
+import org.apache.zest.api.entity.Queryable;
+import org.apache.zest.api.property.Immutable;
+import org.apache.zest.api.util.Classes;
+import org.apache.zest.bootstrap.BindingException;
+import org.apache.zest.functional.Visitable;
+import org.apache.zest.functional.Visitor;
+import org.apache.zest.runtime.composite.ValueConstraintsInstance;
+import org.apache.zest.runtime.model.Binder;
+import org.apache.zest.runtime.model.Resolution;
+
+import static org.apache.zest.functional.Iterables.empty;
+import static org.apache.zest.functional.Iterables.first;
+
+/**
+ * Model for an Association.
+ *
+ * <p>Equality is based on the Association accessor object (associated type and name), not on the QualifiedName.</p>
+ */
+public final class AssociationModel
+ implements AssociationDescriptor, AssociationInfo, Binder, Visitable<AssociationModel>
+{
+ private MetaInfo metaInfo;
+ private Type type;
+ private AccessibleObject accessor;
+ private QualifiedName qualifiedName;
+ private ValueConstraintsInstance constraints;
+ private ValueConstraintsInstance associationConstraints;
+ private boolean queryable;
+ private boolean immutable;
+ private boolean aggregated;
+ private AssociationInfo builderInfo;
+
+ public AssociationModel( AccessibleObject accessor,
+ ValueConstraintsInstance valueConstraintsInstance,
+ ValueConstraintsInstance associationConstraintsInstance,
+ MetaInfo metaInfo
+ )
+ {
+ this.metaInfo = metaInfo;
+ this.constraints = valueConstraintsInstance;
+ this.associationConstraints = associationConstraintsInstance;
+ this.accessor = accessor;
+ initialize();
+ }
+
+ private void initialize()
+ {
+ this.type = GenericAssociationInfo.associationTypeOf( accessor );
+ this.qualifiedName = QualifiedName.fromAccessor( accessor );
+ this.immutable = metaInfo.get( Immutable.class ) != null;
+ this.aggregated = metaInfo.get( Aggregated.class ) != null;
+
+ final Queryable queryable = accessor.getAnnotation( Queryable.class );
+ this.queryable = queryable == null || queryable.value();
+ }
+
+ @Override
+ public <T> T metaInfo( Class<T> infoType )
+ {
+ return metaInfo.get( infoType );
+ }
+
+ @Override
+ public QualifiedName qualifiedName()
+ {
+ return qualifiedName;
+ }
+
+ @Override
+ public Type type()
+ {
+ return type;
+ }
+
+ @Override
+ public boolean isImmutable()
+ {
+ return immutable;
+ }
+
+ @Override
+ public boolean isAggregated()
+ {
+ return aggregated;
+ }
+
+ @Override
+ public AccessibleObject accessor()
+ {
+ return accessor;
+ }
+
+ @Override
+ public boolean queryable()
+ {
+ return queryable;
+ }
+
+ public AssociationInfo getBuilderInfo()
+ {
+ return builderInfo;
+ }
+
+ @Override
+ public <ThrowableType extends Throwable> boolean accept( Visitor<? super AssociationModel, ThrowableType> visitor )
+ throws ThrowableType
+ {
+ return visitor.visit( this );
+ }
+
+ @Override
+ public void checkConstraints( Object value )
+ throws ConstraintViolationException
+ {
+ if( constraints != null )
+ {
+ List<ConstraintViolation> violations = constraints.checkConstraints( value );
+ if( !violations.isEmpty() )
+ {
+ Iterable<Class<?>> empty = empty();
+ throw new ConstraintViolationException( "", empty, (Member) accessor, violations );
+ }
+ }
+ }
+
+ public void checkAssociationConstraints( Association<?> association )
+ throws ConstraintViolationException
+ {
+ if( associationConstraints != null )
+ {
+ List<ConstraintViolation> violations = associationConstraints.checkConstraints( association );
+ if( !violations.isEmpty() )
+ {
+ throw new ConstraintViolationException( (Composite) association.get(), (Member) accessor, violations );
+ }
+ }
+ }
+
+ @Override
+ public void bind( Resolution resolution )
+ throws BindingException
+ {
+ builderInfo = new AssociationInfo()
+ {
+ @Override
+ public boolean isImmutable()
+ {
+ return false;
+ }
+
+ @Override
+ public QualifiedName qualifiedName()
+ {
+ return qualifiedName;
+ }
+
+ @Override
+ public Type type()
+ {
+ return type;
+ }
+
+ @Override
+ public void checkConstraints( Object value )
+ throws ConstraintViolationException
+ {
+ AssociationModel.this.checkConstraints( value );
+ }
+ };
+
+ if( type instanceof TypeVariable )
+ {
+
+ Class mainType = first( resolution.model().types() );
+ type = Classes.resolveTypeVariable( (TypeVariable) type, ( (Member) accessor ).getDeclaringClass(), mainType );
+ }
+ }
+
+ @Override
+ public boolean equals( Object o )
+ {
+ if( this == o )
+ {
+ return true;
+ }
+ if( o == null || getClass() != o.getClass() )
+ {
+ return false;
+ }
+
+ AssociationModel that = (AssociationModel) o;
+
+ if( !accessor.equals( that.accessor ) )
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return accessor.hashCode();
+ }
+
+ @Override
+ public String toString()
+ {
+ if( accessor instanceof Field )
+ {
+ return ( (Field) accessor ).toGenericString();
+ }
+ else
+ {
+ return ( (Method) accessor ).toGenericString();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/association/AssociationsModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/association/AssociationsModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/association/AssociationsModel.java
new file mode 100644
index 0000000..a0f3d67
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/association/AssociationsModel.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2008-2011, Rickard Öberg. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.zest.runtime.association;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Member;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import org.apache.zest.api.association.Association;
+import org.apache.zest.api.association.AssociationDescriptor;
+import org.apache.zest.api.association.AssociationStateHolder;
+import org.apache.zest.api.common.QualifiedName;
+import org.apache.zest.functional.HierarchicalVisitor;
+import org.apache.zest.functional.VisitableHierarchy;
+
+/**
+ * Model for Associations.
+ */
+public final class AssociationsModel
+ implements VisitableHierarchy<AssociationsModel, AssociationModel>
+{
+ private final Map<AccessibleObject, AssociationModel> mapAccessorAssociationModel = new LinkedHashMap<>();
+
+ public AssociationsModel()
+ {
+ }
+
+ public Iterable<AssociationModel> associations()
+ {
+ return mapAccessorAssociationModel.values();
+ }
+
+ public void addAssociation( AssociationModel associationModel )
+ {
+ mapAccessorAssociationModel.put( associationModel.accessor(), associationModel );
+ }
+
+ @Override
+ public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super AssociationsModel, ? super AssociationModel, ThrowableType> visitor )
+ throws ThrowableType
+ {
+ if( visitor.visitEnter( this ) )
+ {
+ for( AssociationModel associationModel : mapAccessorAssociationModel.values() )
+ {
+ if( !associationModel.accept( visitor ) )
+ {
+ break;
+ }
+ }
+ }
+ return visitor.visitLeave( this );
+ }
+
+ public AssociationModel getAssociation( AccessibleObject accessor )
+ throws IllegalArgumentException
+ {
+ AssociationModel associationModel = mapAccessorAssociationModel.get( accessor );
+ if( associationModel == null )
+ {
+ throw new IllegalArgumentException( "No association found with name:" + ( (Member) accessor ).getName() );
+ }
+ return associationModel;
+ }
+
+ public AssociationDescriptor getAssociationByName( String name )
+ throws IllegalArgumentException
+ {
+ for( AssociationModel associationModel : mapAccessorAssociationModel.values() )
+ {
+ if( associationModel.qualifiedName().name().equals( name ) )
+ {
+ return associationModel;
+ }
+ }
+ throw new IllegalArgumentException( "No association found with name:" + name );
+ }
+
+ public AssociationDescriptor getAssociationByQualifiedName( QualifiedName name )
+ throws IllegalArgumentException
+ {
+ for( AssociationModel associationModel : mapAccessorAssociationModel.values() )
+ {
+ if( associationModel.qualifiedName().equals( name ) )
+ {
+ return associationModel;
+ }
+ }
+ throw new IllegalArgumentException( "No association found with qualified name:" + name );
+ }
+
+ public void checkConstraints( AssociationStateHolder state )
+ {
+ for( AssociationModel associationModel : mapAccessorAssociationModel.values() )
+ {
+ Association<Object> association = state.<Object>associationFor( associationModel.accessor() );
+ associationModel.checkAssociationConstraints( association );
+ associationModel.checkConstraints( association.get() );
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/association/ManyAssociationInstance.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/association/ManyAssociationInstance.java b/core/runtime/src/main/java/org/apache/zest/runtime/association/ManyAssociationInstance.java
new file mode 100644
index 0000000..4dce5a7
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/zest/runtime/association/ManyAssociationInstance.java
@@ -0,0 +1,225 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.zest.runtime.association;
+
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import org.apache.zest.api.association.AssociationDescriptor;
+import org.apache.zest.api.association.ManyAssociation;
+import org.apache.zest.api.association.ManyAssociationWrapper;
+import org.apache.zest.api.entity.EntityReference;
+import org.apache.zest.api.entity.Identity;
+import org.apache.zest.api.util.NullArgumentException;
+import org.apache.zest.functional.Function2;
+import org.apache.zest.functional.Iterables;
+import org.apache.zest.spi.entity.ManyAssociationState;
+
+/**
+ * JAVADOC
+ */
+public class ManyAssociationInstance<T>
+ extends AbstractAssociationInstance<T>
+ implements ManyAssociation<T>
+{
+ private ManyAssociationState manyAssociationState;
+
+ public ManyAssociationInstance( AssociationInfo associationInfo,
+ Function2<EntityReference, Type, Object> associationFunction,
+ ManyAssociationState manyAssociationState
+ )
+ {
+ super( associationInfo, associationFunction );
+ this.manyAssociationState = manyAssociationState;
+ }
+
+ @Override
+ public int count()
+ {
+ return manyAssociationState.count();
+ }
+
+ @Override
+ public boolean contains( T entity )
+ {
+ return manyAssociationState.contains( getEntityReference( entity ) );
+ }
+
+ @Override
+ public boolean add( int i, T entity )
+ {
+ NullArgumentException.validateNotNull( "entity", entity );
+ checkImmutable();
+ checkType( entity );
+ associationInfo.checkConstraints( entity );
+ return manyAssociationState.add( i, new EntityReference( ( (Identity) entity ).identity().get() ) );
+ }
+
+ @Override
+ public boolean add( T entity )
+ {
+ return add( manyAssociationState.count(), entity );
+ }
+
+ @Override
+ public boolean remove( T entity )
+ {
+ NullArgumentException.validateNotNull( "entity", entity );
+ checkImmutable();
+ checkType( entity );
+
+ return manyAssociationState.remove( new EntityReference( ( (Identity) entity ).identity().get() ) );
+ }
+
+ @Override
+ public T get( int i )
+ {
+ return getEntity( manyAssociationState.get( i ) );
+ }
+
+ @Override
+ public List<T> toList()
+ {
+ ArrayList<T> list = new ArrayList<>();
+ for( EntityReference entityReference : manyAssociationState )
+ {
+ list.add( getEntity( entityReference ) );
+ }
+
+ return list;
+ }
+
+ @Override
+ public Set<T> toSet()
+ {
+ Set<T> set = new HashSet<>();
+ for( EntityReference entityReference : manyAssociationState )
+ {
+ set.add( getEntity( entityReference ) );
+ }
+
+ return set;
+ }
+
+ @Override
+ public Iterable<EntityReference> references()
+ {
+ return Iterables.toList( manyAssociationState );
+ }
+
+ @Override
+ public String toString()
+ {
+ return manyAssociationState.toString();
+ }
+
+ @Override
+ public Iterator<T> iterator()
+ {
+ return new ManyAssociationIterator( manyAssociationState.iterator() );
+ }
+
+ @Override
+ public boolean equals( Object o )
+ {
+ if( this == o )
+ {
+ return true;
+ }
+ if( o == null || getClass() != o.getClass() )
+ {
+ return false;
+ }
+ ManyAssociation<?> that = (ManyAssociation) o;
+ // Unwrap if needed
+ while( that instanceof ManyAssociationWrapper )
+ {
+ that = ( (ManyAssociationWrapper) that ).next();
+ }
+ // Descriptor equality
+ ManyAssociationInstance<?> thatInstance = (ManyAssociationInstance) that;
+ AssociationDescriptor thatDescriptor = (AssociationDescriptor) thatInstance.associationInfo();
+ if( !associationInfo.equals( thatDescriptor ) )
+ {
+ return false;
+ }
+ // State equality
+ if( manyAssociationState.count() != thatInstance.manyAssociationState.count() )
+ {
+ return false;
+ }
+ for( EntityReference ref : manyAssociationState )
+ {
+ if( !thatInstance.manyAssociationState.contains( ref ) )
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ int hash = associationInfo.hashCode() * 31; // Descriptor
+ for( EntityReference ref : manyAssociationState )
+ {
+ hash += ref.hashCode() * 7; // State
+ }
+ return hash;
+ }
+
+ public ManyAssociationState getManyAssociationState()
+ {
+ return manyAssociationState;
+ }
+
+ protected class ManyAssociationIterator
+ implements Iterator<T>
+ {
+ private final Iterator<EntityReference> idIterator;
+
+ public ManyAssociationIterator( Iterator<EntityReference> idIterator )
+ {
+ this.idIterator = idIterator;
+ }
+
+ @Override
+ public boolean hasNext()
+ {
+ return idIterator.hasNext();
+ }
+
+ @Override
+ public T next()
+ {
+ return getEntity( idIterator.next() );
+ }
+
+ @Override
+ public void remove()
+ {
+ checkImmutable();
+ idIterator.remove();
+ }
+ }
+}