diff --git a/dbcp2-and-tomcat/README.md b/dbcp2-and-tomcat/README.md new file mode 100644 index 0000000000..50cccf060c --- /dev/null +++ b/dbcp2-and-tomcat/README.md @@ -0,0 +1,33 @@ +### Description + +This quickstart shows how to get started with Narayana and common-dbcp2 with a simple JDBC example. + +### Start Tomcat + +Start Tomcat in the usual manner, for example: +`$TOMCAT_HOME/bin/catalina.sh run` + +### Build the app + +`mvn clean package` + +### Deploy the app + +`cp target/*.war apache-tomcat-7.0.78/webapps/` + +### Get strings from the database + +`curl http://localhost:8080/dbcp2-and-tomcat` + +### Save string to the database + +`curl --data "test" http://localhost:8080/dbcp2-and-tomcat` + +### Crash and Recovery + +`curl --data "crash" http://localhost:8080/dbcp2-and-tomcat/crash` + +Restart Tomcat +`$TOMCAT_HOME/bin/catalina.sh run` +`curl http://localhost:8080/dbcp2-and-tomcat/recovery` + diff --git a/dbcp2-and-tomcat/pom.xml b/dbcp2-and-tomcat/pom.xml new file mode 100644 index 0000000000..a81bb2b5af --- /dev/null +++ b/dbcp2-and-tomcat/pom.xml @@ -0,0 +1,95 @@ + + + 4.0.0 + io.narayana + dbcp2-and-tomcat + 5.8.1.Final-SNAPSHOT + war + + + 5.8.1.Final-SNAPSHOT + 3.0.23.Final + 1.4.195 + 2.2 + 2.1.1 + 2.4.3 + 1.8 + 1.8 + + + + + org.jboss.narayana.tomcat + tomcat-jta + ${version.narayana} + + + org.jboss.resteasy + resteasy-servlet-initializer + ${version.resteasy} + + + org.jboss.resteasy + resteasy-jackson-provider + ${version.resteasy} + + + org.apache.commons + commons-dbcp2 + ${version.commons-dbcp2} + + + commons-logging + commons-logging + + + + + org.apache.commons + commons-pool2 + ${version.commons-pool2} + + + com.h2database + h2 + ${version.h2} + + + + + ${artifactId} + + + + + unix + + + unix + + + + + + exec-maven-plugin + org.codehaus.mojo + + + Run tests + integration-test + + exec + + + bash + ${basedir}/run.sh + + + + + + + + + diff --git a/dbcp2-and-tomcat/run.sh b/dbcp2-and-tomcat/run.sh new file mode 100755 index 0000000000..a65efa171d --- /dev/null +++ b/dbcp2-and-tomcat/run.sh @@ -0,0 +1,45 @@ +#/bin/bash +set -m + +export QUICKSTART_NAME=${PWD##*/} +TOMCAT_VERSION=7.0.82 +wget -nc https://archive.apache.org/dist/tomcat/tomcat-7/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.zip +rm -rf apache-tomcat-$TOMCAT_VERSION +unzip apache-tomcat-$TOMCAT_VERSION.zip +export TOMCAT_HOME=$(pwd)/apache-tomcat-$TOMCAT_VERSION/ +chmod +x $TOMCAT_HOME/bin/catalina.sh +mvn package +rm -rf $TOMCAT_HOME/webapps/${QUICKSTART_NAME}/ +cp target/${QUICKSTART_NAME}.war $TOMCAT_HOME/webapps/ +JPDA_SUSPEND=n $TOMCAT_HOME/bin/catalina.sh jpda run & +sleep 10 + +for i in {1..10} +do + curl -f --data "test$i" http://localhost:8080/${QUICKSTART_NAME} +done + +curl -f http://localhost:8080/${QUICKSTART_NAME} + +# remove all strings +curl -f -X DELETE http://localhost:8080/${QUICKSTART_NAME} + +# crash the application +curl -f --data "crash" http://localhost:8080/${QUICKSTART_NAME}/crash + +# restart the Tomcat +JPDA_SUSPEND=n $TOMCAT_HOME/bin/catalina.sh jpda run & + +# verify the recovery +sleep 5 +x=`curl -s http://localhost:8080/${QUICKSTART_NAME}/recovery` + +$TOMCAT_HOME/bin/catalina.sh stop +rm -rf apache-tomcat-$TOMCAT_VERSION + +if [ "$x" != "[\"crash\"]" ]; then + echo "Crash and Recovery failed" + exit -1 +fi + +echo "All tests succeeded" diff --git a/dbcp2-and-tomcat/src/main/java/io/narayana/DummyXAResource.java b/dbcp2-and-tomcat/src/main/java/io/narayana/DummyXAResource.java new file mode 100644 index 0000000000..5616372a54 --- /dev/null +++ b/dbcp2-and-tomcat/src/main/java/io/narayana/DummyXAResource.java @@ -0,0 +1,204 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual + * contributors by the @authors tag. See the copyright.txt in the + * distribution for a full listing of individual contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.narayana; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Arrays; + +import javax.transaction.xa.XAException; +import javax.transaction.xa.XAResource; +import javax.transaction.xa.Xid; + +import com.arjuna.ats.arjuna.common.Uid; + +/** + * This class is used solely for simulating system crash. + * + * @author Gytis Trikleris + * @author Amos Feng + */ +public class DummyXAResource implements XAResource { + + public static final String LOG_DIR = "target/DummyXAResource/"; + + private final boolean shouldCrash; + + private Xid xid; + + private File file; + + public DummyXAResource(boolean shouldCrash) { + this.shouldCrash = shouldCrash; + } + + /** + * Constructor used by recovery manager to recreate XAResource + * + * @param file File where Xid of the XAResource is stored + */ + public DummyXAResource(File file) throws IOException { + this.shouldCrash = false; + this.file = file; + this.xid = getXidFromFile(file); + } + + public int prepare(final Xid xid) throws XAException { + System.out.println("Preparing " + DummyXAResource.class.getSimpleName()); + + this.file = writeXidToFile(xid, LOG_DIR); + + return XA_OK; + } + + public void commit(final Xid xid, final boolean arg1) throws XAException { + System.out.println("Committing " + DummyXAResource.class.getSimpleName()); + + if (shouldCrash) { + System.out.println("Crashing the system"); + Runtime.getRuntime().halt(1); + } + + removeFile(file); + this.file = null; + this.xid = null; + } + + public void rollback(final Xid xid) throws XAException { + System.out.println("Rolling back " + DummyXAResource.class.getSimpleName()); + + removeFile(file); + this.file = null; + this.xid = null; + } + + public boolean isSameRM(XAResource xaResource) throws XAException { + if (!(xaResource instanceof DummyXAResource)) { + return false; + } + + DummyXAResource other = (DummyXAResource) xaResource; + + return xid != null && other.xid != null && xid.getFormatId() == other.xid.getFormatId() + && Arrays.equals(xid.getGlobalTransactionId(), other.xid.getGlobalTransactionId()) + && Arrays.equals(xid.getBranchQualifier(), other.xid.getBranchQualifier()); + } + + public Xid[] recover(int flag) throws XAException { + return new Xid[]{ xid }; + } + + public void start(Xid xid, int flags) throws XAException { + + } + + public void end(Xid xid, int flags) throws XAException { + + } + + public void forget(Xid xid) throws XAException { + + } + + public int getTransactionTimeout() throws XAException { + return 0; + } + + public boolean setTransactionTimeout(final int seconds) throws XAException { + return true; + } + + private Xid getXidFromFile(File file) throws IOException { + try (DataInputStream inputStream = new DataInputStream(new FileInputStream(file))) { + int formatId = inputStream.readInt(); + int globalTransactionIdLength = inputStream.readInt(); + byte[] globalTransactionId = new byte[globalTransactionIdLength]; + inputStream.read(globalTransactionId, 0, globalTransactionIdLength); + int branchQualifierLength = inputStream.readInt(); + byte[] branchQualifier = new byte[branchQualifierLength]; + inputStream.read(branchQualifier, 0, branchQualifierLength); + + return new XidImpl(formatId, globalTransactionId, branchQualifier); + } + } + + private File writeXidToFile(Xid xid, String directory) throws XAException { + File dir = new File(directory); + + if (!dir.mkdirs()) { + throw new XAException(XAException.XAER_RMERR); + } + + File file = new File(dir, new Uid().fileStringForm() + "_"); + + try (DataOutputStream outputStream = new DataOutputStream(new FileOutputStream(file))) { + outputStream.writeInt(xid.getFormatId()); + outputStream.writeInt(xid.getGlobalTransactionId().length); + outputStream.write(xid.getGlobalTransactionId(), 0, xid.getGlobalTransactionId().length); + outputStream.writeInt(xid.getBranchQualifier().length); + outputStream.write(xid.getBranchQualifier(), 0, xid.getBranchQualifier().length); + outputStream.flush(); + } catch (IOException e) { + throw new XAException(XAException.XAER_RMERR); + } + + return file; + } + + private void removeFile(File file) throws XAException { + if (file != null) { + if (!file.delete()) { + throw new XAException(XAException.XA_RETRY); + } + } + } + + private class XidImpl implements Xid { + + private final int formatId; + + private final byte[] globalTransactionId; + + private final byte[] branchQualifier; + + public XidImpl(int formatId, byte[] globalTransactionId, byte[] branchQualifier) { + this.formatId = formatId; + this.globalTransactionId = globalTransactionId; + this.branchQualifier = branchQualifier; + } + + @Override + public int getFormatId() { + return formatId; + } + + @Override + public byte[] getGlobalTransactionId() { + return globalTransactionId; + } + + @Override + public byte[] getBranchQualifier() { + return branchQualifier; + } + + } +} diff --git a/dbcp2-and-tomcat/src/main/java/io/narayana/DummyXAResourceRecovery.java b/dbcp2-and-tomcat/src/main/java/io/narayana/DummyXAResourceRecovery.java new file mode 100644 index 0000000000..55ab8dc466 --- /dev/null +++ b/dbcp2-and-tomcat/src/main/java/io/narayana/DummyXAResourceRecovery.java @@ -0,0 +1,65 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual + * contributors by the @authors tag. See the copyright.txt in the + * distribution for a full listing of individual contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.narayana; + +import java.io.IOException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; + +import javax.transaction.xa.XAResource; + +import org.jboss.tm.XAResourceRecovery; + +/** + * This class is used solely for simulating system crash. + * + * @author Gytis Trikleris + * @author Amos Feng + */ +public class DummyXAResourceRecovery implements XAResourceRecovery { + + @Override + public XAResource[] getXAResources() throws RuntimeException { + List resources; + try { + resources = getXAResourcesFromDirectory(DummyXAResource.LOG_DIR); + } catch (IOException e) { + throw new RuntimeException(e); + } + + System.out.println(DummyXAResourceRecovery.class.getSimpleName() + " returning list of resources: " + resources); + + return resources.toArray(new XAResource[]{}); + } + + private List getXAResourcesFromDirectory(String directory) throws IOException { + List resources = new ArrayList<>(); + + Files.newDirectoryStream(FileSystems.getDefault().getPath(directory), "*_").forEach(path -> { + try { + resources.add(new DummyXAResource(path.toFile())); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + + return resources; + } + +} diff --git a/dbcp2-and-tomcat/src/main/java/io/narayana/StringDao.java b/dbcp2-and-tomcat/src/main/java/io/narayana/StringDao.java new file mode 100755 index 0000000000..e25eb0ac48 --- /dev/null +++ b/dbcp2-and-tomcat/src/main/java/io/narayana/StringDao.java @@ -0,0 +1,135 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2016, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package io.narayana; + +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.LinkedList; +import java.util.List; + +/** + * @author Gytis Trikleris + */ +public class StringDao { + + private static final String CREATE_TABLE_QUERY = "CREATE TABLE IF NOT EXISTS strings (string VARCHAR(500))"; + + private static final String FIND_ALL_STRINGS_QUERY = "SELECT string FROM strings"; + + private static final String DELETE_ALL_STRINGS_QUERY = "DELETE FROM strings"; + + private static final String INSERT_STRING_QUERY = "INSERT INTO strings VALUES ('%s')"; + + private Connection connection; + + public StringDao() throws SQLException { + initDatabase(); + } + + /** + * Get all strings from the database. + * + * @return + * @throws SQLException + */ + public List getAll() throws SQLException { + List strings = new LinkedList<>(); + getConnection(); + try (Statement statement = connection.createStatement()) { + try (ResultSet resultSet = statement.executeQuery(FIND_ALL_STRINGS_QUERY)) { + while (resultSet.next()) { + strings.add(resultSet.getString("string")); + } + } + } + close(); + + return strings; + } + + /** + * Save string to the database. + * @param string + * @throws SQLException + */ + public void save(String string) throws SQLException { + getConnection(); + try (Statement statement = connection.createStatement()) { + statement.execute(String.format(INSERT_STRING_QUERY, string)); + } + close(); + } + + /** + * Delete all strings in the database. + * @throws SQLException + */ + public void removeAll() throws SQLException { + getConnection(); + try (Statement statement = connection.createStatement()) { + statement.execute(DELETE_ALL_STRINGS_QUERY); + } catch (SQLException e) { + throw new RuntimeException(e); + } + close(); + + } + + /** + * Create strings table if it doesn't exist. + */ + private void initDatabase() throws SQLException { + getConnection(); + try (Statement statement = connection.createStatement()) { + statement.execute(CREATE_TABLE_QUERY); + } catch (SQLException e) { + throw new RuntimeException(e); + } + close(); + } + + private void getConnection() { + if (connection == null) { + try { + DataSource ds = InitialContext.doLookup("java:comp/env/transactionalDataSource"); + connection = ds.getConnection(); + } catch (NamingException e) { + throw new RuntimeException(e); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + } + + public void close() throws SQLException { + if (connection != null) { + connection.close(); + connection = null; + } + } +} diff --git a/dbcp2-and-tomcat/src/main/java/io/narayana/StringsApplication.java b/dbcp2-and-tomcat/src/main/java/io/narayana/StringsApplication.java new file mode 100644 index 0000000000..e66d34a8a8 --- /dev/null +++ b/dbcp2-and-tomcat/src/main/java/io/narayana/StringsApplication.java @@ -0,0 +1,33 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2016, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package io.narayana; + +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.core.Application; + +/** + * @author Gytis Trikleris + */ +@ApplicationPath("/") +public class StringsApplication extends Application { +} diff --git a/dbcp2-and-tomcat/src/main/java/io/narayana/StringsResource.java b/dbcp2-and-tomcat/src/main/java/io/narayana/StringsResource.java new file mode 100755 index 0000000000..01c87406db --- /dev/null +++ b/dbcp2-and-tomcat/src/main/java/io/narayana/StringsResource.java @@ -0,0 +1,156 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2016, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package io.narayana; + +import com.arjuna.ats.internal.jta.recovery.arjunacore.XARecoveryModule; +import com.arjuna.ats.jta.recovery.XAResourceRecoveryHelper; + +import java.sql.SQLException; +import java.util.List; + +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.transaction.TransactionManager; +import javax.transaction.xa.XAResource; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import static java.lang.Thread.sleep; + +/** + * @author Gytis Trikleris + */ +@Path("/") +public class StringsResource { + + private final StringDao stringDao; + + private final TransactionManager transactionManager; + + public StringsResource() throws NamingException, SQLException { + stringDao = new StringDao(); + transactionManager = InitialContext.doLookup("java:comp/env/TransactionManager"); + } + + @GET + @Produces(MediaType.APPLICATION_JSON) + public List getStrings() throws SQLException { + System.out.println(this.getClass().getSimpleName() + " GET"); + return stringDao.getAll(); + } + + @POST + public void saveString(String string) throws Exception { + System.out.println(this.getClass().getSimpleName() + " POST"); + System.out.println(this.getClass().getSimpleName() + " begin transaction"); + transactionManager.begin(); + System.out.println(this.getClass().getSimpleName() + " save string"); + try { + stringDao.save(string); + System.out.println(this.getClass().getSimpleName() + " commit transaction"); + transactionManager.commit(); + System.out.println(this.getClass().getSimpleName() + " transaction committed successfully"); + } catch (SQLException e) { + System.out.println(this.getClass().getSimpleName() + " rollback transaction"); + transactionManager.rollback(); + System.out.println(this.getClass().getSimpleName() + " transaction rolled back"); + throw e; + } finally { + stringDao.close(); + } + } + + @DELETE + public void removeAll() throws Exception { + System.out.println(this.getClass().getSimpleName() + " DELETE"); + stringDao.removeAll(); + } + + @POST + @Path("crash") + public void crash(String string) throws Exception { + transactionManager.begin(); + try { + transactionManager.getTransaction().enlistResource(new DummyXAResource(true)); + stringDao.save(string); + transactionManager.commit(); + } catch (SQLException e) { + transactionManager.rollback(); + throw e; + } finally { + stringDao.close(); + } + } + + @GET + @Path("recovery") + @Produces(MediaType.APPLICATION_JSON) + public List recovery() throws Exception{ + List stringsBefore = stringDao.getAll(); + System.out.println("Strings at the start: " + stringsBefore); + getXARecoveryModule().addXAResourceRecoveryHelper(new XAResourceRecoveryHelper() { + @Override + public boolean initialise(String s) throws Exception { + return true; + } + + @Override + public XAResource[] getXAResources() throws Exception { + return new DummyXAResourceRecovery().getXAResources(); + } + }); + waitForRecovery(stringsBefore); + System.out.println("Strings at the end: " + stringDao.getAll()); + return stringDao.getAll(); + } + + private void waitForRecovery(List stringsBefore) throws Exception { + boolean isComplete = false; + + for (int i = 0; i < 3 && !isComplete; i++) { + sleep(5000); + isComplete = stringsBefore.size() < stringDao.getAll().size(); + } + + if (isComplete) { + System.out.println("Recovery completed successfully"); + } else { + throw new Exception("Something wrong happened and recovery didn't complete"); + } + } + + + private XARecoveryModule getXARecoveryModule() { + XARecoveryModule xaRecoveryModule = XARecoveryModule + .getRegisteredXARecoveryModule(); + if (xaRecoveryModule != null) { + return xaRecoveryModule; + } + throw new IllegalStateException( + "XARecoveryModule is not registered with recovery manager"); + } +} diff --git a/dbcp2-and-tomcat/src/main/java/io/narayana/TransactionalDataSourceFactory.java b/dbcp2-and-tomcat/src/main/java/io/narayana/TransactionalDataSourceFactory.java new file mode 100644 index 0000000000..8520e13abb --- /dev/null +++ b/dbcp2-and-tomcat/src/main/java/io/narayana/TransactionalDataSourceFactory.java @@ -0,0 +1,115 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2016, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package io.narayana; + +import com.arjuna.ats.internal.jta.recovery.arjunacore.XARecoveryModule; +import com.arjuna.ats.jta.recovery.XAResourceRecoveryHelper; +import org.apache.commons.dbcp2.PoolableConnection; +import org.apache.commons.dbcp2.PoolableConnectionFactory; +import org.apache.commons.dbcp2.managed.DataSourceXAConnectionFactory; +import org.apache.commons.dbcp2.managed.ManagedDataSource; +import org.apache.commons.pool2.impl.GenericObjectPool; +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; + +import javax.naming.Context; +import javax.naming.Name; +import javax.naming.RefAddr; +import javax.naming.Reference; +import javax.naming.spi.ObjectFactory; +import javax.sql.XADataSource; +import javax.transaction.TransactionManager; +import javax.transaction.xa.XAResource; +import java.sql.SQLException; +import java.util.Hashtable; + +/** + * @author objectPool = + new GenericObjectPool<>(poolableConnectionFactory, config); + poolableConnectionFactory.setPool(objectPool); + return new ManagedDataSource<>(objectPool, xaConnectionFactory.getTransactionRegistry()); + } else { + return null; + } + } + + private Object getReferenceObject(Reference ref, Context context, String prop) throws Exception { + final RefAddr ra = ref.get(prop); + if (ra != null) { + return context.lookup(ra.getContent().toString()); + } else { + return null; + } + } + + private XARecoveryModule getXARecoveryModule() { + XARecoveryModule xaRecoveryModule = XARecoveryModule + .getRegisteredXARecoveryModule(); + if (xaRecoveryModule != null) { + return xaRecoveryModule; + } + throw new IllegalStateException( + "XARecoveryModule is not registered with recovery manager"); + } +} diff --git a/dbcp2-and-tomcat/src/main/webapp/META-INF/context.xml b/dbcp2-and-tomcat/src/main/webapp/META-INF/context.xml new file mode 100755 index 0000000000..07d385cf73 --- /dev/null +++ b/dbcp2-and-tomcat/src/main/webapp/META-INF/context.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/dbcp2-and-tomcat/src/main/webapp/WEB-INF/web.xml b/dbcp2-and-tomcat/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000..da7b9c7108 --- /dev/null +++ b/dbcp2-and-tomcat/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,6 @@ + + + + org.jboss.narayana.tomcat.jta.NarayanaJtaServletContextListener + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 516dbc1c0b..dcc01f57c5 100755 --- a/pom.xml +++ b/pom.xml @@ -127,6 +127,7 @@ ArjunaJTS transactionaldriver jca-and-tomcat + dbcp2-and-tomcat jca-and-hibernate jta-1_2-standalone jta-1_2-in-wildfly