/*
* JBoss, Home of Professional Open Source.
* Copyright 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.web.tomcat.service.session.distributedcache.impl.jbc;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import org.jboss.cache.CacheException;
import org.jboss.cache.Fqn;
import org.jboss.cache.pojo.PojoCache;
import org.jboss.ha.framework.server.PojoCacheManager;
import org.jboss.ha.framework.server.PojoCacheManagerLocator;
import org.jboss.web.tomcat.service.session.distributedcache.spi.ClusteringNotSupportedException;
import org.jboss.web.tomcat.service.session.distributedcache.spi.LocalDistributableSessionManager;
import org.jboss.web.tomcat.service.session.distributedcache.spi.OutgoingDistributableSessionData;
/**
* DistributedCacheManager impl for ReplicationGranularity.FIELD.
*
* @author Brian Stansberry *
*/
public class FieldBasedJBossCacheService extends AbstractJBossCacheService<OutgoingDistributableSessionData>
{
public static final String ATTRIBUTE = "ATTRIBUTE";
public static Fqn<String> getAttributeFqn(String contextHostPath, String sessionId)
{
return Fqn.fromElements(SESSION, contextHostPath, sessionId, ATTRIBUTE);
}
public static Fqn<String> getFieldFqn(String contextHostPath, String sessionId, String attributeKey)
{
StringTokenizer token = new StringTokenizer(attributeKey, FQN_DELIMITER);
int count = token.countTokens();
if (count == 1)
{
return Fqn.fromElements(SESSION, contextHostPath, sessionId, ATTRIBUTE, attributeKey);
}
else
{
String[] args = new String[4 + count];
args[0] = SESSION;
args[1] = contextHostPath;
args[2] = sessionId;
args[3] = ATTRIBUTE;
for (int i = 0; i < count; i++)
{
args[4 + i] = token.nextToken();
}
return Fqn.fromElements(args);
}
}
private final PojoCache pojoCache_;
public FieldBasedJBossCacheService(LocalDistributableSessionManager localManager) throws ClusteringNotSupportedException
{
this(localManager, Util.findPojoCache(Util.getCacheConfigName(localManager)));
this.cacheConfigName_ = Util.getCacheConfigName(localManager);
}
/**
* Create a new FieldBasedJBossCacheService.
*
* @param cache
*/
public FieldBasedJBossCacheService(LocalDistributableSessionManager localManager, PojoCache cache)
{
super(localManager, cache.getCache());
this.pojoCache_ = cache;
if (!isMarshallingAvailable())
{
// BES 16/8/2006 -- throw ISE, not ClusteringNotSupportedException, as a
// misconfig should be treated differently from the absence of clustering
// services
throw new IllegalStateException("replication-granularity value is set to " +
"'FIELD' but is not supported by the cache service configuration. " +
"Must set 'useRegionBasedMarshalling' to 'true' in the cache configuration");
}
}
public boolean getSupportsAttributeOperations()
{
return true;
}
public void putAttribute(String realId, String key, Object value)
{
if(log_.isTraceEnabled())
{
log_.trace("putAttribute(): session id: " + realId + " key: " + key +
" object: " + value.toString());
}
Fqn<String> fqn = getFieldFqn(combinedPath_, realId, key);
try {
pojoCache_.attach(fqn.toString(), value);
}
catch (CacheException e)
{
throw new RuntimeException("Exception occurred in PojoCache attach ... ", e);
}
}
/**
* Remove pojo from the underlying cache store.
* @param realId the session id with any jvmRoute removed
* @param key the attribute key
* @return pojo that just removed. Null if there none.
*/
public Object removeAttribute(String realId, String key)
{
if(log_.isTraceEnabled())
{
log_.trace("removePojo(): session id: " +realId + " key: " +key);
}
// Construct the fqn.
Fqn<String> fqn = getFieldFqn(combinedPath_, realId, key);
try {
return pojoCache_.detach(fqn.toString());
}
catch (CacheException e)
{
throw new RuntimeException("Exception occurred in PojoCache detach ... ", e);
}
}
public void removeAttributeLocal(String realId, String key)
{
if(log_.isTraceEnabled())
{
log_.trace("removePojoLocal(): session id: " + realId + " key: " +key);
}
Fqn<String> fqn = getFieldFqn(combinedPath_, realId, key);
cacheWrapper_.removeLocal(fqn);
}
public Set<String> getAttributeKeys(String realId)
{
Set<String> keys = null;
Fqn<String> fqn = getAttributeFqn(combinedPath_, realId);
try
{
keys = getChildrenNames(fqn);
}
catch (CacheException e)
{
log_.error("getAttributeKeys(): Exception getting keys for session " + realId, e);
}
return keys;
}
/**
*
* @param realId the session id with any jvmRoute removed
* @param key the attribute key
* @return Pojo that is associated with the attribute
*/
public Object getAttribute(String realId, String key)
{
Fqn<String> fqn = getFieldFqn(combinedPath_, realId, key);
if(log_.isTraceEnabled())
{
log_.trace("getPojo(): session id: " +realId + " key: " + key +
" fqn: " + fqn);
}
try
{
return pojoCache_.find(fqn);
}
catch (CacheException e)
{
throw new RuntimeException("Exception occurred in PojoCache find ... ", e);
}
}
public void sessionCreated(String realId)
{
Fqn<String> fqn = getSessionFqn(combinedPath_, realId);
setupSessionRegion(fqn);
}
@Override
protected void setupSessionRegion(Fqn<String> fqn)
{
getCache().getRegion(fqn, true);
if (log_.isTraceEnabled())
{
log_.trace("Created region for session at " + fqn);
}
}
@Override
protected void removeSessionRegion(String realId, Fqn<String> fqn)
{
getCache().removeRegion(fqn);
if (log_.isTraceEnabled())
{
log_.trace("Removed region for session at " + fqn);
}
}
@Override
protected void releaseCacheToManager(String cacheConfigName)
{
try
{
PojoCacheManager pcm = PojoCacheManagerLocator.getCacheManagerLocator().getCacheManager(null);
pcm.releaseCache(cacheConfigName);
}
catch (Exception e)
{
log_.error("Problem releasing cache to CacheManager -- config is " + cacheConfigName, e);
}
}
public Map<String, Object> getAttributes(String realId)
{
Map<String, Object> attrs = new HashMap<String, Object>();
Set<String> keys = getAttributeKeys(realId);
for (String key : keys)
{
attrs.put(key, getAttribute(realId, key));
}
return attrs;
}
public void putAttribute(String realId, Map<String, Object> map)
{
for (Map.Entry<String, Object> entry : map.entrySet())
{
putAttribute(realId, entry.getKey(), entry.getValue());
}
}
/**
* Overrides the superclass to pull in attributes via PojoCache API.
*/
@Override
protected Map<String, Object> getSessionAttributes(String realId, Map<Object, Object> distributedCacheData)
{
return getAttributes(realId);
}
@Override
protected void storeSessionAttributes(Map<Object, Object> dataMap, OutgoingDistributableSessionData sessionData)
{
// no-op; attributes are stored individually
}
}