Java tutorial
/* * $Header: /var/chroot/cvs/cvs/factsheetDesigner/extern/jakarta-slide-server-src-2.1-iPlus Edit/src/stores/org/apache/slide/store/impl/rdbms/AbstractRDBMSStore.java,v 1.3 2007-12-06 16:41:57 peter-cvs Exp $ * $Revision: 1.3 $ * $Date: 2007-12-06 16:41:57 $ * * ==================================================================== * * Copyright 1999-2003 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.slide.store.impl.rdbms; import java.lang.reflect.Constructor; import java.sql.Connection; import java.sql.SQLException; import java.util.Enumeration; import java.util.Hashtable; import javax.transaction.xa.XAException; import javax.transaction.xa.XAResource; import javax.transaction.xa.Xid; import org.apache.commons.transaction.util.xa.AbstractTransactionalResource; import org.apache.commons.transaction.util.xa.TransactionalResource; import org.apache.slide.common.AbstractXAServiceBase; import org.apache.slide.common.Service; import org.apache.slide.common.ServiceAccessException; import org.apache.slide.common.ServiceConnectionFailedException; import org.apache.slide.common.ServiceDisconnectionFailedException; import org.apache.slide.common.ServiceInitializationFailedException; import org.apache.slide.common.ServiceParameterErrorException; import org.apache.slide.common.ServiceParameterMissingException; import org.apache.slide.common.ServiceResetFailedException; import org.apache.slide.common.Uri; import org.apache.slide.content.NodeRevisionContent; import org.apache.slide.content.NodeRevisionDescriptor; import org.apache.slide.content.NodeRevisionDescriptors; import org.apache.slide.content.NodeRevisionNumber; import org.apache.slide.content.RevisionAlreadyExistException; import org.apache.slide.content.RevisionDescriptorNotFoundException; import org.apache.slide.content.RevisionNotFoundException; import org.apache.slide.lock.LockTokenNotFoundException; import org.apache.slide.lock.NodeLock; import org.apache.slide.search.basic.BasicExpressionFactory; import org.apache.slide.search.basic.IBasicExpressionFactory; import org.apache.slide.search.basic.IBasicExpressionFactoryProvider; import org.apache.slide.security.NodePermission; import org.apache.slide.store.ContentStore; import org.apache.slide.store.LockStore; import org.apache.slide.store.NodeStore; import org.apache.slide.store.RevisionDescriptorStore; import org.apache.slide.store.RevisionDescriptorsStore; import org.apache.slide.store.SecurityStore; import org.apache.slide.store.SequenceStore; import org.apache.slide.store.impl.rdbms.expression.RDBMSExpressionFactory; import org.apache.slide.structure.ObjectAlreadyExistsException; import org.apache.slide.structure.ObjectNode; import org.apache.slide.structure.ObjectNotFoundException; import org.apache.slide.util.logger.Logger; /** * J2EE store implementation - implements the shared parts of * the two (content, descriptors) J2EE stores for the new Indexed DB Schema. * * @version $Revision: 1.3 $ */ public abstract class AbstractRDBMSStore extends AbstractXAServiceBase implements LockStore, NodeStore, RevisionDescriptorsStore, RevisionDescriptorStore, SecurityStore, ContentStore, SequenceStore, IBasicExpressionFactoryProvider { protected static final String LOG_CHANNEL = AbstractRDBMSStore.class.getName(); protected RDBMSAdapter adapter; protected boolean alreadyInitialized = false; protected int isSequenceSupported = 0; protected boolean useRdbmsExpressionFactory; /** * Indicates whether the transaction manager will commit / rollback * the transaction or the store is in charge of it. Slide's internal * TM does not commit / rollback, but TMs more aligned to the spec (e.g. JBoss' TM) do. */ protected boolean tmCommits = false; /** * Initializes the data source with a set of parameters. * * @param parameters Hashtable containing the parameters' name * and associated value * @exception ServiceParameterErrorException Incorrect service parameter * @exception ServiceParameterMissingException Service parameter missing */ public void setParameters(Hashtable parameters) throws ServiceParameterErrorException, ServiceParameterMissingException { // Adapter class String value = (String) parameters.get("adapter"); if (value == null) { adapter = new StandardRDBMSAdapter(this, getLogger()); } else { try { Class adapterClass = Class.forName(value); Constructor ctor = adapterClass.getConstructor(new Class[] { Service.class, Logger.class }); adapter = (RDBMSAdapter) ctor.newInstance(new Object[] { this, getLogger() }); } catch (Exception e) { // reflection exception getLogger().log("Error instantiating Adapter '" + value + "' (" + e.getMessage() + ")", LOG_CHANNEL, Logger.ERROR); } } if (adapter != null) { adapter.setParameters(parameters); } // Use RDBMSExpressionFactory? value = (String) parameters.get("use-rdbms-expression-factory"); this.useRdbmsExpressionFactory = Boolean.valueOf(value).booleanValue(); // XXX need to initialize it here, as some security requests access the store before initialization try { initialize(null); } catch (ServiceInitializationFailedException e) { // XXX this is not very satisfactory... throw new ServiceParameterErrorException(this, e.getMessage()); } } /** * Establishes the global connection to the data source. * * @exception ServiceConnectionFailedException if the connection failed */ public void connect() throws ServiceConnectionFailedException { } /** * Returns connection status. */ public boolean isConnected() { return true; } /** * Closes the global connection to the data source. * * @exception ServiceDisconnectionFailedException if closing the connection * failed */ public void disconnect() throws ServiceDisconnectionFailedException { } /** * Does nothing. * * @exception ServiceResetFailedException Reset failed */ public void reset() throws ServiceResetFailedException { } // ----------------------------------------------------- XAResource Methods /** * Get the transaction timeout value for this XAResource. * Just returns 0, we don't have a way of doing transaction timeouts * with the connection. */ public int getTransactionTimeout() throws XAException { return 0; } /** * Set transaction timeout, not implemented (returns false). */ public boolean setTransactionTimeout(int timeout) throws XAException { return false; } public Xid[] recover(int flag) throws XAException { getLogger().log("recover() for thread: " + Thread.currentThread(), LOG_CHANNEL, Logger.DEBUG); TransactionalResource id = getCurrentlyActiveTransactionalResource(); if (id != null && id.getStatus() == STATUS_PREPARED) { Xid[] xids = new Xid[1]; xids[0] = id.getXid(); return xids; } else return new Xid[0]; } public boolean isSameRM(XAResource xares) throws XAException { return (xares == this); } // ----------------------------------------------- IBasicExpressionFactoryProvider Implementation public IBasicExpressionFactory getBasicExpressionFactory() { if (this.useRdbmsExpressionFactory) { return new RDBMSExpressionFactory(this); } else { return new BasicExpressionFactory(); } } // ----------------------------------------------- SequenceStore Implementation /** * @see org.apache.slide.store.SequenceStore#createSequence(java.lang.String) */ public boolean createSequence(String sequenceName) throws ServiceAccessException { if (!isSequenceSupported()) { throw new ServiceAccessException(this, "Sequences not supported"); } Connection connection = null; try { connection = getNewConnection(); return ((SequenceAdapter) adapter).createSequence(connection, sequenceName); } catch (SQLException e) { throw new ServiceAccessException(this, e); } finally { if (connection != null) { try { if (!tmCommits) { connection.commit(); } } catch (SQLException e) { throw new ServiceAccessException(this, e); } finally { try { connection.close(); } catch (SQLException e) { getLogger().log(e, LOG_CHANNEL, Logger.WARNING); } } } } } /** * @see org.apache.slide.store.SequenceStore#isSequenceSupported() */ public boolean isSequenceSupported() { // cache it for better performance as support of an adapter will // not change will running, it is either yes or no all the time if (isSequenceSupported > 0) return true; if (isSequenceSupported < 0) return false; Connection connection = null; try { connection = getNewConnection(); if (adapter instanceof SequenceAdapter && ((SequenceAdapter) adapter).isSequenceSupported(connection)) { isSequenceSupported = 1; return true; } else { isSequenceSupported = -1; return false; } } catch (SQLException e) { getLogger().log("Error while trying to check for sequence support. Assuming false", e, LOG_CHANNEL, Logger.ERROR); isSequenceSupported = -1; return false; } finally { if (connection != null) { try { if (!tmCommits) { connection.commit(); } } catch (SQLException e) { getLogger().log(e, LOG_CHANNEL, Logger.WARNING); } finally { try { connection.close(); } catch (SQLException e) { getLogger().log(e, LOG_CHANNEL, Logger.WARNING); } } } } } /** * @see org.apache.slide.store.SequenceStore#nextSequenceValue(java.lang.String) */ public long nextSequenceValue(String sequenceName) throws ServiceAccessException { if (!isSequenceSupported()) { throw new ServiceAccessException(this, "Sequences not supported"); } Connection connection = null; try { connection = getNewConnection(); //todo: remove //System.out.println("Getting sequence from the database: "+sequenceName); long value = ((SequenceAdapter) adapter).nextSequenceValue(connection, sequenceName); //System.out.println("Getting sequence from the database: "+sequenceName +"="+value); return value; } catch (SQLException e) { throw new ServiceAccessException(this, e); } finally { if (connection != null) { try { if (!tmCommits) { connection.commit(); } } catch (SQLException e) { throw new ServiceAccessException(this, e); } finally { try { connection.close(); } catch (SQLException e) { getLogger().log(e, LOG_CHANNEL, Logger.WARNING); } } } } } /** * @see org.apache.slide.store.SequenceStore#sequenceExists(java.lang.String) */ public boolean sequenceExists(String sequenceName) throws ServiceAccessException { if (!isSequenceSupported()) { throw new ServiceAccessException(this, "Sequences not supported"); } Connection connection = null; try { connection = getNewConnection(); return ((SequenceAdapter) adapter).sequenceExists(connection, sequenceName); } catch (SQLException e) { throw new ServiceAccessException(this, e); } finally { if (connection != null) { try { if (!tmCommits) { connection.commit(); } } catch (SQLException e) { throw new ServiceAccessException(this, e); } finally { try { connection.close(); } catch (SQLException e) { getLogger().log(e, LOG_CHANNEL, Logger.WARNING); } } } } } // ----------------------------------------------- NodeStore Implementation /** * Retrieve an object. * * @param uri Uri of the object we want to retrieve * @exception ServiceAccessException Error accessing the Service * @exception ObjectNotFoundException The object to retrieve was not found */ public ObjectNode retrieveObject(Uri uri) throws ServiceAccessException, ObjectNotFoundException { if (getCurrentlyActiveTransactionalResource() == null) { Connection connection = null; try { connection = getNewConnection(); return adapter.retrieveObject(connection, uri); } catch (SQLException e) { throw new ServiceAccessException(this, e); } finally { if (connection != null) { try { if (!tmCommits) { connection.commit(); } } catch (SQLException e) { throw new ServiceAccessException(this, e); } finally { try { connection.close(); } catch (SQLException e) { getLogger().log(e, LOG_CHANNEL, Logger.WARNING); } } } } } else { return adapter.retrieveObject(getCurrentConnection(), uri); } } /** * Update an object. * * @param object Object to update * @exception ServiceAccessException Error accessing the Service * @exception ObjectNotFoundException The object to update was not found */ public void storeObject(Uri uri, ObjectNode object) throws ServiceAccessException, ObjectNotFoundException { adapter.storeObject(getCurrentConnection(), uri, object); } /** * Create a new object. * * @param object ObjectNode * @param uri Uri of the object we want to create * @exception ServiceAccessException Error accessing the Service * @exception ObjectAlreadyExistsException An object already exists * at this Uri */ public void createObject(Uri uri, ObjectNode object) throws ServiceAccessException, ObjectAlreadyExistsException { adapter.createObject(getCurrentConnection(), uri, object); } /** * Remove an object. * * @param object Object to remove * @exception ServiceAccessException Error accessing the Service * @exception ObjectNotFoundException The object to remove was not found */ public void removeObject(Uri uri, ObjectNode object) throws ServiceAccessException, ObjectNotFoundException { adapter.removeObject(getCurrentConnection(), uri, object); } // ------------------------------------------- SecurityStore Implementation /** * Grant a new permission. * * @param permission Permission we want to create * @exception ServiceAccessException Error accessing the Service */ public void grantPermission(Uri uri, NodePermission permission) throws ServiceAccessException { adapter.grantPermission(getCurrentConnection(), uri, permission); } /** * Revoke a permission. * * @param permission Permission we want to create * @exception ServiceAccessException Error accessing the Service */ public void revokePermission(Uri uri, NodePermission permission) throws ServiceAccessException { adapter.revokePermission(getCurrentConnection(), uri, permission); } /** * Revoke all the permissions on an object. * * @exception ServiceAccessException Error accessing the Service */ public void revokePermissions(Uri uri) throws ServiceAccessException { adapter.revokePermissions(getCurrentConnection(), uri); } /** * Enumerate permissions on an object. * * @exception ServiceAccessException Error accessing the Service */ public Enumeration enumeratePermissions(Uri uri) throws ServiceAccessException { if (getCurrentlyActiveTransactionalResource() == null) { Connection connection = null; try { connection = getNewConnection(); return adapter.enumeratePermissions(connection, uri); } catch (SQLException e) { throw new ServiceAccessException(this, e); } finally { if (connection != null) { try { if (!tmCommits) { connection.commit(); } } catch (SQLException e) { throw new ServiceAccessException(this, e); } finally { try { connection.close(); } catch (SQLException e) { getLogger().log(e, LOG_CHANNEL, Logger.WARNING); } } } } } else { return adapter.enumeratePermissions(getCurrentConnection(), uri); } } // ----------------------------------------------- LockStore Implementation /** * Create a new lock. * * @param lock Lock token * @exception ServiceAccessException Service access error */ public void putLock(Uri uri, NodeLock lock) throws ServiceAccessException { adapter.putLock(getCurrentConnection(), uri, lock); } /** * Refresh a lock. * * @param lock the lock to renew * @exception ServiceAccessException Service access error * @exception LockTokenNotFoundException Lock token was not found */ public void renewLock(Uri uri, NodeLock lock) throws ServiceAccessException, LockTokenNotFoundException { adapter.renewLock(getCurrentConnection(), uri, lock); } /** * Unlock. * * @param lock Token to remove * @exception ServiceAccessException Service access error * @exception LockTokenNotFoundException Lock token was not found */ public void removeLock(Uri uri, NodeLock lock) throws ServiceAccessException, LockTokenNotFoundException { adapter.removeLock(getCurrentConnection(), uri, lock); } /** * Kill a lock. * * @param lock Token to remove * @exception ServiceAccessException Service access error * @exception LockTokenNotFoundException Lock token was not found */ public void killLock(Uri uri, NodeLock lock) throws ServiceAccessException, LockTokenNotFoundException { adapter.killLock(getCurrentConnection(), uri, lock); } /** * Enumerate locks on an object. * * @return Enumeration List of locks which have been put on the subject * @exception ServiceAccessException Service access error */ public Enumeration enumerateLocks(Uri uri) throws ServiceAccessException { if (getCurrentlyActiveTransactionalResource() == null) { Connection connection = null; try { connection = getNewConnection(); return adapter.enumerateLocks(connection, uri); } catch (SQLException e) { throw new ServiceAccessException(this, e); } finally { if (connection != null) { try { if (!tmCommits) { connection.commit(); } } catch (SQLException e) { throw new ServiceAccessException(this, e); } finally { try { connection.close(); } catch (SQLException e) { getLogger().log(e, LOG_CHANNEL, Logger.WARNING); } } } } } else { return adapter.enumerateLocks(getCurrentConnection(), uri); } } // -------------------------------- RevisionDescriptorsStore Implementation /** * Retrieve the revisions informations of an object. * * @param uri Uri * @exception ServiceAccessException Service access error * @exception RevisionDescriptorNotFoundException Revision descriptor * was not found */ public NodeRevisionDescriptors retrieveRevisionDescriptors(Uri uri) throws ServiceAccessException, RevisionDescriptorNotFoundException { if (getCurrentlyActiveTransactionalResource() == null) { Connection connection = null; try { connection = getNewConnection(); return adapter.retrieveRevisionDescriptors(connection, uri); } catch (SQLException e) { throw new ServiceAccessException(this, e); } finally { if (connection != null) { try { if (!tmCommits) { connection.commit(); } } catch (SQLException e) { throw new ServiceAccessException(this, e); } finally { try { connection.close(); } catch (SQLException e) { getLogger().log(e, LOG_CHANNEL, Logger.WARNING); } } } } } else { return adapter.retrieveRevisionDescriptors(getCurrentConnection(), uri); } } /** * Create a new revision information object. * * @param uri Uri * @param revisionDescriptors Node revision descriptors * @exception ServiceAccessException Service access error */ public void createRevisionDescriptors(Uri uri, NodeRevisionDescriptors revisionDescriptors) throws ServiceAccessException { adapter.createRevisionDescriptors(getCurrentConnection(), uri, revisionDescriptors); } /** * Update revision information. * * @param uri Uri * @param revisionDescriptors Node revision descriptors * @exception ServiceAccessException Service access error * @exception RevisionDescriptorNotFoundException Revision descriptor * was not found */ public void storeRevisionDescriptors(Uri uri, NodeRevisionDescriptors revisionDescriptors) throws ServiceAccessException, RevisionDescriptorNotFoundException { adapter.storeRevisionDescriptors(getCurrentConnection(), uri, revisionDescriptors); } /** * Remove revision information. * * @param uri Uri * @exception ServiceAccessException Service access error */ public void removeRevisionDescriptors(Uri uri) throws ServiceAccessException { adapter.removeRevisionDescriptors(getCurrentConnection(), uri); } // --------------------------------- RevisionDescriptorStore Implementation /** * Retrieve an individual object's revision descriptor. * * @param uri uri * @param revisionNumber Node revision number */ public NodeRevisionDescriptor retrieveRevisionDescriptor(Uri uri, NodeRevisionNumber revisionNumber) throws ServiceAccessException, RevisionDescriptorNotFoundException { if (getCurrentlyActiveTransactionalResource() == null) { Connection connection = null; try { connection = getNewConnection(); return adapter.retrieveRevisionDescriptor(connection, uri, revisionNumber); } catch (SQLException e) { throw new ServiceAccessException(this, e); } finally { if (connection != null) { try { if (!tmCommits) { connection.commit(); } } catch (SQLException e) { throw new ServiceAccessException(this, e); } finally { try { connection.close(); } catch (SQLException e) { getLogger().log(e, LOG_CHANNEL, Logger.WARNING); } } } } } else { return adapter.retrieveRevisionDescriptor(getCurrentConnection(), uri, revisionNumber); } } /** * Create a new revision descriptor. * * @param uri Uri * @param revisionDescriptor Node revision descriptor * @exception ServiceAccessException Service access error */ public void createRevisionDescriptor(Uri uri, NodeRevisionDescriptor revisionDescriptor) throws ServiceAccessException { adapter.createRevisionDescriptor(getCurrentConnection(), uri, revisionDescriptor); } /** * Update a revision descriptor. * * @param uri Uri * @param revisionDescriptor Node revision descriptor * @exception ServiceAccessException Service access error * @exception RevisionDescriptorNotFoundException Revision descriptor * was not found */ public void storeRevisionDescriptor(Uri uri, NodeRevisionDescriptor revisionDescriptor) throws ServiceAccessException, RevisionDescriptorNotFoundException { adapter.storeRevisionDescriptor(getCurrentConnection(), uri, revisionDescriptor); } /** * Remove a revision descriptor. * * @param uri Uri * @param revisionNumber Revision number * @exception ServiceAccessException Service access error */ public void removeRevisionDescriptor(Uri uri, NodeRevisionNumber revisionNumber) throws ServiceAccessException { adapter.removeRevisionDescriptor(getCurrentConnection(), uri, revisionNumber); } // -------------------------------------------- ContentStore Implementation /** * Retrieve revision content. * * @param uri Uri * @param revisionDescriptor Node revision number */ public NodeRevisionContent retrieveRevisionContent(Uri uri, NodeRevisionDescriptor revisionDescriptor) throws ServiceAccessException, RevisionNotFoundException { if (getCurrentlyActiveTransactionalResource() == null) { Connection connection = null; try { connection = getNewConnection(); return adapter.retrieveRevisionContent(connection, uri, revisionDescriptor, true); } catch (SQLException e) { // only close connection in case of error as standard closing // will be done in adapter or upon closing of stream if (connection != null) { try { if (!tmCommits) { connection.rollback(); } } catch (SQLException e2) { throw new ServiceAccessException(this, e2); } finally { try { connection.close(); } catch (SQLException e2) { getLogger().log(e2, LOG_CHANNEL, Logger.WARNING); } } } throw new ServiceAccessException(this, e); } } else { return adapter.retrieveRevisionContent(getCurrentConnection(), uri, revisionDescriptor, false); } } /** * Create a new revision * * @param uri Uri * @param revisionDescriptor Node revision descriptor * @param revisionContent Node revision content */ public void createRevisionContent(Uri uri, NodeRevisionDescriptor revisionDescriptor, NodeRevisionContent revisionContent) throws ServiceAccessException, RevisionAlreadyExistException { adapter.createRevisionContent(getCurrentConnection(), uri, revisionDescriptor, revisionContent); } /** * Modify the latest revision of an object. * * @param uri Uri * @param revisionDescriptor Node revision descriptor * @param revisionContent Node revision content */ public void storeRevisionContent(Uri uri, NodeRevisionDescriptor revisionDescriptor, NodeRevisionContent revisionContent) throws ServiceAccessException, RevisionNotFoundException { adapter.storeRevisionContent(getCurrentConnection(), uri, revisionDescriptor, revisionContent); } /** * Remove revision. * * @param uri Uri * @param revisionDescriptor Node revision number */ public void removeRevisionContent(Uri uri, NodeRevisionDescriptor revisionDescriptor) throws ServiceAccessException { adapter.removeRevisionContent(getCurrentConnection(), uri, revisionDescriptor); } // ------------------------------------------------------ Protected Methods // XXX just for visibility in RDBMSComparableResourcesPool protected TransactionalResource getCurrentlyActiveTransactionalResource() { return super.getCurrentlyActiveTransactionalResource(); } public void start(Xid xid, int flags) throws XAException { TransactionalResource resource = getCurrentlyActiveTransactionalResource(); if (resource != null) { throw new XAException(XAException.XAER_INVAL); } if (getLoggerFacade().isFineEnabled()) { getLoggerFacade().logFine(new StringBuffer(128).append("Thread ").append(Thread.currentThread()) .append(flags == TMNOFLAGS ? " starts" : flags == TMJOIN ? " joins" : " resumes") .append(" work on behalf of transaction branch ").append(xid).toString()); } TransactionalResource ts; switch (flags) { // a new transaction case TMNOFLAGS: case TMJOIN: default: try { ts = createTransactionResource(xid); ts.begin(); } catch (Exception e) { getLoggerFacade().logSevere("Could not create new transactional resource", e); throw new XAException(e.getMessage()); } break; case TMRESUME: ts = getSuspendedTransactionalResource(xid); if (ts == null) { throw new XAException(XAException.XAER_NOTA); } ts.resume(); removeSuspendedTransactionalResource(xid); break; } setCurrentlyActiveTransactionalResource(ts); addAcitveTransactionalResource(xid, ts); } /** * Get the Connection object associated with the current transaction. */ protected Connection getCurrentConnection() throws ServiceAccessException { getLogger().log("Getting current connection for thread " + Thread.currentThread(), LOG_CHANNEL, Logger.DEBUG); TransactionId id = (TransactionId) getCurrentlyActiveTransactionalResource(); if (id == null) { getLogger().log("No id for current thread - called outside transaction?", LOG_CHANNEL, Logger.DEBUG); return null; } return id.connection; } abstract protected Connection getNewConnection() throws SQLException; protected TransactionalResource createTransactionResource(Xid xid) throws SQLException { return new TransactionId(xid); } private class TransactionId extends AbstractTransactionalResource { Xid xid; int status; Connection connection; TransactionId(Xid xid) throws SQLException { super(xid); status = STATUS_ACTIVE; connection = getNewConnection(); } public void commit() throws XAException { try { if (!tmCommits) { connection.commit(); } } catch (SQLException e) { throw new XAException(XAException.XA_RBCOMMFAIL); } finally { try { connection.close(); } catch (SQLException e) { getLogger().log(e, LOG_CHANNEL, Logger.WARNING); } } } public void rollback() throws XAException { try { if (!tmCommits) { connection.rollback(); } } catch (SQLException e) { throw new XAException(XAException.XA_RBCOMMFAIL); } finally { try { connection.close(); } catch (SQLException e) { getLogger().log(e, LOG_CHANNEL, Logger.WARNING); } } } public int prepare() throws XAException { // no check possible return XA_OK; } public void begin() throws XAException { } public void suspend() throws XAException { } public void resume() throws XAException { } } }