From 9dbf401e40404da2363f065902682c5cb953d8ff Mon Sep 17 00:00:00 2001 From: Bernard Labno Date: Thu, 5 Jan 2012 16:24:03 +0100 Subject: [PATCH] XA resources example. --- .gitignore | 3 +- examples/xa-playground/pom.xml | 154 ++++++++++++++++++ .../example/xaplayground/CdiJmsBridge.java | 15 ++ .../jms/example/xaplayground/Constants.java | 7 + .../example/xaplayground/GoodlListener.java | 31 ++++ .../example/xaplayground/MeantException.java | 10 ++ .../jms/example/xaplayground/TestView.java | 95 +++++++++++ .../JmsXAConnectionFactoryProducer.java | 35 ++++ .../inject/JmsXASessionProducer.java | 65 ++++++++ .../jms/example/xaplayground/inject/XA.java | 18 ++ .../main/resources/META-INF/seam-beans.xml | 28 ++++ .../src/main/webapp/WEB-INF/beans.xml | 9 + .../src/main/webapp/WEB-INF/faces-config.xml | 6 + .../src/main/webapp/WEB-INF/web.xml | 34 ++++ .../xa-playground/src/main/webapp/index.html | 11 ++ .../src/main/webapp/layout/template.xhtml | 15 ++ .../src/main/webapp/view/home.xhtml | 49 ++++++ 17 files changed, 584 insertions(+), 1 deletion(-) create mode 100644 examples/xa-playground/pom.xml create mode 100644 examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/CdiJmsBridge.java create mode 100644 examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/Constants.java create mode 100644 examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/GoodlListener.java create mode 100644 examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/MeantException.java create mode 100644 examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/TestView.java create mode 100644 examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/inject/JmsXAConnectionFactoryProducer.java create mode 100644 examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/inject/JmsXASessionProducer.java create mode 100644 examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/inject/XA.java create mode 100644 examples/xa-playground/src/main/resources/META-INF/seam-beans.xml create mode 100644 examples/xa-playground/src/main/webapp/WEB-INF/beans.xml create mode 100644 examples/xa-playground/src/main/webapp/WEB-INF/faces-config.xml create mode 100644 examples/xa-playground/src/main/webapp/WEB-INF/web.xml create mode 100644 examples/xa-playground/src/main/webapp/index.html create mode 100644 examples/xa-playground/src/main/webapp/layout/template.xhtml create mode 100644 examples/xa-playground/src/main/webapp/view/home.xhtml diff --git a/.gitignore b/.gitignore index 437ccf2..4e4fa51 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ target *~ transaction.log */bin - +.idea +*.iml diff --git a/examples/xa-playground/pom.xml b/examples/xa-playground/pom.xml new file mode 100644 index 0000000..7e0d506 --- /dev/null +++ b/examples/xa-playground/pom.xml @@ -0,0 +1,154 @@ + + + + 4.0.0 + + org.jboss.seam.jms + seam-jms-parent + 3.1.0.Final + + + + xa-playground + war + + + 7.1.0.Beta1 + UTF-8 + UTF-8 + + + + + + org.jboss.weld + weld-core + 1.1.4.Final + provided + + + + javax.enterprise + cdi-api + 1.0 + provided + + + + org.jboss.solder + solder-api + 3.1.0.Final + + + + org.jboss.seam.international + seam-international + 3.1.0.Final + + + + org.jboss.seam.faces + seam-faces + 3.1.0.Final + + + + org.jboss.seam.transaction + seam-transaction-api + 3.1.0.Final + + + + org.jboss.seam.transaction + seam-transaction + 3.1.0.Final + + + + org.jboss.seam.jms + seam-jms-api + + + + org.jboss.seam.jms + seam-jms + + + + javax.jms + jms + 1.1 + + + + org.jboss.spec.javax.ejb + jboss-ejb-api_3.1_spec + 1.0.1.Final + provided + + + + org.jboss.spec.javax.faces + jboss-jsf-api_2.1_spec + 2.0.0.Beta1 + + + + javax.el + el-api + 2.2 + provided + + + + com.sun.faces + jsf-impl + provided + + + + javax.transaction + jta + 1.1 + provided + + + + + + ${project.artifactId} + + + + + org.zeroturnaround + jrebel-maven-plugin + 1.0.7 + + + generate-rebel-xml + process-resources + + generate + + + + + + + org.jboss.as.plugins + jboss-as-maven-plugin + ${version.jbossas} + + ${project.groupId} + ${project.artifactId} + true +
localhost
+
+
+ +
+
+ +
diff --git a/examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/CdiJmsBridge.java b/examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/CdiJmsBridge.java new file mode 100644 index 0000000..b397b32 --- /dev/null +++ b/examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/CdiJmsBridge.java @@ -0,0 +1,15 @@ +package org.jboss.seam.jms.example.xaplayground; + +import org.jboss.seam.jms.annotations.JmsDestination; +import org.jboss.seam.jms.annotations.Outbound; + +import javax.enterprise.event.Observes; +import javax.jms.Queue; + +@SuppressWarnings({"CdiManagedBeanInconsistencyInspection"}) +public interface CdiJmsBridge { +// -------------------------- OTHER METHODS -------------------------- + + @Outbound + void mapStringToQueue(@Observes String status, @JmsDestination(jndiName = Constants.DEFAULT_QUEUE_JNDI) Queue q); +} diff --git a/examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/Constants.java b/examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/Constants.java new file mode 100644 index 0000000..1dabab4 --- /dev/null +++ b/examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/Constants.java @@ -0,0 +1,7 @@ +package org.jboss.seam.jms.example.xaplayground; + +public interface Constants { +// ------------------------------ FIELDS ------------------------------ + + String DEFAULT_QUEUE_JNDI = "java:/queue/test"; +} diff --git a/examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/GoodlListener.java b/examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/GoodlListener.java new file mode 100644 index 0000000..f49674a --- /dev/null +++ b/examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/GoodlListener.java @@ -0,0 +1,31 @@ +package org.jboss.seam.jms.example.xaplayground; + +import org.jboss.solder.logging.Logger; + +import javax.ejb.ActivationConfigProperty; +import javax.ejb.MessageDriven; +import javax.inject.Inject; +import javax.jms.Message; +import javax.jms.MessageListener; + +@MessageDriven(name = "GoodlListener", + activationConfig = {@ActivationConfigProperty(propertyName = "destination", propertyValue = Constants.DEFAULT_QUEUE_JNDI), + @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"), + @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Session-transacted")}) +public class GoodlListener implements MessageListener { +// ------------------------------ FIELDS ------------------------------ + + @Inject + private Logger logger; + +// ------------------------ INTERFACE METHODS ------------------------ + + +// --------------------- Interface MessageListener --------------------- + + @Override + public void onMessage(Message message) + { + logger.info(message); + } +} diff --git a/examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/MeantException.java b/examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/MeantException.java new file mode 100644 index 0000000..0d5d390 --- /dev/null +++ b/examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/MeantException.java @@ -0,0 +1,10 @@ +package org.jboss.seam.jms.example.xaplayground; + +public class MeantException extends RuntimeException { +// --------------------------- CONSTRUCTORS --------------------------- + + public MeantException() + { + super("This is meant exception"); + } +} diff --git a/examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/TestView.java b/examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/TestView.java new file mode 100644 index 0000000..a15ccc0 --- /dev/null +++ b/examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/TestView.java @@ -0,0 +1,95 @@ +package org.jboss.seam.jms.example.xaplayground; + +import org.jboss.seam.jms.MessageManager; +import org.jboss.seam.jms.annotations.JmsDestination; +import org.jboss.seam.jms.example.xaplayground.inject.XA; +import org.jboss.seam.transaction.Transactional; +import org.jboss.solder.exception.control.CaughtException; +import org.jboss.solder.exception.control.Handles; +import org.jboss.solder.exception.control.HandlesExceptions; +import org.jboss.solder.logging.Logger; + +import javax.enterprise.event.Event; +import javax.enterprise.inject.Model; +import javax.faces.context.FacesContext; +import javax.inject.Inject; +import javax.jms.Message; +import javax.jms.Queue; +import javax.transaction.UserTransaction; +import java.util.Date; + +@HandlesExceptions +@Model +public class TestView { +// ------------------------------ FIELDS ------------------------------ + + @Inject + Event stringEvent; + + @Inject + private FacesContext facesContext; + + @Inject + @JmsDestination(jndiName = Constants.DEFAULT_QUEUE_JNDI) + private Queue mailQueue; + + @Inject + private MessageManager messageManager; + + @Inject + @XA + private MessageManager messageManagerXA; + + @Inject + private Logger logger; + +// -------------------------- OTHER METHODS -------------------------- + + public void handleMeantException(@Handles CaughtException e) + { + logger.info(e.getException().getLocalizedMessage()); + facesContext.getApplication().getNavigationHandler().handleNavigation(facesContext, null, "home"); + e.handled(); + } + + public void sendBridgedEvents() + { + stringEvent.fire("Listening to Florence: " + new Date()); + throw new MeantException(); + } + + @Transactional + public void sendBridgedEventsTransactional() + { + sendBridgedEvents(); + } + + public void sendNonXA() + { + Message jmsMessage = messageManager.createTextMessage("Hello"); + messageManager.sendMessage(jmsMessage, mailQueue); + throw new MeantException(); + } + + @Transactional + public void sendNonXATransactional() + { + sendNonXA(); + } + + public void sendXA() + { + Message jmsMessage = messageManager.createTextMessage("Hello"); + messageManagerXA.sendMessage(jmsMessage, mailQueue); + throw new MeantException(); + } + + @Inject + private UserTransaction seamTransaction; + + @Transactional + public void sendXATransactional() + { + sendXA(); + } +} diff --git a/examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/inject/JmsXAConnectionFactoryProducer.java b/examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/inject/JmsXAConnectionFactoryProducer.java new file mode 100644 index 0000000..086f9b3 --- /dev/null +++ b/examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/inject/JmsXAConnectionFactoryProducer.java @@ -0,0 +1,35 @@ +package org.jboss.seam.jms.example.xaplayground.inject; + +import org.jboss.seam.jms.annotations.JmsDefault; +import org.jboss.solder.logging.Logger; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.inject.Produces; +import javax.inject.Inject; +import javax.jms.XAConnectionFactory; +import javax.naming.Context; +import javax.naming.NamingException; + +@ApplicationScoped +public class JmsXAConnectionFactoryProducer { + + private String connectionFactoryJNDILocation = "/JmsXA"; + + private Logger logger = Logger.getLogger(JmsXAConnectionFactoryProducer.class); + + @Inject + Context context; + + @Produces + @ApplicationScoped + @JmsDefault("XAConnectionFactory") + public XAConnectionFactory produceConnectionFactory() + { + try { + return (XAConnectionFactory) context.lookup(connectionFactoryJNDILocation); + } catch (NamingException e) { + logger.info("Unable to look up " + connectionFactoryJNDILocation + " in JNDI", e); + return null; + } + } +} diff --git a/examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/inject/JmsXASessionProducer.java b/examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/inject/JmsXASessionProducer.java new file mode 100644 index 0000000..08b19ec --- /dev/null +++ b/examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/inject/JmsXASessionProducer.java @@ -0,0 +1,65 @@ +package org.jboss.seam.jms.example.xaplayground.inject; + +import org.jboss.seam.jms.annotations.JmsDefault; +import org.jboss.solder.logging.Logger; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.context.Dependent; +import javax.enterprise.inject.Disposes; +import javax.enterprise.inject.Produces; +import javax.inject.Inject; +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Session; +import javax.jms.XAConnection; +import javax.jms.XAConnectionFactory; +import javax.jms.XASession; +import java.util.HashMap; +import java.util.Map; + +@ApplicationScoped +public class JmsXASessionProducer { +// ------------------------------ FIELDS ------------------------------ + + @Inject + @JmsDefault("XAConnectionFactory") + private XAConnectionFactory connectionFactory; + + /** + * We can create only one session per conneciton cause otherwise we would get: + * javax.jms.IllegalStateException: Only allowed one session per connection. See the J2EE spec, e.g. J2EE1.4 Section 6.6 + *

+ * So we need to cache them. + * TODO doesn't the server take care of closing connections (pooling)? + */ + private Map connectionMap = new HashMap(); + + @Inject + private Logger logger; + +// -------------------------- OTHER METHODS -------------------------- + + public void close(@Disposes @JmsDefault("XASession") Session session) + { + Connection connection = connectionMap.remove(session); + if (connection != null) { + try { + logger.debugv("Closing connection for session {0}", session); + connection.close(); + } catch (JMSException e) { + logger.errorv(e, "Cannot close JMS connection"); + } + } + } + + @Produces + @Dependent + @JmsDefault("XASession") + public Session produceSession() throws JMSException + { + XAConnection connection = connectionFactory.createXAConnection(); + XASession session = connection.createXASession(); + connectionMap.put(session, connection); + return session; + } +} diff --git a/examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/inject/XA.java b/examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/inject/XA.java new file mode 100644 index 0000000..d9470d4 --- /dev/null +++ b/examples/xa-playground/src/main/java/org/jboss/seam/jms/example/xaplayground/inject/XA.java @@ -0,0 +1,18 @@ +package org.jboss.seam.jms.example.xaplayground.inject; + +import javax.inject.Qualifier; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +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.ElementType.TYPE; + +@Qualifier +@Target({FIELD, METHOD, TYPE, PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +public @interface XA { + +} diff --git a/examples/xa-playground/src/main/resources/META-INF/seam-beans.xml b/examples/xa-playground/src/main/resources/META-INF/seam-beans.xml new file mode 100644 index 0000000..cde4054 --- /dev/null +++ b/examples/xa-playground/src/main/resources/META-INF/seam-beans.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/xa-playground/src/main/webapp/WEB-INF/beans.xml b/examples/xa-playground/src/main/webapp/WEB-INF/beans.xml new file mode 100644 index 0000000..8f4bb78 --- /dev/null +++ b/examples/xa-playground/src/main/webapp/WEB-INF/beans.xml @@ -0,0 +1,9 @@ + + + + + org.jboss.seam.transaction.TransactionInterceptor + + + diff --git a/examples/xa-playground/src/main/webapp/WEB-INF/faces-config.xml b/examples/xa-playground/src/main/webapp/WEB-INF/faces-config.xml new file mode 100644 index 0000000..6dfeef7 --- /dev/null +++ b/examples/xa-playground/src/main/webapp/WEB-INF/faces-config.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/examples/xa-playground/src/main/webapp/WEB-INF/web.xml b/examples/xa-playground/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..5edffd0 --- /dev/null +++ b/examples/xa-playground/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,34 @@ + + + + + javax.faces.STATE_SAVING_METHOD + server + + + javax.faces.FACELETS_SKIP_COMMENTS + true + + + Faces Servlet + javax.faces.webapp.FacesServlet + 1 + + + Faces Servlet + *.jsf + + + 10 + + + Restrict raw XHTML Documents + + XHTML + *.xhtml + + + + + diff --git a/examples/xa-playground/src/main/webapp/index.html b/examples/xa-playground/src/main/webapp/index.html new file mode 100644 index 0000000..b2fa40e --- /dev/null +++ b/examples/xa-playground/src/main/webapp/index.html @@ -0,0 +1,11 @@ + + + + + + + + + + \ No newline at end of file diff --git a/examples/xa-playground/src/main/webapp/layout/template.xhtml b/examples/xa-playground/src/main/webapp/layout/template.xhtml new file mode 100644 index 0000000..2535529 --- /dev/null +++ b/examples/xa-playground/src/main/webapp/layout/template.xhtml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + diff --git a/examples/xa-playground/src/main/webapp/view/home.xhtml b/examples/xa-playground/src/main/webapp/view/home.xhtml new file mode 100644 index 0000000..de75b60 --- /dev/null +++ b/examples/xa-playground/src/main/webapp/view/home.xhtml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + +

+ Methods invoked with buttons in left column are not annotated @Transactional while those in right column are.

+ +

+ When you are not logged in then "Send bridged events" will try to fire event with empty value

+ +

+ Note that bridged events are sent via default MessageManager which by default works with @JmsDefault("session") Session. + So events will still get to jms queue even if we get exception. To avoid that we have to modify default MessageManager:

+
+            <jms:MessageManagerImpl>
+                <s:replaces/>
+                <jms:session>
+                    <jmsa:JmsDefault value="XASession"/>
+                    <s:Inject/>
+                </jms:session>
+                <jms:exceptionEvent>
+                    <s:Inject/>
+                </jms:exceptionEvent>
+            </jms:MessageManagerImpl>
+        
+ + + +