/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
* Copyright (c) Ericsson AB, 2004-2008. 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.
*/
package org.jvnet.glassfish.comms.replication.sessmgmt;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.logging.Logger;
import java.util.logging.Level;
import com.sun.logging.LogDomains;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.apache.catalina.Container;
import javax.servlet.ServletContext;
import org.apache.catalina.Context;
import org.apache.catalina.Globals;
import org.apache.catalina.Loader;
import org.apache.catalina.session.IOUtilsCaller;
import org.apache.catalina.util.CustomObjectInputStream;
import com.sun.enterprise.ee.web.sessmgmt.*;
/**
*
* @author Larry White
*/
public class SipFileSync extends BaseFileSync {
public final static String LOGGER_MEM_REP
= ReplicationState.LOGGER_MEM_REP;
/**
* The logger to use for logging ALL web container related messages.
*/
private static final Logger _logger
= Logger.getLogger(LOGGER_MEM_REP);
public enum SyncMode {
SYNC_MODE_SAS, SYNC_MODE_SS, SYNC_MODE_ST
}
/**
* The extension to use for serialized SipApplicationSession filenames.
*/
protected static final String FILE_SAS_ACTIVE_EXT = ".sasactive";
/**
* The extension to use for serialized SipApplicationSession replica filenames.
*/
protected static final String FILE_SAS_REPLICA_EXT = ".sasreplica";
/**
* The extension to use for serialized SipApplicationSession replica update filenames.
*/
protected static final String FILE_SAS_REPLICA_UPDATE_EXT = ".sasreplicaupd";
/**
* The extension to use for serialized SipSession filenames.
*/
protected static final String FILE_SS_ACTIVE_EXT = ".ssactive";
/**
* The extension to use for serialized SipSession replica filenames.
*/
protected static final String FILE_SS_REPLICA_EXT = ".ssreplica";
/**
* The extension to use for serialized SipSession replica update filenames.
*/
protected static final String FILE_SS_REPLICA_UPDATE_EXT = ".ssreplicaupd";
/**
* The extension to use for serialized ServletTimer filenames.
*/
protected static final String FILE_ST_ACTIVE_EXT = ".stimeractive";
/**
* The extension to use for serialized ServletTimer replica filenames.
*/
protected static final String FILE_ST_REPLICA_EXT = ".stimerreplica";
/**
* The extension to use for serialized ServletTimer replica update filenames.
*/
protected static final String FILE_ST_REPLICA_UPDATE_EXT = ".stimerreplicaupd";
/**
* The descriptive information about this implementation.
*/
private static final String INFO = "SipFileSync/1.0";
/**
* Name to register for this Store, used for logging.
*/
private static final String STORENAME = "sipFileSync";
/**
* Name to register for the background thread.
*/
private static final String THREADNAME = "SipFileSync";
// ------------------------------------------------- Properties
/** Creates a new instance of SipFileSync
* @param mgr*/
public SipFileSync(ReplicationManager mgr) {
manager = mgr;
if(manager.getRollingUpgradeBackupDirectory() != null) {
this.setDirectory(manager.getRollingUpgradeBackupDirectory());
}
}
/**
* Load the Sip artifacts from backed up files
* @param waitTime the waitTime in seconds
* @param ctx the RollingUpgradeContext
* @exception ClassNotFoundException if a deserialization error occurs
* @exception IOException if an input/output error occurs
*/
public void load(long waitTime, RollingUpgradeContext ctx)
throws ClassNotFoundException, IOException {
// Open an input stream to the specified pathname, if any
SipTransactionPersistentManager mgr = (SipTransactionPersistentManager)manager;
long startTime = System.currentTimeMillis();
CountDownLatch doneSignal = new CountDownLatch(9);
//load sas active cache
SessionLoad sessionLoadSAS
= new SessionLoad(this, mgr, doneSignal, SyncMode.SYNC_MODE_SAS, FILE_SAS_ACTIVE_EXT);
RollingUpgradeHandler.executeTask(sessionLoadSAS);
//load sas replica cache
ReplicatedSessionLoad replicatedSessionLoadSAS
= new ReplicatedSessionLoad(this, mgr, doneSignal, SyncMode.SYNC_MODE_SAS, FILE_SAS_REPLICA_EXT);
RollingUpgradeHandler.executeTask(replicatedSessionLoadSAS);
//load sas replica update cache
SessionUpdateLoad sessionUpdateLoadSAS
= new SessionUpdateLoad(this, mgr, doneSignal, SyncMode.SYNC_MODE_SAS, FILE_SAS_REPLICA_UPDATE_EXT);
RollingUpgradeHandler.executeTask(sessionUpdateLoadSAS);
//load ss active cache
SessionLoad sessionLoadSS
= new SessionLoad(this, mgr, doneSignal, SyncMode.SYNC_MODE_SS, FILE_SS_ACTIVE_EXT);
RollingUpgradeHandler.executeTask(sessionLoadSS);
//load ss replica cache
ReplicatedSessionLoad replicatedSessionLoadSS
= new ReplicatedSessionLoad(this, mgr, doneSignal, SyncMode.SYNC_MODE_SS, FILE_SS_REPLICA_EXT);
RollingUpgradeHandler.executeTask(replicatedSessionLoadSS);
//load ss replica update cache
SessionUpdateLoad sessionUpdateLoadSS
= new SessionUpdateLoad(this, mgr, doneSignal, SyncMode.SYNC_MODE_SS, FILE_SS_REPLICA_UPDATE_EXT);
RollingUpgradeHandler.executeTask(sessionUpdateLoadSS);
//load st active cache
SessionLoad sessionLoadST
= new SessionLoad(this, mgr, doneSignal, SyncMode.SYNC_MODE_ST, FILE_ST_ACTIVE_EXT);
RollingUpgradeHandler.executeTask(sessionLoadST);
//load st replica cache
ReplicatedSessionLoad replicatedSessionLoadST
= new ReplicatedSessionLoad(this, mgr, doneSignal, SyncMode.SYNC_MODE_ST, FILE_ST_REPLICA_EXT);
RollingUpgradeHandler.executeTask(replicatedSessionLoadST);
//load st replica update cache
SessionUpdateLoad sessionUpdateLoadST
= new SessionUpdateLoad(this, mgr, doneSignal, SyncMode.SYNC_MODE_ST, FILE_ST_REPLICA_UPDATE_EXT);
RollingUpgradeHandler.executeTask(sessionUpdateLoadST);
try {
doneSignal.await(waitTime, TimeUnit.SECONDS);
} catch(InterruptedException ex) {
;
} finally {
if(doneSignal.getCount() != 0) {
String errorMsg = "SipFileSync>>load timed out after " + waitTime + " seconds";
ReplicationUtil.handleErrorMsg(errorMsg, _logger, ctx);
} else {
if (_logger.isLoggable(Level.FINE)) {
_logger.fine("SipFileSync load successful after a wait: wait time = " + (System.currentTimeMillis() - startTime));
}
}
}
}
private ObjectInputStream getObjectInputStream(File file) throws IOException {
// Open an input stream to the specified pathname, if any
if (file == null) {
return null;
} else {
if (_logger.isLoggable(Level.FINE)) {
_logger.fine("file name for ois: " + file.getCanonicalPath());
}
}
if (! file.exists()) {
return (null);
}
FileInputStream fis = null;
ObjectInputStream ois = null;
Loader loader = null;
ClassLoader classLoader = null;
try {
fis = new FileInputStream(file.getAbsolutePath());
BufferedInputStream bis = new BufferedInputStream(fis);
Container container = ((SipTransactionPersistentManager)manager).getContext();
if (container != null)
loader = container.getLoader();
if (loader != null)
classLoader = loader.getClassLoader();
if (classLoader != null) {
IOUtilsCaller caller =
ReplicationUtil.getWebUtilsCaller();
if (caller != null) {
try {
ois = caller.createObjectInputStream(bis, true, classLoader);
} catch (Exception ex) {}
} else {
ois = new CustomObjectInputStream(bis, classLoader);
}
}
if (ois == null) {
ois = new ObjectInputStream(bis);
}
} catch (FileNotFoundException e) {
return (null);
} catch (IOException e) {
if (ois != null) {
try {
ois.close();
} catch (IOException f) {
;
}
ois = null;
}
throw e;
}
return ois;
}
/**
* 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 remove(String id) throws IOException {
File file = file(id, FILE_ACTIVE_EXT);
if (file == null) {
return;
}
file.delete();
}
/**
* Save the Sip artifacts to back up files
* @param waitTime the waitTime in seconds
* @param ctx the RollingUpgradeContext
* @exception IOException if an input/output error occurs
*/
public void save(long waitTime, RollingUpgradeContext ctx) throws IOException {
SipTransactionPersistentManager mgr = (SipTransactionPersistentManager)manager;
long startTime = 0L;
if (_logger.isLoggable(Level.FINE)) {
startTime = System.currentTimeMillis();
}
CountDownLatch doneSignal = new CountDownLatch(9);
//save sas active cache
SessionSave sessionSaveSAS
= new SessionSave(this, mgr, doneSignal, SyncMode.SYNC_MODE_SAS, FILE_SAS_ACTIVE_EXT);
RollingUpgradeHandler.executeTask(sessionSaveSAS);
//save sas replica cache
ReplicatedSessionSave replicatedSessionSaveSAS
= new ReplicatedSessionSave(this, mgr, doneSignal, SyncMode.SYNC_MODE_SAS, FILE_SAS_REPLICA_EXT);
RollingUpgradeHandler.executeTask(replicatedSessionSaveSAS);
//save sas replica update cache
SessionUpdateSave sessionUpdateSaveSAS
= new SessionUpdateSave(this, mgr, doneSignal, SyncMode.SYNC_MODE_SAS, FILE_SAS_REPLICA_UPDATE_EXT);
RollingUpgradeHandler.executeTask(sessionUpdateSaveSAS);
//save ss active cache
SessionSave sessionSaveSS
= new SessionSave(this, mgr, doneSignal, SyncMode.SYNC_MODE_SS, FILE_SS_ACTIVE_EXT);
RollingUpgradeHandler.executeTask(sessionSaveSS);
//save ss replica cache
ReplicatedSessionSave replicatedSessionSaveSS
= new ReplicatedSessionSave(this, mgr, doneSignal, SyncMode.SYNC_MODE_SS, FILE_SS_REPLICA_EXT);
RollingUpgradeHandler.executeTask(replicatedSessionSaveSS);
//save ss replica update cache
SessionUpdateSave sessionUpdateSaveSS
= new SessionUpdateSave(this, mgr, doneSignal, SyncMode.SYNC_MODE_SS, FILE_SS_REPLICA_UPDATE_EXT);
RollingUpgradeHandler.executeTask(sessionUpdateSaveSS);
//save st active cache
SessionSave sessionSaveST
= new SessionSave(this, mgr, doneSignal, SyncMode.SYNC_MODE_ST, FILE_ST_ACTIVE_EXT);
RollingUpgradeHandler.executeTask(sessionSaveST);
//save st replica cache
ReplicatedSessionSave replicatedSessionSaveST
= new ReplicatedSessionSave(this, mgr, doneSignal, SyncMode.SYNC_MODE_ST, FILE_ST_REPLICA_EXT);
RollingUpgradeHandler.executeTask(replicatedSessionSaveST);
//save st replica update cache
SessionUpdateSave sessionUpdateSaveST
= new SessionUpdateSave(this, mgr, doneSignal, SyncMode.SYNC_MODE_ST, FILE_ST_REPLICA_UPDATE_EXT);
RollingUpgradeHandler.executeTask(sessionUpdateSaveST);
try {
doneSignal.await(waitTime, TimeUnit.SECONDS);
} catch(InterruptedException ex) {
;
} finally {
if(doneSignal.getCount() != 0) {
String errorMsg = "SipFileSync>>save timed out after " + waitTime + " seconds";
ReplicationUtil.handleErrorMsg(errorMsg, _logger, ctx);
} else {
if (_logger.isLoggable(Level.FINE)) {
_logger.fine("SipFileSync save successful after a wait: wait time = " + (System.currentTimeMillis() - startTime));
}
}
}
}
/**
* Return a File object representing the pathname to our
* session persistence directory, if any. The directory will be
* created if it does not already exist.
*/
protected File directory() {
if (this.directory == null) {
return (null);
}
File file = new File(this.directory);
try {
if (_logger.isLoggable(Level.FINE)) {
_logger.fine("first file:" + file.getCanonicalPath());
_logger.fine("first file isAbsolute:" + file.isAbsolute());
}
} catch (Exception ex) {ex.printStackTrace();}
if (!file.isAbsolute()) {
Container container = ((SipTransactionPersistentManager)manager).getContext();
if (container instanceof Context) {
ServletContext servletContext =
((Context) container).getServletContext();
File work = (File)
servletContext.getAttribute(Globals.WORK_DIR_ATTR);
file = new File(work, this.directory);
} else {
throw new IllegalArgumentException
("Parent Container is not a Context");
}
}
if (!file.exists() || !file.isDirectory()) {
file.delete();
file.mkdirs();
}
return (file);
}
private class SessionSave implements Runnable {
SyncMode _mode = null;
String _fileExtension = null;
SipFileSync _fileSync = null;
SipTransactionPersistentManager _mgr = null;
CountDownLatch _doneSignal = null;
public SessionSave(SipFileSync fileSync, SipTransactionPersistentManager mgr, CountDownLatch doneSignal, SyncMode mode, String fileExtension) {
_mode = mode;
_fileExtension = fileExtension;
_fileSync = fileSync;
_mgr = mgr;
_doneSignal = doneSignal;
}
public void run() {
ObjectOutputStream oos = null;
try {
oos = _fileSync.getObjectOutputStream(_fileExtension);
switch(_mode) {
case SYNC_MODE_SAS: _mgr.writeSipApplicationSessions(oos);
case SYNC_MODE_SS: _mgr.writeSipSessions(oos);
case SYNC_MODE_ST: _mgr.writeServletTimers(oos);
}
} catch (IOException ex) {
//log warning
} finally {
try {
oos.close();
} catch (IOException ex2) {
;
}
_doneSignal.countDown();
}
}
}
private class ReplicatedSessionSave implements Runnable {
SyncMode _mode = null;
String _fileExtension = null;
SipFileSync _fileSync = null;
SipTransactionPersistentManager _mgr = null;
CountDownLatch _doneSignal = null;
public ReplicatedSessionSave(SipFileSync fileSync, SipTransactionPersistentManager mgr, CountDownLatch doneSignal, SyncMode mode, String fileExtension) {
_mode = mode;
_fileExtension = fileExtension;
_fileSync = fileSync;
_mgr = mgr;
_doneSignal = doneSignal;
}
public void run() {
ObjectOutputStream oos = null;
try {
oos = _fileSync.getObjectOutputStream(_fileExtension);
switch(_mode) {
case SYNC_MODE_SAS: writeReplicatedSessions(_mgr.getReplicatedSipApplicationSessions(), oos);
case SYNC_MODE_SS: writeReplicatedSessions(_mgr.getReplicatedSipSessions(), oos);
case SYNC_MODE_ST: writeReplicatedSessions(_mgr.getReplicatedServletTimers(), oos);
}
} catch (IOException ex) {
//log warning
} finally {
try {
oos.close();
} catch (IOException ex2) {
;
}
_doneSignal.countDown();
}
}
}
private class SessionUpdateSave implements Runnable {
SyncMode _mode = null;
String _fileExtension = null;
SipFileSync _fileSync = null;
SipTransactionPersistentManager _mgr = null;
CountDownLatch _doneSignal = null;
public SessionUpdateSave(SipFileSync fileSync, SipTransactionPersistentManager mgr, CountDownLatch doneSignal, SyncMode mode, String fileExtension) {
_mode = mode;
_fileExtension = fileExtension;
_fileSync = fileSync;
_mgr = mgr;
_doneSignal = doneSignal;
}
public void run() {
ObjectOutputStream oos = null;
try {
oos = _fileSync.getObjectOutputStream(_fileExtension);
switch(_mode) {
case SYNC_MODE_SAS: _mgr.writeReplicatedSipApplicationSessionUpdates(oos);
case SYNC_MODE_SS: _mgr.writeReplicatedSipSessionUpdates(oos);
case SYNC_MODE_ST: _mgr.writeReplicatedServletTimerUpdates(oos);
}
} catch (IOException ex) {
//log warning
} finally {
try {
oos.close();
} catch (IOException ex2) {
;
}
_doneSignal.countDown();
}
}
}
private class SessionLoad implements Runnable {
SyncMode _mode = null;
String _fileExtension = null;
SipFileSync _fileSync = null;
SipTransactionPersistentManager _mgr = null;
CountDownLatch _doneSignal = null;
public SessionLoad(SipFileSync fileSync, SipTransactionPersistentManager mgr, CountDownLatch doneSignal, SyncMode mode, String fileExtension) {
_mode = mode;
_fileExtension = fileExtension;
_fileSync = fileSync;
_mgr = mgr;
_doneSignal = doneSignal;
}
public void run() {
ObjectInputStream ois = null;
try {
File file = getFile(_fileExtension);
ois = _fileSync.getObjectInputStream(file);
if(ois == null) {
return;
}
switch(_mode) {
case SYNC_MODE_SAS: {_mgr.readSipApplicationSessions(ois);
file.delete();}
case SYNC_MODE_SS: {_mgr.readSipSessions(ois);
file.delete();}
case SYNC_MODE_ST: {_mgr.readServletTimers(ois);
file.delete();}
}
} catch (IOException ex) {
//log warning
} catch (ClassNotFoundException ex2) {
//log warning
} finally {
if(ois != null) {
try {
ois.close();
} catch (IOException ex2) {
;
}
}
_doneSignal.countDown();
}
}
}
private class ReplicatedSessionLoad implements Runnable {
SyncMode _mode = null;
String _fileExtension = null;
SipFileSync _fileSync = null;
SipTransactionPersistentManager _mgr = null;
CountDownLatch _doneSignal = null;
public ReplicatedSessionLoad(SipFileSync fileSync, SipTransactionPersistentManager mgr, CountDownLatch doneSignal, SyncMode mode, String fileExtension) {
_mode = mode;
_fileExtension = fileExtension;
_fileSync = fileSync;
_mgr = mgr;
_doneSignal = doneSignal;
}
public void run() {
ObjectInputStream ois = null;
try {
File file = getFile(_fileExtension);
ois = _fileSync.getObjectInputStream(file);
if(ois == null) {
return;
}
switch(_mode) {
case SYNC_MODE_SAS: {readReplicatedSessions(_mgr.getReplicatedSipApplicationSessions(), ois);
file.delete();}
case SYNC_MODE_SS: {readReplicatedSessions(_mgr.getReplicatedSipSessions(), ois);
file.delete();}
case SYNC_MODE_ST: {readReplicatedSessions(_mgr.getReplicatedServletTimers(), ois);
file.delete();}
}
} catch (IOException ex) {
//log warning
} catch (ClassNotFoundException ex2) {
//log warning
} finally {
if(ois != null) {
try {
ois.close();
} catch (IOException ex2) {
;
}
}
_doneSignal.countDown();
}
}
}
private class SessionUpdateLoad implements Runnable {
SyncMode _mode = null;
String _fileExtension = null;
SipFileSync _fileSync = null;
SipTransactionPersistentManager _mgr = null;
CountDownLatch _doneSignal = null;
public SessionUpdateLoad(SipFileSync fileSync, SipTransactionPersistentManager mgr, CountDownLatch doneSignal, SyncMode mode, String fileExtension) {
_mode = mode;
_fileExtension = fileExtension;
_fileSync = fileSync;
_mgr = mgr;
_doneSignal = doneSignal;
}
public void run() {
ObjectInputStream ois = null;
try {
File file = getFile(_fileExtension);
ois = _fileSync.getObjectInputStream(file);
if(ois == null) {
return;
}
switch(_mode) {
case SYNC_MODE_SAS: {_mgr.readReplicatedSipApplicationSessionUpdates(ois);
file.delete();}
case SYNC_MODE_SS: {_mgr.readReplicatedSipSessionUpdates(ois);
file.delete();}
case SYNC_MODE_ST: {_mgr.readReplicatedServletTimerUpdates(ois);
file.delete();}
}
} catch (IOException ex) {
//log warning
} catch (ClassNotFoundException ex2) {
//log warning
} finally {
if(ois != null) {
try {
ois.close();
} catch (IOException ex2) {
;
}
}
_doneSignal.countDown();
}
}
}
}