/**
*
*/
package org.jboss.web.tomcat.service.session.persistent;
import java.util.HashMap;
import java.util.Map;
import org.apache.catalina.LifecycleException;
import org.jboss.logging.Logger;
import org.jboss.metadata.web.jboss.ReplicationGranularity;
import org.jboss.metadata.web.jboss.ReplicationTrigger;
import org.jboss.metadata.web.jboss.SnapshotMode;
import org.jboss.web.tomcat.service.session.JBossCacheManager;
import org.jboss.web.tomcat.service.session.OutdatedSessionChecker;
import org.jboss.web.tomcat.service.session.OwnedSessionUpdate;
import org.jboss.web.tomcat.service.session.distributedcache.spi.IncomingDistributableSessionData;
import org.jboss.web.tomcat.service.session.distributedcache.spi.OutgoingDistributableSessionData;
/**
*
*
* @author Brian Stansberry
*
* @version $Revision: $
*/
public abstract class AbstractPersistentManager<P extends RDBMSStoreBase, O extends OutgoingDistributableSessionData>
extends JBossCacheManager<O>
{
// ----------------------------------------------------- Instance Variables
/**
* The descriptive information about this implementation.
*/
private static final String info = "AbstractPersistentManager/1.0";
/**
* The descriptive name of this Manager implementation (for logging).
*/
protected static String name = "AbstractPersistentManager";
private final P store;
/**
* The connection username to use when trying to connect to the database.
*/
private String connectionName = null;
/**
* The connection URL to use when trying to connect to the database.
*/
private String connectionPassword = null;
/**
* Table to use.
*/
private String sessionTable = null;
/**
* Column to use for /Engine/Host/Context name
*/
private String sessionAppCol = null;
/**
* Id column to use.
*/
private String sessionIdCol = null;
/**
* Full Id (e.g. including jvmRoute) column to use.
*/
private String sessionFullIdCol = null;
/**
* Creation time column to use
*/
private String sessionCreationTimeCol = null;
/**
* Max Inactive column to use.
*/
private String sessionMaxInactiveCol = null;
/**
* Version column to use.
*/
private String sessionVersionCol = null;
/**
* Last Accessed column to use.
*/
private String sessionLastAccessedCol = null;
/**
* Is New column to use
*/
private String sessionNewCol = null;
/**
* Is Valid column to use.
*/
private String sessionValidCol = null;
/**
* Column to use for misc metadata.
*/
private String sessionMetadataCol = null;
/**
* Attribute column to use.
*/
private String sessionAttributeCol = null;
private Integer cleanupInterval = null;
private Logger log = Logger.getLogger(getClass());
// ------------------------------------------------------------ Constructors
/**
*
*/
public AbstractPersistentManager(P store)
{
super(new PersistentStoreDistributedCacheManagerFactory(store));
this.store = store;
}
// ------------------------------------------------------------- Properties
/**
* Return descriptive information about this Manager implementation and
* the corresponding version number, in the format
* <code><description>/<version></code>.
*/
public String getInfo() {
return (info);
}
/**
* Return the descriptive short name of this Manager implementation.
*/
public String getName() {
return (name);
}
public String getConnectionName()
{
return connectionName;
}
public void setConnectionName(String connectionName)
{
this.connectionName = connectionName;
}
public String getConnectionPassword()
{
return connectionPassword;
}
public void setConnectionPassword(String connectionPassword)
{
this.connectionPassword = connectionPassword;
}
public String getSessionTable()
{
return sessionTable;
}
public void setSessionTable(String sessionTable)
{
this.sessionTable = sessionTable;
}
public String getSessionAppCol()
{
return sessionAppCol;
}
public void setSessionAppCol(String sessionAppCol)
{
this.sessionAppCol = sessionAppCol;
}
public String getSessionIdCol()
{
return sessionIdCol;
}
public void setSessionIdCol(String sessionIdCol)
{
this.sessionIdCol = sessionIdCol;
}
public String getSessionFullIdCol()
{
return sessionFullIdCol;
}
public void setSessionFullIdCol(String sessionFullIdCol)
{
this.sessionFullIdCol = sessionFullIdCol;
}
public String getSessionCreationTimeCol()
{
return sessionCreationTimeCol;
}
public void setSessionCreationTimeCol(String sessionCreationTimeCol)
{
this.sessionCreationTimeCol = sessionCreationTimeCol;
}
public String getSessionMaxInactiveCol()
{
return sessionMaxInactiveCol;
}
public void setSessionMaxInactiveCol(String sessionMaxInactiveCol)
{
this.sessionMaxInactiveCol = sessionMaxInactiveCol;
}
public String getSessionVersionCol()
{
return sessionVersionCol;
}
public void setSessionVersionCol(String sessionVersionCol)
{
this.sessionVersionCol = sessionVersionCol;
}
public String getSessionLastAccessedCol()
{
return sessionLastAccessedCol;
}
public void setSessionLastAccessedCol(String sessionLastAccessedCol)
{
this.sessionLastAccessedCol = sessionLastAccessedCol;
}
public String getSessionNewCol()
{
return sessionNewCol;
}
public void setSessionNewCol(String sessionNewCol)
{
this.sessionNewCol = sessionNewCol;
}
public String getSessionValidCol()
{
return sessionValidCol;
}
public void setSessionValidCol(String sessionValidCol)
{
this.sessionValidCol = sessionValidCol;
}
public String getSessionMetadataCol()
{
return sessionMetadataCol;
}
public void setSessionMetadataCol(String sessionMetadataCol)
{
this.sessionMetadataCol = sessionMetadataCol;
}
public String getSessionAttributeCol()
{
return sessionAttributeCol;
}
public void setSessionAttributeCol(String sessionAttributeCol)
{
this.sessionAttributeCol = sessionAttributeCol;
}
public Integer getCleanupInterval()
{
return cleanupInterval;
}
public void setCleanupInterval(Integer cleanupInterval)
{
this.cleanupInterval = cleanupInterval;
}
// -------------------------------------------------------------- Public
@Override
public void setReplicationGranularity(ReplicationGranularity granularity)
{
switch (granularity)
{
case SESSION:
super.setReplicationGranularity(granularity);
break;
default:
log.warn("Ignoring call to set replication granularity to " +
granularity + " -- only " + ReplicationGranularity.SESSION + " is supported");
}
}
@Override
public void start() throws LifecycleException
{
configureStore();
super.start();
}
// -------------------------------------------------------------- Protected
protected P getPersistentStore()
{
return store;
}
@Override
protected void configureUnembedded() throws LifecycleException
{
// Only set replication attributes if they were not
// already set via a <Manager> element in an XML config file
if (getReplicationGranularity() == null)
{
setReplicationGranularity(ReplicationGranularity.SESSION);
}
if (getReplicationTrigger() == null)
{
setReplicationTrigger(ReplicationTrigger.SET_AND_NON_PRIMITIVE_GET);
}
if (isReplicationFieldBatchMode() == null)
{
setReplicationFieldBatchMode(false);
}
if (getSnapshotMode() == null)
{
setSnapshotMode(SnapshotMode.INSTANT);
}
}
protected void configureStore()
{
store.setName(this.getContextName());
store.setMaxUnreplicatedInterval(getMaxUnreplicatedInterval());
if (getConnectionName() != null)
{
store.setConnectionName(getConnectionName());
}
if (getConnectionPassword() != null)
{
store.setConnectionPassword(getConnectionPassword());
}
if (getSessionAppCol() != null)
{
store.setSessionAppCol(getSessionAppCol());
}
if (getSessionAttributeCol() != null)
{
store.setSessionAttributeCol(getSessionAttributeCol());
}
if (getSessionCreationTimeCol() != null)
{
store.setSessionCreationTimeCol(getSessionCreationTimeCol());
}
if (getSessionFullIdCol() != null)
{
store.setSessionFullIdCol(getSessionFullIdCol());
}
if (getSessionIdCol() != null)
{
store.setSessionIdCol(getSessionIdCol());
}
if (getSessionLastAccessedCol() != null)
{
store.setSessionLastAccessedCol(getSessionLastAccessedCol());
}
if (getSessionMaxInactiveCol() != null)
{
store.setSessionMaxInactiveCol(getSessionMaxInactiveCol());
}
if (getSessionMetadataCol() != null)
{
store.setSessionMetadataCol(getSessionMetadataCol());
}
if (getSessionNewCol() != null)
{
store.setSessionNewCol(getSessionNewCol());
}
if (getSessionTable() != null)
{
store.setSessionTable(getSessionTable());
}
if (getSessionValidCol() != null)
{
store.setSessionValidCol(getSessionValidCol());
}
if (getSessionVersionCol() != null)
{
store.setSessionVersionCol(getSessionVersionCol());
}
if (getCleanupInterval() != null)
{
store.setCleanupInterval(getCleanupInterval().intValue());
}
}
/**
* Overrides superclass to update the contents of OwnedSessionUpdate values
* to reflect the current state of the {@link PersistentStore}.
*/
@Override
protected Map<String, OwnedSessionUpdate> getUnloadedSessions()
{
Map<String, OwnedSessionUpdate> map = super.getUnloadedSessions();
Map<String, OwnedSessionUpdate> processed = new HashMap<String, OwnedSessionUpdate>();
for (Map.Entry<String, OwnedSessionUpdate> entry : map.entrySet())
{
String realId = entry.getKey();
OwnedSessionUpdate existing = entry.getValue();
Long timestamp = store.getSessionTimestamp(realId);
if (timestamp != null && existing.getUpdateTime() != timestamp.longValue())
{
// Timestamp change -- pull in the data
IncomingDistributableSessionData data = store.getSessionData(entry.getKey(), false);
if (data != null)
{
OwnedSessionUpdate updated = new OwnedSessionUpdate(existing.getOwner(),
data.getTimestamp(),
data.getMetadata().getMaxInactiveInterval(),
existing.isPassivated());
processed.put(realId, updated);
}
else
{
// Session has been deleted; just keep existing and let
// the caller clean up
processed.put(realId, existing);
}
}
else
{
// Session has been deleted; just keep existing and let
// the caller clean up
processed.put(realId, existing);
}
}
return processed;
}
@Override
protected void initializeUnloadedSessions()
{
// no-op
}
@Override
protected OutdatedSessionChecker initOutdatedSessionChecker()
{
// TODO make this configurable
return new VersionBasedOutdatedSessionChecker((ExtendedDistributedCacheManager<? extends OutgoingDistributableSessionData>) getDistributedCacheManager());
}
@Override
protected void processExpirationPassivation()
{
super.processExpirationPassivation();
this.store.processExpires();
}
}