/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt 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.web.tomcat.service.session.distributedcache.impl.jbc;
import java.io.IOException;
import java.io.Serializable;
import java.security.AccessController;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.transaction.TransactionManager;
import org.jboss.cache.Cache;
import org.jboss.cache.CacheException;
import org.jboss.cache.CacheManager;
import org.jboss.cache.CacheStatus;
import org.jboss.cache.Fqn;
import org.jboss.cache.Node;
import org.jboss.cache.Region;
import org.jboss.cache.buddyreplication.BuddyManager;
import org.jboss.cache.config.CacheLoaderConfig;
import org.jboss.cache.config.CacheLoaderConfig.IndividualCacheLoaderConfig;
import org.jboss.cache.transaction.BatchModeTransactionManager;
import org.jboss.ha.framework.server.MarshalledValueHelper;
import org.jboss.ha.framework.server.SimpleCachableMarshalledValue;
import org.jboss.logging.Logger;
import org.jboss.util.loading.ContextClassLoaderSwitcher;
import org.jboss.web.tomcat.service.session.distributedcache.spi.BatchingManager;
import org.jboss.web.tomcat.service.session.distributedcache.spi.ClusteringNotSupportedException;
import org.jboss.web.tomcat.service.session.distributedcache.spi.DistributableSessionMetadata;
import org.jboss.web.tomcat.service.session.distributedcache.spi.DistributedCacheManager;
import org.jboss.web.tomcat.service.session.distributedcache.spi.IncomingDistributableSessionData;
import org.jboss.web.tomcat.service.session.distributedcache.spi.LocalDistributableSessionManager;
import org.jboss.web.tomcat.service.session.distributedcache.spi.OutgoingDistributableSessionData;
import org.jboss.web.tomcat.service.session.distributedcache.spi.SessionSerializationFactory;
/**
* Abstract base implementation of {@link DistributedCacheManager}.
*/
public abstract class AbstractJBossCacheService<T extends OutgoingDistributableSessionData> implements DistributedCacheManager<T>
{
public static final String BUDDY_BACKUP = BuddyManager.BUDDY_BACKUP_SUBTREE;
@SuppressWarnings("unchecked")
public static final Fqn<String> BUDDY_BACKUP_FQN = BuddyManager.BUDDY_BACKUP_SUBTREE_FQN;
public static final String SESSION = "JSESSION";
public static final String DEAD_BUDDY_SUFFIX = ":DEAD";
// Use Integers as JBC keys -- replication performant but won't be
// confused with String attribute keys for ATTRIBUTE granularity sessions
// Alternative is an enum, but then we replicate a long classname
public static final Integer VERSION_KEY = Integer.valueOf(0);
public static final Integer TIMESTAMP_KEY = Integer.valueOf(1);
public static final Integer METADATA_KEY = Integer.valueOf(2);
public static final Integer ATTRIBUTE_KEY = Integer.valueOf(3);
protected static final Set<Integer> INTERNAL_KEYS = new HashSet<Integer>(Arrays.asList(VERSION_KEY, TIMESTAMP_KEY, METADATA_KEY, ATTRIBUTE_KEY));
public static final String FQN_DELIMITER = "/";
public static String getCombinedPath(String hostname, String contextPath)
{
return contextPath + "_" + hostname;
}
public static Fqn<String> getSessionFqn(String contextHostPath, String sessionId)
{
return Fqn.fromElements(SESSION, contextHostPath, sessionId);
}
@Deprecated
public static Fqn<String> getBuddyBackupSessionFqn(String dataOwner, String contextHostPath, String sessionId)
{
return Fqn.fromElements(BUDDY_BACKUP, dataOwner, SESSION, contextHostPath, sessionId);
}
@SuppressWarnings("unchecked")
private static ContextClassLoaderSwitcher getContextClassLoaderSwitcher()
{
return (ContextClassLoaderSwitcher) AccessController.doPrivileged(ContextClassLoaderSwitcher.INSTANTIATOR);
}
protected Logger log_ = Logger.getLogger(getClass());
private CacheManager cacheManager_;
private Cache<Object, Object> plainCache_;
/** Context path for webapp + hostName; this + session id is a unique combo. */
protected String combinedPath_;
protected BatchingManager batchingManager;
private LocalDistributableSessionManager manager_;
private ClassLoader webAppClassLoader_;
private CacheListener cacheListener_;
protected JBossCacheWrapper cacheWrapper_;
/** Do we have to marshall attributes ourself or can we let JBC do it? */
private boolean useTreeCacheMarshalling_ = false;
/** Are we configured for passivation? */
private boolean usePassivation_ = false;
private PassivationListener passivationListener_;
/** Is cache configured for buddy replication? */
private boolean useBuddyReplication_ = false;
protected String cacheConfigName_;
private boolean purgeOnStartStop_ = true;
protected AbstractJBossCacheService(LocalDistributableSessionManager localManager) throws ClusteringNotSupportedException
{
if (localManager == null)
{
throw new IllegalArgumentException("localManager is null");
}
this.manager_ = localManager;
establishCacheManager();
this.cacheConfigName_ = Util.getCacheConfigName(localManager);
}
protected AbstractJBossCacheService(LocalDistributableSessionManager localManager, Cache<Object, Object> cache)
{
if (localManager == null)
{
throw new IllegalArgumentException("localManager is null");
}
if (cache == null)
{
throw new IllegalArgumentException("cache is null");
}
this.manager_ = localManager;
this.plainCache_ = cache;
}
protected LocalDistributableSessionManager getManager()
{
return manager_;
}
protected Cache<Object, Object> getCache()
{
return plainCache_;
}
protected void setCache(Cache<Object, Object> cache)
{
this.plainCache_ = cache;
}
public void start()
{
establishCache();
this.webAppClassLoader_ = this.manager_.getApplicationClassLoader();
String webAppPath;
String path = manager_.getContextName();
if( path.length() == 0 || path.equals("/")) {
// If this is root.
webAppPath = "ROOT";
} else if ( path.startsWith("/") ) {
webAppPath = path.substring(1);
} else {
webAppPath = path;
}
// JBAS-3941 -- context path can be multi-level, but we don't
// want that turning into a multilevel Fqn, so escape it
// Use '-' which is legal in a filesystem path
webAppPath = webAppPath.replace('/', '_');
log_.debug("Old and new web app path are: " +path + ", " +webAppPath);
String hostName;
String host = manager_.getHostName();
if( host == null || host.length() == 0) {
hostName = "localhost";
}else {
hostName = host;
}
log_.debug("Old and new virtual host name are: " + host + ", " + hostName);
this.combinedPath_ = getCombinedPath(hostName, webAppPath);
if (plainCache_.getCacheStatus() != CacheStatus.STARTED)
{
plainCache_.start();
}
// We require the cache batchingManager to be BatchModeTransactionManager now.
TransactionManager tm = plainCache_.getConfiguration().getRuntimeConfig().getTransactionManager();
if( ! (tm instanceof BatchModeTransactionManager) )
{
throw new RuntimeException("start(): JBoss Cache transaction manager " +
"is not of type BatchModeTransactionManager. " +
"It is " + (tm == null ? "null" : tm.getClass().getName()));
}
this.batchingManager = new BatchingManagerImpl(tm);
Fqn<String> pathFqn = Fqn.fromElements(SESSION, combinedPath_);
// if (useTreeCacheMarshalling_ || this.useBuddyReplication_)
if (this.purgeOnStartStop_)
{
// JBAS-5628/JBAS-5629 -- clean out persistent store
cleanWebappRegion(pathFqn);
}
// Listen for cache changes
cacheListener_ = new CacheListener(cacheWrapper_, manager_, combinedPath_,
Util.getReplicationGranularity(manager_));
plainCache_.addCacheListener(cacheListener_);
if(useTreeCacheMarshalling_)
{
// register the tcl and bring over the state for the webapp
try
{
log_.debug("UseMarshalling is true. We will register the fqn: " +
pathFqn + " with class loader" +webAppClassLoader_ +
" and activate the webapp's Region");
Node<Object, Object> root = plainCache_.getRoot();
if (root.hasChild(pathFqn) == false)
{
plainCache_.getInvocationContext().getOptionOverrides().setCacheModeLocal(true);
root.addChild(pathFqn);
}
Region region = plainCache_.getRegion(pathFqn, true);
region.registerContextClassLoader(webAppClassLoader_);
region.activate();
}
catch (Exception ex)
{
throw new RuntimeException("Can't register class loader", ex);
}
}
if(manager_.isPassivationEnabled())
{
log_.debug("Passivation is enabled");
passivationListener_ = new PassivationListener(manager_, combinedPath_);
plainCache_.addCacheListener(passivationListener_);
}
else
{
log_.debug("Passivation is disabled");
}
}
public void stop()
{
plainCache_.removeCacheListener(cacheListener_);
if (passivationListener_ != null)
plainCache_.removeCacheListener(passivationListener_);
// Construct the fqn
Fqn<String> pathFqn = Fqn.fromElements(SESSION, combinedPath_);
if(useTreeCacheMarshalling_)
{
log_.debug("UseMarshalling is true. We will inactivate the fqn: " +
pathFqn + " and un-register its classloader");
try {
Region region = plainCache_.getRegion(pathFqn, false);
if (region != null)
{
region.deactivate();
region.unregisterContextClassLoader();
}
}
catch (Exception e)
{
log_.error("Exception during inactivation of webapp region " + pathFqn +
" or un-registration of its class loader", e);
}
}
// if (useTreeCacheMarshalling_ || this.useBuddyReplication_)
if (this.purgeOnStartStop_)
{
// JBAS-5628/JBAS-5629 -- clean out persistent store
cleanWebappRegion(pathFqn);
}
// remove session data
// BES 2007/08/18 Can't do this as it will
// 1) blow away passivated sessions
// 2) leave the cache in an inconsistent state if the war
// is restarted
// cacheWrapper_.removeLocalSubtree(pathFqn);
this.webAppClassLoader_ = null;
if (cacheConfigName_ != null)
{
releaseCacheToManager(cacheConfigName_);
}
}
/**
* Get specfically the BatchModeTransactionManager.
*/
public BatchingManager getBatchingManager()
{
return batchingManager;
}
/**
* Gets whether TreeCache-based marshalling is available
*/
public boolean isMarshallingAvailable()
{
return useTreeCacheMarshalling_;
}
public void sessionCreated(String realId)
{
// no-op by default
}
public IncomingDistributableSessionData getSessionData(String realId, boolean initialLoad)
{
if (realId == null)
{
throw new IllegalArgumentException("Null realId");
}
Fqn<String> fqn = getSessionFqn(combinedPath_, realId);
boolean ourBatch = false;
boolean loadCompleted = false;
Map<Object, Object> sessionData = null;
try
{
// We need batching so any data gravitation replication
// is sent in batch.
// Don't do anything if there is already a batch
// associated with this thread.
ourBatch = ensureBatchInProgress();
sessionData = cacheWrapper_.getData(fqn, true);
if (sessionData == null) {
// Requested session is no longer in the cache; return null
return null;
}
if (initialLoad)
{
setupSessionRegion(fqn);
}
IncomingDistributableSessionData dsd = null;
try
{
dsd = getDistributableSessionData(realId, sessionData, true);
}
catch (Exception e)
{
String masked = Util.maskId(realId);
log_.warn("Problem accessing session data for session " + masked + " (" +
e.getClass().getName() + ") -- existing session cannot be used");
log_.debug("Details on problem accessing session data for " + masked, e);
// Clean up
removeSessionLocal(realId);
return null;
}
loadCompleted = true;
return dsd;
}
catch (Exception e)
{
throw handleBatchException(ourBatch, realId, e);
}
finally
{
if (ourBatch)
{
finishBatch(realId, loadCompleted);
}
}
}
public void storeSessionData(T sessionData)
{
String realId = sessionData.getRealId();
if (log_.isTraceEnabled())
{
log_.trace("putSession(): putting session " + Util.maskId(realId));
}
Fqn<String> fqn = getSessionFqn(combinedPath_, realId);
Map<Object, Object> map = new HashMap<Object, Object>();
map.put(VERSION_KEY, Integer.valueOf(sessionData.getVersion()));
DistributableSessionMetadata dsm = sessionData.getMetadata();
if (dsm != null)
{
map.put(METADATA_KEY, dsm);
}
Long timestamp = sessionData.getTimestamp();
if (timestamp != null)
{
map.put(TIMESTAMP_KEY, timestamp);
}
storeSessionAttributes(map, sessionData);
cacheWrapper_.put(fqn, map);
}
protected void establishCacheManager() throws ClusteringNotSupportedException
{
this.cacheManager_ = Util.findPlainCacheManager();
}
protected void establishCache()
{
if (this.plainCache_ == null)
{
obtainCacheFromManager();
}
this.cacheWrapper_ = new JBossCacheWrapper(plainCache_);
this.useTreeCacheMarshalling_ = plainCache_.getConfiguration().isUseRegionBasedMarshalling();
boolean purge = true;
CacheLoaderConfig clc = plainCache_.getConfiguration().getCacheLoaderConfig();
if(clc != null)
{
usePassivation_ = (clc.isPassivation() && !clc.isShared());
purge = false;
for (IndividualCacheLoaderConfig iclc : clc.getIndividualCacheLoaderConfigs())
{
if (iclc.isPurgeOnStartup())
{
purge = true;
break;
}
}
}
this.purgeOnStartStop_ = purge && (this.useBuddyReplication_ || this.useTreeCacheMarshalling_);
}
protected void obtainCacheFromManager()
{
if (this.cacheManager_ == null)
{
throw new IllegalStateException("No CacheManager available");
}
if (this.cacheConfigName_ == null)
{
throw new IllegalStateException("No cache configuration name available");
}
this.plainCache_ = Util.findPlainCache(this.cacheConfigName_, this.cacheManager_);
}
/**
* Extension point to allow subclasses to add per-session JBC regions.
*
* @param session the session
* @param fqn the fqn for the session
*/
protected void setupSessionRegion(Fqn<String> fqn)
{
}
protected abstract void storeSessionAttributes(Map<Object, Object> dataMap, T sessionData);
/**
* Extension point to allow subclasses to remove per-session JBC regions.
*
* @param session the session
* @param fqn the fqn for the session
*/
protected void removeSessionRegion(String realId, Fqn<String> fqn)
{
}
public void removeSession(String realId)
{
Fqn<String> fqn = getSessionFqn(combinedPath_, realId);
if (log_.isTraceEnabled())
{
log_.trace("Remove session " + Util.maskId(realId) + " from " +
"distributed store. Parent Fqn: " + fqn.getParent());
}
cacheWrapper_.remove(fqn);
removeSessionRegion(realId, fqn);
}
public void removeSessionLocal(String realId)
{
Fqn<String> fqn = getSessionFqn(combinedPath_, realId);
if (log_.isTraceEnabled())
{
log_.trace("Removing session " + Util.maskId(realId) + " from my " +
"own distributed store only. Parent Fqn: " + fqn.getParent());
}
cacheWrapper_.removeLocal(fqn);
removeSessionRegion(realId, fqn);
}
public void removeSessionLocal(String realId, String dataOwner)
{
if (dataOwner == null)
{
removeSessionLocal(realId);
}
else
{
List<Fqn<Object>> fqns = getBuddyBackupSessionFqns(dataOwner, combinedPath_, realId);
for (Fqn<Object> fqn : fqns)
{
if (log_.isTraceEnabled())
{
log_.trace("Removing session " + Util.maskId(realId) + " from my " +
"own distributed store only. Parent Fqn: " + fqn.getParent());
}
cacheWrapper_.removeLocal(fqn);
}
}
}
public void evictSession(String realId)
{
Fqn<String> fqn = getSessionFqn(combinedPath_, realId);
if(log_.isTraceEnabled())
{
log_.trace("evictSession(): evicting session " + Util.maskId(realId) +
" from distributed store. Parent Fqn: " + fqn.getParent());
}
cacheWrapper_.evictSubtree(fqn);
}
public void evictSession(String realId, String dataOwner)
{
if (dataOwner == null)
{
evictSession(realId);
}
else
{
List<Fqn<Object>> fqns = getBuddyBackupSessionFqns(dataOwner, combinedPath_, realId);
for (Fqn<Object> fqn : fqns)
{
if(log_.isTraceEnabled())
{
log_.trace("evictSession(): evicting session " + Util.maskId(realId) +
" from distributed store. Parent Fqn: " + fqn.getParent());
}
cacheWrapper_.evictSubtree(fqn);
}
}
}
public IncomingDistributableSessionData getSessionData(String realId, String dataOwner, boolean includeAttributes)
{
boolean ourBatch = false;
boolean loadCompleted = false;
try
{
ourBatch = ensureBatchInProgress();
Map<Object, Object> distributedCacheData = null;
if (dataOwner == null)
{
Fqn<String> fqn = getSessionFqn(combinedPath_, realId);
distributedCacheData = cacheWrapper_.getData(fqn, false);
}
else
{
List<Fqn<Object>> fqns = getBuddyBackupSessionFqns(dataOwner, combinedPath_, realId);
for (Fqn<Object> fqn : fqns)
{
distributedCacheData = cacheWrapper_.getData(fqn, false);
if (distributedCacheData != null && distributedCacheData.size() > 0)
{
break;
}
}
}
IncomingDistributableSessionData result = distributedCacheData == null ? null : getDistributableSessionData(realId, distributedCacheData, includeAttributes);
loadCompleted = true;
return result;
}
catch (Exception e)
{
throw handleBatchException(ourBatch, realId, e);
}
finally
{
if (ourBatch)
{
finishBatch(realId, loadCompleted);
}
}
}
/**
* Gets the ids of all sessions in the underlying cache.
*
* @return Map<String, String> containing all of the session ids of sessions in the cache
* (with any jvmRoute removed) as keys, and the identifier of the data owner for
* the session as value (or a <code>null</code> value if buddy
* replication is not enabled.) Will not return <code>null</code>.
*/
public Map<String, String> getSessionIds()
{
Map<String, String> result = new HashMap<String, String>();
Fqn<String> webappFqn = getWebappFqn();
Node<Object, Object> bbRoot = plainCache_.getRoot().getChild(BUDDY_BACKUP_FQN);
if (bbRoot != null)
{
Set<Node<Object, Object>> owners = bbRoot.getChildren();
if (owners != null)
{
for (Node<Object, Object> owner : owners)
{
@SuppressWarnings("unchecked")
Fqn<String> ownerFqn = owner.getFqn();
if (Util.isBuddyOwnerDead(ownerFqn))
{
for (Node<Object, Object> ownerVersion : owner.getChildren())
{
storeSessionIdsForOwner(ownerVersion, webappFqn, result);
}
}
else
{
storeSessionIdsForOwner(owner, webappFqn, result);
}
}
}
}
storeSessionOwners(getChildrenNames(webappFqn), null, result);
return result;
}
protected Set<String> getChildrenNames(Fqn<String> fqn)
{
Node<Object, Object> node = plainCache_.getRoot().getChild(fqn);
@SuppressWarnings("unchecked")
Set<String> children = (node == null ? Collections.EMPTY_SET : node.getChildrenNames());
return children;
}
private void storeSessionIdsForOwner(Node<Object, Object> owner, Fqn<String> webappFqn, Map<String, String> result)
{
@SuppressWarnings("unchecked")
Node webRoot = owner.getChild(webappFqn);
if (webRoot != null)
{
@SuppressWarnings("unchecked")
Set<String> ids = webRoot.getChildrenNames();
@SuppressWarnings("unchecked")
String ownerName = Util.getBuddyOwner(owner.getFqn());
storeSessionOwners(ids, ownerName, result);
}
}
private void storeSessionOwners(Set<String> ids, String owner, Map<String, String> map)
{
if (ids != null)
{
for (String id : ids)
{
map.put(id, owner);
}
}
}
public boolean isPassivationEnabled()
{
return usePassivation_;
}
public void setForceSynchronous(boolean forceSynchronous)
{
this.cacheWrapper_.setForceSynchronous(forceSynchronous);
}
protected Fqn<String> getWebappFqn()
{
// /SESSION/webAppPath_hostName
return Fqn.fromElements(SESSION, combinedPath_);
}
/**
* Extracts the contents of <code>distributedCacheData</code>.
*
* <strong>Note:</strong> This operation may alter the contents of the
* passed in map. If this is unacceptable, pass in a defensive copy.
*/
protected IncomingDistributableSessionData getDistributableSessionData(String realId,
Map<Object, Object> distributedCacheData,
boolean includeAttributes)
{
Integer version = (Integer) distributedCacheData.get(VERSION_KEY);
Long timestamp = (Long) distributedCacheData.get(TIMESTAMP_KEY);
DistributableSessionMetadata metadata = (DistributableSessionMetadata) distributedCacheData.get(METADATA_KEY);
IncomingDistributableSessionData result = null;
if (includeAttributes)
{
Map<String, Object> attrs = getSessionAttributes(realId, distributedCacheData);
result = new IncomingDistributableSessionDataImpl(version, timestamp, metadata, attrs);
}
else
{
result = new IncomingDistributableSessionDataImpl(version, timestamp, metadata);
}
return result;
}
/**
* Returns the session attributes, possibly using the passed in
* <code>distributedCacheData</code> as a source.
*
* <strong>Note:</strong> This operation may alter the contents of the
* passed in map. If this is unacceptable, pass in a defensive copy.
*/
protected abstract Map<String, Object> getSessionAttributes(String realId, Map<Object, Object> distributedCacheData);
protected void releaseCacheToManager(String cacheConfigName)
{
try
{
this.cacheManager_.releaseCache(cacheConfigName);
}
catch (Exception e)
{
log_.error("Problem releasing cache to CacheManager -- config is " + cacheConfigName, e);
}
finally
{
this.plainCache_ = null;
}
}
protected Object getMarshalledValue(Object value)
{
// JBAS-2920. For now, continue using MarshalledValue, as
// it allows lazy deserialization of the attribute on remote nodes
// For Branch_4_0 this is what we have to do anyway for backwards
// compatibility. For HEAD we'll follow suit for now.
// TODO consider only using MV for complex objects (i.e. not primitives)
// and Strings longer than X.
// if (useTreeCacheMarshalling_)
// {
// return value;
// }
// else
// {
// JBAS-2921 - replaced MarshalledValue calls with SessionSerializationFactory calls
// to allow for switching between JBossSerialization and JavaSerialization using
// system property -D=session.serialization.jboss=true / false
// MarshalledValue mv = new MarshalledValue(value);
if (MarshalledValueHelper.isTypeExcluded(value.getClass()))
{
return value;
}
else
{
try
{
return new SimpleCachableMarshalledValue((Serializable) value, SessionSerializationFactory.getObjectStreamSource(), true);
}
catch (ClassCastException e)
{
throw new IllegalArgumentException(value + " does not implement java.io.Serializable");
}
}
// }
}
protected Object getUnMarshalledValue(Object obj) throws IOException, ClassNotFoundException
{
if (!(obj instanceof SimpleCachableMarshalledValue))
return obj;
// Swap in/out the tcl for this web app. Needed only for un marshalling.
ContextClassLoaderSwitcher.SwitchContext switcher = null;
try
{
switcher = getContextClassLoaderSwitcher().getSwitchContext();
switcher.setClassLoader(webAppClassLoader_);
SimpleCachableMarshalledValue mv = (SimpleCachableMarshalledValue) obj;
mv.setObjectStreamSource(SessionSerializationFactory.getObjectStreamSource());
return mv.get();
}
finally
{
if (switcher != null)
{
switcher.reset();
}
}
}
private List<Fqn<Object>> getBuddyBackupSessionFqns(String dataOwner, String contextHostPath, String sessionId)
{
List<Fqn<Object>> result = new ArrayList<Fqn<Object>>();
// First, just assume a non-dead tree exists
result.add(Fqn.fromElements((Object) BUDDY_BACKUP, dataOwner, SESSION, contextHostPath, sessionId));
// Now append any "dead" trees associated with this owner
String deadBuddy = dataOwner + DEAD_BUDDY_SUFFIX;
Fqn<String> dead = Fqn.fromElements(BUDDY_BACKUP, deadBuddy);
Set<Object> buddies = plainCache_.getChildrenNames(dead); // won't return null
for (Object child : buddies)
{
result.add(Fqn.fromElements(BUDDY_BACKUP, deadBuddy, child, SESSION, contextHostPath, sessionId));
}
return result;
}
private void cleanWebappRegion(Fqn<String> regionFqn)
{
try {
// Remove locally.
plainCache_.getInvocationContext().getOptionOverrides().setCacheModeLocal(true);
plainCache_.removeNode(regionFqn);
}
catch (CacheException e)
{
String msg = e.getLocalizedMessage();
log_.error("Can't clean content from the underlying distributed cache -- " +
e.getClass().getName() + (msg == null ? "" : " " + msg));
}
}
private boolean ensureBatchInProgress() throws Exception
{
boolean newBatch = false;
if (batchingManager.isBatchInProgress() == false)
{
batchingManager.startBatch();
newBatch = true;
}
return newBatch;
}
private RuntimeException handleBatchException(boolean ourBatch, String realId, Exception e)
{
try
{
// if(ourBatch)
// Let's set it no matter what.
batchingManager.setBatchRollbackOnly();
}
catch (Exception exn)
{
log_.error("Caught exception rolling back transaction", exn);
}
return Util.getRuntimeException("Failed to load session " + Util.maskId(realId), e);
}
private void finishBatch(String realId, boolean loadCompleted)
{
try
{
batchingManager.endBatch();
}
catch (Exception e)
{
if (loadCompleted)
{
// We read the data successfully but then failed in commit?
// That indicates a JBC data gravitation where the replication of
// the gravitated data to our buddy failed. We can ignore that
// and count on this request updating the cache. //
log_.warn("Problem ending batch after loading session " + Util.maskId(realId) + " -- " + e.getLocalizedMessage() + " However session data was successful loaded.");
log_.debug("Failure cause", e);
}
else
{
throw Util.getRuntimeException("Failed to load session " + Util.maskId(realId), e);
}
}
}
}