diff --git a/core/deployment/src/main/java/org/jboss/shamrock/deployment/BuildTimeGenerator.java b/core/deployment/src/main/java/org/jboss/shamrock/deployment/BuildTimeGenerator.java index b49388072..ad276830a 100644 --- a/core/deployment/src/main/java/org/jboss/shamrock/deployment/BuildTimeGenerator.java +++ b/core/deployment/src/main/java/org/jboss/shamrock/deployment/BuildTimeGenerator.java @@ -74,6 +74,7 @@ public class BuildTimeGenerator { private final List>> bytecodeTransformers = new ArrayList<>(); private final Set applicationArchiveMarkers; private final ArchiveContextBuilder archiveContextBuilder; + private final Set capabilities; public BuildTimeGenerator(ClassOutput classOutput, ClassLoader cl, boolean useStaticInit, ArchiveContextBuilder contextBuilder) { this.useStaticInit = useStaticInit; @@ -91,6 +92,7 @@ public class BuildTimeGenerator { this.classLoader = cl; this.applicationArchiveMarkers = new HashSet<>(setupContext.applicationArchiveMarkers); this.archiveContextBuilder = contextBuilder; + this.capabilities = new HashSet<>(setupContext.capabilities); } public List>> getBytecodeTransformers() { @@ -294,6 +296,11 @@ public class BuildTimeGenerator { this.proxyClasses.add(Arrays.asList(proxyClasses)); } + @Override + public boolean isCapabilityPresent(String capability) { + return capabilities.contains(capability); + } + void writeMainClass() throws IOException { diff --git a/core/deployment/src/main/java/org/jboss/shamrock/deployment/ProcessorContext.java b/core/deployment/src/main/java/org/jboss/shamrock/deployment/ProcessorContext.java index 83bd40575..ed259223d 100644 --- a/core/deployment/src/main/java/org/jboss/shamrock/deployment/ProcessorContext.java +++ b/core/deployment/src/main/java/org/jboss/shamrock/deployment/ProcessorContext.java @@ -108,4 +108,11 @@ public interface ProcessorContext { * @param proxyClasses The interface names that this proxy will implement */ void addProxyDefinition(String ... proxyClasses); + + /** + * + * @param capability + * @return + */ + boolean isCapabilityPresent(String capability); } diff --git a/core/deployment/src/main/java/org/jboss/shamrock/deployment/RuntimePriority.java b/core/deployment/src/main/java/org/jboss/shamrock/deployment/RuntimePriority.java index a97f980c6..b173d99fb 100644 --- a/core/deployment/src/main/java/org/jboss/shamrock/deployment/RuntimePriority.java +++ b/core/deployment/src/main/java/org/jboss/shamrock/deployment/RuntimePriority.java @@ -15,8 +15,9 @@ public class RuntimePriority { public static final int JAXRS_DEPLOYMENT = 350; public static final int ARC_DEPLOYMENT = 300; public static final int UNDERTOW_DEPLOY = 400; - public static final int UNDERTOW_START = 500; public static final int BEAN_VALIDATION_DEPLOYMENT = 600; public static final int TRANSACTIONS_DEPLOYMENT = 700; public static final int DATASOURCE_DEPLOYMENT = 700; + public static final int BOOTSTRAP_EMF = 800; + public static final int UNDERTOW_START = 900; } diff --git a/core/deployment/src/main/java/org/jboss/shamrock/deployment/SetupContext.java b/core/deployment/src/main/java/org/jboss/shamrock/deployment/SetupContext.java index 095a673db..62a351a8c 100644 --- a/core/deployment/src/main/java/org/jboss/shamrock/deployment/SetupContext.java +++ b/core/deployment/src/main/java/org/jboss/shamrock/deployment/SetupContext.java @@ -24,4 +24,10 @@ public interface SetupContext { * @param file The file location */ void addApplicationArchiveMarker(String file); + + /** + * Registers a capability name as being present, this can be queried via {@link ProcessorContext#isCapabilityPresent(String)} + * @param name The capability name + */ + void addCapability(String name); } diff --git a/core/deployment/src/main/java/org/jboss/shamrock/deployment/SetupContextImpl.java b/core/deployment/src/main/java/org/jboss/shamrock/deployment/SetupContextImpl.java index c7ed59ee5..7ae3d8272 100644 --- a/core/deployment/src/main/java/org/jboss/shamrock/deployment/SetupContextImpl.java +++ b/core/deployment/src/main/java/org/jboss/shamrock/deployment/SetupContextImpl.java @@ -1,13 +1,16 @@ package org.jboss.shamrock.deployment; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; class SetupContextImpl implements SetupContext { final List resourceProcessors = new ArrayList<>(); final List injectionProviders = new ArrayList<>(); final List applicationArchiveMarkers = new ArrayList<>(); + final Set capabilities = new HashSet<>(); @Override public void addResourceProcessor(ResourceProcessor resourceProcessor) { @@ -23,4 +26,8 @@ class SetupContextImpl implements SetupContext { public void addApplicationArchiveMarker(String file) { applicationArchiveMarkers.add(file); } + + public void addCapability(String name) { + capabilities.add(name); + } } diff --git a/core/deployment/src/main/java/org/jboss/shamrock/runner/RuntimeClassLoader.java b/core/deployment/src/main/java/org/jboss/shamrock/runner/RuntimeClassLoader.java index 268d423ae..9f53b5613 100644 --- a/core/deployment/src/main/java/org/jboss/shamrock/runner/RuntimeClassLoader.java +++ b/core/deployment/src/main/java/org/jboss/shamrock/runner/RuntimeClassLoader.java @@ -53,7 +53,14 @@ public class RuntimeClassLoader extends ClassLoader implements ClassOutput, Cons } @Override - public Enumeration getResources(String name) throws IOException { + public Enumeration getResources(String nm) throws IOException { + String name; + if(nm.startsWith("/")) { + name = nm.substring(1); + } else { + name = nm; + } + // TODO some superugly hack for bean provider byte[] data = resources.get(name); if (data != null) { @@ -77,6 +84,28 @@ public class RuntimeClassLoader extends ClassLoader implements ClassOutput, Cons return super.getResources(name); } + @Override + public URL getResource(String nm) { + String name; + if(nm.startsWith("/")) { + name = nm.substring(1); + } else { + name = nm; + } + return super.getResource(name); + } + + @Override + public InputStream getResourceAsStream(String nm) { + String name; + if(nm.startsWith("/")) { + name = nm.substring(1); + } else { + name = nm; + } + return super.getResourceAsStream(name); + } + @Override protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { Class ex = findLoadedClass(name); diff --git a/examples/jpa-strict/src/main/resources/META-INF/persistence.xml b/examples/jpa-strict/src/main/resources/META-INF/persistence.xml index 7ba2efca3..46d838c1f 100644 --- a/examples/jpa-strict/src/main/resources/META-INF/persistence.xml +++ b/examples/jpa-strict/src/main/resources/META-INF/persistence.xml @@ -4,7 +4,7 @@ http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd" version="2.1"> - + Hibernate test case template Persistence Unit diff --git a/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/JPATestEMInjectionEndpoint.java b/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/JPATestEMInjectionEndpoint.java new file mode 100644 index 000000000..61f702ff7 --- /dev/null +++ b/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/JPATestEMInjectionEndpoint.java @@ -0,0 +1,104 @@ +package org.jboss.shamrock.example.jpa; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.List; +import java.util.UUID; + +import javax.inject.Inject; +import javax.persistence.EntityManager; +import javax.persistence.EntityTransaction; +import javax.persistence.TypedQuery; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.transaction.UserTransaction; + +/** + * Various tests for the JPA integration. + */ +@WebServlet(urlPatterns = "/jpa/testjpaeminjection") +public class JPATestEMInjectionEndpoint extends HttpServlet { + + @Inject + private EntityManager em; + + @Inject + private UserTransaction transaction; + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + try { + testStoreLoadOnJPA(); + } catch (Exception e) { + reportException("Oops, shit happened, No boot for you!", e, resp); + } + resp.getWriter().write("OK"); + } + + + public void testStoreLoadOnJPA() throws Exception { + doStuffWithHibernate(); + System.out.println("Hibernate EntityManagerFactory: shut down"); + + } + + private void doStuffWithHibernate() throws Exception { + transaction.begin(); + + persistNewPerson(em); + + listExistingPersons(em); + + transaction.commit(); + } + + private static void listExistingPersons(EntityManager em) { + CriteriaBuilder cb = em.getCriteriaBuilder(); + + CriteriaQuery cq = cb.createQuery(Person.class); + Root from = cq.from(Person.class); + cq.select(from); + TypedQuery q = em.createQuery(cq); + List allpersons = q.getResultList(); + StringBuilder sb = new StringBuilder("list of stored Person names:\n\t"); + for (Person p : allpersons) { + p.describeFully(sb); + sb.append("\n\t"); + } + sb.append("\nList complete.\n"); + System.out.print(sb); + } + + private static void persistNewPerson(EntityManager entityManager) { + Person person = new Person(); + person.setName(randomName()); + person.setAddress(new SequencedAddress("Street " + randomName())); + entityManager.persist(person); + } + + private static String randomName() { + return UUID.randomUUID().toString(); + } + + private void reportException(final Exception e, final HttpServletResponse resp) throws IOException { + reportException(null, e, resp); + } + + private void reportException(String errorMessage, final Exception e, final HttpServletResponse resp) throws IOException { + final PrintWriter writer = resp.getWriter(); + if (errorMessage != null) { + writer.write(errorMessage); + writer.write(" "); + } + writer.write(e.toString()); + writer.append("\n\t"); + e.printStackTrace(writer); + writer.append("\n\t"); + } + +} diff --git a/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/JpaProducer.java b/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/JpaProducer.java index 9efa56f0d..916e6677f 100644 --- a/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/JpaProducer.java +++ b/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/JpaProducer.java @@ -1,6 +1,7 @@ package org.jboss.shamrock.example.jpa; import javax.enterprise.inject.Produces; +import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.PersistenceContext; import javax.persistence.PersistenceUnit; @@ -10,4 +11,8 @@ public class JpaProducer { @Produces @PersistenceUnit(unitName = "templatePU") EntityManagerFactory emf; + + @Produces + @PersistenceContext(unitName = "templatePU") + EntityManager em; } diff --git a/examples/strict/src/main/resources/META-INF/persistence.xml b/examples/strict/src/main/resources/META-INF/persistence.xml index 65979b5b2..ef7dd949d 100644 --- a/examples/strict/src/main/resources/META-INF/persistence.xml +++ b/examples/strict/src/main/resources/META-INF/persistence.xml @@ -4,7 +4,7 @@ http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd" version="2.1"> - + Hibernate test case template Persistence Unit diff --git a/examples/strict/src/test/java/org/jboss/shamrock/example/test/JPAEntityManagerInjectionTestCase.java b/examples/strict/src/test/java/org/jboss/shamrock/example/test/JPAEntityManagerInjectionTestCase.java new file mode 100644 index 000000000..28dc1bfda --- /dev/null +++ b/examples/strict/src/test/java/org/jboss/shamrock/example/test/JPAEntityManagerInjectionTestCase.java @@ -0,0 +1,23 @@ +package org.jboss.shamrock.example.test; + +import static org.junit.Assert.assertEquals; + +import org.jboss.shamrock.example.testutils.URLTester; +import org.jboss.shamrock.junit.ShamrockTest; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Test reflection around JPA entities + * + * @author Emmanuel Bernard emmanuel@hibernate.org + */ +@RunWith(ShamrockTest.class) +public class JPAEntityManagerInjectionTestCase { + + @Test + public void testJpaEntityManagerInjection() throws Exception { + assertEquals("OK", URLTester.relative("jpa/testjpaeminjection").invokeURL().asString()); + } + +} diff --git a/ext/gizmo/src/main/java/org/jboss/protean/gizmo/AnnotatedElement.java b/ext/gizmo/src/main/java/org/jboss/protean/gizmo/AnnotatedElement.java index 02abf6fa6..a501a71c2 100644 --- a/ext/gizmo/src/main/java/org/jboss/protean/gizmo/AnnotatedElement.java +++ b/ext/gizmo/src/main/java/org/jboss/protean/gizmo/AnnotatedElement.java @@ -7,7 +7,9 @@ public interface AnnotatedElement { AnnotationCreator addAnnotation(String annotationType); - AnnotationCreator addAnnotation(Class annotationType); + default AnnotationCreator addAnnotation(Class annotationType) { + return addAnnotation(annotationType.getName()); + } default void addAnnotation(AnnotationInstance annotation) { AnnotationCreator ac = addAnnotation(annotation.name().toString()); diff --git a/ext/gizmo/src/main/java/org/jboss/protean/gizmo/ClassCreator.java b/ext/gizmo/src/main/java/org/jboss/protean/gizmo/ClassCreator.java index 567c2f7f1..1cb3fa816 100644 --- a/ext/gizmo/src/main/java/org/jboss/protean/gizmo/ClassCreator.java +++ b/ext/gizmo/src/main/java/org/jboss/protean/gizmo/ClassCreator.java @@ -150,11 +150,6 @@ public class ClassCreator implements AutoCloseable, AnnotatedElement { return ac; } - @Override - public AnnotationCreator addAnnotation(Class annotationType) { - return addAnnotation(annotationType.getName()); - } - public static class Builder { private ClassOutput classOutput; diff --git a/ext/gizmo/src/main/java/org/jboss/protean/gizmo/FieldCreator.java b/ext/gizmo/src/main/java/org/jboss/protean/gizmo/FieldCreator.java index 6201d646f..f26fc5bf8 100644 --- a/ext/gizmo/src/main/java/org/jboss/protean/gizmo/FieldCreator.java +++ b/ext/gizmo/src/main/java/org/jboss/protean/gizmo/FieldCreator.java @@ -1,7 +1,7 @@ package org.jboss.protean.gizmo; -public interface FieldCreator extends MemberCreator { +public interface FieldCreator extends MemberCreator,AnnotatedElement { FieldDescriptor getFieldDescriptor(); diff --git a/ext/gizmo/src/main/java/org/jboss/protean/gizmo/FieldCreatorImpl.java b/ext/gizmo/src/main/java/org/jboss/protean/gizmo/FieldCreatorImpl.java index 7a31e5ed1..1594a366e 100644 --- a/ext/gizmo/src/main/java/org/jboss/protean/gizmo/FieldCreatorImpl.java +++ b/ext/gizmo/src/main/java/org/jboss/protean/gizmo/FieldCreatorImpl.java @@ -1,11 +1,18 @@ package org.jboss.protean.gizmo; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.Opcodes; class FieldCreatorImpl implements FieldCreator { private final FieldDescriptor fieldDescriptor; + private final List annotations = new ArrayList<>(); private int modifiers; @@ -32,7 +39,21 @@ class FieldCreatorImpl implements FieldCreator { @Override public void write(ClassWriter file) { - file.visitField(modifiers, fieldDescriptor.getName(), fieldDescriptor.getType(), null, null); + FieldVisitor fieldVisitor = file.visitField(modifiers, fieldDescriptor.getName(), fieldDescriptor.getType(), null, null); + for(AnnotationCreatorImpl annotation : annotations) { + AnnotationVisitor av = fieldVisitor.visitAnnotation(DescriptorUtils.extToInt(annotation.getAnnotationType()), true); + for(Map.Entry e : annotation.getValues().entrySet()) { + av.visit(e.getKey(), e.getValue()); + } + av.visitEnd(); + } + fieldVisitor.visitEnd(); } + @Override + public AnnotationCreator addAnnotation(String annotationType) { + AnnotationCreatorImpl ac = new AnnotationCreatorImpl(annotationType); + annotations.add(ac); + return ac; + } } diff --git a/ext/gizmo/src/main/java/org/jboss/protean/gizmo/MethodCreator.java b/ext/gizmo/src/main/java/org/jboss/protean/gizmo/MethodCreator.java index 239895203..1025e23f4 100644 --- a/ext/gizmo/src/main/java/org/jboss/protean/gizmo/MethodCreator.java +++ b/ext/gizmo/src/main/java/org/jboss/protean/gizmo/MethodCreator.java @@ -39,4 +39,6 @@ public interface MethodCreator extends MemberCreator, BytecodeCre */ MethodDescriptor getMethodDescriptor(); + AnnotatedElement getParameterAnnotations(int param); + } diff --git a/ext/gizmo/src/main/java/org/jboss/protean/gizmo/MethodCreatorImpl.java b/ext/gizmo/src/main/java/org/jboss/protean/gizmo/MethodCreatorImpl.java index a6cb136cf..19f412cd5 100644 --- a/ext/gizmo/src/main/java/org/jboss/protean/gizmo/MethodCreatorImpl.java +++ b/ext/gizmo/src/main/java/org/jboss/protean/gizmo/MethodCreatorImpl.java @@ -3,9 +3,9 @@ package org.jboss.protean.gizmo; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.ClassWriter; @@ -17,6 +17,7 @@ class MethodCreatorImpl extends BytecodeCreatorImpl implements MethodCreator { private int modifiers = Opcodes.ACC_PUBLIC; private final List exceptions = new ArrayList<>(); private final List annotations = new ArrayList<>(); + private final Map parameterAnnotations = new HashMap<>(); MethodCreatorImpl(MethodDescriptor methodDescriptor, String declaringClassName, ClassOutput classOutput, ClassCreator classCreator) { super(methodDescriptor, declaringClassName, classOutput, classCreator); @@ -38,6 +39,16 @@ class MethodCreatorImpl extends BytecodeCreatorImpl implements MethodCreator { return methodDescriptor; } + @Override + public AnnotatedElement getParameterAnnotations(int param) { + if(parameterAnnotations.containsKey(param)) { + return parameterAnnotations.get(param); + } + AnnotationParameters p = new AnnotationParameters(); + parameterAnnotations.put(param, p); + return p; + } + @Override public int getModifiers() { return modifiers; @@ -53,6 +64,8 @@ class MethodCreatorImpl extends BytecodeCreatorImpl implements MethodCreator { public void write(ClassWriter file) { MethodVisitor visitor = file.visitMethod(modifiers, methodDescriptor.getName(), methodDescriptor.getDescriptor(), null, exceptions.toArray(new String[0])); + + int localVarCount = Modifier.isStatic(modifiers) ? 0 : 1; for (int i = 0; i < methodDescriptor.getParameterTypes().length; ++i) { String s = methodDescriptor.getParameterTypes()[i]; @@ -73,6 +86,15 @@ class MethodCreatorImpl extends BytecodeCreatorImpl implements MethodCreator { } av.visitEnd(); } + for(Map.Entry entry : parameterAnnotations.entrySet()) { + for(AnnotationCreatorImpl annotation : entry.getValue().annotations) { + AnnotationVisitor av = visitor.visitParameterAnnotation(entry.getKey(), DescriptorUtils.extToInt(annotation.getAnnotationType()), true); + for(Map.Entry e : annotation.getValues().entrySet()) { + av.visit(e.getKey(), e.getValue()); + } + av.visitEnd(); + } + } visitor.visitEnd(); } @@ -88,8 +110,17 @@ class MethodCreatorImpl extends BytecodeCreatorImpl implements MethodCreator { return ac; } - @Override - public AnnotationCreator addAnnotation(Class annotationType) { - return addAnnotation(annotationType.getName()); + + private static class AnnotationParameters implements AnnotatedElement { + + final List annotations = new ArrayList<>(); + + @Override + public AnnotationCreator addAnnotation(String annotationType) { + AnnotationCreatorImpl ret = new AnnotationCreatorImpl(annotationType); + annotations.add(ret); + return ret; + } } + } diff --git a/ext/hibernate-protean/hibernate-orm-protean-example/pom.xml b/ext/hibernate-protean/hibernate-orm-protean-example/pom.xml index 8f866fd4b..950243b24 100644 --- a/ext/hibernate-protean/hibernate-orm-protean-example/pom.xml +++ b/ext/hibernate-protean/hibernate-orm-protean-example/pom.xml @@ -10,6 +10,7 @@ 4.0.0 hibernate-orm-protean-example + 1.0.0-SNAPSHOT diff --git a/ext/hibernate-protean/hibernate-orm-protean/pom.xml b/ext/hibernate-protean/hibernate-orm-protean/pom.xml index be8f14c69..6f0c9151a 100644 --- a/ext/hibernate-protean/hibernate-orm-protean/pom.xml +++ b/ext/hibernate-protean/hibernate-orm-protean/pom.xml @@ -10,6 +10,7 @@ 4.0.0 hibernate-orm-protean + 1.0.0-SNAPSHOT diff --git a/ext/hibernate-protean/hibernate-orm-protean/src/main/java/org/hibernate/protean/impl/FastBootMetadataBuilder.java b/ext/hibernate-protean/hibernate-orm-protean/src/main/java/org/hibernate/protean/impl/FastBootMetadataBuilder.java index daff9936a..cc0588966 100644 --- a/ext/hibernate-protean/hibernate-orm-protean/src/main/java/org/hibernate/protean/impl/FastBootMetadataBuilder.java +++ b/ext/hibernate-protean/hibernate-orm-protean/src/main/java/org/hibernate/protean/impl/FastBootMetadataBuilder.java @@ -31,6 +31,7 @@ import org.hibernate.cfg.Environment; import org.hibernate.cfg.beanvalidation.BeanValidationIntegrator; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.dialect.spi.DialectFactory; +import org.hibernate.engine.transaction.jta.platform.internal.JBossStandAloneJtaPlatform; import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform; import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatformResolver; import org.hibernate.id.factory.spi.MutableIdentifierGeneratorFactory; @@ -268,8 +269,9 @@ class FastBootMetadataBuilder { } private JtaPlatform extractJtaPlatform() { - JtaPlatformResolver service = standardServiceRegistry.getService( JtaPlatformResolver.class ); - return service.resolveJtaPlatform( this.configurationValues, (ServiceRegistryImplementor) standardServiceRegistry ); + return new JBossStandAloneJtaPlatform(); +// JtaPlatformResolver service = standardServiceRegistry.getService( JtaPlatformResolver.class ); +// return service.resolveJtaPlatform( this.configurationValues, (ServiceRegistryImplementor) standardServiceRegistry ); } private Dialect extractDialect() { @@ -416,9 +418,11 @@ class FastBootMetadataBuilder { else { if ( txnType == PersistenceUnitTransactionType.JTA ) { ssrBuilder.applySetting( TRANSACTION_COORDINATOR_STRATEGY, JtaTransactionCoordinatorBuilderImpl.class ); + configurationValues.put(TRANSACTION_COORDINATOR_STRATEGY, JtaTransactionCoordinatorBuilderImpl.class); } else if ( txnType == PersistenceUnitTransactionType.RESOURCE_LOCAL ) { ssrBuilder.applySetting( TRANSACTION_COORDINATOR_STRATEGY, JdbcResourceLocalTransactionCoordinatorBuilderImpl.class ); + configurationValues.put(TRANSACTION_COORDINATOR_STRATEGY, JdbcResourceLocalTransactionCoordinatorBuilderImpl.class); } } } diff --git a/ext/hibernate-protean/hibernate-orm-protean/src/main/java/org/hibernate/protean/impl/FlatClassLoaderService.java b/ext/hibernate-protean/hibernate-orm-protean/src/main/java/org/hibernate/protean/impl/FlatClassLoaderService.java index 35ef23bf3..e2a1ea7ec 100644 --- a/ext/hibernate-protean/hibernate-orm-protean/src/main/java/org/hibernate/protean/impl/FlatClassLoaderService.java +++ b/ext/hibernate-protean/hibernate-orm-protean/src/main/java/org/hibernate/protean/impl/FlatClassLoaderService.java @@ -1,10 +1,13 @@ package org.hibernate.protean.impl; +import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationHandler; import java.net.URL; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Enumeration; import java.util.LinkedHashSet; import java.util.List; import java.util.ServiceLoader; @@ -29,7 +32,7 @@ public class FlatClassLoaderService implements ClassLoaderService { @Override public Class classForName(String className) { try { - return (Class) Class.forName( className, false, Thread.currentThread().getContextClassLoader() ); + return (Class) Class.forName( className, false, getClassLoader() ); } catch (ClassNotFoundException e) { log.errorf( "Could not load class '%s' using Class.forName(String)", className ); @@ -39,7 +42,7 @@ public class FlatClassLoaderService implements ClassLoaderService { @Override public URL locateResource(String name) { - URL resource = FlatClassLoaderService.class.getResource( name ); + URL resource = getClassLoader().getResource( name ); if ( resource == null ) { log.warnf( "Loading of resource '%s' failed. Maybe that's ok, maybe you forgot to include this resource in the binary image? -H:IncludeResources=", name ); } @@ -51,7 +54,7 @@ public class FlatClassLoaderService implements ClassLoaderService { @Override public InputStream locateResourceStream(String name) { - InputStream resourceAsStream = FlatClassLoaderService.class.getResourceAsStream( name ); + InputStream resourceAsStream = getClassLoader().getResourceAsStream( name ); if ( resourceAsStream == null ) { log.warnf( "Loading of resource '%s' failed. Maybe that's ok, maybe you forgot to include this resource in the binary image? -H:IncludeResources=", name ); } @@ -64,12 +67,21 @@ public class FlatClassLoaderService implements ClassLoaderService { @Override public List locateResources(String name) { log.debugf( "locateResources (plural form) was invoked for resource '%s'. Is there a real need for this plural form?", name ); - return Collections.singletonList( locateResource( name ) ); + try { + Enumeration resources = getClassLoader().getResources(name); + List resource = new ArrayList<>(); + while (resources.hasMoreElements()) { + resource.add(resources.nextElement()); + } + return resource; + } catch (IOException e) { + throw new RuntimeException(e); + } } @Override public Collection loadJavaServices(Class serviceContract) { - ServiceLoader serviceLoader = ServiceLoader.load( serviceContract ); + ServiceLoader serviceLoader = ServiceLoader.load( serviceContract , getClassLoader()); final LinkedHashSet services = new LinkedHashSet(); for ( S service : serviceLoader ) { services.add( service ); @@ -85,7 +97,7 @@ public class FlatClassLoaderService implements ClassLoaderService { @Override public T workWithClassLoader(Work work) { - ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); + ClassLoader systemClassLoader = getClassLoader(); return work.doWork( systemClassLoader ); } @@ -94,4 +106,12 @@ public class FlatClassLoaderService implements ClassLoaderService { //easy! } + private ClassLoader getClassLoader() { + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + if(cl == null) { + return FlatClassLoaderService.class.getClassLoader(); + } + return cl; + } + } diff --git a/ext/hibernate-protean/hibernate-orm-protean/src/main/java/org/hibernate/protean/impl/serviceregistry/PreconfiguredServiceRegistryBuilder.java b/ext/hibernate-protean/hibernate-orm-protean/src/main/java/org/hibernate/protean/impl/serviceregistry/PreconfiguredServiceRegistryBuilder.java index b7866d75a..45996fa33 100644 --- a/ext/hibernate-protean/hibernate-orm-protean/src/main/java/org/hibernate/protean/impl/serviceregistry/PreconfiguredServiceRegistryBuilder.java +++ b/ext/hibernate-protean/hibernate-orm-protean/src/main/java/org/hibernate/protean/impl/serviceregistry/PreconfiguredServiceRegistryBuilder.java @@ -19,8 +19,10 @@ import org.hibernate.engine.jdbc.connections.internal.MultiTenantConnectionProvi import org.hibernate.engine.jdbc.cursor.internal.RefCursorSupportInitiator; import org.hibernate.engine.jdbc.internal.JdbcServicesInitiator; import org.hibernate.engine.jndi.internal.JndiServiceInitiator; +import org.hibernate.engine.transaction.jta.platform.internal.JBossStandAloneJtaPlatform; import org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator; import org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformResolverInitiator; +import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform; import org.hibernate.hql.internal.QueryTranslatorFactoryInitiator; import org.hibernate.id.factory.internal.MutableIdentifierGeneratorFactoryInitiator; import org.hibernate.integrator.spi.Integrator; @@ -39,6 +41,7 @@ import org.hibernate.resource.transaction.internal.TransactionCoordinatorBuilder import org.hibernate.service.Service; import org.hibernate.service.internal.ProvidedService; import org.hibernate.service.internal.SessionFactoryServiceRegistryFactoryInitiator; +import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.tool.hbm2ddl.ImportSqlCommandExtractorInitiator; import org.hibernate.tool.schema.internal.SchemaManagementToolInitiator; @@ -182,6 +185,12 @@ public class PreconfiguredServiceRegistryBuilder { //Replaces JtaPlatformResolverInitiator.INSTANCE ); serviceInitiators.add( new ProteanJtaPlatformResolver( rs.getJtaPlatform() ) ); + serviceInitiators.add(new JtaPlatformInitiator() { + @Override + protected JtaPlatform getFallbackProvider(Map configurationValues, ServiceRegistryImplementor registry) { + return new JBossStandAloneJtaPlatform(); + } + }); //Disabled: //serviceInitiators.add( JtaPlatformInitiator.INSTANCE ); diff --git a/ext/hibernate-protean/pom.xml b/ext/hibernate-protean/pom.xml index 779981dd4..0c595e707 100644 --- a/ext/hibernate-protean/pom.xml +++ b/ext/hibernate-protean/pom.xml @@ -91,6 +91,20 @@ + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar-no-fork + + + + + diff --git a/jpa/deployment/src/main/java/org/jboss/shamrock/jpa/HibernateEntityEnhancer.java b/jpa/deployment/src/main/java/org/jboss/shamrock/jpa/HibernateEntityEnhancer.java index b8f0daf17..09b60baf3 100644 --- a/jpa/deployment/src/main/java/org/jboss/shamrock/jpa/HibernateEntityEnhancer.java +++ b/jpa/deployment/src/main/java/org/jboss/shamrock/jpa/HibernateEntityEnhancer.java @@ -27,7 +27,13 @@ public final class HibernateEntityEnhancer implements Function knownUnitNames = new HashSet<>(); Set knownContextNames = new HashSet<>(); scanForAnnotations(archiveContext, knownUnitNames, PERSISTENCE_UNIT); @@ -45,25 +63,26 @@ public class HibernateCdiResourceProcessor implements ResourceProcessor { knownUnitNames.remove(""); //TODO: support for the default PU //now create producer beans for all of the above unit names //this is not great, we really need a better way to do this than generating bytecode - for (String name : knownUnitNames) { + + + Set allKnownNames = new HashSet<>(knownUnitNames); + allKnownNames.addAll(knownContextNames); + + for (String name : allKnownNames) { String className = getClass().getName() + "$$EMFProducer-" + name; AtomicReference bytes = new AtomicReference<>(); - try (ClassCreator creator = new ClassCreator(new ClassOutput() { - @Override - public void write(String name, byte[] data) { - try { - bytes.set(data); - processorContext.addGeneratedClass(true, name, data); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - }, className, null, Object.class.getName())) { + try (ClassCreator creator = new ClassCreator(new InMemoryClassOutput(bytes, processorContext), className, null, Object.class.getName())) { creator.addAnnotation(Dependent.class); MethodCreator producer = creator.getMethodCreator("producerMethod", EntityManagerFactory.class); producer.addAnnotation(Produces.class); producer.addAnnotation(ApplicationScoped.class); + if (!knownUnitNames.contains(name)) { + //there was no @PersistenceUnit producer with this name + //this means that we still need it, but the user would not be expecting a bean to be registered + //we register an artificial qualifier that we will use for the managed persistence contexts + producer.addAnnotation(SystemEntityManager.class); + } ResultHandle ret = producer.invokeStaticMethod(MethodDescriptor.ofMethod(Persistence.class, "createEntityManagerFactory", EntityManagerFactory.class, String.class), producer.load(name)); producer.returnValue(ret); @@ -72,25 +91,117 @@ public class HibernateCdiResourceProcessor implements ResourceProcessor { } + try(BytecodeRecorder recorder = processorContext.addDeploymentTask(RuntimePriority.BOOTSTRAP_EMF)) { + JPADeploymentTemplate template = recorder.getRecordingProxy(JPADeploymentTemplate.class); + + for (String name : knownContextNames) { + String className = getClass().getName() + "$$EMProducer-" + name; + AtomicReference bytes = new AtomicReference<>(); + + //we need to know if transactions are present or not + //TODO: this should be based on if a PU is JTA enabled or not + if (processorContext.isCapabilityPresent("transactions")) { + boolean system = false; + try (ClassCreator creator = new ClassCreator(new InMemoryClassOutput(bytes, processorContext), className, null, Object.class.getName())) { + + creator.addAnnotation(Dependent.class); + + FieldCreator emfField = creator.getFieldCreator("emf", EntityManagerFactory.class); + emfField.addAnnotation(Inject.class); + if (!knownUnitNames.contains(name)) { + emfField.addAnnotation(SystemEntityManager.class); + system = true; + } + FieldDescriptor emf = emfField.getFieldDescriptor(); + + + FieldCreator tsrField = creator.getFieldCreator("tsr", TransactionSynchronizationRegistry.class); + tsrField.addAnnotation(Inject.class); + FieldDescriptor tsr = tsrField.getFieldDescriptor(); + + + FieldCreator tmField = creator.getFieldCreator("tm", TransactionManager.class); + tmField.addAnnotation(Inject.class); + FieldDescriptor tm = tmField.getFieldDescriptor(); + + MethodCreator producer = creator.getMethodCreator("producerMethod", EntityManager.class); + producer.addAnnotation(Produces.class); + producer.addAnnotation(RequestScoped.class); + + ResultHandle emfRh = producer.readInstanceField(emf, producer.getThis()); + ResultHandle tsrRh = producer.readInstanceField(tsr, producer.getThis()); + ResultHandle tmRh = producer.readInstanceField(tm, producer.getThis()); + + producer.returnValue(producer.newInstance(MethodDescriptor.ofConstructor(TransactionScopedEntityManager.class, TransactionManager.class, TransactionSynchronizationRegistry.class, EntityManagerFactory.class), tmRh, tsrRh, emfRh)); + + + MethodCreator disposer = creator.getMethodCreator("disposerMethod", void.class, EntityManager.class); + disposer.getParameterAnnotations(0).addAnnotation(Disposes.class); + disposer.invokeVirtualMethod(MethodDescriptor.ofMethod(TransactionScopedEntityManager.class, "requestDone", void.class), disposer.getMethodParam(0)); + disposer.returnValue(null); + + } + beanDeployment.addGeneratedBean(className, bytes.get()); + template.boostrapPu(null, system); + } else { + boolean system = false; + //if there is no TX support then we just use a super simple approach, and produce a normal EM + try (ClassCreator creator = new ClassCreator(new InMemoryClassOutput(bytes, processorContext), className, null, Object.class.getName())) { + + creator.addAnnotation(Dependent.class); + + FieldCreator emfField = creator.getFieldCreator("emf", EntityManagerFactory.class); + emfField.addAnnotation(Inject.class); + if (!knownUnitNames.contains(name)) { + emfField.addAnnotation(SystemEntityManager.class); + system = true; + } + FieldDescriptor emf = emfField.getFieldDescriptor(); + + + MethodCreator producer = creator.getMethodCreator("producerMethod", EntityManager.class); + producer.addAnnotation(Produces.class); + producer.addAnnotation(Dependent.class); + + ResultHandle factory = producer.readInstanceField(emf, producer.getThis()); + producer.returnValue(producer.invokeInterfaceMethod(MethodDescriptor.ofMethod(EntityManagerFactory.class, "createEntityManager", EntityManager.class), factory)); + + + MethodCreator disposer = creator.getMethodCreator("disposerMethod", void.class, EntityManager.class); + disposer.getParameterAnnotations(0).addAnnotation(Disposes.class); + disposer.invokeInterfaceMethod(MethodDescriptor.ofMethod(EntityManager.class, "close", void.class), disposer.getMethodParam(0)); + disposer.returnValue(null); + + } + beanDeployment.addGeneratedBean(className, bytes.get()); + template.boostrapPu(null, system); + } + } + } + } private void scanForAnnotations(ArchiveContext archiveContext, Set knownUnitNames, DotName nm) { for (AnnotationInstance anno : archiveContext.getCombinedIndex().getAnnotations(nm)) { + AnnotationValue unitName = anno.value("unitName"); + if(unitName == null) { + continue; + } if (anno.target().kind() == AnnotationTarget.Kind.METHOD) { if (anno.target().asMethod().hasAnnotation(PRODUCES)) { - knownUnitNames.add(anno.value("unitName").asString()); + knownUnitNames.add(unitName.asString()); } } else if (anno.target().kind() == AnnotationTarget.Kind.FIELD) { for (AnnotationInstance i : anno.target().asField().annotations()) { if (i.name().equals(PRODUCES)) { - knownUnitNames.add(anno.value("unitName").asString()); + knownUnitNames.add(unitName.asString()); break; } } } else if (anno.target().kind() == AnnotationTarget.Kind.CLASS) { for (AnnotationInstance i : anno.target().asClass().classAnnotations()) { if (i.name().equals(PRODUCES)) { - knownUnitNames.add(anno.value("unitName").asString()); + knownUnitNames.add(unitName.asString()); break; } } @@ -100,6 +211,26 @@ public class HibernateCdiResourceProcessor implements ResourceProcessor { @Override public int getPriority() { - return 0; + return 100; + } + + private static class InMemoryClassOutput implements ClassOutput { + private final AtomicReference bytes; + private final ProcessorContext processorContext; + + public InMemoryClassOutput(AtomicReference bytes, ProcessorContext processorContext) { + this.bytes = bytes; + this.processorContext = processorContext; + } + + @Override + public void write(String name, byte[] data) { + try { + bytes.set(data); + processorContext.addGeneratedClass(true, name, data); + } catch (IOException e) { + throw new RuntimeException(e); + } + } } } diff --git a/jpa/deployment/src/test/java/org/jboss/shamrock/jpa/HqlNodeScannerTestCase.java b/jpa/deployment/src/test/java/org/jboss/shamrock/jpa/HqlNodeScannerTestCase.java new file mode 100644 index 000000000..6efddcb4a --- /dev/null +++ b/jpa/deployment/src/test/java/org/jboss/shamrock/jpa/HqlNodeScannerTestCase.java @@ -0,0 +1,42 @@ +package org.jboss.shamrock.jpa; + +import java.io.FileInputStream; +import java.net.URL; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import org.hibernate.hql.internal.ast.tree.Node; +import org.jboss.jandex.ClassInfo; +import org.jboss.jandex.DotName; +import org.jboss.jandex.Index; +import org.jboss.jandex.Indexer; +import org.junit.Ignore; +import org.junit.Test; + +//not a real test, but you can use to to +//get all not implementation that need to be added for reflection +@Ignore +public class HqlNodeScannerTestCase { + + @Test + public void generateAllNodes() throws Exception { + URL url = Node.class.getResource("Node.class"); + String jar = url.getPath().substring(5, url.getPath().lastIndexOf("!")); + System.out.println(jar); + Indexer indexer = new Indexer(); + try (ZipInputStream in = new ZipInputStream(new FileInputStream(jar))) { + ZipEntry e = in.getNextEntry(); + while (e != null) { + if (e.getName().endsWith(".class")) { + indexer.index(in); + } + e = in.getNextEntry(); + } + } + Index index = indexer.complete(); + for (ClassInfo i : index.getAllKnownSubclasses(DotName.createSimple(Node.class.getName()))) { + System.out.println("simpleConstructor(" + i.name() + ".class);"); + } + } + +} diff --git a/jpa/runtime/src/main/java/org/jboss/shamrock/jpa/JPADeploymentTemplate.java b/jpa/runtime/src/main/java/org/jboss/shamrock/jpa/JPADeploymentTemplate.java deleted file mode 100644 index ca33c6979..000000000 --- a/jpa/runtime/src/main/java/org/jboss/shamrock/jpa/JPADeploymentTemplate.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.jboss.shamrock.jpa; - -import org.hibernate.protean.Hibernate; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author Emmanuel Bernard emmanuel@hibernate.org - */ -public class JPADeploymentTemplate { - private List entities = new ArrayList<>(); - - public void addEntity(String entityClass) { - entities.add(entityClass); - } - - public void enlistPersistenceUnit() { - System.out.println("List of entities found by Shamrock deployment \n" + entities.toString()); - } - - public void callHibernateFeatureInit() { - Hibernate.featureInit(); - } -} diff --git a/jpa/runtime/src/main/java/org/jboss/shamrock/jpa/runtime/JPADeploymentTemplate.java b/jpa/runtime/src/main/java/org/jboss/shamrock/jpa/runtime/JPADeploymentTemplate.java new file mode 100644 index 000000000..f57fbcfe9 --- /dev/null +++ b/jpa/runtime/src/main/java/org/jboss/shamrock/jpa/runtime/JPADeploymentTemplate.java @@ -0,0 +1,48 @@ +package org.jboss.shamrock.jpa.runtime; + +import org.hibernate.protean.Hibernate; +import org.jboss.shamrock.jpa.runtime.cdi.SystemEntityManager; +import org.jboss.shamrock.runtime.BeanContainer; +import org.jboss.shamrock.runtime.ContextObject; + +import java.lang.annotation.Annotation; +import java.util.ArrayList; +import java.util.List; + +import javax.enterprise.util.AnnotationLiteral; +import javax.persistence.EntityManagerFactory; + +/** + * @author Emmanuel Bernard emmanuel@hibernate.org + */ +public class JPADeploymentTemplate { + private List entities = new ArrayList<>(); + + public void addEntity(String entityClass) { + entities.add(entityClass); + } + + public void enlistPersistenceUnit() { + System.out.println("List of entities found by Shamrock deployment \n" + entities.toString()); + } + + public void callHibernateFeatureInit() { + Hibernate.featureInit(); + } + + public void boostrapPu(@ContextObject("bean.container") BeanContainer beanContainer, boolean synthetic) { + //TODO: we need to take qualifiers into account, at the moment we can only have one EM, but this is probably fine for the PoC + if(synthetic) { + beanContainer.instance(EntityManagerFactory.class, new AnnotationLiteral() { + + @Override + public Class annotationType() { + return SystemEntityManager.class; + } + }).getProperties(); + } else { + beanContainer.instance(EntityManagerFactory.class).getProperties(); + } + } + +} diff --git a/jpa/runtime/src/main/java/org/jboss/shamrock/jpa/runtime/cdi/SystemEntityManager.java b/jpa/runtime/src/main/java/org/jboss/shamrock/jpa/runtime/cdi/SystemEntityManager.java new file mode 100644 index 000000000..bc523771d --- /dev/null +++ b/jpa/runtime/src/main/java/org/jboss/shamrock/jpa/runtime/cdi/SystemEntityManager.java @@ -0,0 +1,11 @@ +package org.jboss.shamrock.jpa.runtime.cdi; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import javax.inject.Qualifier; + +@Qualifier +@Retention(RetentionPolicy.RUNTIME) +public @interface SystemEntityManager { +} diff --git a/jpa/runtime/src/main/java/org/jboss/shamrock/jpa/runtime/cdi/TransactionScopedEntityManager.java b/jpa/runtime/src/main/java/org/jboss/shamrock/jpa/runtime/cdi/TransactionScopedEntityManager.java new file mode 100644 index 000000000..e7fed41df --- /dev/null +++ b/jpa/runtime/src/main/java/org/jboss/shamrock/jpa/runtime/cdi/TransactionScopedEntityManager.java @@ -0,0 +1,460 @@ +package org.jboss.shamrock.jpa.runtime.cdi; + +import java.util.List; +import java.util.Map; + +import javax.persistence.EntityGraph; +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.EntityTransaction; +import javax.persistence.FlushModeType; +import javax.persistence.LockModeType; +import javax.persistence.Query; +import javax.persistence.StoredProcedureQuery; +import javax.persistence.TypedQuery; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaDelete; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.CriteriaUpdate; +import javax.persistence.metamodel.Metamodel; +import javax.transaction.Status; +import javax.transaction.Synchronization; +import javax.transaction.TransactionManager; +import javax.transaction.TransactionSynchronizationRegistry; + +public class TransactionScopedEntityManager implements EntityManager { + + private final TransactionManager transactionManager; + private final TransactionSynchronizationRegistry tsr; + private final EntityManagerFactory emf; + private static final Object transactionKey = new Object(); + private EntityManager fallbackEntityManager; + + public TransactionScopedEntityManager(TransactionManager transactionManager, TransactionSynchronizationRegistry tsr, EntityManagerFactory emf) { + this.transactionManager = transactionManager; + this.tsr = tsr; + this.emf = emf; + } + + public void requestDone() { + if(fallbackEntityManager != null) { + fallbackEntityManager.close(); + } + } + + EntityManagerResult getEntityManager() { + if (isInTransaction()) { + EntityManager em = (EntityManager) tsr.getResource(transactionKey); + if (em != null) { + return new EntityManagerResult(em, false); + } + EntityManager newEm = emf.createEntityManager(); + tsr.putResource(transactionKey, newEm); + tsr.registerInterposedSynchronization(new Synchronization() { + @Override + public void beforeCompletion() { + newEm.flush(); + newEm.close(); + } + + @Override + public void afterCompletion(int i) { + + } + }); + return new EntityManagerResult(newEm, false); + } else { + if(fallbackEntityManager == null) { + fallbackEntityManager = emf.createEntityManager(); + } + return new EntityManagerResult(emf.createEntityManager(), false); + } + } + + private boolean isInTransaction() { + try { + switch (transactionManager.getStatus()) { + case Status.STATUS_ACTIVE: + case Status.STATUS_COMMITTING: + case Status.STATUS_MARKED_ROLLBACK: + case Status.STATUS_PREPARED: + case Status.STATUS_PREPARING: + return true; + default: + return false; + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public void persist(Object entity) { + try (EntityManagerResult emr = getEntityManager()) { + emr.em.persist(entity); + } + } + + @Override + public T merge(T entity) { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.merge(entity); + } + } + + @Override + public void remove(Object entity) { + try (EntityManagerResult emr = getEntityManager()) { + emr.em.remove(entity); + } + } + + @Override + public T find(Class entityClass, Object primaryKey) { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.find(entityClass, primaryKey); + } + } + + @Override + public T find(Class entityClass, Object primaryKey, Map properties) { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.find(entityClass, primaryKey, properties); + } + } + + @Override + public T find(Class entityClass, Object primaryKey, LockModeType lockMode) { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.find(entityClass, primaryKey, lockMode); + } + } + + @Override + public T find(Class entityClass, Object primaryKey, LockModeType lockMode, Map properties) { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.find(entityClass, primaryKey, lockMode, properties); + } + } + + @Override + public T getReference(Class entityClass, Object primaryKey) { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.getReference(entityClass, primaryKey); + } + } + + @Override + public void flush() { + try (EntityManagerResult emr = getEntityManager()) { + emr.em.flush(); + } + } + + @Override + public void setFlushMode(FlushModeType flushMode) { + try (EntityManagerResult emr = getEntityManager()) { + emr.em.setFlushMode(flushMode); + } + } + + @Override + public FlushModeType getFlushMode() { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.getFlushMode(); + } + } + + @Override + public void lock(Object entity, LockModeType lockMode) { + try (EntityManagerResult emr = getEntityManager()) { + emr.em.lock(entity, lockMode); + } + } + + @Override + public void lock(Object entity, LockModeType lockMode, Map properties) { + try (EntityManagerResult emr = getEntityManager()) { + emr.em.lock(entity, lockMode, properties); + } + } + + @Override + public void refresh(Object entity) { + try (EntityManagerResult emr = getEntityManager()) { + emr.em.refresh(entity); + } + } + + @Override + public void refresh(Object entity, Map properties) { + try (EntityManagerResult emr = getEntityManager()) { + emr.em.refresh(entity, properties); + } + } + + @Override + public void refresh(Object entity, LockModeType lockMode) { + try (EntityManagerResult emr = getEntityManager()) { + emr.em.refresh(entity, lockMode); + } + } + + @Override + public void refresh(Object entity, LockModeType lockMode, Map properties) { + try (EntityManagerResult emr = getEntityManager()) { + emr.em.refresh(entity, lockMode, properties); + } + } + + @Override + public void clear() { + try (EntityManagerResult emr = getEntityManager()) { + emr.em.clear(); + } + } + + @Override + public void detach(Object entity) { + try (EntityManagerResult emr = getEntityManager()) { + emr.em.detach(entity); + } + } + + @Override + public boolean contains(Object entity) { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.contains(entity); + } + } + + @Override + public LockModeType getLockMode(Object entity) { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.getLockMode(entity); + } + } + + @Override + public void setProperty(String propertyName, Object value) { + try (EntityManagerResult emr = getEntityManager()) { + emr.em.setProperty(propertyName, value); + } + } + + @Override + public Map getProperties() { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.getProperties(); + } + } + + @Override + public Query createQuery(String qlString) { + //TODO: this needs some thought for how it works outside a tx + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.createQuery(qlString); + } + } + + @Override + public TypedQuery createQuery(CriteriaQuery criteriaQuery) { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.createQuery(criteriaQuery); + } + } + + @Override + public Query createQuery(CriteriaUpdate updateQuery) { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.createQuery(updateQuery); + } + } + + @Override + public Query createQuery(CriteriaDelete deleteQuery) { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.createQuery(deleteQuery); + } + } + + @Override + public TypedQuery createQuery(String qlString, Class resultClass) { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.createQuery(qlString, resultClass); + } + } + + @Override + public Query createNamedQuery(String name) { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.createNamedQuery(name); + } + } + + @Override + public TypedQuery createNamedQuery(String name, Class resultClass) { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.createNamedQuery(name, resultClass); + } + } + + @Override + public Query createNativeQuery(String sqlString) { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.createNativeQuery(sqlString); + } + } + + @Override + public Query createNativeQuery(String sqlString, Class resultClass) { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.createNativeQuery(sqlString, resultClass); + } + } + + @Override + public Query createNativeQuery(String sqlString, String resultSetMapping) { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.createNativeQuery(sqlString, resultSetMapping); + } + } + + @Override + public StoredProcedureQuery createNamedStoredProcedureQuery(String name) { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.createNamedStoredProcedureQuery(name); + } + } + + @Override + public StoredProcedureQuery createStoredProcedureQuery(String procedureName) { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.createStoredProcedureQuery(procedureName); + } + } + + @Override + public StoredProcedureQuery createStoredProcedureQuery(String procedureName, Class... resultClasses) { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.createStoredProcedureQuery(procedureName, resultClasses); + } + } + + @Override + public StoredProcedureQuery createStoredProcedureQuery(String procedureName, String... resultSetMappings) { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.createStoredProcedureQuery(procedureName, resultSetMappings); + } + } + + @Override + public void joinTransaction() { + try (EntityManagerResult emr = getEntityManager()) { + emr.em.joinTransaction(); + } + } + + @Override + public boolean isJoinedToTransaction() { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.isJoinedToTransaction(); + } + } + + @Override + public T unwrap(Class cls) { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.unwrap(cls); + } + } + + @Override + public Object getDelegate() { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.getDelegate(); + } + } + + @Override + public void close() { + throw new IllegalStateException("Not supported for transaction scoped entity managers"); + } + + @Override + public boolean isOpen() { + return true; + } + + @Override + public EntityTransaction getTransaction() { + throw new IllegalStateException("Not supported for JTA entity managers"); + } + + @Override + public EntityManagerFactory getEntityManagerFactory() { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.getEntityManagerFactory(); + } + } + + @Override + public CriteriaBuilder getCriteriaBuilder() { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.getCriteriaBuilder(); + } + } + + @Override + public Metamodel getMetamodel() { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.getMetamodel(); + } + } + + @Override + public EntityGraph createEntityGraph(Class rootType) { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.createEntityGraph(rootType); + } + } + + @Override + public EntityGraph createEntityGraph(String graphName) { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.createEntityGraph(graphName); + } + } + + @Override + public EntityGraph getEntityGraph(String graphName) { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.getEntityGraph(graphName); + } + } + + @Override + public List> getEntityGraphs(Class entityClass) { + try (EntityManagerResult emr = getEntityManager()) { + return emr.em.getEntityGraphs(entityClass); + } + } + + static class EntityManagerResult implements AutoCloseable { + + private final EntityManager em; + private final boolean closeOnEnd; + + EntityManagerResult(EntityManager em, boolean closeOnEnd) { + this.em = em; + this.closeOnEnd = closeOnEnd; + } + + @Override + public void close() { + if (closeOnEnd) { + em.close(); + } + } + } +} diff --git a/test-framework/junit/src/main/java/org/jboss/shamrock/junit/ShamrockTest.java b/test-framework/junit/src/main/java/org/jboss/shamrock/junit/ShamrockTest.java index 13e8d4319..06f846b70 100644 --- a/test-framework/junit/src/main/java/org/jboss/shamrock/junit/ShamrockTest.java +++ b/test-framework/junit/src/main/java/org/jboss/shamrock/junit/ShamrockTest.java @@ -17,6 +17,7 @@ public class ShamrockTest extends BlockJUnit4ClassRunner { private static boolean first = true; private static boolean started = false; + private static boolean failed = false; /** * Creates a BlockJUnit4ClassRunner to run {@code klass} @@ -42,19 +43,29 @@ public class ShamrockTest extends BlockJUnit4ClassRunner { try { notifier.addListener(new RunListener() { + @Override public void testStarted(Description description) { + if (failed) { + notifier.fireTestFailure(new Failure(description, new AssertionError("Startup failed"))); + return; + } if (!started) { started = true; //TODO: so much hacks... - Class theClass = description.getTestClass(); - String classFileName = theClass.getName().replace(".", "/") + ".class"; - URL resource = theClass.getClassLoader().getResource(classFileName); - String testClassLocation = resource.getPath().substring(0, resource.getPath().length() - classFileName.length()); - String appClassLocation = testClassLocation.replace("test-classes", "classes"); - Path appRoot = Paths.get(appClassLocation); - RuntimeRunner runtimeRunner = new RuntimeRunner(getClass().getClassLoader(), appRoot, Paths.get(testClassLocation), new ArchiveContextBuilder()); - runtimeRunner.run(); + try { + Class theClass = description.getTestClass(); + String classFileName = theClass.getName().replace(".", "/") + ".class"; + URL resource = theClass.getClassLoader().getResource(classFileName); + String testClassLocation = resource.getPath().substring(0, resource.getPath().length() - classFileName.length()); + String appClassLocation = testClassLocation.replace("test-classes", "classes"); + Path appRoot = Paths.get(appClassLocation); + RuntimeRunner runtimeRunner = new RuntimeRunner(getClass().getClassLoader(), appRoot, Paths.get(testClassLocation), new ArchiveContextBuilder()); + runtimeRunner.run(); + } catch (RuntimeException e) { + failed = true; + throw e; + } } } }); diff --git a/transactions/deployment/src/main/java/org/jboss/shamrock/transactions/TransactionsSetup.java b/transactions/deployment/src/main/java/org/jboss/shamrock/transactions/TransactionsSetup.java index 04a36b8ca..3321c4e36 100644 --- a/transactions/deployment/src/main/java/org/jboss/shamrock/transactions/TransactionsSetup.java +++ b/transactions/deployment/src/main/java/org/jboss/shamrock/transactions/TransactionsSetup.java @@ -6,6 +6,7 @@ import org.jboss.shamrock.deployment.ShamrockSetup; public class TransactionsSetup implements ShamrockSetup { @Override public void setup(SetupContext context) { + context.addCapability("transactions"); context.addResourceProcessor(new TransactionsProcessor()); } }