| /* |
| * 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.qi4j.runtime.structure; |
| |
| import java.util.Iterator; |
| import org.junit.Test; |
| import org.qi4j.api.activation.ActivationException; |
| import org.qi4j.api.composite.AmbiguousTypeException; |
| import org.qi4j.api.entity.Identity; |
| import org.qi4j.api.mixin.Mixins; |
| import org.qi4j.api.service.ServiceReference; |
| import org.qi4j.api.structure.Module; |
| import org.qi4j.api.unitofwork.UnitOfWork; |
| import org.qi4j.api.unitofwork.UnitOfWorkCompletionException; |
| import org.qi4j.bootstrap.AssemblyException; |
| import org.qi4j.bootstrap.ModuleAssembly; |
| import org.qi4j.bootstrap.SingletonAssembler; |
| import org.qi4j.functional.Iterables; |
| import org.qi4j.test.EntityTestAssembler; |
| |
| import static org.junit.Assert.*; |
| |
| /** |
| * Theses tests ensure that Type to Composite lookup work as expected for |
| * Objects, Transients, Values, Entities and Services. |
| */ |
| public class TypeToCompositeLookupTest |
| { |
| |
| private static final String CATHEDRAL = "cathedral"; |
| private static final String BAZAR = "bazar"; |
| |
| public interface Foo |
| { |
| |
| String bar(); |
| |
| } |
| |
| public static class BasicFooImpl |
| implements Foo |
| { |
| |
| @Override |
| public String bar() |
| { |
| return BAZAR; |
| } |
| |
| } |
| |
| public static class SomeOtherFooImpl |
| extends BasicFooImpl |
| { |
| |
| @Override |
| public String bar() |
| { |
| return CATHEDRAL; |
| } |
| |
| } |
| |
| @Mixins( BasicFooImpl.class ) |
| public interface BasicFoo |
| extends Foo |
| { |
| } |
| |
| @Mixins( SomeOtherFooImpl.class ) |
| public interface SomeOtherFoo |
| extends BasicFoo |
| { |
| } |
| |
| @Test |
| public void objects() |
| throws ActivationException, AssemblyException |
| { |
| Module module = new SingletonAssembler() |
| { |
| |
| @Override |
| public void assemble( ModuleAssembly module ) |
| throws AssemblyException |
| { |
| module.objects( SomeOtherFooImpl.class ); |
| } |
| |
| }.module(); |
| |
| assertEquals( CATHEDRAL, module.newObject( SomeOtherFooImpl.class ).bar() ); |
| assertEquals( CATHEDRAL, module.newObject( BasicFooImpl.class ).bar() ); |
| assertEquals( CATHEDRAL, module.newObject( Foo.class ).bar() ); |
| } |
| |
| @Test |
| public void objectsAmbiguousDeclaration() |
| throws ActivationException, AssemblyException |
| { |
| Module module = new SingletonAssembler() |
| { |
| |
| @Override |
| public void assemble( ModuleAssembly module ) |
| throws AssemblyException |
| { |
| module.objects( SomeOtherFooImpl.class, BasicFooImpl.class ); |
| } |
| |
| }.module(); |
| |
| assertEquals( CATHEDRAL, module.newObject( SomeOtherFooImpl.class ).bar() ); |
| assertEquals( BAZAR, module.newObject( BasicFooImpl.class ).bar() ); |
| |
| try |
| { |
| module.newObject( Foo.class ); |
| fail( "Ambiguous type exception not detected for Objects" ); |
| } |
| catch( AmbiguousTypeException expected ) |
| { |
| } |
| } |
| |
| @Test |
| public void transients() |
| throws ActivationException, AssemblyException |
| { |
| Module module = new SingletonAssembler() |
| { |
| |
| @Override |
| public void assemble( ModuleAssembly module ) |
| throws AssemblyException |
| { |
| module.transients( SomeOtherFoo.class ); |
| } |
| |
| }.module(); |
| |
| assertEquals( CATHEDRAL, module.newTransientBuilder( SomeOtherFoo.class ).newInstance().bar() ); |
| assertEquals( CATHEDRAL, module.newTransientBuilder( BasicFoo.class ).newInstance().bar() ); |
| assertEquals( CATHEDRAL, module.newTransientBuilder( Foo.class ).newInstance().bar() ); |
| } |
| |
| @Test |
| public void transientsAmbiguousDeclaration() |
| throws ActivationException, AssemblyException |
| { |
| Module module = new SingletonAssembler() |
| { |
| |
| @Override |
| public void assemble( ModuleAssembly module ) |
| throws AssemblyException |
| { |
| module.transients( SomeOtherFoo.class, BasicFoo.class ); |
| } |
| |
| }.module(); |
| |
| assertEquals( CATHEDRAL, module.newTransientBuilder( SomeOtherFoo.class ).newInstance().bar() ); |
| assertEquals( BAZAR, module.newTransientBuilder( BasicFoo.class ).newInstance().bar() ); |
| |
| try |
| { |
| module.newTransientBuilder( Foo.class ); |
| fail( "Ambiguous type exception not detected for Transients" ); |
| } |
| catch( AmbiguousTypeException expected ) |
| { |
| } |
| } |
| |
| @Test |
| public void values() |
| throws ActivationException, AssemblyException |
| { |
| Module module = new SingletonAssembler() |
| { |
| |
| @Override |
| public void assemble( ModuleAssembly module ) |
| throws AssemblyException |
| { |
| module.values( SomeOtherFoo.class ); |
| } |
| |
| }.module(); |
| |
| assertEquals( CATHEDRAL, module.newValueBuilder( SomeOtherFoo.class ).newInstance().bar() ); |
| assertEquals( CATHEDRAL, module.newValueBuilder( BasicFoo.class ).newInstance().bar() ); |
| assertEquals( CATHEDRAL, module.newValueBuilder( Foo.class ).newInstance().bar() ); |
| } |
| |
| @Test |
| public void valuesAmbiguousDeclaration() |
| throws ActivationException, AssemblyException |
| { |
| Module module = new SingletonAssembler() |
| { |
| |
| @Override |
| public void assemble( ModuleAssembly module ) |
| throws AssemblyException |
| { |
| module.values( SomeOtherFoo.class, BasicFoo.class ); |
| } |
| |
| }.module(); |
| |
| assertEquals( CATHEDRAL, module.newValueBuilder( SomeOtherFoo.class ).newInstance().bar() ); |
| assertEquals( BAZAR, module.newValueBuilder( BasicFoo.class ).newInstance().bar() ); |
| |
| try |
| { |
| module.newValueBuilder( Foo.class ); |
| fail( "Ambiguous type exception not detected for Values" ); |
| } |
| catch( AmbiguousTypeException expected ) |
| { |
| } |
| } |
| |
| @Test |
| public void entities() |
| throws UnitOfWorkCompletionException, ActivationException, AssemblyException |
| { |
| Module module = new SingletonAssembler() |
| { |
| |
| @Override |
| public void assemble( ModuleAssembly module ) |
| throws AssemblyException |
| { |
| new EntityTestAssembler().assemble( module ); |
| module.entities( SomeOtherFoo.class ); |
| } |
| |
| }.module(); |
| |
| UnitOfWork uow = module.newUnitOfWork(); |
| |
| SomeOtherFoo someOtherFoo = uow.newEntityBuilder( SomeOtherFoo.class ).newInstance(); |
| BasicFoo basicFoo = uow.newEntityBuilder( BasicFoo.class ).newInstance(); |
| Foo foo = uow.newEntityBuilder( Foo.class ).newInstance(); |
| |
| assertEquals( CATHEDRAL, someOtherFoo.bar() ); |
| assertEquals( CATHEDRAL, basicFoo.bar() ); |
| assertEquals( CATHEDRAL, foo.bar() ); |
| |
| String someOtherFooIdentity = ( (Identity) someOtherFoo ).identity().get(); |
| String basicFooIdentity = ( (Identity) basicFoo ).identity().get(); |
| String fooIdentity = ( (Identity) foo ).identity().get(); |
| |
| uow.complete(); |
| |
| uow = module.newUnitOfWork(); |
| |
| uow.get( SomeOtherFoo.class, someOtherFooIdentity ); |
| uow.get( BasicFoo.class, basicFooIdentity ); |
| uow.get( Foo.class, fooIdentity ); |
| |
| uow.discard(); |
| } |
| |
| @Test |
| public void entitiesAmbiguousDeclaration() |
| throws UnitOfWorkCompletionException, ActivationException, AssemblyException |
| { |
| Module module = new SingletonAssembler() |
| { |
| |
| @Override |
| public void assemble( ModuleAssembly module ) |
| throws AssemblyException |
| { |
| new EntityTestAssembler().assemble( module ); |
| module.entities( SomeOtherFoo.class, BasicFoo.class ); |
| } |
| |
| }.module(); |
| |
| UnitOfWork uow = module.newUnitOfWork(); |
| |
| SomeOtherFoo someOtherFoo = uow.newEntityBuilder( SomeOtherFoo.class ).newInstance(); |
| BasicFoo basicFoo = uow.newEntityBuilder( BasicFoo.class ).newInstance(); |
| try |
| { |
| uow.newEntityBuilder( Foo.class ).newInstance(); |
| fail( "Ambiguous type exception not detected for Entities" ); |
| } |
| catch( AmbiguousTypeException expected ) |
| { |
| } |
| |
| // Specific Type used |
| assertEquals( CATHEDRAL, uow.newEntityBuilder( SomeOtherFoo.class ).newInstance().bar() ); |
| |
| // Specific Type used |
| assertEquals( BAZAR, uow.newEntityBuilder( BasicFoo.class ).newInstance().bar() ); |
| |
| String someOtherFooIdentity = ( (Identity) someOtherFoo ).identity().get(); |
| String basicFooIdentity = ( (Identity) basicFoo ).identity().get(); |
| |
| uow.complete(); |
| |
| uow = module.newUnitOfWork(); |
| |
| assertEquals( CATHEDRAL, uow.get( SomeOtherFoo.class, someOtherFooIdentity ).bar() ); |
| assertEquals( BAZAR, uow.get( BasicFoo.class, basicFooIdentity ).bar() ); |
| assertEquals( CATHEDRAL, uow.get( Foo.class, someOtherFooIdentity ).bar() ); |
| assertEquals( BAZAR, uow.get( Foo.class, basicFooIdentity ).bar() ); |
| |
| uow.discard(); |
| } |
| |
| @Test |
| public void services() |
| throws ActivationException, AssemblyException |
| { |
| Module module = new SingletonAssembler() |
| { |
| |
| @Override |
| public void assemble( ModuleAssembly module ) |
| throws AssemblyException |
| { |
| module.services( SomeOtherFoo.class ); |
| } |
| |
| }.module(); |
| |
| assertEquals( CATHEDRAL, module.findService( SomeOtherFoo.class ).get().bar() ); |
| assertEquals( CATHEDRAL, module.findService( BasicFoo.class ).get().bar() ); |
| assertEquals( CATHEDRAL, module.findService( Foo.class ).get().bar() ); |
| } |
| |
| @Test |
| public void servicesPluralDeclaration() |
| throws ActivationException, AssemblyException |
| { |
| Module module = new SingletonAssembler() |
| { |
| |
| @Override |
| public void assemble( ModuleAssembly module ) |
| throws AssemblyException |
| { |
| module.services( SomeOtherFoo.class, BasicFoo.class ); |
| } |
| |
| }.module(); |
| |
| assertEquals( 1, Iterables.count( module.findServices( SomeOtherFoo.class ) ) ); |
| assertEquals( 2, Iterables.count( module.findServices( BasicFoo.class ) ) ); |
| assertEquals( 2, Iterables.count( module.findServices( Foo.class ) ) ); |
| |
| assertEquals( CATHEDRAL, module.findService( SomeOtherFoo.class ).get().bar() ); |
| |
| // Exact type match first even if it is assembled _after_ an assignable, the assignable comes after |
| Iterator<ServiceReference<BasicFoo>> basicFoos = module.findServices( BasicFoo.class ).iterator(); |
| assertEquals( BAZAR, basicFoos.next().get().bar() ); |
| assertEquals( CATHEDRAL, basicFoos.next().get().bar() ); |
| assertFalse( basicFoos.hasNext() ); |
| |
| // No exact type match, all assembled are assignable, follows assembly Type order |
| Iterator<ServiceReference<Foo>> foos = module.findServices( Foo.class ).iterator(); |
| assertEquals( CATHEDRAL, foos.next().get().bar() ); |
| assertEquals( BAZAR, foos.next().get().bar() ); |
| assertFalse( foos.hasNext() ); |
| } |
| |
| } |