/*
* JBoss, Home of Professional Open Source.
* Copyright 2000 - 2008, Red Hat Middleware LLC, 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 org.jboss.cache.invocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.cache.*;
import org.jboss.cache.batch.BatchContainer;
import org.jboss.cache.buddyreplication.BuddyManager;
import org.jboss.cache.buddyreplication.GravitateResult;
import org.jboss.cache.commands.CommandsFactory;
import org.jboss.cache.commands.read.ExistsCommand;
import org.jboss.cache.commands.read.GetChildrenNamesCommand;
import org.jboss.cache.commands.read.GetDataMapCommand;
import org.jboss.cache.commands.read.GetKeyValueCommand;
import org.jboss.cache.commands.read.GetKeysCommand;
import org.jboss.cache.commands.read.GetNodeCommand;
import org.jboss.cache.commands.read.GravitateDataCommand;
import org.jboss.cache.commands.write.EvictCommand;
import org.jboss.cache.commands.write.MoveCommand;
import org.jboss.cache.commands.write.PutDataMapCommand;
import org.jboss.cache.commands.write.PutForExternalReadCommand;
import org.jboss.cache.commands.write.PutKeyValueCommand;
import org.jboss.cache.commands.write.RemoveKeyCommand;
import org.jboss.cache.commands.write.RemoveNodeCommand;
import org.jboss.cache.config.Configuration;
import org.jboss.cache.config.Configuration.NodeLockingScheme;
import org.jboss.cache.config.ConfigurationException;
import org.jboss.cache.config.Option;
import org.jboss.cache.factories.ComponentRegistry;
import org.jboss.cache.factories.annotations.Inject;
import org.jboss.cache.factories.annotations.NonVolatile;
import org.jboss.cache.factories.annotations.Start;
import org.jboss.cache.interceptors.base.CommandInterceptor;
import org.jboss.cache.loader.CacheLoaderManager;
import org.jboss.cache.marshall.Marshaller;
import org.jboss.cache.mvcc.MVCCNodeHelper;
import org.jboss.cache.notifications.Notifier;
import org.jboss.cache.statetransfer.StateTransferManager;
import org.jboss.cache.transaction.GlobalTransaction;
import org.jboss.cache.transaction.TransactionTable;
import org.jboss.cache.util.Immutables;
import org.jgroups.Address;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Iterator;
/**
* The delegate that users (and ChainedInterceptor authors) interact with when they create a cache by using a cache factory.
* This wrapper delegates calls down the interceptor chain.
*
* @author Manik Surtani (manik AT jboss DOT org)
* @since 2.1.0
*/
@NonVolatile
public class CacheInvocationDelegate extends AbstractInvocationDelegate implements CacheSPI
{
private static final Log log = LogFactory.getLog(CacheInvocationDelegate.class);
// this stuff is needed since the SPI has methods to retrieve these.
private StateTransferManager stateTransferManager;
private CacheLoaderManager cacheLoaderManager;
private Notifier notifier;
private TransactionManager transactionManager;
private BuddyManager buddyManager;
private TransactionTable transactionTable;
private RPCManager rpcManager;
private RegionManager regionManager;
private Marshaller marshaller;
private DataContainer dataContainer;
private CommandsFactory commandsFactory;
private MVCCNodeHelper mvccHelper;
private boolean usingMvcc;
private BatchContainer batchContainer;
@Inject
public void initialize(StateTransferManager stateTransferManager, CacheLoaderManager cacheLoaderManager, Notifier notifier,
TransactionManager transactionManager, BuddyManager buddyManager, TransactionTable transactionTable,
RPCManager rpcManager, RegionManager regionManager, Marshaller marshaller,
CommandsFactory commandsFactory, DataContainer dataContainer, MVCCNodeHelper mvccHelper, BatchContainer batchContainer)
{
this.stateTransferManager = stateTransferManager;
this.cacheLoaderManager = cacheLoaderManager;
this.notifier = notifier;
this.transactionManager = transactionManager;
this.buddyManager = buddyManager;
this.transactionTable = transactionTable;
this.rpcManager = rpcManager;
this.regionManager = regionManager;
this.marshaller = marshaller;
this.dataContainer = dataContainer;
this.commandsFactory = commandsFactory;
this.mvccHelper = mvccHelper;
this.batchContainer = batchContainer;
}
@Start
void setNodeLockingScheme()
{
usingMvcc = configuration.getNodeLockingScheme() == NodeLockingScheme.MVCC;
}
private void reset()
{
this.usingMvcc = false;
this.stateTransferManager = null;
this.cacheLoaderManager = null;
this.transactionManager = null;
this.buddyManager = null;
this.transactionTable = null;
this.rpcManager = null;
this.marshaller = null;
this.dataContainer = null;
this.commandsFactory = null;
}
@Override
public String toString()
{
return dataContainer == null ? super.toString() : dataContainer.toString();
}
public Configuration getConfiguration()
{
return configuration;
}
public NodeSPI getRoot()
{
return getNode(Fqn.ROOT);
}
public TransactionManager getTransactionManager()
{
return transactionManager;
}
public void addInterceptor(CommandInterceptor i, int position)
{
invoker.addInterceptor(i, position);
}
public void addInterceptor(CommandInterceptor i, Class extends CommandInterceptor> afterInterceptor)
{
invoker.addAfterInterceptor(i, afterInterceptor);
}
public List getInterceptorChain()
{
return invoker.asList();
}
public void removeInterceptor(int position)
{
invoker.removeInterceptor(position);
}
public void removeInterceptor(Class extends CommandInterceptor> interceptorType)
{
invoker.removeInterceptor(interceptorType);
}
public CacheLoaderManager getCacheLoaderManager()
{
return cacheLoaderManager;
}
public BuddyManager getBuddyManager()
{
return buddyManager;
}
public TransactionTable getTransactionTable()
{
return transactionTable;
}
public RPCManager getRPCManager()
{
return rpcManager;
}
public StateTransferManager getStateTransferManager()
{
return stateTransferManager;
}
public String getClusterName()
{
return configuration.getClusterName();
}
public int getNumberOfAttributes()
{
return dataContainer.getNumberOfAttributes();
}
public int getNumberOfNodes()
{
return dataContainer.getNumberOfNodes();
}
public RegionManager getRegionManager()
{
return regionManager;
}
public GlobalTransaction getCurrentTransaction(Transaction tx, boolean createIfNotExists)
{
return transactionTable.getCurrentTransaction(tx, createIfNotExists);
}
public GlobalTransaction getCurrentTransaction()
{
return transactionTable.getCurrentTransaction();
}
public Set getInternalFqns()
{
return dataContainer.getInternalFqns();
}
public int getNumberOfLocksHeld()
{
return dataContainer.getNumberOfLocksHeld();
}
public boolean exists(String fqn)
{
return exists(Fqn.fromString(fqn));
}
public boolean exists(Fqn fqn)
{
if (usingMvcc)
{
InvocationContext ctx = invocationContextContainer.get();
cacheStatusCheck(ctx);
ExistsCommand command = commandsFactory.buildExistsNodeCommand(fqn);
return (Boolean) invoker.invoke(ctx, command);
}
else
{
return peek(fqn, false) != null;
}
}
public Notifier getNotifier()
{
return notifier;
}
public Marshaller getMarshaller()
{
return marshaller;
}
public GravitateResult gravitateData(Fqn fqn, boolean searchBuddyBackupSubtrees, InvocationContext ctx)
{
cacheStatusCheck(ctx);
GravitateDataCommand command = commandsFactory.buildGravitateDataCommand(fqn, searchBuddyBackupSubtrees);
return (GravitateResult) invoker.invoke(ctx, command);
}
@SuppressWarnings("unchecked")
public NodeSPI peek(Fqn fqn, boolean includeDeletedNodes, boolean includeInvalidNodes)
{
// TODO: clean this up somehow! Anyway, this method should NOT be used outside of testing frameworks.
return (usingMvcc)
? mvccPeek(fqn)
: (NodeSPI) dataContainer.peek(fqn, includeDeletedNodes, includeInvalidNodes);
}
@SuppressWarnings("unchecked")
public NodeSPI peek(Fqn fqn, boolean includeDeletedNodes)
{
// TODO: clean this up somehow! Anyway, this method should NOT be used outside of testing frameworks.
return (usingMvcc)
? mvccPeek(fqn)
: (NodeSPI) dataContainer.peek(fqn, includeDeletedNodes);
}
@SuppressWarnings("unchecked")
private NodeSPI mvccPeek(Fqn f)
{
NodeSPI n;
try
{
n = mvccHelper.wrapNodeForReading(getInvocationContext(), f, false);
}
catch (InterruptedException e)
{
throw new CacheException(e);
}
if (n == null || n.isNullNode()) return null;
return n;
}
public void addCacheListener(Object listener)
{
notifier.addCacheListener(listener);
}
public void removeCacheListener(Object listener)
{
notifier.removeCacheListener(listener);
}
public Set