Repository: polygene-java Updated Branches: refs/heads/develop 77286d72e -> 9ee911b0e
POLYGENE-54 - Adding a ToValueConverter, ToEntityConverter and UsecaseFactory, all to support manipulation when converting value to/from entities. Project: http://git-wip-us.apache.org/repos/asf/polygene-java/repo Commit: http://git-wip-us.apache.org/repos/asf/polygene-java/commit/9ee911b0 Tree: http://git-wip-us.apache.org/repos/asf/polygene-java/tree/9ee911b0 Diff: http://git-wip-us.apache.org/repos/asf/polygene-java/diff/9ee911b0 Branch: refs/heads/develop Commit: 9ee911b0e79247d5efff911b3f5fad40b1e5660d Parents: 77286d7 Author: niclas <[email protected]> Authored: Mon Apr 10 10:56:10 2017 +0800 Committer: niclas <[email protected]> Committed: Mon Apr 10 10:56:10 2017 +0800 ---------------------------------------------------------------------- .../api/association/ManyAssociation.java | 60 ++++++-- .../api/unitofwork/ToEntityConverter.java | 94 +++++++++++++ .../api/unitofwork/ToValueConverter.java | 92 ++++++++++++ .../polygene/api/unitofwork/UnitOfWork.java | 76 +++++----- .../unitofwork/concern/UnitOfWorkConcern.java | 24 +++- .../polygene/api/usecase/UsecaseFactory.java | 34 +++++ .../apache/polygene/api/value/ValueBuilder.java | 6 + .../bootstrap/ApplicationModelFactoryImpl.java | 1 - .../runtime/unitofwork/ModuleUnitOfWork.java | 139 ++++++++++++++----- .../runtime/value/ValueBuilderInstance.java | 7 + .../value/ValueBuilderWithPrototype.java | 7 + .../runtime/value/ValueBuilderWithState.java | 10 +- .../polygene/library/rdf/model/Model2XML.java | 4 +- 13 files changed, 459 insertions(+), 95 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/polygene-java/blob/9ee911b0/core/api/src/main/java/org/apache/polygene/api/association/ManyAssociation.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/polygene/api/association/ManyAssociation.java b/core/api/src/main/java/org/apache/polygene/api/association/ManyAssociation.java index a2247b9..93aa9f2 100644 --- a/core/api/src/main/java/org/apache/polygene/api/association/ManyAssociation.java +++ b/core/api/src/main/java/org/apache/polygene/api/association/ManyAssociation.java @@ -30,24 +30,68 @@ import org.apache.polygene.api.entity.EntityReference; */ public interface ManyAssociation<T> extends Iterable<T>, AbstractAssociation { - /** - * Returns the number of references in this association. - * @return the number of references in this association. - */ - int count(); - boolean contains( T entity ); - boolean add( int i, T entity ); + /** Adds an entity reference representing the given entity to the {@code index} slot of this collection. + * <p> + * {@code index=0} represents the beginning of the collection and if the {@code index} is equal or larger + * than the length of the collection, the entity reference will be added to the end. + * </p> + * @param entity The entity whose entity reference is to be added to this collection. + * @return true if the entity reference has been added, false otherwise. + */ + boolean add( int index, T entity ); + /** Adds an entity reference representing the given entity to the end of this collection. + * + * @param entity The entity whose entity reference is to be added to this collection. + * @return true if the entity reference has been added, false otherwise. + */ boolean add( T entity ); + /** + * Removes the given entity from this {@code ManyAssociation}. + * <p> + * The entity reference representing the given entity is removed from this collection. + * </p> + * @param entity The entity reference to be removed. + * @return true if an entity reference was removed, otherwise false + */ boolean remove( T entity ); - T get( int i ); + /** Fetch the entity refrence at the given index and fetch the entity from the entity store. + * + * @param index The index location in the collection of the entity reference to be fetched. + * @return The retrieved entity that the entity reference of this collection represents. + */ + T get( int index ); + /** + * Returns the number of references in this association. + * @return the number of references in this association. + */ + int count(); + + /** + * Fetches all entities represented by entity references in this collection and returns a List of such + * entities. + * <p> + * Multiple references to the same entity will be present multiple times in the List, unlike {@link #toSet()}. + * The order in which the entities were added to this collection is preserved. + * </p> + * @return a List of entities represented by the entity references in this collection. + */ List<T> toList(); + /** + * Fetches all entities represented by entity references in this collection and returns a Set of such + * entities. + * <p> + * Multiple references to the same entity will NOT be present, unlike {@link #toList()}. Sets are defined + * to only contain any particular object once. Order is not preserved. + * </p> + * @return a Set of entities represented by the entity references in this collection. + */ Set<T> toSet(); /** http://git-wip-us.apache.org/repos/asf/polygene-java/blob/9ee911b0/core/api/src/main/java/org/apache/polygene/api/unitofwork/ToEntityConverter.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/polygene/api/unitofwork/ToEntityConverter.java b/core/api/src/main/java/org/apache/polygene/api/unitofwork/ToEntityConverter.java new file mode 100644 index 0000000..dfa1195 --- /dev/null +++ b/core/api/src/main/java/org/apache/polygene/api/unitofwork/ToEntityConverter.java @@ -0,0 +1,94 @@ +/* + * 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.api.unitofwork; + +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Stream; +import org.apache.polygene.api.association.AssociationDescriptor; +import org.apache.polygene.api.entity.EntityReference; +import org.apache.polygene.api.identity.HasIdentity; +import org.apache.polygene.api.property.PropertyDescriptor; +import org.apache.polygene.api.usecase.Usecase; + +/** + * MetaInfo holder for value-to-entity conversion in {@link UnitOfWork#toEntity(Class, HasIdentity)}. + * <p> + * The implementation of this interface should be registered as metaInfo on the {@link Usecase} + * of the {@link UnitOfWork} where the conversion should take place. It is also possible to register + * the implementation to the {@link UnitOfWork}'s metaInfo. + * </p> + * <p>Example;</p> + * <code><pre> + * + * private static final Usecase USECASE_GET_USER_DETAILS = UseCaseBuilder + * .buildUseCase("get user details") + * .withMetaInfo( new UserToEntityConverter() ) + * .newUsecase(); + * + * @Structure + * private UnitOfWorkFactory uowf; + * : + * : + * try( UnitOfWork uow = uowf.newUnitOfWork( USECASE_GET_USER_DETAILS ) ) + * { + * : + * User value = ...; + * User entity = uow.toEntity( User.class, value ); + * : + * } + * : + * : + * </pre></code> + */ +public interface ToEntityConverter +{ + /** + * Returns the Function to convert each of the properties of the entities into the value. + * + * @param entityComposite the entity that is to be converted. + * @return The function to do the conversion, or null if the default converter should be used. + */ + Function<PropertyDescriptor, Object> properties( Object entityComposite ); + + /** + * Returns the Function to convert each of the associations of the entities into the value. + * + * @param entityComposite the entity that is to be converted. + * @return The function to do the conversion, or null if the default converter should be used. + */ + Function<AssociationDescriptor, EntityReference> associations( Object entityComposite ); + + /** + * Returns the Function to convert each of the manyAssociations of the entities into the value. + * + * @param entityComposite the entity that is to be converted. + * @return The function to do the conversion, or null if the default converter should be used. + */ + Function<AssociationDescriptor, Stream<EntityReference>> manyAssociations( Object entityComposite ); + + /** + * Returns the Function to convert each of the NamedAssociations of the entities into the value. + * + * @param entityComposite the entity that is to be converted. + * @return The function to do the conversion, or null if the default converter should be used. + */ + Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> namedAssociations( Object entityComposite ); +} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/9ee911b0/core/api/src/main/java/org/apache/polygene/api/unitofwork/ToValueConverter.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/polygene/api/unitofwork/ToValueConverter.java b/core/api/src/main/java/org/apache/polygene/api/unitofwork/ToValueConverter.java new file mode 100644 index 0000000..519a4c5 --- /dev/null +++ b/core/api/src/main/java/org/apache/polygene/api/unitofwork/ToValueConverter.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.api.unitofwork; + +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Stream; +import org.apache.polygene.api.association.AssociationDescriptor; +import org.apache.polygene.api.entity.EntityReference; +import org.apache.polygene.api.property.PropertyDescriptor; +import org.apache.polygene.api.identity.HasIdentity; +import org.apache.polygene.api.usecase.Usecase; + +/** + * MetaInfo holder for entity-to-value conversion in {@link UnitOfWork#toValue(Class, HasIdentity)} + * <p> + * The implementation of this interface should be registered as metaInfo on the {@link Usecase} + * of the {@link UnitOfWork} where the conversion should take place. + * </p> + * <code><pre> + * + * private static final Usecase USECASE_GET_USER_DETAILS = UseCaseBuilder + * .buildUseCase("get user details") + * .withMetaInfo( new MyToValueConverter() ) + * .newUsecase(); + * + * @Structure + * private UnitOfWorkFactory uowf; + * : + * : + * try( UnitOfWork uow = uowf.newUnitOfWork( USECASE_GET_USER_DETAILS ) ) + * { + * : + * User entity = ...; + * User value = uow.toValue( User.class, value ); + * : + * } + * : + * : + * </pre></code> + */ +public interface ToValueConverter +{ + /** + * Returns the Function to convert each of the properties of the entities into the value. + * + * @param entityComposite the entity that is to be converted. + * @return The function to do the conversion, or null if the default converter should be used. + */ + Function<PropertyDescriptor, Object> properties( Object entityComposite ); + + /** + * Returns the Function to convert each of the associations of the entities into the value. + * + * @param entityComposite the entity that is to be converted. + * @return The function to do the conversion, or null if the default converter should be used. + */ + Function<AssociationDescriptor, EntityReference> associations( Object entityComposite ); + + /** + * Returns the Function to convert each of the manyAssociations of the entities into the value. + * + * @param entityComposite the entity that is to be converted. + * @return The function to do the conversion, or null if the default converter should be used. + */ + Function<AssociationDescriptor, Stream<EntityReference>> manyAssociations( Object entityComposite ); + + /** + * Returns the Function to convert each of the NamedAssociations of the entities into the value. + * + * @param entityComposite the entity that is to be converted. + * @return The function to do the conversion, or null if the default converter should be used. + */ + Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> namedAssociations( Object entityComposite ); +} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/9ee911b0/core/api/src/main/java/org/apache/polygene/api/unitofwork/UnitOfWork.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/polygene/api/unitofwork/UnitOfWork.java b/core/api/src/main/java/org/apache/polygene/api/unitofwork/UnitOfWork.java index 974f8eb..86eec45 100644 --- a/core/api/src/main/java/org/apache/polygene/api/unitofwork/UnitOfWork.java +++ b/core/api/src/main/java/org/apache/polygene/api/unitofwork/UnitOfWork.java @@ -23,6 +23,7 @@ import java.time.Instant; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.BiFunction; import java.util.function.Function; import java.util.stream.Stream; import org.apache.polygene.api.association.AssociationDescriptor; @@ -32,8 +33,8 @@ import org.apache.polygene.api.common.Optional; import org.apache.polygene.api.composite.AmbiguousTypeException; import org.apache.polygene.api.entity.EntityBuilder; import org.apache.polygene.api.entity.EntityReference; -import org.apache.polygene.api.identity.HasIdentity; import org.apache.polygene.api.entity.LifecycleException; +import org.apache.polygene.api.identity.HasIdentity; import org.apache.polygene.api.identity.Identity; import org.apache.polygene.api.property.PropertyDescriptor; import org.apache.polygene.api.query.Query; @@ -41,6 +42,7 @@ import org.apache.polygene.api.query.QueryBuilder; import org.apache.polygene.api.structure.MetaInfoHolder; import org.apache.polygene.api.structure.ModuleDescriptor; import org.apache.polygene.api.usecase.Usecase; +import org.apache.polygene.api.value.ValueBuilder; /** * All operations on entities goes through an UnitOfWork. @@ -95,7 +97,7 @@ import org.apache.polygene.api.usecase.Usecase; * } * </pre> * <p> - * It has the very same effect than the template above but is shorter.</p> + * It has the very same effect as the template above but is shorter.</p> */ public interface UnitOfWork extends MetaInfoHolder, AutoCloseable { @@ -107,6 +109,13 @@ public interface UnitOfWork extends MetaInfoHolder, AutoCloseable */ UnitOfWorkFactory unitOfWorkFactory(); + /** + * Current Time is a relative concept in systems capable of event sourcing and other + * history-capable systems. Current time is always expected to be read from here, and + * history-capable systems will set the current time for each {@link UnitOfWorkFactory#newUnitOfWork(Instant)} + * + * @return the current time, either actual real time or historical time being part of some playback. + */ Instant currentTime(); /** @@ -116,12 +125,27 @@ public interface UnitOfWork extends MetaInfoHolder, AutoCloseable */ Usecase usecase(); + /** + * Sets an arbitrary metaInfo object on this {@code UnitOfWork} which can be used for application-specific + * information. + * <p> + * The metaInfo object is retrieved by the {@link UnitOfWork#metaInfo(Class)} method on the same UnitOfWork + * instance. + * </p> + * + * @param metaInfo The metaInfo object that can be retrieved with {@link UnitOfWork#metaInfo(Class)}. + */ void setMetaInfo( Object metaInfo ); + /** + * Creates a {@link Query} from the given {@link QueryBuilder} on this {@code UnitOfWork}. + * + * @param queryBuilder The QueryBuilder holding the query specification/expression + * @param <T> The resulting type of the query. + * @return A Query against this {@code UnitOfWork} + */ <T> Query<T> newQuery( QueryBuilder<T> queryBuilder ); -// DataSet newDataSetBuilder(Specification<?>... constraints); - /** * Create a new Entity which implements the given mixin type. * <p> @@ -136,9 +160,7 @@ public interface UnitOfWork extends MetaInfoHolder, AutoCloseable * * @param <T> Entity type * @param type the mixin type that the EntityComposite must implement - * * @return a new Entity - * * @throws NoSuchEntityTypeException if no EntityComposite type of the given mixin type has been registered * @throws AmbiguousTypeException If several mixins implement the given type * @throws LifecycleException if the entity cannot be created @@ -155,9 +177,7 @@ public interface UnitOfWork extends MetaInfoHolder, AutoCloseable * @param <T> Entity type * @param type the mixin type that the EntityComposite must implement * @param identity the reference of the new Entity - * * @return a new Entity - * * @throws NoSuchEntityTypeException if no EntityComposite type of the given mixin type has been registered * @throws AmbiguousTypeException If several mixins implement the given type * @throws LifecycleException if the entity cannot be created @@ -173,9 +193,7 @@ public interface UnitOfWork extends MetaInfoHolder, AutoCloseable * * @param <T> Entity type * @param type the mixin type that the EntityComposite must implement - * * @return a new EntityBuilder - * * @throws NoSuchEntityTypeException if no EntityComposite type of the given mixin type has been registered * @throws AmbiguousTypeException If several mixins implement the given type */ @@ -191,9 +209,7 @@ public interface UnitOfWork extends MetaInfoHolder, AutoCloseable * @param <T> Entity type * @param type the mixin type that the EntityComposite must implement * @param identity the reference of the new Entity - * * @return a new EntityBuilder - * * @throws NoSuchEntityTypeException if no EntityComposite type of the given mixin type has been registered * @throws AmbiguousTypeException If several mixins implement the given type */ @@ -213,9 +229,7 @@ public interface UnitOfWork extends MetaInfoHolder, AutoCloseable * @param associationFunction a function providing the state of associations * @param manyAssociationFunction a function providing the state of many associations * @param namedAssociationFunction a function providing the state of named associations - * * @return a new EntityBuilder starting with the given state - * * @throws NoSuchEntityTypeException if no EntityComposite type of the given mixin type has been registered * @throws AmbiguousTypeException If several mixins implement the given type */ @@ -224,7 +238,7 @@ public interface UnitOfWork extends MetaInfoHolder, AutoCloseable Function<AssociationDescriptor, EntityReference> associationFunction, Function<AssociationDescriptor, Stream<EntityReference>> manyAssociationFunction, Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> namedAssociationFunction - ) + ) throws NoSuchEntityTypeException, AmbiguousTypeException; /** @@ -241,9 +255,7 @@ public interface UnitOfWork extends MetaInfoHolder, AutoCloseable * @param associationFunction a function providing the state of associations * @param manyAssociationFunction a function providing the state of many associations * @param namedAssociationFunction a function providing the state of named associations - * * @return a new EntityBuilder starting with the given state - * * @throws NoSuchEntityTypeException If no mixins implements the given type * @throws AmbiguousTypeException If several mixins implement the given type */ @@ -252,7 +264,7 @@ public interface UnitOfWork extends MetaInfoHolder, AutoCloseable Function<AssociationDescriptor, EntityReference> associationFunction, Function<AssociationDescriptor, Stream<EntityReference>> manyAssociationFunction, Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> namedAssociationFunction - ) + ) throws NoSuchEntityTypeException, AmbiguousTypeException; /** @@ -262,9 +274,7 @@ public interface UnitOfWork extends MetaInfoHolder, AutoCloseable * @param <T> Entity type * @param type of the entity * @param identity of the entity - * * @return the entity - * * @throws NoSuchEntityTypeException if no entity type could be found * @throws NoSuchEntityException if the entity could not be found */ @@ -278,9 +288,7 @@ public interface UnitOfWork extends MetaInfoHolder, AutoCloseable * * @param <T> Entity type * @param entity the Entity to be dereferenced - * * @return an Entity from this UnitOfWork - * * @throws NoSuchEntityTypeException if no entity type could be found */ <T> T get( T entity ) @@ -290,7 +298,6 @@ public interface UnitOfWork extends MetaInfoHolder, AutoCloseable * Remove the given Entity. * * @param entity the Entity to be removed. - * * @throws LifecycleException if the entity could not be removed */ void remove( Object entity ) @@ -403,21 +410,18 @@ public interface UnitOfWork extends MetaInfoHolder, AutoCloseable * @param primaryType The shared type for which the properties and associations will * be converted. Properties outside this type will be ignored. * @param entityComposite The entity to be convered. - * * @return The Value */ - <T extends HasIdentity> T toValue(Class<T> primaryType, T entityComposite ); + <T extends HasIdentity> T toValue( Class<T> primaryType, T entityComposite ); /** * Converts all the entities referenced in the ManyAssociation into a List of values of the same type. - * * <p> * All the referenced entities inside the association will be fetched from the underlying entity store, * which is potentially very expensive operation. Each of the fetched entities will be passed to * {@link #toValue(Class, HasIdentity)}, and its associations will NOT be converted into values, but remain * {@link EntityReference} values. Hence there is no problem with circular references. * </p> - * * <p> * For this to work, the type <T> must be registered at bootstrap as both an Entity and a Value, and * as seen in the method signature, also be sub-type of {@link HasIdentity}. @@ -425,16 +429,13 @@ public interface UnitOfWork extends MetaInfoHolder, AutoCloseable * * @param association The association of entities to be converted into values. * @param <T> The primary type of the association. - * * @return A List of ValueComposites that has been converted from EntityComposites referenced by the Associations. - * * @see #toValue(Class, HasIdentity) */ - <T extends HasIdentity> List<T> toValueList(ManyAssociation<T> association ); + <T extends HasIdentity> List<T> toValueList( ManyAssociation<T> association ); /** * Converts all the entities referenced in the ManyAssociation into a Set of values of the same type. - * * <p> * All the referenced entities inside the association will be fetched from the underlying entity store, * which is potentially very expensive operation. However, any duplicate EntityReferences in the association @@ -442,7 +443,6 @@ public interface UnitOfWork extends MetaInfoHolder, AutoCloseable * {@link #toValue(Class, HasIdentity)}, and its associations will NOT be converted into values, but remain * {@link EntityReference} values. Hence there is no problem with circular references. * </p> - * * <p> * For this to work, the type <T> must be registered at bootstrap as both an Entity and a Value, and * as seen in the method signature, also be sub-type of {@link HasIdentity}. @@ -450,16 +450,13 @@ public interface UnitOfWork extends MetaInfoHolder, AutoCloseable * * @param association The association of entities to be converted into values. * @param <T> The primary type of the association. - * * @return A List of ValueComposites that has been converted from EntityComposites referenced by the Associations. - * * @see #toValue(Class, HasIdentity) */ - <T extends HasIdentity> Set<T> toValueSet(ManyAssociation<T> association ); + <T extends HasIdentity> Set<T> toValueSet( ManyAssociation<T> association ); /** * Converts the {@link NamedAssociation} into a Map with a String key and a ValueComposite as the value. - * * <p> * A {@link NamedAssociation} is effectively a Map with a String key and an EntityReference as the value. The * EntityReference is fetched from the entity store and converted into a value of the same type.Each of the fetched @@ -473,12 +470,10 @@ public interface UnitOfWork extends MetaInfoHolder, AutoCloseable * * @param association The association of entities to be converted into values. * @param <T> The primary type of the association. - * * @return A List of ValueComposites that has been converted from EntityComposites referenced by the Associations. - * * @see #toValue(Class, HasIdentity) */ - <T extends HasIdentity> Map<String, T> toValueMap(NamedAssociation<T> association ); + <T extends HasIdentity> Map<String, T> toValueMap( NamedAssociation<T> association ); /** * Converts the provided Value to an Entity of the same type. @@ -519,10 +514,9 @@ public interface UnitOfWork extends MetaInfoHolder, AutoCloseable * @param primaryType The shared type for which the properties and associations will * be converted. Properties outside this type will be ignored. * @param valueComposite The Value to be convered into an Entity. - * * @return The new or updated Entity */ - <T extends HasIdentity> T toEntity(Class<T> primaryType, T valueComposite ); + <T extends HasIdentity> T toEntity( Class<T> primaryType, T valueComposite ); /** * The Module of the UnitOfWork is defined as the Module the UnitOfWorkFactory belonged to from where the http://git-wip-us.apache.org/repos/asf/polygene-java/blob/9ee911b0/core/api/src/main/java/org/apache/polygene/api/unitofwork/concern/UnitOfWorkConcern.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/polygene/api/unitofwork/concern/UnitOfWorkConcern.java b/core/api/src/main/java/org/apache/polygene/api/unitofwork/concern/UnitOfWorkConcern.java index f982c45..b07cb46 100644 --- a/core/api/src/main/java/org/apache/polygene/api/unitofwork/concern/UnitOfWorkConcern.java +++ b/core/api/src/main/java/org/apache/polygene/api/unitofwork/concern/UnitOfWorkConcern.java @@ -22,14 +22,17 @@ package org.apache.polygene.api.unitofwork.concern; import java.lang.reflect.Method; import java.lang.reflect.UndeclaredThrowableException; import org.apache.polygene.api.common.AppliesTo; +import org.apache.polygene.api.common.Optional; import org.apache.polygene.api.concern.GenericConcern; import org.apache.polygene.api.injection.scope.Invocation; +import org.apache.polygene.api.injection.scope.Service; import org.apache.polygene.api.injection.scope.Structure; import org.apache.polygene.api.unitofwork.ConcurrentEntityModificationException; import org.apache.polygene.api.unitofwork.UnitOfWork; import org.apache.polygene.api.unitofwork.UnitOfWorkFactory; import org.apache.polygene.api.usecase.Usecase; import org.apache.polygene.api.usecase.UsecaseBuilder; +import org.apache.polygene.api.usecase.UsecaseFactory; /** * {@code UnitOfWorkConcern} manages the unit of work complete, discard and retry policy. @@ -49,15 +52,17 @@ public class UnitOfWorkConcern @Invocation private UnitOfWorkPropagation propagation; + @Optional + @Service + private UsecaseFactory usecaseFactory; + /** * Handles method with {@code UnitOfWorkPropagation} annotation. * * @param proxy The object. * @param method The invoked method. * @param args The method arguments. - * * @return The returned value of method invocation. - * * @throws Throwable Thrown if the method invocation throw exception. */ @Override @@ -98,13 +103,20 @@ public class UnitOfWorkConcern { String usecaseName = propagation.usecase(); Usecase usecase; - if( usecaseName == null ) + if( usecaseFactory == null ) { - usecase = Usecase.DEFAULT; + if( usecaseName.length() == 0 ) + { + usecase = Usecase.DEFAULT; + } + else + { + usecase = UsecaseBuilder.newUsecase( usecaseName ); + } } else { - usecase = UsecaseBuilder.newUsecase( usecaseName ); + usecase = usecaseFactory.createUsecase( usecaseName ); } return usecase; } @@ -168,7 +180,7 @@ public class UnitOfWorkConcern long initialDelay, int retry, ConcurrentEntityModificationException e - ) + ) throws ConcurrentEntityModificationException, InterruptedException { if( retry >= maxTries ) http://git-wip-us.apache.org/repos/asf/polygene-java/blob/9ee911b0/core/api/src/main/java/org/apache/polygene/api/usecase/UsecaseFactory.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/polygene/api/usecase/UsecaseFactory.java b/core/api/src/main/java/org/apache/polygene/api/usecase/UsecaseFactory.java new file mode 100644 index 0000000..b26129e --- /dev/null +++ b/core/api/src/main/java/org/apache/polygene/api/usecase/UsecaseFactory.java @@ -0,0 +1,34 @@ +/* + * 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.api.usecase; + +import org.apache.polygene.api.unitofwork.UnitOfWork; +import org.apache.polygene.api.unitofwork.concern.UnitOfWorkConcern; +import org.apache.polygene.api.unitofwork.concern.UnitOfWorkPropagation; +import org.apache.polygene.api.usecase.Usecase; + +/** An optional service that if implemented and available to the {@link UnitOfWorkConcern} + * will use to create the named {@link Usecase} of the {@link UnitOfWorkPropagation} annotation. + * + */ +public interface UsecaseFactory +{ + Usecase createUsecase( String name ); +} http://git-wip-us.apache.org/repos/asf/polygene-java/blob/9ee911b0/core/api/src/main/java/org/apache/polygene/api/value/ValueBuilder.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/polygene/api/value/ValueBuilder.java b/core/api/src/main/java/org/apache/polygene/api/value/ValueBuilder.java index 2698305..09105aa 100644 --- a/core/api/src/main/java/org/apache/polygene/api/value/ValueBuilder.java +++ b/core/api/src/main/java/org/apache/polygene/api/value/ValueBuilder.java @@ -62,4 +62,10 @@ public interface ValueBuilder<T> */ T newInstance() throws ConstructionException; + + /** Returns the primaryType that this builder is configured to build. + * + * @return the primaryType to be built. + */ + Class<T> primaryType(); } http://git-wip-us.apache.org/repos/asf/polygene-java/blob/9ee911b0/core/runtime/src/main/java/org/apache/polygene/runtime/bootstrap/ApplicationModelFactoryImpl.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/bootstrap/ApplicationModelFactoryImpl.java b/core/runtime/src/main/java/org/apache/polygene/runtime/bootstrap/ApplicationModelFactoryImpl.java index a39c521..5d3b000 100644 --- a/core/runtime/src/main/java/org/apache/polygene/runtime/bootstrap/ApplicationModelFactoryImpl.java +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/bootstrap/ApplicationModelFactoryImpl.java @@ -186,7 +186,6 @@ public final class ApplicationModelFactoryImpl { layer = (LayerModel) visited; } - return true; } http://git-wip-us.apache.org/repos/asf/polygene-java/blob/9ee911b0/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/ModuleUnitOfWork.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/ModuleUnitOfWork.java b/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/ModuleUnitOfWork.java index 542cc0a..04508e9 100644 --- a/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/ModuleUnitOfWork.java +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/unitofwork/ModuleUnitOfWork.java @@ -60,6 +60,8 @@ import org.apache.polygene.api.structure.ModuleDescriptor; import org.apache.polygene.api.unitofwork.ConcurrentEntityModificationException; import org.apache.polygene.api.unitofwork.NoSuchEntityException; import org.apache.polygene.api.unitofwork.NoSuchEntityTypeException; +import org.apache.polygene.api.unitofwork.ToEntityConverter; +import org.apache.polygene.api.unitofwork.ToValueConverter; import org.apache.polygene.api.unitofwork.UnitOfWork; import org.apache.polygene.api.unitofwork.UnitOfWorkCallback; import org.apache.polygene.api.unitofwork.UnitOfWorkCompletionException; @@ -213,7 +215,7 @@ public class ModuleUnitOfWork Function<AssociationDescriptor, EntityReference> associationFunction, Function<AssociationDescriptor, Stream<EntityReference>> manyAssociationFunction, Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> namedAssociationFunction - ) + ) throws NoSuchEntityTypeException { return newEntityBuilderWithState( type, null, @@ -230,7 +232,7 @@ public class ModuleUnitOfWork Function<AssociationDescriptor, EntityReference> associationFunction, Function<AssociationDescriptor, Stream<EntityReference>> manyAssociationFunction, Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> namedAssociationFunction - ) + ) throws NoSuchEntityTypeException { Objects.requireNonNull( propertyFunction, "propertyFunction" ); @@ -259,7 +261,7 @@ public class ModuleUnitOfWork PropertyModel identityModel = (PropertyModel) model .state() .findPropertyModelByQualifiedName( IDENTITY_STATE_NAME ); - String propertyState = (String) stateResolver.getPropertyState(identityModel); + String propertyState = (String) stateResolver.getPropertyState( identityModel ); if( propertyState == null ) { // Generate reference @@ -273,7 +275,7 @@ public class ModuleUnitOfWork } else { - identity = new StringIdentity(propertyState); + identity = new StringIdentity( propertyState ); } } @@ -426,13 +428,38 @@ public class ModuleUnitOfWork } @Override - public <T extends HasIdentity> T toValue(Class<T> primaryType, T entityComposite ) + public <T extends HasIdentity> T toValue( Class<T> primaryType, T entityComposite ) { - Function<PropertyDescriptor, Object> propertyFunction = new ToValuePropertyMappingFunction( entityComposite ); - Function<AssociationDescriptor, EntityReference> assocationFunction = new ToValueAssociationMappingFunction<>( entityComposite ); - Function<AssociationDescriptor, Stream<EntityReference>> manyAssocFunction = new ToValueManyAssociationMappingFunction<>( entityComposite ); - Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> namedAssocFunction = new ToValueNameAssociationMappingFunction<>( entityComposite ); - + Objects.requireNonNull( primaryType ); + Objects.requireNonNull( entityComposite ); + Function<PropertyDescriptor, Object> propertyFunction = null; + Function<AssociationDescriptor, EntityReference> assocationFunction = null; + Function<AssociationDescriptor, Stream<EntityReference>> manyAssocFunction = null; + Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> namedAssocFunction = null; + ToValueConverter converter = getConverter( ToValueConverter.class ); + if( converter != null ) + { + propertyFunction = converter.properties( entityComposite ); + manyAssocFunction = converter.manyAssociations( entityComposite ); + assocationFunction = converter.associations( entityComposite ); + namedAssocFunction = converter.namedAssociations( entityComposite ); + } + if( propertyFunction == null ) + { + propertyFunction = new ToValuePropertyMappingFunction( entityComposite ); + } + if( assocationFunction == null ) + { + assocationFunction = new ToValueAssociationMappingFunction<>( entityComposite ); + } + if( manyAssocFunction == null ) + { + manyAssocFunction = new ToValueManyAssociationMappingFunction<>( entityComposite ); + } + if( namedAssocFunction == null ) + { + namedAssocFunction = new ToValueNameAssociationMappingFunction<>( entityComposite ); + } @SuppressWarnings( "unchecked" ) ValueBuilder<T> builder = module().instance().newValueBuilderWithState( primaryType, propertyFunction, assocationFunction, manyAssocFunction, namedAssocFunction ); @@ -440,7 +467,7 @@ public class ModuleUnitOfWork } @Override - public <T extends HasIdentity> Map<String, T> toValueMap(NamedAssociation<T> association ) + public <T extends HasIdentity> Map<String, T> toValueMap( NamedAssociation<T> association ) { @SuppressWarnings( "unchecked" ) Class<T> primaryType = (Class<T>) api.associationDescriptorFor( association ).type(); @@ -449,11 +476,11 @@ public class ModuleUnitOfWork .toMap() .entrySet() .stream() - .collect( Collectors.toMap( Map.Entry::getKey, entry -> toValue( primaryType, entry.getValue()) ) ); + .collect( Collectors.toMap( Map.Entry::getKey, entry -> toValue( primaryType, entry.getValue() ) ) ); } @Override - public <T extends HasIdentity> List<T> toValueList(ManyAssociation<T> association ) + public <T extends HasIdentity> List<T> toValueList( ManyAssociation<T> association ) { @SuppressWarnings( "unchecked" ) Class<T> primaryType = (Class<T>) api.associationDescriptorFor( association ).type(); @@ -466,7 +493,7 @@ public class ModuleUnitOfWork } @Override - public <T extends HasIdentity> Set<T> toValueSet(ManyAssociation<T> association ) + public <T extends HasIdentity> Set<T> toValueSet( ManyAssociation<T> association ) { @SuppressWarnings( "unchecked" ) Class<T> primaryType = (Class<T>) api.associationDescriptorFor( association ).type(); @@ -479,12 +506,37 @@ public class ModuleUnitOfWork } @Override - public <T extends HasIdentity> T toEntity(Class<T> primaryType, T valueComposite ) + public <T extends HasIdentity> T toEntity( Class<T> primaryType, T valueComposite ) { - Function<PropertyDescriptor, Object> propertyFunction = new ToEntityPropertyMappingFunction<>( valueComposite ); - Function<AssociationDescriptor, EntityReference> assocationFunction = new ToEntityAssociationMappingFunction<>( valueComposite ); - Function<AssociationDescriptor, Stream<EntityReference>> manyAssocFunction = new ToEntityManyAssociationMappingFunction<>( valueComposite ); - Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> namedAssocFunction = new ToEntityNameAssociationMappingFunction<>( valueComposite ); + + Function<PropertyDescriptor, Object> propertyFunction = null; + Function<AssociationDescriptor, EntityReference> assocationFunction = null; + Function<AssociationDescriptor, Stream<EntityReference>> manyAssocFunction = null; + Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> namedAssocFunction = null; + ToEntityConverter converter = getConverter( ToEntityConverter.class ); + if( converter != null ) + { + propertyFunction = converter.properties( valueComposite ); + manyAssocFunction = converter.manyAssociations( valueComposite ); + assocationFunction = converter.associations( valueComposite ); + namedAssocFunction = converter.namedAssociations( valueComposite ); + } + if( propertyFunction == null ) + { + propertyFunction = new ToEntityPropertyMappingFunction<>( valueComposite ); + } + if( assocationFunction == null ) + { + assocationFunction = new ToEntityAssociationMappingFunction<>( valueComposite ); + } + if( manyAssocFunction == null ) + { + manyAssocFunction = new ToEntityManyAssociationMappingFunction<>( valueComposite ); + } + if( namedAssocFunction == null ) + { + namedAssocFunction = new ToEntityNameAssociationMappingFunction<>( valueComposite ); + } try { @@ -512,6 +564,21 @@ public class ModuleUnitOfWork } } + private <T> T getConverter( Class<T> converterType ) + { + T converter = null; + Usecase usecase = usecase(); + if( usecase != null ) + { + converter = usecase.metaInfo( converterType ); + } + if( converter == null ) + { + converter = metaInfo( converterType ); + } + return converter; + } + private static class UoWQuerySource implements QuerySource { private final ModuleUnitOfWork moduleUnitOfWork; @@ -528,12 +595,12 @@ public class ModuleUnitOfWork Integer firstResult, Integer maxResults, Map<String, Object> variables - ) + ) { final EntityFinder entityFinder = moduleUnitOfWork.module() - .instance() - .findService( EntityFinder.class ) - .get(); + .instance() + .findService( EntityFinder.class ) + .get(); try { @@ -565,7 +632,7 @@ public class ModuleUnitOfWork Integer firstResult, Integer maxResults, Map<String, Object> variables - ) + ) { EntityFinder entityFinder = moduleUnitOfWork.module().instance().findService( EntityFinder.class ).get(); @@ -599,18 +666,18 @@ public class ModuleUnitOfWork firstResult, maxResults, variables == null ? Collections.emptyMap() : variables - ).map( ref -> - { - try - { - return moduleUnitOfWork.get( resultType, ref.identity() ); - } - catch( NoSuchEntityException e ) - { - // Index is out of sync - entity has been removed - return null; - } - } ); + ).map( ref -> + { + try + { + return moduleUnitOfWork.get( resultType, ref.identity() ); + } + catch( NoSuchEntityException e ) + { + // Index is out of sync - entity has been removed + return null; + } + } ); } catch( EntityFinderException e ) { http://git-wip-us.apache.org/repos/asf/polygene-java/blob/9ee911b0/core/runtime/src/main/java/org/apache/polygene/runtime/value/ValueBuilderInstance.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/value/ValueBuilderInstance.java b/core/runtime/src/main/java/org/apache/polygene/runtime/value/ValueBuilderInstance.java index 248b97d..91f975d 100644 --- a/core/runtime/src/main/java/org/apache/polygene/runtime/value/ValueBuilderInstance.java +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/value/ValueBuilderInstance.java @@ -57,6 +57,13 @@ public final class ValueBuilderInstance<T> } @Override + @SuppressWarnings( "unchecked" ) + public Class<T> primaryType() + { + return (Class<T>) prototypeInstance.descriptor().primaryType(); + } + + @Override public AssociationStateHolder state() { return prototypeInstance.state(); http://git-wip-us.apache.org/repos/asf/polygene-java/blob/9ee911b0/core/runtime/src/main/java/org/apache/polygene/runtime/value/ValueBuilderWithPrototype.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/value/ValueBuilderWithPrototype.java b/core/runtime/src/main/java/org/apache/polygene/runtime/value/ValueBuilderWithPrototype.java index 9a786a3..78815f6 100644 --- a/core/runtime/src/main/java/org/apache/polygene/runtime/value/ValueBuilderWithPrototype.java +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/value/ValueBuilderWithPrototype.java @@ -88,6 +88,13 @@ public class ValueBuilderWithPrototype<T> } @Override + @SuppressWarnings( "unchecked" ) + public Class<T> primaryType() + { + return (Class<T>) valueModel.primaryType(); + } + + @Override public AssociationStateHolder state() { verifyUnderConstruction(); http://git-wip-us.apache.org/repos/asf/polygene-java/blob/9ee911b0/core/runtime/src/main/java/org/apache/polygene/runtime/value/ValueBuilderWithState.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/value/ValueBuilderWithState.java b/core/runtime/src/main/java/org/apache/polygene/runtime/value/ValueBuilderWithState.java index e371b04..c49d809 100644 --- a/core/runtime/src/main/java/org/apache/polygene/runtime/value/ValueBuilderWithState.java +++ b/core/runtime/src/main/java/org/apache/polygene/runtime/value/ValueBuilderWithState.java @@ -26,7 +26,8 @@ import org.apache.polygene.api.value.ValueDescriptor; import org.apache.polygene.runtime.composite.StateResolver; import org.apache.polygene.runtime.structure.ModuleInstance; -public class ValueBuilderWithState<T> implements ValueBuilder<T> +public class ValueBuilderWithState<T> + implements ValueBuilder<T> { private final ValueDescriptor model; private ValueInstance prototypeInstance; @@ -50,6 +51,13 @@ public class ValueBuilderWithState<T> implements ValueBuilder<T> } @Override + @SuppressWarnings( "unchecked" ) + public Class<T> primaryType() + { + return (Class<T>) model.primaryType(); + } + + @Override public AssociationStateHolder state() { verifyUnderConstruction(); http://git-wip-us.apache.org/repos/asf/polygene-java/blob/9ee911b0/libraries/rdf/src/main/java/org/apache/polygene/library/rdf/model/Model2XML.java ---------------------------------------------------------------------- diff --git a/libraries/rdf/src/main/java/org/apache/polygene/library/rdf/model/Model2XML.java b/libraries/rdf/src/main/java/org/apache/polygene/library/rdf/model/Model2XML.java index 168a35b..7fa79c5 100644 --- a/libraries/rdf/src/main/java/org/apache/polygene/library/rdf/model/Model2XML.java +++ b/libraries/rdf/src/main/java/org/apache/polygene/library/rdf/model/Model2XML.java @@ -62,7 +62,7 @@ public class Model2XML } @Override - public Document apply( ApplicationDescriptor Application ) + public Document apply( ApplicationDescriptor application ) { try { @@ -72,7 +72,7 @@ public class Model2XML final Stack<Node> current = new Stack<Node>(); current.push( document ); - Application.accept( new HierarchicalVisitor<Object, Object, DOMException>() + application.accept( new HierarchicalVisitor<Object, Object, DOMException>() { @Override public boolean visitEnter( Object visited )
