http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/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/061ddaa0/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/061ddaa0/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/061ddaa0/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/061ddaa0/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/061ddaa0/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/061ddaa0/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/061ddaa0/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/061ddaa0/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/061ddaa0/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/061ddaa0/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/061ddaa0/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/061ddaa0/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/061ddaa0/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(); + } + } +}
