Return-Path: X-Original-To: apmail-zest-commits-archive@minotaur.apache.org Delivered-To: apmail-zest-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 38F771871F for ; Thu, 30 Jul 2015 19:54:41 +0000 (UTC) Received: (qmail 59936 invoked by uid 500); 30 Jul 2015 19:48:00 -0000 Delivered-To: apmail-zest-commits-archive@zest.apache.org Received: (qmail 59858 invoked by uid 500); 30 Jul 2015 19:48:00 -0000 Mailing-List: contact commits-help@zest.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@zest.apache.org Delivered-To: mailing list commits@zest.apache.org Received: (qmail 59615 invoked by uid 99); 30 Jul 2015 19:48:00 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 30 Jul 2015 19:48:00 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 54C28E714F; Thu, 30 Jul 2015 19:48:00 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: niclas@apache.org To: commits@zest.apache.org Date: Thu, 30 Jul 2015 19:48:09 -0000 Message-Id: <9954f1bb8d6d4bc3b3bf8b0cb7725e4c@git.apache.org> In-Reply-To: <4cbd2683fa884aa6bf1c8b2865185ebf@git.apache.org> References: <4cbd2683fa884aa6bf1c8b2865185ebf@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [10/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/runtime/src/main/java/org/apache/zest/runtime/injection/provider/InvocationInjectionProviderFactory.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/InvocationInjectionProviderFactory.java b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/InvocationInjectionProviderFactory.java new file mode 100644 index 0000000..d7348ff --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/InvocationInjectionProviderFactory.java @@ -0,0 +1,117 @@ +/* + * 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.injection.provider; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import org.apache.zest.api.util.Classes; +import org.apache.zest.bootstrap.InvalidInjectionException; +import org.apache.zest.runtime.composite.CompositeMethodModel; +import org.apache.zest.runtime.injection.DependencyModel; +import org.apache.zest.runtime.injection.InjectionContext; +import org.apache.zest.runtime.injection.InjectionProvider; +import org.apache.zest.runtime.injection.InjectionProviderFactory; +import org.apache.zest.runtime.model.Resolution; + +/** + * JAVADOC + */ +public final class InvocationInjectionProviderFactory + implements InjectionProviderFactory +{ + @Override + @SuppressWarnings( "raw" ) + public InjectionProvider newInjectionProvider( Resolution resolution, DependencyModel dependencyModel ) + throws InvalidInjectionException + { + Class injectionClass = Classes.RAW_CLASS.map( dependencyModel.injectionType() ); + if( injectionClass.equals( Method.class ) || + injectionClass.equals( AnnotatedElement.class ) || + injectionClass.equals( Iterable.class ) || + Annotation.class.isAssignableFrom( injectionClass ) ) + { + return new InvocationDependencyResolution( resolution, dependencyModel ); + } + else + { + String injectedTo = dependencyModel.injectedClass().getName(); + throw new InvalidInjectionException( "Invalid injection type " + injectionClass + " in " + injectedTo ); + } + } + + private static class InvocationDependencyResolution + implements InjectionProvider + { + private final Resolution resolution; + private final DependencyModel dependencyModel; + + private InvocationDependencyResolution( Resolution resolution, DependencyModel dependencyModel ) + { + this.resolution = resolution; + this.dependencyModel = dependencyModel; + } + + @Override + @SuppressWarnings( {"raw", "unchecked"} ) + public Object provideInjection( InjectionContext context ) + throws InjectionProviderException + { + Class injectionClass = Classes.RAW_CLASS.map( dependencyModel.injectionType() ); + final CompositeMethodModel methodModel = resolution.method(); + if( injectionClass.equals( Method.class ) ) + { + return methodModel.method(); + } + + final AnnotatedElement annotatedElement = methodModel.annotatedElement(); + if( injectionClass.equals( AnnotatedElement.class ) ) + { + return annotatedElement; + } + final Annotation annotation = annotatedElement.getAnnotation( injectionClass ); + if( annotation != null ) + { + return annotation; + } + if( dependencyModel.injectionType() instanceof Class ) + { + return annotatedElement.getAnnotation( (Class) dependencyModel.injectionType() ); + } + if( dependencyModel.injectionType() instanceof ParameterizedType ) + { + ParameterizedType injectionType = (ParameterizedType) dependencyModel.injectionType(); + Type rawType = injectionType.getRawType(); + Type[] actualTypeArguments = injectionType.getActualTypeArguments(); + boolean isAnIterable = rawType.equals( Iterable.class ); + boolean haveOneGenericType = actualTypeArguments.length == 1; + boolean thatIsOfTypeMethod = actualTypeArguments[ 0 ].equals( Method.class ); + if( isAnIterable && haveOneGenericType && thatIsOfTypeMethod ) + { + Class injectedClass = dependencyModel.injectedClass(); + Iterable result = methodModel.invocationsFor( injectedClass ); + return result; + } + } + return null; + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/ModifiesInjectionProviderFactory.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/ModifiesInjectionProviderFactory.java b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/ModifiesInjectionProviderFactory.java new file mode 100644 index 0000000..fedb010 --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/ModifiesInjectionProviderFactory.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.zest.runtime.injection.provider; + +import org.apache.zest.api.composite.CompositeDescriptor; +import org.apache.zest.api.util.Classes; +import org.apache.zest.bootstrap.InvalidInjectionException; +import org.apache.zest.runtime.injection.DependencyModel; +import org.apache.zest.runtime.injection.InjectionContext; +import org.apache.zest.runtime.injection.InjectionProvider; +import org.apache.zest.runtime.injection.InjectionProviderFactory; +import org.apache.zest.runtime.model.Resolution; + +/** + * JAVADOC + */ +public final class ModifiesInjectionProviderFactory + implements InjectionProviderFactory +{ + @Override + public InjectionProvider newInjectionProvider( Resolution bindingContext, DependencyModel dependencyModel ) + throws InvalidInjectionException + { + if( bindingContext.model() instanceof CompositeDescriptor ) + { + Class type = Classes.RAW_CLASS.map( dependencyModel.injectionType() ); + if( type.isAssignableFrom( dependencyModel.injectedClass() ) ) + { + return new ModifiedInjectionProvider(); + } + else + { + throw new InvalidInjectionException( "Composite " + bindingContext.model() + " does not implement @ConcernFor type " + type + .getName() + " in modifier " + dependencyModel.injectedClass().getName() ); + } + } + else + { + throw new InvalidInjectionException( "The class " + dependencyModel.injectedClass() + .getName() + " is not a modifier" ); + } + } + + private static class ModifiedInjectionProvider + implements InjectionProvider + { + @Override + public Object provideInjection( InjectionContext context ) + throws InjectionProviderException + { + return context.next(); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/ServiceInjectionProviderFactory.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/ServiceInjectionProviderFactory.java b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/ServiceInjectionProviderFactory.java new file mode 100644 index 0000000..4c5bb26 --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/ServiceInjectionProviderFactory.java @@ -0,0 +1,225 @@ +/* + * 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.injection.provider; + +import java.lang.annotation.Annotation; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import org.apache.zest.api.service.NoSuchServiceException; +import org.apache.zest.api.service.ServiceReference; +import org.apache.zest.api.service.qualifier.Qualifier; +import org.apache.zest.api.util.Annotations; +import org.apache.zest.api.util.Classes; +import org.apache.zest.bootstrap.InvalidInjectionException; +import org.apache.zest.functional.Function; +import org.apache.zest.functional.Iterables; +import org.apache.zest.functional.Specification; +import org.apache.zest.functional.Specifications; +import org.apache.zest.runtime.injection.DependencyModel; +import org.apache.zest.runtime.injection.InjectionContext; +import org.apache.zest.runtime.injection.InjectionProvider; +import org.apache.zest.runtime.injection.InjectionProviderFactory; +import org.apache.zest.runtime.model.Resolution; + +import static org.apache.zest.api.util.Annotations.hasAnnotation; +import static org.apache.zest.functional.Iterables.filter; +import static org.apache.zest.functional.Iterables.first; +import static org.apache.zest.functional.Iterables.iterable; + +public final class ServiceInjectionProviderFactory + implements InjectionProviderFactory +{ + @Override + @SuppressWarnings( "unchecked" ) + public InjectionProvider newInjectionProvider( Resolution resolution, DependencyModel dependencyModel ) + throws InvalidInjectionException + { + // TODO This could be changed to allow multiple @Qualifier annotations + Annotation qualifierAnnotation = first( filter( Specifications.translate( Annotations.type(), hasAnnotation( Qualifier.class ) ), iterable( dependencyModel + .annotations() ) ) ); + Specification> serviceQualifier = null; + if( qualifierAnnotation != null ) + { + Qualifier qualifier = qualifierAnnotation.annotationType().getAnnotation( Qualifier.class ); + try + { + serviceQualifier = qualifier.value().newInstance().qualifier( qualifierAnnotation ); + } + catch( Exception e ) + { + throw new InvalidInjectionException( "Could not instantiate qualifier serviceQualifier", e ); + } + } + + if( dependencyModel.rawInjectionType().equals( Iterable.class ) ) + { + Type iterableType = ( (ParameterizedType) dependencyModel.injectionType() ).getActualTypeArguments()[ 0 ]; + if( Classes.RAW_CLASS.map( iterableType ).equals( ServiceReference.class ) ) + { + // @Service Iterable> serviceRefs + Type serviceType = ( (ParameterizedType) iterableType ).getActualTypeArguments()[ 0 ]; + + return new IterableServiceReferenceProvider( serviceType, serviceQualifier ); + } + else + { + // @Service Iterable> services + return new IterableServiceProvider( iterableType, serviceQualifier ); + } + } + else if( dependencyModel.rawInjectionType().equals( ServiceReference.class ) ) + { + // @Service ServiceReference> serviceRef + Type referencedType = ( (ParameterizedType) dependencyModel.injectionType() ).getActualTypeArguments()[ 0 ]; + return new ServiceReferenceProvider( referencedType, serviceQualifier ); + } + else + { + // @Service MyService service + return new ServiceProvider( dependencyModel.injectionType(), serviceQualifier ); + } + } + + private static class IterableServiceReferenceProvider + extends ServiceInjectionProvider + { + private IterableServiceReferenceProvider( Type serviceType, + Specification> serviceQualifier + ) + { + super( serviceType, serviceQualifier ); + } + + @Override + public synchronized Object provideInjection( InjectionContext context ) + throws InjectionProviderException + { + return getServiceReferences( context ); + } + } + + private static class IterableServiceProvider + extends ServiceInjectionProvider + implements Function, Object> + { + private IterableServiceProvider( Type serviceType, + Specification> serviceQualifier + ) + { + super( serviceType, serviceQualifier ); + } + + @Override + public synchronized Object provideInjection( final InjectionContext context ) + throws InjectionProviderException + { + return Iterables.map( this, getServiceReferences( context ) ); + } + + @Override + public Object map( ServiceReference objectServiceReference ) + { + return objectServiceReference.get(); + } + } + + private static class ServiceReferenceProvider + extends ServiceInjectionProvider + { + ServiceReferenceProvider( Type serviceType, Specification> qualifier ) + { + super( serviceType, qualifier ); + } + + @Override + public synchronized Object provideInjection( InjectionContext context ) + throws InjectionProviderException + { + return getServiceReference( context ); + } + } + + private static class ServiceProvider + extends ServiceInjectionProvider + { + ServiceProvider( Type serviceType, Specification> qualifier ) + { + super( serviceType, qualifier ); + } + + @Override + public synchronized Object provideInjection( InjectionContext context ) + throws InjectionProviderException + { + ServiceReference ref = getServiceReference( context ); + + if( ref != null ) + { + return ref.get(); + } + else + { + return null; + } + } + } + + private abstract static class ServiceInjectionProvider + implements InjectionProvider + { + private final Type serviceType; + private final Specification> serviceQualifier; + + private ServiceInjectionProvider( Type serviceType, + Specification> serviceQualifier + ) + { + this.serviceType = serviceType; + this.serviceQualifier = serviceQualifier; + } + + protected ServiceReference getServiceReference( InjectionContext context ) + { + try + { + if( serviceQualifier == null ) + { + return context.module().findService( serviceType ); + } + else + { + return Iterables.first( Iterables.filter( serviceQualifier, context.module() + .findServices( serviceType ) ) ); + } + } + catch( NoSuchServiceException e ) + { + return null; + } + } + + protected Iterable> getServiceReferences( final InjectionContext context ) + { + if( serviceQualifier == null ) + { + return context.module().findServices( serviceType ); + } + else + { + return Iterables.filter( serviceQualifier, context.module().findServices( serviceType ) ); + } + } + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/StateInjectionProviderFactory.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/StateInjectionProviderFactory.java b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/StateInjectionProviderFactory.java new file mode 100644 index 0000000..8d0bcc7 --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/StateInjectionProviderFactory.java @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2008-2011, Rickard Öberg. All Rights Reserved. + * Copyright (c) 2008-2013, Niclas Hedhman. All Rights Reserved. + * 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.injection.provider; + +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.AssociationStateDescriptor; +import org.apache.zest.api.association.AssociationStateHolder; +import org.apache.zest.api.association.ManyAssociation; +import org.apache.zest.api.association.NamedAssociation; +import org.apache.zest.api.composite.StateDescriptor; +import org.apache.zest.api.composite.StatefulCompositeDescriptor; +import org.apache.zest.api.entity.EntityDescriptor; +import org.apache.zest.api.injection.scope.State; +import org.apache.zest.api.property.Property; +import org.apache.zest.api.property.PropertyDescriptor; +import org.apache.zest.api.property.StateHolder; +import org.apache.zest.api.unitofwork.UnitOfWork; +import org.apache.zest.bootstrap.InvalidInjectionException; +import org.apache.zest.runtime.entity.EntityInstance; +import org.apache.zest.runtime.injection.DependencyModel; +import org.apache.zest.runtime.injection.InjectionContext; +import org.apache.zest.runtime.injection.InjectionProvider; +import org.apache.zest.runtime.injection.InjectionProviderFactory; +import org.apache.zest.runtime.model.Resolution; + +/** + * JAVADOC + */ +public final class StateInjectionProviderFactory + implements InjectionProviderFactory +{ + @Override + public InjectionProvider newInjectionProvider( Resolution resolution, DependencyModel dependencyModel ) + throws InvalidInjectionException + { + if( StateHolder.class.isAssignableFrom( dependencyModel.rawInjectionType() ) ) + { + // @State StateHolder properties; + return new StateInjectionProvider(); + } + else if( UnitOfWork.class.isAssignableFrom( dependencyModel.rawInjectionType() ) ) + { + if( !( resolution.model() instanceof EntityDescriptor ) ) + { + throw new InvalidInjectionException( "Only EntityComposites can be injected with '@State UnitOfWork'" ); + } + return new UnitOfWorkInjectionProvider(); + } + else if( Property.class.isAssignableFrom( dependencyModel.rawInjectionType() ) ) + { + // @State Property name; + StateDescriptor descriptor; + descriptor = ( (StatefulCompositeDescriptor) resolution.model() ).state(); + + State annotation = (State) dependencyModel.injectionAnnotation(); + String name; + if( annotation.value().isEmpty() ) + { + name = resolution.field().getName(); + } + else + { + name = annotation.value(); + } + + PropertyDescriptor propertyDescriptor = descriptor.findPropertyModelByName( name ); + return new PropertyInjectionProvider( propertyDescriptor ); + } + else if( Association.class.isAssignableFrom( dependencyModel.rawInjectionType() ) ) + { + // @State Association name; + AssociationStateDescriptor descriptor = ( (EntityDescriptor) resolution.model() ).state(); + State annotation = (State) dependencyModel.injectionAnnotation(); + String name; + if( annotation.value().isEmpty() ) + { + name = resolution.field().getName(); + } + else + { + name = annotation.value(); + } + AssociationDescriptor model = descriptor.getAssociationByName( name ); + return new AssociationInjectionProvider( model ); + } + else if( ManyAssociation.class.isAssignableFrom( dependencyModel.rawInjectionType() ) ) + { + // @State ManyAssociation name; + AssociationStateDescriptor descriptor = ( (EntityDescriptor) resolution.model() ).state(); + State annotation = (State) dependencyModel.injectionAnnotation(); + String name; + if( annotation.value().isEmpty() ) + { + name = resolution.field().getName(); + } + else + { + name = annotation.value(); + } + AssociationDescriptor model = descriptor.getManyAssociationByName( name ); + return new ManyAssociationInjectionProvider( model ); + } + else if( NamedAssociation.class.isAssignableFrom( dependencyModel.rawInjectionType() ) ) + { + // @State NamedAssociation name; + AssociationStateDescriptor descriptor = ( (EntityDescriptor) resolution.model() ).state(); + State annotation = (State) dependencyModel.injectionAnnotation(); + String name; + if( annotation.value().isEmpty() ) + { + name = resolution.field().getName(); + } + else + { + name = annotation.value(); + } + AssociationDescriptor model = descriptor.getNamedAssociationByName( name ); + return new NamedAssociationInjectionProvider( model ); + } + + throw new InjectionProviderException( "Injected value has invalid type" ); + } + + private static class PropertyInjectionProvider + implements InjectionProvider + { + private final PropertyDescriptor propertyDescriptor; + + private PropertyInjectionProvider( PropertyDescriptor propertyDescriptor ) + { + this.propertyDescriptor = propertyDescriptor; + } + + @Override + public Object provideInjection( InjectionContext context ) + throws InjectionProviderException + { + Property value = context.state().propertyFor( propertyDescriptor.accessor() ); + if( value != null ) + { + return value; + } + else + { + throw new InjectionProviderException( "Non-optional property " + propertyDescriptor + " had no value" ); + } + } + } + + private static class AssociationInjectionProvider + implements InjectionProvider + { + private final AssociationDescriptor associationDescriptor; + + private AssociationInjectionProvider( AssociationDescriptor associationDescriptor ) + { + this.associationDescriptor = associationDescriptor; + } + + @Override + public Object provideInjection( InjectionContext context ) + throws InjectionProviderException + { + AbstractAssociation abstractAssociation = ( (AssociationStateHolder) context.state() ). + associationFor( associationDescriptor.accessor() ); + if( abstractAssociation != null ) + { + return abstractAssociation; + } + else + { + throw new InjectionProviderException( "Non-optional association " + associationDescriptor.qualifiedName() + " had no association" ); + } + } + } + + private static class ManyAssociationInjectionProvider + implements InjectionProvider + { + private final AssociationDescriptor manyAssociationDescriptor; + + private ManyAssociationInjectionProvider( AssociationDescriptor manyAssociationDescriptor ) + { + this.manyAssociationDescriptor = manyAssociationDescriptor; + } + + @Override + public Object provideInjection( InjectionContext context ) + throws InjectionProviderException + { + ManyAssociation abstractAssociation = ( (AssociationStateHolder) context.state() ). + manyAssociationFor( manyAssociationDescriptor.accessor() ); + if( abstractAssociation != null ) + { + return abstractAssociation; + } + else + { + throw new InjectionProviderException( "Non-optional association " + manyAssociationDescriptor.qualifiedName() + " had no association" ); + } + } + } + + private static class NamedAssociationInjectionProvider + implements InjectionProvider + { + private final AssociationDescriptor namedAssociationDescriptor; + + private NamedAssociationInjectionProvider( AssociationDescriptor namedAssociationDescriptor ) + { + this.namedAssociationDescriptor = namedAssociationDescriptor; + } + + @Override + public Object provideInjection( InjectionContext context ) + throws InjectionProviderException + { + NamedAssociation abstractAssociation = ( (AssociationStateHolder) context.state() ). + namedAssociationFor( namedAssociationDescriptor.accessor() ); + if( abstractAssociation != null ) + { + return abstractAssociation; + } + else + { + throw new InjectionProviderException( "Non-optional association " + namedAssociationDescriptor.qualifiedName() + " had no association" ); + } + } + } + + static private class StateInjectionProvider + implements InjectionProvider + { + @Override + public Object provideInjection( InjectionContext context ) + throws InjectionProviderException + { + return context.state(); + } + } + + static private class UnitOfWorkInjectionProvider + implements InjectionProvider + { + + @Override + public Object provideInjection( InjectionContext context ) + throws InjectionProviderException + { + return ( (EntityInstance) context.compositeInstance() ).unitOfWork(); + } + } + +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/StructureInjectionProviderFactory.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/StructureInjectionProviderFactory.java b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/StructureInjectionProviderFactory.java new file mode 100644 index 0000000..7ee3db0 --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/StructureInjectionProviderFactory.java @@ -0,0 +1,118 @@ +/* + * Copyright 2007, 2008 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.injection.provider; + +import java.lang.reflect.Type; +import org.apache.zest.api.Qi4j; +import org.apache.zest.api.composite.TransientBuilderFactory; +import org.apache.zest.api.object.ObjectFactory; +import org.apache.zest.api.query.QueryBuilderFactory; +import org.apache.zest.api.service.ServiceFinder; +import org.apache.zest.api.structure.Application; +import org.apache.zest.api.structure.Layer; +import org.apache.zest.api.structure.Module; +import org.apache.zest.api.unitofwork.UnitOfWorkFactory; +import org.apache.zest.api.value.ValueBuilderFactory; +import org.apache.zest.bootstrap.InvalidInjectionException; +import org.apache.zest.runtime.injection.DependencyModel; +import org.apache.zest.runtime.injection.InjectionContext; +import org.apache.zest.runtime.injection.InjectionProvider; +import org.apache.zest.runtime.injection.InjectionProviderFactory; +import org.apache.zest.runtime.model.Resolution; +import org.apache.zest.runtime.structure.ModuleInstance; +import org.apache.zest.spi.module.ModuleSpi; + +public final class StructureInjectionProviderFactory + implements InjectionProviderFactory +{ + @Override + public InjectionProvider newInjectionProvider( Resolution resolution, DependencyModel dependencyModel ) + throws InvalidInjectionException + { + return new StructureInjectionProvider( dependencyModel ); + } + + private static class StructureInjectionProvider + implements InjectionProvider + { + private final DependencyModel dependencyModel; + + private StructureInjectionProvider( DependencyModel dependencyModel ) + { + this.dependencyModel = dependencyModel; + } + + @Override + public Object provideInjection( InjectionContext context ) + throws InjectionProviderException + { + Type type1 = dependencyModel.injectionType(); + if( !( type1 instanceof Class ) ) + { + throw new InjectionProviderException( "Type [" + type1 + "] can not be injected from the @Structure injection scope: " + context ); + } + Class clazz = (Class) type1; + if( clazz.equals( TransientBuilderFactory.class ) ) + { + return context.module(); + } + else if( clazz.equals( ObjectFactory.class ) ) + { + return context.module(); + } + else if( clazz.equals( ValueBuilderFactory.class ) ) + { + return context.module(); + } + else if( clazz.equals( UnitOfWorkFactory.class ) ) + { + return context.module(); + } + else if( clazz.equals( QueryBuilderFactory.class ) ) + { + return context.module(); + } + else if( clazz.equals( ServiceFinder.class ) ) + { + return context.module(); + } + else if( Module.class.isAssignableFrom( clazz ) ) + { + return context.module(); + } + else if( ModuleSpi.class.isAssignableFrom( clazz ) ) + { + return context.module(); + } + else if( Layer.class.isAssignableFrom( clazz ) ) + { + return (( ModuleInstance) context.module()).layerInstance(); + } + else if( Application.class.isAssignableFrom( clazz ) ) + { + return (( ModuleInstance) context.module()).layerInstance().applicationInstance(); + } + else if( Qi4j.class.isAssignableFrom( clazz ) ) + { + return (( ModuleInstance) context.module()).layerInstance().applicationInstance().runtime(); + } + + return null; + } + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/ThisInjectionProviderFactory.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/ThisInjectionProviderFactory.java b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/ThisInjectionProviderFactory.java new file mode 100644 index 0000000..a7b53eb --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/ThisInjectionProviderFactory.java @@ -0,0 +1,138 @@ +/* + * 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.injection.provider; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import org.apache.zest.api.composite.CompositeDescriptor; +import org.apache.zest.api.util.Classes; +import org.apache.zest.bootstrap.InvalidInjectionException; +import org.apache.zest.functional.Iterables; +import org.apache.zest.runtime.composite.ProxyGenerator; +import org.apache.zest.runtime.injection.DependencyModel; +import org.apache.zest.runtime.injection.InjectionContext; +import org.apache.zest.runtime.injection.InjectionProvider; +import org.apache.zest.runtime.injection.InjectionProviderFactory; +import org.apache.zest.runtime.model.Resolution; + +import static org.apache.zest.functional.Iterables.first; +import static org.apache.zest.functional.Iterables.iterable; + +/** + * JAVADOC + */ +public final class ThisInjectionProviderFactory + implements InjectionProviderFactory +{ + @Override + @SuppressWarnings( "unchecked" ) + public InjectionProvider newInjectionProvider( Resolution bindingContext, DependencyModel dependencyModel ) + throws InvalidInjectionException + { + if( bindingContext.model() instanceof CompositeDescriptor ) + { + // If Composite type then return real type, otherwise use the specified one + final Class thisType = dependencyModel.rawInjectionType(); + + Iterable> injectionTypes = null; + if( Classes.assignableTypeSpecification( thisType ).satisfiedBy( bindingContext.model() ) ) + { + injectionTypes = bindingContext.model().types(); + } + else + { + CompositeDescriptor acd = ( (CompositeDescriptor) bindingContext.model() ); + for( Class mixinType : acd.mixinTypes() ) + { + if( thisType.isAssignableFrom( mixinType ) ) + { + Iterable> iterable = iterable( thisType ); + injectionTypes = (Iterable>) iterable; + break; + } + } + + if( injectionTypes == null ) + { + throw new InvalidInjectionException( "Composite " + bindingContext.model() + + " does not implement @This type " + thisType.getName() + " in fragment " + + dependencyModel.injectedClass().getName() ); + } + } + + return new ThisInjectionProvider( injectionTypes ); + } + else + { + throw new InvalidInjectionException( "Object " + dependencyModel.injectedClass() + " may not use @This" ); + } + } + + @SuppressWarnings( {"raw", "unchecked"} ) + private static class ThisInjectionProvider + implements InjectionProvider + { + Constructor proxyConstructor; + private Class[] interfaces; + + private ThisInjectionProvider( Iterable> types ) + { + try + { + Class proxyClass; + if( Proxy.class.isAssignableFrom( first( types ) ) ) + { + proxyClass = first( types ); + } + else + { + Class mainType = first( types ); + interfaces = Iterables.toArray( Class.class, Iterables.cast( types ) ); + proxyClass = ProxyGenerator.createProxyClass(mainType.getClassLoader(), interfaces); + } + + proxyConstructor = proxyClass.getConstructor( InvocationHandler.class ); + } + catch( Exception e ) + { + // Ignore + e.printStackTrace(); + } + } + + @Override + public Object provideInjection( InjectionContext context ) + { + try + { + InvocationHandler handler = context.compositeInstance(); + if( handler == null ) + { + handler = context.proxyHandler(); + } + return proxyConstructor.newInstance( handler ); + } + catch( Exception e ) + { + throw new InjectionProviderException( "Could not instantiate @This proxy", e ); + } + } + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/UsesInjectionProviderFactory.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/UsesInjectionProviderFactory.java b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/UsesInjectionProviderFactory.java new file mode 100644 index 0000000..0e5ed5a --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/injection/provider/UsesInjectionProviderFactory.java @@ -0,0 +1,131 @@ +/* + * 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.injection.provider; + +import java.lang.reflect.Constructor; +import org.apache.zest.api.composite.NoSuchTransientException; +import org.apache.zest.api.object.NoSuchObjectException; +import org.apache.zest.api.structure.Module; +import org.apache.zest.bootstrap.InvalidInjectionException; +import org.apache.zest.runtime.composite.UsesInstance; +import org.apache.zest.runtime.injection.DependencyModel; +import org.apache.zest.runtime.injection.InjectionContext; +import org.apache.zest.runtime.injection.InjectionProvider; +import org.apache.zest.runtime.injection.InjectionProviderFactory; +import org.apache.zest.runtime.model.Resolution; + +/** + * JAVADOC + */ +public final class UsesInjectionProviderFactory + implements InjectionProviderFactory +{ + public UsesInjectionProviderFactory() + { + } + + @Override + public InjectionProvider newInjectionProvider( Resolution resolution, DependencyModel dependencyModel ) + throws InvalidInjectionException + { + return new UsesInjectionProvider( dependencyModel ); + } + + private static class UsesInjectionProvider + implements InjectionProvider + { + private final DependencyModel dependency; + + public UsesInjectionProvider( DependencyModel dependency ) + { + this.dependency = dependency; + } + + @SuppressWarnings( "unchecked" ) + @Override + public Object provideInjection( InjectionContext context ) + throws InjectionProviderException + { + UsesInstance uses = context.uses(); + + Class injectionType = dependency.rawInjectionType(); + Object usesObject = uses.useForType( injectionType ); + + if( usesObject == null && !dependency.optional() ) + { + // No @Uses object provided + // Try instantiating a Transient or Object for the given type + Module moduleInstance = context.module(); + + try + { + if( context.instance() != null ) + { + uses = uses.use( context.instance() ); + } + usesObject = moduleInstance.newTransient( injectionType, uses.toArray() ); + } + catch( NoSuchTransientException e ) + { + try + { + usesObject = moduleInstance.newObject( injectionType, uses.toArray() ); + } + catch( NoSuchObjectException e1 ) + { + // Could not instantiate an instance - to try instantiate as plain class + try + { + usesObject = injectionType.newInstance(); + } + catch( Throwable e2 ) + { + // Could not instantiate - try with this as first argument + try + { + Constructor constructor = injectionType.getDeclaredConstructor( context.instance() + .getClass() ); + if( !constructor.isAccessible() ) + { + constructor.setAccessible( true ); + } + usesObject = constructor.newInstance( context.instance() ); + } + catch( Throwable e3 ) + { + // Really can't instantiate it - ignore + } + } + } + } + + if( usesObject != null ) + { + context.setUses( context.uses().use( usesObject ) ); // Use this for other injections in same graph + } + + return usesObject; + } + else + { + return usesObject; + } + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/internal/Activator.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/internal/Activator.java b/core/runtime/src/main/java/org/apache/zest/runtime/internal/Activator.java new file mode 100644 index 0000000..d94a67a --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/internal/Activator.java @@ -0,0 +1,57 @@ +/* + * 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.internal; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceRegistration; +import org.apache.zest.bootstrap.Qi4jRuntime; +import org.apache.zest.bootstrap.RuntimeFactory; +import org.apache.zest.runtime.Qi4jRuntimeImpl; + +/** + * + */ +public class Activator + implements BundleActivator +{ + private ServiceRegistration registration; + + @Override + public void start( BundleContext bundleContext ) + throws Exception + { + RuntimeFactory factory = new RuntimeFactory() + { + @Override + public Qi4jRuntime createRuntime() + { + return new Qi4jRuntimeImpl(); + } + }; + registration = bundleContext.registerService( RuntimeFactory.class.getName(), factory, null ); + } + + @Override + public void stop( BundleContext bundleContext ) + throws Exception + { + registration.unregister(); + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/model/Binder.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/model/Binder.java b/core/runtime/src/main/java/org/apache/zest/runtime/model/Binder.java new file mode 100644 index 0000000..fdcbd2b --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/model/Binder.java @@ -0,0 +1,26 @@ +/* + * 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.model; + +import org.apache.zest.bootstrap.BindingException; + +/** + * Interface for models that can understand binding of dependencies + */ +public interface Binder +{ + void bind( Resolution resolution ) + throws BindingException; +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/model/Resolution.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/model/Resolution.java b/core/runtime/src/main/java/org/apache/zest/runtime/model/Resolution.java new file mode 100644 index 0000000..db64211 --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/model/Resolution.java @@ -0,0 +1,86 @@ +/* + * 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.model; + +import java.lang.reflect.Field; +import org.apache.zest.api.composite.ModelDescriptor; +import org.apache.zest.runtime.composite.CompositeMethodModel; +import org.apache.zest.runtime.structure.ApplicationModel; +import org.apache.zest.runtime.structure.LayerModel; +import org.apache.zest.runtime.structure.ModuleModel; + +/** + * JAVADOC + */ +public final class Resolution +{ + private final ApplicationModel application; + private final LayerModel layer; + private final ModuleModel module; + private final ModelDescriptor modelDescriptor; + private final CompositeMethodModel method; + private final Field field; + + public Resolution( ApplicationModel application, + LayerModel layer, + ModuleModel module, + ModelDescriptor modelDescriptor, + CompositeMethodModel method, + Field field + ) + { + this.application = application; + this.layer = layer; + this.module = module; + this.modelDescriptor = modelDescriptor; + this.method = method; + this.field = field; + } + + public ApplicationModel application() + { + return application; + } + + public LayerModel layer() + { + return layer; + } + + public ModuleModel module() + { + return module; + } + + public ModelDescriptor model() + { + return modelDescriptor; + } + + public CompositeMethodModel method() + { + return method; + } + + public Field field() + { + return field; + } + + public Resolution forField( final Field injectedField ) + { + return new Resolution( application, layer, module, modelDescriptor, method, injectedField ); + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/object/ObjectModel.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/object/ObjectModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/object/ObjectModel.java new file mode 100644 index 0000000..e4df4e5 --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/object/ObjectModel.java @@ -0,0 +1,143 @@ +/* + * 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.object; + +import org.apache.zest.api.common.ConstructionException; +import org.apache.zest.api.common.MetaInfo; +import org.apache.zest.api.common.Visibility; +import org.apache.zest.api.mixin.Initializable; +import org.apache.zest.api.mixin.InitializationException; +import org.apache.zest.api.object.ObjectDescriptor; +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; + +import static org.apache.zest.functional.Iterables.iterable; + +/** + * JAVADOC + */ +public final class ObjectModel + implements ObjectDescriptor, VisitableHierarchy +{ + private final Class objectType; + private final Visibility visibility; + private final MetaInfo metaInfo; + private final ConstructorsModel constructorsModel; + private final InjectedFieldsModel injectedFieldsModel; + private final InjectedMethodsModel injectedMethodsModel; + + public ObjectModel( Class objectType, + Visibility visibility, + MetaInfo metaInfo + ) + { + this.objectType = objectType; + this.visibility = visibility; + this.metaInfo = metaInfo; + + constructorsModel = new ConstructorsModel( objectType ); + injectedFieldsModel = new InjectedFieldsModel( objectType ); + injectedMethodsModel = new InjectedMethodsModel( objectType ); + } + + @Override + @SuppressWarnings( "unchecked" ) + public Iterable> types() + { + Iterable> iterable = iterable( objectType ); + return (Iterable>) iterable; + } + + @Override + public Visibility visibility() + { + return visibility; + } + + @Override + public T metaInfo( Class infoType ) + { + return metaInfo.get( infoType ); + } + + @Override + public boolean isAssignableTo( Class type ) + { + return type.isAssignableFrom( objectType ); + } + + @Override + public boolean accept( HierarchicalVisitor visitor ) + throws ThrowableType + { + if( visitor.visitEnter( this ) ) + { + if( constructorsModel.accept( visitor ) ) + { + if( injectedFieldsModel.accept( visitor ) ) + { + injectedMethodsModel.accept( visitor ); + } + } + } + return visitor.visitLeave( this ); + } + + public Object newInstance( InjectionContext injectionContext ) + { + Object instance; + try + { + instance = constructorsModel.newInstance( injectionContext ); + injectionContext = new InjectionContext( injectionContext.module(), injectionContext.uses(), instance ); + injectedFieldsModel.inject( injectionContext, instance ); + injectedMethodsModel.inject( injectionContext, instance ); + } + catch( Exception e ) + { + throw new ConstructionException( "Could not instantiate " + objectType.getName(), e ); + } + + if( instance instanceof Initializable ) + { + try + { + ( (Initializable) instance ).initialize(); + } + catch( InitializationException e ) + { + throw new ConstructionException( "Unable to initialize " + objectType, e ); + } + } + + return instance; + } + + public void inject( InjectionContext injectionContext, Object instance ) + { + injectedFieldsModel.inject( injectionContext, instance ); + injectedMethodsModel.inject( injectionContext, instance ); + } + + @Override + public String toString() + { + return objectType.getName(); + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/object/ObjectsModel.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/object/ObjectsModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/object/ObjectsModel.java new file mode 100644 index 0000000..9f05074 --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/object/ObjectsModel.java @@ -0,0 +1,55 @@ +/* + * 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.object; + +import java.util.List; +import org.apache.zest.functional.HierarchicalVisitor; +import org.apache.zest.functional.VisitableHierarchy; + +/** + * JAVADOC + */ +public class ObjectsModel + implements VisitableHierarchy +{ + private final List objectModels; + + public ObjectsModel( List objectModels ) + { + this.objectModels = objectModels; + } + + @Override + public boolean accept( HierarchicalVisitor visitor ) + throws ThrowableType + { + if( visitor.visitEnter( this ) ) + { + for( ObjectModel objectModel : objectModels ) + { + if( !objectModel.accept( visitor ) ) + { + break; + } + } + } + return visitor.visitLeave( this ); + } + + public Iterable models() + { + return objectModels; + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/package.html ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/package.html b/core/runtime/src/main/java/org/apache/zest/runtime/package.html new file mode 100644 index 0000000..612d1ae --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/package.html @@ -0,0 +1,21 @@ + + + +

Apache Zest™ Runtime.

+ + http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertiesModel.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertiesModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertiesModel.java new file mode 100644 index 0000000..202fc89 --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertiesModel.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2007-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.property; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Member; +import java.util.LinkedHashMap; +import java.util.Map; +import org.apache.zest.api.common.QualifiedName; +import org.apache.zest.functional.HierarchicalVisitor; +import org.apache.zest.functional.VisitableHierarchy; + +/** + * Base class for properties model + */ +public class PropertiesModel + implements VisitableHierarchy +{ + protected final Map mapAccessiblePropertyModel = new LinkedHashMap<>(); + + public PropertiesModel() + { + } + + public void addProperty( PropertyModel property ) + { + mapAccessiblePropertyModel.put( property.accessor(), property ); + } + + @Override + public boolean accept( HierarchicalVisitor visitor ) + throws ThrowableType + { + if( visitor.visitEnter( this ) ) + { + for( PropertyModel propertyModel : mapAccessiblePropertyModel.values() ) + { + if( !propertyModel.accept( visitor ) ) + { + break; + } + } + } + + return visitor.visitLeave( this ); + } + + public Iterable properties() + { + return mapAccessiblePropertyModel.values(); + } + + public PropertyModel getProperty( AccessibleObject accessor ) + { + PropertyModel propertyModel = mapAccessiblePropertyModel.get( accessor ); + if( propertyModel == null ) + { + throw new IllegalArgumentException( "No property found with name: " + ( (Member) accessor ).getName() ); + } + + return propertyModel; + } + + public PropertyModel getPropertyByName( String name ) + throws IllegalArgumentException + { + for( PropertyModel propertyModel : mapAccessiblePropertyModel.values() ) + { + if( propertyModel.qualifiedName().name().equals( name ) ) + { + return propertyModel; + } + } + throw new IllegalArgumentException( "No property found with name: " + name ); + } + + public PropertyModel getPropertyByQualifiedName( QualifiedName name ) + throws IllegalArgumentException + { + for( PropertyModel propertyModel : mapAccessiblePropertyModel.values() ) + { + if( propertyModel.qualifiedName().equals( name ) ) + { + return propertyModel; + } + } + throw new IllegalArgumentException( "No property found with qualified name: " + name ); + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertyInfo.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertyInfo.java b/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertyInfo.java new file mode 100644 index 0000000..cb185cf --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertyInfo.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.property; + +import java.lang.reflect.Type; +import org.apache.zest.api.common.QualifiedName; +import org.apache.zest.runtime.composite.ConstraintsCheck; + +/** + * TODO + */ +public interface PropertyInfo + 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/property/PropertyInstance.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertyInstance.java b/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertyInstance.java new file mode 100644 index 0000000..9bd2e9d --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertyInstance.java @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2007, Rickard Öberg. All Rights Reserved. + * Copyright (c) 2008, Edward Yakop. 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.property; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +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.type.CollectionType; +import org.apache.zest.api.type.MapType; +import org.apache.zest.api.type.ValueCompositeType; +import org.apache.zest.api.value.ValueComposite; +import org.apache.zest.runtime.value.ValueInstance; + +/** + * {@code PropertyInstance} represents a property. + */ +public class PropertyInstance + implements Property +{ + protected volatile T value; + protected PropertyInfo model; + + /** + * Construct an instance of {@code PropertyInstance} with the specified arguments. + * + * @param model The property model. This argument must not be {@code null}. + * @param aValue The property value. + */ + public PropertyInstance( PropertyInfo model, T aValue ) + { + this.model = model; + value = aValue; + } + + public PropertyInfo propertyInfo() + { + return model; + } + + /** + * @param model The property model. This argument must not be {@code null}. + */ + public void setPropertyInfo( PropertyInfo model ) + { + this.model = model; + } + + /** + * Returns this property value. + * + * @return This property value. + */ + @Override + public T get() + { + return value; + } + + /** + * Sets this property value. + * + * @param aNewValue The new value. + */ + @Override + public void set( T aNewValue ) + { + if( model.isImmutable() ) + { + throw new IllegalStateException( "Property [" + model.qualifiedName() + "] is immutable." ); + } + + model.checkConstraints( aNewValue ); + + value = aNewValue; + } + + /** + * Perform equals with {@code o} argument. + *

+ * The definition of equals() for the Property is that if both the state and descriptor are equal, + * then the properties are equal. + *

+ * + * @param o The other object to compare. + * @return Returns a {@code boolean} indicator whether this object is equals the other. + */ + @Override + public boolean equals( Object o ) + { + if( this == o ) + { + return true; + } + if( o == null || getClass() != o.getClass() ) + { + return false; + } + + Property that = (Property) o; + // Unwrap if needed + while( that instanceof PropertyWrapper ) + { + that = ( (PropertyWrapper) that ).next(); + } + // Descriptor equality + PropertyDescriptor thatDescriptor = (PropertyDescriptor) ( (PropertyInstance) that ).propertyInfo(); + if( !model.equals( thatDescriptor ) ) + { + return false; + } + // State equality + T value = get(); + if( value == null ) + { + return that.get() == null; + } + return value.equals( that.get() ); + } + + /** + * Calculate hash code. + * + * @return the hashcode of this instance. + */ + @Override + public int hashCode() + { + int hash = model.hashCode() * 19; // Descriptor + T value = get(); + if( value != null ) + { + hash += value.hashCode() * 13; // State + } + return hash; + } + + /** + * Returns the value as string. + * + * @return The value as string. + */ + @Override + public String toString() + { + Object value = get(); + return value == null ? "" : value.toString(); + } + + @SuppressWarnings( {"raw", "unchecked"} ) + public void prepareToBuild( PropertyModel propertyDescriptor ) + { + // Check if state has to be modified + model = propertyDescriptor.getBuilderInfo(); + if( propertyDescriptor.valueType() instanceof ValueCompositeType ) + { + Object value = get(); + if( value != null ) + { + ValueInstance.valueInstanceOf( (ValueComposite) value ).prepareToBuild(); + } + } + else if( propertyDescriptor.valueType() instanceof CollectionType ) + { + Object value = get(); + + if( value != null ) + { + if( value instanceof List ) + { + value = new ArrayList( (Collection) value ); + } + else if( value instanceof Set ) + { + value = new LinkedHashSet( (Collection) value ); + } + + // Check if items are Values + CollectionType collection = (CollectionType) propertyDescriptor.valueType(); + if( collection.collectedType() instanceof ValueCompositeType ) + { + Collection coll = (Collection) value; + for( Object instance : coll ) + { + ValueInstance.valueInstanceOf( (ValueComposite) instance ).prepareToBuild(); + } + } + + set( (T) value ); + } + } + else if( propertyDescriptor.valueType() instanceof MapType ) + { + Object value = get(); + + if( value != null ) + { + Map map = new LinkedHashMap( (Map) value ); + + // Check if keys/values are Values + MapType mapType = (MapType) propertyDescriptor.valueType(); + if( mapType.keyType() instanceof ValueCompositeType ) + { + for( Object instance : map.keySet() ) + { + ValueInstance.valueInstanceOf( (ValueComposite) instance ).prepareToBuild(); + } + } + if( mapType.valueType() instanceof ValueCompositeType ) + { + for( Object instance : map.values() ) + { + ValueInstance.valueInstanceOf( (ValueComposite) instance ).prepareToBuild(); + } + } + + set( (T) value ); + } + } + } + + @SuppressWarnings( {"raw", "unchecked"} ) + public void prepareBuilderState( PropertyModel propertyDescriptor ) + { + // Check if state has to be modified + if( propertyDescriptor.valueType() instanceof ValueCompositeType ) + { + Object value = get(); + if( value != null ) + { + ValueInstance.valueInstanceOf( (ValueComposite) value ).prepareBuilderState(); + } + } + else if( propertyDescriptor.valueType() instanceof CollectionType ) + { + T value = get(); + if( value != null ) + { + if( propertyDescriptor.isImmutable() ) + { + if( value instanceof List ) + { + value = (T) Collections.unmodifiableList( (List) value ); + } + else if( value instanceof Set ) + { + value = (T) Collections.unmodifiableSet( (Set) value ); + } + else + { + value = (T) Collections.unmodifiableCollection( (Collection) value ); + } + + this.value = value; + } + + CollectionType collection = (CollectionType) propertyDescriptor.valueType(); + if( collection.collectedType() instanceof ValueCompositeType ) + { + Collection coll = (Collection) value; + for( Object instance : coll ) + { + ValueInstance.valueInstanceOf( (ValueComposite) instance ).prepareBuilderState(); + } + } + } + } + else if( propertyDescriptor.valueType() instanceof MapType ) + { + T value = get(); + + if( value != null ) + { + MapType mapType = (MapType) propertyDescriptor.valueType(); + if( mapType.keyType() instanceof ValueCompositeType ) + { + Map map = (Map) value; + for( Object instance : map.keySet() ) + { + ValueInstance.valueInstanceOf( (ValueComposite) instance ).prepareBuilderState(); + } + } + if( mapType.valueType() instanceof ValueCompositeType ) + { + Map map = (Map) value; + for( Object instance : map.values() ) + { + ValueInstance.valueInstanceOf( (ValueComposite) instance ).prepareBuilderState(); + } + } + if( propertyDescriptor.isImmutable() ) + { + value = (T) Collections.unmodifiableMap( (Map) value ); + } + + this.value = value; + } + } + + model = propertyDescriptor; + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertyModel.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertyModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertyModel.java new file mode 100644 index 0000000..9f37373 --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/property/PropertyModel.java @@ -0,0 +1,309 @@ +/* + * 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.property; + +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.common.MetaInfo; +import org.apache.zest.api.common.QualifiedName; +import org.apache.zest.api.constraint.ConstraintViolation; +import org.apache.zest.api.constraint.ConstraintViolationException; +import org.apache.zest.api.entity.Queryable; +import org.apache.zest.api.property.DefaultValues; +import org.apache.zest.api.property.GenericPropertyInfo; +import org.apache.zest.api.property.InvalidPropertyTypeException; +import org.apache.zest.api.property.Property; +import org.apache.zest.api.property.PropertyDescriptor; +import org.apache.zest.api.structure.Module; +import org.apache.zest.api.type.Serialization; +import org.apache.zest.api.type.ValueCompositeType; +import org.apache.zest.api.type.ValueType; +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 org.apache.zest.runtime.types.ValueTypeFactory; + +import static org.apache.zest.functional.Iterables.empty; +import static org.apache.zest.functional.Iterables.first; + +/** + * Model for a Property. + * + *

Equality is based on the Property accessor object (property type and name), not on the QualifiedName.

+ */ +public class PropertyModel + implements PropertyDescriptor, PropertyInfo, Binder, Visitable +{ + private Type type; + + private transient AccessibleObject accessor; // Interface accessor + + private final QualifiedName qualifiedName; + + private final ValueConstraintsInstance constraints; // May be null + + protected final MetaInfo metaInfo; + + private final Object initialValue; + + private final boolean useDefaults; + + private final boolean immutable; + + private ValueType valueType; + + protected PropertyInfo builderInfo; + + private final boolean queryable; + + public PropertyModel( AccessibleObject accessor, + boolean immutable, + boolean useDefaults, + ValueConstraintsInstance constraints, + MetaInfo metaInfo, + Object initialValue + ) + { + if( accessor instanceof Method ) + { + Method m = (Method) accessor; + if( !m.getReturnType().equals( Property.class ) ) + { + throw new InvalidPropertyTypeException( accessor ); + } + } + this.immutable = immutable; + this.metaInfo = metaInfo; + type = GenericPropertyInfo.propertyTypeOf( accessor ); + this.accessor = accessor; + qualifiedName = QualifiedName.fromAccessor( accessor ); + + this.useDefaults = useDefaults; + + this.initialValue = initialValue; + + this.constraints = constraints; + + final Queryable queryable = accessor.getAnnotation( Queryable.class ); + this.queryable = queryable == null || queryable.value(); + } + + @Override + public T metaInfo( Class infoType ) + { + return metaInfo.get( infoType ); + } + + public String name() + { + return qualifiedName.name(); + } + + @Override + public QualifiedName qualifiedName() + { + return qualifiedName; + } + + @Override + public Type type() + { + return type; + } + + @Override + public AccessibleObject accessor() + { + return accessor; + } + + @Override + public ValueType valueType() + { + return valueType; + } + + @Override + public boolean isImmutable() + { + return immutable; + } + + public PropertyInfo getBuilderInfo() + { + return builderInfo; + } + + @Override + public boolean queryable() + { + return queryable; + } + + @Override + public Object initialValue( Module module ) + { + // Use supplied value from assembly + Object value = initialValue; + + // Check for @UseDefaults annotation + if( value == null && useDefaults ) + { + if( valueType instanceof ValueCompositeType ) + { + return module.newValue( (Class) first( valueType().types() ) ); + } + else + { + value = DefaultValues.getDefaultValueOf( type ); + } + } + + return value; + } + + @Override + public void bind( Resolution resolution ) + throws BindingException + { + ValueTypeFactory factory = ValueTypeFactory.instance(); + Class declaringClass = ( (Member) accessor() ).getDeclaringClass(); + Class mainType = first( resolution.model().types() ); + Serialization.Variant variant = findVariant(); + valueType = factory.newValueType( type(), declaringClass, mainType, resolution.layer(), resolution.module(), variant ); + builderInfo = new BuilderPropertyInfo(); + if( type instanceof TypeVariable ) + { + type = Classes.resolveTypeVariable( (TypeVariable) type, declaringClass, mainType ); + } + } + + private Serialization.Variant findVariant() + { + Serialization serialization = metaInfo.get( Serialization.class ); + Serialization.Variant variant = null; + if( serialization != null ) + { + variant = serialization.value(); + } + if( variant == null ) + { + variant = Serialization.Variant.entry; + } + return variant; + } + + @Override + public boolean accept( Visitor visitor ) + throws ThrowableType + { + return visitor.visit( this ); + } + + @Override + public void checkConstraints( Object value ) + throws ConstraintViolationException + { + if( constraints != null ) + { + List violations = constraints.checkConstraints( value ); + if( !violations.isEmpty() ) + { + Iterable> empty = empty(); + throw new ConstraintViolationException( "", empty, ( (Member) accessor ), violations ); + } + } + } + + @Override + public boolean equals( Object o ) + { + if( this == o ) + { + return true; + } + if( o == null || getClass() != o.getClass() ) + { + return false; + } + + PropertyModel that = (PropertyModel) o; + return accessor.equals( that.accessor ); + } + + @Override + public int hashCode() + { + return accessor.hashCode(); + } + + @Override + public String toString() + { + if( accessor instanceof Field ) + { + return ( (Field) accessor ).toGenericString(); + } + else + { + return ( (Method) accessor ).toGenericString(); + } + } + + private class BuilderPropertyInfo implements PropertyInfo + { + @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 + { + if( constraints != null ) + { + List violations = constraints.checkConstraints( value ); + if( !violations.isEmpty() ) + { + Iterable> empty = empty(); + throw new ConstraintViolationException( "", empty, ( (Member) accessor ), violations ); + } + } + } + } +} \ No newline at end of file