http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/InjectionProviderFactoryStrategy.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/InjectionProviderFactoryStrategy.java b/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/InjectionProviderFactoryStrategy.java new file mode 100644 index 0000000..38bc5ba --- /dev/null +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/InjectionProviderFactoryStrategy.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + */ + +package org.apache.polygene.runtime.injection.provider; + +import java.lang.annotation.Annotation; +import java.util.HashMap; +import java.util.Map; +import org.apache.polygene.api.common.MetaInfo; +import org.apache.polygene.api.composite.InvalidValueCompositeException; +import org.apache.polygene.api.composite.ModelDescriptor; +import org.apache.polygene.api.concern.internal.ConcernFor; +import org.apache.polygene.api.injection.scope.Invocation; +import org.apache.polygene.api.injection.scope.Service; +import org.apache.polygene.api.injection.scope.State; +import org.apache.polygene.api.injection.scope.Structure; +import org.apache.polygene.api.injection.scope.This; +import org.apache.polygene.api.injection.scope.Uses; +import org.apache.polygene.api.sideeffect.internal.SideEffectFor; +import org.apache.polygene.api.value.ValueComposite; +import org.apache.polygene.bootstrap.InvalidInjectionException; +import org.apache.polygene.runtime.injection.DependencyModel; +import org.apache.polygene.runtime.injection.InjectionProvider; +import org.apache.polygene.runtime.injection.InjectionProviderFactory; +import org.apache.polygene.runtime.model.Resolution; + +/** + * JAVADOC + */ +public final class InjectionProviderFactoryStrategy + implements InjectionProviderFactory +{ + private final Map<Class<? extends Annotation>, InjectionProviderFactory> generalProviderFactories = new HashMap<>(); + private final Map<Class<? extends Annotation>, InjectionProviderFactory> valuesProviderFactories = new HashMap<>(); + private MetaInfo metaInfo; + + public InjectionProviderFactoryStrategy( MetaInfo metaInfo ) + { + this.metaInfo = metaInfo; + valuesProviderFactories.put( This.class, new ThisInjectionProviderFactory() ); + ModifiesInjectionProviderFactory modifiesInjectionProviderFactory = new ModifiesInjectionProviderFactory(); + valuesProviderFactories.put( ConcernFor.class, modifiesInjectionProviderFactory ); + valuesProviderFactories.put( SideEffectFor.class, modifiesInjectionProviderFactory ); + valuesProviderFactories.put( State.class, new StateInjectionProviderFactory() ); + + valuesProviderFactories.put( Structure.class, new CachingInjectionProviderFactoryDecorator( new StructureInjectionProviderFactory() ) ); + valuesProviderFactories.put( Service.class, new CachingInjectionProviderFactoryDecorator( new ServiceInjectionProviderFactory() ) ); + generalProviderFactories.put( Invocation.class, new InvocationInjectionProviderFactory() ); + generalProviderFactories.put( Uses.class, new UsesInjectionProviderFactory() ); + } + + @Override + public InjectionProvider newInjectionProvider( Resolution resolution, DependencyModel dependencyModel ) + throws InvalidInjectionException + { + Class<? extends Annotation> injectionAnnotationType = dependencyModel.injectionAnnotation().annotationType(); + InjectionProviderFactory factory1 = generalProviderFactories.get( injectionAnnotationType ); + InjectionProviderFactory factory2 = valuesProviderFactories.get( injectionAnnotationType ); + if( factory1 == null && factory2 == null ) + { + InjectionProviderFactory factory = metaInfo.get( InjectionProviderFactory.class ); + if( factory != null ) + { + return factory.newInjectionProvider( resolution, dependencyModel ); + } + else + { + throw new InvalidInjectionException( "Unknown injection annotation @" + injectionAnnotationType.getSimpleName() ); + } + } + ModelDescriptor composite = resolution.model(); + Class<?> compositeType = composite.types().findFirst().orElse( null ); + if( factory1 != null && ValueComposite.class.isAssignableFrom( compositeType ) ) + { + throw new InvalidValueCompositeException( "@" + injectionAnnotationType.getSimpleName() + " is not allowed in ValueComposites: " + compositeType ); + } + + InjectionProviderFactory factory; + if( factory1 == null ) + { + factory = factory2; + } + else + { + factory = factory1; + } + return factory.newInjectionProvider( resolution, dependencyModel ); + } +}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/InvocationInjectionProviderFactory.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/InvocationInjectionProviderFactory.java b/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/InvocationInjectionProviderFactory.java new file mode 100644 index 0000000..90e2987 --- /dev/null +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/InvocationInjectionProviderFactory.java @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + */ +package org.apache.polygene.runtime.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.polygene.api.util.Classes; +import org.apache.polygene.bootstrap.InvalidInjectionException; +import org.apache.polygene.runtime.composite.CompositeMethodModel; +import org.apache.polygene.runtime.injection.DependencyModel; +import org.apache.polygene.runtime.injection.InjectionContext; +import org.apache.polygene.runtime.injection.InjectionProvider; +import org.apache.polygene.runtime.injection.InjectionProviderFactory; +import org.apache.polygene.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.apply( 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.apply( 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<Annotation>) 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<Method> 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/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/ModifiesInjectionProviderFactory.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/ModifiesInjectionProviderFactory.java b/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/ModifiesInjectionProviderFactory.java new file mode 100644 index 0000000..b0f662b --- /dev/null +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/ModifiesInjectionProviderFactory.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + */ +package org.apache.polygene.runtime.injection.provider; + +import org.apache.polygene.api.composite.CompositeDescriptor; +import org.apache.polygene.api.util.Classes; +import org.apache.polygene.bootstrap.InvalidInjectionException; +import org.apache.polygene.runtime.injection.DependencyModel; +import org.apache.polygene.runtime.injection.InjectionContext; +import org.apache.polygene.runtime.injection.InjectionProvider; +import org.apache.polygene.runtime.injection.InjectionProviderFactory; +import org.apache.polygene.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.apply( 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/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/ServiceInjectionProviderFactory.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/ServiceInjectionProviderFactory.java b/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/ServiceInjectionProviderFactory.java new file mode 100644 index 0000000..f3dc70c --- /dev/null +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/ServiceInjectionProviderFactory.java @@ -0,0 +1,224 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + */ + +package org.apache.polygene.runtime.injection.provider; + +import java.lang.annotation.Annotation; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Stream; +import org.apache.polygene.api.service.NoSuchServiceException; +import org.apache.polygene.api.service.ServiceReference; +import org.apache.polygene.api.service.qualifier.Qualifier; +import org.apache.polygene.api.util.Classes; +import org.apache.polygene.bootstrap.InvalidInjectionException; +import org.apache.polygene.runtime.injection.DependencyModel; +import org.apache.polygene.runtime.injection.InjectionContext; +import org.apache.polygene.runtime.injection.InjectionProvider; +import org.apache.polygene.runtime.injection.InjectionProviderFactory; +import org.apache.polygene.runtime.model.Resolution; + +import static java.util.stream.Collectors.toCollection; +import static org.apache.polygene.api.util.Annotations.typeHasAnnotation; + +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 = Stream.of( dependencyModel.annotations() ) + .filter( typeHasAnnotation( Qualifier.class ) ) + .findFirst().orElse( null ); + Predicate<ServiceReference<?>> 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.apply( iterableType ).equals( ServiceReference.class ) ) + { + // @Service Iterable<ServiceReference<MyService<Foo>> serviceRefs + Type serviceType = ( (ParameterizedType) iterableType ).getActualTypeArguments()[ 0 ]; + + return new IterableServiceReferenceProvider( serviceType, serviceQualifier ); + } + else + { + // @Service Iterable<MyService<Foo>> services + return new IterableServiceProvider( iterableType, serviceQualifier ); + } + } + else if( dependencyModel.rawInjectionType().equals( ServiceReference.class ) ) + { + // @Service ServiceReference<MyService<Foo>> serviceRef + Type referencedType = ( (ParameterizedType) dependencyModel.injectionType() ).getActualTypeArguments()[ 0 ]; + return new ServiceReferenceProvider( referencedType, serviceQualifier ); + } + else + { + // @Service MyService<Foo> service + return new ServiceProvider( dependencyModel.injectionType(), serviceQualifier ); + } + } + + private static class IterableServiceReferenceProvider + extends ServiceInjectionProvider + { + private IterableServiceReferenceProvider( Type serviceType, Predicate<ServiceReference<?>> serviceQualifier ) + { + super( serviceType, serviceQualifier ); + } + + @Override + public synchronized Object provideInjection( InjectionContext context ) + throws InjectionProviderException + { + return getServiceReferences( context ).collect( toCollection( ArrayList::new ) ); + } + } + + private static class IterableServiceProvider + extends ServiceInjectionProvider + implements Function<ServiceReference<?>, Object> + { + private IterableServiceProvider( Type serviceType, Predicate<ServiceReference<?>> serviceQualifier ) + { + super( serviceType, serviceQualifier ); + } + + @Override + public synchronized Object provideInjection( final InjectionContext context ) + throws InjectionProviderException + { + return getServiceReferences( context ).map( ServiceReference::get ) + .collect( toCollection( ArrayList::new ) ); + } + + @Override + public Object apply( ServiceReference<?> objectServiceReference ) + { + return objectServiceReference.get(); + } + } + + private static class ServiceReferenceProvider + extends ServiceInjectionProvider + { + ServiceReferenceProvider( Type serviceType, Predicate<ServiceReference<?>> 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, Predicate<ServiceReference<?>> 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; + } + } + } + + public abstract static class ServiceInjectionProvider + implements InjectionProvider + { + private final Type serviceType; + private final Predicate<ServiceReference<?>> serviceQualifier; + + private ServiceInjectionProvider( Type serviceType, Predicate<ServiceReference<?>> serviceQualifier ) + { + this.serviceType = serviceType; + this.serviceQualifier = serviceQualifier; + } + + protected ServiceReference<Object> getServiceReference( InjectionContext context ) + { + try + { + if( serviceQualifier == null ) + { + return context.module().instance().findService( serviceType ); + } + else + { + return context.module().instance().findServices( serviceType ) + .filter( serviceQualifier ).findFirst().orElse( null ); + } + } + catch( NoSuchServiceException e ) + { + return null; + } + } + + protected Stream<ServiceReference<Object>> getServiceReferences( final InjectionContext context ) + { + if( serviceQualifier == null ) + { + return context.module().instance().findServices( serviceType ); + } + else + { + return context.module().instance().findServices( serviceType ).filter( serviceQualifier ); + } + } + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/StateInjectionProviderFactory.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/StateInjectionProviderFactory.java b/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/StateInjectionProviderFactory.java new file mode 100644 index 0000000..3a3a80e --- /dev/null +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/StateInjectionProviderFactory.java @@ -0,0 +1,273 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + */ +package org.apache.polygene.runtime.injection.provider; + +import org.apache.polygene.api.association.AbstractAssociation; +import org.apache.polygene.api.association.Association; +import org.apache.polygene.api.association.AssociationDescriptor; +import org.apache.polygene.api.association.AssociationStateDescriptor; +import org.apache.polygene.api.association.AssociationStateHolder; +import org.apache.polygene.api.association.ManyAssociation; +import org.apache.polygene.api.association.NamedAssociation; +import org.apache.polygene.api.composite.StateDescriptor; +import org.apache.polygene.api.composite.StatefulCompositeDescriptor; +import org.apache.polygene.api.entity.EntityDescriptor; +import org.apache.polygene.api.injection.scope.State; +import org.apache.polygene.api.property.Property; +import org.apache.polygene.api.property.PropertyDescriptor; +import org.apache.polygene.api.property.StateHolder; +import org.apache.polygene.api.unitofwork.UnitOfWork; +import org.apache.polygene.bootstrap.InvalidInjectionException; +import org.apache.polygene.runtime.entity.EntityInstance; +import org.apache.polygene.runtime.injection.DependencyModel; +import org.apache.polygene.runtime.injection.InjectionContext; +import org.apache.polygene.runtime.injection.InjectionProvider; +import org.apache.polygene.runtime.injection.InjectionProviderFactory; +import org.apache.polygene.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<String> 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<MyEntity> 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<MyEntity> 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<MyEntity> 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/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/StructureInjectionProviderFactory.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/StructureInjectionProviderFactory.java b/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/StructureInjectionProviderFactory.java new file mode 100644 index 0000000..0d20dab --- /dev/null +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/StructureInjectionProviderFactory.java @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + */ +package org.apache.polygene.runtime.injection.provider; + +import java.lang.reflect.Type; +import org.apache.polygene.api.PolygeneAPI; +import org.apache.polygene.api.composite.TransientBuilderFactory; +import org.apache.polygene.api.object.ObjectFactory; +import org.apache.polygene.api.query.QueryBuilderFactory; +import org.apache.polygene.api.service.ServiceFinder; +import org.apache.polygene.api.structure.Application; +import org.apache.polygene.api.structure.ApplicationDescriptor; +import org.apache.polygene.api.structure.Layer; +import org.apache.polygene.api.structure.LayerDescriptor; +import org.apache.polygene.api.structure.Module; +import org.apache.polygene.api.structure.ModuleDescriptor; +import org.apache.polygene.api.unitofwork.UnitOfWorkFactory; +import org.apache.polygene.api.value.ValueBuilderFactory; +import org.apache.polygene.bootstrap.InvalidInjectionException; +import org.apache.polygene.runtime.injection.DependencyModel; +import org.apache.polygene.runtime.injection.InjectionContext; +import org.apache.polygene.runtime.injection.InjectionProvider; +import org.apache.polygene.runtime.injection.InjectionProviderFactory; +import org.apache.polygene.runtime.model.Resolution; +import org.apache.polygene.runtime.structure.ApplicationInstance; + +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().instance(); + } + else if( clazz.equals( ObjectFactory.class ) ) + { + return context.module().instance(); + } + else if( clazz.equals( ValueBuilderFactory.class ) ) + { + return context.module().instance(); + } + else if( clazz.equals( UnitOfWorkFactory.class ) ) + { + return context.module().instance().unitOfWorkFactory(); + } + else if( clazz.equals( QueryBuilderFactory.class ) ) + { + return context.module().instance(); + } + else if( clazz.equals( ServiceFinder.class ) ) + { + return context.module().instance(); + } + else if( Module.class.isAssignableFrom( clazz ) ) + { + return context.module().instance(); + } + else if( ModuleDescriptor.class.isAssignableFrom( clazz ) ) + { + return context.module(); + } + else if( Layer.class.isAssignableFrom( clazz ) ) + { + return context.module().layer().instance(); + } + else if( LayerDescriptor.class.isAssignableFrom( clazz ) ) + { + return context.module().layer(); + } + else if( Application.class.isAssignableFrom( clazz ) ) + { + return context.module().layer().instance().application(); + } + else if( ApplicationDescriptor.class.isAssignableFrom( clazz ) ) + { + return context.module().layer().instance().application().descriptor(); + } + else if( PolygeneAPI.class.isAssignableFrom( clazz ) ) + { + return (( ApplicationInstance) context.module().layer().instance().application()).runtime(); + } + return null; + } + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/ThisInjectionProviderFactory.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/ThisInjectionProviderFactory.java b/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/ThisInjectionProviderFactory.java new file mode 100644 index 0000000..161cfbd --- /dev/null +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/ThisInjectionProviderFactory.java @@ -0,0 +1,130 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + */ +package org.apache.polygene.runtime.injection.provider; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.apache.polygene.api.composite.CompositeDescriptor; +import org.apache.polygene.api.util.Classes; +import org.apache.polygene.bootstrap.InvalidInjectionException; +import org.apache.polygene.runtime.composite.ProxyGenerator; +import org.apache.polygene.runtime.injection.DependencyModel; +import org.apache.polygene.runtime.injection.InjectionContext; +import org.apache.polygene.runtime.injection.InjectionProvider; +import org.apache.polygene.runtime.injection.InjectionProviderFactory; +import org.apache.polygene.runtime.model.Resolution; + +/** + * 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(); + + Stream<Class<?>> injectionTypes; + if( Classes.assignableTypeSpecification( thisType ).test( bindingContext.model() ) ) + { + injectionTypes = bindingContext.model().types(); + } + else + { + CompositeDescriptor acd = ( (CompositeDescriptor) bindingContext.model() ); + injectionTypes = acd.mixinTypes().filter( thisType::isAssignableFrom ); + } + + List<Class<?>> classes = injectionTypes.collect( Collectors.toList() ); + if( classes.size() == 0 ) + { + throw new InvalidInjectionException( "Composite " + bindingContext.model() + + " does not implement @This type " + thisType.getName() + " in fragment " + + dependencyModel.injectedClass().getName() ); + } + return new ThisInjectionProvider( classes ); + } + 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( List<Class<?>> types ) + { + try + { + Class proxyClass; + Class<?> mainType = types.get( 0 ); + if( Proxy.class.isAssignableFrom( mainType ) ) + { + proxyClass = mainType; + } + else + { + interfaces = types.stream().map( Class.class::cast ).toArray( Class[]::new ); + 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/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/UsesInjectionProviderFactory.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/UsesInjectionProviderFactory.java b/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/UsesInjectionProviderFactory.java new file mode 100644 index 0000000..f4549c5 --- /dev/null +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/injection/provider/UsesInjectionProviderFactory.java @@ -0,0 +1,132 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + */ +package org.apache.polygene.runtime.injection.provider; + +import java.lang.reflect.Constructor; +import org.apache.polygene.api.composite.NoSuchTransientException; +import org.apache.polygene.api.object.NoSuchObjectException; +import org.apache.polygene.api.structure.Module; +import org.apache.polygene.bootstrap.InvalidInjectionException; +import org.apache.polygene.runtime.composite.UsesInstance; +import org.apache.polygene.runtime.injection.DependencyModel; +import org.apache.polygene.runtime.injection.InjectionContext; +import org.apache.polygene.runtime.injection.InjectionProvider; +import org.apache.polygene.runtime.injection.InjectionProviderFactory; +import org.apache.polygene.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().instance(); + + 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/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/internal/Activator.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/internal/Activator.java b/core/runtime/src/main/java/org/apache/polygene/runtime/internal/Activator.java new file mode 100644 index 0000000..6a0481f --- /dev/null +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/internal/Activator.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + */ +package org.apache.polygene.runtime.internal; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceRegistration; +import org.apache.polygene.bootstrap.PolygeneRuntime; +import org.apache.polygene.bootstrap.RuntimeFactory; +import org.apache.polygene.runtime.PolygeneRuntimeImpl; + +/** + * + */ +public class Activator + implements BundleActivator +{ + private ServiceRegistration registration; + + @Override + public void start( BundleContext bundleContext ) + throws Exception + { + RuntimeFactory factory = new RuntimeFactory() + { + @Override + public PolygeneRuntime createRuntime() + { + return new PolygeneRuntimeImpl(); + } + }; + 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/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/model/Binder.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/model/Binder.java b/core/runtime/src/main/java/org/apache/polygene/runtime/model/Binder.java new file mode 100644 index 0000000..c59cc96 --- /dev/null +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/model/Binder.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + */ + +package org.apache.polygene.runtime.model; + +import org.apache.polygene.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/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/model/Resolution.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/model/Resolution.java b/core/runtime/src/main/java/org/apache/polygene/runtime/model/Resolution.java new file mode 100644 index 0000000..f5ff0f5 --- /dev/null +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/model/Resolution.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + */ + +package org.apache.polygene.runtime.model; + +import java.lang.reflect.Field; +import org.apache.polygene.api.composite.ModelDescriptor; +import org.apache.polygene.runtime.composite.CompositeMethodModel; +import org.apache.polygene.runtime.structure.ApplicationModel; +import org.apache.polygene.runtime.structure.LayerModel; +import org.apache.polygene.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/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/object/ObjectModel.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/object/ObjectModel.java b/core/runtime/src/main/java/org/apache/polygene/runtime/object/ObjectModel.java new file mode 100644 index 0000000..c1a3dbf --- /dev/null +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/object/ObjectModel.java @@ -0,0 +1,158 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + */ + +package org.apache.polygene.runtime.object; + +import java.util.stream.Stream; +import org.apache.polygene.api.common.ConstructionException; +import org.apache.polygene.api.common.MetaInfo; +import org.apache.polygene.api.common.Visibility; +import org.apache.polygene.api.mixin.Initializable; +import org.apache.polygene.api.mixin.InitializationException; +import org.apache.polygene.api.object.ObjectDescriptor; +import org.apache.polygene.api.structure.ModuleDescriptor; +import org.apache.polygene.api.util.HierarchicalVisitor; +import org.apache.polygene.api.util.VisitableHierarchy; +import org.apache.polygene.runtime.composite.ConstructorsModel; +import org.apache.polygene.runtime.injection.InjectedFieldsModel; +import org.apache.polygene.runtime.injection.InjectedMethodsModel; +import org.apache.polygene.runtime.injection.InjectionContext; + +/** + * JAVADOC + */ +public final class ObjectModel + implements ObjectDescriptor, VisitableHierarchy<Object, Object> +{ + private final ModuleDescriptor module; + 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( ModuleDescriptor module, + Class<?> objectType, + Visibility visibility, + MetaInfo metaInfo + ) + { + this.module = module; + 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 Stream<Class<?>> types() + { + return Stream.of( objectType ); + } + + @Override + public Visibility visibility() + { + return visibility; + } + + @Override + public ModuleDescriptor module() + { + return module; + } + + @Override + public <T> T metaInfo( Class<T> infoType ) + { + return metaInfo.get( infoType ); + } + + @Override + public boolean isAssignableTo( Class<?> type ) + { + return type.isAssignableFrom( objectType ); + } + + @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 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( Exception e ) + { + String message = "Unable to initialize " + objectType; + throw new ConstructionException( new InitializationException( message, 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/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/object/ObjectsModel.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/object/ObjectsModel.java b/core/runtime/src/main/java/org/apache/polygene/runtime/object/ObjectsModel.java new file mode 100644 index 0000000..84d2c11 --- /dev/null +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/object/ObjectsModel.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + */ + +package org.apache.polygene.runtime.object; + +import java.util.List; +import java.util.stream.Stream; +import org.apache.polygene.api.util.HierarchicalVisitor; +import org.apache.polygene.api.util.VisitableHierarchy; + +/** + * JAVADOC + */ +public class ObjectsModel + implements VisitableHierarchy<Object, Object> +{ + private final List<ObjectModel> objectModels; + + public ObjectsModel( List<ObjectModel> objectModels ) + { + this.objectModels = objectModels; + } + + @Override + public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> visitor ) + throws ThrowableType + { + if( visitor.visitEnter( this ) ) + { + for( ObjectModel objectModel : objectModels ) + { + if( !objectModel.accept( visitor ) ) + { + break; + } + } + } + return visitor.visitLeave( this ); + } + + public Stream<ObjectModel> models() + { + return objectModels.stream(); + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/package.html ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/package.html b/core/runtime/src/main/java/org/apache/polygene/runtime/package.html new file mode 100644 index 0000000..1ed6d55 --- /dev/null +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/package.html @@ -0,0 +1,24 @@ +<!-- + ~ 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. + ~ + ~ + --> +<html> + <body> + <h2>Apache Polygene⢠Runtime.</h2> + </body> +</html> http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/property/PropertiesModel.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/property/PropertiesModel.java b/core/runtime/src/main/java/org/apache/polygene/runtime/property/PropertiesModel.java new file mode 100644 index 0000000..cfcfcb5 --- /dev/null +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/property/PropertiesModel.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + */ +package org.apache.polygene.runtime.property; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Member; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.stream.Stream; +import org.apache.polygene.api.common.QualifiedName; +import org.apache.polygene.api.util.HierarchicalVisitor; +import org.apache.polygene.api.util.VisitableHierarchy; + +/** + * Base class for properties model + */ +public class PropertiesModel + implements VisitableHierarchy<Object, Object> +{ + protected final Map<AccessibleObject, PropertyModel> mapAccessiblePropertyModel = new LinkedHashMap<>(); + + public PropertiesModel() + { + } + + public void addProperty( PropertyModel property ) + { + mapAccessiblePropertyModel.put( property.accessor(), property ); + } + + @Override + public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> visitor ) + throws ThrowableType + { + if( visitor.visitEnter( this ) ) + { + for( PropertyModel propertyModel : mapAccessiblePropertyModel.values() ) + { + if( !propertyModel.accept( visitor ) ) + { + break; + } + } + } + + return visitor.visitLeave( this ); + } + + public Stream<PropertyModel> properties() + { + return mapAccessiblePropertyModel.values().stream(); + } + + 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/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/property/PropertyInfo.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/property/PropertyInfo.java b/core/runtime/src/main/java/org/apache/polygene/runtime/property/PropertyInfo.java new file mode 100644 index 0000000..fa8e1e6 --- /dev/null +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/property/PropertyInfo.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + */ +package org.apache.polygene.runtime.property; + +import java.lang.reflect.Type; +import org.apache.polygene.api.common.QualifiedName; +import org.apache.polygene.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/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/property/PropertyInstance.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/property/PropertyInstance.java b/core/runtime/src/main/java/org/apache/polygene/runtime/property/PropertyInstance.java new file mode 100644 index 0000000..72d39cb --- /dev/null +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/property/PropertyInstance.java @@ -0,0 +1,326 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + */ +package org.apache.polygene.runtime.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.polygene.api.property.Property; +import org.apache.polygene.api.property.PropertyDescriptor; +import org.apache.polygene.api.property.PropertyWrapper; +import org.apache.polygene.api.type.CollectionType; +import org.apache.polygene.api.type.MapType; +import org.apache.polygene.api.type.ValueCompositeType; +import org.apache.polygene.api.value.ValueComposite; +import org.apache.polygene.runtime.value.ValueInstance; + +/** + * {@code PropertyInstance} represents a property. + */ +public class PropertyInstance<T> + implements Property<T> +{ + 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. + * <p> + * The definition of equals() for the Property is that if both the state and descriptor are equal, + * then the properties are equal. + * </p> + * + * @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<? extends Object>) value ); + } + else if( value instanceof Set ) + { + value = (T) Collections.unmodifiableSet( (Set<? extends Object>) value ); + } + else + { + value = (T) Collections.unmodifiableCollection( (Collection<? extends Object>) 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; + } +}
