Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* HA-JDBC: High-Availability JDBC
* Copyright (C) 2012 Paul Ferraro
*
* This program 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 3 of the License, or
* (at your option) any later version.
*
* This program 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 program. If not, see .
*/
package net.sf.hajdbc.sql.xa;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.SortedMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.Lock;
import javax.sql.XAConnection;
import javax.sql.XADataSource;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
import net.sf.hajdbc.Database;
import net.sf.hajdbc.DatabaseCluster;
import net.sf.hajdbc.durability.Durability;
import net.sf.hajdbc.invocation.InvocationStrategies;
import net.sf.hajdbc.invocation.InvocationStrategy;
import net.sf.hajdbc.invocation.Invoker;
import net.sf.hajdbc.sql.ChildInvocationHandler;
import net.sf.hajdbc.sql.DurabilityPhaseRegistry;
import net.sf.hajdbc.sql.ProxyFactory;
import net.sf.hajdbc.util.StaticRegistry;
import net.sf.hajdbc.util.reflect.Methods;
/**
* @author Paul Ferraro
*
*/
@SuppressWarnings("nls")
public class XAResourceInvocationHandler extends ChildInvocationHandler
{
private static final Set driverReadMethodSet = Methods.findMethods(XAResource.class, "getTransactionTimeout", "isSameRM");
private static final Set databaseWriteMethodSet = Methods.findMethods(XAResource.class, "setTransactionTimeout");
private static final Set intraTransactionMethodSet = Methods.findMethods(XAResource.class, "prepare", "end", "recover");
private static final Method prepareMethod = Methods.getMethod(XAResource.class, "prepare", Xid.class);
private static final Method startMethod = Methods.getMethod(XAResource.class, "start", Xid.class, Integer.TYPE);
private static final Method commitMethod = Methods.getMethod(XAResource.class, "commit", Xid.class, Boolean.TYPE);
private static final Method rollbackMethod = Methods.getMethod(XAResource.class, "rollback", Xid.class);
private static final Method forgetMethod = Methods.getMethod(XAResource.class, "forget", Xid.class);
private static final Set endTransactionMethodSet = new HashSet(Arrays.asList(commitMethod, rollbackMethod, forgetMethod));
private static final StaticRegistry phaseRegistry = new DurabilityPhaseRegistry(Arrays.asList(prepareMethod), Arrays.asList(commitMethod), Arrays.asList(rollbackMethod), Arrays.asList(forgetMethod));
// Xids are global - so store in static variable
private static final ConcurrentMap lockMap = new ConcurrentHashMap();
public XAResourceInvocationHandler(XAResourceProxyFactory proxyFactory)
{
super(XAResource.class, proxyFactory, null);
}
/**
* @see net.sf.hajdbc.sql.AbstractInvocationHandler#getInvocationStrategy(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
*/
@Override
protected InvocationStrategy getInvocationStrategy(XAResource resource, Method method, Object... parameters) throws XAException
{
if (driverReadMethodSet.contains(method))
{
return InvocationStrategies.INVOKE_ON_ANY;
}
if (databaseWriteMethodSet.contains(method))
{
return InvocationStrategies.INVOKE_ON_ALL;
}
boolean start = method.equals(startMethod);
boolean end = endTransactionMethodSet.contains(method);
if (start || end || method.equals(prepareMethod) || intraTransactionMethodSet.contains(method))
{
final InvocationStrategy strategy = end ? InvocationStrategies.END_TRANSACTION_INVOKE_ON_ALL : InvocationStrategies.TRANSACTION_INVOKE_ON_ALL;
Xid xid = (Xid) parameters[0];
DatabaseCluster cluster = this.getProxyFactory().getDatabaseCluster();
if (start)
{
final Lock lock = cluster.getLockManager().readLock(null);
// Lock may already exist if we're resuming a suspended transaction
if (lockMap.putIfAbsent(xid, lock) == null)
{
return new InvocationStrategy()
{
@Override
public , T, R, E extends Exception> SortedMap invoke(ProxyFactory proxy, Invoker invoker) throws E
{
lock.lock();
try
{
return strategy.invoke(proxy, invoker);
}
catch (Exception e)
{
lock.unlock();
throw proxy.getExceptionFactory().createException(e);
}
}
};
}
}
Durability.Phase phase = phaseRegistry.get(method);
if (phase != null)
{
final InvocationStrategy durabilityStrategy = cluster.getDurability().getInvocationStrategy(strategy, phase, xid);
if (endTransactionMethodSet.contains(method))
{
final Lock lock = lockMap.remove(xid);
return new InvocationStrategy()
{
@Override
public , T, R, E extends Exception> SortedMap invoke(ProxyFactory proxy, Invoker invoker) throws E
{
try
{
return durabilityStrategy.invoke(proxy, invoker);
}
finally
{
if (lock != null)
{
lock.unlock();
}
}
}
};
}
return durabilityStrategy;
}
return strategy;
}
return super.getInvocationStrategy(resource, method, parameters);
}
/**
* {@inheritDoc}
* @see net.sf.hajdbc.sql.AbstractInvocationHandler#getInvoker(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
*/
@Override
protected Invoker getInvoker(XAResource object, Method method, Object... parameters) throws XAException
{
Invoker invoker = super.getInvoker(object, method, parameters);
Durability.Phase phase = phaseRegistry.get(method);
if (method.equals(prepareMethod) || endTransactionMethodSet.contains(method))
{
return this.getProxyFactory().getDatabaseCluster().getDurability().getInvoker(invoker, phase, parameters[0], this.getProxyFactory().getExceptionFactory());
}
return invoker;
}
@Override
protected void postInvoke(Invoker invoker, XAResource proxy, Method method, Object... parameters)
{
if (databaseWriteMethodSet.contains(method))
{
this.getProxyFactory().record(invoker);
}
}
}