From 4982ab9e10399e6724662dd29c547c2176cfe0b1 Mon Sep 17 00:00:00 2001 From: Moritz Becker Date: Tue, 21 Nov 2017 06:44:06 +0100 Subject: [PATCH] #328 deltaspike-data integration --- README.md | 26 +- .../manual/en_US/02_getting_started.adoc | 8 +- .../manual/en_US/11_spring_data.adoc | 12 +- .../manual/en_US/12_deltaspike_data.adoc | 69 ++++ .../{12_metamodel.adoc => 13_metamodel.adoc} | 0 ...nfiguration.adoc => 14_configuration.adoc} | 0 .../entity-view/manual/en_US/index.adoc | 6 +- examples/cdi-showcase/pom.xml | 27 +- .../examples/cdi/CDIShowcaseRunner.java | 7 +- .../springdata/SpringDataShowcaseConfig.java | 2 +- .../springdata/repository/CatRepository.java | 2 +- .../examples/spring/SpringShowcaseRunner.java | 2 +- integration/deltaspike-data/api/pom.xml | 29 ++ .../deltaspikedata/api/CriteriaSupport.java | 54 ++++ .../api/EntityViewRepository.java | 88 ++++++ .../api/FullEntityViewRepository.java | 26 ++ integration/deltaspike-data/impl/pom.xml | 106 +++++++ .../CustomPartialBeanBindingExtension.java | 120 +++++++ .../impl/DeltaspikeExtensionDeactivator.java | 33 ++ .../impl/EntityViewRepositoryExtension.java | 167 ++++++++++ .../EntityViewAwareQueryBuilderFactory.java | 61 ++++ .../EntityViewDelegateQueryBuilder.java | 126 ++++++++ .../builder/EntityViewMethodQueryBuilder.java | 71 +++++ .../impl/builder/EntityViewQueryBuilder.java | 60 ++++ .../EntityViewQueryBuilderContext.java | 49 +++ .../WrappedEntityViewQueryBuilder.java | 44 +++ .../builder/part/EntityViewAndQueryPart.java | 49 +++ .../part/EntityViewBasePropertyQueryPart.java | 58 ++++ .../part/EntityViewConnectingQueryPart.java | 36 +++ .../builder/part/EntityViewOrQueryPart.java | 57 ++++ .../part/EntityViewOrderByQueryPart.java | 137 ++++++++ .../part/EntityViewPropertyQueryPart.java | 68 ++++ .../builder/part/EntityViewQueryPart.java | 44 +++ .../builder/part/EntityViewQueryRoot.java | 101 ++++++ .../impl/builder/part/QueryOperator.java | 82 +++++ .../postprocessor/FlushModePostProcessor.java | 45 +++ .../postprocessor/HintPostProcessor.java | 46 +++ .../postprocessor/LockModePostProcessor.java | 45 +++ .../OrderByCriteriaBuilderPostProcessor.java | 63 ++++ ...aginationCriteriaBuilderPostProcessor.java | 40 +++ .../result/EntityViewDefaultQueryResult.java | 295 ++++++++++++++++++ .../impl/criteria/QueryCriteria.java | 124 ++++++++ .../handler/CriteriaBuilderPostProcessor.java | 28 ++ .../impl/handler/CriteriaSupportHandler.java | 73 +++++ .../impl/handler/EntityManagerRefLookup.java | 122 ++++++++ .../handler/EntityViewAwareQueryHandler.java | 119 +++++++ .../EntityViewCdiQueryInvocationContext.java | 274 ++++++++++++++++ ...tyViewCdiQueryInvocationContextHolder.java | 60 ++++ .../impl/handler/EntityViewContext.java | 33 ++ .../EntityViewDelegateQueryHandler.java | 24 ++ .../EntityViewJpaQueryPostProcessor.java | 31 ++ .../handler/EntityViewQueryProcessor.java | 30 ++ .../EntityViewQueryProcessorFactory.java | 156 +++++++++ .../impl/handler/EntityViewQueryRunner.java | 31 ++ .../handler/EntityViewRepositoryHandler.java | 174 +++++++++++ .../TransactionalEntityViewQueryRunner.java | 97 ++++++ .../meta/EntityViewRepositoryComponent.java | 221 +++++++++++++ .../meta/EntityViewRepositoryComponents.java | 117 +++++++ ...EntityViewRepositoryComponentsFactory.java | 53 ++++ .../impl/meta/EntityViewRepositoryMethod.java | 198 ++++++++++++ .../impl/meta/RepositoryEntityView.java | 66 ++++ ...EntityViewAnnotationMetadataExtractor.java | 44 +++ .../EntityViewMetadataExtractor.java | 31 ++ .../EntityViewTypeMetadataExtractor.java | 89 ++++++ .../deltaspikedata/impl/param/Parameters.java | 181 +++++++++++ .../EntityViewInvocationContextWrapper.java | 33 ++ .../META-INF/apache-deltaspike.properties | 1 + .../src/main/resources/META-INF/beans.xml | 24 ++ integration/deltaspike-data/pom.xml | 20 ++ integration/deltaspike-data/testsuite/pom.xml | 153 +++++++++ .../testsuite/entity/Address.java | 36 +++ .../testsuite/entity/Person.java | 126 ++++++++ .../src/main/resources/META-INF/beans.xml | 24 ++ .../main/resources/META-INF/persistence.xml | 34 ++ .../AbstractEntityViewRepositoryTest.java | 142 +++++++++ .../testsuite/CriteriaSupportTest.java | 49 +++ .../ExtendedEntityViewRepositoryTest.java | 180 +++++++++++ .../FullEntityViewRepositoryTest.java | 124 ++++++++ .../testsuite/FullPersonViewRepository.java | 61 ++++ .../testsuite/PersonRepository.java | 29 ++ .../PersonViewCriteriaRepository.java | 40 +++ .../testsuite/SimplePersonViewRepository.java | 29 ++ .../producer/BlazePersistenceProducer.java | 56 ++++ .../producer/EntityManagerProducer.java | 48 +++ .../testsuite/view/ChildView.java | 34 ++ .../testsuite/view/PersonView.java | 33 ++ .../src/test/resources/META-INF/beans.xml | 24 ++ .../src/test/resources/logging.properties | 33 ++ integration/pom.xml | 1 + .../api}/repository/EntityViewRepository.java | 2 +- .../BlazePersistenceQueryLookupStrategy.java | 2 +- .../query/EntityViewAwareJpaQueryMethod.java | 2 +- .../EntityViewAwareRepositoryFactory.java | 4 +- .../EntityViewRepositoryFactoryBean.java | 2 +- .../repository/EntityViewRepositoryImpl.java | 3 +- .../EntityViewSpecificationExecutor.java | 2 +- .../query/PartTreeEntityViewQuery.java | 2 +- .../data/impl}/AbstractSpringTest.java | 2 +- .../data/impl}/DocumentRepositoryTest.java | 32 +- .../data/impl}/accessor/DocumentAccessor.java | 2 +- .../impl}/accessor/DocumentAccessors.java | 6 +- .../config/BlazePersistenceConfiguration.java | 2 +- ...emPropertyBasedActiveProfilesResolver.java | 2 +- .../data/impl}/entity/Document.java | 2 +- .../data/impl}/entity/Person.java | 2 +- .../repository/DocumentEntityRepository.java | 4 +- .../impl}/repository/DocumentRepository.java | 5 +- .../repository/DocumentViewRepository.java | 4 +- .../impl}/tx/TransactionalWorkService.java | 2 +- .../data/impl}/tx/TxVoidWork.java | 2 +- .../data/impl}/tx/TxWork.java | 2 +- .../data/impl}/view/DocumentView.java | 4 +- .../data/impl}/view/PersonView.java | 4 +- .../data/impl}/application-config.xml | 0 parent/pom.xml | 53 ++-- 115 files changed, 6117 insertions(+), 103 deletions(-) create mode 100644 documentation/src/main/asciidoc/entity-view/manual/en_US/12_deltaspike_data.adoc rename documentation/src/main/asciidoc/entity-view/manual/en_US/{12_metamodel.adoc => 13_metamodel.adoc} (100%) rename documentation/src/main/asciidoc/entity-view/manual/en_US/{13_configuration.adoc => 14_configuration.adoc} (100%) create mode 100644 integration/deltaspike-data/api/pom.xml create mode 100644 integration/deltaspike-data/api/src/main/java/com/balzebit/persistence/impl/deltaspikedata/api/CriteriaSupport.java create mode 100644 integration/deltaspike-data/api/src/main/java/com/balzebit/persistence/impl/deltaspikedata/api/EntityViewRepository.java create mode 100644 integration/deltaspike-data/api/src/main/java/com/balzebit/persistence/impl/deltaspikedata/api/FullEntityViewRepository.java create mode 100644 integration/deltaspike-data/impl/pom.xml create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/CustomPartialBeanBindingExtension.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/DeltaspikeExtensionDeactivator.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/EntityViewRepositoryExtension.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/EntityViewAwareQueryBuilderFactory.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/EntityViewDelegateQueryBuilder.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/EntityViewMethodQueryBuilder.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/EntityViewQueryBuilder.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/EntityViewQueryBuilderContext.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/WrappedEntityViewQueryBuilder.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewAndQueryPart.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewBasePropertyQueryPart.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewConnectingQueryPart.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewOrQueryPart.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewOrderByQueryPart.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewPropertyQueryPart.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewQueryPart.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewQueryRoot.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/QueryOperator.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/postprocessor/FlushModePostProcessor.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/postprocessor/HintPostProcessor.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/postprocessor/LockModePostProcessor.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/postprocessor/OrderByCriteriaBuilderPostProcessor.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/postprocessor/PaginationCriteriaBuilderPostProcessor.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/result/EntityViewDefaultQueryResult.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/criteria/QueryCriteria.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/CriteriaBuilderPostProcessor.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/CriteriaSupportHandler.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityManagerRefLookup.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewAwareQueryHandler.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewCdiQueryInvocationContext.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewCdiQueryInvocationContextHolder.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewContext.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewDelegateQueryHandler.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewJpaQueryPostProcessor.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewQueryProcessor.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewQueryProcessorFactory.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewQueryRunner.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewRepositoryHandler.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/TransactionalEntityViewQueryRunner.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/EntityViewRepositoryComponent.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/EntityViewRepositoryComponents.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/EntityViewRepositoryComponentsFactory.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/EntityViewRepositoryMethod.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/RepositoryEntityView.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/extractor/EntityViewAnnotationMetadataExtractor.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/extractor/EntityViewMetadataExtractor.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/extractor/EntityViewTypeMetadataExtractor.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/param/Parameters.java create mode 100644 integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/tx/EntityViewInvocationContextWrapper.java create mode 100644 integration/deltaspike-data/impl/src/main/resources/META-INF/apache-deltaspike.properties create mode 100644 integration/deltaspike-data/impl/src/main/resources/META-INF/beans.xml create mode 100644 integration/deltaspike-data/pom.xml create mode 100644 integration/deltaspike-data/testsuite/pom.xml create mode 100644 integration/deltaspike-data/testsuite/src/main/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/entity/Address.java create mode 100644 integration/deltaspike-data/testsuite/src/main/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/entity/Person.java create mode 100644 integration/deltaspike-data/testsuite/src/main/resources/META-INF/beans.xml create mode 100644 integration/deltaspike-data/testsuite/src/main/resources/META-INF/persistence.xml create mode 100644 integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/AbstractEntityViewRepositoryTest.java create mode 100644 integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/CriteriaSupportTest.java create mode 100644 integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/ExtendedEntityViewRepositoryTest.java create mode 100644 integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/FullEntityViewRepositoryTest.java create mode 100644 integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/FullPersonViewRepository.java create mode 100644 integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/PersonRepository.java create mode 100644 integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/PersonViewCriteriaRepository.java create mode 100644 integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/SimplePersonViewRepository.java create mode 100644 integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/producer/BlazePersistenceProducer.java create mode 100644 integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/producer/EntityManagerProducer.java create mode 100644 integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/view/ChildView.java create mode 100644 integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/view/PersonView.java create mode 100644 integration/deltaspike-data/testsuite/src/test/resources/META-INF/beans.xml create mode 100644 integration/deltaspike-data/testsuite/src/test/resources/logging.properties rename integration/spring-data/src/main/java/com/blazebit/persistence/{impl/springdata => spring/data/api}/repository/EntityViewRepository.java (94%) rename integration/spring-data/src/main/java/com/blazebit/persistence/{impl/springdata => spring/data/impl}/query/BlazePersistenceQueryLookupStrategy.java (99%) rename integration/spring-data/src/main/java/com/blazebit/persistence/{impl/springdata => spring/data/impl}/query/EntityViewAwareJpaQueryMethod.java (97%) rename integration/spring-data/src/main/java/com/blazebit/persistence/{impl/springdata => spring/data/impl}/repository/EntityViewAwareRepositoryFactory.java (96%) rename integration/spring-data/src/main/java/com/blazebit/persistence/{impl/springdata => spring/data/impl}/repository/EntityViewRepositoryFactoryBean.java (98%) rename integration/spring-data/src/main/java/com/blazebit/persistence/{impl/springdata => spring/data/impl}/repository/EntityViewRepositoryImpl.java (98%) rename integration/spring-data/src/main/java/com/blazebit/persistence/{impl/springdata => spring/data/impl}/repository/EntityViewSpecificationExecutor.java (95%) rename integration/spring-data/src/test/java/com/blazebit/persistence/{impl/springdata => spring/data/impl}/AbstractSpringTest.java (97%) rename integration/spring-data/src/test/java/com/blazebit/persistence/{impl/springdata => spring/data/impl}/DocumentRepositoryTest.java (93%) rename integration/spring-data/src/test/java/com/blazebit/persistence/{impl/springdata => spring/data/impl}/accessor/DocumentAccessor.java (93%) rename integration/spring-data/src/test/java/com/blazebit/persistence/{impl/springdata => spring/data/impl}/accessor/DocumentAccessors.java (94%) rename integration/spring-data/src/test/java/com/blazebit/persistence/{impl/springdata => spring/data/impl}/config/BlazePersistenceConfiguration.java (97%) rename integration/spring-data/src/test/java/com/blazebit/persistence/{impl/springdata => spring/data/impl}/config/SystemPropertyBasedActiveProfilesResolver.java (95%) rename integration/spring-data/src/test/java/com/blazebit/persistence/{impl/springdata => spring/data/impl}/entity/Document.java (96%) rename integration/spring-data/src/test/java/com/blazebit/persistence/{impl/springdata => spring/data/impl}/entity/Person.java (96%) rename integration/spring-data/src/test/java/com/blazebit/persistence/{impl/springdata => spring/data/impl}/repository/DocumentEntityRepository.java (87%) rename integration/spring-data/src/test/java/com/blazebit/persistence/{impl/springdata => spring/data/impl}/repository/DocumentRepository.java (89%) rename integration/spring-data/src/test/java/com/blazebit/persistence/{impl/springdata => spring/data/impl}/repository/DocumentViewRepository.java (87%) rename integration/spring-data/src/test/java/com/blazebit/persistence/{impl/springdata => spring/data/impl}/tx/TransactionalWorkService.java (95%) rename integration/spring-data/src/test/java/com/blazebit/persistence/{impl/springdata => spring/data/impl}/tx/TxVoidWork.java (93%) rename integration/spring-data/src/test/java/com/blazebit/persistence/{impl/springdata => spring/data/impl}/tx/TxWork.java (93%) rename integration/spring-data/src/test/java/com/blazebit/persistence/{impl/springdata => spring/data/impl}/view/DocumentView.java (88%) rename integration/spring-data/src/test/java/com/blazebit/persistence/{impl/springdata => spring/data/impl}/view/PersonView.java (88%) rename integration/spring-data/src/test/resources/com/blazebit/persistence/{impl/springdata => spring/data/impl}/application-config.xml (100%) diff --git a/README.md b/README.md index 6e74b2f5da..659515b24f 100644 --- a/README.md +++ b/README.md @@ -155,10 +155,34 @@ Blaze-Persistence Spring Data integration dependencies ```xml com.blazebit - blaze-persistence-integration-spring-data + blaze-persistence-integration-spring-data-api ${blaze-persistence.version} compile + + com.blazebit + blaze-persistence-integration-spring-data-impl + ${blaze-persistence.version} + runtime + +``` + +Blaze-Persistence DeltaSpike Data integration + +```xml + + com.blazebit + blaze-persistence-integration-deltaspike-data-api + ${blaze-persistence.version} + compile + + + + com.blazebit + blaze-persistence-integration-deltaspike-data-impl + ${blaze-persistence.version} + runtime + ``` Blaze-Persistence JPA provider integration module dependencies diff --git a/documentation/src/main/asciidoc/entity-view/manual/en_US/02_getting_started.adoc b/documentation/src/main/asciidoc/entity-view/manual/en_US/02_getting_started.adoc index 27479cf65e..f6341e5db8 100644 --- a/documentation/src/main/asciidoc/entity-view/manual/en_US/02_getting_started.adoc +++ b/documentation/src/main/asciidoc/entity-view/manual/en_US/02_getting_started.adoc @@ -83,10 +83,16 @@ When you work with Spring Data you can additionally have first class integration ---- com.blazebit - blaze-persistence-integration-spring-data + blaze-persistence-integration-spring-data-api ${blaze-persistence.version} compile + + com.blazebit + blaze-persistence-integration-spring-data-impl + ${blaze-persistence.version} + runtime + ---- NOTE: The Spring Data integration depends on the _jpa-criteria_ module diff --git a/documentation/src/main/asciidoc/entity-view/manual/en_US/11_spring_data.adoc b/documentation/src/main/asciidoc/entity-view/manual/en_US/11_spring_data.adoc index cad9324427..ed10d1a173 100644 --- a/documentation/src/main/asciidoc/entity-view/manual/en_US/11_spring_data.adoc +++ b/documentation/src/main/asciidoc/entity-view/manual/en_US/11_spring_data.adoc @@ -8,7 +8,7 @@ there is also a Spring Data integration module which tries to make using entity === Setup To setup the project for Spring Data you have to add dependencies as described in the <> section -and make a beans available for `CriteriaBuilderFactory` and `EntityViewManager` instances as laid out in the <> section. +and make beans available for `CriteriaBuilderFactory` and `EntityViewManager` instances as laid out in the <> section. In short, the following Maven dependencies are required @@ -16,10 +16,16 @@ In short, the following Maven dependencies are required ---- com.blazebit - blaze-persistence-integration-spring-data + blaze-persistence-integration-spring-data-api ${blaze-persistence.version} compile + + com.blazebit + blaze-persistence-integration-spring-data-impl + ${blaze-persistence.version} + runtime + com.blazebit blaze-persistence-integration-hibernate-5.2 @@ -77,7 +83,7 @@ Optionally specify a custom basePackage for repository class scanning and a cust [[spring-data-features]] === Features -The integration comes with a convenience base interface `com.blazebit.persistence.impl.springdata.repository.EntityViewRepository` +The integration comes with a convenience base interface `com.blazebit.persistence.impl.springdata.api.repository.EntityViewRepository` that you can use for your repository definitions. Assume we have the following entity view: diff --git a/documentation/src/main/asciidoc/entity-view/manual/en_US/12_deltaspike_data.adoc b/documentation/src/main/asciidoc/entity-view/manual/en_US/12_deltaspike_data.adoc new file mode 100644 index 0000000000..1dcf570544 --- /dev/null +++ b/documentation/src/main/asciidoc/entity-view/manual/en_US/12_deltaspike_data.adoc @@ -0,0 +1,69 @@ +[[deltaspike-data-integration]] +== DeltaSpike Data integration + +{projectname} provides an integration with https://deltaspike.apache.org/documentation/data.html[DeltaSpike Data] to create entity view based repositories. + +[[deltaspike-data-setup]] +=== Setup + +To setup the project for DeltaSpike Data you have to add the entity view and CDI integration dependencies as described +in the <> section along with the integration dependencies for your JPA provider +as described in the link:{core_doc}#maven-setup[core module setup section]. + +In addition, the following Maven dependencies are required: + +[source,xml] +---- + + com.blazebit + blaze-persistence-integration-deltaspike-data-api + ${blaze-persistence.version} + compile + + + com.blazebit + blaze-persistence-integration-deltaspike-data-impl + ${blaze-persistence.version} + runtime + +---- + +You also need to make beans available for `CriteriaBuilderFactory` and `EntityViewManager` as laid out in the +<> section. + +[[deltaspike-data-features]] +=== Features + +To mark a class or an interface as repository, use the DeltaSpike `org.apache.deltaspike.data.api.Repository` annotation. + +[source,java] +---- +@Repository(forEntity = PersonView.class) +public interface PersonViewRepository { + PersonView findAnyByName(String name); +} +---- + +The integration provides the following base interfaces that you may optionally extend to define entity view repositories: + +* `com.balzebit.persistence.impl.deltaspikedata.api.EntityViewRepository` provides simple base methods. +* `com.balzebit.persistence.impl.deltaspikedata.api.CriteriaSupport` adds support for the JPA Criteria API to an entity view +repository. See the https://deltaspike.apache.org/documentation/data.html#_jpa_criteria_api_support[DeltaSpike documentation] +for more details. +* `com.balzebit.persistence.impl.deltaspikedata.api.FullEntityViewRepository` combines the capabilities of the above +interfaces. + +[source,java] +---- +@Repository +public abstract class PersonViewRepository extends FullEntityViewRepository { + public abstract PersonView findAnyByName(String name); + + public List getPersonsByComplexCondition() { + return criteria().or( + criteria().gt(Person_.position, 3), + criteria().likeIgnoreCase(Person_.name, "john%") + ).orderAsc(Person_.id).getResultList(); + } +} +---- \ No newline at end of file diff --git a/documentation/src/main/asciidoc/entity-view/manual/en_US/12_metamodel.adoc b/documentation/src/main/asciidoc/entity-view/manual/en_US/13_metamodel.adoc similarity index 100% rename from documentation/src/main/asciidoc/entity-view/manual/en_US/12_metamodel.adoc rename to documentation/src/main/asciidoc/entity-view/manual/en_US/13_metamodel.adoc diff --git a/documentation/src/main/asciidoc/entity-view/manual/en_US/13_configuration.adoc b/documentation/src/main/asciidoc/entity-view/manual/en_US/14_configuration.adoc similarity index 100% rename from documentation/src/main/asciidoc/entity-view/manual/en_US/13_configuration.adoc rename to documentation/src/main/asciidoc/entity-view/manual/en_US/14_configuration.adoc diff --git a/documentation/src/main/asciidoc/entity-view/manual/en_US/index.adoc b/documentation/src/main/asciidoc/entity-view/manual/en_US/index.adoc index f602d9a670..28fa7299f1 100644 --- a/documentation/src/main/asciidoc/entity-view/manual/en_US/index.adoc +++ b/documentation/src/main/asciidoc/entity-view/manual/en_US/index.adoc @@ -37,6 +37,8 @@ include::10_change_model.adoc[] include::11_spring_data.adoc[] -include::12_metamodel.adoc[] +include::12_deltaspike_data.adoc[] -include::13_configuration.adoc[] \ No newline at end of file +include::13_metamodel.adoc[] + +include::14_configuration.adoc[] \ No newline at end of file diff --git a/examples/cdi-showcase/pom.xml b/examples/cdi-showcase/pom.xml index 261f5ea935..f859942adf 100644 --- a/examples/cdi-showcase/pom.xml +++ b/examples/cdi-showcase/pom.xml @@ -25,22 +25,6 @@ Blazebit Persistence Examples CDI Showcase blaze-persistence-cdi-showcase - - 1.7.1 - - - - - - org.apache.deltaspike.distribution - distributions-bom - ${version.deltaspike} - pom - import - - - - javax @@ -92,7 +76,6 @@ org.jboss.weld.se weld-se-core - 2.4.0.Final @@ -124,6 +107,16 @@ org.apache.deltaspike.cdictrl deltaspike-cdictrl-weld runtime + + + weld-api + org.jboss.weld + + + jboss-logging + org.jboss.logging + + diff --git a/examples/cdi-showcase/src/main/java/com/blazebit/persistence/examples/cdi/CDIShowcaseRunner.java b/examples/cdi-showcase/src/main/java/com/blazebit/persistence/examples/cdi/CDIShowcaseRunner.java index b1d4dcd022..1306ca8200 100644 --- a/examples/cdi-showcase/src/main/java/com/blazebit/persistence/examples/cdi/CDIShowcaseRunner.java +++ b/examples/cdi-showcase/src/main/java/com/blazebit/persistence/examples/cdi/CDIShowcaseRunner.java @@ -21,11 +21,10 @@ import org.apache.deltaspike.cdise.api.CdiContainerLoader; import org.apache.deltaspike.cdise.api.ContextControl; import org.apache.deltaspike.core.api.provider.BeanProvider; -import org.jboss.weld.bootstrap.spi.Metadata; -import org.jboss.weld.util.ServiceLoader; import javax.enterprise.context.ApplicationScoped; import java.util.Iterator; +import java.util.ServiceLoader; /** * @author Moritz Becker (moritz.becker@gmx.at) @@ -44,12 +43,12 @@ public static void main(String[] args) { contextControl.startContext(ApplicationScoped.class); ServiceLoader showcaseLoader = ServiceLoader.load(Showcase.class); - Iterator> showcaseIterator = showcaseLoader.iterator(); + Iterator showcaseIterator = showcaseLoader.iterator(); if (!showcaseIterator.hasNext()) { throw new RuntimeException("No showcases found"); } while (showcaseIterator.hasNext()) { - BeanProvider.injectFields(showcaseIterator.next().getValue()).run(); + BeanProvider.injectFields(showcaseIterator.next()).run(); } cdiContainer.shutdown(); diff --git a/examples/spring-data-showcase/src/main/java/com/blazebit/persistence/examples/springdata/SpringDataShowcaseConfig.java b/examples/spring-data-showcase/src/main/java/com/blazebit/persistence/examples/springdata/SpringDataShowcaseConfig.java index 60b41674df..df985bea93 100644 --- a/examples/spring-data-showcase/src/main/java/com/blazebit/persistence/examples/springdata/SpringDataShowcaseConfig.java +++ b/examples/spring-data-showcase/src/main/java/com/blazebit/persistence/examples/springdata/SpringDataShowcaseConfig.java @@ -16,7 +16,7 @@ package com.blazebit.persistence.examples.springdata; -import com.blazebit.persistence.impl.springdata.repository.EntityViewRepositoryFactoryBean; +import com.blazebit.persistence.spring.data.impl.repository.EntityViewRepositoryFactoryBean; import org.springframework.context.annotation.Configuration; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; diff --git a/examples/spring-data-showcase/src/main/java/com/blazebit/persistence/examples/springdata/repository/CatRepository.java b/examples/spring-data-showcase/src/main/java/com/blazebit/persistence/examples/springdata/repository/CatRepository.java index 62df747a5a..c13e85b67e 100644 --- a/examples/spring-data-showcase/src/main/java/com/blazebit/persistence/examples/springdata/repository/CatRepository.java +++ b/examples/spring-data-showcase/src/main/java/com/blazebit/persistence/examples/springdata/repository/CatRepository.java @@ -17,7 +17,7 @@ package com.blazebit.persistence.examples.springdata.repository; import com.blazebit.persistence.examples.springdata.view.CatView; -import com.blazebit.persistence.impl.springdata.repository.EntityViewRepository; +import com.blazebit.persistence.spring.data.api.repository.EntityViewRepository; import java.util.List; diff --git a/examples/spring-showcase/src/main/java/com/blazebit/persistence/examples/spring/SpringShowcaseRunner.java b/examples/spring-showcase/src/main/java/com/blazebit/persistence/examples/spring/SpringShowcaseRunner.java index 0fbea3d3e2..5f3b409ffa 100644 --- a/examples/spring-showcase/src/main/java/com/blazebit/persistence/examples/spring/SpringShowcaseRunner.java +++ b/examples/spring-showcase/src/main/java/com/blazebit/persistence/examples/spring/SpringShowcaseRunner.java @@ -17,7 +17,7 @@ package com.blazebit.persistence.examples.spring; import com.blazebit.persistence.examples.spi.Showcase; -import com.blazebit.persistence.impl.springdata.repository.EntityViewRepositoryFactoryBean; +import com.blazebit.persistence.spring.data.impl.repository.EntityViewRepositoryFactoryBean; import com.blazebit.persistence.view.impl.spring.EnableEntityViews; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.boot.CommandLineRunner; diff --git a/integration/deltaspike-data/api/pom.xml b/integration/deltaspike-data/api/pom.xml new file mode 100644 index 0000000000..76b56edc0c --- /dev/null +++ b/integration/deltaspike-data/api/pom.xml @@ -0,0 +1,29 @@ + + + + blaze-persistence-integration-deltaspike-data + com.blazebit + 1.2.0-SNAPSHOT + + 4.0.0 + + blaze-persistence-integration-deltaspike-data-api + + Blazebit Persistence Integration DeltaSpike Data API + + + + org.apache.deltaspike.modules + deltaspike-data-module-api + provided + + + javax + javaee-api + 7.0 + provided + + + \ No newline at end of file diff --git a/integration/deltaspike-data/api/src/main/java/com/balzebit/persistence/impl/deltaspikedata/api/CriteriaSupport.java b/integration/deltaspike-data/api/src/main/java/com/balzebit/persistence/impl/deltaspikedata/api/CriteriaSupport.java new file mode 100644 index 0000000000..6a5f5f709f --- /dev/null +++ b/integration/deltaspike-data/api/src/main/java/com/balzebit/persistence/impl/deltaspikedata/api/CriteriaSupport.java @@ -0,0 +1,54 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.balzebit.persistence.impl.deltaspikedata.api; + +import org.apache.deltaspike.data.api.criteria.Criteria; + +import javax.persistence.criteria.JoinType; + +/** + * @author Moritz Becker + * @since 1.2.0 + */ +public interface CriteriaSupport { + + /** + * Create a {@link Criteria} instance. + * + * @return Criteria instance related to the Repository entity class. + */ + Criteria criteria(); + + /** + * Create a {@link Criteria} instance. + * + * @param Type related to the current criteria class. + * @param clazz Class other than the current entity class. + * @return Criteria instance related to a join type of the current entity class. + */ + Criteria where(Class clazz); + + /** + * Create a {@link Criteria} instance with a join type. + * + * @param Type related to the current criteria class. + * @param clazz Class other than the current entity class. + * @param joinType Join type to apply. + * @return Criteria instance related to a join type of the current entity class. + */ + Criteria where(Class clazz, JoinType joinType); +} diff --git a/integration/deltaspike-data/api/src/main/java/com/balzebit/persistence/impl/deltaspikedata/api/EntityViewRepository.java b/integration/deltaspike-data/api/src/main/java/com/balzebit/persistence/impl/deltaspikedata/api/EntityViewRepository.java new file mode 100644 index 0000000000..a56f84ae4e --- /dev/null +++ b/integration/deltaspike-data/api/src/main/java/com/balzebit/persistence/impl/deltaspikedata/api/EntityViewRepository.java @@ -0,0 +1,88 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.balzebit.persistence.impl.deltaspikedata.api; + +import org.apache.deltaspike.core.spi.activation.Deactivatable; + +import javax.persistence.metamodel.SingularAttribute; +import java.io.Serializable; +import java.util.List; + +/** + * @author Moritz Becker + * @since 1.2.0 + */ +public interface EntityViewRepository extends Deactivatable { + /** + * Entity lookup by primary key. Convenicence method around + * {@link javax.persistence.EntityManager#find(Class, Object)}. + * @param primaryKey DB primary key. + * @return Entity identified by primary or null if it does not exist. + */ + V findBy(PK primaryKey); + + /** + * Lookup all existing entities of entity class {@code }. + * @return List of entities, empty if none found. + */ + List findAll(); + + /** + * Lookup a range of existing entities of entity class {@code } with support for pagination. + * @param start The starting position. + * @param max The maximum number of results to return + * @return List of entities, empty if none found. + */ + List findAll(int start, int max); + + /** + * Query by example - for a given object and a specific set of properties. + * @param example Sample entity. Query all like. + * @param attributes Which attributes to consider for the query. + * @return List of entities matching the example, or empty if none found. + */ + List findBy(E example, SingularAttribute... attributes); + + /** + * Query by example - for a given object and a specific set of properties with support for pagination. + * @param example Sample entity. Query all like. + * @param start The starting position. + * @param max The maximum number of results to return + * @param attributes Which attributes to consider for the query. + * @return List of entities matching the example, or empty if none found. + */ + List findBy(E example, int start, int max, SingularAttribute... attributes); + + /** + * Query by example - for a given object and a specific set of properties using a like operator for Strings. + * @param example Sample entity. Query all like. + * @param attributes Which attributes to consider for the query. + * @return List of entities matching the example, or empty if none found. + */ + List findByLike(E example, SingularAttribute... attributes); + + /** + * Query by example - for a given object and a specific set of properties + * using a like operator for Strings with support for pagination. + * @param example Sample entity. Query all like. + * @param start The starting position. + * @param max The maximum number of results to return + * @param attributes Which attributes to consider for the query. + * @return List of entities matching the example, or empty if none found. + */ + List findByLike(E example, int start, int max, SingularAttribute... attributes); +} \ No newline at end of file diff --git a/integration/deltaspike-data/api/src/main/java/com/balzebit/persistence/impl/deltaspikedata/api/FullEntityViewRepository.java b/integration/deltaspike-data/api/src/main/java/com/balzebit/persistence/impl/deltaspikedata/api/FullEntityViewRepository.java new file mode 100644 index 0000000000..7e202caf66 --- /dev/null +++ b/integration/deltaspike-data/api/src/main/java/com/balzebit/persistence/impl/deltaspikedata/api/FullEntityViewRepository.java @@ -0,0 +1,26 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.balzebit.persistence.impl.deltaspikedata.api; + +import java.io.Serializable; + +/** + * @author Moritz Becker + * @since 1.2.0 + */ +public interface FullEntityViewRepository extends EntityViewRepository, CriteriaSupport { +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/pom.xml b/integration/deltaspike-data/impl/pom.xml new file mode 100644 index 0000000000..cbe9173c0f --- /dev/null +++ b/integration/deltaspike-data/impl/pom.xml @@ -0,0 +1,106 @@ + + + + blaze-persistence-integration-deltaspike-data + com.blazebit + 1.2.0-SNAPSHOT + + 4.0.0 + + blaze-persistence-integration-deltaspike-data-impl + + Blazebit Persistence Integration DeltaSpike Data Impl + + + + ${project.groupId} + blaze-persistence-entity-view-api + + + ${project.groupId} + blaze-persistence-integration-deltaspike-data-api + + + ${project.groupId} + blaze-persistence-jpa-criteria-impl + + + javax + javaee-api + 7.0 + provided + + + org.apache.deltaspike.core + deltaspike-core-api + provided + + + org.apache.deltaspike.modules + deltaspike-data-module-api + provided + + + org.apache.deltaspike.modules + deltaspike-data-module-impl + provided + + + org.apache.deltaspike.modules + deltaspike-partial-bean-module-impl + provided + + + ${project.groupId} + blaze-apt-utils + provided + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add-resource + generate-resources + + add-resource + + + + + target/generated/resources + + + + + + + + org.bsc.maven + maven-processor-plugin + + + process-resouces + + process + + generate-resources + + target/generated/resources + + + com.blazebit.apt.service.ServiceProviderAnnotationProcessor + + + + + + + + \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/CustomPartialBeanBindingExtension.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/CustomPartialBeanBindingExtension.java new file mode 100644 index 0000000000..4eefbb7c77 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/CustomPartialBeanBindingExtension.java @@ -0,0 +1,120 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl; + +import com.blazebit.apt.service.ServiceProvider; +import org.apache.deltaspike.data.api.Repository; +import org.apache.deltaspike.data.impl.handler.QueryHandler; +import org.apache.deltaspike.partialbean.impl.PartialBeanBindingExtension; +import org.apache.deltaspike.partialbean.impl.PartialBeanDescriptor; + +import javax.enterprise.event.Observes; +import javax.enterprise.inject.spi.BeanManager; +import javax.enterprise.inject.spi.Extension; +import javax.enterprise.inject.spi.ProcessAnnotatedType; +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Modifier; +import java.util.Map; + +/** + * @author Moritz Becker + * @since 1.2.0 + */ +@ServiceProvider(Extension.class) +public class CustomPartialBeanBindingExtension extends PartialBeanBindingExtension { + + private boolean isActivated() { + try { + Field descriptorsField = PartialBeanBindingExtension.class.getDeclaredField("isActivated"); + descriptorsField.setAccessible(true); + return (boolean) descriptorsField.get(this); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + private Map, PartialBeanDescriptor> getDescriptors() { + try { + Field descriptorsField = PartialBeanBindingExtension.class.getDeclaredField("descriptors"); + descriptorsField.setAccessible(true); + return (Map, PartialBeanDescriptor>) descriptorsField.get(this); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + private IllegalStateException getDefinitionError() { + try { + Field descriptorsField = PartialBeanBindingExtension.class.getDeclaredField("definitionError"); + descriptorsField.setAccessible(true); + return (IllegalStateException) descriptorsField.get(this); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + private void setDefinitionError(IllegalStateException definitionError) { + try { + Field descriptorsField = PartialBeanBindingExtension.class.getDeclaredField("definitionError"); + descriptorsField.setAccessible(true); + descriptorsField.set(this, definitionError); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + @Override + public void findInvocationHandlerBindings(@Observes ProcessAnnotatedType pat, BeanManager beanManager) { + if (isActivated() && getDefinitionError() == null) { + Map, PartialBeanDescriptor> descriptors = getDescriptors(); + Class beanClass = (Class) pat.getAnnotatedType().getJavaClass(); + Class bindingClass = this.extractBindingClass(pat); + if (bindingClass != null) { + if (bindingClass.equals(Repository.class) && beanClass.equals(QueryHandler.class)) { + return; + } + PartialBeanDescriptor descriptor; + if (!beanClass.isInterface() && !Modifier.isAbstract(beanClass.getModifiers())) { + if (InvocationHandler.class.isAssignableFrom(beanClass)) { + descriptor = descriptors.get(bindingClass); + if (descriptor == null) { + descriptor = new PartialBeanDescriptor(bindingClass, beanClass); + descriptors.put(bindingClass, descriptor); + } else if (descriptor.getHandler() == null) { + descriptor.setHandler(beanClass); + } else if (!descriptor.getHandler().equals(beanClass)) { + setDefinitionError(new IllegalStateException("Multiple handlers found for " + bindingClass.getName() + " (" + descriptor.getHandler().getName() + " and " + beanClass.getName() + ")")); + } + } else { + setDefinitionError(new IllegalStateException(beanClass.getName() + " is annotated with @" + bindingClass.getName() + " and therefore has to be " + "an abstract class, an interface or an implementation of " + InvocationHandler.class.getName())); + } + } else { + pat.veto(); + descriptor = descriptors.get(bindingClass); + if (descriptor == null) { + descriptor = new PartialBeanDescriptor(bindingClass, (Class)null, beanClass); + descriptors.put(bindingClass, descriptor); + } else if (!descriptor.getClasses().contains(beanClass)) { + descriptor.getClasses().add(beanClass); + } + } + } + } + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/DeltaspikeExtensionDeactivator.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/DeltaspikeExtensionDeactivator.java new file mode 100644 index 0000000000..9c6da51b26 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/DeltaspikeExtensionDeactivator.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl; + +import org.apache.deltaspike.core.spi.activation.ClassDeactivator; +import org.apache.deltaspike.core.spi.activation.Deactivatable; +import org.apache.deltaspike.data.impl.RepositoryExtension; +import org.apache.deltaspike.partialbean.impl.PartialBeanBindingExtension; + +/** + * @author Moritz Becker + * @since 1.2.0 + */ +public class DeltaspikeExtensionDeactivator implements ClassDeactivator { + @Override + public Boolean isActivated(Class aClass) { + return !(aClass.equals(RepositoryExtension.class) || aClass.equals(PartialBeanBindingExtension.class)); + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/EntityViewRepositoryExtension.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/EntityViewRepositoryExtension.java new file mode 100644 index 0000000000..606456bde5 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/EntityViewRepositoryExtension.java @@ -0,0 +1,167 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl; + +import com.blazebit.apt.service.ServiceProvider; +import com.blazebit.persistence.impl.deltaspikedata.impl.meta.EntityViewRepositoryComponents; +import org.apache.deltaspike.core.spi.activation.Deactivatable; +import org.apache.deltaspike.core.util.ClassDeactivationUtils; +import org.apache.deltaspike.data.api.AbstractEntityRepository; +import org.apache.deltaspike.data.api.AbstractFullEntityRepository; +import org.apache.deltaspike.data.api.Repository; +import org.apache.deltaspike.data.impl.RepositoryDefinitionException; +import org.apache.deltaspike.data.impl.meta.RepositoryComponents; + +import javax.enterprise.event.Observes; +import javax.enterprise.inject.spi.AfterBeanDiscovery; +import javax.enterprise.inject.spi.AnnotatedType; +import javax.enterprise.inject.spi.BeanManager; +import javax.enterprise.inject.spi.BeforeBeanDiscovery; +import javax.enterprise.inject.spi.BeforeShutdown; +import javax.enterprise.inject.spi.Extension; +import javax.enterprise.inject.spi.ProcessAnnotatedType; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Modifier; +import java.util.LinkedList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.RepositoryExtension} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +@ServiceProvider(Extension.class) +public class EntityViewRepositoryExtension implements Extension, Deactivatable { + + private static final Logger LOG = Logger.getLogger(EntityViewRepositoryExtension.class.getName()); + + private static RepositoryComponents staticComponents = new RepositoryComponents(); + private static EntityViewRepositoryComponents staticEntityViewRepositoryComponents = new EntityViewRepositoryComponents(); + + private final List definitionExceptions = new LinkedList<>(); + + private Boolean isActivated = true; + + private RepositoryComponents components = new RepositoryComponents(); + private EntityViewRepositoryComponents entityViewRepositoryComponents = new EntityViewRepositoryComponents(); + + void beforeBeanDiscovery(@Observes BeforeBeanDiscovery before) { + isActivated = ClassDeactivationUtils.isActivated(getClass()); + } + + @SuppressWarnings("unchecked") + void processAnnotatedType(@Observes ProcessAnnotatedType event) { + if (!isActivated) { + return; + } + + if (isVetoed(event.getAnnotatedType())) { + event.veto(); + } else if (isRepository(event.getAnnotatedType())) { + Class repoClass = event.getAnnotatedType().getJavaClass(); + try { + LOG.log(Level.FINER, "getHandlerClass: Repository annotation detected on {0}", + event.getAnnotatedType()); + if (Deactivatable.class.isAssignableFrom(repoClass) + && !ClassDeactivationUtils.isActivated((Class) repoClass)) { + LOG.log(Level.FINER, "Class {0} is Deactivated", repoClass); + return; + } + try { + entityViewRepositoryComponents.add(repoClass); + staticEntityViewRepositoryComponents.add(repoClass); + } catch (RepositoryDefinitionException e) { + components.add(repoClass); + staticComponents.add(repoClass); + } + } catch (RepositoryDefinitionException e) { + definitionExceptions.add(e); + } catch (Exception e) { + definitionExceptions.add(new RepositoryDefinitionException(repoClass, e)); + } + } + } + + void addDefinitionErrors(@Observes AfterBeanDiscovery afterBeanDiscovery, BeanManager beanManager) { + if (!isActivated) { + return; + } + + for (RepositoryDefinitionException ex : definitionExceptions) { + afterBeanDiscovery.addDefinitionError(ex); + } + } + + private boolean isRepository(AnnotatedType annotatedType) { + return (annotatedType.isAnnotationPresent(Repository.class) || + annotatedType.getJavaClass().isAnnotationPresent(Repository.class)) && + !InvocationHandler.class.isAssignableFrom(annotatedType.getJavaClass()); + } + + private boolean isVetoed(AnnotatedType annotated) { + Class javaClass = annotated.getJavaClass(); + return javaClass.equals(AbstractEntityRepository.class) || + javaClass.equals(AbstractFullEntityRepository.class); + } + + public RepositoryComponents getComponents() { + RepositoryComponents result = new RepositoryComponents(); + if (components.getRepositories().isEmpty() && !staticComponents.getRepositories().isEmpty()) { + result.addAll(staticComponents.getRepositories()); + } + + if (!components.getRepositories().isEmpty()) { + result.addAll(components.getRepositories()); + } + + return result; + } + + public EntityViewRepositoryComponents getEntityViewRepositoryComponents() { + EntityViewRepositoryComponents result = new EntityViewRepositoryComponents(); + if (entityViewRepositoryComponents.getRepositories().isEmpty() && !staticEntityViewRepositoryComponents.getRepositories().isEmpty()) { + result.addAll(staticEntityViewRepositoryComponents.getRepositories()); + } + + if (!entityViewRepositoryComponents.getRepositories().isEmpty()) { + result.addAll(entityViewRepositoryComponents.getRepositories()); + } + + return result; + } + + protected void cleanup(@Observes BeforeShutdown beforeShutdown) { + //we can reset it in any case, + //because every application produced a copy as application-scoped bean (see RepositoryComponentsFactory) + staticComponents.getRepositories().clear(); + } + + private static void setFinalField(Field field, Object instance, Object newValue) throws NoSuchFieldException, IllegalAccessException { + field.setAccessible(true); + + Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); + + field.set(instance, newValue); + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/EntityViewAwareQueryBuilderFactory.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/EntityViewAwareQueryBuilderFactory.java new file mode 100644 index 0000000000..405629291c --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/EntityViewAwareQueryBuilderFactory.java @@ -0,0 +1,61 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.builder; + +import com.blazebit.persistence.impl.deltaspikedata.impl.handler.EntityViewCdiQueryInvocationContext; +import com.blazebit.persistence.impl.deltaspikedata.impl.meta.EntityViewRepositoryMethod; +import org.apache.deltaspike.core.api.provider.BeanProvider; +import org.apache.deltaspike.data.api.QueryResult; +import org.apache.deltaspike.data.impl.meta.MethodType; +import org.apache.deltaspike.data.impl.meta.QueryInvocationLiteral; + +import javax.enterprise.context.ApplicationScoped; +import java.util.HashMap; +import java.util.Map; + +import static org.apache.deltaspike.data.impl.meta.MethodType.DELEGATE; +import static org.apache.deltaspike.data.impl.meta.MethodType.PARSE; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.builder.QueryBuilderFactory} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +@ApplicationScoped +public class EntityViewAwareQueryBuilderFactory { + + private static final Map LITERALS = + new HashMap() + { + private static final long serialVersionUID = 1L; + + { + put(DELEGATE, new QueryInvocationLiteral(DELEGATE)); + put(PARSE, new QueryInvocationLiteral(PARSE)); + } + }; + + public EntityViewQueryBuilder build(EntityViewRepositoryMethod method, EntityViewCdiQueryInvocationContext context) { + EntityViewQueryBuilder builder = BeanProvider.getContextualReference(EntityViewQueryBuilder.class, LITERALS.get(method.getMethodType())); + if (method.returns(QueryResult.class)) { + return new WrappedEntityViewQueryBuilder(builder); + } + return builder; + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/EntityViewDelegateQueryBuilder.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/EntityViewDelegateQueryBuilder.java new file mode 100644 index 0000000000..2c76ee8ab4 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/EntityViewDelegateQueryBuilder.java @@ -0,0 +1,126 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.builder; + +import com.blazebit.persistence.impl.deltaspikedata.impl.handler.EntityViewCdiQueryInvocationContext; +import com.blazebit.persistence.impl.deltaspikedata.impl.handler.EntityViewDelegateQueryHandler; +import org.apache.deltaspike.core.api.provider.BeanProvider; +import org.apache.deltaspike.core.util.ClassUtils; +import org.apache.deltaspike.core.util.OptionalUtil; +import org.apache.deltaspike.core.util.StreamUtil; +import org.apache.deltaspike.data.api.QueryInvocationException; +import org.apache.deltaspike.data.impl.meta.MethodType; +import org.apache.deltaspike.data.impl.meta.QueryInvocation; +import org.apache.deltaspike.data.impl.util.bean.BeanDestroyable; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.context.Dependent; +import javax.enterprise.context.spi.CreationalContext; +import javax.enterprise.inject.spi.Bean; +import javax.enterprise.inject.spi.BeanManager; +import javax.inject.Inject; +import javax.persistence.PersistenceException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.builder.DelegateQueryBuilder} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +@QueryInvocation(MethodType.DELEGATE) +@ApplicationScoped +public class EntityViewDelegateQueryBuilder extends EntityViewQueryBuilder { + @Inject + private BeanManager beanManager; + + private final Map> lookupCache = new HashMap<>(); + + @Override + public Object execute(EntityViewCdiQueryInvocationContext context) { + try { + EntityViewDelegateQueryHandler delegate = lookup(context); + if (delegate != null) { + Object result = invoke(delegate, context); + if (result instanceof Collection && StreamUtil.isStreamReturned(context.getMethod())) { + return StreamUtil.wrap(result); + } else if (OptionalUtil.isOptionalReturned(context.getMethod())) { + return OptionalUtil.wrap(result); + } else { + return result; + } + } + } catch (PersistenceException e) { + throw e; + } catch (Exception e) { + throw new QueryInvocationException(e, context); + } + throw new QueryInvocationException("No DelegateQueryHandler found", context); + } + + private EntityViewDelegateQueryHandler lookup(EntityViewCdiQueryInvocationContext context) { + Bean selectedBean = lookupCache.get(context.getMethod()); + + if (selectedBean == null) { + Set> beans = BeanProvider + .getBeanDefinitions(EntityViewDelegateQueryHandler.class, true, true); + for (Bean bean : beans) { + if (ClassUtils.containsPossiblyGenericMethod(bean.getBeanClass(), context.getMethod())) { + selectedBean = bean; + } + } + + if (selectedBean != null) { + lookupCache.put(context.getMethod(), selectedBean); + } + } + + + if (selectedBean != null) { + CreationalContext cc = beanManager.createCreationalContext(selectedBean); + EntityViewDelegateQueryHandler instance = (EntityViewDelegateQueryHandler) beanManager.getReference( + selectedBean, EntityViewDelegateQueryHandler.class, cc); + + if (selectedBean.getScope().equals(Dependent.class)) { + context.addDestroyable(new BeanDestroyable(selectedBean, instance, cc)); + } + + return instance; + } + return null; + } + + private Object invoke(EntityViewDelegateQueryHandler delegate, EntityViewCdiQueryInvocationContext context) { + try { + Method extract = ClassUtils.extractPossiblyGenericMethod(delegate.getClass(), context.getMethod()); + return extract.invoke(delegate, context.getMethodParameters()); + } catch (InvocationTargetException e) { + if (e.getCause() != null && e.getCause() instanceof PersistenceException) { + throw (PersistenceException) e.getCause(); + } + throw new QueryInvocationException(e, context); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/EntityViewMethodQueryBuilder.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/EntityViewMethodQueryBuilder.java new file mode 100644 index 0000000000..d46b56fcfd --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/EntityViewMethodQueryBuilder.java @@ -0,0 +1,71 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.builder; + +import com.blazebit.persistence.CriteriaBuilder; +import com.blazebit.persistence.FullQueryBuilder; +import com.blazebit.persistence.impl.deltaspikedata.impl.builder.part.EntityViewQueryRoot; +import com.blazebit.persistence.impl.deltaspikedata.impl.handler.EntityViewCdiQueryInvocationContext; +import com.blazebit.persistence.impl.deltaspikedata.impl.param.Parameters; +import com.blazebit.persistence.view.EntityViewSetting; +import org.apache.deltaspike.data.impl.meta.MethodType; +import org.apache.deltaspike.data.impl.meta.QueryInvocation; + +import javax.enterprise.context.ApplicationScoped; +import javax.persistence.Query; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.builder.MethodQueryBuilder} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +@QueryInvocation(MethodType.PARSE) +@ApplicationScoped +public class EntityViewMethodQueryBuilder extends EntityViewQueryBuilder { + + @Override + public Object execute(EntityViewCdiQueryInvocationContext context) { + Query jpaQuery = createJpaQuery(context); + return context.executeQuery(jpaQuery); + } + + private Query createJpaQuery(EntityViewCdiQueryInvocationContext context) { + Parameters params = context.getParams(); + EntityViewQueryRoot root = context.getRepositoryMethod().getQueryRoot(); + CriteriaBuilder cb = context.getCriteriaBuilderFactory().create(context.getEntityManager(), context.getEntityClass()); + root.apply(cb); + + cb = context.getEntityViewManager().applySetting( + EntityViewSetting.create(context.getEntityViewClass()), + cb + ); + FullQueryBuilder fullCb; + if (params.hasFirstResult() || params.hasSizeRestriction()) { + int firstResult = params.hasFirstResult() ? params.getFirstResult() : 0; + int maxResults = params.hasSizeRestriction() ? params.getSizeRestriciton() : Integer.MAX_VALUE; + fullCb = cb.page(firstResult, maxResults); + } else { + fullCb = cb; + } + + fullCb = context.applyCriteriaBuilderPostProcessors(fullCb); + fullCb = params.applyTo(fullCb); + return context.applyRestrictions(fullCb.getQuery()); + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/EntityViewQueryBuilder.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/EntityViewQueryBuilder.java new file mode 100644 index 0000000000..1688d79404 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/EntityViewQueryBuilder.java @@ -0,0 +1,60 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.builder; + +import com.blazebit.persistence.impl.deltaspikedata.impl.handler.EntityViewCdiQueryInvocationContext; +import org.apache.deltaspike.data.api.QueryResult; +import org.apache.deltaspike.data.api.mapping.QueryInOutMapper; + +import javax.persistence.Query; +import java.lang.reflect.Method; +import java.util.List; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.builder.QueryBuilder} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +public abstract class EntityViewQueryBuilder { + + @SuppressWarnings("unchecked") + public Object executeQuery(EntityViewCdiQueryInvocationContext context) { + Object result = execute(context); + if (!isUnmappableResult(result) && context.hasQueryInOutMapper()) { + QueryInOutMapper mapper = (QueryInOutMapper) + context.getQueryInOutMapper(); + if (result instanceof List) { + return mapper.mapResultList((List) result); + } + return mapper.mapResult(result); + } + return result; + } + + protected abstract Object execute(EntityViewCdiQueryInvocationContext ctx); + + protected boolean returnsList(Method method) { + return method.getReturnType().isAssignableFrom(List.class); + } + + private boolean isUnmappableResult(Object result) { + return result instanceof QueryResult || + result instanceof Query; + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/EntityViewQueryBuilderContext.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/EntityViewQueryBuilderContext.java new file mode 100644 index 0000000000..222d000650 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/EntityViewQueryBuilderContext.java @@ -0,0 +1,49 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.builder; + +import com.blazebit.persistence.CriteriaBuilder; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.builder.QueryBuilderContext} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +public class EntityViewQueryBuilderContext { + + private final StringBuilder whereExpressionBuilder = new StringBuilder(); + private final CriteriaBuilder criteriaBuilder; + private int counter = 1; + + public EntityViewQueryBuilderContext(CriteriaBuilder criteriaBuilder) { + this.criteriaBuilder = criteriaBuilder; + } + + public CriteriaBuilder getCriteriaBuilder() { + return criteriaBuilder; + } + + public int increment() { + return counter++; + } + + public StringBuilder getWhereExpressionBuilder() { + return whereExpressionBuilder; + } +} diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/WrappedEntityViewQueryBuilder.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/WrappedEntityViewQueryBuilder.java new file mode 100644 index 0000000000..43c391c949 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/WrappedEntityViewQueryBuilder.java @@ -0,0 +1,44 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.builder; + +import com.blazebit.persistence.impl.deltaspikedata.impl.builder.result.EntityViewDefaultQueryResult; +import com.blazebit.persistence.impl.deltaspikedata.impl.handler.EntityViewCdiQueryInvocationContext; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.builder.WrappedQueryBuilder} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +public class WrappedEntityViewQueryBuilder extends EntityViewQueryBuilder { + + private final EntityViewQueryBuilder delegate; + + public WrappedEntityViewQueryBuilder(EntityViewQueryBuilder delegate) + { + this.delegate = delegate; + } + + @Override + @SuppressWarnings("rawtypes") + public Object execute(EntityViewCdiQueryInvocationContext ctx) + { + return new EntityViewDefaultQueryResult(delegate, ctx); + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewAndQueryPart.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewAndQueryPart.java new file mode 100644 index 0000000000..52832c8296 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewAndQueryPart.java @@ -0,0 +1,49 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.builder.part; + +import com.blazebit.persistence.impl.deltaspikedata.impl.builder.EntityViewQueryBuilderContext; +import com.blazebit.persistence.impl.deltaspikedata.impl.meta.EntityViewRepositoryComponent; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.builder.part.AndQueryPart} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +class EntityViewAndQueryPart extends EntityViewConnectingQueryPart { + + public EntityViewAndQueryPart(boolean first) { + super(first); + } + + @Override + protected EntityViewQueryPart build(String queryPart, String method, EntityViewRepositoryComponent repo) { + children.add(new EntityViewPropertyQueryPart().build(queryPart, method, repo)); + return this; + } + + @Override + protected EntityViewQueryPart buildQuery(EntityViewQueryBuilderContext ctx) { + if (!first) { + ctx.getWhereExpressionBuilder().append(" and "); + } + buildQueryForChildren(ctx); + return this; + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewBasePropertyQueryPart.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewBasePropertyQueryPart.java new file mode 100644 index 0000000000..355675d66b --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewBasePropertyQueryPart.java @@ -0,0 +1,58 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.builder.part; + +import com.blazebit.persistence.impl.deltaspikedata.impl.meta.EntityViewRepositoryComponent; +import org.apache.deltaspike.data.impl.builder.MethodExpressionException; +import org.apache.deltaspike.data.impl.property.Property; +import org.apache.deltaspike.data.impl.property.query.NamedPropertyCriteria; +import org.apache.deltaspike.data.impl.property.query.PropertyQueries; +import org.apache.deltaspike.data.impl.property.query.PropertyQuery; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.builder.part.BasePropertyQueryPart} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +abstract class EntityViewBasePropertyQueryPart extends EntityViewQueryPart { + static final String SEPARATOR = "_"; + + void validate(String name, String method, EntityViewRepositoryComponent repo) { + Class current = repo.getEntityClass(); + if (name == null) { + throw new MethodExpressionException(null, repo.getRepositoryClass(), method); + } + for (String property : name.split(SEPARATOR)) { + PropertyQuery query = PropertyQueries.createQuery(current) + .addCriteria(new NamedPropertyCriteria(property)); + Property result = query.getFirstResult(); + if (result == null) { + throw new MethodExpressionException(property, repo.getRepositoryClass(), method); + } + current = result.getJavaClass(); + } + } + + String rewriteSeparator(String name) { + if (name.contains("_")) { + return name.replaceAll(SEPARATOR, "."); + } + return name; + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewConnectingQueryPart.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewConnectingQueryPart.java new file mode 100644 index 0000000000..1c981bc9bf --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewConnectingQueryPart.java @@ -0,0 +1,36 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.builder.part; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.builder.part.ConnectingQueryPart} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +abstract class EntityViewConnectingQueryPart extends EntityViewQueryPart { + protected final boolean first; + + public EntityViewConnectingQueryPart(boolean first) { + this.first = first; + } + + public boolean isFirst() { + return first; + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewOrQueryPart.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewOrQueryPart.java new file mode 100644 index 0000000000..4379b9dc55 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewOrQueryPart.java @@ -0,0 +1,57 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.builder.part; + +import com.blazebit.persistence.impl.deltaspikedata.impl.builder.EntityViewQueryBuilderContext; +import com.blazebit.persistence.impl.deltaspikedata.impl.meta.EntityViewRepositoryComponent; + +import static org.apache.deltaspike.data.impl.util.QueryUtils.splitByKeyword; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.builder.part.OrQueryPart} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +class EntityViewOrQueryPart extends EntityViewConnectingQueryPart { + + public EntityViewOrQueryPart(boolean first) { + super(first); + } + + @Override + protected EntityViewQueryPart build(String queryPart, String method, EntityViewRepositoryComponent repo) { + String[] andParts = splitByKeyword(queryPart, "And"); + boolean first = true; + for (String and : andParts) { + EntityViewAndQueryPart andPart = new EntityViewAndQueryPart(first); + first = false; + children.add(andPart.build(and, method, repo)); + } + return this; + } + + @Override + protected EntityViewQueryPart buildQuery(EntityViewQueryBuilderContext ctx) { + if (!first) { + ctx.getWhereExpressionBuilder().append(" or "); + } + buildQueryForChildren(ctx); + return this; + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewOrderByQueryPart.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewOrderByQueryPart.java new file mode 100644 index 0000000000..373c3ca07a --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewOrderByQueryPart.java @@ -0,0 +1,137 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.builder.part; + +import com.blazebit.persistence.impl.deltaspikedata.impl.builder.EntityViewQueryBuilderContext; +import com.blazebit.persistence.impl.deltaspikedata.impl.meta.EntityViewRepositoryComponent; + +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import static org.apache.deltaspike.core.util.StringUtils.isNotEmpty; +import static org.apache.deltaspike.data.impl.util.QueryUtils.splitByKeyword; +import static org.apache.deltaspike.data.impl.util.QueryUtils.uncapitalize; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.builder.part.OrderByQueryPart} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +class EntityViewOrderByQueryPart extends EntityViewBasePropertyQueryPart { + private static final String KEYWORD_ASC = "Asc"; + private static final String KEYWORD_DESC = "Desc"; + + private final List attributes = new LinkedList<>(); + + @Override + protected EntityViewQueryPart build(String queryPart, String method, EntityViewRepositoryComponent repo) { + Set collect = new LinkedHashSet(); + List ascSplit = new LinkedList(); + split(queryPart, KEYWORD_ASC, ascSplit); + for (String ascPart : ascSplit) { + split(ascPart, KEYWORD_DESC, collect); + } + for (String part : collect) { + EntityViewOrderByQueryPart.Direction direction = EntityViewOrderByQueryPart.Direction.fromQueryPart(part); + String attribute = direction.attribute(part); + validate(attribute, method, repo); + attributes.add(new EntityViewOrderByQueryPart.OrderByQueryAttribute(attribute, direction)); + } + return this; + } + + @Override + protected EntityViewOrderByQueryPart buildQuery(EntityViewQueryBuilderContext ctx) { + for (Iterator it = attributes.iterator(); it.hasNext(); ) { + it.next().buildQuery(ctx); + } + return this; + } + + private void split(String queryPart, String keyword, Collection result) { + for (String part : splitByKeyword(queryPart, keyword)) { + String attribute = !part.endsWith(KEYWORD_DESC) && !part.endsWith(KEYWORD_ASC) ? part + keyword : part; + result.add(attribute); + } + } + + private class OrderByQueryAttribute { + + private final String attribute; + private final EntityViewOrderByQueryPart.Direction direction; + + public OrderByQueryAttribute(String attribute, EntityViewOrderByQueryPart.Direction direction) { + this.attribute = attribute; + this.direction = direction; + } + + protected void buildQuery(EntityViewQueryBuilderContext ctx) { + switch (direction) { + case DEFAULT: + case ASC: + ctx.getCriteriaBuilder().orderByAsc(rewriteSeparator(attribute)); + break; + case DESC: + ctx.getCriteriaBuilder().orderByDesc(rewriteSeparator(attribute)); + break; + } + } + } + + private enum Direction { + ASC(KEYWORD_ASC), + DESC(KEYWORD_DESC), + DEFAULT(""); + + private final String postfix; + + Direction(String postfix) { + this.postfix = postfix; + } + + public boolean endsWith(String queryPart) { + return isNotEmpty(postfix) ? queryPart.endsWith(postfix) : false; + } + + public String attribute(String queryPart) { + String attribute = isNotEmpty(postfix) ? + queryPart.substring(0, queryPart.indexOf(postfix)) : + queryPart; + return uncapitalize(attribute); + } + + public String queryDirection() { + return isNotEmpty(postfix) ? " " + postfix.toLowerCase() : ""; + } + + public static EntityViewOrderByQueryPart.Direction fromQueryPart(String queryPart) { + for (EntityViewOrderByQueryPart.Direction dir : values()) { + if (dir.endsWith(queryPart)) { + return dir; + } + } + return DEFAULT; + } + + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewPropertyQueryPart.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewPropertyQueryPart.java new file mode 100644 index 0000000000..14dda07a86 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewPropertyQueryPart.java @@ -0,0 +1,68 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.builder.part; + +import com.blazebit.persistence.impl.deltaspikedata.impl.builder.EntityViewQueryBuilderContext; +import com.blazebit.persistence.impl.deltaspikedata.impl.meta.EntityViewRepositoryComponent; + +import java.text.MessageFormat; + +import static org.apache.deltaspike.data.impl.util.QueryUtils.uncapitalize; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.builder.part.PropertyQueryPart} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +class EntityViewPropertyQueryPart extends EntityViewBasePropertyQueryPart { + + private String name; + private QueryOperator comparator; + + @Override + protected EntityViewQueryPart build(String queryPart, String method, EntityViewRepositoryComponent repo) { + comparator = QueryOperator.Equal; + name = uncapitalize(queryPart); + for (QueryOperator comp : QueryOperator.values()) { + if (queryPart.endsWith(comp.getExpression())) { + comparator = comp; + name = uncapitalize(queryPart.substring(0, queryPart.indexOf(comp.getExpression()))); + break; + } + } + validate(name, method, repo); + name = rewriteSeparator(name); + return this; + } + + @Override + protected EntityViewQueryPart buildQuery(EntityViewQueryBuilderContext ctx) { + String[] args = new String[comparator.getParamNum() + 1]; + args[0] = name; + for (int i = 1; i < args.length; i++) { + args[i] = getAndIncrementParamName(ctx); + } + ctx.getWhereExpressionBuilder().append(MessageFormat.format(comparator.getJpql(), (Object[]) args)); + return this; + } + + private String getAndIncrementParamName(EntityViewQueryBuilderContext ctx) { + return ":methodArg" + ctx.increment(); + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewQueryPart.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewQueryPart.java new file mode 100644 index 0000000000..9fb82f6317 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewQueryPart.java @@ -0,0 +1,44 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.builder.part; + +import com.blazebit.persistence.impl.deltaspikedata.impl.builder.EntityViewQueryBuilderContext; +import com.blazebit.persistence.impl.deltaspikedata.impl.meta.EntityViewRepositoryComponent; + +import java.util.LinkedList; +import java.util.List; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.builder.part.QueryPart} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +abstract class EntityViewQueryPart { + protected List children = new LinkedList<>(); + + protected abstract EntityViewQueryPart build(String queryPart, String method, EntityViewRepositoryComponent repo); + + protected abstract EntityViewQueryPart buildQuery(EntityViewQueryBuilderContext ctx); + + protected void buildQueryForChildren(EntityViewQueryBuilderContext ctx) { + for (EntityViewQueryPart child : children) { + child.buildQuery(ctx); + } + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewQueryRoot.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewQueryRoot.java new file mode 100644 index 0000000000..da44f31e01 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/EntityViewQueryRoot.java @@ -0,0 +1,101 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.builder.part; + +import com.blazebit.persistence.CriteriaBuilder; +import com.blazebit.persistence.impl.deltaspikedata.impl.builder.EntityViewQueryBuilderContext; +import com.blazebit.persistence.impl.deltaspikedata.impl.meta.EntityViewRepositoryComponent; +import org.apache.deltaspike.data.impl.builder.MethodExpressionException; +import org.apache.deltaspike.data.impl.meta.MethodPrefix; + +import static org.apache.deltaspike.data.impl.util.QueryUtils.splitByKeyword; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.builder.part.QueryRoot} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +public class EntityViewQueryRoot extends EntityViewQueryPart { + public static final EntityViewQueryRoot UNKNOWN_ROOT = new EntityViewQueryRoot(null, new MethodPrefix("", null)); + + private final Class entityClass; + private final MethodPrefix methodPrefix; + + protected EntityViewQueryRoot(Class entityClass, MethodPrefix methodPrefix) { + this.entityClass = entityClass; + this.methodPrefix = methodPrefix; + } + + public static EntityViewQueryRoot create(String method, EntityViewRepositoryComponent repo, MethodPrefix prefix) { + EntityViewQueryRoot root = new EntityViewQueryRoot(repo.getEntityClass(), prefix); + root.build(method, method, repo); + return root; + } + + @Override + protected EntityViewQueryPart build(String queryPart, String method, EntityViewRepositoryComponent repo) { + String[] orderByParts = splitByKeyword(queryPart, "OrderBy"); + if (hasQueryConditions(orderByParts)) { + String[] orParts = splitByKeyword(removePrefix(orderByParts[0]), "Or"); + boolean first = true; + for (String or : orParts) { + EntityViewOrQueryPart orPart = new EntityViewOrQueryPart(first); + first = false; + children.add(orPart.build(or, method, repo)); + } + } + if (orderByParts.length > 1) { + EntityViewOrderByQueryPart orderByPart = new EntityViewOrderByQueryPart(); + children.add(orderByPart.build(orderByParts[1], method, repo)); + } + if (children.isEmpty()) { + throw new MethodExpressionException(repo.getRepositoryClass(), method); + } + return this; + } + + @Override + protected EntityViewQueryPart buildQuery(EntityViewQueryBuilderContext ctx) { + if (methodPrefix.isDelete()) { + throw new UnsupportedOperationException("Delete queries not supported in entity view repositories"); + } else { + ctx.getCriteriaBuilder().from(entityClass); + } + buildQueryForChildren(ctx); + if (ctx.getWhereExpressionBuilder().length() > 0) { + ctx.getCriteriaBuilder().whereExpression(ctx.getWhereExpressionBuilder().toString()); + } + return this; + } + + public void apply(CriteriaBuilder cb) { + EntityViewQueryBuilderContext ctx = new EntityViewQueryBuilderContext(cb); + buildQuery(ctx); + } + + private boolean hasQueryConditions(String[] orderByParts) { + String orderByPart = orderByParts[0]; + String prefix = methodPrefix.getPrefix(); + return !prefix.equals(orderByPart) && !orderByPart.matches(prefix); + } + + private String removePrefix(String queryPart) { + return methodPrefix.removePrefix(queryPart); + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/QueryOperator.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/QueryOperator.java new file mode 100644 index 0000000000..dd94d0e125 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/part/QueryOperator.java @@ -0,0 +1,82 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.builder.part; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.builder.QueryOperator} but altered + * LikeIgnoreCase to use upper on both sides. + * + * @author Moritz Becker + * @since 1.2.0 + */ +public enum QueryOperator { + + LessThan("LessThan", "{0} < {1}"), + LessThanEquals("LessThanEquals", "{0} <= {1}"), + GreaterThan("GreaterThan", "{0} > {1}"), + GreaterThanEquals("GreaterThanEquals", "{0} >= {1}"), + Like("Like", "{0} like {1}"), + LikeIgnoreCase("LikeIgnoreCase", "upper({0}) like upper({1})", true), + NotEqual("NotEqual", "{0} <> {1}"), + NotEqualIgnoreCase("NotEqualIgnoreCase", "upper({0}) <> upper({1})"), + Equal("Equal", "{0} = {1}"), + EqualIgnoreCase("EqualIgnoreCase", "upper({0}) = upper({1})"), + IgnoreCase("IgnoreCase", "upper({0}) = upper({1})"), + Between("Between", "{0} between {1} and {2}", 2), + IsNotNull("IsNotNull", "{0} IS NOT NULL", 0), + IsNull("IsNull", "{0} IS NULL", 0); + + private final String expression; + private final String jpql; + private final int paramNum; + private final boolean caseInsensitive; + + private QueryOperator(String expression, String jpql) { + this(expression, jpql, 1); + } + + private QueryOperator(String expression, String jpql, boolean caseInsensitive) { + this(expression, jpql, 1, caseInsensitive); + } + + private QueryOperator(String expression, String jpql, int paramNum) { + this(expression, jpql, paramNum, false); + } + + private QueryOperator(String expression, String jpql, int paramNum, boolean caseInsensitive) { + this.expression = expression; + this.jpql = jpql; + this.paramNum = paramNum; + this.caseInsensitive = caseInsensitive; + } + + public String getExpression() { + return expression; + } + + public String getJpql() { + return jpql; + } + + public int getParamNum() { + return paramNum; + } + + public boolean isCaseInsensitive() { + return caseInsensitive; + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/postprocessor/FlushModePostProcessor.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/postprocessor/FlushModePostProcessor.java new file mode 100644 index 0000000000..c6cb352993 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/postprocessor/FlushModePostProcessor.java @@ -0,0 +1,45 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.builder.postprocessor; + +import com.blazebit.persistence.impl.deltaspikedata.impl.handler.EntityViewCdiQueryInvocationContext; +import com.blazebit.persistence.impl.deltaspikedata.impl.handler.EntityViewJpaQueryPostProcessor; + +import javax.persistence.FlushModeType; +import javax.persistence.Query; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.builder.postprocessor.FlushModePostProcessor} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +public class FlushModePostProcessor implements EntityViewJpaQueryPostProcessor { + + private final FlushModeType flushMode; + + public FlushModePostProcessor(FlushModeType flushMode) { + this.flushMode = flushMode; + } + + @Override + public Query postProcess(EntityViewCdiQueryInvocationContext context, Query query) { + query.setFlushMode(flushMode); + return query; + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/postprocessor/HintPostProcessor.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/postprocessor/HintPostProcessor.java new file mode 100644 index 0000000000..2f18beef72 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/postprocessor/HintPostProcessor.java @@ -0,0 +1,46 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.builder.postprocessor; + +import com.blazebit.persistence.impl.deltaspikedata.impl.handler.EntityViewCdiQueryInvocationContext; +import com.blazebit.persistence.impl.deltaspikedata.impl.handler.EntityViewJpaQueryPostProcessor; + +import javax.persistence.Query; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.builder.postprocessor.HintPostProcessor} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +public class HintPostProcessor implements EntityViewJpaQueryPostProcessor { + + private final String hintName; + private final Object hintValue; + + public HintPostProcessor(String hintName, Object hintValue) { + this.hintName = hintName; + this.hintValue = hintValue; + } + + @Override + public Query postProcess(EntityViewCdiQueryInvocationContext context, Query query) { + query.setHint(hintName, hintValue); + return query; + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/postprocessor/LockModePostProcessor.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/postprocessor/LockModePostProcessor.java new file mode 100644 index 0000000000..73ef6d4403 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/postprocessor/LockModePostProcessor.java @@ -0,0 +1,45 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.builder.postprocessor; + +import com.blazebit.persistence.impl.deltaspikedata.impl.handler.EntityViewCdiQueryInvocationContext; +import com.blazebit.persistence.impl.deltaspikedata.impl.handler.EntityViewJpaQueryPostProcessor; + +import javax.persistence.LockModeType; +import javax.persistence.Query; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.builder.postprocessor.LockModePostProcessor} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +public class LockModePostProcessor implements EntityViewJpaQueryPostProcessor { + + private final LockModeType lockMode; + + public LockModePostProcessor(LockModeType lockMode) { + this.lockMode = lockMode; + } + + @Override + public Query postProcess(EntityViewCdiQueryInvocationContext context, Query query) { + query.setLockMode(lockMode); + return query; + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/postprocessor/OrderByCriteriaBuilderPostProcessor.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/postprocessor/OrderByCriteriaBuilderPostProcessor.java new file mode 100644 index 0000000000..3282c93e45 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/postprocessor/OrderByCriteriaBuilderPostProcessor.java @@ -0,0 +1,63 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.builder.postprocessor; + +import com.blazebit.persistence.FullQueryBuilder; +import com.blazebit.persistence.impl.deltaspikedata.impl.handler.CriteriaBuilderPostProcessor; +import org.apache.deltaspike.data.impl.builder.OrderDirection; + +import javax.persistence.metamodel.SingularAttribute; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.builder.postprocessor.OrderByQueryStringPostProcessor} + * but was modified to work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +public class OrderByCriteriaBuilderPostProcessor implements CriteriaBuilderPostProcessor { + + private final String attribute; + private OrderDirection direction; + + public OrderByCriteriaBuilderPostProcessor(SingularAttribute attribute, OrderDirection direction) { + this.attribute = attribute.getName(); + this.direction = direction; + } + + public OrderByCriteriaBuilderPostProcessor(String attribute, OrderDirection direction) { + this.attribute = attribute; + this.direction = direction; + } + + @Override + public FullQueryBuilder postProcess(FullQueryBuilder criteriaBuilder) { + return criteriaBuilder.orderBy(attribute, direction == OrderDirection.ASC, false); + } + + public boolean matches(SingularAttribute attribute) { + return matches(attribute.getName()); + } + + public boolean matches(String attribute) { + return this.attribute.equals(attribute); + } + + public void changeDirection() { + direction = direction.change(); + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/postprocessor/PaginationCriteriaBuilderPostProcessor.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/postprocessor/PaginationCriteriaBuilderPostProcessor.java new file mode 100644 index 0000000000..5754f89a3d --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/postprocessor/PaginationCriteriaBuilderPostProcessor.java @@ -0,0 +1,40 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.builder.postprocessor; + +import com.blazebit.persistence.FullQueryBuilder; +import com.blazebit.persistence.impl.deltaspikedata.impl.handler.CriteriaBuilderPostProcessor; + +/** + * @author Moritz Becker + * @since 1.2.0 + */ +public class PaginationCriteriaBuilderPostProcessor implements CriteriaBuilderPostProcessor { + + private final int firstResult; + private final int maxResults; + + public PaginationCriteriaBuilderPostProcessor(int firstResult, int maxResults) { + this.firstResult = firstResult; + this.maxResults = maxResults; + } + + @Override + public FullQueryBuilder postProcess(FullQueryBuilder queryBuilder) { + return queryBuilder.page(firstResult, maxResults); + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/result/EntityViewDefaultQueryResult.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/result/EntityViewDefaultQueryResult.java new file mode 100644 index 0000000000..cec5ded58e --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/builder/result/EntityViewDefaultQueryResult.java @@ -0,0 +1,295 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.builder.result; + +import com.blazebit.persistence.impl.deltaspikedata.impl.builder.EntityViewQueryBuilder; +import com.blazebit.persistence.impl.deltaspikedata.impl.builder.postprocessor.FlushModePostProcessor; +import com.blazebit.persistence.impl.deltaspikedata.impl.builder.postprocessor.HintPostProcessor; +import com.blazebit.persistence.impl.deltaspikedata.impl.builder.postprocessor.LockModePostProcessor; +import com.blazebit.persistence.impl.deltaspikedata.impl.builder.postprocessor.OrderByCriteriaBuilderPostProcessor; +import com.blazebit.persistence.impl.deltaspikedata.impl.builder.postprocessor.PaginationCriteriaBuilderPostProcessor; +import com.blazebit.persistence.impl.deltaspikedata.impl.handler.CriteriaBuilderPostProcessor; +import com.blazebit.persistence.impl.deltaspikedata.impl.handler.EntityViewCdiQueryInvocationContext; +import org.apache.deltaspike.data.api.QueryResult; +import org.apache.deltaspike.data.impl.builder.OrderDirection; + +import javax.persistence.FlushModeType; +import javax.persistence.LockModeType; +import javax.persistence.NoResultException; +import javax.persistence.Query; +import javax.persistence.metamodel.SingularAttribute; +import java.util.Iterator; +import java.util.List; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.builder.result.DefaultQueryResult} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +public class EntityViewDefaultQueryResult implements QueryResult { + + private final EntityViewQueryBuilder builder; + private final EntityViewCdiQueryInvocationContext context; + + private int page = 0; + private int pageSize = 10; + private int firstResult = 0; + private int maxResults = -1; + + public EntityViewDefaultQueryResult(EntityViewQueryBuilder builder, EntityViewCdiQueryInvocationContext context) { + this.builder = builder; + this.context = context; + } + + @Override + public QueryResult orderAsc(SingularAttribute attribute) { + return orderAsc(attribute, true); + } + + @Override + public QueryResult orderAsc(SingularAttribute attribute, boolean appendEntityName) { + context.addCriteriaBuilderPostProcessor(new OrderByCriteriaBuilderPostProcessor(attribute, OrderDirection.ASC)); + return this; + } + + @Override + public QueryResult orderAsc(String attribute) { + return orderAsc(attribute, true); + } + + @Override + public QueryResult orderAsc(String attribute, boolean appendEntityName) { + context.addCriteriaBuilderPostProcessor(new OrderByCriteriaBuilderPostProcessor(attribute, OrderDirection.ASC)); + return this; + } + + @Override + public QueryResult orderDesc(SingularAttribute attribute) { + return orderDesc(attribute, true); + } + + @Override + public QueryResult orderDesc(SingularAttribute attribute, boolean appendEntityName) { + context.addCriteriaBuilderPostProcessor(new OrderByCriteriaBuilderPostProcessor(attribute, OrderDirection.DESC)); + return this; + } + + @Override + public QueryResult orderDesc(String attribute) { + return orderDesc(attribute, true); + } + + @Override + public QueryResult orderDesc(String attribute, boolean appendEntityName) { + context.addCriteriaBuilderPostProcessor(new OrderByCriteriaBuilderPostProcessor(attribute, OrderDirection.DESC)); + return this; + } + + @Override + public QueryResult changeOrder(final SingularAttribute attribute) { + changeOrder(new EntityViewDefaultQueryResult.ChangeOrder() { + @Override + public boolean matches(OrderByCriteriaBuilderPostProcessor orderBy) { + return orderBy.matches(attribute); + } + + @Override + public void addDefault() { + orderAsc(attribute); + } + }); + return this; + } + + @Override + public QueryResult changeOrder(final String attribute) { + changeOrder(new EntityViewDefaultQueryResult.ChangeOrder() { + @Override + public boolean matches(OrderByCriteriaBuilderPostProcessor orderBy) { + return orderBy.matches(attribute); + } + + @Override + public void addDefault() { + orderAsc(attribute); + } + }); + return this; + } + + @Override + public QueryResult clearOrder() { + for (Iterator it = context.getCriteriaBuilderPostProcessors().iterator(); it.hasNext(); ) { + if (it.next() instanceof OrderByCriteriaBuilderPostProcessor) { + it.remove(); + } + } + return this; + } + + @Override + public QueryResult maxResults(int max) { + maxResults = max; + pageSize = max; + return this; + } + + @Override + public QueryResult firstResult(int first) { + firstResult = first; + return this; + } + + private void updatePaginationPostProcessor() { + clearPagination(); + if (isFirstResultSet() || isMaxResultsSet()) { + context.addCriteriaBuilderPostProcessor(new PaginationCriteriaBuilderPostProcessor(firstResult, maxResults < 0 ? Integer.MAX_VALUE : maxResults)); + } + } + + private void clearPagination() { + Iterator iterator = context.getCriteriaBuilderPostProcessors().iterator(); + while (iterator.hasNext()) { + if (iterator.next() instanceof PaginationCriteriaBuilderPostProcessor) { + iterator.remove(); + } + } + } + + private boolean isFirstResultSet() { + return firstResult > 0; + } + + private boolean isMaxResultsSet() { + return maxResults >= 0; + } + + @Override + public QueryResult lockMode(LockModeType lockMode) { + context.addJpaQueryPostProcessor(new LockModePostProcessor(lockMode)); + return this; + } + + @Override + public QueryResult flushMode(FlushModeType flushMode) { + context.addJpaQueryPostProcessor(new FlushModePostProcessor(flushMode)); + return this; + } + + @Override + public QueryResult hint(String hint, Object value) { + context.addJpaQueryPostProcessor(new HintPostProcessor(hint, value)); + return this; + } + + @Override + @SuppressWarnings("unchecked") + public List getResultList() { + updatePaginationPostProcessor(); + return ((Query) builder.executeQuery(context)).getResultList(); + } + + @Override + @SuppressWarnings("unchecked") + public T getSingleResult() { + updatePaginationPostProcessor(); + return (T) ((Query) builder.executeQuery(context)).getSingleResult(); + } + + @Override + public T getOptionalResult() { + try { + return getSingleResult(); + } catch (NoResultException e) { + return null; + } + } + + @Override + public T getAnyResult() { + List queryResult = getResultList(); + return !queryResult.isEmpty() ? queryResult.get(0) : null; + } + + @Override + public long count() { + throw new UnsupportedOperationException("Count rewrite not supported for entity view repositories"); + } + + @Override + public QueryResult withPageSize(int pageSize) { + return maxResults(pageSize); + } + + @Override + public QueryResult toPage(int page) { + this.page = page; + return firstResult(pageSize * page); + } + + @Override + public QueryResult nextPage() { + page = page + 1; + return firstResult(pageSize * page); + } + + @Override + public QueryResult previousPage() { + page = page > 0 ? page - 1 : page; + return firstResult(pageSize * page); + } + + @Override + public int countPages() { + return (int) Math.ceil((double) count() / pageSize); + } + + @Override + public int currentPage() { + return page; + } + + @Override + public int pageSize() { + return pageSize; + } + + private QueryResult changeOrder(EntityViewDefaultQueryResult.ChangeOrder changeOrder) { + for (CriteriaBuilderPostProcessor processor : context.getCriteriaBuilderPostProcessors()) { + if (processor instanceof OrderByCriteriaBuilderPostProcessor) { + OrderByCriteriaBuilderPostProcessor orderBy = (OrderByCriteriaBuilderPostProcessor) processor; + if (changeOrder.matches(orderBy)) { + orderBy.changeDirection(); + return this; + } + } + } + changeOrder.addDefault(); + return this; + } + + private abstract static class ChangeOrder { + + public abstract boolean matches(OrderByCriteriaBuilderPostProcessor orderBy); + + public abstract void addDefault(); + + } + +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/criteria/QueryCriteria.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/criteria/QueryCriteria.java new file mode 100644 index 0000000000..f42ef0bb88 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/criteria/QueryCriteria.java @@ -0,0 +1,124 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.criteria; + +import com.blazebit.persistence.CriteriaBuilderFactory; +import com.blazebit.persistence.criteria.BlazeCriteriaBuilder; +import com.blazebit.persistence.criteria.BlazeCriteriaQuery; +import com.blazebit.persistence.criteria.impl.BlazeCriteria; +import com.blazebit.persistence.view.EntityViewManager; +import com.blazebit.persistence.view.EntityViewSetting; +import org.apache.deltaspike.data.api.criteria.Criteria; +import org.apache.deltaspike.data.api.criteria.QuerySelection; + +import javax.persistence.EntityManager; +import javax.persistence.TypedQuery; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.From; +import javax.persistence.criteria.JoinType; +import javax.persistence.criteria.Predicate; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.criteria.QueryCriteria} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +public class QueryCriteria extends org.apache.deltaspike.data.impl.criteria.QueryCriteria { + + private static final Logger LOG = Logger.getLogger(QueryCriteria.class.getName()); + + private final Class entityClass; + private final EntityManager entityManager; + private final Class resultClass; + private final CriteriaBuilderFactory criteriaBuilderFactory; + private final EntityViewManager entityViewManager; + + public QueryCriteria(Class entityClass, Class resultClass, EntityManager entityManager, CriteriaBuilderFactory criteriaBuilderFactory, EntityViewManager entityViewManager) { + this(entityClass, resultClass, entityManager, null, criteriaBuilderFactory, entityViewManager); + } + + public QueryCriteria(Class entityClass, Class resultClass, EntityManager entityManager, JoinType joinType, CriteriaBuilderFactory criteriaBuilderFactory, EntityViewManager entityViewManager) { + super(entityClass, resultClass, entityManager, joinType); + this.entityClass = entityClass; + this.resultClass = resultClass; + this.entityManager = entityManager; + this.criteriaBuilderFactory = criteriaBuilderFactory; + this.entityViewManager = entityViewManager; + } + + @Override + public TypedQuery createQuery() { + try { + BlazeCriteriaBuilder builder = BlazeCriteria.get(entityManager, criteriaBuilderFactory); + BlazeCriteriaQuery query = builder.createQuery(entityClass); + From root = query.from(entityClass); + List predicates = predicates(builder, root); + query.distinct(isDistinct()); + if (!predicates.isEmpty()) { + query.where(predicates.toArray(new Predicate[predicates.size()])); + } + applyProcessors(query, builder, root); + return entityViewManager.applySetting(EntityViewSetting.create(resultClass), query.createCriteriaBuilder()).getQuery(); + } catch (RuntimeException e) { + LOG.log(Level.SEVERE, "Exception while creating JPA query", e); + throw e; + } + } + + private void applyProcessors(CriteriaQuery query, CriteriaBuilder builder, From from) { + try { + Method applyProcessorsMethod = org.apache.deltaspike.data.impl.criteria.QueryCriteria.class.getDeclaredMethod("applyProcessors", CriteriaQuery.class, CriteriaBuilder.class, From.class); + applyProcessorsMethod.setAccessible(true); + applyProcessorsMethod.invoke(this, query, builder, from); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + private boolean isDistinct() { + try { + Field distinctField = org.apache.deltaspike.data.impl.criteria.QueryCriteria.class.getDeclaredField("distinct"); + distinctField.setAccessible(true); + return distinctField.getBoolean(this); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + @Override + public Criteria select(Class resultClass, QuerySelection... selection) { + throw selectionNotSupported(); + } + + @Override + public Criteria select(QuerySelection... selection) { + throw selectionNotSupported(); + } + + private RuntimeException selectionNotSupported() { + return new UnsupportedOperationException("Selection not supported for entity view repositories"); + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/CriteriaBuilderPostProcessor.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/CriteriaBuilderPostProcessor.java new file mode 100644 index 0000000000..61ebe053ad --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/CriteriaBuilderPostProcessor.java @@ -0,0 +1,28 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.handler; + +import com.blazebit.persistence.FullQueryBuilder; + +/** + * @author Moritz Becker + * @since 1.2.0 + */ +public interface CriteriaBuilderPostProcessor { + + FullQueryBuilder postProcess(FullQueryBuilder queryString); +} diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/CriteriaSupportHandler.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/CriteriaSupportHandler.java new file mode 100644 index 0000000000..8bb7843368 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/CriteriaSupportHandler.java @@ -0,0 +1,73 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.handler; + +import com.balzebit.persistence.impl.deltaspikedata.api.CriteriaSupport; +import com.blazebit.persistence.CriteriaBuilderFactory; +import com.blazebit.persistence.impl.deltaspikedata.impl.criteria.QueryCriteria; +import com.blazebit.persistence.view.EntityViewManager; +import org.apache.deltaspike.data.api.criteria.Criteria; + +import javax.enterprise.context.Dependent; +import javax.inject.Inject; +import javax.persistence.EntityManager; +import javax.persistence.criteria.JoinType; + +/** + * @author Moritz Becker + * @since 1.2.0 + */ +@Dependent +public class CriteriaSupportHandler implements CriteriaSupport, EntityViewDelegateQueryHandler { + + @Inject + @EntityViewContext + private EntityViewCdiQueryInvocationContext context; + @Inject + private CriteriaBuilderFactory criteriaBuilderFactory; + @Inject + private EntityViewManager entityViewManager; + + @SuppressWarnings("unchecked") + private Class getEntityClass() { + return (Class) context.getEntityClass(); + } + + @SuppressWarnings("unchecked") + private Class getEntityViewClass() { + return (Class) context.getEntityViewClass(); + } + + private EntityManager getEntityManager() { + return context.getEntityManager(); + } + + @Override + public Criteria criteria() { + return new QueryCriteria(getEntityClass(), getEntityViewClass(), getEntityManager(), criteriaBuilderFactory, entityViewManager); + } + + @Override + public Criteria where(Class clazz) { + return new QueryCriteria(clazz, getEntityViewClass(), getEntityManager(), criteriaBuilderFactory, entityViewManager); + } + + @Override + public Criteria where(Class clazz, JoinType joinType) { + return new QueryCriteria(clazz, getEntityViewClass(), getEntityManager(), joinType, criteriaBuilderFactory, entityViewManager); + } +} diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityManagerRefLookup.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityManagerRefLookup.java new file mode 100644 index 0000000000..6e31927216 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityManagerRefLookup.java @@ -0,0 +1,122 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.handler; + +import com.blazebit.persistence.impl.deltaspikedata.impl.meta.EntityViewRepositoryComponent; +import org.apache.deltaspike.core.api.provider.BeanManagerProvider; +import org.apache.deltaspike.core.api.provider.BeanProvider; +import org.apache.deltaspike.data.impl.handler.EntityManagerRef; +import org.apache.deltaspike.jpa.spi.entitymanager.ActiveEntityManagerHolder; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.inject.spi.Bean; +import javax.enterprise.inject.spi.BeanManager; +import javax.inject.Inject; +import javax.persistence.EntityManager; +import java.util.Set; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.handler.EntityManagerRefLookup} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +@ApplicationScoped +public class EntityManagerRefLookup { + @Inject + private ActiveEntityManagerHolder activeEntityManagerHolder; + + private volatile Boolean globalEntityManagerInitialized; + private boolean globalEntityManagerIsNormalScope; + private EntityManager globalEntityManager; + + private void lazyInitGlobalEntityManager() { + if (this.globalEntityManagerInitialized == null) { + initGlobalEntityManager(); + } + } + + private synchronized void initGlobalEntityManager() { + // switch into paranoia mode + if (this.globalEntityManagerInitialized == null) { + this.globalEntityManagerInitialized = true; + + BeanManager beanManager = BeanManagerProvider.getInstance().getBeanManager(); + Set> beans = beanManager.getBeans(EntityManager.class); + Bean bean = beanManager.resolve(beans); + + if (bean == null) { + throw new IllegalStateException("Could not find EntityManager with default qualifier."); + } + + globalEntityManagerIsNormalScope = beanManager.isNormalScope(bean.getScope()); + if (globalEntityManagerIsNormalScope) { + globalEntityManager = (EntityManager) beanManager.getReference(bean, + EntityManager.class, + beanManager.createCreationalContext(bean)); + } + } + } + + public EntityManagerRef lookupReference(final EntityViewRepositoryComponent repository) { + EntityManagerRef ref = new EntityManagerRef(); + + if (repository.hasEntityManagerResolver()) { + ref.setEntityManagerResolverClass( + repository.getEntityManagerResolverClass()); + + if (repository.isEntityManagerResolverIsNormalScope()) { + ref.setEntityManagerResolver( + BeanProvider.getContextualReference(ref.getEntityManagerResolverClass())); + } else { + ref.setEntityManagerResolverDependentProvider( + BeanProvider.getDependent(ref.getEntityManagerResolverClass())); + + ref.setEntityManagerResolver( + ref.getEntityManagerResolverDependentProvider().get()); + } + + ref.setEntityManager( + ref.getEntityManagerResolver().resolveEntityManager()); + } else { + if (activeEntityManagerHolder.isSet()) { + ref.setEntityManager( + activeEntityManagerHolder.get()); + + // TODO should we really not apply the FlushMode on the active EntityManager? + return ref; + } else { + lazyInitGlobalEntityManager(); + if (globalEntityManagerIsNormalScope) { + ref.setEntityManager(globalEntityManager); + } else { + ref.setEntityManagerDependentProvider( + BeanProvider.getDependent(EntityManager.class)); + ref.setEntityManager( + ref.getEntityManagerDependentProvider().get()); + } + } + } + + if (repository.hasEntityManagerFlushMode()) { + ref.getEntityManager().setFlushMode(repository.getEntityManagerFlushMode()); + } + + return ref; + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewAwareQueryHandler.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewAwareQueryHandler.java new file mode 100644 index 0000000000..b26065438d --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewAwareQueryHandler.java @@ -0,0 +1,119 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.handler; + +import com.blazebit.persistence.CriteriaBuilderFactory; +import com.blazebit.persistence.impl.deltaspikedata.impl.builder.EntityViewAwareQueryBuilderFactory; +import com.blazebit.persistence.impl.deltaspikedata.impl.builder.EntityViewQueryBuilder; +import com.blazebit.persistence.impl.deltaspikedata.impl.meta.EntityViewRepositoryComponent; +import com.blazebit.persistence.impl.deltaspikedata.impl.meta.EntityViewRepositoryComponents; +import com.blazebit.persistence.impl.deltaspikedata.impl.meta.EntityViewRepositoryMethod; +import com.blazebit.persistence.view.EntityViewManager; +import org.apache.deltaspike.core.api.lifecycle.Initialized; +import org.apache.deltaspike.core.util.ProxyUtils; +import org.apache.deltaspike.data.api.QueryInvocationException; +import org.apache.deltaspike.data.api.Repository; +import org.apache.deltaspike.data.impl.handler.EntityManagerRef; +import org.apache.deltaspike.data.impl.handler.QueryHandler; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.inject.Specializes; +import javax.inject.Inject; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceException; +import java.lang.reflect.Method; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * @author Moritz Becker + * @since 1.2.0 + */ +@Repository +@Specializes +@ApplicationScoped +public class EntityViewAwareQueryHandler extends QueryHandler { + private static final Logger LOG = Logger.getLogger(QueryHandler.class.getName()); + + @Inject + @Initialized + private EntityViewRepositoryComponents components; + + @Inject + private EntityManagerRefLookup entityManagerRefLookup; + + @Inject + private EntityViewAwareQueryBuilderFactory queryBuilderFactory; + + @Inject + private EntityViewQueryRunner runner; + + @Inject + private EntityViewCdiQueryInvocationContextHolder contextHolder; + + @Inject + private CriteriaBuilderFactory criteriaBuilderFactory; + + @Inject + private EntityViewManager entityViewManager; + + @Override + public Object process(Object proxy, Method method, Object[] args) throws Throwable { + EntityViewCdiQueryInvocationContext queryContext = null; + EntityManagerRef entityManagerRef = null; + try { + List> candidates = ProxyUtils.getProxyAndBaseTypes(proxy.getClass()); + EntityViewRepositoryComponent repo; + try { + repo = components.lookupComponent(candidates); + } catch (RuntimeException e) { + return super.process(proxy, method, args); + } + EntityViewRepositoryMethod repoMethod = components.lookupMethod(repo, method); + + entityManagerRef = entityManagerRefLookup.lookupReference(repo); + queryContext = createContext(proxy, method, args, entityManagerRef.getEntityManager(), repoMethod); + contextHolder.set(queryContext); + + EntityViewQueryBuilder builder = queryBuilderFactory.build(repoMethod, queryContext); + return runner.executeQuery(builder, queryContext); + } catch (PersistenceException e) { + throw e; + } catch (Exception e) { + LOG.log(Level.FINEST, "Query execution error", e); + if (queryContext != null) { + throw new QueryInvocationException(e, queryContext); + } + throw new QueryInvocationException(e, proxy.getClass(), method); + } finally { + if (entityManagerRef != null) { + entityManagerRef.release(); + } + contextHolder.dispose(); + } + } + + private EntityViewCdiQueryInvocationContext createContext(Object proxy, Method method, + Object[] args, EntityManager entityManager, + EntityViewRepositoryMethod repoMethod) { + EntityViewCdiQueryInvocationContext queryContext = new EntityViewCdiQueryInvocationContext(proxy, method, args, repoMethod, + entityManager, entityViewManager, criteriaBuilderFactory); + queryContext.initMapper(); + return queryContext; + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewCdiQueryInvocationContext.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewCdiQueryInvocationContext.java new file mode 100644 index 0000000000..e8f01b377e --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewCdiQueryInvocationContext.java @@ -0,0 +1,274 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.handler; + +import com.blazebit.persistence.CriteriaBuilderFactory; +import com.blazebit.persistence.FullQueryBuilder; +import com.blazebit.persistence.impl.deltaspikedata.impl.meta.EntityViewRepositoryMethod; +import com.blazebit.persistence.impl.deltaspikedata.impl.param.Parameters; +import com.blazebit.persistence.view.EntityViewManager; +import org.apache.deltaspike.data.api.EntityGraph; +import org.apache.deltaspike.data.api.SingleResultType; +import org.apache.deltaspike.data.api.mapping.QueryInOutMapper; +import org.apache.deltaspike.data.impl.graph.EntityGraphHelper; +import org.apache.deltaspike.data.impl.util.bean.Destroyable; +import org.apache.deltaspike.data.spi.QueryInvocationContext; + +import javax.persistence.EntityManager; +import javax.persistence.LockModeType; +import javax.persistence.Query; +import javax.persistence.QueryHint; +import java.lang.reflect.Method; +import java.util.LinkedList; +import java.util.List; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.handler.CdiQueryInvocationContext} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +public class EntityViewCdiQueryInvocationContext implements QueryInvocationContext { + + private final EntityManager entityManager; + private final EntityViewManager entityViewManager; + private final CriteriaBuilderFactory criteriaBuilderFactory; + private final Parameters params; + private final Class entityClass; + private final Class entityViewClass; + private final Object proxy; + private final Method method; + private final Object[] args; + private final EntityViewRepositoryMethod repoMethod; + private final List criteriaBuilderPostProcessors; + private final List jpaPostProcessors; + private final List cleanup; + + public EntityViewCdiQueryInvocationContext(Object proxy, Method method, Object[] args, EntityViewRepositoryMethod repoMethod, + EntityManager entityManager, EntityViewManager entityViewManager, CriteriaBuilderFactory criteriaBuilderFactory) { + this.entityManager = entityManager; + this.entityViewManager = entityViewManager; + this.criteriaBuilderFactory = criteriaBuilderFactory; + this.args = args == null ? new Object[]{} : args; + this.params = Parameters.create(method, this.args, repoMethod); + this.proxy = proxy; + this.method = method; + this.repoMethod = repoMethod; + this.entityClass = repoMethod.getRepository().getEntityClass(); + this.entityViewClass = repoMethod.getRepository().getRepositoryEntity().getEntityViewClass(); + this.criteriaBuilderPostProcessors = new LinkedList(); + this.jpaPostProcessors = new LinkedList(); + this.cleanup = new LinkedList(); + } + + public void initMapper() { + if (hasQueryInOutMapper()) { + QueryInOutMapper mapper = getQueryInOutMapper(); + params.applyMapper(mapper); + for (int i = 0; i < args.length; i++) { + if (mapper.mapsParameter(args[i])) { + args[i] = mapper.mapParameter(args[i]); + } + } + } + } + + @Override + public EntityManager getEntityManager() { + return entityManager; + } + + public EntityViewManager getEntityViewManager() { + return entityViewManager; + } + + public CriteriaBuilderFactory getCriteriaBuilderFactory() { + return criteriaBuilderFactory; + } + + @Override + public boolean isNew(Object entity) { + throw new UnsupportedOperationException(); + } + + @Override + public Class getEntityClass() { + return entityClass; + } + + public Class getEntityViewClass() { + return entityViewClass; + } + + @Override + public Class getRepositoryClass() { + return repoMethod.getRepository().getRepositoryClass(); + } + + public Object proceed() throws Exception { + return method.invoke(proxy, args); + } + + @Override + public Method getMethod() { + return method; + } + + public Query applyRestrictions(Query query) { + Method method = getMethod(); + if (hasLockMode(method)) { + query.setLockMode(extractLockMode(method)); + } + if (hasQueryHints(method)) { + QueryHint[] hints = extractQueryHints(method); + for (QueryHint hint : hints) { + query.setHint(hint.name(), hint.value()); + } + } + applyEntityGraph(query, method); + return applyJpaQueryPostProcessors(query); + } + + public Object[] getMethodParameters() { + return args; + } + + public void addCriteriaBuilderPostProcessor(CriteriaBuilderPostProcessor postProcessor) { + criteriaBuilderPostProcessors.add(postProcessor); + } + + public List getCriteriaBuilderPostProcessors() { + return criteriaBuilderPostProcessors; + } + + public boolean hasCriteriaBuilderPostProcessors() { + return !criteriaBuilderPostProcessors.isEmpty(); + } + + public FullQueryBuilder applyCriteriaBuilderPostProcessors(FullQueryBuilder criteriaBuilder) { + FullQueryBuilder fullCb = criteriaBuilder; + for (CriteriaBuilderPostProcessor processor : criteriaBuilderPostProcessors) { + fullCb = processor.postProcess(fullCb); + } + return fullCb; + } + + public void addJpaQueryPostProcessor(EntityViewJpaQueryPostProcessor postProcessor) + { + jpaPostProcessors.add(postProcessor); + } + + public void removeJpaQueryPostProcessor(EntityViewJpaQueryPostProcessor postProcessor) + { + jpaPostProcessors.remove(postProcessor); + } + + public Query applyJpaQueryPostProcessors(Query query) + { + Query result = query; + for (EntityViewJpaQueryPostProcessor processor : jpaPostProcessors) + { + result = processor.postProcess(this, result); + } + return result; + } + + public void addDestroyable(Destroyable destroyable) { + cleanup.add(destroyable); + } + + public void cleanup() { + for (Destroyable destroy : cleanup) { + destroy.destroy(); + } + cleanup.clear(); + } + + public Object executeQuery(Query jpaQuery) { + return repoMethod.getQueryProcessor().executeQuery(jpaQuery, this); + } + + public Parameters getParams() { + return params; + } + + public EntityViewRepositoryMethod getRepositoryMethod() { + return repoMethod; + } + + public boolean hasQueryInOutMapper() { + return repoMethod.hasQueryInOutMapper(); + } + + public QueryInOutMapper getQueryInOutMapper() { + return repoMethod.getQueryInOutMapperInstance(this); + } + + public SingleResultType getSingleResultStyle() { + SingleResultType baseSingleResultType = repoMethod.getSingleResultStyle(); + if (repoMethod.isOptional() && baseSingleResultType == SingleResultType.JPA) { + return SingleResultType.OPTIONAL; + } else { + return baseSingleResultType; + } + } + + public Object getProxy() { + return proxy; + } + + private boolean hasLockMode(Method method) { + return extractLockMode(method) != null; + } + + private LockModeType extractLockMode(Method method) { + Class query = org.apache.deltaspike.data.api.Query.class; + if (method.isAnnotationPresent(query) && + method.getAnnotation(query).lock() != LockModeType.NONE) { + return method.getAnnotation(query).lock(); + } + return null; + } + + private QueryHint[] extractQueryHints(Method method) { + Class query = org.apache.deltaspike.data.api.Query.class; + if (method.isAnnotationPresent(query) && + method.getAnnotation(query).hints().length > 0) { + return method.getAnnotation(query).hints(); + } + return null; + } + + private boolean hasQueryHints(Method method) { + return extractQueryHints(method) != null; + } + + private void applyEntityGraph(Query query, Method method) { + EntityGraph entityGraphAnn = method.getAnnotation(EntityGraph.class); + if (entityGraphAnn == null) { + return; + } + + Object graph = EntityGraphHelper.getEntityGraph(getEntityManager(), entityClass, entityGraphAnn); + query.setHint(entityGraphAnn.type().getHintName(), graph); + } + + public boolean isOptional() { + return this.repoMethod.isOptional(); + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewCdiQueryInvocationContextHolder.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewCdiQueryInvocationContextHolder.java new file mode 100644 index 0000000000..20199fa18d --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewCdiQueryInvocationContextHolder.java @@ -0,0 +1,60 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.handler; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.inject.Produces; +import java.util.Stack; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.handler.CdiQueryContextHolder} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +@ApplicationScoped +public class EntityViewCdiQueryInvocationContextHolder { + + private final ThreadLocal> contextStack = new ThreadLocal<>(); + + public void set(EntityViewCdiQueryInvocationContext context) { + if (contextStack.get() == null) { + contextStack.set(new Stack()); + } + contextStack.get().push(context); + } + + @Produces + @EntityViewContext + public EntityViewCdiQueryInvocationContext get() { + if (contextStack.get() != null && !contextStack.get().isEmpty()) { + return contextStack.get().peek(); + } + return null; + } + + public void dispose() { + if (contextStack.get() != null && !contextStack.get().isEmpty()) { + EntityViewCdiQueryInvocationContext ctx = contextStack.get().pop(); + ctx.cleanup(); + } + if (contextStack.get() != null && contextStack.get().isEmpty()) { + contextStack.remove(); + } + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewContext.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewContext.java new file mode 100644 index 0000000000..a6708729c2 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewContext.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.handler; + +import javax.inject.Qualifier; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author Moritz Becker + * @since 1.2.0 + */ +@Qualifier +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER}) +public @interface EntityViewContext { +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewDelegateQueryHandler.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewDelegateQueryHandler.java new file mode 100644 index 0000000000..f2e8cc2dae --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewDelegateQueryHandler.java @@ -0,0 +1,24 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.handler; + +/** + * @author Moritz Becker + * @since 1.2.0 + */ +public interface EntityViewDelegateQueryHandler { +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewJpaQueryPostProcessor.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewJpaQueryPostProcessor.java new file mode 100644 index 0000000000..af14fd7db2 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewJpaQueryPostProcessor.java @@ -0,0 +1,31 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.handler; + +import javax.persistence.Query; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.handler.JpaQueryPostProcessor} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +public interface EntityViewJpaQueryPostProcessor { + + Query postProcess(EntityViewCdiQueryInvocationContext context, Query query); +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewQueryProcessor.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewQueryProcessor.java new file mode 100644 index 0000000000..fb2d95e80b --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewQueryProcessor.java @@ -0,0 +1,30 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.handler; + +import javax.persistence.Query; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.builder.result.QueryProcessor} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +public interface EntityViewQueryProcessor { + Object executeQuery(Query query, EntityViewCdiQueryInvocationContext context); +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewQueryProcessorFactory.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewQueryProcessorFactory.java new file mode 100644 index 0000000000..dcf8533f4e --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewQueryProcessorFactory.java @@ -0,0 +1,156 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.handler; + +import org.apache.deltaspike.core.util.OptionalUtil; +import org.apache.deltaspike.core.util.StreamUtil; +import org.apache.deltaspike.data.api.Modifying; +import org.apache.deltaspike.data.api.QueryResult; +import org.apache.deltaspike.data.api.SingleResultType; +import org.apache.deltaspike.data.impl.meta.MethodPrefix; + +import javax.persistence.NoResultException; +import javax.persistence.Query; +import java.lang.reflect.Method; +import java.util.List; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.builder.result.QueryProcessorFactory} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +public class EntityViewQueryProcessorFactory { + private final Method method; + private final MethodPrefix methodPrefix; + + private EntityViewQueryProcessorFactory(Method method) { + this.method = method; + this.methodPrefix = new MethodPrefix("", method.getName()); + } + + private EntityViewQueryProcessorFactory(Method method, MethodPrefix methodPrefix) { + this.method = method; + this.methodPrefix = methodPrefix; + } + + public static EntityViewQueryProcessorFactory newInstance(Method method) { + return new EntityViewQueryProcessorFactory(method); + } + + public static EntityViewQueryProcessorFactory newInstance(Method method, MethodPrefix methodPrefix) { + return new EntityViewQueryProcessorFactory(method, methodPrefix); + } + + public EntityViewQueryProcessor build() { + if (returns(QueryResult.class)) { + return new EntityViewQueryProcessorFactory.NoOpQueryProcessor(); + } + if (returns(List.class)) { + return new EntityViewQueryProcessorFactory.ListQueryProcessor(); + } + if (streams()) { + return new EntityViewQueryProcessorFactory.StreamQueryProcessor(); + } + if (isModifying()) { + return new EntityViewQueryProcessorFactory.ExecuteUpdateQueryProcessor(returns(Void.TYPE)); + } + return new EntityViewQueryProcessorFactory.SingleResultQueryProcessor(); + } + + private boolean isModifying() { + boolean matchesType = Void.TYPE.equals(method.getReturnType()) || + int.class.equals(method.getReturnType()) || + Integer.class.equals(method.getReturnType()); + return (method.isAnnotationPresent(Modifying.class) && matchesType) || methodPrefix.isDelete(); + } + + private boolean returns(Class clazz) { + return method.getReturnType().isAssignableFrom(clazz); + } + + private boolean streams() { + return StreamUtil.isStreamReturned(method); + } + + private static final class ListQueryProcessor implements EntityViewQueryProcessor { + @Override + public Object executeQuery(Query query, EntityViewCdiQueryInvocationContext context) { + return query.getResultList(); + } + } + + private static final class NoOpQueryProcessor implements EntityViewQueryProcessor { + @Override + public Object executeQuery(Query query, EntityViewCdiQueryInvocationContext context) { + return query; + } + } + + private static final class StreamQueryProcessor implements EntityViewQueryProcessor { + @Override + public Object executeQuery(Query query, EntityViewCdiQueryInvocationContext context) { + return StreamUtil.wrap(query.getResultList()); + } + } + + private static final class SingleResultQueryProcessor implements EntityViewQueryProcessor { + @Override + public Object executeQuery(Query query, EntityViewCdiQueryInvocationContext context) { + SingleResultType style = context.getSingleResultStyle(); + Object result = null; + switch (style) { + case JPA: + return query.getSingleResult(); + case OPTIONAL: + try { + result = query.getSingleResult(); + } catch (NoResultException e) { + } + break; + default: + @SuppressWarnings("unchecked") + List queryResult = query.getResultList(); + result = !queryResult.isEmpty() ? queryResult.get(0) : null; + } + if (context.isOptional()) { + return OptionalUtil.wrap(result); + } else { + return result; + } + } + } + + private static final class ExecuteUpdateQueryProcessor implements EntityViewQueryProcessor { + + private final boolean returnsVoid; + + private ExecuteUpdateQueryProcessor(boolean returnsVoid) { + this.returnsVoid = returnsVoid; + } + + @Override + public Object executeQuery(Query query, EntityViewCdiQueryInvocationContext context) { + int result = query.executeUpdate(); + if (!returnsVoid) { + return result; + } + return null; + } + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewQueryRunner.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewQueryRunner.java new file mode 100644 index 0000000000..d1193036fe --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewQueryRunner.java @@ -0,0 +1,31 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.handler; + +import com.blazebit.persistence.impl.deltaspikedata.impl.builder.EntityViewQueryBuilder; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.handler.QueryRunner} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +public interface EntityViewQueryRunner { + + Object executeQuery(EntityViewQueryBuilder builder, EntityViewCdiQueryInvocationContext context) throws Throwable; +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewRepositoryHandler.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewRepositoryHandler.java new file mode 100644 index 0000000000..84832283d7 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/EntityViewRepositoryHandler.java @@ -0,0 +1,174 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.handler; + +import com.balzebit.persistence.impl.deltaspikedata.api.EntityViewRepository; +import com.blazebit.persistence.CriteriaBuilder; +import com.blazebit.persistence.CriteriaBuilderFactory; +import com.blazebit.persistence.PaginatedCriteriaBuilder; +import com.blazebit.persistence.view.EntityViewManager; +import com.blazebit.persistence.view.EntityViewSetting; +import org.apache.deltaspike.data.impl.property.Property; +import org.apache.deltaspike.data.impl.property.query.NamedPropertyCriteria; +import org.apache.deltaspike.data.impl.property.query.PropertyQueries; + +import javax.inject.Inject; +import javax.persistence.metamodel.SingularAttribute; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import static org.apache.deltaspike.core.util.ArraysUtils.isEmpty; + +/** + * @author Moritz Becker + * @since 1.2.0 + */ +public class EntityViewRepositoryHandler + implements EntityViewRepository, EntityViewDelegateQueryHandler { + + @Inject + @EntityViewContext + private EntityViewCdiQueryInvocationContext context; + + @Inject + private CriteriaBuilderFactory cbf; + + @Inject + private EntityViewManager evm; + + @Override + public V findBy(PK pk) { + CriteriaBuilder cb = createCriteriaBuilder(); + String idAttribute = evm.getMetamodel().view(viewClass()).getIdAttribute().getName(); + + List result = evm.applySetting( + createSetting(), + cb.where(idAttribute).eq(pk) + ).getResultList(); + + return result.isEmpty() ? null : result.get(0); + } + + @Override + public List findAll() { + return evm.applySetting( + createSetting(), + createCriteriaBuilder() + ).getResultList(); + } + + @Override + public List findAll(int start, int max) { + EntityViewSetting> setting = EntityViewSetting.create(viewClass(), start, max); + return evm.applySetting(setting, createCriteriaBuilder()) + .orderByAsc(idAttribute()) + .getResultList(); + } + + @Override + public List findBy(E e, SingularAttribute... singularAttributes) { + return executeExampleQuery(e, 0, 0, false, singularAttributes); + } + + @Override + public List findBy(E e, int start, int max, SingularAttribute... singularAttributes) { + return executeExampleQuery(e, start, max, false, singularAttributes); + } + + @Override + public List findByLike(E e, SingularAttribute... singularAttributes) { + return executeExampleQuery(e, 0, 0, true, singularAttributes); + } + + @Override + public List findByLike(E e, int start, int max, SingularAttribute... singularAttributes) { + return executeExampleQuery(e, start, max, true, singularAttributes); + } + + private CriteriaBuilder createCriteriaBuilder() { + return cbf.create(context.getEntityManager(), entityClass()); + } + + private Class viewClass() { + return (Class) context.getEntityViewClass(); + } + + private Class entityClass() { + return (Class) context.getEntityClass(); + } + + private EntityViewSetting> createSetting() { + return EntityViewSetting.create((Class) context.getRepositoryMethod().getRepository().getRepositoryEntity().getEntityViewClass()); + } + + private List extractPropertyNames(SingularAttribute... attributes) { + List result = new ArrayList(attributes.length); + for (SingularAttribute attribute : attributes) { + result.add(attribute.getName()); + } + return result; + } + + private List> extractProperties(SingularAttribute... attributes) { + List names = extractPropertyNames(attributes); + List> properties = PropertyQueries.createQuery(context.getEntityClass()) + .addCriteria(new NamedPropertyCriteria(names.toArray(new String[]{}))).getResultList(); + return properties; + } + + private void prepareWhere(CriteriaBuilder cb, E example, List> properties, boolean useLikeOperator) { + Iterator> iterator = properties.iterator(); + StringBuilder result = new StringBuilder(); + while (iterator.hasNext()) { + Property property = iterator.next(); + String name = property.getName(); + if (useLikeOperator && property.getJavaClass().getName().equals(String.class.getName())) { + cb.where(name).like(false).value(property.getValue(example)).noEscape(); + } else { + cb.where(name).eq(property.getValue(example)); + } + } + } + + private List executeExampleQuery(E example, int start, int max, boolean useLikeOperator, + SingularAttribute... attributes) { + if (isEmpty(attributes)) { + return findAll(); + } + + CriteriaBuilder cb = createCriteriaBuilder(); + List> properties = extractProperties(attributes); + prepareWhere(cb, example, properties, useLikeOperator); + + EntityViewSetting setting; + if (start > 0 || max > 0) { + setting = EntityViewSetting.create(viewClass(), start, max); + } else { + setting = EntityViewSetting.create(viewClass()); + } + + return evm.applySetting(setting, cb) + .orderByAsc(idAttribute()) + .getResultList(); + } + + private String idAttribute() { + return evm.getMetamodel().view(viewClass()).getIdAttribute().getName(); + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/TransactionalEntityViewQueryRunner.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/TransactionalEntityViewQueryRunner.java new file mode 100644 index 0000000000..acb2b551ff --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/handler/TransactionalEntityViewQueryRunner.java @@ -0,0 +1,97 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.handler; + +import com.blazebit.persistence.impl.deltaspikedata.impl.builder.EntityViewQueryBuilder; +import com.blazebit.persistence.impl.deltaspikedata.impl.tx.EntityViewInvocationContextWrapper; +import org.apache.deltaspike.core.util.ClassUtils; +import org.apache.deltaspike.data.impl.handler.EntityRepositoryHandler; +import org.apache.deltaspike.data.impl.meta.RequiresTransaction; +import org.apache.deltaspike.jpa.spi.entitymanager.ActiveEntityManagerHolder; +import org.apache.deltaspike.jpa.spi.transaction.TransactionStrategy; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import java.lang.reflect.Method; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.tx.TransactionalQueryRunner} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +@ApplicationScoped +public class TransactionalEntityViewQueryRunner implements EntityViewQueryRunner +{ + + @Inject + private TransactionStrategy strategy; + + @Inject + private ActiveEntityManagerHolder activeEntityManagerHolder; + + @Override + public Object executeQuery(final EntityViewQueryBuilder builder, final EntityViewCdiQueryInvocationContext context) + throws Throwable + { + if (needsTransaction(context)) + { + try + { + activeEntityManagerHolder.set(context.getEntityManager()); + return executeTransactional(builder, context); + } + finally + { + activeEntityManagerHolder.dispose(); + } + } + return executeNonTransactional(builder, context); + } + + protected Object executeNonTransactional(final EntityViewQueryBuilder builder, final EntityViewCdiQueryInvocationContext context) + { + return builder.executeQuery(context); + } + + protected Object executeTransactional(final EntityViewQueryBuilder builder, final EntityViewCdiQueryInvocationContext context) + throws Exception + { + return strategy.execute(new EntityViewInvocationContextWrapper(context) + { + @Override + public Object proceed() throws Exception + { + return builder.executeQuery(context); + } + }); + } + + private boolean needsTransaction(EntityViewCdiQueryInvocationContext context) + { + boolean requiresTx = false; + Method method = context.getMethod(); + if (ClassUtils.containsMethod(EntityRepositoryHandler.class, method)) + { + Method executed = ClassUtils.extractMethod(EntityRepositoryHandler.class, method); + requiresTx = executed.isAnnotationPresent(RequiresTransaction.class); + } + return requiresTx || context.getRepositoryMethod().requiresTransaction(); + } + +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/EntityViewRepositoryComponent.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/EntityViewRepositoryComponent.java new file mode 100644 index 0000000000..36a9762d30 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/EntityViewRepositoryComponent.java @@ -0,0 +1,221 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.meta; + +import org.apache.deltaspike.core.api.provider.BeanManagerProvider; +import org.apache.deltaspike.data.api.EntityManagerConfig; +import org.apache.deltaspike.data.api.EntityManagerResolver; +import org.apache.deltaspike.data.api.Repository; +import org.apache.deltaspike.data.impl.meta.MethodType; + +import javax.enterprise.inject.spi.Bean; +import javax.enterprise.inject.spi.BeanManager; +import javax.persistence.FlushModeType; +import java.io.Serializable; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.meta.RepositoryComponent} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +public class EntityViewRepositoryComponent { + private static final Logger LOG = Logger.getLogger(EntityViewRepositoryComponent.class.getName()); + + private volatile Boolean entityManagerResolverIsNormalScope; + + private final Class repoClass; + private final RepositoryEntityView repositoryEntity; + private final Class entityManagerResolver; + private final FlushModeType entityManagerFlushMode; + + private final Map methods = new HashMap(); + + public EntityViewRepositoryComponent(Class repoClass, RepositoryEntityView repositoryEntity) { + if (repositoryEntity == null) { + throw new IllegalArgumentException("repositoryEntity cannot be null"); + } + this.repoClass = repoClass; + this.repositoryEntity = repositoryEntity; + this.entityManagerResolver = extractEntityManagerResolver(repoClass); + this.entityManagerFlushMode = extractEntityManagerFlushMode(repoClass); + } + + //don't trigger this lookup during ProcessAnnotatedType + private void lazyInit() { + if (entityManagerResolverIsNormalScope == null) { + init(BeanManagerProvider.getInstance().getBeanManager()); + } + } + + private synchronized void init(BeanManager beanManager) { + if (entityManagerResolverIsNormalScope != null) { + return; + } + initialize(); + if (entityManagerResolver != null && beanManager != null) { + final Set> beans = beanManager.getBeans(entityManagerResolver); + final Class scope = beanManager.resolve(beans).getScope(); + entityManagerResolverIsNormalScope = beanManager.isNormalScope(scope); + } else { + entityManagerResolverIsNormalScope = false; + } + } + + public boolean isEntityManagerResolverIsNormalScope() { + lazyInit(); + return entityManagerResolverIsNormalScope; + } + + public String getEntityName() { + return repositoryEntity.getEntityName(); + } + + /** + * Looks up method meta data by a Method object. + * + * @param method The Repository method. + * @return Method meta data. + */ + public EntityViewRepositoryMethod lookupMethod(Method method) { + lazyInit(); + return methods.get(method); + } + + /** + * Looks up the method type by a Method object. + * + * @param method The Repository method. + * @return Method meta data. + */ + public MethodType lookupMethodType(Method method) { + return lookupMethod(method).getMethodType(); + } + + /** + * Gets the entity class related the Repository. + * + * @return The class of the entity related to the Repository. + */ + public Class getEntityClass() { + return repositoryEntity.getEntityClass(); + } + + /** + * Gets the entity primary key class related the Repository. + * + * @return The class of the entity primary key related to the Repository. + */ + public Class getPrimaryKey() { + return repositoryEntity.getPrimaryKeyClass(); + } + + public RepositoryEntityView getRepositoryEntity() { + return repositoryEntity; + } + + /** + * Returns the original Repository class this meta data is related to. + * + * @return The class of the Repository. + */ + public Class getRepositoryClass() { + return repoClass; + } + + public boolean hasEntityManagerResolver() { + return getEntityManagerResolverClass() != null; + } + + public Class getEntityManagerResolverClass() { + return entityManagerResolver; + } + + public boolean hasEntityManagerFlushMode() { + return entityManagerFlushMode != null; + } + + public FlushModeType getEntityManagerFlushMode() { + return entityManagerFlushMode; + } + + private void initialize() { + Collection> allImplemented = collectClasses(); + for (Class implemented : allImplemented) { + Method[] repoClassMethods = implemented.getDeclaredMethods(); + for (Method repoClassMethod : repoClassMethods) { + EntityViewRepositoryMethod repoMethod = new EntityViewRepositoryMethod(repoClassMethod, this); + methods.put(repoClassMethod, repoMethod); + } + } + } + + private Set> collectClasses() { + Set> result = new HashSet>(); + collectClasses(repoClass, result); + LOG.log(Level.FINER, "collectClasses(): Found {0} for {1}", new Object[]{result, repoClass}); + return result; + } + + private void collectClasses(Class cls, Set> result) { + if (cls == null || cls == Object.class) { + return; + } + result.add(cls); + for (Class child : cls.getInterfaces()) { + collectClasses(child, result); + } + collectClasses(cls.getSuperclass(), result); + } + + private Class extractEntityManagerResolver(Class clazz) { + EntityManagerConfig config = extractEntityManagerConfig(clazz); + if (config != null && !EntityManagerResolver.class.equals(config.entityManagerResolver())) { + return config.entityManagerResolver(); + } + return null; + } + + private FlushModeType extractEntityManagerFlushMode(Class clazz) { + EntityManagerConfig config = extractEntityManagerConfig(clazz); + if (config != null) { + return config.flushMode(); + } + return null; + } + + private EntityManagerConfig extractEntityManagerConfig(Class clazz) { + if (clazz.isAnnotationPresent(EntityManagerConfig.class)) { + return clazz.getAnnotation(EntityManagerConfig.class); + } + return null; + } + + public String getCustomMethodPrefix() { + return repoClass.getAnnotation(Repository.class).methodPrefix(); + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/EntityViewRepositoryComponents.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/EntityViewRepositoryComponents.java new file mode 100644 index 0000000000..0ff0e06dc4 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/EntityViewRepositoryComponents.java @@ -0,0 +1,117 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.meta; + +import com.blazebit.persistence.impl.deltaspikedata.impl.meta.extractor.EntityViewAnnotationMetadataExtractor; +import com.blazebit.persistence.impl.deltaspikedata.impl.meta.extractor.EntityViewMetadataExtractor; +import com.blazebit.persistence.impl.deltaspikedata.impl.meta.extractor.EntityViewTypeMetadataExtractor; +import org.apache.deltaspike.data.impl.RepositoryDefinitionException; +import org.apache.deltaspike.data.impl.meta.RepositoryComponent; +import org.apache.deltaspike.data.impl.meta.RepositoryMethod; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.meta.RepositoryComponents} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +public class EntityViewRepositoryComponents { + private final Map, EntityViewRepositoryComponent> repos = new ConcurrentHashMap, EntityViewRepositoryComponent>(); + + private final List extractors = Arrays.asList(new EntityViewTypeMetadataExtractor(), new EntityViewAnnotationMetadataExtractor()); + + /** + * Add a Repository class to the meta data repository. + * + * @param repoClass The repo class. + */ + public void add(Class repoClass) { + RepositoryEntityView entityClass = extractEntityMetaData(repoClass); + EntityViewRepositoryComponent repo = new EntityViewRepositoryComponent(repoClass, entityClass); + repos.put(repoClass, repo); + } + + /** + * Repository access - lookup the Repository component meta data from a list of candidate classes. + * Depending on the implementation, proxy objects might have been modified so the actual class + * does not match the original Repository class. + * + * @param candidateClasses List of candidates to check. + * @return A {@link RepositoryComponent} corresponding to the repoClass parameter. + */ + public EntityViewRepositoryComponent lookupComponent(List> candidateClasses) { + for (Class repoClass : candidateClasses) { + if (repos.containsKey(repoClass)) { + return repos.get(repoClass); + } + } + throw new RuntimeException("Unknown Repository classes " + candidateClasses); + } + + /** + * Repository access - lookup the Repository component meta data for a specific Repository class. + * + * @param repoClass The Repository class to lookup the method for + * @return A {@link RepositoryComponent} corresponding to the repoClass parameter. + */ + public EntityViewRepositoryComponent lookupComponent(Class repoClass) { + if (repos.containsKey(repoClass)) { + return repos.get(repoClass); + } + throw new RuntimeException("Unknown Repository class " + repoClass.getName()); + } + + /** + * Repository access - lookup method information for a specific Repository class. + * + * @param repoClass The Repository class to lookup the method for + * @param method The Method object to get Repository meta data for. + * @return A {@link RepositoryMethod} corresponding to the method parameter. + */ + public EntityViewRepositoryMethod lookupMethod(Class repoClass, Method method) { + return lookupComponent(repoClass).lookupMethod(method); + } + + public EntityViewRepositoryMethod lookupMethod(EntityViewRepositoryComponent component, Method method) { + return component.lookupMethod(method); + } + + private RepositoryEntityView extractEntityMetaData(Class repoClass) { + for (EntityViewMetadataExtractor extractor : extractors) { + RepositoryEntityView entity = extractor.extract(repoClass); + if (entity != null) { + return entity; + } + } + throw new RepositoryDefinitionException(repoClass); + } + + public Map, EntityViewRepositoryComponent> getRepositories() { + return repos; + } + + public void addAll(Map, EntityViewRepositoryComponent> repositories) { + this.repos.putAll(repositories); + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/EntityViewRepositoryComponentsFactory.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/EntityViewRepositoryComponentsFactory.java new file mode 100644 index 0000000000..da38d90503 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/EntityViewRepositoryComponentsFactory.java @@ -0,0 +1,53 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.meta; + +import com.blazebit.persistence.impl.deltaspikedata.impl.EntityViewRepositoryExtension; +import org.apache.deltaspike.core.api.lifecycle.Initialized; +import org.apache.deltaspike.data.impl.meta.RepositoryComponents; +import org.apache.deltaspike.data.impl.meta.RepositoryComponentsFactory; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.inject.Produces; +import javax.enterprise.inject.Specializes; +import javax.inject.Inject; + +/** + * @author Moritz Becker + * @since 1.2.0 + */ +public class EntityViewRepositoryComponentsFactory extends RepositoryComponentsFactory { + + @Inject + private EntityViewRepositoryExtension extension; + + @Override + @Produces + @ApplicationScoped + @Initialized + @Specializes + public RepositoryComponents producer() { + return extension.getComponents(); + } + + @Produces + @ApplicationScoped + @Initialized + public EntityViewRepositoryComponents createEntityViewRepositoryComponents() { + return extension.getEntityViewRepositoryComponents(); + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/EntityViewRepositoryMethod.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/EntityViewRepositoryMethod.java new file mode 100644 index 0000000000..50d7c9c21d --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/EntityViewRepositoryMethod.java @@ -0,0 +1,198 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.meta; + +import com.blazebit.persistence.impl.deltaspikedata.impl.builder.part.EntityViewQueryRoot; +import com.blazebit.persistence.impl.deltaspikedata.impl.handler.EntityViewCdiQueryInvocationContext; +import com.blazebit.persistence.impl.deltaspikedata.impl.handler.EntityViewQueryProcessor; +import com.blazebit.persistence.impl.deltaspikedata.impl.handler.EntityViewQueryProcessorFactory; +import org.apache.deltaspike.core.api.provider.BeanManagerProvider; +import org.apache.deltaspike.core.api.provider.BeanProvider; +import org.apache.deltaspike.core.api.provider.DependentProvider; +import org.apache.deltaspike.core.util.OptionalUtil; +import org.apache.deltaspike.data.api.Modifying; +import org.apache.deltaspike.data.api.Query; +import org.apache.deltaspike.data.api.SingleResultType; +import org.apache.deltaspike.data.api.mapping.MappingConfig; +import org.apache.deltaspike.data.api.mapping.QueryInOutMapper; +import org.apache.deltaspike.data.impl.builder.MethodExpressionException; +import org.apache.deltaspike.data.impl.meta.MethodPrefix; +import org.apache.deltaspike.data.impl.meta.MethodType; +import org.apache.deltaspike.data.impl.util.bean.DependentProviderDestroyable; + +import javax.enterprise.inject.spi.Bean; +import javax.enterprise.inject.spi.BeanManager; +import javax.persistence.LockModeType; +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Set; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.meta.RepositoryMethod} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +public class EntityViewRepositoryMethod { + private final Method method; + private final MethodType methodType; + private final MethodPrefix methodPrefix; + private final EntityViewRepositoryComponent repo; + private final EntityViewQueryRoot queryRoot; + private final EntityViewQueryProcessor queryProcessor; + private final Class> mapper; + private final boolean isOptional; + + private volatile Boolean queryInOutMapperIsNormalScope; + + public EntityViewRepositoryMethod(Method method, EntityViewRepositoryComponent repo) { + this.method = method; + this.repo = repo; + this.methodPrefix = new MethodPrefix(repo.getCustomMethodPrefix(), method.getName()); + this.methodType = extractMethodType(); + this.queryRoot = initQueryRoot(); + this.queryProcessor = EntityViewQueryProcessorFactory.newInstance(method, methodPrefix).build(); + this.mapper = extractMapper(method, repo); + this.isOptional = OptionalUtil.isOptionalReturned(this.method); + } + + public boolean returns(Class returnType) { + return returnType.equals(method.getReturnType()); + } + + public QueryInOutMapper getQueryInOutMapperInstance(EntityViewCdiQueryInvocationContext context) { + if (!hasQueryInOutMapper()) { + return null; + } + QueryInOutMapper result = null; + lazyInit(); + if (!queryInOutMapperIsNormalScope) { + final DependentProvider> mappedProvider = BeanProvider.getDependent(mapper); + result = mappedProvider.get(); + context.addDestroyable(new DependentProviderDestroyable(mappedProvider)); + } else { + result = BeanProvider.getContextualReference(mapper); + } + return result; + } + + private MethodType extractMethodType() { + if (isMethodExpression()) { + return MethodType.PARSE; + } + return MethodType.DELEGATE; + } + + private EntityViewQueryRoot initQueryRoot() { + if (methodType == MethodType.PARSE) { + return EntityViewQueryRoot.create(method.getName(), repo, methodPrefix); + } + return EntityViewQueryRoot.UNKNOWN_ROOT; + } + + private boolean isMethodExpression() { + if (!Modifier.isAbstract(method.getModifiers())) { + return false; + } + try { + EntityViewQueryRoot.create(method.getName(), repo, methodPrefix); + return true; + } catch (MethodExpressionException e) { + return false; + } + } + + private Class> extractMapper(Method queryMethod, EntityViewRepositoryComponent repoComponent) { + if (queryMethod.isAnnotationPresent(MappingConfig.class)) { + return queryMethod.getAnnotation(MappingConfig.class).value(); + } + if (repoComponent.getRepositoryClass().isAnnotationPresent(MappingConfig.class)) { + return repoComponent.getRepositoryClass().getAnnotation(MappingConfig.class).value(); + } + return null; + } + + //don't trigger this lookup during ProcessAnnotatedType + private void lazyInit() { + if (queryInOutMapperIsNormalScope == null) { + init(BeanManagerProvider.getInstance().getBeanManager()); + } + } + + private synchronized void init(BeanManager beanManager) { + if (queryInOutMapperIsNormalScope != null) { + return; + } + + if (beanManager != null) { + final Set> beans = beanManager.getBeans(mapper); + final Class scope = beanManager.resolve(beans).getScope(); + queryInOutMapperIsNormalScope = beanManager.isNormalScope(scope); + } else { + queryInOutMapperIsNormalScope = false; + } + } + + public MethodType getMethodType() { + return methodType; + } + + public EntityViewRepositoryComponent getRepository() { + return repo; + } + + public EntityViewQueryRoot getQueryRoot() { + return queryRoot; + } + + public EntityViewQueryProcessor getQueryProcessor() { + return queryProcessor; + } + + public boolean hasQueryInOutMapper() { + return mapper != null; + } + + public int getDefinedMaxResults() { + try { + Method getDefinedMaxResultsMethod = MethodPrefix.class.getDeclaredMethod("getDefinedMaxResults"); + getDefinedMaxResultsMethod.setAccessible(true); + return (int) getDefinedMaxResultsMethod.invoke(methodPrefix); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + public SingleResultType getSingleResultStyle() { + return methodPrefix.getSingleResultStyle(); + } + + public boolean requiresTransaction() { + boolean hasLockMode = false; + if (method.isAnnotationPresent(Query.class)) { + hasLockMode = !method.getAnnotation(Query.class).lock().equals(LockModeType.NONE); + } + return hasLockMode || method.isAnnotationPresent(Modifying.class); + } + + public boolean isOptional() { + return this.isOptional; + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/RepositoryEntityView.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/RepositoryEntityView.java new file mode 100644 index 0000000000..a5fdffcfcf --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/RepositoryEntityView.java @@ -0,0 +1,66 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.meta; + +import com.blazebit.persistence.view.EntityView; + +import java.io.Serializable; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.meta.RepositoryEntity} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +public class RepositoryEntityView { + private Class entityViewClass; + private final Class entityClass; + private final String entityName; + private Class primaryKeyClass; + + public RepositoryEntityView(Class entityClass) { + this(entityClass, null); + } + + public RepositoryEntityView(Class entityViewClass, Class primaryClass) { + this.entityViewClass = entityViewClass; + this.entityClass = entityViewClass.getAnnotation(EntityView.class).value(); + this.primaryKeyClass = primaryClass; + this.entityName = entityClass.getSimpleName(); + } + + public Class getEntityViewClass() { + return entityViewClass; + } + + public Class getEntityClass() { + return entityClass; + } + + public Class getPrimaryKeyClass() { + return primaryKeyClass; + } + + public void setPrimaryKeyClass(Class primaryKeyClass) { + this.primaryKeyClass = primaryKeyClass; + } + + public String getEntityName() { + return entityName; + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/extractor/EntityViewAnnotationMetadataExtractor.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/extractor/EntityViewAnnotationMetadataExtractor.java new file mode 100644 index 0000000000..55915b22a1 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/extractor/EntityViewAnnotationMetadataExtractor.java @@ -0,0 +1,44 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.meta.extractor; + +import com.blazebit.persistence.impl.deltaspikedata.impl.meta.RepositoryEntityView; +import com.blazebit.persistence.view.EntityView; +import org.apache.deltaspike.data.api.Repository; +import org.apache.deltaspike.data.impl.util.EntityUtils; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.meta.extractor.AnnotationMetadataExtractor} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +public class EntityViewAnnotationMetadataExtractor implements EntityViewMetadataExtractor { + + @Override + public RepositoryEntityView extract(Class repoClass) { + Repository repo = repoClass.getAnnotation(Repository.class); + Class repoEntity = repo.forEntity(); + EntityView entityViewAnnotation = repoEntity.getAnnotation(EntityView.class); + boolean isEntityViewClass = !Object.class.equals(repoEntity) && entityViewAnnotation != null; + if (isEntityViewClass) { + return new RepositoryEntityView(repoEntity, EntityUtils.primaryKeyClass(entityViewAnnotation.value())); + } + return null; + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/extractor/EntityViewMetadataExtractor.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/extractor/EntityViewMetadataExtractor.java new file mode 100644 index 0000000000..813b0c5022 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/extractor/EntityViewMetadataExtractor.java @@ -0,0 +1,31 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.meta.extractor; + +import com.blazebit.persistence.impl.deltaspikedata.impl.meta.RepositoryEntityView; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.meta.extractor.MetadataExtractor} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +public interface EntityViewMetadataExtractor { + + RepositoryEntityView extract(Class repoClass); +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/extractor/EntityViewTypeMetadataExtractor.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/extractor/EntityViewTypeMetadataExtractor.java new file mode 100644 index 0000000000..ba8834d060 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/meta/extractor/EntityViewTypeMetadataExtractor.java @@ -0,0 +1,89 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.meta.extractor; + +import com.blazebit.persistence.impl.deltaspikedata.impl.meta.RepositoryEntityView; +import com.blazebit.persistence.view.EntityView; + +import java.io.Serializable; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.meta.extractor.TypeMetadataExtractor} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +public class EntityViewTypeMetadataExtractor implements EntityViewMetadataExtractor { + private static final Logger LOG = Logger.getLogger(EntityViewTypeMetadataExtractor.class.getName()); + + @Override + public RepositoryEntityView extract(Class repoClass) { + for (Type inf : repoClass.getGenericInterfaces()) { + RepositoryEntityView result = extractFrom(inf); + if (result != null) { + return result; + } + } + RepositoryEntityView result = extractFrom(repoClass.getGenericSuperclass()); + if (result != null) { + return result; + } + for (Type intf : repoClass.getGenericInterfaces()) { + result = extractFrom(intf); + if (result != null) { + return result; + } + } + if (repoClass.getSuperclass() != null) { + return extract(repoClass.getSuperclass()); + } + return null; + } + + @SuppressWarnings("unchecked") + private RepositoryEntityView extractFrom(Type type) { + LOG.log(Level.FINER, "extractFrom: type = {0}", type); + if (!(type instanceof ParameterizedType)) { + return null; + } + + ParameterizedType parametrizedType = (ParameterizedType) type; + Type[] genericTypes = parametrizedType.getActualTypeArguments(); + + RepositoryEntityView result = null; + + // don't use a foreach here, we must be sure that the we first get the entity type + for (int i = 0; i < genericTypes.length; i++) { + Type genericType = genericTypes[i]; + + if (genericType instanceof Class && ((Class) genericType).isAnnotationPresent(EntityView.class)) { + result = new RepositoryEntityView((Class) genericType); + continue; + } + if (result != null && genericType instanceof Class) { + result.setPrimaryKeyClass((Class) genericType); + return result; + } + } + return result; + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/param/Parameters.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/param/Parameters.java new file mode 100644 index 0000000000..0b6ade1e48 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/param/Parameters.java @@ -0,0 +1,181 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.param; + +import com.blazebit.persistence.FullQueryBuilder; +import com.blazebit.persistence.impl.deltaspikedata.impl.meta.EntityViewRepositoryMethod; +import org.apache.deltaspike.data.api.FirstResult; +import org.apache.deltaspike.data.api.MaxResults; +import org.apache.deltaspike.data.api.QueryParam; +import org.apache.deltaspike.data.api.mapping.QueryInOutMapper; +import org.apache.deltaspike.data.impl.param.NamedParameter; +import org.apache.deltaspike.data.impl.param.Parameter; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.param.Parameters} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +public class Parameters { + private static final Logger LOG = Logger.getLogger(Parameters.class.getName()); + + private static final int DEFAULT_MAX = 0; + private static final int DEFAULT_FIRST = -1; + + private final List parameterList; + private final int max; + private final int firstResult; + + private Parameters(List parameters, int max, int firstResult) { + this.parameterList = parameters; + this.max = max; + this.firstResult = firstResult; + } + + public static Parameters createEmpty() { + List empty = Collections.emptyList(); + return new Parameters(empty, DEFAULT_MAX, DEFAULT_FIRST); + } + + public static Parameters create(Method method, Object[] parameters, EntityViewRepositoryMethod repositoryMethod) { + int max = extractSizeRestriction(method, repositoryMethod); + int first = DEFAULT_FIRST; + List result = new ArrayList(parameters.length); + int paramIndex = 1; + Annotation[][] annotations = method.getParameterAnnotations(); + for (int i = 0; i < parameters.length; i++) { + if (isParameter(method.getParameterAnnotations()[i])) { + QueryParam qpAnnotation = extractFrom(annotations[i], QueryParam.class); + if (qpAnnotation != null) { + result.add(new NamedParameter(qpAnnotation.value(), parameters[i])); + } else { + result.add(new NamedParameter("methodArg" + paramIndex++, parameters[i])); + } + } else { + max = extractInt(parameters[i], annotations[i], MaxResults.class, max); + first = extractInt(parameters[i], annotations[i], FirstResult.class, first); + } + } + return new Parameters(result, max, first); + } + + public void applyMapper(QueryInOutMapper mapper) { + for (Parameter param : parameterList) { + param.applyMapper(mapper); + } + } + + public FullQueryBuilder applyTo(FullQueryBuilder queryBuilder) { + for (Parameter param : parameterList) { + if (param instanceof NamedParameter) { + NamedParameter namedParameter = (NamedParameter) param; + queryBuilder.setParameter(getParameterName(namedParameter), getParameterValue(param)); + } else { + throw new UnsupportedOperationException("Blaze-Persistence criteria builder only supports named parameters"); + } + } + return queryBuilder; + } + + private String getParameterName(NamedParameter namedParameter) { + try { + Field nameField = NamedParameter.class.getDeclaredField("name"); + nameField.setAccessible(true); + return (String) nameField.get(namedParameter); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + private Object getParameterValue(Parameter parameter) { + try { + Method queryValueMethod = Parameter.class.getDeclaredMethod("queryValue"); + queryValueMethod.setAccessible(true); + return queryValueMethod.invoke(parameter); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + public boolean hasSizeRestriction() { + return max > DEFAULT_MAX; + } + + public int getSizeRestriciton() { + return max; + } + + public boolean hasFirstResult() { + return firstResult > DEFAULT_FIRST; + } + + public int getFirstResult() { + return firstResult; + } + + private static int extractSizeRestriction(Method method, EntityViewRepositoryMethod repositoryMethod) { + if (method.isAnnotationPresent(org.apache.deltaspike.data.api.Query.class)) { + return method.getAnnotation(org.apache.deltaspike.data.api.Query.class).max(); + } + return repositoryMethod.getDefinedMaxResults(); + } + + @SuppressWarnings("unchecked") + private static A extractFrom(Annotation[] annotations, Class target) { + for (Annotation annotation : annotations) { + if (annotation.annotationType().isAssignableFrom(target)) { + return (A) annotation; + } + } + return null; + } + + private static int extractInt(Object parameter, Annotation[] annotations, + Class target, int defaultVal) { + if (parameter != null) { + A result = extractFrom(annotations, target); + if (result != null) { + if (parameter instanceof Integer) { + return (Integer) parameter; + } else { + LOG.log(Level.WARNING, "Method parameter extraction: " + + "Param type must be int: {0}->is:{1}", + new Object[]{target, parameter.getClass()}); + } + } + } + return defaultVal; + } + + private static boolean isParameter(Annotation[] annotations) { + return extractFrom(annotations, MaxResults.class) == null && + extractFrom(annotations, FirstResult.class) == null; + } + +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/tx/EntityViewInvocationContextWrapper.java b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/tx/EntityViewInvocationContextWrapper.java new file mode 100644 index 0000000000..beb086f027 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/java/com/blazebit/persistence/impl/deltaspikedata/impl/tx/EntityViewInvocationContextWrapper.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.impl.tx; + +import com.blazebit.persistence.impl.deltaspikedata.impl.handler.EntityViewCdiQueryInvocationContext; +import org.apache.deltaspike.core.util.interceptor.AbstractInvocationContext; + +/** + * Implementation is similar to {@link org.apache.deltaspike.data.impl.tx.InvocationContextWrapper} but was modified to + * work with entity views. + * + * @author Moritz Becker + * @since 1.2.0 + */ +public abstract class EntityViewInvocationContextWrapper extends AbstractInvocationContext { + public EntityViewInvocationContextWrapper(EntityViewCdiQueryInvocationContext context) { + super(context.getProxy(), context.getMethod(), context.getMethodParameters(), null); + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/resources/META-INF/apache-deltaspike.properties b/integration/deltaspike-data/impl/src/main/resources/META-INF/apache-deltaspike.properties new file mode 100644 index 0000000000..2696d73297 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/resources/META-INF/apache-deltaspike.properties @@ -0,0 +1 @@ +org.apache.deltaspike.core.spi.activation.ClassDeactivator=com.blazebit.persistence.impl.deltaspikedata.impl.DeltaspikeExtensionDeactivator \ No newline at end of file diff --git a/integration/deltaspike-data/impl/src/main/resources/META-INF/beans.xml b/integration/deltaspike-data/impl/src/main/resources/META-INF/beans.xml new file mode 100644 index 0000000000..3b5fea4b80 --- /dev/null +++ b/integration/deltaspike-data/impl/src/main/resources/META-INF/beans.xml @@ -0,0 +1,24 @@ + + + + \ No newline at end of file diff --git a/integration/deltaspike-data/pom.xml b/integration/deltaspike-data/pom.xml new file mode 100644 index 0000000000..31bca7522c --- /dev/null +++ b/integration/deltaspike-data/pom.xml @@ -0,0 +1,20 @@ + + + + blaze-persistence-integration + com.blazebit + 1.2.0-SNAPSHOT + + 4.0.0 + + blaze-persistence-integration-deltaspike-data + pom + Blazebit Persistence Integration DeltaSpike Data + + api + impl + testsuite + + \ No newline at end of file diff --git a/integration/deltaspike-data/testsuite/pom.xml b/integration/deltaspike-data/testsuite/pom.xml new file mode 100644 index 0000000000..c08d1b066a --- /dev/null +++ b/integration/deltaspike-data/testsuite/pom.xml @@ -0,0 +1,153 @@ + + + + blaze-persistence-integration-deltaspike-data + com.blazebit + 1.2.0-SNAPSHOT + + 4.0.0 + + blaze-persistence-integration-deltaspike-data-testsuite + + Blazebit Persistence Integration DeltaSpike Data Testsuite + + + + org.hibernate + hibernate-entitymanager + ${version.hibernate-5.2} + + + + ${project.groupId} + blaze-persistence-integration-deltaspike-data-impl + test + + + ${project.groupId} + blaze-persistence-core-impl + test + + + ${project.groupId} + blaze-persistence-integration-entity-view-cdi + test + + + ${project.groupId} + blaze-persistence-entity-view-impl + test + + + ${project.groupId} + blaze-persistence-integration-hibernate-5.2 + test + + + org.apache.deltaspike.core + deltaspike-core-impl + test + + + org.apache.deltaspike.cdictrl + deltaspike-cdictrl-api + test + + + org.apache.deltaspike.cdictrl + deltaspike-cdictrl-weld + test + + + weld-api + org.jboss.weld + + + jboss-logging + org.jboss.logging + + + + + org.apache.deltaspike.modules + deltaspike-data-module-impl + test + + + org.jboss.weld.se + weld-se-core + test + + + com.h2database + h2 + test + + + junit + junit + test + + + + + org.hibernate + hibernate-jpamodelgen + ${version.hibernate-5.2} + provided + + + + + + + org.bsc.maven + maven-processor-plugin + + + process + + process + + generate-sources + + + ${project.build.directory}/test-metamodel + + org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor + + + + + + + + org.hibernate + hibernate-jpamodelgen + ${version.hibernate-5.2} + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add-source-metamodel + generate-sources + + add-source + + + + ${project.build.directory}/test-metamodel + + + + + + + + \ No newline at end of file diff --git a/integration/deltaspike-data/testsuite/src/main/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/entity/Address.java b/integration/deltaspike-data/testsuite/src/main/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/entity/Address.java new file mode 100644 index 0000000000..09a8252992 --- /dev/null +++ b/integration/deltaspike-data/testsuite/src/main/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/entity/Address.java @@ -0,0 +1,36 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.testsuite.entity; + +import javax.persistence.Embeddable; + +/** + * @author Moritz Becker + * @since 1.2.0 + */ +@Embeddable +public class Address { + private String street; + + public String getStreet() { + return street; + } + + public void setStreet(String street) { + this.street = street; + } +} diff --git a/integration/deltaspike-data/testsuite/src/main/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/entity/Person.java b/integration/deltaspike-data/testsuite/src/main/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/entity/Person.java new file mode 100644 index 0000000000..8204b8b04c --- /dev/null +++ b/integration/deltaspike-data/testsuite/src/main/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/entity/Person.java @@ -0,0 +1,126 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.testsuite.entity; + +import javax.persistence.Column; +import javax.persistence.Embedded; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; + +/** + * + * @author Christian Beikov + * @since 1.0 + */ +@Entity +public class Person implements Serializable { + + private static final long serialVersionUID = 1L; + + private Long id; + private String name; + private Integer position; + private Person parent; + private Set children = new HashSet<>(0); + private Address address = new Address(); + + public Person() { } + + public Person(Long id, String name, Integer position) { + this.id = id; + this.name = name; + this.position = position; + } + + public Person(Long id, String name, Integer position, String street) { + this(id, name, position); + address.setStreet(street); + } + + @Id + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Column(nullable = false) + public Integer getPosition() { + return position; + } + + public void setPosition(Integer position) { + this.position = position; + } + + @ManyToOne + public Person getParent() { + return parent; + } + + public void setParent(Person parent) { + this.parent = parent; + } + + @OneToMany(mappedBy = "parent") + public Set getChildren() { + return children; + } + + public void setChildren(Set children) { + this.children = children; + } + + @Embedded + public Address getAddress() { + return address; + } + + public void setAddress(Address address) { + this.address = address; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Person)) return false; + + Person person = (Person) o; + + return id != null ? id.equals(person.id) : person.id == null; + } + + @Override + public int hashCode() { + return id != null ? id.hashCode() : 0; + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/testsuite/src/main/resources/META-INF/beans.xml b/integration/deltaspike-data/testsuite/src/main/resources/META-INF/beans.xml new file mode 100644 index 0000000000..3b5fea4b80 --- /dev/null +++ b/integration/deltaspike-data/testsuite/src/main/resources/META-INF/beans.xml @@ -0,0 +1,24 @@ + + + + \ No newline at end of file diff --git a/integration/deltaspike-data/testsuite/src/main/resources/META-INF/persistence.xml b/integration/deltaspike-data/testsuite/src/main/resources/META-INF/persistence.xml new file mode 100644 index 0000000000..250eab4b1b --- /dev/null +++ b/integration/deltaspike-data/testsuite/src/main/resources/META-INF/persistence.xml @@ -0,0 +1,34 @@ + + + + + com.blazebit.persistence.impl.deltaspikedata.testsuite.entity.Person + com.blazebit.persistence.impl.deltaspikedata.testsuite.entity.Address + + true + + + + + + + + + + + \ No newline at end of file diff --git a/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/AbstractEntityViewRepositoryTest.java b/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/AbstractEntityViewRepositoryTest.java new file mode 100644 index 0000000000..46cbe8aee0 --- /dev/null +++ b/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/AbstractEntityViewRepositoryTest.java @@ -0,0 +1,142 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.testsuite; + +import com.blazebit.persistence.CriteriaBuilder; +import com.blazebit.persistence.CriteriaBuilderFactory; +import com.blazebit.persistence.impl.deltaspikedata.testsuite.entity.Person; +import com.blazebit.persistence.view.EntityViewManager; +import com.blazebit.persistence.view.EntityViewSetting; +import com.blazebit.persistence.view.metamodel.ViewType; +import org.apache.deltaspike.cdise.api.CdiContainer; +import org.apache.deltaspike.cdise.api.CdiContainerLoader; +import org.apache.deltaspike.core.api.provider.BeanProvider; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; + +import javax.inject.Inject; +import javax.persistence.EntityManager; +import javax.persistence.EntityTransaction; +import java.util.logging.Level; +import java.util.logging.LogManager; +import java.util.logging.Logger; + +/** + * @author Moritz Becker + * @since 1.2.0 + */ +public class AbstractEntityViewRepositoryTest { + + private static final Logger LOG = Logger.getLogger(AbstractEntityViewRepositoryTest.class.getName()); + + @Inject + protected EntityManager em; + @Inject + private EntityViewManager evm; + @Inject + private CriteriaBuilderFactory cbf; + + protected Person[] persons; + + @BeforeClass + public static void bootContainer() { + CdiContainer container = CdiContainerLoader.getCdiContainer(); + container.boot(); + } + + @BeforeClass + public static void initLogging() { + try { + LogManager.getLogManager().readConfiguration(AbstractEntityViewRepositoryTest.class.getResourceAsStream( + "/logging.properties")); + } catch (Exception e) { + e.printStackTrace(System.err); + } + } + + @AfterClass + public static void shutdownContainer() { + CdiContainer container = CdiContainerLoader.getCdiContainer(); + container.shutdown(); + } + + @Before + public void startContexts() { + CdiContainer container = CdiContainerLoader.getCdiContainer(); + container.getContextControl().startContexts(); + BeanProvider.injectFields(this); + + transactional(new Runnable() { + @Override + public void run() { + createTestData(); + } + }); + } + + @After + public void stopContexts() { + CdiContainer container = CdiContainerLoader.getCdiContainer(); + container.getContextControl().stopContexts(); + } + + protected void transactional(Runnable r) { + EntityTransaction tx = em.getTransaction(); + try { + tx.begin(); + r.run(); + tx.commit(); + } catch (Exception e) { + LOG.log(Level.SEVERE, null, e); + if (tx != null) { + tx.rollback(); + } + } + } + + private void createTestData() { + persons = new Person[] { + new Person(0L, "Mother", 0), + new Person(1L, "John Doe", 2), + new Person(2L, "James Harley", 4), + new Person(3L, "Berry Cooper", 5), + new Person(4L, "John Smith", 4, "King Street"), + new Person(5L, "Harry Norman", 1, "Rich Street"), + new Person(6L, "Harry Norman", 3, "King Street") + }; + + persons[1].setParent(persons[0]); + persons[2].setParent(persons[0]); + persons[3].setParent(persons[1]); + persons[4].setParent(persons[2]); + persons[5].setParent(persons[2]); + persons[6].setParent(persons[2]); + + for (Person person : persons) { + em.persist(person); + } + } + + protected T fetch(Class entityView, Object id) { + ViewType viewType = evm.getMetamodel().view(entityView); + Class entityClass = viewType.getEntityClass(); + CriteriaBuilder cb = cbf.create(em, entityClass).where(viewType.getIdAttribute().getName()).eq(id); + return evm.applySetting(EntityViewSetting.create(entityView), cb).getSingleResult(); + } +} diff --git a/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/CriteriaSupportTest.java b/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/CriteriaSupportTest.java new file mode 100644 index 0000000000..46794f2f69 --- /dev/null +++ b/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/CriteriaSupportTest.java @@ -0,0 +1,49 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.testsuite; + +import com.blazebit.persistence.impl.deltaspikedata.testsuite.view.PersonView; +import org.junit.Test; + +import javax.inject.Inject; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +/** + * @author Moritz Becker + * @since 1.2.0 + */ +public class CriteriaSupportTest extends AbstractEntityViewRepositoryTest { + + @Inject + private PersonViewCriteriaRepository personViewRepository; + + @Test + public void testGetPersonsByComplexCondition() { + List expected = new ArrayList<>(Arrays.asList( + fetch(PersonView.class, persons[1].getId()), + fetch(PersonView.class, persons[2].getId()), + fetch(PersonView.class, persons[3].getId()), + fetch(PersonView.class, persons[4].getId()) + )); + List result = personViewRepository.getPersonsByComplexCondition(); + assertEquals(expected, result); + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/ExtendedEntityViewRepositoryTest.java b/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/ExtendedEntityViewRepositoryTest.java new file mode 100644 index 0000000000..1d2334d9ff --- /dev/null +++ b/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/ExtendedEntityViewRepositoryTest.java @@ -0,0 +1,180 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.testsuite; + +import com.blazebit.persistence.impl.deltaspikedata.testsuite.entity.Person; +import com.blazebit.persistence.impl.deltaspikedata.testsuite.view.PersonView; +import org.apache.deltaspike.data.api.QueryResult; +import org.junit.Test; + +import javax.inject.Inject; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +/** + * @author Moritz Becker + * @since 1.2.0 + */ +public class ExtendedEntityViewRepositoryTest extends AbstractEntityViewRepositoryTest { + + @Inject + private FullPersonViewRepository personViewRepository; + @Inject + private SimplePersonViewRepository simplePersonViewRepository; + + @Test + public void testFindAnyByName() { + String name = "John Smith"; + PersonView result1 = personViewRepository.findAnyByName(name); + PersonView result2 = simplePersonViewRepository.findAnyByName(name); + assertEquals(persons[4].getId(), result1.getId()); + assertEquals(result1, result2); + } + + @Test + public void testFindByNameAndPosition() { + List result = personViewRepository.findByNameAndPosition("Harry Norman", 1); + assertEquals(1, result.size()); + assertEquals(persons[5].getId(), result.get(0).getId()); + } + + @Test + public void testFindByNameAndPosition_noResult() { + List result = personViewRepository.findByNameAndPosition("Harry Norman", 2); + assertTrue(result.isEmpty()); + } + + @Test + public void testFindByNameOrPosition() { + List expected = new ArrayList<>(Arrays.asList( + fetch(PersonView.class, persons[1].getId()), + fetch(PersonView.class, persons[5].getId()), + fetch(PersonView.class, persons[6].getId()) + )); + List result = personViewRepository.findByNameOrPosition("Harry Norman", 2); + assertEquals(expected, result); + } + + @Test + public void testFindByPositionBetween() { + List expected = new ArrayList<>(Arrays.asList( + fetch(PersonView.class, persons[1].getId()), + fetch(PersonView.class, persons[6].getId()) + )); + List result = personViewRepository.findByPositionBetween(2, 3); + assertEquals(expected, result); + } + + @Test + public void testFindFirstByNameLikeOrderByIdAsc() { + PersonView result1 = personViewRepository.findFirst1ByNameLikeOrderByIdAsc("John%"); + PersonView result2 = personViewRepository.findTop1ByNameLikeOrderByIdAsc("John%"); + assertEquals(persons[1].getId(), result1.getId()); + assertEquals(persons[1].getId(), result2.getId()); + } + + @Test + public void testFindFirst2ByNameLikeOrderByIdAsc() { + List expected = new ArrayList<>(Arrays.asList( + fetch(PersonView.class, persons[1].getId()), + fetch(PersonView.class, persons[4].getId()) + )); + List result1 = personViewRepository.findFirst2ByNameLikeOrderByIdAsc("John%"); + List result2 = personViewRepository.findTop2ByNameLikeOrderByIdAsc("John%"); + assertEquals(expected, result1); + assertEquals(expected, result2); + } + + @Test + public void testFindAnyByNameIsNullOrderByIdAsc() { + assertNull(personViewRepository.findAnyByNameIsNullOrderByIdAsc()); + final Person newPerson = new Person(persons[persons.length - 1].getId() + 1, null, 0); + transactional(new Runnable() { + @Override + public void run() { + em.persist(newPerson); + } + }); + PersonView result = personViewRepository.findAnyByNameIsNullOrderByIdAsc(); + assertEquals(newPerson.getId(), result.getId()); + } + + @Test + public void testFindAllOrderByNameDescIdAsc() { + List expected = new ArrayList<>(Arrays.asList( + fetch(PersonView.class, persons[0].getId()), + fetch(PersonView.class, persons[4].getId()), + fetch(PersonView.class, persons[1].getId()), + fetch(PersonView.class, persons[2].getId()), + fetch(PersonView.class, persons[5].getId()), + fetch(PersonView.class, persons[6].getId()), + fetch(PersonView.class, persons[3].getId()) + )); + List result = personViewRepository.findAllOrderByNameDescIdAsc(); + assertEquals(expected, result); + } + + @Test + public void testFindByNameLikeOrderByIdAsc() { + List expected1 = new ArrayList<>(Arrays.asList( + fetch(PersonView.class, persons[1].getId()), + fetch(PersonView.class, persons[2].getId()) + )); + List expected2 = new ArrayList<>(Arrays.asList( + fetch(PersonView.class, persons[2].getId()), + fetch(PersonView.class, persons[4].getId()) + )); + List result1 = personViewRepository.findByNameLikeOrderByIdAsc("J%", 0, 2); + List result2 = personViewRepository.findByNameLikeOrderByIdAsc("J%", 1, 2); + assertEquals(expected1, result1); + assertEquals(expected2, result2); + } + + @Test + public void testFindAnyByAdress_streetLike() { + PersonView result = personViewRepository.findAnyByAddress_streetLikeOrderByIdAsc("King%"); + assertEquals(persons[4].getId(), result.getId()); + } + + @Test + public void testFindByPosition() { + List expected = new ArrayList<>(Arrays.asList( + fetch(PersonView.class, persons[2].getId()), + fetch(PersonView.class, persons[4].getId()) + )); + List expectedReversed = new ArrayList<>(expected); + Collections.reverse(expectedReversed); + QueryResult result = personViewRepository.findByPosition(4); + assertEquals(expected, result.orderAsc("id").getResultList()); + assertEquals(expectedReversed, result.changeOrder("id").getResultList()); + result.clearOrder(); + + assertEquals(persons[4].getId(), result.orderAsc("id").firstResult(1).getSingleResult().getId()); + assertEquals(persons[2].getId(), result.firstResult(0).maxResults(1).getSingleResult().getId()); + + assertEquals(persons[2].getId(), result.withPageSize(1).toPage(0).getSingleResult().getId()); + assertEquals(persons[4].getId(), result.nextPage().getSingleResult().getId()); + assertEquals(persons[2].getId(), result.previousPage().getSingleResult().getId()); + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/FullEntityViewRepositoryTest.java b/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/FullEntityViewRepositoryTest.java new file mode 100644 index 0000000000..42dad511ca --- /dev/null +++ b/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/FullEntityViewRepositoryTest.java @@ -0,0 +1,124 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.testsuite; + +import com.blazebit.persistence.impl.deltaspikedata.testsuite.entity.Person; +import com.blazebit.persistence.impl.deltaspikedata.testsuite.entity.Person_; +import com.blazebit.persistence.impl.deltaspikedata.testsuite.view.PersonView; +import org.junit.Test; + +import javax.inject.Inject; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +/** + * + * @author Moritz Becker + * @since 1.2.0 + */ +public class FullEntityViewRepositoryTest extends AbstractEntityViewRepositoryTest { + + @Inject + private FullPersonViewRepository personViewRepository; + @Inject + private PersonRepository personRepository; + + @Test + public void testFindAll() throws Exception { + assertEquals(persons.length, personRepository.findAll().size()); + assertEquals(persons.length, personViewRepository.findAll().size()); + } + + @Test + public void testFindAllRange() throws Exception { + int start = 1; + int offset = 2; + List expected = new ArrayList<>(); + for (int i = start; i < start + offset; i++) { + expected.add(fetch(PersonView.class, persons[i].getId())); + } + // we do not test DeltaSpike's findAll(int, int) method here because its results are non-deterministic + List actual = personViewRepository.findAll(start, offset); + assertEquals(expected, actual); + for (int i = 0; i < actual.size(); i++) { + assertEquals(expected.get(i).getChildren(), actual.get(i).getChildren()); + } + } + + @Test + public void testFindBy() { + List expected = new ArrayList<>(Arrays.asList( + fetch(PersonView.class, persons[2].getId()), + fetch(PersonView.class, persons[4].getId()) + )); + Person example = new Person(); + example.setPosition(4); + + // we do not test DeltaSpike's findBy(E, SingularAttribute...) method here because its results are non-deterministic + assertEquals(expected, personViewRepository.findBy(example, Person_.position)); + } + + @Test + public void testFindByPaginated() { + Person example = new Person(); + example.setPosition(4); + + // we do not test DeltaSpike's findBy(E, int, int, SingularAttribute...) method here because its results are non-deterministic + List page2 = personViewRepository.findBy(example, 1, 1, Person_.position); + assertEquals(1, page2.size()); + assertEquals(persons[4].getId(), page2.get(0).getId()); + + List page1 = personViewRepository.findBy(example, 0, 1, Person_.position); + assertEquals(1, page1.size()); + assertEquals(persons[2].getId(), page1.get(0).getId()); + } + + @Test + public void testFindByLike() { + List expected = new ArrayList<>(Arrays.asList( + fetch(PersonView.class, persons[1].getId()), + fetch(PersonView.class, persons[4].getId()) + )); + Person example = new Person(); + example.setName("John %"); + + // we do not test DeltaSpike's findByLike(E, SingularAttribute...) method here because its results are non-deterministic + assertEquals(expected, personViewRepository.findByLike(example, Person_.name)); + } + + @Test + public void testFindByLikePaginated() { + List expected = new ArrayList<>(Arrays.asList( + fetch(PersonView.class, persons[0].getId()), + fetch(PersonView.class, persons[3].getId()) + )); + Person example = new Person(); + example.setName("John %"); + + // we do not test DeltaSpike's findByLike(E, int, int, SingularAttribute...) method here because its results are non-deterministic + List page2 = personViewRepository.findByLike(example, 1, 1, Person_.name); + assertEquals(1, page2.size()); + assertEquals(persons[4].getId(), page2.get(0).getId()); + + List page1 = personViewRepository.findByLike(example, 0, 1, Person_.name); + assertEquals(1, page1.size()); + assertEquals(persons[1].getId(), page1.get(0).getId()); + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/FullPersonViewRepository.java b/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/FullPersonViewRepository.java new file mode 100644 index 0000000000..2a7c2fb670 --- /dev/null +++ b/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/FullPersonViewRepository.java @@ -0,0 +1,61 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.testsuite; + +import com.balzebit.persistence.impl.deltaspikedata.api.FullEntityViewRepository; +import com.blazebit.persistence.impl.deltaspikedata.testsuite.entity.Person; +import com.blazebit.persistence.impl.deltaspikedata.testsuite.view.PersonView; +import org.apache.deltaspike.data.api.FirstResult; +import org.apache.deltaspike.data.api.MaxResults; +import org.apache.deltaspike.data.api.QueryResult; +import org.apache.deltaspike.data.api.Repository; + +import java.util.List; + +/** + * @author Moritz Becker + * @since 1.2.0 + */ +@Repository +public interface FullPersonViewRepository extends FullEntityViewRepository { + + PersonView findAnyByName(String name); + + List findByNameAndPosition(String name, int position); + + List findByNameOrPosition(String name, int position); + + List findByPositionBetween(int positionFrom, int positionTo); + + PersonView findFirst1ByNameLikeOrderByIdAsc(String namePattern); + + PersonView findTop1ByNameLikeOrderByIdAsc(String namePattern); + + List findFirst2ByNameLikeOrderByIdAsc(String namePattern); + + List findTop2ByNameLikeOrderByIdAsc(String namePattern); + + PersonView findAnyByNameIsNullOrderByIdAsc(); + + List findAllOrderByNameDescIdAsc(); + + List findByNameLikeOrderByIdAsc(String name, @FirstResult int start, @MaxResults int max); + + PersonView findAnyByAddress_streetLikeOrderByIdAsc(String streetPattern); + + QueryResult findByPosition(int position); +} \ No newline at end of file diff --git a/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/PersonRepository.java b/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/PersonRepository.java new file mode 100644 index 0000000000..17b144149c --- /dev/null +++ b/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/PersonRepository.java @@ -0,0 +1,29 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.testsuite; + +import com.blazebit.persistence.impl.deltaspikedata.testsuite.entity.Person; +import org.apache.deltaspike.data.api.FullEntityRepository; +import org.apache.deltaspike.data.api.Repository; + +/** + * @author Moritz Becker + * @since 1.2.0 + */ +@Repository +public interface PersonRepository extends FullEntityRepository { +} \ No newline at end of file diff --git a/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/PersonViewCriteriaRepository.java b/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/PersonViewCriteriaRepository.java new file mode 100644 index 0000000000..fedb73dd4f --- /dev/null +++ b/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/PersonViewCriteriaRepository.java @@ -0,0 +1,40 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.testsuite; + +import com.balzebit.persistence.impl.deltaspikedata.api.CriteriaSupport; +import com.blazebit.persistence.impl.deltaspikedata.testsuite.entity.Person; +import com.blazebit.persistence.impl.deltaspikedata.testsuite.entity.Person_; +import com.blazebit.persistence.impl.deltaspikedata.testsuite.view.PersonView; +import org.apache.deltaspike.data.api.Repository; + +import java.util.List; + +/** + * @author Moritz Becker + * @since 1.2.0 + */ +@Repository(forEntity = Person.class) +public abstract class PersonViewCriteriaRepository implements CriteriaSupport { + + public List getPersonsByComplexCondition() { + return criteria().or( + criteria().gt(Person_.position, 3), + criteria().likeIgnoreCase(Person_.name, "john%") + ).orderAsc(Person_.id).getResultList(); + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/SimplePersonViewRepository.java b/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/SimplePersonViewRepository.java new file mode 100644 index 0000000000..b38a8eb914 --- /dev/null +++ b/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/SimplePersonViewRepository.java @@ -0,0 +1,29 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.testsuite; + +import com.blazebit.persistence.impl.deltaspikedata.testsuite.view.PersonView; +import org.apache.deltaspike.data.api.Repository; + +/** + * @author Moritz Becker + * @since 1.2.0 + */ +@Repository(forEntity = PersonView.class) +public interface SimplePersonViewRepository { + PersonView findAnyByName(String name); +} diff --git a/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/producer/BlazePersistenceProducer.java b/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/producer/BlazePersistenceProducer.java new file mode 100644 index 0000000000..2c1bda5725 --- /dev/null +++ b/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/producer/BlazePersistenceProducer.java @@ -0,0 +1,56 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.testsuite.producer; + +import com.blazebit.persistence.Criteria; +import com.blazebit.persistence.CriteriaBuilderFactory; +import com.blazebit.persistence.spi.CriteriaBuilderConfiguration; +import com.blazebit.persistence.view.EntityViewManager; +import com.blazebit.persistence.view.spi.EntityViewConfiguration; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.inject.Produces; +import javax.inject.Inject; +import javax.persistence.EntityManagerFactory; + +/** + * @author Moritz Becker (moritz.becker@gmx.at) + * @since 1.2 + */ +@ApplicationScoped +public class BlazePersistenceProducer { + + @Inject + private EntityManagerFactory emf; + + @Inject + private EntityViewConfiguration entityViewConfiguration; + + @Produces + @ApplicationScoped + public CriteriaBuilderFactory createCriteriaBuilderFactory() { + CriteriaBuilderConfiguration config = Criteria.getDefault(); + return config.createCriteriaBuilderFactory(emf); + } + + @Produces + @ApplicationScoped + public EntityViewManager createEntityViewManager(CriteriaBuilderFactory criteriaBuilderFactory) { + return entityViewConfiguration.createEntityViewManager(criteriaBuilderFactory); + } + +} diff --git a/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/producer/EntityManagerProducer.java b/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/producer/EntityManagerProducer.java new file mode 100644 index 0000000000..f6cc8b8f93 --- /dev/null +++ b/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/producer/EntityManagerProducer.java @@ -0,0 +1,48 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.testsuite.producer; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.inject.Disposes; +import javax.enterprise.inject.Produces; +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; + +/** + * @author Moritz Becker + * @since 1.2.0 + */ +public class EntityManagerProducer { + + @Produces + public EntityManager createEm(EntityManagerFactory emf) { + return emf.createEntityManager(); + } + + @Produces + @ApplicationScoped + public EntityManagerFactory getEntityManagerFactory() { + return Persistence.createEntityManagerFactory("IntegrationDeltaspikeData", null); + } + + public void onShutdown(@Disposes EntityManagerFactory emf) { + if (emf.isOpen()) { + emf.close(); + } + } +} \ No newline at end of file diff --git a/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/view/ChildView.java b/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/view/ChildView.java new file mode 100644 index 0000000000..46a55a1689 --- /dev/null +++ b/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/view/ChildView.java @@ -0,0 +1,34 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.testsuite.view; + +import com.blazebit.persistence.impl.deltaspikedata.testsuite.entity.Person; +import com.blazebit.persistence.view.EntityView; +import com.blazebit.persistence.view.IdMapping; + +/** + * @author Moritz Becker + * @since 1.2.0 + */ +@EntityView(Person.class) +public interface ChildView { + + @IdMapping("id") + Long getId(); + + String getName(); +} diff --git a/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/view/PersonView.java b/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/view/PersonView.java new file mode 100644 index 0000000000..0772b75f3a --- /dev/null +++ b/integration/deltaspike-data/testsuite/src/test/java/com/blazebit/persistence/impl/deltaspikedata/testsuite/view/PersonView.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014 - 2017 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.impl.deltaspikedata.testsuite.view; + +import com.blazebit.persistence.impl.deltaspikedata.testsuite.entity.Person; +import com.blazebit.persistence.view.EntityView; + +import java.util.Set; + +/** + * + * @author Moritz Becker + * @since 1.2.0 + */ +@EntityView(Person.class) +public interface PersonView extends ChildView { + + Set getChildren(); +} \ No newline at end of file diff --git a/integration/deltaspike-data/testsuite/src/test/resources/META-INF/beans.xml b/integration/deltaspike-data/testsuite/src/test/resources/META-INF/beans.xml new file mode 100644 index 0000000000..3b5fea4b80 --- /dev/null +++ b/integration/deltaspike-data/testsuite/src/test/resources/META-INF/beans.xml @@ -0,0 +1,24 @@ + + + + \ No newline at end of file diff --git a/integration/deltaspike-data/testsuite/src/test/resources/logging.properties b/integration/deltaspike-data/testsuite/src/test/resources/logging.properties new file mode 100644 index 0000000000..970654e209 --- /dev/null +++ b/integration/deltaspike-data/testsuite/src/test/resources/logging.properties @@ -0,0 +1,33 @@ +# +# Copyright 2014 - 2017 Blazebit. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +handlers = java.util.logging.ConsoleHandler + +# For debugging purposes use ALL +# We turn it off for TravisCI build with SEVERE +org.hibernate.level = SEVERE +org.hibernate.tool.hbm2ddl.level = OFF +#org.hibernate.SQL.level = ALL +#org.hibernate.type.descriptor.sql.level = ALL +#org.hibernate.tool.hbm2ddl.level = ALL +#org.hibernate.pretty.level = ALL +#org.hibernate.cache.level = ALL +#org.hibernate.hql.internal.ast.AST.level = ALL + +org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl.level = SEVERE + +java.util.logging.ConsoleHandler.level = ALL +java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter \ No newline at end of file diff --git a/integration/pom.xml b/integration/pom.xml index 732d52a179..0ef31e452f 100644 --- a/integration/pom.xml +++ b/integration/pom.xml @@ -45,5 +45,6 @@ entity-view-cdi entity-view-spring spring-data + deltaspike-data diff --git a/integration/spring-data/src/main/java/com/blazebit/persistence/impl/springdata/repository/EntityViewRepository.java b/integration/spring-data/src/main/java/com/blazebit/persistence/spring/data/api/repository/EntityViewRepository.java similarity index 94% rename from integration/spring-data/src/main/java/com/blazebit/persistence/impl/springdata/repository/EntityViewRepository.java rename to integration/spring-data/src/main/java/com/blazebit/persistence/spring/data/api/repository/EntityViewRepository.java index f73f32db7a..8ef9411b74 100644 --- a/integration/spring-data/src/main/java/com/blazebit/persistence/impl/springdata/repository/EntityViewRepository.java +++ b/integration/spring-data/src/main/java/com/blazebit/persistence/spring/data/api/repository/EntityViewRepository.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.blazebit.persistence.impl.springdata.repository; +package com.blazebit.persistence.spring.data.api.repository; import org.springframework.data.repository.NoRepositoryBean; import org.springframework.data.repository.Repository; diff --git a/integration/spring-data/src/main/java/com/blazebit/persistence/impl/springdata/query/BlazePersistenceQueryLookupStrategy.java b/integration/spring-data/src/main/java/com/blazebit/persistence/spring/data/impl/query/BlazePersistenceQueryLookupStrategy.java similarity index 99% rename from integration/spring-data/src/main/java/com/blazebit/persistence/impl/springdata/query/BlazePersistenceQueryLookupStrategy.java rename to integration/spring-data/src/main/java/com/blazebit/persistence/spring/data/impl/query/BlazePersistenceQueryLookupStrategy.java index 40c2c1b68c..b28232ba27 100644 --- a/integration/spring-data/src/main/java/com/blazebit/persistence/impl/springdata/query/BlazePersistenceQueryLookupStrategy.java +++ b/integration/spring-data/src/main/java/com/blazebit/persistence/spring/data/impl/query/BlazePersistenceQueryLookupStrategy.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.blazebit.persistence.impl.springdata.query; +package com.blazebit.persistence.spring.data.impl.query; import com.blazebit.persistence.CriteriaBuilderFactory; import com.blazebit.persistence.view.EntityViewManager; diff --git a/integration/spring-data/src/main/java/com/blazebit/persistence/impl/springdata/query/EntityViewAwareJpaQueryMethod.java b/integration/spring-data/src/main/java/com/blazebit/persistence/spring/data/impl/query/EntityViewAwareJpaQueryMethod.java similarity index 97% rename from integration/spring-data/src/main/java/com/blazebit/persistence/impl/springdata/query/EntityViewAwareJpaQueryMethod.java rename to integration/spring-data/src/main/java/com/blazebit/persistence/spring/data/impl/query/EntityViewAwareJpaQueryMethod.java index 87e023ea57..19a37ab9ce 100644 --- a/integration/spring-data/src/main/java/com/blazebit/persistence/impl/springdata/query/EntityViewAwareJpaQueryMethod.java +++ b/integration/spring-data/src/main/java/com/blazebit/persistence/spring/data/impl/query/EntityViewAwareJpaQueryMethod.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.blazebit.persistence.impl.springdata.query; +package com.blazebit.persistence.spring.data.impl.query; import com.blazebit.persistence.view.EntityView; import org.springframework.data.jpa.provider.QueryExtractor; diff --git a/integration/spring-data/src/main/java/com/blazebit/persistence/impl/springdata/repository/EntityViewAwareRepositoryFactory.java b/integration/spring-data/src/main/java/com/blazebit/persistence/spring/data/impl/repository/EntityViewAwareRepositoryFactory.java similarity index 96% rename from integration/spring-data/src/main/java/com/blazebit/persistence/impl/springdata/repository/EntityViewAwareRepositoryFactory.java rename to integration/spring-data/src/main/java/com/blazebit/persistence/spring/data/impl/repository/EntityViewAwareRepositoryFactory.java index e156059c01..0a70f11be1 100644 --- a/integration/spring-data/src/main/java/com/blazebit/persistence/impl/springdata/repository/EntityViewAwareRepositoryFactory.java +++ b/integration/spring-data/src/main/java/com/blazebit/persistence/spring/data/impl/repository/EntityViewAwareRepositoryFactory.java @@ -14,10 +14,10 @@ * limitations under the License. */ -package com.blazebit.persistence.impl.springdata.repository; +package com.blazebit.persistence.spring.data.impl.repository; import com.blazebit.persistence.CriteriaBuilderFactory; -import com.blazebit.persistence.impl.springdata.query.BlazePersistenceQueryLookupStrategy; +import com.blazebit.persistence.spring.data.impl.query.BlazePersistenceQueryLookupStrategy; import com.blazebit.persistence.view.EntityView; import com.blazebit.persistence.view.EntityViewManager; import org.springframework.data.jpa.provider.PersistenceProvider; diff --git a/integration/spring-data/src/main/java/com/blazebit/persistence/impl/springdata/repository/EntityViewRepositoryFactoryBean.java b/integration/spring-data/src/main/java/com/blazebit/persistence/spring/data/impl/repository/EntityViewRepositoryFactoryBean.java similarity index 98% rename from integration/spring-data/src/main/java/com/blazebit/persistence/impl/springdata/repository/EntityViewRepositoryFactoryBean.java rename to integration/spring-data/src/main/java/com/blazebit/persistence/spring/data/impl/repository/EntityViewRepositoryFactoryBean.java index 0b75195b82..9782e55430 100644 --- a/integration/spring-data/src/main/java/com/blazebit/persistence/impl/springdata/repository/EntityViewRepositoryFactoryBean.java +++ b/integration/spring-data/src/main/java/com/blazebit/persistence/spring/data/impl/repository/EntityViewRepositoryFactoryBean.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.blazebit.persistence.impl.springdata.repository; +package com.blazebit.persistence.spring.data.impl.repository; import com.blazebit.persistence.CriteriaBuilderFactory; import com.blazebit.persistence.view.EntityViewManager; diff --git a/integration/spring-data/src/main/java/com/blazebit/persistence/impl/springdata/repository/EntityViewRepositoryImpl.java b/integration/spring-data/src/main/java/com/blazebit/persistence/spring/data/impl/repository/EntityViewRepositoryImpl.java similarity index 98% rename from integration/spring-data/src/main/java/com/blazebit/persistence/impl/springdata/repository/EntityViewRepositoryImpl.java rename to integration/spring-data/src/main/java/com/blazebit/persistence/spring/data/impl/repository/EntityViewRepositoryImpl.java index 4342f99deb..0e62802bc1 100644 --- a/integration/spring-data/src/main/java/com/blazebit/persistence/impl/springdata/repository/EntityViewRepositoryImpl.java +++ b/integration/spring-data/src/main/java/com/blazebit/persistence/spring/data/impl/repository/EntityViewRepositoryImpl.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.blazebit.persistence.impl.springdata.repository; +package com.blazebit.persistence.spring.data.impl.repository; import com.blazebit.persistence.CriteriaBuilder; import com.blazebit.persistence.CriteriaBuilderFactory; @@ -22,6 +22,7 @@ import com.blazebit.persistence.criteria.BlazeCriteriaBuilder; import com.blazebit.persistence.criteria.BlazeCriteriaQuery; import com.blazebit.persistence.criteria.impl.BlazeCriteria; +import com.blazebit.persistence.spring.data.api.repository.EntityViewRepository; import com.blazebit.persistence.view.EntityViewManager; import com.blazebit.persistence.view.EntityViewSetting; import org.springframework.data.domain.Page; diff --git a/integration/spring-data/src/main/java/com/blazebit/persistence/impl/springdata/repository/EntityViewSpecificationExecutor.java b/integration/spring-data/src/main/java/com/blazebit/persistence/spring/data/impl/repository/EntityViewSpecificationExecutor.java similarity index 95% rename from integration/spring-data/src/main/java/com/blazebit/persistence/impl/springdata/repository/EntityViewSpecificationExecutor.java rename to integration/spring-data/src/main/java/com/blazebit/persistence/spring/data/impl/repository/EntityViewSpecificationExecutor.java index 6cd3b24cf9..ef527f9cdd 100644 --- a/integration/spring-data/src/main/java/com/blazebit/persistence/impl/springdata/repository/EntityViewSpecificationExecutor.java +++ b/integration/spring-data/src/main/java/com/blazebit/persistence/spring/data/impl/repository/EntityViewSpecificationExecutor.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.blazebit.persistence.impl.springdata.repository; +package com.blazebit.persistence.spring.data.impl.repository; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; diff --git a/integration/spring-data/src/main/java/org/springframework/data/jpa/repository/query/PartTreeEntityViewQuery.java b/integration/spring-data/src/main/java/org/springframework/data/jpa/repository/query/PartTreeEntityViewQuery.java index 1892be156d..fcdd48e5f6 100644 --- a/integration/spring-data/src/main/java/org/springframework/data/jpa/repository/query/PartTreeEntityViewQuery.java +++ b/integration/spring-data/src/main/java/org/springframework/data/jpa/repository/query/PartTreeEntityViewQuery.java @@ -20,7 +20,7 @@ import com.blazebit.persistence.CriteriaBuilderFactory; import com.blazebit.persistence.criteria.BlazeCriteriaQuery; import com.blazebit.persistence.criteria.impl.BlazeCriteria; -import com.blazebit.persistence.impl.springdata.query.EntityViewAwareJpaQueryMethod; +import com.blazebit.persistence.spring.data.impl.query.EntityViewAwareJpaQueryMethod; import com.blazebit.persistence.view.EntityViewManager; import com.blazebit.persistence.view.EntityViewSetting; import org.springframework.data.domain.Sort; diff --git a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/AbstractSpringTest.java b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/AbstractSpringTest.java similarity index 97% rename from integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/AbstractSpringTest.java rename to integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/AbstractSpringTest.java index 0d21059b28..8ac62e3638 100644 --- a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/AbstractSpringTest.java +++ b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/AbstractSpringTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.blazebit.persistence.impl.springdata; +package com.blazebit.persistence.spring.data.impl; import org.junit.After; import org.junit.Before; diff --git a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/DocumentRepositoryTest.java b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/DocumentRepositoryTest.java similarity index 93% rename from integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/DocumentRepositoryTest.java rename to integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/DocumentRepositoryTest.java index 8970f9b128..f3a50187f5 100644 --- a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/DocumentRepositoryTest.java +++ b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/DocumentRepositoryTest.java @@ -14,19 +14,19 @@ * limitations under the License. */ -package com.blazebit.persistence.impl.springdata; - -import com.blazebit.persistence.impl.springdata.accessor.DocumentAccessor; -import com.blazebit.persistence.impl.springdata.accessor.DocumentAccessors; -import com.blazebit.persistence.impl.springdata.config.SystemPropertyBasedActiveProfilesResolver; -import com.blazebit.persistence.impl.springdata.entity.Document; -import com.blazebit.persistence.impl.springdata.entity.Person; -import com.blazebit.persistence.impl.springdata.repository.DocumentEntityRepository; -import com.blazebit.persistence.impl.springdata.repository.DocumentRepository; -import com.blazebit.persistence.impl.springdata.repository.DocumentViewRepository; -import com.blazebit.persistence.impl.springdata.repository.EntityViewRepositoryFactoryBean; -import com.blazebit.persistence.impl.springdata.tx.TransactionalWorkService; -import com.blazebit.persistence.impl.springdata.tx.TxWork; +package com.blazebit.persistence.spring.data.impl; + +import com.blazebit.persistence.spring.data.impl.accessor.DocumentAccessor; +import com.blazebit.persistence.spring.data.impl.accessor.DocumentAccessors; +import com.blazebit.persistence.spring.data.impl.config.SystemPropertyBasedActiveProfilesResolver; +import com.blazebit.persistence.spring.data.impl.entity.Document; +import com.blazebit.persistence.spring.data.impl.entity.Person; +import com.blazebit.persistence.spring.data.impl.repository.DocumentEntityRepository; +import com.blazebit.persistence.spring.data.impl.repository.DocumentRepository; +import com.blazebit.persistence.spring.data.impl.repository.DocumentViewRepository; +import com.blazebit.persistence.spring.data.impl.repository.EntityViewRepositoryFactoryBean; +import com.blazebit.persistence.spring.data.impl.tx.TransactionalWorkService; +import com.blazebit.persistence.spring.data.impl.tx.TxWork; import com.blazebit.persistence.view.impl.spring.EnableEntityViews; import org.junit.Assume; import org.junit.Before; @@ -489,10 +489,10 @@ private boolean isEclipseLink() { @Configuration @ComponentScan - @ImportResource("classpath:/com/blazebit/persistence/impl/springdata/application-config.xml") - @EnableEntityViews(basePackages = {"org.springframework.data.jpa.repository.support", "com.blazebit.persistence.impl.springdata.view"}) + @ImportResource("classpath:/com/blazebit/persistence/spring/data/impl/application-config.xml") + @EnableEntityViews(basePackages = {"org.springframework.data.jpa.repository.support", "com.blazebit.persistence.spring.data.impl.view"}) @EnableJpaRepositories( - basePackages = "com.blazebit.persistence.impl.springdata.repository", + basePackages = "com.blazebit.persistence.spring.data.impl.repository", entityManagerFactoryRef = "myEmf", repositoryFactoryBeanClass = EntityViewRepositoryFactoryBean.class) static class TestConfig { diff --git a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/accessor/DocumentAccessor.java b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/accessor/DocumentAccessor.java similarity index 93% rename from integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/accessor/DocumentAccessor.java rename to integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/accessor/DocumentAccessor.java index b9fa9831e4..3f55e78028 100644 --- a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/accessor/DocumentAccessor.java +++ b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/accessor/DocumentAccessor.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.blazebit.persistence.impl.springdata.accessor; +package com.blazebit.persistence.spring.data.impl.accessor; import javax.persistence.GeneratedValue; import javax.persistence.Id; diff --git a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/accessor/DocumentAccessors.java b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/accessor/DocumentAccessors.java similarity index 94% rename from integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/accessor/DocumentAccessors.java rename to integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/accessor/DocumentAccessors.java index ecfd5ec1ef..f952ca5d6b 100644 --- a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/accessor/DocumentAccessors.java +++ b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/accessor/DocumentAccessors.java @@ -14,10 +14,10 @@ * limitations under the License. */ -package com.blazebit.persistence.impl.springdata.accessor; +package com.blazebit.persistence.spring.data.impl.accessor; -import com.blazebit.persistence.impl.springdata.entity.Document; -import com.blazebit.persistence.impl.springdata.view.DocumentView; +import com.blazebit.persistence.spring.data.impl.entity.Document; +import com.blazebit.persistence.spring.data.impl.view.DocumentView; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageRequest; diff --git a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/config/BlazePersistenceConfiguration.java b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/config/BlazePersistenceConfiguration.java similarity index 97% rename from integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/config/BlazePersistenceConfiguration.java rename to integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/config/BlazePersistenceConfiguration.java index 2b9554a6b3..0d0c62389d 100644 --- a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/config/BlazePersistenceConfiguration.java +++ b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/config/BlazePersistenceConfiguration.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.blazebit.persistence.impl.springdata.config; +package com.blazebit.persistence.spring.data.impl.config; import com.blazebit.persistence.Criteria; import com.blazebit.persistence.CriteriaBuilderFactory; diff --git a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/config/SystemPropertyBasedActiveProfilesResolver.java b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/config/SystemPropertyBasedActiveProfilesResolver.java similarity index 95% rename from integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/config/SystemPropertyBasedActiveProfilesResolver.java rename to integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/config/SystemPropertyBasedActiveProfilesResolver.java index 4a1af3a063..3053b2b9d5 100644 --- a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/config/SystemPropertyBasedActiveProfilesResolver.java +++ b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/config/SystemPropertyBasedActiveProfilesResolver.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.blazebit.persistence.impl.springdata.config; +package com.blazebit.persistence.spring.data.impl.config; import org.springframework.test.context.support.DefaultActiveProfilesResolver; diff --git a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/entity/Document.java b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/entity/Document.java similarity index 96% rename from integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/entity/Document.java rename to integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/entity/Document.java index 6f924692f7..d823b31755 100644 --- a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/entity/Document.java +++ b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/entity/Document.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.blazebit.persistence.impl.springdata.entity; +package com.blazebit.persistence.spring.data.impl.entity; import javax.persistence.Entity; import javax.persistence.GeneratedValue; diff --git a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/entity/Person.java b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/entity/Person.java similarity index 96% rename from integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/entity/Person.java rename to integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/entity/Person.java index 216645538c..1c47d867b1 100644 --- a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/entity/Person.java +++ b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/entity/Person.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.blazebit.persistence.impl.springdata.entity; +package com.blazebit.persistence.spring.data.impl.entity; import javax.persistence.*; import java.io.Serializable; diff --git a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/repository/DocumentEntityRepository.java b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/repository/DocumentEntityRepository.java similarity index 87% rename from integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/repository/DocumentEntityRepository.java rename to integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/repository/DocumentEntityRepository.java index 913ae0704a..bbaa9eb959 100644 --- a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/repository/DocumentEntityRepository.java +++ b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/repository/DocumentEntityRepository.java @@ -14,9 +14,9 @@ * limitations under the License. */ -package com.blazebit.persistence.impl.springdata.repository; +package com.blazebit.persistence.spring.data.impl.repository; -import com.blazebit.persistence.impl.springdata.entity.Document; +import com.blazebit.persistence.spring.data.impl.entity.Document; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; diff --git a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/repository/DocumentRepository.java b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/repository/DocumentRepository.java similarity index 89% rename from integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/repository/DocumentRepository.java rename to integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/repository/DocumentRepository.java index 813523f296..fbc1f6bd13 100644 --- a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/repository/DocumentRepository.java +++ b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/repository/DocumentRepository.java @@ -14,9 +14,10 @@ * limitations under the License. */ -package com.blazebit.persistence.impl.springdata.repository; +package com.blazebit.persistence.spring.data.impl.repository; -import com.blazebit.persistence.impl.springdata.entity.Document; +import com.blazebit.persistence.spring.data.api.repository.EntityViewRepository; +import com.blazebit.persistence.spring.data.impl.entity.Document; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; diff --git a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/repository/DocumentViewRepository.java b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/repository/DocumentViewRepository.java similarity index 87% rename from integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/repository/DocumentViewRepository.java rename to integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/repository/DocumentViewRepository.java index 4565abde59..ee1b986148 100644 --- a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/repository/DocumentViewRepository.java +++ b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/repository/DocumentViewRepository.java @@ -14,9 +14,9 @@ * limitations under the License. */ -package com.blazebit.persistence.impl.springdata.repository; +package com.blazebit.persistence.spring.data.impl.repository; -import com.blazebit.persistence.impl.springdata.view.DocumentView; +import com.blazebit.persistence.spring.data.impl.view.DocumentView; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; diff --git a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/tx/TransactionalWorkService.java b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/tx/TransactionalWorkService.java similarity index 95% rename from integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/tx/TransactionalWorkService.java rename to integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/tx/TransactionalWorkService.java index f15ef5f95d..35d01e8e20 100644 --- a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/tx/TransactionalWorkService.java +++ b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/tx/TransactionalWorkService.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.blazebit.persistence.impl.springdata.tx; +package com.blazebit.persistence.spring.data.impl.tx; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; diff --git a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/tx/TxVoidWork.java b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/tx/TxVoidWork.java similarity index 93% rename from integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/tx/TxVoidWork.java rename to integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/tx/TxVoidWork.java index b8bca8ebac..c51d3a2cd8 100644 --- a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/tx/TxVoidWork.java +++ b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/tx/TxVoidWork.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.blazebit.persistence.impl.springdata.tx; +package com.blazebit.persistence.spring.data.impl.tx; import javax.persistence.EntityManager; diff --git a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/tx/TxWork.java b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/tx/TxWork.java similarity index 93% rename from integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/tx/TxWork.java rename to integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/tx/TxWork.java index b5a63ed5bd..47fcb9e773 100644 --- a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/tx/TxWork.java +++ b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/tx/TxWork.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.blazebit.persistence.impl.springdata.tx; +package com.blazebit.persistence.spring.data.impl.tx; import javax.persistence.EntityManager; diff --git a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/view/DocumentView.java b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/view/DocumentView.java similarity index 88% rename from integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/view/DocumentView.java rename to integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/view/DocumentView.java index c126e3b99a..3242c8be08 100644 --- a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/view/DocumentView.java +++ b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/view/DocumentView.java @@ -14,9 +14,9 @@ * limitations under the License. */ -package com.blazebit.persistence.impl.springdata.view; +package com.blazebit.persistence.spring.data.impl.view; -import com.blazebit.persistence.impl.springdata.entity.Document; +import com.blazebit.persistence.spring.data.impl.entity.Document; import com.blazebit.persistence.view.EntityView; import com.blazebit.persistence.view.IdMapping; diff --git a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/view/PersonView.java b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/view/PersonView.java similarity index 88% rename from integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/view/PersonView.java rename to integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/view/PersonView.java index 454b4c8e0f..9d4a4bc584 100644 --- a/integration/spring-data/src/test/java/com/blazebit/persistence/impl/springdata/view/PersonView.java +++ b/integration/spring-data/src/test/java/com/blazebit/persistence/spring/data/impl/view/PersonView.java @@ -14,9 +14,9 @@ * limitations under the License. */ -package com.blazebit.persistence.impl.springdata.view; +package com.blazebit.persistence.spring.data.impl.view; -import com.blazebit.persistence.impl.springdata.entity.Person; +import com.blazebit.persistence.spring.data.impl.entity.Person; import com.blazebit.persistence.view.EntityView; import com.blazebit.persistence.view.IdMapping; diff --git a/integration/spring-data/src/test/resources/com/blazebit/persistence/impl/springdata/application-config.xml b/integration/spring-data/src/test/resources/com/blazebit/persistence/spring/data/impl/application-config.xml similarity index 100% rename from integration/spring-data/src/test/resources/com/blazebit/persistence/impl/springdata/application-config.xml rename to integration/spring-data/src/test/resources/com/blazebit/persistence/spring/data/impl/application-config.xml diff --git a/parent/pom.xml b/parent/pom.xml index a4a8aa690c..8d73f4ab17 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -37,7 +37,7 @@ 0.2.0 0.1.15 - 1.0.1 + 1.8.0 4.12 3.18.2-GA @@ -74,6 +74,8 @@ 4.6.0 6.0-4 + 2.4.5.Final + 3.3.2 1.0.2 @@ -239,6 +241,16 @@ blaze-persistence-integration-spring-data ${project.version} + + com.blazebit + blaze-persistence-integration-deltaspike-data-api + ${project.version} + + + com.blazebit + blaze-persistence-integration-deltaspike-data-impl + ${project.version} + ${project.groupId} blaze-persistence-showcase-base @@ -274,6 +286,20 @@ provided + + org.apache.deltaspike.distribution + distributions-bom + ${version.deltaspike} + pom + import + + + + org.jboss.weld.se + weld-se-core + ${version.weld} + + junit @@ -287,36 +313,13 @@ 1.2.0 test - - org.apache.deltaspike.core - deltaspike-core-api - ${version.deltaspike} - test - - - org.apache.deltaspike.core - deltaspike-core-impl - ${version.deltaspike} - test - + org.apache.openejb openejb-core ${version.openejb} test - - org.apache.deltaspike.cdictrl - deltaspike-cdictrl-api - ${version.deltaspike} - test - - - org.apache.deltaspike.cdictrl - deltaspike-cdictrl-openejb - ${version.deltaspike} - test -