Author: rmannibucau Date: Mon Oct 24 10:01:45 2016 New Revision: 1766367 URL: http://svn.apache.org/viewvc?rev=1766367&view=rev Log: adding JPA proposal - still experimental
Added: openwebbeans/microwave/trunk/microwave-core/src/main/java/org/apache/microwave/cxf/MicrowaveBus.java openwebbeans/microwave/trunk/microwave-jpa/ openwebbeans/microwave/trunk/microwave-jpa/README.adoc openwebbeans/microwave/trunk/microwave-jpa/pom.xml openwebbeans/microwave/trunk/microwave-jpa/src/ openwebbeans/microwave/trunk/microwave-jpa/src/main/ openwebbeans/microwave/trunk/microwave-jpa/src/main/java/ openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/ openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/ openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/ openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/ openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/api/ openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/api/EntityManagerScoped.java openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/api/Jpa.java openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/api/PersistenceUnitInfoBuilder.java openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/api/Unit.java openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/ openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/AnyLiteral.java openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/EntityManagerBean.java openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/EntityManagerContext.java openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/JpaExtension.java openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/JpaInterceptorBase.java openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/JpaNoTransactionInterceptor.java openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/JpaTransactionInterceptor.java openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/UnitLiteral.java openwebbeans/microwave/trunk/microwave-jpa/src/main/resources/ openwebbeans/microwave/trunk/microwave-jpa/src/main/resources/META-INF/ openwebbeans/microwave/trunk/microwave-jpa/src/main/resources/META-INF/services/ openwebbeans/microwave/trunk/microwave-jpa/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension openwebbeans/microwave/trunk/microwave-jpa/src/test/ openwebbeans/microwave/trunk/microwave-jpa/src/test/java/ openwebbeans/microwave/trunk/microwave-jpa/src/test/java/org/ openwebbeans/microwave/trunk/microwave-jpa/src/test/java/org/apache/ openwebbeans/microwave/trunk/microwave-jpa/src/test/java/org/apache/microwave/ openwebbeans/microwave/trunk/microwave-jpa/src/test/java/org/apache/microwave/jpa/ openwebbeans/microwave/trunk/microwave-jpa/src/test/java/org/apache/microwave/jpa/internal/ openwebbeans/microwave/trunk/microwave-jpa/src/test/java/org/apache/microwave/jpa/internal/JpaExtensionTest.java openwebbeans/microwave/trunk/microwave-jpa/src/test/java/org/app/ openwebbeans/microwave/trunk/microwave-jpa/src/test/java/org/app/JPADao.java openwebbeans/microwave/trunk/microwave-jpa/src/test/resources/ openwebbeans/microwave/trunk/microwave-jpa/src/test/resources/META-INF/ openwebbeans/microwave/trunk/microwave-jpa/src/test/resources/META-INF/beans.xml Modified: openwebbeans/microwave/trunk/microwave-core/src/main/java/org/apache/microwave/cxf/CxfCdiAutoSetup.java openwebbeans/microwave/trunk/microwave-core/src/main/java/org/apache/microwave/openwebbeans/KnowClassesFilter.java openwebbeans/microwave/trunk/microwave-core/src/main/java/org/apache/microwave/openwebbeans/KnownJarsFilter.java openwebbeans/microwave/trunk/microwave-junit/src/main/java/org/apache/microwave/junit/MicrowaveRule.java openwebbeans/microwave/trunk/microwave-junit/src/main/java/org/apache/microwave/junit/MicrowaveRuleBase.java openwebbeans/microwave/trunk/microwave-junit/src/main/java/org/apache/microwave/junit/MonoMicrowave.java openwebbeans/microwave/trunk/pom.xml Modified: openwebbeans/microwave/trunk/microwave-core/src/main/java/org/apache/microwave/cxf/CxfCdiAutoSetup.java URL: http://svn.apache.org/viewvc/openwebbeans/microwave/trunk/microwave-core/src/main/java/org/apache/microwave/cxf/CxfCdiAutoSetup.java?rev=1766367&r1=1766366&r2=1766367&view=diff ============================================================================== --- openwebbeans/microwave/trunk/microwave-core/src/main/java/org/apache/microwave/cxf/CxfCdiAutoSetup.java (original) +++ openwebbeans/microwave/trunk/microwave-core/src/main/java/org/apache/microwave/cxf/CxfCdiAutoSetup.java Mon Oct 24 10:01:45 2016 @@ -19,6 +19,8 @@ package org.apache.microwave.cxf; import org.apache.cxf.cdi.CXFCdiServlet; +import org.apache.cxf.common.util.ClassHelper; +import org.apache.cxf.common.util.ClassUnwrapper; import org.apache.cxf.endpoint.Endpoint; import org.apache.cxf.jaxrs.JAXRSServiceFactoryBean; import org.apache.cxf.jaxrs.model.ApplicationInfo; @@ -316,6 +318,7 @@ public class CxfCdiAutoSetup implements @Override protected void loadBus(final ServletConfig servletConfig) { super.loadBus(servletConfig); + if (noProviderSetup) { return; } Added: openwebbeans/microwave/trunk/microwave-core/src/main/java/org/apache/microwave/cxf/MicrowaveBus.java URL: http://svn.apache.org/viewvc/openwebbeans/microwave/trunk/microwave-core/src/main/java/org/apache/microwave/cxf/MicrowaveBus.java?rev=1766367&view=auto ============================================================================== --- openwebbeans/microwave/trunk/microwave-core/src/main/java/org/apache/microwave/cxf/MicrowaveBus.java (added) +++ openwebbeans/microwave/trunk/microwave-core/src/main/java/org/apache/microwave/cxf/MicrowaveBus.java Mon Oct 24 10:01:45 2016 @@ -0,0 +1,116 @@ +package org.apache.microwave.cxf; + +import org.apache.cxf.Bus; +import org.apache.cxf.bus.extension.ExtensionManagerBus; +import org.apache.cxf.common.util.ClassHelper; +import org.apache.cxf.common.util.ClassUnwrapper; +import org.apache.cxf.feature.Feature; +import org.apache.cxf.interceptor.Interceptor; +import org.apache.cxf.message.Message; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Named; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +@Named("cxf") +@ApplicationScoped +public class MicrowaveBus implements Bus { + private final Bus delegate = new ExtensionManagerBus(); + + public MicrowaveBus() { + setProperty(ClassUnwrapper.class.getName(), (ClassUnwrapper) o -> { + final Class<?> aClass = o.getClass(); + if (aClass.getName().contains("$$")) { + return aClass.getSuperclass(); + } + return aClass; + }); + } + + @Override + public <T> T getExtension(final Class<T> extensionType) { + return delegate.getExtension(extensionType); + } + + @Override + public <T> void setExtension(final T extension, final Class<T> extensionType) { + delegate.setExtension(extension, extensionType); + } + + @Override + public boolean hasExtensionByName(final String name) { + return delegate.hasExtensionByName(name); + } + + @Override + public String getId() { + return delegate.getId(); + } + + @Override + public void setId(final String i) { + delegate.setId(i); + } + + @Override + public void shutdown(final boolean wait) { + delegate.shutdown(wait); + } + + @Override + public void setProperty(final String s, final Object o) { + delegate.setProperty(s, o); + } + + @Override + public Object getProperty(final String s) { + return delegate.getProperty(s); + } + + @Override + public void setProperties(final Map<String, Object> properties) { + delegate.setProperties(properties); + } + + @Override + public Map<String, Object> getProperties() { + return delegate.getProperties(); + } + + @Override + public Collection<Feature> getFeatures() { + return delegate.getFeatures(); + } + + @Override + public void setFeatures(final Collection<? extends Feature> features) { + delegate.setFeatures(features); + } + + @Override + public BusState getState() { + return delegate.getState(); + } + + @Override + public List<Interceptor<? extends Message>> getInInterceptors() { + return delegate.getInInterceptors(); + } + + @Override + public List<Interceptor<? extends Message>> getOutInterceptors() { + return delegate.getOutInterceptors(); + } + + @Override + public List<Interceptor<? extends Message>> getInFaultInterceptors() { + return delegate.getInFaultInterceptors(); + } + + @Override + public List<Interceptor<? extends Message>> getOutFaultInterceptors() { + return delegate.getOutFaultInterceptors(); + } +} Modified: openwebbeans/microwave/trunk/microwave-core/src/main/java/org/apache/microwave/openwebbeans/KnowClassesFilter.java URL: http://svn.apache.org/viewvc/openwebbeans/microwave/trunk/microwave-core/src/main/java/org/apache/microwave/openwebbeans/KnowClassesFilter.java?rev=1766367&r1=1766366&r2=1766367&view=diff ============================================================================== --- openwebbeans/microwave/trunk/microwave-core/src/main/java/org/apache/microwave/openwebbeans/KnowClassesFilter.java (original) +++ openwebbeans/microwave/trunk/microwave-core/src/main/java/org/apache/microwave/openwebbeans/KnowClassesFilter.java Mon Oct 24 10:01:45 2016 @@ -147,6 +147,7 @@ public class KnowClassesFilter implement included.add("org.apache.myfaces.cdi"); // included.add("org.apache.myfaces.application.cdi"); included.add("org.apache.myfaces.flow.cdi"); + included.add("org.apache.microwave.cxf.MicrowaveBus"); delegateSkip = new OptimizedExclusionFilter(excluded); delegateAccept = new OptimizedExclusionFilter(included); Modified: openwebbeans/microwave/trunk/microwave-core/src/main/java/org/apache/microwave/openwebbeans/KnownJarsFilter.java URL: http://svn.apache.org/viewvc/openwebbeans/microwave/trunk/microwave-core/src/main/java/org/apache/microwave/openwebbeans/KnownJarsFilter.java?rev=1766367&r1=1766366&r2=1766367&view=diff ============================================================================== --- openwebbeans/microwave/trunk/microwave-core/src/main/java/org/apache/microwave/openwebbeans/KnownJarsFilter.java (original) +++ openwebbeans/microwave/trunk/microwave-core/src/main/java/org/apache/microwave/openwebbeans/KnownJarsFilter.java Mon Oct 24 10:01:45 2016 @@ -117,6 +117,7 @@ public class KnownJarsFilter implements add("gson-"); add("guava-"); add("guice-"); + add("h2-"); add("hamcrest-"); add("hawtbuf-"); add("hawtdispatch-"); Added: openwebbeans/microwave/trunk/microwave-jpa/README.adoc URL: http://svn.apache.org/viewvc/openwebbeans/microwave/trunk/microwave-jpa/README.adoc?rev=1766367&view=auto ============================================================================== --- openwebbeans/microwave/trunk/microwave-jpa/README.adoc (added) +++ openwebbeans/microwave/trunk/microwave-jpa/README.adoc Mon Oct 24 10:01:45 2016 @@ -0,0 +1,68 @@ += Microwave JPA + +The overall idea behind this module is to propose a CDI integration of JPA +allowing to programmatically control its persistence units. + +Concretely you will create a persistence unit from a `PersistenceUnitBuilder` +allowing you to fully configure your unit from CDI context including the datasource: + +[source,java] +---- +@ApplicationScoped +public class JpaConfig { + @Produces + public PersistenceUnitInfoBuilder unit(final DataSource ds) { + return new PersistenceUnitInfoBuilder() + .setUnitName("test") + .setDataSource(ds) + .setExcludeUnlistedClasses(true) + .addManagedClazz(User.class) + .addProperty("openjpa.RuntimeUnenhancedClasses", "supported") + .addProperty("openjpa.jdbc.SynchronizeMappings", "buildSchema"); + } +} +---- + +The datasource can be produces as you wish using your own configuration mecanism: + +[source,java] +---- +@ApplicationScoped +public class JpaConfig { + @Produces // dbcp2 datasource + public DataSource dataSource() { + final BasicDataSource source = new BasicDataSource(); + source.setDriver(new Driver()); + source.setUrl("jdbc:h2:mem:jpaextensiontest"); + return source; + } +} +---- + +Finally you can inject your entity manager using `@Unit`. Ensure to +decorate with `@Jpa` a class/method before using the entity manager to activate +the jpa CDI context: + +[source,java] +---- +@ApplicationScoped +@Jpa(transactional = false) +public class JPADao { + @Inject + @Unit(name = "test") + private EntityManager em; + + @Jpa // with a resource local transaction + public User save(final User user) { + em.persist(user); + return user; + } + + // inherit form class, no tx + public User find(final long id) { + return em.find(User.class, id); + } +} +---- + +IMPORTANT: this integration is 100% based on `RESOURCE_LOCAL` units for now. Added: openwebbeans/microwave/trunk/microwave-jpa/pom.xml URL: http://svn.apache.org/viewvc/openwebbeans/microwave/trunk/microwave-jpa/pom.xml?rev=1766367&view=auto ============================================================================== --- openwebbeans/microwave/trunk/microwave-jpa/pom.xml (added) +++ openwebbeans/microwave/trunk/microwave-jpa/pom.xml Mon Oct 24 10:01:45 2016 @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation=" + http://maven.apache.org/POM/4.0.0 + http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <artifactId>microwave</artifactId> + <groupId>org.apache.microwave</groupId> + <version>0.0.1-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>microwave-jpa</artifactId> + <name>Microwave :: JPA</name> + + <dependencies> + <dependency> + <groupId>org.apache.geronimo.specs</groupId> + <artifactId>geronimo-jpa_2.1_spec</artifactId> + <version>1.0-alpha-1</version> + </dependency> + <dependency> + <groupId>org.apache.microwave</groupId> + <artifactId>microwave-core</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>org.apache.openjpa</groupId> + <artifactId>openjpa</artifactId> + <version>2.4.1</version> + </dependency> + + <dependency> + <groupId>org.apache.microwave</groupId> + <artifactId>microwave-junit</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.h2database</groupId> + <artifactId>h2</artifactId> + <version>1.4.192</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-dbcp2</artifactId> + <version>2.1</version> + <scope>test</scope> + </dependency> + </dependencies> +</project> \ No newline at end of file Added: openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/api/EntityManagerScoped.java URL: http://svn.apache.org/viewvc/openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/api/EntityManagerScoped.java?rev=1766367&view=auto ============================================================================== --- openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/api/EntityManagerScoped.java (added) +++ openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/api/EntityManagerScoped.java Mon Oct 24 10:01:45 2016 @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.microwave.jpa.api; + +import javax.enterprise.context.NormalScope; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@NormalScope +@Target({METHOD, TYPE}) +@Retention(RUNTIME) +public @interface EntityManagerScoped { +} Added: openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/api/Jpa.java URL: http://svn.apache.org/viewvc/openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/api/Jpa.java?rev=1766367&view=auto ============================================================================== --- openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/api/Jpa.java (added) +++ openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/api/Jpa.java Mon Oct 24 10:01:45 2016 @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.microwave.jpa.api; + +import javax.interceptor.InterceptorBinding; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@InterceptorBinding +@Target({METHOD, TYPE}) +@Retention(RUNTIME) +public @interface Jpa { + boolean transactional() default true; +} Added: openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/api/PersistenceUnitInfoBuilder.java URL: http://svn.apache.org/viewvc/openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/api/PersistenceUnitInfoBuilder.java?rev=1766367&view=auto ============================================================================== --- openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/api/PersistenceUnitInfoBuilder.java (added) +++ openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/api/PersistenceUnitInfoBuilder.java Mon Oct 24 10:01:45 2016 @@ -0,0 +1,284 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.microwave.jpa.api; + +import javax.enterprise.inject.Vetoed; +import javax.persistence.SharedCacheMode; +import javax.persistence.ValidationMode; +import javax.persistence.spi.ClassTransformer; +import javax.persistence.spi.PersistenceProvider; +import javax.persistence.spi.PersistenceUnitInfo; +import javax.persistence.spi.PersistenceUnitTransactionType; +import javax.sql.DataSource; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; +import java.util.ServiceLoader; + +import static java.util.Collections.emptyList; +import static java.util.Objects.requireNonNull; +import static java.util.stream.Collectors.toList; +import static javax.persistence.spi.PersistenceUnitTransactionType.RESOURCE_LOCAL; + +@Vetoed +public class PersistenceUnitInfoBuilder { + private String unitName; + private String providerClass; + private DataSource dataSource; + private List<String> mappingFiles = emptyList(); + private List<URL> jarFiles = emptyList(); + private URL rootUrl; + private List<String> managedClasses = new ArrayList<>(); + private boolean excludeUnlistedClasses; + private SharedCacheMode sharedCacheMode = SharedCacheMode.UNSPECIFIED; + private ValidationMode validationMode = ValidationMode.AUTO; + private Properties properties = new Properties(); + private String version = "2.0"; + private ClassLoader loader = Thread.currentThread().getContextClassLoader(); + + public String getUnitName() { + return unitName; + } + + public PersistenceUnitInfoBuilder setUnitName(final String unitName) { + this.unitName = unitName; + return this; + } + + public String getProviderClass() { + return providerClass; + } + + public PersistenceUnitInfoBuilder setProviderClass(final String providerClass) { + this.providerClass = providerClass; + return this; + } + + public DataSource getDataSource() { + return dataSource; + } + + public PersistenceUnitInfoBuilder setDataSource(final DataSource dataSource) { + this.dataSource = dataSource; + return this; + } + + public List<String> getMappingFiles() { + return mappingFiles; + } + + public PersistenceUnitInfoBuilder setMappingFiles(final List<String> mappingFiles) { + this.mappingFiles = mappingFiles; + return this; + } + + public List<URL> getJarFiles() { + return jarFiles; + } + + public PersistenceUnitInfoBuilder setJarFiles(final List<URL> jarFiles) { + this.jarFiles = jarFiles; + return this; + } + + public URL getRootUrl() { + return rootUrl; + } + + public PersistenceUnitInfoBuilder setRootUrl(final URL rootUrl) { + this.rootUrl = rootUrl; + return this; + } + + public List<String> getManagedClasses() { + return managedClasses; + } + + public PersistenceUnitInfoBuilder addManagedClazz(final Class<?> clazz) { + managedClasses.add(clazz.getName()); + return this; + } + + public PersistenceUnitInfoBuilder setManagedClassNames(final List<String> managedClasses) { + this.managedClasses = managedClasses; + return this; + } + + public PersistenceUnitInfoBuilder setManagedClasses(final List<Class<?>> managedClasses) { + this.managedClasses = managedClasses.stream().map(Class::getName).collect(toList()); + return this; + } + + public boolean isExcludeUnlistedClasses() { + return excludeUnlistedClasses; + } + + public PersistenceUnitInfoBuilder setExcludeUnlistedClasses(final boolean excludeUnlistedClasses) { + this.excludeUnlistedClasses = excludeUnlistedClasses; + return this; + } + + public SharedCacheMode getSharedCacheMode() { + return sharedCacheMode; + } + + public PersistenceUnitInfoBuilder setSharedCacheMode(final SharedCacheMode sharedCacheMode) { + this.sharedCacheMode = sharedCacheMode; + return this; + } + + public ValidationMode getValidationMode() { + return validationMode; + } + + public PersistenceUnitInfoBuilder setValidationMode(final ValidationMode validationMode) { + this.validationMode = validationMode; + return this; + } + + public Properties getProperties() { + return properties; + } + + public PersistenceUnitInfoBuilder addProperty(final String key, final String value) { + if (properties == null) { + properties = new Properties(); + } + properties.setProperty(key, value); + return this; + } + + public PersistenceUnitInfoBuilder setProperties(final Properties properties) { + this.properties = properties; + return this; + } + + public String getVersion() { + return version; + } + + public PersistenceUnitInfoBuilder setVersion(final String version) { + this.version = version; + return this; + } + + public ClassLoader getLoader() { + return loader; + } + + public PersistenceUnitInfoBuilder setLoader(final ClassLoader loader) { + this.loader = loader; + return this; + } + + public PersistenceUnitInfo toInfo() { + if (providerClass == null) { + providerClass = ServiceLoader.load(PersistenceProvider.class).iterator().next().getClass().getName(); + } + requireNonNull(dataSource, "datasource not provided"); + return new PersistenceUnitInfo() { + @Override + public String getPersistenceUnitName() { + return unitName; + } + + @Override + public String getPersistenceProviderClassName() { + return providerClass; + } + + @Override + public PersistenceUnitTransactionType getTransactionType() { + return RESOURCE_LOCAL; + } + + @Override + public DataSource getJtaDataSource() { + return null; + } + + @Override + public DataSource getNonJtaDataSource() { + return dataSource; + } + + @Override + public List<String> getMappingFileNames() { + return mappingFiles; + } + + @Override + public List<URL> getJarFileUrls() { + return jarFiles; + } + + @Override + public URL getPersistenceUnitRootUrl() { + return rootUrl; + } + + @Override + public List<String> getManagedClassNames() { + return managedClasses; + } + + @Override + public boolean excludeUnlistedClasses() { + return excludeUnlistedClasses; + } + + @Override + public SharedCacheMode getSharedCacheMode() { + return sharedCacheMode; + } + + @Override + public ValidationMode getValidationMode() { + return validationMode; + } + + @Override + public Properties getProperties() { + return properties; + } + + @Override + public String getPersistenceXMLSchemaVersion() { + return version; + } + + @Override + public ClassLoader getClassLoader() { + return loader; + } + + @Override + public void addTransformer(final ClassTransformer transformer) { + // no-op: not supported + } + + @Override + public ClassLoader getNewTempClassLoader() { + return new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader()); + } + }; + } +} Added: openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/api/Unit.java URL: http://svn.apache.org/viewvc/openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/api/Unit.java?rev=1766367&view=auto ============================================================================== --- openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/api/Unit.java (added) +++ openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/api/Unit.java Mon Oct 24 10:01:45 2016 @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.microwave.jpa.api; + +import javax.inject.Qualifier; +import javax.persistence.SynchronizationType; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Qualifier +@Target({FIELD, METHOD, PARAMETER}) +@Retention(RUNTIME) +public @interface Unit { + String name(); + SynchronizationType synchronization() default SynchronizationType.SYNCHRONIZED; +} Added: openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/AnyLiteral.java URL: http://svn.apache.org/viewvc/openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/AnyLiteral.java?rev=1766367&view=auto ============================================================================== --- openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/AnyLiteral.java (added) +++ openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/AnyLiteral.java Mon Oct 24 10:01:45 2016 @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.microwave.jpa.internal; + +import javax.enterprise.inject.Any; +import javax.enterprise.util.AnnotationLiteral; +import java.lang.annotation.Annotation; + +public class AnyLiteral extends AnnotationLiteral<Any> implements Any { + public static final AnyLiteral INSTANCE = new AnyLiteral(); + + private static final String TOSTRING = "@javax.enterprise.inject.Any()"; + private static final long serialVersionUID = -8922048102786275371L; + + @Override + public Class<? extends Annotation> annotationType() { + return Any.class; + } + + @Override + public boolean equals(final Object other) { + return Any.class.isInstance(other) + || (AnnotationLiteral.class.isInstance(other) && AnnotationLiteral.class.cast(other).annotationType() == annotationType()); + } + + @Override + public int hashCode() { + return 0; + } + + @Override + public String toString() { + return TOSTRING; + } +} Added: openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/EntityManagerBean.java URL: http://svn.apache.org/viewvc/openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/EntityManagerBean.java?rev=1766367&view=auto ============================================================================== --- openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/EntityManagerBean.java (added) +++ openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/EntityManagerBean.java Mon Oct 24 10:01:45 2016 @@ -0,0 +1,130 @@ +package org.apache.microwave.jpa.internal; + +import org.apache.microwave.jpa.api.EntityManagerScoped; + +import javax.enterprise.context.spi.CreationalContext; +import javax.enterprise.inject.Vetoed; +import javax.enterprise.inject.spi.Bean; +import javax.enterprise.inject.spi.BeanManager; +import javax.enterprise.inject.spi.InjectionPoint; +import javax.enterprise.inject.spi.PassivationCapable; +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.SynchronizationType; +import javax.persistence.spi.PersistenceProvider; +import javax.persistence.spi.PersistenceUnitInfo; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; +import java.util.function.Supplier; + +import static java.util.Arrays.asList; +import static java.util.Collections.emptySet; +import static java.util.Collections.singletonList; + +@Vetoed +public class EntityManagerBean implements Bean<EntityManager>, PassivationCapable { + private final Set<Type> types = new HashSet<>(singletonList(EntityManager.class)); + private final Set<Annotation> qualifiers = new HashSet<>(); + private final EntityManagerContext entityManagerContext; + private final SynchronizationType synchronization; + private final String id; + private Supplier<EntityManager> instanceFactory; + + EntityManagerBean(final EntityManagerContext context, final String name, final SynchronizationType synchronization) { + this.entityManagerContext = context; + this.qualifiers.addAll(asList(new UnitLiteral(name, synchronization), AnyLiteral.INSTANCE)); + this.id = "microwave::jpa::entitymanager::" + name + "/" + synchronization.name(); + this.synchronization = synchronization; + } + + void init(final BeanManager bm, final PersistenceUnitInfo info) { + final PersistenceProvider provider; + try { + provider = PersistenceProvider.class.cast( + Thread.currentThread().getContextClassLoader().loadClass(info.getPersistenceProviderClassName()).newInstance()); + } catch (final InstantiationException | IllegalAccessException | ClassNotFoundException e) { + throw new IllegalArgumentException("Bad provider: " + info.getPersistenceProviderClassName()); + } + final EntityManagerFactory factory = provider.createContainerEntityManagerFactory(info, new HashMap() {{ + // TODO: bval + CDI integ + }}); + instanceFactory = synchronization == SynchronizationType.SYNCHRONIZED ? factory::createEntityManager : () -> factory.createEntityManager(synchronization); + } + + @Override + public EntityManager create(final CreationalContext<EntityManager> context) { + final EntityManager entityManager = instanceFactory.get(); + if (entityManagerContext.isTransactional()) { + entityManager.getTransaction().begin(); + } + return entityManager; + } + + @Override + public void destroy(final EntityManager instance, final CreationalContext<EntityManager> context) { + try { + if (entityManagerContext.isTransactional()) { + if (entityManagerContext.hasFailed()) { + instance.getTransaction().rollback(); + } else { + instance.getTransaction().commit(); + } + } + } finally { + instance.close(); + } + } + + @Override + public Set<InjectionPoint> getInjectionPoints() { + return emptySet(); + } + + @Override + public Class<?> getBeanClass() { + return EntityManager.class; + } + + @Override + public boolean isNullable() { + return false; + } + + @Override + public Set<Type> getTypes() { + return types; + } + + @Override + public Set<Annotation> getQualifiers() { + return qualifiers; + } + + @Override + public Class<? extends Annotation> getScope() { + return EntityManagerScoped.class; + } + + @Override + public String getName() { + return null; + } + + @Override + public Set<Class<? extends Annotation>> getStereotypes() { + return emptySet(); + } + + @Override + public boolean isAlternative() { + return false; + } + + @Override + public String getId() { + return id; + } +} Added: openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/EntityManagerContext.java URL: http://svn.apache.org/viewvc/openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/EntityManagerContext.java?rev=1766367&view=auto ============================================================================== --- openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/EntityManagerContext.java (added) +++ openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/EntityManagerContext.java Mon Oct 24 10:01:45 2016 @@ -0,0 +1,152 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.microwave.jpa.internal; + +import org.apache.microwave.jpa.api.EntityManagerScoped; + +import javax.enterprise.context.spi.AlterableContext; +import javax.enterprise.context.spi.Contextual; +import javax.enterprise.context.spi.CreationalContext; +import java.io.Serializable; +import java.lang.annotation.Annotation; +import java.util.HashMap; +import java.util.Map; + +import static java.util.Optional.ofNullable; + +public class EntityManagerContext implements AlterableContext { + private final ThreadLocal<ThreadContext> context = new ThreadLocal<>(); + + public boolean enter(final boolean transactional) { + if (context.get() != null) { + return false; + } + final ThreadContext value = new ThreadContext(); + value.transactional = transactional; + context.set(value); + return true; + } + + public void failed() { + context.get().failed = true; + } + + public void exit(final boolean created) { + if (created) { + context.get().exit(); + context.remove(); + } + } + + @Override + public Class<? extends Annotation> getScope() { + return EntityManagerScoped.class; + } + + @Override + public void destroy(final Contextual<?> contextual) { + context.get().destroy(contextual); + } + + @Override + public <T> T get(final Contextual<T> component, final CreationalContext<T> creationalContext) { + return context.get().get(component, creationalContext); + } + + @Override + public <T> T get(final Contextual<T> component) { + return context.get().get(component); + } + + @Override + public boolean isActive() { + final boolean active = context.get() != null; + if (!active) { + context.remove(); + } + return active; + } + + public boolean hasFailed() { + return context.get().failed; + } + + public boolean isTransactional() { + return context.get().transactional; + } + + private static class ThreadContext implements AlterableContext { + private final Map<Contextual<?>, BeanInstanceBag<?>> components = new HashMap<>(); + private boolean failed; + private boolean transactional; + + @Override + public Class<? extends Annotation> getScope() { + return EntityManagerScoped.class; + } + + @Override + public <T> T get(final Contextual<T> component, final CreationalContext<T> creationalContext) { + BeanInstanceBag<T> bag = (BeanInstanceBag<T>) components.get(component); + if (bag == null) { + bag = new BeanInstanceBag<>(creationalContext); + components.put(component, bag); + } + if (bag.beanInstance == null) { + bag.beanInstance = component.create(creationalContext); + } + return bag.beanInstance; + } + + @Override + public <T> T get(final Contextual<T> component) { + final BeanInstanceBag<?> bag = components.get(component); + return bag == null ? null : (T) bag.beanInstance; + } + + @Override + public void destroy(final Contextual<?> contextual) { + final BeanInstanceBag remove = components.remove(contextual); + ofNullable(remove).ifPresent(b -> doDestroy(contextual, b)); + } + + private <T> void doDestroy(final Contextual<T> contextual, final BeanInstanceBag<T> bag) { + contextual.destroy(bag.beanInstance, bag.beanCreationalContext); + bag.beanCreationalContext.release(); + } + + @Override + public boolean isActive() { + return true; + } + + private void exit() { + components.forEach((k, bag) -> doDestroy(k, BeanInstanceBag.class.cast(bag))); + } + } + + private static class BeanInstanceBag<T> implements Serializable { + private final CreationalContext<T> beanCreationalContext; + private T beanInstance; + + private BeanInstanceBag(final CreationalContext<T> beanCreationalContext) { + this.beanCreationalContext = beanCreationalContext; + } + } +} Added: openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/JpaExtension.java URL: http://svn.apache.org/viewvc/openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/JpaExtension.java?rev=1766367&view=auto ============================================================================== --- openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/JpaExtension.java (added) +++ openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/JpaExtension.java Mon Oct 24 10:01:45 2016 @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.microwave.jpa.internal; + +import org.apache.microwave.jpa.api.Unit; +import org.apache.microwave.jpa.api.PersistenceUnitInfoBuilder; + +import javax.enterprise.context.spi.CreationalContext; +import javax.enterprise.event.Observes; +import javax.enterprise.inject.spi.AfterBeanDiscovery; +import javax.enterprise.inject.spi.AfterDeploymentValidation; +import javax.enterprise.inject.spi.Bean; +import javax.enterprise.inject.spi.BeanManager; +import javax.enterprise.inject.spi.BeforeBeanDiscovery; +import javax.enterprise.inject.spi.Extension; +import javax.enterprise.inject.spi.ProcessAnnotatedType; +import javax.enterprise.inject.spi.ProcessBean; +import javax.enterprise.inject.spi.WithAnnotations; +import javax.persistence.Embeddable; +import javax.persistence.Entity; +import javax.persistence.MappedSuperclass; +import javax.persistence.spi.PersistenceUnitInfo; +import java.lang.annotation.Annotation; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +import static java.util.function.Function.identity; +import static java.util.stream.Collectors.toMap; + +/** + * This extension is responsible to create entitymanagers, entitymanagerfactories + * and link it to CDI named units. + * <p> + * Note: we don't reuse @DataSourceDefinition which is all but defined (pooling, datasource configs are a mess). + */ +public class JpaExtension implements Extension { + private final EntityManagerContext entityManagerContext = new EntityManagerContext(); + private final List<String> jpaClasses = new ArrayList<>(); + private final Map<String, EntityManagerBean> entityManagerBeans = new HashMap<>(); + private final Collection<Bean<?>> unitBuilders = new ArrayList<>(2); + + void addInternals(@Observes final BeforeBeanDiscovery bbd, final BeanManager bm) { + Stream.of(JpaTransactionInterceptor.class, JpaNoTransactionInterceptor.class) + .forEach(interceptor -> bbd.addAnnotatedType(bm.createAnnotatedType(interceptor))); + } + + void collectEntityManagerInjections(@Observes final ProcessBean<?> bean) { + final Map<String, EntityManagerBean> beans = bean.getBean().getInjectionPoints().stream() + .filter(i -> i.getAnnotated().isAnnotationPresent(Unit.class)) + .map(i -> i.getAnnotated().getAnnotation(Unit.class)) + .collect(toMap(Unit::name, unit -> new EntityManagerBean(entityManagerContext, unit.name(), unit.synchronization()))); + entityManagerBeans.putAll(beans); + } + + void collectEntityManagers(@Observes final ProcessBean<?> bean) { + if (bean.getBean().getTypes().contains(PersistenceUnitInfoBuilder.class)) { + unitBuilders.add(bean.getBean()); + } + } + + void collectEntities(@Observes @WithAnnotations({Entity.class, MappedSuperclass.class, Embeddable.class}) final ProcessAnnotatedType<?> jpa) { + jpaClasses.add(jpa.getAnnotatedType().getJavaClass().getName()); + } + + void addBeans(@Observes final AfterBeanDiscovery afb, final BeanManager bm) { + afb.addContext(entityManagerContext); + entityManagerBeans.forEach((n, b) -> afb.addBean(b)); + } + + void initBeans(@Observes final AfterDeploymentValidation adv, final BeanManager bm) { + final Map<String, PersistenceUnitInfo> infoIndex = unitBuilders.stream() + .map(bean -> { + final CreationalContext<?> cc = bm.createCreationalContext(null); + try { + final Bean<?> resolvedBean = bm.resolve(bm.getBeans( + PersistenceUnitInfoBuilder.class, + bean.getQualifiers().toArray(new Annotation[bean.getQualifiers().size()]))); + final PersistenceUnitInfoBuilder builder = PersistenceUnitInfoBuilder.class.cast( + bm.getReference(resolvedBean, PersistenceUnitInfoBuilder.class, cc)); + if (builder.getManagedClasses().isEmpty()) { + builder.setManagedClassNames(jpaClasses).setExcludeUnlistedClasses(true); + } + return builder.toInfo(); + } finally { + cc.release(); + } + }).collect(toMap(PersistenceUnitInfo::getPersistenceUnitName, identity())); + + entityManagerBeans.forEach((k, e) -> { + final PersistenceUnitInfo info = infoIndex.get(k); + if (info == null) { + adv.addDeploymentProblem(new IllegalArgumentException("Didn't find any PersistenceUnitInfoBuilder for " + k)); + } else { + e.init(bm, info); + } + }); + } + + public EntityManagerContext getEntityManagerContext() { + return entityManagerContext; + } +} Added: openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/JpaInterceptorBase.java URL: http://svn.apache.org/viewvc/openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/JpaInterceptorBase.java?rev=1766367&view=auto ============================================================================== --- openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/JpaInterceptorBase.java (added) +++ openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/JpaInterceptorBase.java Mon Oct 24 10:01:45 2016 @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.microwave.jpa.internal; + +import javax.inject.Inject; +import javax.interceptor.AroundInvoke; +import javax.interceptor.InvocationContext; +import java.io.Serializable; + +public abstract class JpaInterceptorBase implements Serializable { + @Inject + private JpaExtension extension; + + @AroundInvoke + public Object inTransaction(final InvocationContext context) throws Exception { + final EntityManagerContext entityManagerContext = extension.getEntityManagerContext(); + final boolean owner = entityManagerContext.enter(isTransactional()); + try { + return context.proceed(); + } catch (final Exception e) { + entityManagerContext.failed(); + throw e; + } finally { + entityManagerContext.exit(owner); + } + } + + protected abstract boolean isTransactional(); +} Added: openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/JpaNoTransactionInterceptor.java URL: http://svn.apache.org/viewvc/openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/JpaNoTransactionInterceptor.java?rev=1766367&view=auto ============================================================================== --- openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/JpaNoTransactionInterceptor.java (added) +++ openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/JpaNoTransactionInterceptor.java Mon Oct 24 10:01:45 2016 @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.microwave.jpa.internal; + +import org.apache.microwave.jpa.api.Jpa; + +import javax.annotation.Priority; +import javax.interceptor.Interceptor; + +@Jpa(transactional = false) +@Interceptor +@Priority(Interceptor.Priority.LIBRARY_BEFORE) +public class JpaNoTransactionInterceptor extends JpaInterceptorBase { + @Override + protected boolean isTransactional() { + return false; + } +} Added: openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/JpaTransactionInterceptor.java URL: http://svn.apache.org/viewvc/openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/JpaTransactionInterceptor.java?rev=1766367&view=auto ============================================================================== --- openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/JpaTransactionInterceptor.java (added) +++ openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/JpaTransactionInterceptor.java Mon Oct 24 10:01:45 2016 @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.microwave.jpa.internal; + +import org.apache.microwave.jpa.api.Jpa; + +import javax.annotation.Priority; +import javax.interceptor.Interceptor; + +@Jpa +@Interceptor +@Priority(Interceptor.Priority.LIBRARY_BEFORE) +public class JpaTransactionInterceptor extends JpaInterceptorBase { + @Override + protected boolean isTransactional() { + return true; + } +} Added: openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/UnitLiteral.java URL: http://svn.apache.org/viewvc/openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/UnitLiteral.java?rev=1766367&view=auto ============================================================================== --- openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/UnitLiteral.java (added) +++ openwebbeans/microwave/trunk/microwave-jpa/src/main/java/org/apache/microwave/jpa/internal/UnitLiteral.java Mon Oct 24 10:01:45 2016 @@ -0,0 +1,49 @@ +package org.apache.microwave.jpa.internal; + +import org.apache.microwave.jpa.api.Unit; + +import javax.enterprise.util.AnnotationLiteral; +import javax.persistence.SynchronizationType; + +class UnitLiteral extends AnnotationLiteral<Unit> implements Unit { + private final String name; + private final SynchronizationType synchronization; + + UnitLiteral(final String name, final SynchronizationType synchronization) { + this.name = name; + this.synchronization = synchronization; + } + + @Override + public String name() { + return name; + } + + @Override + public SynchronizationType synchronization() { + return synchronization; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final UnitLiteral that = UnitLiteral.class.cast(o); + return name.equals(that.name) && synchronization.equals(that.synchronization); + + } + + @Override + public int hashCode() { + return name.hashCode() + 31 * synchronization.hashCode(); + } + + @Override + public String toString() { + return "@Unit(name=" + name + ",synchronization=" + synchronization.name() + ")"; + } +} Added: openwebbeans/microwave/trunk/microwave-jpa/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension URL: http://svn.apache.org/viewvc/openwebbeans/microwave/trunk/microwave-jpa/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension?rev=1766367&view=auto ============================================================================== --- openwebbeans/microwave/trunk/microwave-jpa/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension (added) +++ openwebbeans/microwave/trunk/microwave-jpa/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension Mon Oct 24 10:01:45 2016 @@ -0,0 +1 @@ +org.apache.microwave.jpa.internal.JpaExtension Added: openwebbeans/microwave/trunk/microwave-jpa/src/test/java/org/apache/microwave/jpa/internal/JpaExtensionTest.java URL: http://svn.apache.org/viewvc/openwebbeans/microwave/trunk/microwave-jpa/src/test/java/org/apache/microwave/jpa/internal/JpaExtensionTest.java?rev=1766367&view=auto ============================================================================== --- openwebbeans/microwave/trunk/microwave-jpa/src/test/java/org/apache/microwave/jpa/internal/JpaExtensionTest.java (added) +++ openwebbeans/microwave/trunk/microwave-jpa/src/test/java/org/apache/microwave/jpa/internal/JpaExtensionTest.java Mon Oct 24 10:01:45 2016 @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.microwave.jpa.internal; + +import org.apache.microwave.junit.MicrowaveRule; +import org.app.JPADao; +import org.junit.Rule; +import org.junit.Test; + +import javax.inject.Inject; + +import static org.junit.Assert.assertEquals; + +public class JpaExtensionTest { + @Rule + public final MicrowaveRule rule = new MicrowaveRule().inject(this); + + @Inject + private JPADao service; + + @Test + public void run() { + final JPADao.User u = new JPADao.User(); + u.setName("test"); + assertEquals("test", service.find(service.save(u).getId()).getName()); + } +} Added: openwebbeans/microwave/trunk/microwave-jpa/src/test/java/org/app/JPADao.java URL: http://svn.apache.org/viewvc/openwebbeans/microwave/trunk/microwave-jpa/src/test/java/org/app/JPADao.java?rev=1766367&view=auto ============================================================================== --- openwebbeans/microwave/trunk/microwave-jpa/src/test/java/org/app/JPADao.java (added) +++ openwebbeans/microwave/trunk/microwave-jpa/src/test/java/org/app/JPADao.java Mon Oct 24 10:01:45 2016 @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.app; + +import org.apache.commons.dbcp2.BasicDataSource; +import org.apache.microwave.jpa.api.Jpa; +import org.apache.microwave.jpa.api.PersistenceUnitInfoBuilder; +import org.apache.microwave.jpa.api.Unit; +import org.h2.Driver; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.context.Dependent; +import javax.enterprise.inject.Produces; +import javax.inject.Inject; +import javax.persistence.Entity; +import javax.persistence.EntityManager; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.sql.DataSource; + +@ApplicationScoped +@Jpa(transactional = false) +public class JPADao { + @Inject + @Unit(name = "test") + private EntityManager em; + + @Jpa // tx + public User save(final User user) { + em.persist(user); + return user; + } + + // inherit form class, no tx + public User find(final long id) { + return em.find(User.class, id); + } + + @ApplicationScoped + public static class JpaConfig { + @Produces + public DataSource dataSource() { + final BasicDataSource source = new BasicDataSource(); + source.setDriver(new Driver()); + source.setUrl("jdbc:h2:mem:jpaextensiontest"); + return source; + } + + @Produces + public PersistenceUnitInfoBuilder unit(final DataSource ds) { + return new PersistenceUnitInfoBuilder() + .setUnitName("test") + .setDataSource(ds) + .setExcludeUnlistedClasses(true) + .addManagedClazz(User.class) + .addProperty("openjpa.RuntimeUnenhancedClasses", "supported") + .addProperty("openjpa.jdbc.SynchronizeMappings", "buildSchema"); + } + } + + @Entity + @Dependent + public static class User { + @Id + @GeneratedValue + private long id; + + private String name; + + public long getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } + } + +} Added: openwebbeans/microwave/trunk/microwave-jpa/src/test/resources/META-INF/beans.xml URL: http://svn.apache.org/viewvc/openwebbeans/microwave/trunk/microwave-jpa/src/test/resources/META-INF/beans.xml?rev=1766367&view=auto ============================================================================== --- openwebbeans/microwave/trunk/microwave-jpa/src/test/resources/META-INF/beans.xml (added) +++ openwebbeans/microwave/trunk/microwave-jpa/src/test/resources/META-INF/beans.xml Mon Oct 24 10:01:45 2016 @@ -0,0 +1,19 @@ +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +--> +<beans /> Modified: openwebbeans/microwave/trunk/microwave-junit/src/main/java/org/apache/microwave/junit/MicrowaveRule.java URL: http://svn.apache.org/viewvc/openwebbeans/microwave/trunk/microwave-junit/src/main/java/org/apache/microwave/junit/MicrowaveRule.java?rev=1766367&r1=1766366&r2=1766367&view=diff ============================================================================== --- openwebbeans/microwave/trunk/microwave-junit/src/main/java/org/apache/microwave/junit/MicrowaveRule.java (original) +++ openwebbeans/microwave/trunk/microwave-junit/src/main/java/org/apache/microwave/junit/MicrowaveRule.java Mon Oct 24 10:01:45 2016 @@ -20,7 +20,7 @@ package org.apache.microwave.junit; import org.apache.microwave.Microwave; -public class MicrowaveRule extends MicrowaveRuleBase { +public class MicrowaveRule extends MicrowaveRuleBase<MicrowaveRule> { private final Microwave.Builder configuration; private final String context; Modified: openwebbeans/microwave/trunk/microwave-junit/src/main/java/org/apache/microwave/junit/MicrowaveRuleBase.java URL: http://svn.apache.org/viewvc/openwebbeans/microwave/trunk/microwave-junit/src/main/java/org/apache/microwave/junit/MicrowaveRuleBase.java?rev=1766367&r1=1766366&r2=1766367&view=diff ============================================================================== --- openwebbeans/microwave/trunk/microwave-junit/src/main/java/org/apache/microwave/junit/MicrowaveRuleBase.java (original) +++ openwebbeans/microwave/trunk/microwave-junit/src/main/java/org/apache/microwave/junit/MicrowaveRuleBase.java Mon Oct 24 10:01:45 2016 @@ -23,19 +23,58 @@ import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement; -public abstract class MicrowaveRuleBase implements TestRule { +import javax.enterprise.context.spi.CreationalContext; +import javax.enterprise.inject.spi.AnnotatedType; +import javax.enterprise.inject.spi.BeanManager; +import javax.enterprise.inject.spi.CDI; +import javax.enterprise.inject.spi.InjectionTarget; +import java.util.ArrayList; +import java.util.Collection; +import java.util.concurrent.atomic.AtomicBoolean; + +import static java.util.stream.Collectors.toList; + +public abstract class MicrowaveRuleBase<T extends MicrowaveRuleBase> implements TestRule { + private final Collection<Object> toInject = new ArrayList<>(); + private final AtomicBoolean started = new AtomicBoolean(false); + @Override public Statement apply(final Statement base, final Description description) { return new Statement() { @Override public void evaluate() throws Throwable { try (final AutoCloseable closeable = onStart()) { - base.evaluate(); + started.set(true); + final Collection<CreationalContext<?>> contexts = toInject.stream().map(MicrowaveRuleBase::doInject).collect(toList()); + try { + base.evaluate(); + } finally { + contexts.forEach(CreationalContext::release); + started.set(false); + } } } }; } + private static CreationalContext<Object> doInject(final Object instance) { + final BeanManager bm = CDI.current().getBeanManager(); + final AnnotatedType<?> annotatedType = bm.createAnnotatedType(instance.getClass()); + final InjectionTarget injectionTarget = bm.createInjectionTarget(annotatedType); + final CreationalContext<Object> creationalContext = bm.createCreationalContext(null); + injectionTarget.inject(instance, creationalContext); + return creationalContext; + } + + public <T> T inject(final Object instance) { + if (started.get()) { + doInject(instance); // TODO: store cc to release it + } else { + toInject.add(instance); + } + return (T) this; + } + public abstract Microwave.Builder getConfiguration(); protected abstract AutoCloseable onStart(); Modified: openwebbeans/microwave/trunk/microwave-junit/src/main/java/org/apache/microwave/junit/MonoMicrowave.java URL: http://svn.apache.org/viewvc/openwebbeans/microwave/trunk/microwave-junit/src/main/java/org/apache/microwave/junit/MonoMicrowave.java?rev=1766367&r1=1766366&r2=1766367&view=diff ============================================================================== --- openwebbeans/microwave/trunk/microwave-junit/src/main/java/org/apache/microwave/junit/MonoMicrowave.java (original) +++ openwebbeans/microwave/trunk/microwave-junit/src/main/java/org/apache/microwave/junit/MonoMicrowave.java Mon Oct 24 10:01:45 2016 @@ -90,7 +90,7 @@ public class MonoMicrowave { } } - public static class Rule extends MicrowaveRuleBase { + public static class Rule extends MicrowaveRuleBase<Rule> { @Override public Microwave.Builder getConfiguration() { return CONFIGURATION.get(); Modified: openwebbeans/microwave/trunk/pom.xml URL: http://svn.apache.org/viewvc/openwebbeans/microwave/trunk/pom.xml?rev=1766367&r1=1766366&r2=1766367&view=diff ============================================================================== --- openwebbeans/microwave/trunk/pom.xml (original) +++ openwebbeans/microwave/trunk/pom.xml Mon Oct 24 10:01:45 2016 @@ -47,6 +47,7 @@ <module>microwave-gradle-plugin</module> <module>microwave-junit</module> <module>microwave-arquillian</module> + <module>microwave-jpa</module> </modules> <build>