/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
/*
* ReplicationStore.java
*
* Created on November 17, 2005, 10:24 AM
*/
package com.sun.enterprise.ee.web.sessmgmt;
import com.sun.appserv.ha.spi.BackingStore;
import com.sun.appserv.ha.spi.BackingStoreException;
import com.sun.appserv.ha.util.SimpleMetadata;
import com.sun.appserv.ha.util.SimpleMetadataFactory;
import com.sun.appserv.ha.util.Metadata;
import com.sun.appserv.ha.uow.ReplicableEntity;
import com.sun.appserv.util.cache.BaseCache;
import com.sun.enterprise.ee.web.authenticator.ReplicationSingleSignOn;
import com.sun.enterprise.security.web.SingleSignOn;
import com.sun.enterprise.security.web.SingleSignOnEntry;
import com.sun.enterprise.web.ServerConfigLookup;
import org.apache.catalina.*;
import org.apache.catalina.session.*;
import java.io.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.GZIPInputStream;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
/**
*
* @author Larry White
*/
public class ReplicationStore extends HAStoreBase implements HAStorePoolElement,
SessionStoreInterface {
public final static String BEKEY
= ReplicationState.BEKEY;
private final static String EXTENDED_UTILITY_CLASS_NAME
= "org.jvnet.glassfish.comms.replication.sessmgmt.ExtendedReplicationUtil";
public final static String LOGGER_MEM_REP
= ReplicationState.LOGGER_MEM_REP;
private static boolean useReplicationUnicastLoadBatching = false;
static {
ServerConfigLookup lookup = new ServerConfigLookup();
useReplicationUnicastLoadBatching
= lookup.isReplicationUnicastLoadBatchingEnabled();
}
/**
* The logger to use for logging ALL web container related messages.
*/
//protected static final Logger _logger
// = LogDomains.getLogger(LogDomains.WEB_LOGGER);
private static final Logger _logger
= Logger.getLogger(LOGGER_MEM_REP);
protected final static String MODE_WEB = ReplicationState.MODE_WEB;
protected ReplicationUtil replicationUtil = createReplicationUtil();
private String instanceName = ReplicationUtil.getInstanceName();
/**
* Creates a new instance of ReplicationStore
*/
public ReplicationStore() {
setLogLevel();
}
protected ReplicationUtil createReplicationUtil() {
ReplicationUtil replicationUtil = new ReplicationUtil();
try {
replicationUtil =
(ReplicationUtil) (Class.forName(EXTENDED_UTILITY_CLASS_NAME)).newInstance();
} catch (Exception ex) {
;
}
return replicationUtil;
}
public String getApplicationId() {
if(applicationId != null) {
return applicationId;
}
applicationId = "WEB:" + super.getApplicationId();
return applicationId;
}
// HAStorePoolElement methods begin
/**
* Save the specified Session into this Store. Any previously saved
* information for the associated session identifier is replaced.
*
* @param session Session to be saved
*
* @exception IOException if an input/output error occurs
*/
public void valveSave(Session session) throws IOException {
HASession haSess = (HASession)session;
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("ReplicationStore>>valveSave id=" + haSess.getIdInternal() +
" isPersistent=" + haSess.isPersistent() + " isDirty=" + haSess.isDirty());
}
if( haSess.isPersistent() && !haSess.isDirty() ) {
this.updateLastAccessTime(session);
} else {
this.doValveSave(session);
haSess.setPersistent(true);
}
haSess.setDirty(false);
}
/**
* Save the specified Session into this Store. Any previously saved
* information for the associated session identifier is replaced.
*
* @param session Session to be saved
*
* @exception IOException if an input/output error occurs
*/
public void doValveSave(Session session) throws IOException {
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("ReplicationStore>>doValveSave:id =" + ((HASession)session).getIdInternal());
_logger.fine("ReplicationStore>>doValveSave:valid =" + ((StandardSession)session).getIsValid());
_logger.fine("ReplicationStore>>doValveSave:ssoId=" + ((HASession)session).getSsoId());
}
// begin 6470831 do not save if session is not valid
if( !((StandardSession)session).getIsValid() ) {
return;
}
// end 6470831
String userName = "";
if(session.getPrincipal() !=null){
userName = session.getPrincipal().getName();
((BaseHASession)session).setUserName(userName);
}
byte[] sessionState = this.getByteArray(session, isReplicationCompressionEnabled());
ReplicationManagerBase mgr
= (ReplicationManagerBase)this.getManager();
BackingStore replicator = mgr.getBackingStore();
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("ReplicationStore>>doValveSave replicator: " + replicator);
_logger.fine("ReplicationStore>>doValveSave version:" + session.getVersion());
}
SimpleMetadata simpleMetadata =
SimpleMetadataFactory.createSimpleMetadata(session.getVersion(), //version
((BaseHASession)session).getLastAccessedTimeInternal(), //lastaccesstime
session.getMaxInactiveInterval(), //maxinactiveinterval
sessionState, //state
((HASession)session).getExtraParameters()); //containerExtraParam
String beKey = session.getBeKey();
if(beKey != null) {
simpleMetadata.setBeKey(beKey);
}
try {
HASession haSess = (HASession)session;
replicator.save(session.getIdInternal(), //id
simpleMetadata, haSess.isPersistent()); //TODO: Revist the last param
} catch (BackingStoreException ex) {
IOException ex1 =
(IOException) new IOException("Error during save: " + ex.getMessage()).initCause(ex);
throw ex1;
}
}
public ReplicationState getTransmitState(Session session) throws IOException {
ReplicationManagerBase mgr
= (ReplicationManagerBase)this.getManager();
BackingStore replicator = mgr.getBackingStore();
if(!(replicator instanceof JxtaBackingStoreImpl)) {
return null;
}
JxtaBackingStoreImpl jxtaReplicator = (JxtaBackingStoreImpl)replicator;
ReplicationState transmitState = null;
String userName = "";
if(session.getPrincipal() !=null){
userName = session.getPrincipal().getName();
((BaseHASession)session).setUserName(userName);
}
byte[] sessionState = this.getByteArray(session, isReplicationCompressionEnabled());
SimpleMetadata simpleMetadata =
SimpleMetadataFactory.createSimpleMetadata(session.getVersion(), //version
((BaseHASession)session).getLastAccessedTimeInternal(), //lastaccesstime
session.getMaxInactiveInterval(), //maxinactiveinterval
sessionState, //state
((HASession)session).getExtraParameters()); //containerExtraParam
String beKey = session.getBeKey();
if(beKey != null) {
simpleMetadata.setBeKey(beKey);
}
//need this here because save not called
simpleMetadata.setOwningInstanceName(ReplicationUtil.getInstanceName());
try {
transmitState = jxtaReplicator.getSimpleTransmitState(session.getIdInternal(), simpleMetadata);
} catch (BackingStoreException ex) {}
return transmitState;
}
//state is already formatted as a response
public void sendResponse(ReplicationState state) {
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("ReplicationStore>>sendResponse");
}
this.doReturnTransmit(state);
}
protected void transmitSession(Session session, String command) throws IOException {
ReplicationState transmitState =
createReplicationState(session, command);
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("ReplicationStore>>transmitSession: command: " + command);
}
this.doTransmit(transmitState);
//remove after testing
//this.testDeserializeState(transmitState);
}
protected void transmitSession(Session session, String command, boolean wait) throws IOException {
ReplicationState transmitState =
createReplicationState(session, command);
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("ReplicationStore>>transmitSession: command: " + command);
}
this.doTransmit(transmitState, wait);
//remove after testing
//this.testDeserializeState(transmitState);
}
private boolean isMethodVoidReturn(String methodName) {
return ReplicationState.isMethodVoidReturn(methodName);
}
ReplicationState createReplicationState(Session session, String command)
throws IOException {
HttpSessionExtraParams containerExtraParam = ((BaseHASession)session).getExtraParameters();
byte[] sessionState = this.getByteArray(session);
byte[] containerExtraParamState = null;
if(containerExtraParam != null) {
try {
containerExtraParamState = ReplicationUtil.getByteArray(containerExtraParam, isReplicationCompressionEnabled());
} catch (IOException ex) {
IOException ex1 =
(IOException) new IOException("error during serialization of extra parameters" + ex.getMessage()).initCause(ex);
throw ex1;
}
}
ReplicationState transmitState =
new ReplicationState(MODE_WEB, //web mode
session.getIdInternal(), //id
getApplicationId(), //appid
session.getVersion(), //version
((BaseHASession)session).getLastAccessedTimeInternal(), //lastaccesstime
session.getMaxInactiveInterval(), //maxInactiveInterval (seconds)
getSsoId((StandardSession)session), //ssoid (extraParam)
null, //queryResult not used here
ReplicationUtil.getInstanceName(), //instanceName
command, //command
sessionState, //state
null, //trunkState
containerExtraParamState); //containerExtraParamState
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("ReplicationStore>>createReplicationState:transmitState = " + transmitState);
}
return transmitState;
}
private void testDeserializeState(ReplicationState transmitState) {
try {
Session sess = this.getSession(transmitState);
//System.out.println("sess = " + sess);
} catch (Exception e) {
_logger.log(Level.WARNING, "exception occurred in testDeserializeState", e);
}
}
public void cleanup() {
//FIXME;
}
public BaseCache getSessions(){
//FIXME
return null;
}
public void setSessions(BaseCache sesstable) {
//FIXME;
}
// HAStorePoolElement methods end
// Store method begin
/**
* Save the specified Session into this Store. Any previously saved
* information for the associated session identifier is replaced.
*
* @param session Session to be saved
*
* @exception IOException if an input/output error occurs
*/
public void save(Session session) throws IOException {
HASession haSess = (HASession)session;
if( haSess.isPersistent() && !haSess.isDirty() ) {
this.updateLastAccessTime(session);
} else {
this.doSave(session);
haSess.setPersistent(true);
}
haSess.setDirty(false);
}
protected boolean isReplicationCompressionEnabled() {
ReplicationManagerBase repMgr
= (ReplicationManagerBase)this.getManager();
return repMgr.isReplicationCompressionEnabled();
}
/**
* Save the specified Session into this Store. Any previously saved
* information for the associated session identifier is replaced.
*
* @param session Session to be saved
*
* @exception IOException if an input/output error occurs
*/
public void doSave(Session session) throws IOException {
byte[] sessionState = this.getByteArray(session, isReplicationCompressionEnabled());
ReplicationManagerBase mgr
= (ReplicationManagerBase)this.getManager();
BackingStore replicator = mgr.getBackingStore();
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("ReplicationStore>>save: replicator: " + replicator);
}
SimpleMetadata simpleMetadata =
SimpleMetadataFactory.createSimpleMetadata(session.getVersion(), //version
((BaseHASession)session).getLastAccessedTimeInternal(), //lastaccesstime
session.getMaxInactiveInterval(), //maxinactiveinterval
sessionState, //state
((HASession)session).getExtraParameters()); //containerExtraParams
String beKey = session.getBeKey();
if(beKey != null) {
simpleMetadata.setBeKey(beKey);
}
try {
replicator.save(session.getIdInternal(), //id
simpleMetadata, !((HASession) session).isPersistent()); //TODO: Revist the last param
} catch (BackingStoreException ex) {
IOException ex1 =
(IOException) new IOException("Error during save: " + ex.getMessage()).initCause(ex);
throw ex1;
}
}
/**
* Clear sessions
*
* @exception IOException if an input/output error occurs
*/
public synchronized void clear() throws IOException {
//FIXME
}
/**
* Remove the Session with the specified session identifier from
* this Store, if present. If no such Session is present, this method
* takes no action.
*
* @param id Session identifier of the Session to be removed
*
* @exception IOException if an input/output error occurs
*/
public void doRemove(String id) throws IOException {
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("ReplicationStore>>doRemove");
}
ReplicationManagerBase mgr
= (ReplicationManagerBase)this.getManager();
BackingStore replicator = mgr.getBackingStore();
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("ReplicationStore>>doRemove: replicator: " + replicator);
}
try {
replicator.remove(id);
} catch (BackingStoreException ex) {
//FIXME
}
}
/**
* Remove the Session with the specified session identifier from
* this Store, if present. If no such Session is present, this method
* takes no action.
*
* @param id Session identifier of the Session to be removed
*
* @exception IOException if an input/output error occurs
*/
public synchronized void removeSynchronized(String id) throws IOException {
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("ReplicationStore>>removeSynchronized");
}
ReplicationManagerBase mgr
= (ReplicationManagerBase)this.getManager();
BackingStore replicator = mgr.getBackingStore();
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("ReplicationStore>>removeSynchronized: replicator: " + replicator);
}
try {
replicator.remove(id);
} catch (BackingStoreException ex) {
//FIXME
}
}
/**
* Remove the list of ids in removedIdsData from
* this Store, if present. If no such Session is present, this method
* takes no action.
*
* @param msgID message id for this remove all message
* @param removedIdsData serialized list of ids to remove
*
* @exception IOException if an input/output error occurs
*/
public void removeIds(long msgID, byte[] removedIdsData) throws IOException {
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("ReplicationStore>>removeIds");
}
ReplicationManagerBase mgr
= (ReplicationManagerBase)this.getManager();
JxtaBackingStoreImpl replicator = (JxtaBackingStoreImpl)mgr.getBackingStore();
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("ReplicationStore>>removeIds: replicator: " + replicator);
}
try {
replicator.removeIds(msgID, removedIdsData);
} catch (BackingStoreException ex) {
//FIXME
}
}
/**
* Called by our background reaper thread to remove expired
* sessions in the replica - this can be done on the same
* instance - i.e. each instance will do its own
*
*/
public void processExpires() {
// ReplicationManagerBase replicationMgr =
// (ReplicationManagerBase) this.getManager();
// if(!(replicationMgr.isThirdPartyBackingStoreInUse())) {
// replicationMgr.processExpiredReplicas();
// } else {
// removeExpiredSessions();
// }
removeExpiredSessions();
}
/** This method deletes all the sessions corresponding to the "appId"
* that should be expired
* @return number of removed sessions
*/
public int removeExpiredSessions() {
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("IN ReplicationStore>>removeExpiredSessions");
}
int result = 0;
ReplicationManagerBase mgr
= (ReplicationManagerBase)this.getManager();
if(mgr == null) {
return result;
}
BackingStore replicator = mgr.getBackingStore();
try {
result = replicator.removeExpired();
} catch (BackingStoreException ex) {
//FIXME
}
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("ReplicationStore>>removeExpiredSessions():number of expired sessions = " + result);
}
return result;
}
//FIXME: this could return null which would mean a problem
//might want to throw exception in that case
protected ReplicationState doTransmit(ReplicationState transmitState) {
return doTransmit(transmitState, true);
//FIXME above is just for testing put back original later
/*
JxtaReplicationSender replicationSender =
JxtaReplicationSender.createInstance();
ReplicationState resultState =
replicationSender.sendReplicationState(transmitState);
return resultState;
*/
}
//FIXME: this could return null which would mean a problem
//might want to throw exception in that case
protected ReplicationState doTransmit(ReplicationState transmitState, boolean wait) {
//FIXME
JxtaReplicationSender replicationSender =
JxtaReplicationSender.createInstance();
ReplicationState resultState =
replicationSender.sendReplicationState(transmitState, wait);
return resultState;
}
protected ReplicationState doReturnTransmit(ReplicationState transmitState) {
JxtaReplicationReceiver replicationReceiver =
JxtaReplicationReceiver.createInstance();
ReplicationState resultState =
replicationReceiver.sendReplicationStateResponse(transmitState);
return resultState;
}
/**
* Load and return the Session associated with the specified session
* identifier from this Store, without removing it. If there is no
* such stored Session, return <code>null</code>.
*
* @param id Session identifier of the session to load
*
* @exception ClassNotFoundException if a deserialization error occurs
* @exception IOException if an input/output error occurs
*/
public Session load(String id) throws ClassNotFoundException, IOException {
return load(id, null);
}
public Session load(String id, String version) throws ClassNotFoundException, IOException {
try {
ExpatListElement expat = this.getExpatListElementFor(id);
if (expat != null && expat.isFromActive()) {
/**
* Irrespective of the backing store implementation, if the session
* is activated in the remote instance, then we should load it from there.
*/
return loadFromRemoteActiveCache(id, expat);
} else {
return loadFromBackingStore(id, version);
}
} catch (BackingStoreException ex) {
IOException ex1 =
(IOException) new IOException("Error during load: " + ex.getMessage()).initCause(ex);
throw ex1;
}
}
public Session loadFromRemoteActiveCache(String id, ExpatListElement expat)
throws IOException, ClassNotFoundException, BackingStoreException {
/**
* For the in-memory implementation, the restarted instance might
* have the session in its replica cache, if the load-factor is used.
*/
BaseCache replicaCache = getReplicaCache();
if(replicaCache != null) {
replicaCache.remove(id);
}
ReplicationState sessionState = loadSessionFromRemoteActiveCache(
id, String.valueOf(expat.getVersion()), expat.getInstanceName());
if (_logger.isLoggable(Level.FINE)) {
_logger.fine("ReplicationStore>>loadFromActiveCache:id="
+ id + ", sessionState=" + sessionState);
}
Session session = getSession(sessionState);
validateAndSave(session);
return session;
}
public Session loadFromBackingStore(String id, String version)
throws IOException, ClassNotFoundException, BackingStoreException {
SimpleMetadata metaData = (SimpleMetadata) getBackingStore().load(id, version);
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("ReplicationStore>>loadFromBackingStore:id=" +
id + ", metaData=" + metaData);
}
Session session = getSession(metaData);
validateAndSave(session);
return session;
}
BackingStore getBackingStore() {
ReplicationManagerBase mgr
= (ReplicationManagerBase) this.getManager();
BackingStore replicator = mgr.getBackingStore();
return replicator;
}
/**
* Load and return the Session associated with the specified session
* identifier from this Store, without removing it. If there is no
* such stored Session, return <code>null</code>.
*
* @param id Session identifier of the session to load
*
* @exception ClassNotFoundException if a deserialization error occurs
* @exception IOException if an input/output error occurs
*/
public Metadata __load(String id, String version)
throws BackingStoreException {
SimpleMetadata result = null;
if(id == null) {
return result;
}
ReplicationManagerBase repMgr =
(ReplicationManagerBase)this.getManager();
if(_logger.isLoggable(Level.FINE)) {
repMgr.printReplicatedSessionIds();
}
//repMgr.printReplicatedSessionIds();
ReplicationState localCachedState = repMgr.transferFromReplicationCache(id);
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("ReplicationStore>>load:localCachedState=" + localCachedState);
}
//check if we got a hit from our own replica cache
//and if so return it immediately
if(version != null && localCachedState != null) {
long versionLong = ReplicationUtil.parseLong(version);
if(localCachedState.getVersion() == versionLong) {
return ReplicationState.createSimpleMetadataFrom(localCachedState, isReplicationCompressionEnabled());
}
}
ReplicationState broadcastResultState
= findSessionViaBroadcastOrUnicast(id, version);
ReplicationState bestState = ReplicationState.getBestResult(
localCachedState, broadcastResultState);
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("ReplicationStore>>__load:id=" + id + ", broadcastResultState " +
"from broadcast or unicast=" + broadcastResultState + ", bestState = " + bestState);
}
result = ReplicationState.createSimpleMetadataFrom(
bestState, isReplicationCompressionEnabled());
return result;
}
private void validateAndSave(Session session) throws IOException {
if (session != null) {
if (__removeFromRemotelyLoadedSessionIds(session.getId())) {
//save session - save will reset dirty to false
if (_logger.isLoggable(Level.FINE)) {
_logger.fine("ReplicationStore>>validateAndSave saving " +
"the session after loading it. Session=" + session);
}
((HASession) session).setDirty(true);
valveSave(session);
//send acknowledgement of load receipt
//no response to wait for in this case
sendLoadAcknowledgement(session.getId(), session.getVersion(), session.getBeKey());
}
}
}
protected ReplicationState getBestResult(ReplicationState localState, ReplicationState broadcastResultState) {
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("ReplicationStore>>getBestResult:localState=" + localState + "other=" + broadcastResultState);
}
if(localState == null) {
return broadcastResultState;
}
//localState is not null
if(broadcastResultState == null) {
return localState;
}
//both are non-null
if(broadcastResultState.getVersion() >= localState.getVersion()) {
return broadcastResultState;
} else {
return localState;
}
}
protected void sendLoadAcknowledgement(String id,
long version, String beKey) {
ReplicationState loadReceivedState =
ReplicationState.createBroadcastLoadReceivedState(
MODE_WEB, id,
getApplicationId(), version,
ReplicationUtil.getInstanceName(),
ReplicationManagerBase.MESSAGE_BROADCAST_LOAD_RECEIVED);
sendLoadAcknowledgement(loadReceivedState, beKey);
}
private void sendLoadAcknowledgement(ReplicationState bestState, String beKey) {
//send acknowledgement of load receipt
//no response to wait for in this case
JxtaReplicationSender sender
= JxtaReplicationSender.createInstance();
ReplicationState loadReceivedState =
ReplicationState.createBroadcastLoadReceivedState(MODE_WEB,
(String)bestState.getId(), this.getApplicationId(),
bestState.getVersion(), ReplicationUtil.getInstanceName(),
ReplicationManagerBase.MESSAGE_BROADCAST_LOAD_RECEIVED);
ReplicationUtil repUtil = ReplicationUtil.createReplicationUtil();
if ((beKey != null) && repUtil.isInstanceLoadBalancedByCLB()){
loadReceivedState.setProperty(ReplicationState.IGNORE_REMOVE_INSTANCE_NAME,
repUtil.getFailoverServerInstanceForBeKey(beKey));
} else {
ReplicationHealthChecker healthChecker = ReplicationHealthChecker.getInstance();
String currentReplicaPartner = healthChecker.getCurrentPartnerInstanceName();
loadReceivedState.setProperty(ReplicationState.IGNORE_REMOVE_INSTANCE_NAME,
currentReplicaPartner);
}
sender.sendBroadcastQuery(loadReceivedState);
}
protected ExpatListElement getExpatListElementFor(String id) {
ReplicationManagerBase mgr
= (ReplicationManagerBase)getManager();
if(mgr.isExpectingExpatIdsMap()) {
//in this period do not trust expatIdsMap
return null;
} else {
return mgr.getExpatListElement(id);
}
}
protected ExpatListElement removeExpatListElementFor(String id) {
ReplicationManagerBase mgr
= (ReplicationManagerBase)getManager();
return mgr.removeExpatListElement(id);
}
private ReplicationState findSessionViaBroadcastOrUnicast(String id, String version)
throws BackingStoreException {
try {
ExpatListElement expat = this.getExpatListElementFor(id);
if(expat == null || expat.getInstanceName() == null) {
return findSessionViaBroadcast(id, version);
} else {
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("doing unicast load id = " + id + " version = " + version + "to instance: " + expat.getInstanceName());
}
return findSessionViaUnicast(id, version, expat.getInstanceName());
}
} finally {
removeExpatListElementFor(id);
}
}
private ReplicationState loadSessionFromRemoteActiveCache(String id,
String version,
String instanceName)
throws BackingStoreException {
ReplicationState returnState = findSessionViaUnicast(id, version, instanceName);
if (returnState != null && returnState.getState() != null) {
__addToRemotelyLoadedSessionIds(id);
removeExpatListElementFor(id);
}
return returnState;
}
private ReplicationState findSessionViaUnicast(String id, String version, String instanceName)
throws BackingStoreException {
if (ReplicationUtil.getInstanceName().equals(instanceName)) {
// We can't unicast to ourselves. This request can happen
// for version unaware loads; we return null to indicate
// to use whatever is in the replica cache
return null;
}
return sendUnicastLoadQuery(id, version, instanceName);
}
private ReplicationState findSessionViaBroadcast(String id, String version)
throws BackingStoreException {
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("ReplicationStore>>findSessionViaBroadcast");
}
ReplicationManagerBase mgr
= (ReplicationManagerBase)this.getManager();
BackingStore replicator = mgr.getBackingStore();
JxtaBackingStoreImpl jxtaReplicator = null;
if(replicator instanceof JxtaBackingStoreImpl) {
jxtaReplicator = (JxtaBackingStoreImpl)replicator;
}
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("ReplicationStore>>findSessionViaBroadcast: replicator: " + replicator);
}
ReplicationState queryResult = jxtaReplicator != null ?
jxtaReplicator.__load(id, version) : null;
return queryResult;
}
void sendUnicastLoadAcknowledgement(String id, String instanceName)
throws IOException {
//send load received ack to instanceName
ReplicationManagerBase mgr
= (ReplicationManagerBase)getManager();
String theCommand = mgr.MESSAGE_BROADCAST_LOAD_RECEIVED;
ReplicationState loadReceivedState =
ReplicationState.createBroadcastLoadReceivedState(MODE_WEB, id, this.getApplicationId(), 0L, ReplicationUtil.getInstanceName(), theCommand);
JxtaReplicationSender sender
= JxtaReplicationSender.createInstance();
sender.sendOverPropagatedPipe(loadReceivedState, instanceName, false);
//if we want to batch unicast load acks use next line
//sender.sendReplicationReceivedState(loadReceivedState, instanceName);
}
ReplicationState sendUnicastLoadQuery(String id, String version, String instanceName)
{
//send load query to instanceName via unicast
ReplicationManagerBase mgr
= (ReplicationManagerBase)getManager();
String theCommand = mgr.LOAD_SESSION_COMMAND;
ReplicationState loadState
= ReplicationState.createUnicastLoadState(MODE_WEB, id, this.getApplicationId(), ReplicationUtil.parseLong(version), ReplicationUtil.getInstanceName(), theCommand);
JxtaReplicationSender sender
= JxtaReplicationSender.createInstance();
ReplicationState returnState
= sender.sendReplicationLoadState(loadState, instanceName, useReplicationUnicastLoadBatching);
return returnState;
}
SimpleMetadata loadUnicast(String id, String version, String instanceName)
throws BackingStoreException {
ReplicationState state = sendUnicastLoadQuery(id, version, instanceName);
SimpleMetadata result = ReplicationState.createSimpleMetadataFrom(state, isReplicationCompressionEnabled());
if(result != null) {
__addToRemotelyLoadedSessionIds(id);
}
return result;
}
protected void __addToRemotelyLoadedSessionIds(String id) {
ReplicationManagerBase mgr
= (ReplicationManagerBase) this.getManager();
mgr.getRemotelyLoadedSessionIds().add(id);
}
protected boolean __removeFromRemotelyLoadedSessionIds(String id) {
ReplicationManagerBase mgr
= (ReplicationManagerBase) this.getManager();
return mgr.getRemotelyLoadedSessionIds().remove(id);
}
/**
* update the lastaccess time of the specified Session into this Store.
*
* @param session Session to be saved
*
* @exception IOException if an input/output error occurs
*/
public void updateLastAccessTime(Session session) throws IOException {
ReplicationManagerBase mgr
= (ReplicationManagerBase)this.getManager();
BackingStore replicator = mgr.getBackingStore();
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("ReplicationStore>>updateLastAccessTime: replicator: " + replicator);
}
try {
/* FIXED
replicator.updateLastAccessTime(session.getIdInternal(), //id
((BaseHASession)session).getLastAccessedTimeInternal(), //lastaccesstime
session.getVersion()); //version
*/
SimpleMetadata smd = SimpleMetadataFactory.createSimpleMetadata(session.getVersion(),
((BaseHASession)session).getLastAccessedTimeInternal());
replicator.save(session.getIdInternal(), smd, !((HASession) session).isPersistent()); //version
} catch (BackingStoreException ex) {
//FIXME
}
}
/**
* Return an array containing the session identifiers of all Sessions
* currently saved in this Store. If there are no such Sessions, a
* zero-length array is returned.
*
* @exception IOException if an input/output error occurred
*/
public String[] keys() throws IOException {
//FIXME
return new String[0];
}
public int getSize() throws IOException {
int result = 0;
ReplicationManagerBase mgr
= (ReplicationManagerBase)this.getManager();
BackingStore replicator = mgr.getBackingStore();
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("ReplicationStore>>getSize: replicator: " + replicator);
}
try {
result = replicator.size();
} catch (BackingStoreException ex) {
//nothing to do - ok to eat exception
}
return result;
}
// Store methods end
private Session getSession(SimpleMetadata metaData) throws IOException {
if (metaData == null || metaData.getState() == null) {
return null;
} else {
HttpSessionExtraParams extraParams
= (HttpSessionExtraParams) metaData.getExtraParam();
String ssoId = null;
if (extraParams != null) {
//ssoid is the extraParam in extraParams
ssoId = extraParams.getSsoId();
}
return getSession(metaData.getState(),
ssoId, metaData.getVersion());
}
}
/**
* Given a byte[] containing session data, return a session
* object
*
* @param replicationState
* The byte[] with the session data
*
* @return
* A newly created session for the given session data, and associated
* with this Manager
*/
public Session getSession(ReplicationState replicationState)
throws IOException {
if (replicationState == null || replicationState.getState() == null) {
return null;
} else {
return getSession(replicationState.getState(),
replicationState.getExtraParam(), replicationState.getVersion());
}
}
public Session getSession(byte[] state, String ssoId, long version) throws IOException {
Session _session = null;
InputStream is = null;
BufferedInputStream bis = null;
ByteArrayInputStream bais = null;
Loader loader = null;
ClassLoader classLoader = null;
ObjectInputStream ois = null;
Container container = manager.getContainer();
java.security.Principal pal=null; //MERGE chg added
IOUtilsCaller utilsCaller = null;
try
{
bais = new ByteArrayInputStream(state);
bis = new BufferedInputStream(bais);
if(isReplicationCompressionEnabled()) {
is = new GZIPInputStream(bis);
} else {
is = bis;
}
//Get the username, ssoId from replicationState
//ssoId = replicationState.getSsoId();
//debug("ReplicationStore.getSession() id="+id+" username ="+username+";");
if(_logger.isLoggable(Level.FINEST)) {
_logger.finest("loaded session from replicationstore, length = "+state.length);
}
if (container != null) {
loader = container.getLoader();
}
if (loader != null) {
classLoader = loader.getClassLoader();
}
//Bug 4832603 : EJB Reference Failover
//HERCULES FIXME: for now reverting back
//need to look at new EJBUtils and related serialization code
/*
if (classLoader != null) {
ois = new CustomObjectInputStream(bis, classLoader);
}
else {
ois = new ObjectInputStream(bis);
}
//ois = EJBUtils.getInputStream(bis, classLoader, true, true);
//end - Bug 4832603
*/
if (classLoader != null) {
if( (utilsCaller = this.getWebUtilsCaller()) != null) {
try {
ois = utilsCaller.createObjectInputStream(is, true, classLoader);
} catch (Exception ex) {}
}
}
if (ois == null) {
ois = new ObjectInputStream(is);
}
if(ois != null) {
try {
_session = readSession(manager, ois);
}
finally {
if (ois != null) {
try {
ois.close();
bis = null;
}
catch (IOException e) {
}
}
}
}
}
catch(ClassNotFoundException e)
{
IOException ex1 = (IOException) new IOException(
"Error during deserialization: " + e.getMessage()).initCause(e);
throw ex1;
}
catch(IOException e)
{
//if (_logger.isLoggable(Level.FINE)) {
// _logger.fine("Exception occurred in getSession", e);
//}
throw e;
}
String username = ((HASession)_session).getUserName();
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("ReplicationStore>>getSession: username=" + username + " principal=" + _session.getPrincipal());
}
if((username !=null) && (!username.equals("")) && _session.getPrincipal() == null) {
if (_debug > 0) {
debug("Username retrieved is "+username);
}
pal = ((com.sun.web.security.RealmAdapter)container.getRealm()).createFailOveredPrincipal(username);
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("ReplicationStore>>getSession:created pal=" + pal);
}
if (_debug > 0) {
debug("principal created using username "+pal);
}
if(pal != null) {
_session.setPrincipal(pal);
if (_debug > 0) {
debug("getSession principal="+pal+" was added to session="+_session);
}
}
}
//--SRI
_session.setNew(false);
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("ReplicationStore>>getSession:ssoId=" + ssoId);
}
((BaseHASession)_session).setSsoId(ssoId);
if((ssoId !=null) && (!ssoId.equals("")))
associate(ssoId, _session);
((HASession)_session).setVersion(version);
((HASession)_session).setDirty(false);
((HASession)_session).setPersistent(false);
return _session;
}
protected void associate(String ssoId, Session _session) {
if (_debug > 0) {
debug("Inside associate() -- ReplicationStore");
}
Container parent = manager.getContainer();
SingleSignOn sso = null;
while ((sso == null) && (parent != null)) {
if (_debug > 0) {
debug("Inside associate() while loop -- ReplicationStore");
}
if (!(parent instanceof Pipeline)) {
if (_debug > 0) {
debug("Inside associate() parent instanceof Pipeline -- ReplicationStore");
}
parent = parent.getParent();
continue;
}
Valve valves[] = ((Pipeline) parent).getValves();
for (int i = 0; i < valves.length; i++) {
if (valves[i] instanceof SingleSignOn) {
if (_debug > 0) {
debug("Inside associate() valves[i] instanceof SingleSignOn -- ReplicationStore");
}
if (valves[i] instanceof ReplicationSingleSignOn) {
sso = (SingleSignOn) valves[i];
break;
} else {
_logger.log(Level.WARNING, "SSO misconfigured: sso is enabled but sso failover is not enabled");
}
}
}
if (sso == null)
parent = parent.getParent();
}
if (sso != null) {
if (_debug > 0) {
debug("Inside associate() sso != null");
}
//SingleSignOnEntry ssoEntry = ((ReplicationSingleSignOn)sso).lookup(ssoId);
SingleSignOnEntry ssoEntry = ((ReplicationSingleSignOn)sso).lookupEntry(ssoId);
if(_logger.isLoggable(Level.FINEST)) {
_logger.finest("ReplicationStore>>associate: ssoEntry = "+ssoEntry);
_logger.finest("ReplicationStore>>associate: ssoEntry.principal = " + ssoEntry.principal + "_session.getPrincipal() =" + _session.getPrincipal());
}
if(ssoEntry!=null) {
ssoEntry.addSession(sso, _session);
if(ssoEntry.principal == null && _session.getPrincipal() != null) {
ssoEntry.principal = _session.getPrincipal();
}
}
}
}
protected String getUsername(StandardSession session) {
String result = null;
if(session.getPrincipal() !=null){
result = session.getPrincipal().getName();
} else {
result = "";
}
return result;
}
protected String getSsoId(StandardSession session) {
return ((HASession)session).getSsoId();
}
// find the session in local active cache, passivate it and remove from local cache.
public ReplicableEntity findSessionAndPassivate(String id) {
ReplicationManagerBase mgr
= (ReplicationManagerBase) this.getManager();
return mgr.findSessionAndPassivate(id, new AtomicBoolean());
}
// get the active cache sessions.
public Map<String, ReplicableEntity> getActiveCache() {
ReplicationManagerBase mgr
= (ReplicationManagerBase) this.getManager();
return mgr.getActiveHttpSessions();
}
// put the state in the local replica cache.
public void putInReplicaCache(ReplicationState state) {
ReplicationManagerBase mgr
= (ReplicationManagerBase) this.getManager();
mgr.putInReplicationCache(state);
}
// remove the entry from replica cache with given id.
public void removeFromReplicaCache(String id) {
ReplicationManagerBase mgr
= (ReplicationManagerBase) this.getManager();
mgr.removeFromReplicationCache(id);
}
public BaseCache getReplicaCache() {
ReplicationManagerBase mgr
= (ReplicationManagerBase) this.getManager();
return mgr.getReplicatedSessions();
}
public ReplicableEntity deserialize(ReplicationState state) {
try {
return (ReplicableEntity) getSession(state);
} catch (IOException ex) {
return null;
}
}
public void activate(ReplicableEntity session) {
ReplicationManagerBase mgr
= (ReplicationManagerBase) this.getManager();
mgr.activate((Session) session, true);
}
public String getMode() {
return MODE_WEB;
}
}