/*
* 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.
*/
package com.sun.enterprise.ee.web.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.ArrayList;
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 javax.servlet.ServletContext;
import org.apache.catalina.Context;
import org.apache.catalina.Globals;
import org.apache.catalina.Loader;
import org.apache.catalina.Container;
import org.apache.catalina.session.IOUtilsCaller;
import org.apache.catalina.util.CustomObjectInputStream;
/**
* Implementation of FileSync for http sessions and replicas
*/
public final class WebFileSync 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);
// ----------------------------------------------------- Constants
/**
* The descriptive information about this implementation.
*/
private static final String INFO = "WebFileSync/1.0";
/**
* Name to register for this Store, used for logging.
*/
private static final String STORENAME = "webFileSync";
/**
* Name to register for the background thread.
*/
private static final String THREADNAME = "WebFileSync";
// ----------------------------------------------------- Instance Variables
// ------------------------------------------------- Properties
/** Creates a new instance of WebFileSync
* @param mgr*/
public WebFileSync(ReplicationManager mgr) {
manager = mgr;
if(manager.getRollingUpgradeBackupDirectory() != null) {
this.setDirectory(manager.getRollingUpgradeBackupDirectory());
}
}
// --------------------------------------------------------- Public Methods
/**
* Remove all of the Sessions in this Store.
*
* @exception IOException if an input/output error occurs
*/
public void clear()
throws IOException {
//FIXME - this isn't correct implementation
String[] keys = keys();
for (int i = 0; i < keys.length; i++) {
remove(keys[i]);
}
}
/**
* 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 {
// Acquire the list of files in our storage directory
File file = directory();
if (file == null) {
return (new String[0]);
}
String files[] = file.list();
// Build and return the list of session identifiers
ArrayList list = new ArrayList();
int n = FILE_ACTIVE_EXT.length();
for (int i = 0; i < files.length; i++) {
if (files[i].endsWith(FILE_ACTIVE_EXT)) {
list.add(files[i].substring(0, files[i].length() - n));
}
}
return ((String[]) list.toArray(new String[list.size()]));
}
/**
* Load web artifacts from backup 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
long startTime = System.currentTimeMillis();
ReplicationManagerBase mgr = (ReplicationManagerBase)manager;
CountDownLatch doneSignal = new CountDownLatch(3);
//load active cache
SessionLoad sessionLoad
= new SessionLoad(this, mgr, doneSignal);
RollingUpgradeHandler.executeTask(sessionLoad);
//load replica cache
ReplicatedSessionLoad replicatedSessionLoad
= new ReplicatedSessionLoad(this, mgr, doneSignal);
RollingUpgradeHandler.executeTask(replicatedSessionLoad);
//load replica update cache
SessionUpdateLoad sessionUpdateLoad
= new SessionUpdateLoad(this, mgr, doneSignal);
RollingUpgradeHandler.executeTask(sessionUpdateLoad);
try {
doneSignal.await(waitTime, TimeUnit.SECONDS);
} catch(InterruptedException ex) {
;
} finally {
if(doneSignal.getCount() != 0) {
String errorMsg = "WebFileSync>>load timed out after " + waitTime + " seconds";
ReplicationUtil.handleErrorMsg(errorMsg, _logger, ctx);
} else {
if (_logger.isLoggable(Level.FINE)) {
_logger.fine("WebFileSync 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 = ((ReplicationManagerBase)manager).getContainer();
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 web artifacts to backup 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 {
long startTime = 0L;
if (_logger.isLoggable(Level.FINE)) {
startTime = System.currentTimeMillis();
}
ReplicationManagerBase mgr = (ReplicationManagerBase)manager;
CountDownLatch doneSignal = new CountDownLatch(3);
//save active cache
SessionSave sessionSave
= new SessionSave(this, mgr, doneSignal);
RollingUpgradeHandler.executeTask(sessionSave);
//save replica cache
ReplicatedSessionSave replicatedSessionSave
= new ReplicatedSessionSave(this, mgr, doneSignal);
RollingUpgradeHandler.executeTask(replicatedSessionSave);
//save replica update cache
SessionUpdateSave sessionUpdateSave
= new SessionUpdateSave(this, mgr, doneSignal);
RollingUpgradeHandler.executeTask(sessionUpdateSave);
try {
doneSignal.await(waitTime, TimeUnit.SECONDS);
} catch(InterruptedException ex) {
;
} finally {
if(doneSignal.getCount() != 0) {
String errorMsg = "WebFileSync>>save timed out after " + waitTime + " seconds";
ReplicationUtil.handleErrorMsg(errorMsg, _logger, ctx);
} else {
if (_logger.isLoggable(Level.FINE)) {
_logger.fine("WebFileSync 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 = ((ReplicationManagerBase)manager).getContainer();
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 {
WebFileSync _fileSync = null;
ReplicationManagerBase _mgr = null;
CountDownLatch _doneSignal = null;
public SessionSave(WebFileSync fileSync, ReplicationManagerBase mgr, CountDownLatch doneSignal) {
_fileSync = fileSync;
_mgr = mgr;
_doneSignal = doneSignal;
}
public void run() {
ObjectOutputStream oos = null;
try {
oos = _fileSync.getObjectOutputStream(FILE_ACTIVE_EXT);
_mgr.writeSessions(oos);
} catch (IOException ex) {
//log warning
} finally {
try {
oos.close();
} catch (IOException ex2) {
;
}
_doneSignal.countDown();
}
}
}
private class ReplicatedSessionSave implements Runnable {
WebFileSync _fileSync = null;
ReplicationManagerBase _mgr = null;
CountDownLatch _doneSignal = null;
public ReplicatedSessionSave(WebFileSync fileSync, ReplicationManagerBase mgr, CountDownLatch doneSignal) {
_fileSync = fileSync;
_mgr = mgr;
_doneSignal = doneSignal;
}
public void run() {
ObjectOutputStream oos = null;
try {
oos = _fileSync.getObjectOutputStream(FILE_REPLICA_EXT);
writeReplicatedSessions(_mgr.getReplicatedSessions(), oos);
} catch (IOException ex) {
//log warning
} finally {
try {
oos.close();
} catch (IOException ex2) {
;
}
_doneSignal.countDown();
}
}
}
private class SessionUpdateSave implements Runnable {
WebFileSync _fileSync = null;
ReplicationManagerBase _mgr = null;
CountDownLatch _doneSignal = null;
public SessionUpdateSave(WebFileSync fileSync, ReplicationManagerBase mgr, CountDownLatch doneSignal) {
_fileSync = fileSync;
_mgr = mgr;
_doneSignal = doneSignal;
}
public void run() {
ObjectOutputStream oos = null;
try {
oos = _fileSync.getObjectOutputStream(FILE_REPLICA_UPDATE_EXT);
_mgr.writeReplicatedSessionUpdates(oos);
} catch (IOException ex) {
//log warning
} finally {
try {
oos.close();
} catch (IOException ex2) {
;
}
_doneSignal.countDown();
}
}
}
private class SessionLoad implements Runnable {
WebFileSync _fileSync = null;
ReplicationManagerBase _mgr = null;
CountDownLatch _doneSignal = null;
public SessionLoad(WebFileSync fileSync, ReplicationManagerBase mgr, CountDownLatch doneSignal) {
_fileSync = fileSync;
_mgr = mgr;
_doneSignal = doneSignal;
}
public void run() {
ObjectInputStream ois = null;
try {
File file = getFile(FILE_ACTIVE_EXT);
ois = _fileSync.getObjectInputStream(file);
if(ois == null) {
return;
}
_mgr.readSessions(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 {
WebFileSync _fileSync = null;
ReplicationManagerBase _mgr = null;
CountDownLatch _doneSignal = null;
public ReplicatedSessionLoad(WebFileSync fileSync, ReplicationManagerBase mgr, CountDownLatch doneSignal) {
_fileSync = fileSync;
_mgr = mgr;
_doneSignal = doneSignal;
}
public void run() {
ObjectInputStream ois = null;
try {
File file = getFile(FILE_REPLICA_EXT);
ois = _fileSync.getObjectInputStream(file);
if(ois == null) {
return;
}
readReplicatedSessions(_mgr.getReplicatedSessions(), 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 {
WebFileSync _fileSync = null;
ReplicationManagerBase _mgr = null;
CountDownLatch _doneSignal = null;
public SessionUpdateLoad(WebFileSync fileSync, ReplicationManagerBase mgr, CountDownLatch doneSignal) {
_fileSync = fileSync;
_mgr = mgr;
_doneSignal = doneSignal;
}
public void run() {
ObjectInputStream ois = null;
try {
File file = getFile(FILE_REPLICA_UPDATE_EXT);
ois = _fileSync.getObjectInputStream(file);
if(ois == null) {
return;
}
_mgr.readReplicatedSessionUpdates(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();
}
}
}
}