diff --git a/.gitignore b/.gitignore index 8dda6a9dd1..a7df9ee514 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,5 @@ gradle-app.setting *~ \#* /.metadata/ -docs/ \ No newline at end of file +docs/ +.vscode/ diff --git a/settings.gradle b/settings.gradle index 5bbd41fc44..f44d5b8e13 100644 --- a/settings.gradle +++ b/settings.gradle @@ -36,6 +36,7 @@ include('plastic', 'tapestry-upload', 'tapestry-beanvalidator', 'tapestry-jpa', + 'tapestry-jpa-core', 'tapestry-kaptcha', //'quickstart', 'tapestry-clojure', diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java index 0709fd572a..622df17743 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java @@ -1213,7 +1213,7 @@ public Resource coerce(String input) return assetSource.resourceForPath(input); } }); - configuration.add(stringToResource.getKey(), stringToResource); + configuration.override(stringToResource.getKey(), stringToResource); CoercionTuple renderableToRenderCommand = CoercionTuple.create(Renderable.class, RenderCommand.class, new Coercion() diff --git a/tapestry-core/src/main/typescript/package-lock.json b/tapestry-core/src/main/typescript/package-lock.json index de9f7e7ca3..336639a5d8 100644 --- a/tapestry-core/src/main/typescript/package-lock.json +++ b/tapestry-core/src/main/typescript/package-lock.json @@ -369,7 +369,6 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", "dev": true, - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/modules/TapestryIOCModule.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/modules/TapestryIOCModule.java index 2aeed2235d..4f739e94b8 100644 --- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/modules/TapestryIOCModule.java +++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/modules/TapestryIOCModule.java @@ -60,6 +60,7 @@ import org.apache.tapestry5.ioc.internal.services.UpdateListenerHubImpl; import org.apache.tapestry5.ioc.internal.services.ValueObjectProvider; import org.apache.tapestry5.ioc.internal.services.cron.PeriodicExecutorImpl; +import org.apache.tapestry5.ioc.internal.util.ClasspathResource; import org.apache.tapestry5.ioc.internal.util.InternalUtils; import org.apache.tapestry5.ioc.services.ApplicationDefaults; import org.apache.tapestry5.ioc.services.AspectDecorator; @@ -312,6 +313,23 @@ public static void provideJSR10TypeCoercions(MappedConfiguration configuration) + { + Coercion stringToResource = new Coercion() + { + @Override + public Resource coerce(String input) + { + return new ClasspathResource(input); + } + }; + + CoercionTuple stringToResourceTuple = CoercionTuple.create(String.class, Resource.class, stringToResource); + + configuration.add(stringToResourceTuple.getKey(), stringToResourceTuple); + } + /** *
*
SystemProperties
diff --git a/tapestry-jpa-core/LICENSE.txt b/tapestry-jpa-core/LICENSE.txt new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/tapestry-jpa-core/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/tapestry-jpa-core/NOTICE.txt b/tapestry-jpa-core/NOTICE.txt new file mode 100644 index 0000000000..2ee18498c4 --- /dev/null +++ b/tapestry-jpa-core/NOTICE.txt @@ -0,0 +1,12 @@ +This product includes software developed by +The Apache Software Foundation (http://www.apache.org/). + +Please refer to the NOTICE.txt in each sub-module to +identify further dependencies. + +The Maven central repository is the prefered method to download Tapestry +and its dependencies. The binary archive includes just basic +dependencies for tapestry-core; using other modules (such as +tapestry-hibernate or any of the others) requires downloading +additional dependencies. Please refer to the Maven POM for each module +to identify its dependencies. diff --git a/tapestry-jpa-core/build.gradle b/tapestry-jpa-core/build.gradle new file mode 100644 index 0000000000..b9b3feb61f --- /dev/null +++ b/tapestry-jpa-core/build.gradle @@ -0,0 +1,28 @@ +plugins { + id 'tapestry.junit5-spock-convention' + id 'groovy' +} + +description = 'Provides support for JPA without a dependency on tapestry-core' + +dependencies { + api libs.jakarta.persistence.api + implementation libs.jakarta.cdi.api + + implementation project(':commons') + implementation project(':tapestry-ioc') + + testImplementation project(':tapestry-test') + testRuntimeOnly project(':tapestry-spock') + + testImplementation libs.eclipselink + + testRuntimeOnly libs.dbcp + testRuntimeOnly libs.h2 +} + +tasks.named('jar', Jar) { + manifest { + attributes 'Tapestry-Module-Classes': 'org.apache.tapestry5.jpa.core.modules.JpaCoreModule' + } +} diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/CommitAfterMethodAdvice.java b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/CommitAfterMethodAdvice.java similarity index 88% rename from tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/CommitAfterMethodAdvice.java rename to tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/CommitAfterMethodAdvice.java index d73444467f..ed50791d2d 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/CommitAfterMethodAdvice.java +++ b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/CommitAfterMethodAdvice.java @@ -1,4 +1,4 @@ -// Copyright 2011, 2012, 2014 The Apache Software Foundation +// Copyright 2011, 2012, 2014, 2026 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -package org.apache.tapestry5.internal.jpa; +package org.apache.tapestry5.internal.jpa.core; import org.apache.tapestry5.ioc.Invokable; -import org.apache.tapestry5.jpa.EntityTransactionManager; +import org.apache.tapestry5.jpa.core.EntityTransactionManager; import org.apache.tapestry5.plastic.MethodAdvice; import org.apache.tapestry5.plastic.MethodInvocation; diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/EntityManagerManagerImpl.java b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/EntityManagerManagerImpl.java similarity index 93% rename from tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/EntityManagerManagerImpl.java rename to tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/EntityManagerManagerImpl.java index 77a2ef5bb0..2c4d5be41a 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/EntityManagerManagerImpl.java +++ b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/EntityManagerManagerImpl.java @@ -1,4 +1,4 @@ -// Copyright 2011 The Apache Software Foundation +// Copyright 2011, 2026 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package org.apache.tapestry5.internal.jpa; +package org.apache.tapestry5.internal.jpa.core; import java.util.Collections; import java.util.Map; @@ -23,8 +23,8 @@ import org.apache.tapestry5.commons.util.CollectionFactory; import org.apache.tapestry5.ioc.services.ThreadCleanupListener; -import org.apache.tapestry5.jpa.EntityManagerManager; -import org.apache.tapestry5.jpa.EntityManagerSource; +import org.apache.tapestry5.jpa.core.EntityManagerManager; +import org.apache.tapestry5.jpa.core.EntityManagerSource; import org.slf4j.Logger; public class EntityManagerManagerImpl implements EntityManagerManager, ThreadCleanupListener diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/EntityManagerObjectProvider.java b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/EntityManagerObjectProvider.java similarity index 91% rename from tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/EntityManagerObjectProvider.java rename to tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/EntityManagerObjectProvider.java index 004e7bb941..692c0e978c 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/EntityManagerObjectProvider.java +++ b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/EntityManagerObjectProvider.java @@ -1,4 +1,4 @@ -// Copyright 2011 The Apache Software Foundation +// Copyright 2011, 2026 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package org.apache.tapestry5.internal.jpa; +package org.apache.tapestry5.internal.jpa.core; import java.util.HashMap; import java.util.Map; @@ -25,7 +25,7 @@ import org.apache.tapestry5.commons.ObjectLocator; import org.apache.tapestry5.commons.ObjectProvider; import org.apache.tapestry5.commons.services.PlasticProxyFactory; -import org.apache.tapestry5.jpa.EntityManagerManager; +import org.apache.tapestry5.jpa.core.EntityManagerManager; public class EntityManagerObjectProvider implements ObjectProvider { @@ -64,7 +64,7 @@ public Object createObject() final EntityManagerManager entityManagerManager = objectLocator .getService(EntityManagerManager.class); - return JpaInternalUtils.getEntityManager(entityManagerManager, annotation); + return JpaCoreInternalUtils.getEntityManager(entityManagerManager, annotation); } }, ""); emProxyByName.put(unitName, proxy); diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/EntityManagerSourceImpl.java b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/EntityManagerSourceImpl.java similarity index 91% rename from tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/EntityManagerSourceImpl.java rename to tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/EntityManagerSourceImpl.java index b819d1a965..eb130b1358 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/EntityManagerSourceImpl.java +++ b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/EntityManagerSourceImpl.java @@ -1,4 +1,4 @@ -// Copyright 2011 The Apache Software Foundation +// Copyright 2011, 2026 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,8 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -package org.apache.tapestry5.internal.jpa; +package org.apache.tapestry5.internal.jpa.core; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; import java.io.InputStream; import java.util.Collections; import java.util.List; @@ -29,6 +32,7 @@ import jakarta.persistence.spi.PersistenceUnitInfo; import org.apache.tapestry5.commons.Resource; +import org.apache.tapestry5.commons.services.TypeCoercer; import org.apache.tapestry5.commons.util.CollectionFactory; import org.apache.tapestry5.func.F; import org.apache.tapestry5.func.Mapper; @@ -37,12 +41,13 @@ import org.apache.tapestry5.ioc.annotations.PostInjection; import org.apache.tapestry5.ioc.annotations.Symbol; import org.apache.tapestry5.ioc.internal.util.InternalUtils; +import org.apache.tapestry5.ioc.internal.util.ClasspathResource; import org.apache.tapestry5.ioc.services.RegistryShutdownHub; -import org.apache.tapestry5.jpa.EntityManagerSource; -import org.apache.tapestry5.jpa.JpaConstants; -import org.apache.tapestry5.jpa.JpaSymbols; -import org.apache.tapestry5.jpa.PersistenceUnitConfigurer; -import org.apache.tapestry5.jpa.TapestryPersistenceUnitInfo; +import org.apache.tapestry5.jpa.core.EntityManagerSource; +import org.apache.tapestry5.jpa.core.JpaCoreConstants; +import org.apache.tapestry5.jpa.core.JpaCoreSymbols; +import org.apache.tapestry5.jpa.core.PersistenceUnitConfigurer; +import org.apache.tapestry5.jpa.core.TapestryPersistenceUnitInfo; import org.slf4j.Logger; public class EntityManagerSourceImpl implements EntityManagerSource @@ -54,10 +59,10 @@ public class EntityManagerSourceImpl implements EntityManagerSource private final List persistenceUnitInfos; - public EntityManagerSourceImpl(Logger logger, @Symbol(JpaSymbols.PERSISTENCE_DESCRIPTOR) - final Resource persistenceDescriptor, @Local - PersistenceUnitConfigurer packageNamePersistenceUnitConfigurer, - Map configuration) + public EntityManagerSourceImpl(Logger logger, + @Symbol(JpaCoreSymbols.PERSISTENCE_DESCRIPTOR) Resource persistenceDescriptor, + @Local PersistenceUnitConfigurer packageNamePersistenceUnitConfigurer, + Map configuration) { this.logger = logger; @@ -215,7 +220,7 @@ EntityManagerFactory createEntityManagerFactory(final String persistenceUnitName if (info.getPersistenceUnitName().equals(persistenceUnitName)) { final Map properties = info.getEntityManagerProperties() == null ? CollectionFactory.newCaseInsensitiveMap() : info.getEntityManagerProperties(); - properties.put(JpaConstants.PERSISTENCE_UNIT_NAME, persistenceUnitName); + properties.put(JpaCoreConstants.PERSISTENCE_UNIT_NAME, persistenceUnitName); String providerClassName = info.getPersistenceProviderClassName(); diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/EntityTransactionManagerImpl.java b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/EntityTransactionManagerImpl.java similarity index 96% rename from tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/EntityTransactionManagerImpl.java rename to tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/EntityTransactionManagerImpl.java index 31b09b0e92..b1d8c8039d 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/EntityTransactionManagerImpl.java +++ b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/EntityTransactionManagerImpl.java @@ -11,7 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.tapestry5.internal.jpa; +package org.apache.tapestry5.internal.jpa.core; import java.util.HashMap; import java.util.Map; @@ -21,8 +21,8 @@ import org.apache.tapestry5.ioc.Invokable; import org.apache.tapestry5.ioc.ScopeConstants; import org.apache.tapestry5.ioc.annotations.Scope; -import org.apache.tapestry5.jpa.EntityManagerManager; -import org.apache.tapestry5.jpa.EntityTransactionManager; +import org.apache.tapestry5.jpa.core.EntityManagerManager; +import org.apache.tapestry5.jpa.core.EntityTransactionManager; import org.slf4j.Logger; @Scope(ScopeConstants.PERTHREAD) diff --git a/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/JpaCoreInternalUtils.java b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/JpaCoreInternalUtils.java new file mode 100644 index 0000000000..f054bd7d70 --- /dev/null +++ b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/JpaCoreInternalUtils.java @@ -0,0 +1,79 @@ +// Copyright 2011, 2026 The Apache Software Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.apache.tapestry5.internal.jpa.core; + +import java.util.Map; +import java.util.Set; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.PersistenceContext; +import jakarta.persistence.metamodel.EntityType; +import jakarta.persistence.metamodel.Metamodel; + +import org.apache.tapestry5.ioc.internal.util.InternalUtils; +import org.apache.tapestry5.jpa.core.EntityManagerManager; +import org.apache.tapestry5.jpa.core.JpaCoreConstants; + +public class JpaCoreInternalUtils +{ + private static EntityManager getEntityManagerFactory( + final EntityManagerManager entityManagerManager, final Object entity) + { + final Map entityManagers = entityManagerManager.getEntityManagers(); + + for (final EntityManager em : entityManagers.values()) + { + final EntityManagerFactory emf = em.getEntityManagerFactory(); + + final Metamodel metamodel = emf.getMetamodel(); + + final Set> entities = metamodel.getEntities(); + + for (final EntityType entityType : entities) + { + if (entityType.getJavaType().equals(entity.getClass())) + { + if (em.contains(entity)) + { + return em; + } + } + } + } + + throw new IllegalArgumentException( + String.format( + "Failed persisting the entity. The entity '%s' does not belong to any of the existing persistence contexts.", + entity)); + } + + public static EntityManager getEntityManager(EntityManagerManager entityManagerManager, + PersistenceContext annotation) + { + String unitName = annotation == null ? null : annotation.unitName(); + + if (InternalUtils.isNonBlank(unitName)) + return entityManagerManager.getEntityManager(unitName); + + Map entityManagers = entityManagerManager.getEntityManagers(); + + if (entityManagers.size() == 1) + return entityManagers.values().iterator().next(); + + throw new RuntimeException("Unable to locate a single EntityManager. " + + "You must provide the persistence unit name as defined in the persistence.xml using the @PersistenceContext annotation."); + } +} diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/JpaTransactionAdvisorImpl.java b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/JpaTransactionAdvisorImpl.java similarity index 85% rename from tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/JpaTransactionAdvisorImpl.java rename to tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/JpaTransactionAdvisorImpl.java index 4b29e849f5..43ef62a47d 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/JpaTransactionAdvisorImpl.java +++ b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/JpaTransactionAdvisorImpl.java @@ -1,4 +1,4 @@ -// Copyright 2015 The Apache Software Foundation +// Copyright 2015, 2026 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package org.apache.tapestry5.internal.jpa; +package org.apache.tapestry5.internal.jpa.core; import java.lang.reflect.Method; import java.util.HashMap; @@ -22,10 +22,10 @@ import jakarta.persistence.PersistenceContext; import org.apache.tapestry5.ioc.MethodAdviceReceiver; -import org.apache.tapestry5.jpa.EntityManagerManager; -import org.apache.tapestry5.jpa.EntityTransactionManager; -import org.apache.tapestry5.jpa.JpaTransactionAdvisor; -import org.apache.tapestry5.jpa.annotations.CommitAfter; +import org.apache.tapestry5.jpa.core.EntityManagerManager; +import org.apache.tapestry5.jpa.core.EntityTransactionManager; +import org.apache.tapestry5.jpa.core.JpaTransactionAdvisor; +import org.apache.tapestry5.jpa.core.annotations.CommitAfter; import org.apache.tapestry5.plastic.MethodAdvice; public class JpaTransactionAdvisorImpl implements JpaTransactionAdvisor diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/NoopAnnotatedType.java b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/NoopAnnotatedType.java similarity index 97% rename from tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/NoopAnnotatedType.java rename to tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/NoopAnnotatedType.java index a0d675c89a..46bad1f69c 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/NoopAnnotatedType.java +++ b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/NoopAnnotatedType.java @@ -11,7 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.tapestry5.internal.jpa; +package org.apache.tapestry5.internal.jpa.core; import java.lang.annotation.Annotation; import java.lang.reflect.Type; diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/NoopBeanManager.java b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/NoopBeanManager.java similarity index 99% rename from tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/NoopBeanManager.java rename to tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/NoopBeanManager.java index 6b1e4833d9..e4e95ad8b1 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/NoopBeanManager.java +++ b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/NoopBeanManager.java @@ -11,7 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.tapestry5.internal.jpa; +package org.apache.tapestry5.internal.jpa.core; import java.lang.annotation.Annotation; import java.lang.reflect.Type; diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/NoopCreationalContext.java b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/NoopCreationalContext.java similarity index 94% rename from tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/NoopCreationalContext.java rename to tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/NoopCreationalContext.java index 1a1f57541a..9d70ba2997 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/NoopCreationalContext.java +++ b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/NoopCreationalContext.java @@ -11,7 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.tapestry5.internal.jpa; +package org.apache.tapestry5.internal.jpa.core; import jakarta.enterprise.context.spi.CreationalContext; diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/NoopInjectionTarget.java b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/NoopInjectionTarget.java similarity index 97% rename from tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/NoopInjectionTarget.java rename to tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/NoopInjectionTarget.java index 06e727b062..0109835f77 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/NoopInjectionTarget.java +++ b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/NoopInjectionTarget.java @@ -11,7 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.tapestry5.internal.jpa; +package org.apache.tapestry5.internal.jpa.core; import java.util.Set; diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/PackageNamePersistenceUnitConfigurer.java b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/PackageNamePersistenceUnitConfigurer.java similarity index 83% rename from tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/PackageNamePersistenceUnitConfigurer.java rename to tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/PackageNamePersistenceUnitConfigurer.java index f85d598c41..a2c71d5067 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/PackageNamePersistenceUnitConfigurer.java +++ b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/PackageNamePersistenceUnitConfigurer.java @@ -1,4 +1,4 @@ -// Copyright 2011 The Apache Software Foundation +// Copyright 2011, 2026 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,12 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -package org.apache.tapestry5.internal.jpa; +package org.apache.tapestry5.internal.jpa.core; import org.apache.tapestry5.ioc.services.ClassNameLocator; -import org.apache.tapestry5.jpa.JpaEntityPackageManager; -import org.apache.tapestry5.jpa.PersistenceUnitConfigurer; -import org.apache.tapestry5.jpa.TapestryPersistenceUnitInfo; +import org.apache.tapestry5.jpa.core.JpaEntityPackageManager; +import org.apache.tapestry5.jpa.core.PersistenceUnitConfigurer; +import org.apache.tapestry5.jpa.core.TapestryPersistenceUnitInfo; public class PackageNamePersistenceUnitConfigurer implements PersistenceUnitConfigurer { diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/PersistenceContentHandler.java b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/PersistenceContentHandler.java similarity index 94% rename from tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/PersistenceContentHandler.java rename to tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/PersistenceContentHandler.java index a27c67ab43..34d7180295 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/PersistenceContentHandler.java +++ b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/PersistenceContentHandler.java @@ -1,4 +1,4 @@ -// Copyright 2011, 2014 The Apache Software Foundation +// Copyright 2011, 2014, 2026 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -package org.apache.tapestry5.internal.jpa; +package org.apache.tapestry5.internal.jpa.core; import java.util.Arrays; import java.util.List; import org.apache.tapestry5.commons.util.CollectionFactory; -import org.apache.tapestry5.jpa.TapestryPersistenceUnitInfo; +import org.apache.tapestry5.jpa.core.TapestryPersistenceUnitInfo; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.Locator; diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/PersistenceContextSpecificEntityTransactionManager.java b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/PersistenceContextSpecificEntityTransactionManager.java similarity index 98% rename from tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/PersistenceContextSpecificEntityTransactionManager.java rename to tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/PersistenceContextSpecificEntityTransactionManager.java index 0962062695..401d0deacf 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/PersistenceContextSpecificEntityTransactionManager.java +++ b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/PersistenceContextSpecificEntityTransactionManager.java @@ -11,7 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.tapestry5.internal.jpa; +package org.apache.tapestry5.internal.jpa.core; import java.util.ArrayDeque; import java.util.ArrayList; @@ -23,7 +23,7 @@ import jakarta.persistence.EntityTransaction; import org.apache.tapestry5.ioc.Invokable; -import org.apache.tapestry5.jpa.EntityTransactionManager.VoidInvokable; +import org.apache.tapestry5.jpa.core.EntityTransactionManager.VoidInvokable; import org.slf4j.Logger; public class PersistenceContextSpecificEntityTransactionManager diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/PersistenceParser.java b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/PersistenceParser.java similarity index 89% rename from tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/PersistenceParser.java rename to tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/PersistenceParser.java index cf2402fb09..1fa78a1d43 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/PersistenceParser.java +++ b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/PersistenceParser.java @@ -1,4 +1,4 @@ -// Copyright 2011 The Apache Software Foundation +// Copyright 2011, 2026 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -package org.apache.tapestry5.internal.jpa; +package org.apache.tapestry5.internal.jpa.core; import org.apache.tapestry5.ioc.internal.util.InternalUtils; -import org.apache.tapestry5.jpa.TapestryPersistenceUnitInfo; +import org.apache.tapestry5.jpa.core.TapestryPersistenceUnitInfo; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; import org.xml.sax.helpers.XMLReaderFactory; diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/PersistenceUnitInfoImpl.java b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/PersistenceUnitInfoImpl.java similarity index 98% rename from tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/PersistenceUnitInfoImpl.java rename to tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/PersistenceUnitInfoImpl.java index c0235d850c..ccc0c5e7bc 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/PersistenceUnitInfoImpl.java +++ b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/PersistenceUnitInfoImpl.java @@ -1,4 +1,4 @@ -// Copyright 2011 The Apache Software Foundation +// Copyright 2011, 2026 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -package org.apache.tapestry5.internal.jpa; +package org.apache.tapestry5.internal.jpa.core; import org.apache.tapestry5.commons.util.CollectionFactory; -import org.apache.tapestry5.jpa.TapestryPersistenceUnitInfo; +import org.apache.tapestry5.jpa.core.TapestryPersistenceUnitInfo; import javax.naming.Context; import javax.naming.InitialContext; diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/TapestryCDIBeanManagerForJPAEntityListeners.java b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/TapestryCDIBeanManagerForJPAEntityListeners.java similarity index 98% rename from tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/TapestryCDIBeanManagerForJPAEntityListeners.java rename to tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/TapestryCDIBeanManagerForJPAEntityListeners.java index c608abf438..ccc8970d49 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/TapestryCDIBeanManagerForJPAEntityListeners.java +++ b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/internal/jpa/core/TapestryCDIBeanManagerForJPAEntityListeners.java @@ -11,7 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.tapestry5.internal.jpa; +package org.apache.tapestry5.internal.jpa.core; import java.lang.reflect.Method; diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/EntityManagerManager.java b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/EntityManagerManager.java similarity index 97% rename from tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/EntityManagerManager.java rename to tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/EntityManagerManager.java index 699d22b9da..53a628f7b0 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/EntityManagerManager.java +++ b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/EntityManagerManager.java @@ -10,7 +10,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package org.apache.tapestry5.jpa; +package org.apache.tapestry5.jpa.core; import jakarta.persistence.EntityManager; import java.util.Map; diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/EntityManagerSource.java b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/EntityManagerSource.java similarity index 97% rename from tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/EntityManagerSource.java rename to tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/EntityManagerSource.java index a52852c960..a2ba7e2072 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/EntityManagerSource.java +++ b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/EntityManagerSource.java @@ -10,7 +10,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package org.apache.tapestry5.jpa; +package org.apache.tapestry5.jpa.core; import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManagerFactory; diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/EntityTransactionManager.java b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/EntityTransactionManager.java similarity index 97% rename from tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/EntityTransactionManager.java rename to tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/EntityTransactionManager.java index e8b2ae1c4a..13eef2ca5a 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/EntityTransactionManager.java +++ b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/EntityTransactionManager.java @@ -11,7 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.tapestry5.jpa; +package org.apache.tapestry5.jpa.core; import org.apache.tapestry5.ioc.Invokable; diff --git a/tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/JpaCoreConstants.java b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/JpaCoreConstants.java new file mode 100644 index 0000000000..3d40c8e5e2 --- /dev/null +++ b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/JpaCoreConstants.java @@ -0,0 +1,28 @@ +// Copyright 2011, 2026 The Apache Software Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.apache.tapestry5.jpa.core; + +/** + * Defines constants used inside the Tapestry JPA integration. + * + * @since 5.3 + */ +public class JpaCoreConstants +{ + /** + * Name of the EntityManager property whose value is the name of a persistence unit. + */ + public static final String PERSISTENCE_UNIT_NAME = "tapestry.persistence-unit-name"; +} diff --git a/tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/JpaCoreSymbols.java b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/JpaCoreSymbols.java new file mode 100644 index 0000000000..ababe04425 --- /dev/null +++ b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/JpaCoreSymbols.java @@ -0,0 +1,38 @@ +// Copyright 2011, 2026 The Apache Software Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.apache.tapestry5.jpa.core; + +/** + * Configuration symbols, for use with contributions to {@link org.apache.tapestry5.ioc.services.ApplicationDefaults}. + * + * @since 5.3 + */ +public class JpaCoreSymbols +{ + /** + * If "true", then JPA will be started up at application launch, rather than lazily. + * + * @since 5.3 + */ + public static final String EARLY_START_UP = "tapestry.jpa.early-startup"; + + /** + * The location of the persistence configuration file, located on the classpath. This + * will normally be /META-INF/persistence.xml. + * + * @since 5.3 + */ + public static final String PERSISTENCE_DESCRIPTOR = "tapestry.jpa.persistence-descriptor"; +} diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/JpaEntityPackageManager.java b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/JpaEntityPackageManager.java similarity index 96% rename from tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/JpaEntityPackageManager.java rename to tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/JpaEntityPackageManager.java index a4d28dc556..47d032aa3b 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/JpaEntityPackageManager.java +++ b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/JpaEntityPackageManager.java @@ -10,7 +10,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package org.apache.tapestry5.jpa; +package org.apache.tapestry5.jpa.core; import org.apache.tapestry5.ioc.annotations.UsesConfiguration; diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/JpaTransactionAdvisor.java b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/JpaTransactionAdvisor.java similarity index 90% rename from tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/JpaTransactionAdvisor.java rename to tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/JpaTransactionAdvisor.java index 10957b524c..a390ea13f1 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/JpaTransactionAdvisor.java +++ b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/JpaTransactionAdvisor.java @@ -1,4 +1,4 @@ -// Copyright 2011 The Apache Software Foundation +// Copyright 2011, 2026 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package org.apache.tapestry5.jpa; +package org.apache.tapestry5.jpa.core; import org.apache.tapestry5.ioc.MethodAdviceReceiver; @@ -29,7 +29,7 @@ public interface JpaTransactionAdvisor { /** - * Identifies any methods with the {@link org.apache.tapestry5.jpa.annotations.CommitAfter} annotation and + * Identifies any methods with the {@link org.apache.tapestry5.jpa.core.annotations.CommitAfter} annotation and * applies the transaction logic to those methods. * * @param receiver diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/PersistenceUnitConfigurer.java b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/PersistenceUnitConfigurer.java similarity index 91% rename from tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/PersistenceUnitConfigurer.java rename to tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/PersistenceUnitConfigurer.java index d1acafe15d..5c390ec67f 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/PersistenceUnitConfigurer.java +++ b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/PersistenceUnitConfigurer.java @@ -1,4 +1,4 @@ -// Copyright 2011 The Apache Software Foundation +// Copyright 2011, 2026 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package org.apache.tapestry5.jpa; +package org.apache.tapestry5.jpa.core; /** * Used to configure a {@linkplain jakarta.persistence.spi.PersistenceUnitInfo}, which is used to diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/TapestryPersistenceUnitInfo.java b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/TapestryPersistenceUnitInfo.java similarity index 98% rename from tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/TapestryPersistenceUnitInfo.java rename to tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/TapestryPersistenceUnitInfo.java index b930ca9cb6..b470100c9a 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/TapestryPersistenceUnitInfo.java +++ b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/TapestryPersistenceUnitInfo.java @@ -1,4 +1,4 @@ -// Copyright 2011, 2014 The Apache Software Foundation +// Copyright 2011, 2014, 2026 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package org.apache.tapestry5.jpa; +package org.apache.tapestry5.jpa.core; import jakarta.persistence.SharedCacheMode; import jakarta.persistence.ValidationMode; diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/annotations/CommitAfter.java b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/annotations/CommitAfter.java similarity index 91% rename from tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/annotations/CommitAfter.java rename to tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/annotations/CommitAfter.java index e715b7cfec..e2c9d965e0 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/annotations/CommitAfter.java +++ b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/annotations/CommitAfter.java @@ -1,4 +1,4 @@ -// Copyright 2011 The Apache Software Foundation +// Copyright 2011, 2026 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package org.apache.tapestry5.jpa.annotations; +package org.apache.tapestry5.jpa.core.annotations; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.RetentionPolicy.RUNTIME; diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/annotations/package-info.java b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/annotations/package-info.java similarity index 81% rename from tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/annotations/package-info.java rename to tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/annotations/package-info.java index 7f85230631..869eff0b13 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/annotations/package-info.java +++ b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/annotations/package-info.java @@ -1,4 +1,4 @@ -// Copyright 2012 The Apache Software Foundation +// Copyright 2012, 2026The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,6 +13,6 @@ // limitations under the License. /** - * JPA annotations + * JPA Core annotations */ -package org.apache.tapestry5.jpa.annotations; +package org.apache.tapestry5.jpa.core.annotations; diff --git a/tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/modules/JpaCoreModule.java b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/modules/JpaCoreModule.java new file mode 100644 index 0000000000..be05207a12 --- /dev/null +++ b/tapestry-jpa-core/src/main/java/org/apache/tapestry5/jpa/core/modules/JpaCoreModule.java @@ -0,0 +1,119 @@ +// Copyright 2011-2014, 2026 The Apache Software Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.apache.tapestry5.jpa.core.modules; + +import java.util.Collection; + +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.metamodel.EntityType; +import jakarta.persistence.metamodel.Metamodel; +import jakarta.persistence.spi.PersistenceUnitInfo; + +import org.apache.tapestry5.commons.Configuration; +import org.apache.tapestry5.commons.MappedConfiguration; +import org.apache.tapestry5.commons.ObjectProvider; +import org.apache.tapestry5.commons.OrderedConfiguration; +import org.apache.tapestry5.commons.services.PropertyAccess; +import org.apache.tapestry5.commons.services.TypeCoercer; +import org.apache.tapestry5.internal.jpa.core.EntityManagerManagerImpl; +import org.apache.tapestry5.internal.jpa.core.EntityManagerObjectProvider; +import org.apache.tapestry5.internal.jpa.core.EntityManagerSourceImpl; +import org.apache.tapestry5.internal.jpa.core.EntityTransactionManagerImpl; +import org.apache.tapestry5.internal.jpa.core.JpaTransactionAdvisorImpl; +import org.apache.tapestry5.internal.jpa.core.PackageNamePersistenceUnitConfigurer; +import org.apache.tapestry5.ioc.LoggerSource; +import org.apache.tapestry5.ioc.ScopeConstants; +import org.apache.tapestry5.ioc.ServiceBinder; +import org.apache.tapestry5.ioc.annotations.Contribute; +import org.apache.tapestry5.ioc.annotations.Primary; +import org.apache.tapestry5.ioc.annotations.Scope; +import org.apache.tapestry5.ioc.annotations.Startup; +import org.apache.tapestry5.ioc.annotations.Symbol; +import org.apache.tapestry5.ioc.services.FactoryDefaults; +import org.apache.tapestry5.ioc.services.MasterObjectProvider; +import org.apache.tapestry5.ioc.services.PerthreadManager; +import org.apache.tapestry5.ioc.services.SymbolProvider; +import org.apache.tapestry5.jpa.core.EntityManagerManager; +import org.apache.tapestry5.jpa.core.EntityManagerSource; +import org.apache.tapestry5.jpa.core.EntityTransactionManager; +import org.apache.tapestry5.jpa.core.JpaEntityPackageManager; +import org.apache.tapestry5.jpa.core.JpaCoreSymbols; +import org.apache.tapestry5.jpa.core.JpaTransactionAdvisor; +import org.apache.tapestry5.jpa.core.PersistenceUnitConfigurer; +import org.slf4j.Logger; + +/** + * Defines core services for JPA support. + * + * @since 5.3 + */ +public class JpaCoreModule +{ + public static void bind(final ServiceBinder binder) + { + binder.bind(JpaTransactionAdvisor.class, JpaTransactionAdvisorImpl.class); + binder.bind(PersistenceUnitConfigurer.class, PackageNamePersistenceUnitConfigurer.class).withSimpleId(); + binder.bind(EntityManagerSource.class, EntityManagerSourceImpl.class); + binder.bind(EntityTransactionManager.class, EntityTransactionManagerImpl.class); + } + + public static JpaEntityPackageManager buildJpaEntityPackageManager(final Collection packageNames) + { + return new JpaEntityPackageManager() + { + @Override + public Collection getPackageNames() + { + return packageNames; + } + }; + } + + @Scope(ScopeConstants.PERTHREAD) + public static EntityManagerManager buildEntityManagerManager(final EntityManagerSource entityManagerSource, + final PerthreadManager perthreadManager, final Logger logger) + { + final EntityManagerManagerImpl service = new EntityManagerManagerImpl(entityManagerSource, logger); + + perthreadManager.addThreadCleanupListener(service); + + return service; + } + + @Contribute(MasterObjectProvider.class) + public static void provideObjectProviders(final OrderedConfiguration configuration) + { + configuration.addInstance("EntityManager", EntityManagerObjectProvider.class, + "before:AnnotationBasedContributions"); + } + + @Contribute(SymbolProvider.class) + @FactoryDefaults + public static void provideFactoryDefaults(final MappedConfiguration configuration) + { + configuration.add(JpaCoreSymbols.EARLY_START_UP, "true"); + configuration.add(JpaCoreSymbols.PERSISTENCE_DESCRIPTOR, "/META-INF/persistence.xml"); + } + + @Startup + public static void startupEarly(final EntityManagerManager entityManagerManager, @Symbol(JpaCoreSymbols.EARLY_START_UP) + final boolean earlyStartup) + { + if (earlyStartup) + { + entityManagerManager.getEntityManagers(); + } + } +} diff --git a/tapestry-jpa-core/src/test/groovy/org/apache/tapestry5/internal/jpa/core/JpaTransactionAdvisorImplSpec.groovy b/tapestry-jpa-core/src/test/groovy/org/apache/tapestry5/internal/jpa/core/JpaTransactionAdvisorImplSpec.groovy new file mode 100644 index 0000000000..115f96f66e --- /dev/null +++ b/tapestry-jpa-core/src/test/groovy/org/apache/tapestry5/internal/jpa/core/JpaTransactionAdvisorImplSpec.groovy @@ -0,0 +1,319 @@ +// Copyright 2011, 2026 The Apache Software Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.apache.tapestry5.internal.jpa.core + +import java.sql.SQLException + +import jakarta.persistence.EntityManager +import jakarta.persistence.EntityTransaction +import jakarta.persistence.PersistenceContext + +import org.apache.tapestry5.ioc.annotations.ImportModule +import org.apache.tapestry5.ioc.annotations.Inject +import org.apache.tapestry5.ioc.services.AspectDecorator +import org.apache.tapestry5.ioc.services.AspectInterceptorBuilder +import org.apache.tapestry5.jpa.core.EntityManagerManager +import org.apache.tapestry5.jpa.core.EntityTransactionManager +import org.apache.tapestry5.jpa.core.annotations.CommitAfter +import org.apache.tapestry5.jpa.core.modules.JpaCoreModule +import org.apache.tapestry5.internal.jpa.core.EntityTransactionManagerImpl +import org.slf4j.Logger + +import spock.lang.Specification + +@ImportModule(JpaCoreModule.class) +class JpaTransactionAdvisorImplSpec extends Specification +{ + static final String UNIT_NAME = "FooUnit"; + + @Inject AspectDecorator aspectDecorator + + def "doesn't advise for methods not annotated with @CommitAfter"() + { + given: "a mock delegate whose undecorated() method has no @CommitAfter annotation" + VoidService delegate = Mock() + + and: "mock dependencies — empty map is sufficient, constructor only needs the map size" + EntityManagerManager manager = Mock { + getEntityManagers() >> [:] + } + EntityTransactionManager transactionManager = Mock() + + and: "an interceptor built with advice from the class under test" + VoidService interceptor = buildInterceptor(delegate, manager, transactionManager) + + when: "the unannotated method is called via the interceptor" + interceptor.undecorated() + + then: "the call passes straight through to the delegate with no transaction involvement" + 1 * delegate.undecorated() + 0 * manager.getEntityManagers() + 0 * transactionManager._ + } + + def "throws when EntityManager cannot be resolved unambiguously with multiple persistence units"() + { + given: "two EntityManagers configured — the advisor cannot pick one without a unitName" + EntityManagerManager manager = Stub { + getEntityManagers() >> [A: Mock(EntityManager), B: Mock(EntityManager)] + } + + and: "a real EntityTransactionManager so transaction logic actually executes" + EntityTransactionManager transactionManager = new EntityTransactionManagerImpl(Stub(Logger), manager) + + and: "an interceptor built with advice from the class under test" + VoidService interceptor = buildInterceptor(Mock(VoidService), manager, transactionManager) + + when: "a @CommitAfter-annotated method with an unresolvable EntityManager is called" + interceptor."$method"() + + then: "an exception is thrown because the advisor cannot identify which EntityManager to use" + Exception e = thrown() + e.message.contains("Unable to locate a single EntityManager") + + where: + method | _ + "persistenceUnitNameMissing" | _ // @PersistenceContext present but unitName not set + "persistenceUnitMissing" | _ // no @PersistenceContext at all + } + + def "succeeds when EntityManager can be resolved unambiguously with a single persistence unit"() + { + given: "a single EntityManager — the advisor can pick it without a unitName" + EntityManager em = Mock() + EntityTransaction transaction = Mock() + + and: "manager returns the single EntityManager for any lookup" + EntityManagerManager manager = Stub { + getEntityManagers() >> [A: em] + } + + and: "a real EntityTransactionManager so transaction logic actually executes" + EntityTransactionManager transactionManager = new EntityTransactionManagerImpl(Stub(Logger), manager) + + and: "a mock delegate and an interceptor built with advice from the class under test" + VoidService delegate = Mock() + VoidService interceptor = buildInterceptor(delegate, manager, transactionManager) + + when: "a @CommitAfter-annotated method with no explicit unitName is called" + interceptor."$method"() + + then: "the single EntityManager is resolved, the delegate is called, and the transaction is committed" + 1 * em.getTransaction() >> transaction + _ * transaction.isActive() >> true + 1 * delegate."$method"() + 1 * transaction.commit() + + where: + method | _ + "persistenceUnitNameMissing" | _ // @PersistenceContext present but unitName not set + "persistenceUnitMissing" | _ // no @PersistenceContext at all + } + + def "commits transaction after calling an annotated void method [#delegateMethod, #initiallyActive]"() + { + given: "a single EntityManager — UNIT_NAME must be a key in the map so the advisor wires up the correct MethodAdvice" + EntityManager em = Mock() + EntityTransaction transaction = Mock() + + and: "manager returns the EntityManager both during construction and during advice execution" + EntityManagerManager manager = Stub { + getEntityManagers() >> [(UNIT_NAME): em] + getEntityManager(UNIT_NAME) >> em + } + + and: "a real EntityTransactionManager so transaction logic actually executes" + EntityTransactionManager transactionManager = new EntityTransactionManagerImpl(Stub(Logger), manager) + + and: "a mock delegate and an interceptor built with advice from the class under test" + VoidService delegate = Mock() + VoidService interceptor = buildInterceptor(delegate, manager, transactionManager) + + when: "an annotated method is called" + invocation(interceptor) + + then: "begin() is called only when no transaction was active, the delegate is called, and the transaction is committed" + 1 * em.getTransaction() >> transaction + 1 * transaction.isActive() >> initiallyActive // if false, begin() will be called to start a new transaction + (initiallyActive ? 0 : 1) * transaction.begin() + 1 * delegate."$delegateMethod"(*_) + _ * transaction.isActive() >> true // subsequent isActive() checks after the delegate call + 1 * transaction.commit() + + where: + initiallyActive | delegateMethod | invocation + false | "voidMethod" | { it.voidMethod() } // no active transaction: begin() is called first + true | "voidMethod" | { it.voidMethod() } // active transaction: begin() is skipped + true | "voidMethodWithParam" | { it.voidMethodWithParam(777) } // same but with a method parameter + } + + def "rolls back transaction and rethrows when delegate throws a RuntimeException"() + { + given: "a RuntimeException the delegate will throw" + def re = new RuntimeException("Unexpected.") + + and: "a single EntityManager with an active transaction" + EntityManager em = Mock() + EntityTransaction transaction = Mock() + EntityManagerManager manager = Stub { + getEntityManagers() >> [(UNIT_NAME): em] + getEntityManager(UNIT_NAME) >> em + } + EntityTransactionManager transactionManager = new EntityTransactionManagerImpl(Stub(Logger), manager) + + and: "a mock Performer delegate and an interceptor built with advice from the class under test" + Performer delegate = Mock() + Performer interceptor = buildPerformerInterceptor(delegate, manager, transactionManager) + + when: "the annotated method is called and the delegate throws a RuntimeException" + interceptor.perform() + + then: "the transaction is rolled back and the original exception instance is rethrown" + 1 * em.getTransaction() >> transaction + _ * transaction.isActive() >> true + 1 * delegate.perform() >> { throw re } + 1 * transaction.rollback() + RuntimeException ex = thrown() + ex.is(re) + } + + def "commits transaction and rethrows when delegate throws a checked exception"() + { + given: "a checked exception the delegate will throw" + def se = new SQLException("Checked.") + + and: "a single EntityManager with an active transaction" + EntityManager em = Mock() + EntityTransaction transaction = Mock() + EntityManagerManager manager = Stub { + getEntityManagers() >> [(UNIT_NAME): em] + getEntityManager(UNIT_NAME) >> em + } + EntityTransactionManager transactionManager = new EntityTransactionManagerImpl(Stub(Logger), manager) + + and: "a mock Performer delegate and an interceptor built with advice from the class under test" + Performer delegate = Mock() + Performer interceptor = buildPerformerInterceptor(delegate, manager, transactionManager) + + when: "the annotated method is called and the delegate throws a checked exception" + interceptor.perform() + + then: "the transaction is committed (not rolled back) and the original exception instance is rethrown" + 1 * em.getTransaction() >> transaction + _ * transaction.isActive() >> true + 1 * delegate.perform() >> { throw se } + 1 * transaction.commit() + SQLException ex = thrown() + ex.is(se) + } + + def "commits transaction and returns value after calling an annotated method with a return type [#delegateMethod]"() + { + given: "a single EntityManager with an active transaction" + EntityManager em = Mock() + EntityTransaction transaction = Mock() + EntityManagerManager manager = Stub { + getEntityManagers() >> [(UNIT_NAME): em] + getEntityManager(UNIT_NAME) >> em + } + EntityTransactionManager transactionManager = new EntityTransactionManagerImpl(Stub(Logger), manager) + + and: "a real ReturnTypeService delegate (returnTypeMethod returns 'Foo', returnTypeMethodWithParam returns the sum)" + ReturnTypeService delegate = [returnTypeMethod: { "Foo" }, returnTypeMethodWithParam: { a, b -> a + b }] as ReturnTypeService + + and: "an interceptor built with advice from the class under test" + def advisor = newJpaTransactionAdvisor(manager, transactionManager) + AspectInterceptorBuilder builder = aspectDecorator.createBuilder(ReturnTypeService.class, delegate, "foo.Bar") + advisor.addTransactionCommitAdvice(builder) + ReturnTypeService interceptor = builder.build() + + when: "an annotated method with a return type is called" + def result = invocation(interceptor) + + then: "the transaction is committed and the return value from the delegate is preserved" + 1 * em.getTransaction() >> transaction + _ * transaction.isActive() >> true + 1 * transaction.commit() + result == expectedResult + + where: + delegateMethod | invocation || expectedResult + "returnTypeMethod" | ({ it.returnTypeMethod() }) || "Foo" // String return type + "returnTypeMethodWithParam" | ({ it.returnTypeMethodWithParam(5, 3) }) || 8 // int return type, result is 5 + 3 + } + + // ---- helpers ---- + + def newJpaTransactionAdvisor(manager, transactionManager) + { + return new JpaTransactionAdvisorImpl(manager, transactionManager) + } + + VoidService buildInterceptor(VoidService delegate, EntityManagerManager manager, EntityTransactionManager transactionManager) + { + def advisor = newJpaTransactionAdvisor(manager, transactionManager) + AspectInterceptorBuilder builder = aspectDecorator.createBuilder(VoidService.class, delegate, "foo.Bar") + advisor.addTransactionCommitAdvice(builder) + return builder.build() + } + + Performer buildPerformerInterceptor(Performer delegate, EntityManagerManager manager, EntityTransactionManager transactionManager) + { + def advisor = newJpaTransactionAdvisor(manager, transactionManager) + AspectInterceptorBuilder builder = aspectDecorator.createBuilder(Performer.class, delegate, "foo.Bar") + advisor.addTransactionCommitAdvice(builder) + return builder.build() + } + + + public interface VoidService + { + void undecorated() + + @CommitAfter + @PersistenceContext + void persistenceUnitNameMissing() + + @CommitAfter + void persistenceUnitMissing() + + @CommitAfter + @PersistenceContext(unitName = UNIT_NAME) + void voidMethod() + + @CommitAfter + @PersistenceContext(unitName = UNIT_NAME) + void voidMethodWithParam(long id) + } + + public interface Performer + { + @CommitAfter + @PersistenceContext(unitName = UNIT_NAME) + void perform() throws SQLException + } + + public interface ReturnTypeService + { + @CommitAfter + @PersistenceContext(unitName = UNIT_NAME) + String returnTypeMethod() + + @CommitAfter + @PersistenceContext(unitName = UNIT_NAME) + int returnTypeMethodWithParam(int first, int second) + } + +} \ No newline at end of file diff --git a/tapestry-jpa/src/test/java/org/apache/tapestry5/internal/jpa/EntityManagerSourceImplTest.java b/tapestry-jpa-core/src/test/java/org/apache/tapestry5/internal/jpa/core/EntityManagerSourceImplTest.java similarity index 88% rename from tapestry-jpa/src/test/java/org/apache/tapestry5/internal/jpa/EntityManagerSourceImplTest.java rename to tapestry-jpa-core/src/test/java/org/apache/tapestry5/internal/jpa/core/EntityManagerSourceImplTest.java index 61c0be72a1..6ed68a7839 100644 --- a/tapestry-jpa/src/test/java/org/apache/tapestry5/internal/jpa/EntityManagerSourceImplTest.java +++ b/tapestry-jpa-core/src/test/java/org/apache/tapestry5/internal/jpa/core/EntityManagerSourceImplTest.java @@ -1,4 +1,4 @@ -// Copyright 2011-2014 The Apache Software Foundation +// Copyright 2011-2014, 2026 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,23 +12,26 @@ // See the License for the specific language governing permissions and // limitations under the License. -package org.apache.tapestry5.internal.jpa; +package org.apache.tapestry5.internal.jpa.core; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.fail; + +import java.util.HashMap; +import java.util.Map; import org.apache.tapestry5.commons.util.CollectionFactory; import org.apache.tapestry5.ioc.internal.util.ClasspathResource; -import org.apache.tapestry5.jpa.PersistenceUnitConfigurer; -import org.apache.tapestry5.jpa.TapestryPersistenceUnitInfo; -import org.apache.tapestry5.test.TapestryTestCase; +import org.apache.tapestry5.jpa.core.PersistenceUnitConfigurer; +import org.apache.tapestry5.jpa.core.TapestryPersistenceUnitInfo; +import org.junit.jupiter.api.Test; import org.slf4j.LoggerFactory; -import org.testng.annotations.Test; import jakarta.persistence.EntityManager; import jakarta.persistence.spi.PersistenceUnitTransactionType; -import java.util.HashMap; -import java.util.Map; - -public class EntityManagerSourceImplTest extends TapestryTestCase +public class EntityManagerSourceImplTest { @Test public void multiple_persistence_units_include_unlisted_classes() @@ -95,5 +98,4 @@ public void configure(TapestryPersistenceUnitInfo unitInfo) persistenceUnitFile), null, configurerMap); return emSource; } - } diff --git a/tapestry-jpa/src/test/resources/multiple-persistence-units-include-unlisted-classes.xml b/tapestry-jpa-core/src/test/resources/multiple-persistence-units-include-unlisted-classes.xml similarity index 100% rename from tapestry-jpa/src/test/resources/multiple-persistence-units-include-unlisted-classes.xml rename to tapestry-jpa-core/src/test/resources/multiple-persistence-units-include-unlisted-classes.xml diff --git a/tapestry-jpa-core/src/test/resources/single-persistence-unit.xml b/tapestry-jpa-core/src/test/resources/single-persistence-unit.xml new file mode 100644 index 0000000000..467c1b53f5 --- /dev/null +++ b/tapestry-jpa-core/src/test/resources/single-persistence-unit.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tapestry-jpa/build.gradle b/tapestry-jpa/build.gradle index 0f7ff48e53..4e360f78fc 100644 --- a/tapestry-jpa/build.gradle +++ b/tapestry-jpa/build.gradle @@ -6,6 +6,7 @@ description = 'Provides support for simple CRUD applications built on top of Tap dependencies { implementation project(':tapestry-core') + implementation project(':tapestry-jpa-core') api libs.jakarta.persistence.api implementation libs.jakarta.cdi.api diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/CommitAfterWorker.java b/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/CommitAfterWorker.java index 0df0b963a5..85fd35eaea 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/CommitAfterWorker.java +++ b/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/CommitAfterWorker.java @@ -1,4 +1,4 @@ -// Copyright 2011, 2014 The Apache Software Foundation +// Copyright 2011, 2014, 2026 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -20,9 +20,10 @@ import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; -import org.apache.tapestry5.jpa.EntityManagerManager; -import org.apache.tapestry5.jpa.EntityTransactionManager; -import org.apache.tapestry5.jpa.annotations.CommitAfter; +import org.apache.tapestry5.internal.jpa.core.CommitAfterMethodAdvice; +import org.apache.tapestry5.jpa.core.EntityManagerManager; +import org.apache.tapestry5.jpa.core.EntityTransactionManager; +import org.apache.tapestry5.jpa.core.annotations.CommitAfter; import org.apache.tapestry5.model.MutableComponentModel; import org.apache.tapestry5.plastic.MethodAdvice; import org.apache.tapestry5.plastic.PlasticClass; diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/EntityApplicationStatePersistenceStrategy.java b/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/EntityApplicationStatePersistenceStrategy.java index 7566ea43d1..f61dbcb562 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/EntityApplicationStatePersistenceStrategy.java +++ b/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/EntityApplicationStatePersistenceStrategy.java @@ -1,4 +1,4 @@ -// Copyright 2011 The Apache Software Foundation +// Copyright 2011, 2026 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ import org.apache.tapestry5.http.services.Request; import org.apache.tapestry5.internal.services.SessionApplicationStatePersistenceStrategy; -import org.apache.tapestry5.jpa.EntityManagerManager; +import org.apache.tapestry5.jpa.core.EntityManagerManager; import org.apache.tapestry5.services.ApplicationStateCreator; public class EntityApplicationStatePersistenceStrategy extends diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/EntityPersistentFieldStrategy.java b/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/EntityPersistentFieldStrategy.java index a49230f568..1f00078a24 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/EntityPersistentFieldStrategy.java +++ b/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/EntityPersistentFieldStrategy.java @@ -1,4 +1,4 @@ -// Copyright 2011 The Apache Software Foundation +// Copyright 2011, 2026 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ import org.apache.tapestry5.http.services.Request; import org.apache.tapestry5.internal.services.AbstractSessionPersistentFieldStrategy; -import org.apache.tapestry5.jpa.EntityManagerManager; +import org.apache.tapestry5.jpa.core.EntityManagerManager; /** * Persists JPA entities by storing their id in the session. diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/JpaInternalUtils.java b/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/JpaInternalUtils.java index 4b8b0ffe7b..2629ffa12d 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/JpaInternalUtils.java +++ b/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/JpaInternalUtils.java @@ -1,4 +1,4 @@ -// Copyright 2011 The Apache Software Foundation +// Copyright 2011, 2026 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -23,11 +23,12 @@ import jakarta.persistence.metamodel.EntityType; import jakarta.persistence.metamodel.Metamodel; +import org.apache.tapestry5.internal.jpa.core.JpaCoreInternalUtils; import org.apache.tapestry5.ioc.internal.util.InternalUtils; -import org.apache.tapestry5.jpa.EntityManagerManager; +import org.apache.tapestry5.jpa.core.EntityManagerManager; import org.apache.tapestry5.jpa.JpaConstants; -public class JpaInternalUtils +public class JpaInternalUtils extends JpaCoreInternalUtils { public static PersistedEntity convertApplicationValueToPersisted( final EntityManagerManager entityManagerManager, final Object newValue) @@ -76,21 +77,4 @@ private static EntityManager getEntityManagerFactory( "Failed persisting the entity. The entity '%s' does not belong to any of the existing persistence contexts.", entity)); } - - public static EntityManager getEntityManager(EntityManagerManager entityManagerManager, - PersistenceContext annotation) - { - String unitName = annotation == null ? null : annotation.unitName(); - - if (InternalUtils.isNonBlank(unitName)) - return entityManagerManager.getEntityManager(unitName); - - Map entityManagers = entityManagerManager.getEntityManagers(); - - if (entityManagers.size() == 1) - return entityManagers.values().iterator().next(); - - throw new RuntimeException("Unable to locate a single EntityManager. " + - "You must provide the persistence unit name as defined in the persistence.xml using the @PersistenceContext annotation."); - } } diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/JpaValueEncoder.java b/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/JpaValueEncoder.java index 7bf678aa01..357c45fec9 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/JpaValueEncoder.java +++ b/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/JpaValueEncoder.java @@ -1,4 +1,4 @@ -// Copyright 2011-2013 The Apache Software Foundation +// Copyright 2011-2013, 2026 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ import org.apache.tapestry5.commons.services.TypeCoercer; import org.apache.tapestry5.commons.util.ExceptionUtils; import org.apache.tapestry5.ioc.internal.util.InternalUtils; -import org.apache.tapestry5.jpa.EntityManagerManager; +import org.apache.tapestry5.jpa.core.EntityManagerManager; import org.slf4j.Logger; import jakarta.persistence.EntityManager; diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/PersistedEntity.java b/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/PersistedEntity.java index 0e6817ab73..10deedc967 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/PersistedEntity.java +++ b/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/PersistedEntity.java @@ -1,4 +1,4 @@ -// Copyright 2011 The Apache Software Foundation +// Copyright 2011, 2026 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -19,7 +19,7 @@ import jakarta.persistence.EntityManager; import org.apache.tapestry5.http.annotations.ImmutableSessionPersistedObject; -import org.apache.tapestry5.jpa.EntityManagerManager; +import org.apache.tapestry5.jpa.core.EntityManagerManager; /** * Encapsulates a JPA entity name with an entity id. diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/PersistenceContextWorker.java b/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/PersistenceContextWorker.java index fbb05bca26..3e111a25f5 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/PersistenceContextWorker.java +++ b/tapestry-jpa/src/main/java/org/apache/tapestry5/internal/jpa/PersistenceContextWorker.java @@ -1,4 +1,4 @@ -// Copyright 2011 The Apache Software Foundation +// Copyright 2011, 2026 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,7 +15,7 @@ package org.apache.tapestry5.internal.jpa; import org.apache.tapestry5.internal.transform.ReadOnlyComponentFieldConduit; -import org.apache.tapestry5.jpa.EntityManagerManager; +import org.apache.tapestry5.jpa.core.EntityManagerManager; import org.apache.tapestry5.model.MutableComponentModel; import org.apache.tapestry5.plastic.InstanceContext; import org.apache.tapestry5.plastic.PlasticClass; diff --git a/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/modules/JpaModule.java b/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/modules/JpaModule.java index cdc0b225af..2e371ecc95 100644 --- a/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/modules/JpaModule.java +++ b/tapestry-jpa/src/main/java/org/apache/tapestry5/jpa/modules/JpaModule.java @@ -1,4 +1,4 @@ -// Copyright 2011-2014 The Apache Software Foundation +// Copyright 2011-2014, 2026 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -31,20 +31,16 @@ import org.apache.tapestry5.http.internal.TapestryHttpInternalConstants; import org.apache.tapestry5.internal.jpa.CommitAfterWorker; import org.apache.tapestry5.internal.jpa.EntityApplicationStatePersistenceStrategy; -import org.apache.tapestry5.internal.jpa.EntityManagerManagerImpl; -import org.apache.tapestry5.internal.jpa.EntityManagerObjectProvider; -import org.apache.tapestry5.internal.jpa.EntityManagerSourceImpl; import org.apache.tapestry5.internal.jpa.EntityPersistentFieldStrategy; -import org.apache.tapestry5.internal.jpa.EntityTransactionManagerImpl; -import org.apache.tapestry5.internal.jpa.JpaTransactionAdvisorImpl; import org.apache.tapestry5.internal.jpa.JpaValueEncoder; -import org.apache.tapestry5.internal.jpa.PackageNamePersistenceUnitConfigurer; import org.apache.tapestry5.internal.jpa.PersistenceContextWorker; import org.apache.tapestry5.internal.services.PersistentFieldManager; import org.apache.tapestry5.ioc.LoggerSource; import org.apache.tapestry5.ioc.ScopeConstants; import org.apache.tapestry5.ioc.ServiceBinder; import org.apache.tapestry5.ioc.annotations.Contribute; +import org.apache.tapestry5.ioc.annotations.ImportModule; +import org.apache.tapestry5.ioc.annotations.Local; import org.apache.tapestry5.ioc.annotations.Primary; import org.apache.tapestry5.ioc.annotations.Scope; import org.apache.tapestry5.ioc.annotations.Startup; @@ -52,15 +48,17 @@ import org.apache.tapestry5.ioc.services.FactoryDefaults; import org.apache.tapestry5.ioc.services.MasterObjectProvider; import org.apache.tapestry5.ioc.services.PerthreadManager; +import org.apache.tapestry5.ioc.services.ServiceOverride; import org.apache.tapestry5.ioc.services.SymbolProvider; -import org.apache.tapestry5.jpa.EntityManagerManager; -import org.apache.tapestry5.jpa.EntityManagerSource; -import org.apache.tapestry5.jpa.EntityTransactionManager; -import org.apache.tapestry5.jpa.JpaEntityPackageManager; +import org.apache.tapestry5.jpa.core.EntityManagerManager; +import org.apache.tapestry5.jpa.core.EntityManagerSource; +import org.apache.tapestry5.jpa.core.EntityTransactionManager; +import org.apache.tapestry5.jpa.core.JpaEntityPackageManager; import org.apache.tapestry5.jpa.JpaPersistenceConstants; import org.apache.tapestry5.jpa.JpaSymbols; -import org.apache.tapestry5.jpa.JpaTransactionAdvisor; -import org.apache.tapestry5.jpa.PersistenceUnitConfigurer; +import org.apache.tapestry5.jpa.core.JpaTransactionAdvisor; +import org.apache.tapestry5.jpa.core.PersistenceUnitConfigurer; +import org.apache.tapestry5.jpa.core.modules.JpaCoreModule; import org.apache.tapestry5.services.ApplicationStateContribution; import org.apache.tapestry5.services.ApplicationStateManager; import org.apache.tapestry5.services.ApplicationStatePersistenceStrategy; @@ -76,40 +74,9 @@ * * @since 5.3 */ +@ImportModule(JpaCoreModule.class) public class JpaModule { - public static void bind(final ServiceBinder binder) - { - binder.bind(JpaTransactionAdvisor.class, JpaTransactionAdvisorImpl.class); - binder.bind(PersistenceUnitConfigurer.class, PackageNamePersistenceUnitConfigurer.class).withSimpleId(); - binder.bind(EntityManagerSource.class, EntityManagerSourceImpl.class); - binder.bind(EntityTransactionManager.class, EntityTransactionManagerImpl.class); - - } - - public static JpaEntityPackageManager buildJpaEntityPackageManager(final Collection packageNames) - { - return new JpaEntityPackageManager() - { - @Override - public Collection getPackageNames() - { - return packageNames; - } - }; - } - - @Scope(ScopeConstants.PERTHREAD) - public static EntityManagerManager buildEntityManagerManager(final EntityManagerSource entityManagerSource, - final PerthreadManager perthreadManager, final Logger logger) - { - final EntityManagerManagerImpl service = new EntityManagerManagerImpl(entityManagerSource, logger); - - perthreadManager.addThreadCleanupListener(service); - - return service; - } - @Contribute(JpaEntityPackageManager.class) public static void provideEntityPackages(Configuration configuration, @@ -141,21 +108,14 @@ public static void provideClassTransformWorkers(OrderedConfiguration configuration) - { - configuration.addInstance("EntityManager", EntityManagerObjectProvider.class, - "before:AnnotationBasedContributions"); - } - @Contribute(SymbolProvider.class) @FactoryDefaults public static void provideFactoryDefaults(final MappedConfiguration configuration) { configuration.add(JpaSymbols.PROVIDE_ENTITY_VALUE_ENCODERS, "true"); - configuration.add(JpaSymbols.EARLY_START_UP, "true"); + configuration.override(JpaSymbols.EARLY_START_UP, "true"); configuration.add(JpaSymbols.ENTITY_SESSION_STATE_PERSISTENCE_STRATEGY_ENABLED, "true"); - configuration.add(JpaSymbols.PERSISTENCE_DESCRIPTOR, "/META-INF/persistence.xml"); + configuration.override(JpaSymbols.PERSISTENCE_DESCRIPTOR, "/META-INF/persistence.xml"); } @Contribute(ValueEncoderSource.class) diff --git a/tapestry-jpa/src/test/java/org/apache/tapestry5/internal/jpa/JpaTransactionAdvisorImplTest.java b/tapestry-jpa/src/test/java/org/apache/tapestry5/internal/jpa/JpaTransactionAdvisorImplTest.java deleted file mode 100644 index 558ea8dbc6..0000000000 --- a/tapestry-jpa/src/test/java/org/apache/tapestry5/internal/jpa/JpaTransactionAdvisorImplTest.java +++ /dev/null @@ -1,552 +0,0 @@ -// Copyright 2011 The Apache Software Foundation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package org.apache.tapestry5.internal.jpa; - -import java.sql.SQLException; -import java.util.Map; - -import jakarta.persistence.EntityManager; -import jakarta.persistence.EntityTransaction; -import jakarta.persistence.PersistenceContext; - -import org.apache.tapestry5.commons.util.CollectionFactory; -import org.apache.tapestry5.ioc.IOCUtilities; -import org.apache.tapestry5.ioc.Registry; -import org.apache.tapestry5.ioc.services.AspectDecorator; -import org.apache.tapestry5.ioc.services.AspectInterceptorBuilder; -import org.apache.tapestry5.ioc.test.IOCTestCase; -import org.apache.tapestry5.jpa.EntityManagerManager; -import org.apache.tapestry5.jpa.EntityTransactionManager; -import org.apache.tapestry5.jpa.JpaTransactionAdvisor; -import org.apache.tapestry5.jpa.annotations.CommitAfter; -import org.apache.tapestry5.test.ioc.TestBase; -import org.testng.Assert; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Test; - -public class JpaTransactionAdvisorImplTest extends IOCTestCase -{ - private static final String UNIT_NAME = "FooUnit"; - - private Registry registry; - - private AspectDecorator aspectDecorator; - - @BeforeClass - public void setup() - { - registry = IOCUtilities.buildDefaultRegistry(); - - aspectDecorator = registry.getService(AspectDecorator.class); - } - - @AfterClass - public void shutdown() - { - registry.shutdown(); - - aspectDecorator = null; - registry = null; - } - - @Test - public void undecorated() - { - final VoidService delegate = newMock(VoidService.class); - final EntityManagerManager manager = newMock(EntityManagerManager.class); - final EntityTransactionManager transactionManager = newMock(EntityTransactionManager.class); - final JpaTransactionAdvisor advisor = newJpaTransactionAdvisor(manager, transactionManager); - - final AspectInterceptorBuilder builder = aspectDecorator.createBuilder( - VoidService.class, delegate, "foo.Bar"); - - advisor.addTransactionCommitAdvice(builder); - - final VoidService interceptor = builder.build(); - - delegate.undecorated(); - - replay(); - interceptor.undecorated(); - verify(); - } - - @Test - public void persistence_unit_name_missing() - { - final VoidService delegate = newMock(VoidService.class); - final EntityManagerManager manager = newMock(EntityManagerManager.class); - final EntityTransactionManager transactionManager = newMock(EntityTransactionManager.class); - final JpaTransactionAdvisor advisor = newJpaTransactionAdvisor(manager, transactionManager); - Map managers = CollectionFactory.newMap(); - managers.put("A", newMock(EntityManager.class)); - managers.put("B", newMock(EntityManager.class)); - - final AspectInterceptorBuilder builder = aspectDecorator.createBuilder( - VoidService.class, delegate, "foo.Bar"); - - advisor.addTransactionCommitAdvice(builder); - - final VoidService interceptor = builder.build(); - - expect(manager.getEntityManagers()).andReturn(managers); - - replay(); - - try - { - interceptor.persistenceUnitNameMissing(); - TestBase.unreachable(); - } catch (Exception e) - { - Assert.assertEquals(e.getMessage(), "Unable to locate a single EntityManager. " + - "You must provide the persistence unit name as defined in the persistence.xml using the @PersistenceContext annotation."); - } - verify(); - } - - @Test - public void persistence_unit_name_missing_single_unit_configured() - { - final VoidService delegate = newMock(VoidService.class); - final EntityManagerManager manager = newMock(EntityManagerManager.class); - final EntityTransactionManager transactionManager = newMock(EntityTransactionManager.class); - final JpaTransactionAdvisor advisor = newJpaTransactionAdvisor(manager, transactionManager); - final EntityTransaction transaction = newMock(EntityTransaction.class); - EntityManager em = newMock(EntityManager.class); - Map managers = CollectionFactory.newMap(); - managers.put("A", em); - - final AspectInterceptorBuilder builder = aspectDecorator.createBuilder( - VoidService.class, delegate, "foo.Bar"); - - advisor.addTransactionCommitAdvice(builder); - - final VoidService interceptor = builder.build(); - - expect(manager.getEntityManagers()).andReturn(managers); - train_getTransaction(em, transaction, true); - delegate.persistenceUnitNameMissing(); - train_commitActiveTransaction(transaction); - - replay(); - interceptor.persistenceUnitNameMissing(); - verify(); - } - - @Test - public void persistence_unit_missing() - { - final VoidService delegate = newMock(VoidService.class); - final EntityManagerManager manager = newMock(EntityManagerManager.class); - final EntityTransactionManager transactionManager = newMock(EntityTransactionManager.class); - final JpaTransactionAdvisor advisor = newJpaTransactionAdvisor(manager, transactionManager); - Map managers = CollectionFactory.newMap(); - managers.put("A", newMock(EntityManager.class)); - managers.put("B", newMock(EntityManager.class)); - - final AspectInterceptorBuilder builder = aspectDecorator.createBuilder( - VoidService.class, delegate, "foo.Bar"); - - advisor.addTransactionCommitAdvice(builder); - - final VoidService interceptor = builder.build(); - - expect(manager.getEntityManagers()).andReturn(managers); - - replay(); - - try - { - interceptor.persistenceUnitMissing(); - TestBase.unreachable(); - } catch (Exception e) - { - assertMessageContains(e, "Unable to locate a single EntityManager"); - } - - verify(); - } - - @Test - public void persistence_unit_missing_single_unit_configured() - { - final VoidService delegate = newMock(VoidService.class); - final EntityManagerManager manager = newMock(EntityManagerManager.class); - final EntityTransactionManager transactionManager = newMock(EntityTransactionManager.class); - final JpaTransactionAdvisor advisor = newJpaTransactionAdvisor(manager, transactionManager); - final EntityTransaction transaction = newMock(EntityTransaction.class); - EntityManager em = newMock(EntityManager.class); - Map managers = CollectionFactory.newMap(); - managers.put("A", em); - - final AspectInterceptorBuilder builder = aspectDecorator.createBuilder( - VoidService.class, delegate, "foo.Bar"); - - advisor.addTransactionCommitAdvice(builder); - - final VoidService interceptor = builder.build(); - - expect(manager.getEntityManagers()).andReturn(managers); - train_getTransaction(em, transaction, true); - delegate.persistenceUnitMissing(); - train_commitActiveTransaction(transaction); - - replay(); - interceptor.persistenceUnitMissing(); - verify(); - } - - @Test - public void transaction_inactive() - { - final VoidService delegate = newMock(VoidService.class); - final EntityManagerManager manager = newMock(EntityManagerManager.class); - final EntityTransactionManager transactionManager = newMock(EntityTransactionManager.class); - final JpaTransactionAdvisor advisor = newJpaTransactionAdvisor(manager, transactionManager); - final EntityManager entityManager = newMock(EntityManager.class); - final EntityTransaction transaction = newMock(EntityTransaction.class); - - final AspectInterceptorBuilder builder = aspectDecorator.createBuilder( - VoidService.class, delegate, "foo.Bar"); - - advisor.addTransactionCommitAdvice(builder); - - final VoidService interceptor = builder.build(); - - train_getAndBeginTransaction(manager, entityManager, transaction); - - delegate.voidMethod(); - - train_commitActiveTransaction(transaction); - - replay(); - interceptor.voidMethod(); - verify(); - } - - @Test - public void void_method() - { - final VoidService delegate = newMock(VoidService.class); - final EntityManagerManager manager = newMock(EntityManagerManager.class); - final EntityTransactionManager transactionManager = newMock(EntityTransactionManager.class); - final JpaTransactionAdvisor advisor = newJpaTransactionAdvisor(manager, transactionManager); - final EntityManager entityManager = newMock(EntityManager.class); - final EntityTransaction transaction = newMock(EntityTransaction.class); - - final AspectInterceptorBuilder builder = aspectDecorator.createBuilder( - VoidService.class, delegate, "foo.Bar"); - - advisor.addTransactionCommitAdvice(builder); - - final VoidService interceptor = builder.build(); - - train_getActiveTransaction(manager, entityManager, transaction); - - delegate.voidMethod(); - - train_commitActiveTransaction(transaction); - - replay(); - interceptor.voidMethod(); - verify(); - } - - @Test - public void void_method_with_param() - { - final VoidService delegate = newMock(VoidService.class); - final EntityManagerManager manager = newMock(EntityManagerManager.class); - final EntityTransactionManager transactionManager = newMock(EntityTransactionManager.class); - final JpaTransactionAdvisor advisor = newJpaTransactionAdvisor(manager, transactionManager); - final EntityManager entityManager = newMock(EntityManager.class); - final EntityTransaction transaction = newMock(EntityTransaction.class); - - final AspectInterceptorBuilder builder = aspectDecorator.createBuilder( - VoidService.class, delegate, "foo.Bar"); - - advisor.addTransactionCommitAdvice(builder); - - final VoidService interceptor = builder.build(); - - train_getActiveTransaction(manager, entityManager, transaction); - delegate.voidMethodWithParam(777); - train_commitActiveTransaction(transaction); - - replay(); - interceptor.voidMethodWithParam(777); - verify(); - } - - @Test - public void runtime_exception_will_abort_transaction() throws Exception - { - final Performer delegate = newMock(Performer.class); - final EntityManagerManager manager = newMock(EntityManagerManager.class); - final EntityTransactionManager transactionManager = newMock(EntityTransactionManager.class); - final JpaTransactionAdvisor advisor = newJpaTransactionAdvisor(manager, transactionManager); - final EntityManager entityManager = newMock(EntityManager.class); - final EntityTransaction transaction = newMock(EntityTransaction.class); - final RuntimeException re = new RuntimeException("Unexpected."); - - final AspectInterceptorBuilder builder = aspectDecorator.createBuilder( - Performer.class, delegate, "foo.Bar"); - - advisor.addTransactionCommitAdvice(builder); - - final Performer interceptor = builder.build(); - - train_getActiveTransaction(manager, entityManager, transaction); - delegate.perform(); - TestBase.setThrowable(re); - train_rollBackActiveTransaction(transaction); - - replay(); - try - { - interceptor.perform(); - TestBase.unreachable(); - } catch (final RuntimeException ex) - { - Assert.assertSame(ex, re); - } - - verify(); - } - - @Test - public void checked_exception_will_commit_transaction() throws Exception - { - final Performer delegate = newMock(Performer.class); - final EntityManagerManager manager = newMock(EntityManagerManager.class); - final EntityTransactionManager transactionManager = newMock(EntityTransactionManager.class); - final JpaTransactionAdvisor advisor = newJpaTransactionAdvisor(manager, transactionManager); - final EntityManager entityManager = newMock(EntityManager.class); - final EntityTransaction transaction = newMock(EntityTransaction.class); - final SQLException se = new SQLException("Checked."); - - final AspectInterceptorBuilder builder = aspectDecorator.createBuilder( - Performer.class, delegate, "foo.Bar"); - - advisor.addTransactionCommitAdvice(builder); - - final Performer interceptor = builder.build(); - - train_getActiveTransaction(manager, entityManager, transaction); - - delegate.perform(); - setThrowable(se); - - train_commitActiveTransaction(transaction); - - replay(); - - - try - { - interceptor.perform(); - - unreachable(); - } catch (final SQLException ex) - { - Assert.assertSame(ex, se); - } - - verify(); - } - - @Test - public void return_type_method() - { - final ReturnTypeService delegate = newTestService(); - final EntityManagerManager manager = newMock(EntityManagerManager.class); - final EntityTransactionManager transactionManager = newMock(EntityTransactionManager.class); - final JpaTransactionAdvisor advisor = newJpaTransactionAdvisor(manager, transactionManager); - final EntityManager entityManager = newMock(EntityManager.class); - final EntityTransaction transaction = newMock(EntityTransaction.class); - - final AspectInterceptorBuilder builder = aspectDecorator.createBuilder( - ReturnTypeService.class, delegate, "foo.Bar"); - - advisor.addTransactionCommitAdvice(builder); - - final ReturnTypeService interceptor = builder.build(); - - train_getActiveTransaction(manager, entityManager, transaction); - delegate.returnTypeMethod(); - train_commitActiveTransaction(transaction); - - replay(); - Assert.assertEquals(interceptor.returnTypeMethod(), "Foo"); - verify(); - } - - @Test - public void return_type_method_with_param() - { - final ReturnTypeService delegate = newTestService(); - final EntityManagerManager manager = newMock(EntityManagerManager.class); - final EntityTransactionManager transactionManager = newMock(EntityTransactionManager.class); - final JpaTransactionAdvisor advisor = newJpaTransactionAdvisor(manager, transactionManager); - final EntityManager entityManager = newMock(EntityManager.class); - final EntityTransaction transaction = newMock(EntityTransaction.class); - - final AspectInterceptorBuilder builder = aspectDecorator.createBuilder( - ReturnTypeService.class, delegate, "foo.Bar"); - - advisor.addTransactionCommitAdvice(builder); - - final ReturnTypeService interceptor = builder.build(); - - train_getActiveTransaction(manager, entityManager, transaction); - delegate.returnTypeMethodWithParam(5, 3); - train_commitActiveTransaction(transaction); - - replay(); - Assert.assertEquals(interceptor.returnTypeMethodWithParam(5, 3), 8); - verify(); - } - - private void train_getAndBeginTransaction(final EntityManagerManager manager, - final EntityManager entityManager, final EntityTransaction transaction) - { - train_getTransaction(manager, entityManager, transaction, false); - transaction.begin(); - } - - private void train_getActiveTransaction(final EntityManagerManager manager, - final EntityManager entityManager, final EntityTransaction transaction) - { - train_getTransaction(manager, entityManager, transaction, true); - } - - private void train_getTransaction(final EntityManagerManager manager, - final EntityManager entityManager, final EntityTransaction transaction, - final boolean isActive) - { - expect(manager.getEntityManager(UNIT_NAME)).andReturn(entityManager); - train_getTransaction(entityManager, transaction, isActive); - } - - private void train_getTransaction( - final EntityManager entityManager, final EntityTransaction transaction, - final boolean isActive) - { - expect(entityManager.getTransaction()).andReturn(transaction); - expect(transaction.isActive()).andReturn(isActive); - } - - private void train_commitActiveTransaction(final EntityTransaction transaction) - { - expect(transaction.isActive()).andReturn(true); - transaction.commit(); - } - - private void train_rollBackActiveTransaction(final EntityTransaction transaction) - { - expect(transaction.isActive()).andReturn(true); - transaction.rollback(); - } - - private JpaTransactionAdvisor newJpaTransactionAdvisor(final EntityManagerManager manager, - EntityTransactionManager transactionManager) - { - return new JpaTransactionAdvisorImpl(manager, transactionManager); - } - - private ReturnTypeService newTestService() - { - return new ReturnTypeService() - { - - @Override - public String returnTypeMethod() - { - return "Foo"; - } - - @Override - public int returnTypeMethodWithParam(final int first, final int second) - { - return first + second; - } - - @Override - public String toString() - { - return "Baz"; - } - }; - } - - public interface ReturnTypeService - { - @CommitAfter - @PersistenceContext(unitName = UNIT_NAME) - String returnTypeMethod(); - - @CommitAfter - @PersistenceContext(unitName = UNIT_NAME) - int returnTypeMethodWithParam(int first, int second); - - @Override - String toString(); - } - - public interface VoidService - { - void undecorated(); - - @CommitAfter - @PersistenceContext - void persistenceUnitNameMissing(); - - @CommitAfter - void persistenceUnitMissing(); - - @CommitAfter - @PersistenceContext(unitName = UNIT_NAME) - void voidMethod(); - - @CommitAfter - @PersistenceContext(unitName = UNIT_NAME) - void voidMethodWithParam(long id); - } - - public interface Performer - { - @CommitAfter - @PersistenceContext(unitName = UNIT_NAME) - void perform() throws SQLException; - } - - public interface Service - { - void perform(); - } - - public class ServiceImpl implements Service { - @Override - @CommitAfter - @PersistenceContext(unitName = UNIT_NAME) - public void perform() - { - - } - } - -} diff --git a/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/test/CommitCounter.java b/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/test/CommitCounter.java index 8d8de28484..cce16de929 100644 --- a/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/test/CommitCounter.java +++ b/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/test/CommitCounter.java @@ -21,7 +21,7 @@ import jakarta.persistence.PostPersist; import jakarta.persistence.PostUpdate; -import org.apache.tapestry5.jpa.EntityTransactionManager; +import org.apache.tapestry5.jpa.core.EntityTransactionManager; import org.apache.tapestry5.jpa.test.entities.VersionedThing; public class CommitCounter diff --git a/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/test/JpaTest.java b/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/test/JpaTest.java index 6c7493f0dd..b87a070eaa 100644 --- a/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/test/JpaTest.java +++ b/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/test/JpaTest.java @@ -36,7 +36,7 @@ import org.apache.tapestry5.internal.test.PageTesterContext; import org.apache.tapestry5.ioc.Registry; import org.apache.tapestry5.ioc.RegistryBuilder; -import org.apache.tapestry5.jpa.EntityManagerManager; +import org.apache.tapestry5.jpa.core.EntityManagerManager; import org.apache.tapestry5.jpa.modules.JpaModule; import org.apache.tapestry5.jpa.test.entities.ThingOne; import org.apache.tapestry5.jpa.test.entities.ThingTwo; diff --git a/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/test/JpaTestModule.java b/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/test/JpaTestModule.java index 4beca5f6cb..8aa355acb6 100644 --- a/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/test/JpaTestModule.java +++ b/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/test/JpaTestModule.java @@ -17,18 +17,18 @@ import org.apache.tapestry5.commons.MappedConfiguration; import org.apache.tapestry5.commons.ObjectLocator; import org.apache.tapestry5.http.internal.TapestryHttpInternalConstants; -import org.apache.tapestry5.internal.jpa.TapestryCDIBeanManagerForJPAEntityListeners; +import org.apache.tapestry5.internal.jpa.core.TapestryCDIBeanManagerForJPAEntityListeners; import org.apache.tapestry5.ioc.MethodAdviceReceiver; import org.apache.tapestry5.ioc.ServiceBinder; import org.apache.tapestry5.ioc.annotations.Contribute; import org.apache.tapestry5.ioc.annotations.Match; import org.apache.tapestry5.ioc.services.ApplicationDefaults; import org.apache.tapestry5.ioc.services.SymbolProvider; -import org.apache.tapestry5.jpa.EntityManagerSource; -import org.apache.tapestry5.jpa.JpaEntityPackageManager; -import org.apache.tapestry5.jpa.JpaTransactionAdvisor; -import org.apache.tapestry5.jpa.PersistenceUnitConfigurer; -import org.apache.tapestry5.jpa.TapestryPersistenceUnitInfo; +import org.apache.tapestry5.jpa.core.EntityManagerSource; +import org.apache.tapestry5.jpa.core.JpaEntityPackageManager; +import org.apache.tapestry5.jpa.core.JpaTransactionAdvisor; +import org.apache.tapestry5.jpa.core.PersistenceUnitConfigurer; +import org.apache.tapestry5.jpa.core.TapestryPersistenceUnitInfo; import org.apache.tapestry5.jpa.test.entities.ThingOne; import org.apache.tapestry5.jpa.test.entities.ThingTwo; import org.apache.tapestry5.jpa.test.entities.VersionedThing; diff --git a/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/test/NestedService.java b/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/test/NestedService.java index d427a86eb5..284b0bd86c 100644 --- a/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/test/NestedService.java +++ b/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/test/NestedService.java @@ -13,7 +13,7 @@ */ package org.apache.tapestry5.jpa.test; -import org.apache.tapestry5.jpa.annotations.CommitAfter; +import org.apache.tapestry5.jpa.core.annotations.CommitAfter; public interface NestedService { diff --git a/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/test/TopLevelService.java b/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/test/TopLevelService.java index 849b84daef..1291ae7c3a 100644 --- a/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/test/TopLevelService.java +++ b/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/test/TopLevelService.java @@ -13,7 +13,7 @@ */ package org.apache.tapestry5.jpa.test; -import org.apache.tapestry5.jpa.annotations.CommitAfter; +import org.apache.tapestry5.jpa.core.annotations.CommitAfter; public interface TopLevelService { diff --git a/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/test/TopLevelServiceImpl.java b/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/test/TopLevelServiceImpl.java index 04fa8d7886..7d14d52e93 100644 --- a/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/test/TopLevelServiceImpl.java +++ b/tapestry-jpa/src/test/java/org/apache/tapestry5/jpa/test/TopLevelServiceImpl.java @@ -16,8 +16,8 @@ import jakarta.persistence.EntityManager; import org.apache.tapestry5.ioc.Invokable; -import org.apache.tapestry5.jpa.EntityTransactionManager; -import org.apache.tapestry5.jpa.annotations.CommitAfter; +import org.apache.tapestry5.jpa.core.EntityTransactionManager; +import org.apache.tapestry5.jpa.core.annotations.CommitAfter; import org.apache.tapestry5.jpa.test.entities.ThingOne; public class TopLevelServiceImpl implements TopLevelService diff --git a/tapestry-jpa/src/test/java/org/example/app1/pages/CommitAfterDemo.java b/tapestry-jpa/src/test/java/org/example/app1/pages/CommitAfterDemo.java index 9b333c564d..3f08f82a3c 100644 --- a/tapestry-jpa/src/test/java/org/example/app1/pages/CommitAfterDemo.java +++ b/tapestry-jpa/src/test/java/org/example/app1/pages/CommitAfterDemo.java @@ -18,7 +18,7 @@ import jakarta.persistence.PersistenceContext; -import org.apache.tapestry5.jpa.annotations.CommitAfter; +import org.apache.tapestry5.jpa.core.annotations.CommitAfter; import org.example.app1.AppConstants; import org.example.app1.entities.User; diff --git a/tapestry-jpa/src/test/java/org/example/app1/pages/EncodeEntities.java b/tapestry-jpa/src/test/java/org/example/app1/pages/EncodeEntities.java index 49d190a6cc..06c0d7f793 100644 --- a/tapestry-jpa/src/test/java/org/example/app1/pages/EncodeEntities.java +++ b/tapestry-jpa/src/test/java/org/example/app1/pages/EncodeEntities.java @@ -1,4 +1,4 @@ -// Copyright 2011 The Apache Software Foundation +// Copyright 2011, 2026 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ import org.apache.tapestry5.annotations.Property; import org.apache.tapestry5.ioc.annotations.Inject; -import org.apache.tapestry5.jpa.annotations.CommitAfter; +import org.apache.tapestry5.jpa.core.annotations.CommitAfter; import org.example.app1.AppConstants; import org.example.app1.entities.User; import org.example.app1.services.UserDAO; diff --git a/tapestry-jpa/src/test/java/org/example/app1/pages/GridDemo.java b/tapestry-jpa/src/test/java/org/example/app1/pages/GridDemo.java index d0746be24b..1bf77ea96d 100644 --- a/tapestry-jpa/src/test/java/org/example/app1/pages/GridDemo.java +++ b/tapestry-jpa/src/test/java/org/example/app1/pages/GridDemo.java @@ -23,7 +23,7 @@ import org.apache.tapestry5.grid.GridDataSource; import org.apache.tapestry5.ioc.annotations.Inject; import org.apache.tapestry5.jpa.JpaGridDataSource; -import org.apache.tapestry5.jpa.annotations.CommitAfter; +import org.apache.tapestry5.jpa.core.annotations.CommitAfter; import org.example.app1.AppConstants; import org.example.app1.entities.User; import org.example.app1.services.UserDAO; diff --git a/tapestry-jpa/src/test/java/org/example/app1/pages/PersistEntity.java b/tapestry-jpa/src/test/java/org/example/app1/pages/PersistEntity.java index 6f34f29a1b..1188e4ac42 100644 --- a/tapestry-jpa/src/test/java/org/example/app1/pages/PersistEntity.java +++ b/tapestry-jpa/src/test/java/org/example/app1/pages/PersistEntity.java @@ -22,7 +22,7 @@ import org.apache.tapestry5.annotations.Persist; import org.apache.tapestry5.annotations.Property; import org.apache.tapestry5.jpa.JpaPersistenceConstants; -import org.apache.tapestry5.jpa.annotations.CommitAfter; +import org.apache.tapestry5.jpa.core.annotations.CommitAfter; import org.example.app1.AppConstants; import org.example.app1.entities.User; diff --git a/tapestry-jpa/src/test/java/org/example/app1/pages/PersistThang.java b/tapestry-jpa/src/test/java/org/example/app1/pages/PersistThang.java index 9c4d209620..1e4cabf0bd 100644 --- a/tapestry-jpa/src/test/java/org/example/app1/pages/PersistThang.java +++ b/tapestry-jpa/src/test/java/org/example/app1/pages/PersistThang.java @@ -17,7 +17,7 @@ import org.apache.tapestry5.annotations.Persist; import org.apache.tapestry5.annotations.Property; import org.apache.tapestry5.jpa.JpaPersistenceConstants; -import org.apache.tapestry5.jpa.annotations.CommitAfter; +import org.apache.tapestry5.jpa.core.annotations.CommitAfter; import org.example.app1.AppConstants; import org.example.app1.entities.Thang; import org.example.app1.entities.User; diff --git a/tapestry-jpa/src/test/java/org/example/app1/services/AppModule.java b/tapestry-jpa/src/test/java/org/example/app1/services/AppModule.java index 14d7c11b6e..552fb6006d 100644 --- a/tapestry-jpa/src/test/java/org/example/app1/services/AppModule.java +++ b/tapestry-jpa/src/test/java/org/example/app1/services/AppModule.java @@ -21,10 +21,10 @@ import org.apache.tapestry5.ioc.annotations.Match; import org.apache.tapestry5.ioc.services.ApplicationDefaults; import org.apache.tapestry5.ioc.services.SymbolProvider; -import org.apache.tapestry5.jpa.EntityManagerSource; -import org.apache.tapestry5.jpa.JpaTransactionAdvisor; -import org.apache.tapestry5.jpa.PersistenceUnitConfigurer; -import org.apache.tapestry5.jpa.TapestryPersistenceUnitInfo; +import org.apache.tapestry5.jpa.core.EntityManagerSource; +import org.apache.tapestry5.jpa.core.JpaTransactionAdvisor; +import org.apache.tapestry5.jpa.core.PersistenceUnitConfigurer; +import org.apache.tapestry5.jpa.core.TapestryPersistenceUnitInfo; import org.apache.tapestry5.jpa.modules.JpaModule; import org.example.app1.AppConstants; import org.example.app1.entities.Thang; diff --git a/tapestry-jpa/src/test/java/org/example/app1/services/UserDAO.java b/tapestry-jpa/src/test/java/org/example/app1/services/UserDAO.java index 5ac815beed..970a08d807 100644 --- a/tapestry-jpa/src/test/java/org/example/app1/services/UserDAO.java +++ b/tapestry-jpa/src/test/java/org/example/app1/services/UserDAO.java @@ -18,7 +18,7 @@ import jakarta.persistence.PersistenceContext; -import org.apache.tapestry5.jpa.annotations.CommitAfter; +import org.apache.tapestry5.jpa.core.annotations.CommitAfter; import org.example.app1.AppConstants; import org.example.app1.entities.User; diff --git a/tapestry-jpa/src/test/java/org/example/app2/pages/PersistItem.java b/tapestry-jpa/src/test/java/org/example/app2/pages/PersistItem.java index f81813cb88..a5c7069cd8 100644 --- a/tapestry-jpa/src/test/java/org/example/app2/pages/PersistItem.java +++ b/tapestry-jpa/src/test/java/org/example/app2/pages/PersistItem.java @@ -1,4 +1,4 @@ -// Copyright 2011 The Apache Software Foundation +// Copyright 2011, 2026 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -19,7 +19,7 @@ import org.apache.tapestry5.annotations.Persist; import org.apache.tapestry5.annotations.Property; -import org.apache.tapestry5.jpa.annotations.CommitAfter; +import org.apache.tapestry5.jpa.core.annotations.CommitAfter; import org.example.app2.entities.Item; public class PersistItem diff --git a/tapestry-jpa/src/test/java/org/example/app2/pages/PersistItem2.java b/tapestry-jpa/src/test/java/org/example/app2/pages/PersistItem2.java index 786f9273de..ea4e2855e5 100644 --- a/tapestry-jpa/src/test/java/org/example/app2/pages/PersistItem2.java +++ b/tapestry-jpa/src/test/java/org/example/app2/pages/PersistItem2.java @@ -1,4 +1,4 @@ -// Copyright 2011 The Apache Software Foundation +// Copyright 2011, 2026 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ import org.apache.tapestry5.annotations.Persist; import org.apache.tapestry5.annotations.Property; import org.apache.tapestry5.ioc.annotations.Inject; -import org.apache.tapestry5.jpa.annotations.CommitAfter; +import org.apache.tapestry5.jpa.core.annotations.CommitAfter; import org.example.app2.entities.Item; import jakarta.persistence.EntityManager; diff --git a/tapestry-jpa/src/test/java/org/example/app2/pages/PersistItem3.java b/tapestry-jpa/src/test/java/org/example/app2/pages/PersistItem3.java index f8d9820b5e..ffbf5c182f 100644 --- a/tapestry-jpa/src/test/java/org/example/app2/pages/PersistItem3.java +++ b/tapestry-jpa/src/test/java/org/example/app2/pages/PersistItem3.java @@ -17,7 +17,7 @@ import org.apache.tapestry5.annotations.Persist; import org.apache.tapestry5.annotations.Property; import org.apache.tapestry5.ioc.annotations.Inject; -import org.apache.tapestry5.jpa.annotations.CommitAfter; +import org.apache.tapestry5.jpa.core.annotations.CommitAfter; import org.example.app2.entities.Item; import org.example.app2.services.UserDAO; diff --git a/tapestry-jpa/src/test/java/org/example/app3/pages/PersistThing.java b/tapestry-jpa/src/test/java/org/example/app3/pages/PersistThing.java index 172f7d97a2..bb53bbe1f8 100644 --- a/tapestry-jpa/src/test/java/org/example/app3/pages/PersistThing.java +++ b/tapestry-jpa/src/test/java/org/example/app3/pages/PersistThing.java @@ -1,4 +1,4 @@ -// Copyright 2011 The Apache Software Foundation +// Copyright 2011, 2026 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ import org.apache.tapestry5.annotations.Persist; import org.apache.tapestry5.annotations.Property; import org.apache.tapestry5.jpa.JpaPersistenceConstants; -import org.apache.tapestry5.jpa.annotations.CommitAfter; +import org.apache.tapestry5.jpa.core.annotations.CommitAfter; import org.example.app3.model.Thing; public class PersistThing diff --git a/tapestry-jpa/src/test/java/org/example/app3/services/AppModule.java b/tapestry-jpa/src/test/java/org/example/app3/services/AppModule.java index fa2cd1461d..c889b666dc 100644 --- a/tapestry-jpa/src/test/java/org/example/app3/services/AppModule.java +++ b/tapestry-jpa/src/test/java/org/example/app3/services/AppModule.java @@ -17,10 +17,10 @@ import org.apache.tapestry5.ioc.annotations.ImportModule; import org.apache.tapestry5.ioc.services.ApplicationDefaults; import org.apache.tapestry5.ioc.services.SymbolProvider; -import org.apache.tapestry5.jpa.EntityManagerSource; +import org.apache.tapestry5.jpa.core.EntityManagerSource; import org.apache.tapestry5.jpa.JpaSymbols; -import org.apache.tapestry5.jpa.PersistenceUnitConfigurer; -import org.apache.tapestry5.jpa.TapestryPersistenceUnitInfo; +import org.apache.tapestry5.jpa.core.PersistenceUnitConfigurer; +import org.apache.tapestry5.jpa.core.TapestryPersistenceUnitInfo; import org.apache.tapestry5.jpa.modules.JpaModule; @ImportModule(JpaModule.class) diff --git a/tapestry-jpa/src/test/java/org/example/app4/pages/PersistAll.java b/tapestry-jpa/src/test/java/org/example/app4/pages/PersistAll.java index d7a808076f..07b0fbf2ef 100644 --- a/tapestry-jpa/src/test/java/org/example/app4/pages/PersistAll.java +++ b/tapestry-jpa/src/test/java/org/example/app4/pages/PersistAll.java @@ -1,4 +1,4 @@ -// Copyright 2011 The Apache Software Foundation +// Copyright 2011, 2026 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ import org.apache.tapestry5.annotations.Persist; import org.apache.tapestry5.annotations.Property; import org.apache.tapestry5.jpa.JpaPersistenceConstants; -import org.apache.tapestry5.jpa.annotations.CommitAfter; +import org.apache.tapestry5.jpa.core.annotations.CommitAfter; import org.example.app1.entities.Thang; import org.example.app1.entities.User; import org.example.app2.entities.Item; diff --git a/tapestry-jpa/src/test/java/org/example/app6/pages/CommitAfterDemo.java b/tapestry-jpa/src/test/java/org/example/app6/pages/CommitAfterDemo.java index c6445f44b5..b59bed456c 100644 --- a/tapestry-jpa/src/test/java/org/example/app6/pages/CommitAfterDemo.java +++ b/tapestry-jpa/src/test/java/org/example/app6/pages/CommitAfterDemo.java @@ -18,7 +18,7 @@ import jakarta.persistence.PersistenceContext; -import org.apache.tapestry5.jpa.annotations.CommitAfter; +import org.apache.tapestry5.jpa.core.annotations.CommitAfter; import org.example.app6.AppConstants; import org.example.app6.entities.User; diff --git a/tapestry-jpa/src/test/java/org/example/app6/pages/EncodeEntities.java b/tapestry-jpa/src/test/java/org/example/app6/pages/EncodeEntities.java index 8d172ab108..10541ecb9e 100644 --- a/tapestry-jpa/src/test/java/org/example/app6/pages/EncodeEntities.java +++ b/tapestry-jpa/src/test/java/org/example/app6/pages/EncodeEntities.java @@ -21,7 +21,7 @@ import org.apache.tapestry5.annotations.Property; import org.apache.tapestry5.ioc.annotations.Inject; -import org.apache.tapestry5.jpa.annotations.CommitAfter; +import org.apache.tapestry5.jpa.core.annotations.CommitAfter; import org.example.app6.AppConstants; import org.example.app6.entities.User; import org.example.app6.services.UserDAO; diff --git a/tapestry-jpa/src/test/java/org/example/app6/pages/GridDemo.java b/tapestry-jpa/src/test/java/org/example/app6/pages/GridDemo.java index 88b2e6fd73..9d13a4e332 100644 --- a/tapestry-jpa/src/test/java/org/example/app6/pages/GridDemo.java +++ b/tapestry-jpa/src/test/java/org/example/app6/pages/GridDemo.java @@ -23,7 +23,7 @@ import org.apache.tapestry5.grid.GridDataSource; import org.apache.tapestry5.ioc.annotations.Inject; import org.apache.tapestry5.jpa.JpaGridDataSource; -import org.apache.tapestry5.jpa.annotations.CommitAfter; +import org.apache.tapestry5.jpa.core.annotations.CommitAfter; import org.example.app6.AppConstants; import org.example.app6.entities.User; import org.example.app6.services.UserDAO; diff --git a/tapestry-jpa/src/test/java/org/example/app6/pages/PersistEntity.java b/tapestry-jpa/src/test/java/org/example/app6/pages/PersistEntity.java index 26a9225069..da7068de63 100644 --- a/tapestry-jpa/src/test/java/org/example/app6/pages/PersistEntity.java +++ b/tapestry-jpa/src/test/java/org/example/app6/pages/PersistEntity.java @@ -22,7 +22,7 @@ import org.apache.tapestry5.annotations.Persist; import org.apache.tapestry5.annotations.Property; import org.apache.tapestry5.jpa.JpaPersistenceConstants; -import org.apache.tapestry5.jpa.annotations.CommitAfter; +import org.apache.tapestry5.jpa.core.annotations.CommitAfter; import org.example.app6.AppConstants; import org.example.app6.entities.User; diff --git a/tapestry-jpa/src/test/java/org/example/app6/pages/PersistThang.java b/tapestry-jpa/src/test/java/org/example/app6/pages/PersistThang.java index b542f24194..866d7be1bb 100644 --- a/tapestry-jpa/src/test/java/org/example/app6/pages/PersistThang.java +++ b/tapestry-jpa/src/test/java/org/example/app6/pages/PersistThang.java @@ -24,7 +24,7 @@ import org.apache.tapestry5.annotations.Persist; import org.apache.tapestry5.annotations.Property; import org.apache.tapestry5.jpa.JpaPersistenceConstants; -import org.apache.tapestry5.jpa.annotations.CommitAfter; +import org.apache.tapestry5.jpa.core.annotations.CommitAfter; import org.example.app6.entities.Thang; public class PersistThang diff --git a/tapestry-jpa/src/test/java/org/example/app6/services/AppModule.java b/tapestry-jpa/src/test/java/org/example/app6/services/AppModule.java index 9304acc5ca..2895f3b967 100644 --- a/tapestry-jpa/src/test/java/org/example/app6/services/AppModule.java +++ b/tapestry-jpa/src/test/java/org/example/app6/services/AppModule.java @@ -21,10 +21,10 @@ import org.apache.tapestry5.ioc.annotations.Match; import org.apache.tapestry5.ioc.services.ApplicationDefaults; import org.apache.tapestry5.ioc.services.SymbolProvider; -import org.apache.tapestry5.jpa.EntityManagerSource; -import org.apache.tapestry5.jpa.JpaTransactionAdvisor; -import org.apache.tapestry5.jpa.PersistenceUnitConfigurer; -import org.apache.tapestry5.jpa.TapestryPersistenceUnitInfo; +import org.apache.tapestry5.jpa.core.EntityManagerSource; +import org.apache.tapestry5.jpa.core.JpaTransactionAdvisor; +import org.apache.tapestry5.jpa.core.PersistenceUnitConfigurer; +import org.apache.tapestry5.jpa.core.TapestryPersistenceUnitInfo; import org.apache.tapestry5.jpa.modules.JpaModule; import org.example.app6.AppConstants; import org.example.app6.entities.Thang; diff --git a/tapestry-jpa/src/test/java/org/example/app6/services/UserDAO.java b/tapestry-jpa/src/test/java/org/example/app6/services/UserDAO.java index 0e6fb274c0..30eb91af41 100644 --- a/tapestry-jpa/src/test/java/org/example/app6/services/UserDAO.java +++ b/tapestry-jpa/src/test/java/org/example/app6/services/UserDAO.java @@ -18,7 +18,7 @@ import jakarta.persistence.PersistenceContext; -import org.apache.tapestry5.jpa.annotations.CommitAfter; +import org.apache.tapestry5.jpa.core.annotations.CommitAfter; import org.example.app6.AppConstants; import org.example.app6.entities.User; diff --git a/tapestry-jpa/src/test/java/org/example/app6/services/impl/UserDAOImpl.java b/tapestry-jpa/src/test/java/org/example/app6/services/impl/UserDAOImpl.java index a29985f308..29fc711e3b 100644 --- a/tapestry-jpa/src/test/java/org/example/app6/services/impl/UserDAOImpl.java +++ b/tapestry-jpa/src/test/java/org/example/app6/services/impl/UserDAOImpl.java @@ -20,7 +20,7 @@ import jakarta.persistence.PersistenceContext; import org.apache.tapestry5.ioc.annotations.Inject; -import org.apache.tapestry5.jpa.annotations.CommitAfter; +import org.apache.tapestry5.jpa.core.annotations.CommitAfter; import org.example.app6.AppConstants; import org.example.app6.entities.User; import org.example.app6.services.UserDAO;