/*
* 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 com.sun.enterprise.web.ServerConfigLookup;
import java.util.logging.Logger;
import java.util.logging.Level;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
import java.lang.reflect.Method;
/**
*
* @author Larry White
*/
public class RollingUpgradeHandler {
protected static final long MINIMUM_WAIT_TIME = 60L;
public static final String FILE_BASED_ROLLING_UPGRADE_TYPE = "file_based_rolling_upgrade";
public static final String MEMORY_BASED_ROLLING_UPGRADE_TYPE = "memory_based_rolling_upgrade";
public static String USED_ROLLING_UPGRADE_TYPE = MEMORY_BASED_ROLLING_UPGRADE_TYPE;
public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_ADVISORY
= "rollingupgradeadvisory";
public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_ACTIVE_CACHE_RECONCILIATION_ADVISORY
= "rollingupgradegetidsforactivecachereconciliationadvisory";
public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_ACTIVE_CACHE_RECONCILIATION_RESPONSE
= "rollingupgradegetidsforactivecachereconciliationresponse";
public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_REPLICA_CACHE_RECONCILIATION_ADVISORY
= "rollingupgradegetidsforreplicacachereconciliationadvisory";
public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_GET_IDS_FOR_REPLICA_CACHE_RECONCILIATION_RESPONSE
= "rollingupgradegetidsforreplicacachereconciliationresponse";
public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_REPLICA_RECONCILIATION_COMPLETE_ADVISORY
= "rollingupgradereplicareconciliationcompleteadvisory";
public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_ACTIVE_CACHE_RESTORATION_ADVISORY
= "rollingupgradeactivecacherestorationadvisory";
public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_ACTIVE_CACHE_RESTORATION_RESPONSE
= "rollingupgradeactivecacherestorationresponse";
public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_REPLICA_CACHE_RESTORATION_ADVISORY
= "rollingupgradereplicacacherestorationadvisory";
public final static String MESSAGE_BROADCAST_ROLLING_UPGRADE_REPLICA_CACHE_RESTORATION_RESPONSE
= "rollingupgradereplicacacherestorationresponse";
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);
private static volatile RollingUpgradeHandler soleInstance = null;
private static final Object monitor = new Object();
private static LinkedBlockingQueue senderTaskQueue = null;
private static final int NTHREADS = 25;
private static final ThreadPoolExecutor exec;
static final int COREPOOLSIZE = NTHREADS;
static final int MAXPOOLSIZE = NTHREADS;
static final int KEEPALIVETIME = 15; //seconds that a thread remains idle before terminating.
static {
senderTaskQueue = new LinkedBlockingQueue<Runnable>();
ThreadGroup threadGroup = new ThreadGroup(Thread.currentThread().getThreadGroup(), "Group RollingUpgrade");
exec = new ThreadPoolExecutor(COREPOOLSIZE, MAXPOOLSIZE,
KEEPALIVETIME, TimeUnit.SECONDS,
senderTaskQueue,
new RollingUpgradeThreadFactory("RollingUpgradeExecutor", threadGroup));
// Try to allow core threads to idle out. (Requires a 1.6 method)
try {
Method allowCoreThreadTimeOut = exec.getClass().getMethod("allowCoreThreadTimeOut", boolean.class);
allowCoreThreadTimeOut.invoke(exec, Boolean.TRUE);
} catch (Throwable ohWell) {
// Our attempt failed.
if (_logger.isLoggable(Level.FINEST)) {
_logger.log(Level.FINEST, "Failed to enable 'allowCoreThreadTimeOut'", ohWell);
}
}
}
public static void executeTask(Runnable r) {
exec.execute(r);
}
public static boolean isFileBased(String rollingUpgradeType) {
return rollingUpgradeType.equalsIgnoreCase(FILE_BASED_ROLLING_UPGRADE_TYPE);
}
public static boolean isMemoryBased(String rollingUpgradeType) {
return rollingUpgradeType.equalsIgnoreCase(MEMORY_BASED_ROLLING_UPGRADE_TYPE);
}
public static String getRollingUpgradeStrategyType() {
ServerConfigLookup lookup = new ServerConfigLookup();
return lookup.getRollingUpgradeStrategyType();
}
public static RollingUpgradeHandler getRollingUpgradeHandler() throws RollingUpgradeException {
if(soleInstance == null) {
synchronized (monitor) {
if(soleInstance == null) {
soleInstance = createRollingUpgradeHandler();
}
}
}
return soleInstance;
}
public static RollingUpgradeHandler createRollingUpgradeHandler() throws RollingUpgradeException {
String rollingUpgradeStrategyType = getRollingUpgradeStrategyType();
return createRollingUpgradeHandler(rollingUpgradeStrategyType);
}
public static RollingUpgradeHandler createRollingUpgradeHandler(String type) throws RollingUpgradeException {
if(type == null) {
return new MemoryRollingUpgradeHandler();
}
if(isFileBased(type)) {
return new FileRollingUpgradeHandler();
} else {
if(isMemoryBased(type)) {
return new MemoryRollingUpgradeHandler();
} else {
throw new RollingUpgradeException("invalid rolling upgrade handler type specified - must be either "
+ FILE_BASED_ROLLING_UPGRADE_TYPE
+ " or " + MEMORY_BASED_ROLLING_UPGRADE_TYPE);
}
}
}
public static void backupSessionState(long waitTime, long drainTime) throws RollingUpgradeException {
RollingUpgradeHandler handler = null;
try {
handler = RollingUpgradeHandler.createRollingUpgradeHandler();
handler.syncPointApps(waitTime);
try {
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("sleeping for drainTime = " + drainTime + " seconds");
}
Thread.sleep(drainTime * 1000);
} catch (InterruptedException iex) {}
} catch (RollingUpgradeException ex) {
_logger.log(Level.WARNING, "RollingUpgradeHandler>>error during backupSessionState");
ex.printStackTrace();
throw ex;
}
}
public void syncPointApps(long waitTime) throws RollingUpgradeException {
//no-op
//will be over-ridden for file-based approach only
}
public static void restoreSessionState(long waitTime) throws RollingUpgradeException {
RollingUpgradeHandler handler = null;
try {
handler = RollingUpgradeHandler.createRollingUpgradeHandler();
handler.restoreApps(waitTime);
} catch (RollingUpgradeException ex) {
_logger.log(Level.WARNING, "RollingUpgradeHandler>>error during restoreSessionState");
ex.printStackTrace();
throw ex;
}
}
public void restoreApps(long waitTime) throws RollingUpgradeException {
//no-op
//will be over-ridden for file-based and memory-based approaches
}
public static void reconcileSessionState(long waitTime) throws RollingUpgradeException {
RollingUpgradeHandler handler = null;
try {
handler = RollingUpgradeHandler.createRollingUpgradeHandler();
handler.reconcileApps(waitTime);
} catch (RollingUpgradeException ex) {
_logger.log(Level.WARNING, "RollingUpgradeHandler>>error during reconcileSessionState");
ex.printStackTrace();
throw ex;
}
}
public void reconcileApps(long waitTime) throws RollingUpgradeException {
long theWaitTime = waitTime;
if(waitTime < MINIMUM_WAIT_TIME) {
theWaitTime = MINIMUM_WAIT_TIME;
_logger.log(Level.WARNING, "RollingUpgradeHandler>>reconcileApps:waitTime must be greater than 60 seconds - setting to 60 seconds");
}
ReplicationMessageRouter router = ReplicationMessageRouter.createInstance();
router.reconcileApps(theWaitTime);
}
/**
* Our thread factory that adds the threads to our thread group and names
* the thread to something recognizable.
*/
static class RollingUpgradeThreadFactory implements ThreadFactory {
final AtomicInteger threadNumber = new AtomicInteger(1);
final String name;
final ThreadGroup threadgroup;
RollingUpgradeThreadFactory(String name, ThreadGroup threadgroup) {
this.name = name;
this.threadgroup = threadgroup;
}
public Thread newThread(Runnable runnable) {
Thread thread = new Thread(threadgroup, runnable, name + " - " + threadNumber.getAndIncrement(), 0);
if (thread.isDaemon()) {
thread.setDaemon(false);
}
if (thread.getPriority() != Thread.NORM_PRIORITY) {
thread.setPriority(Thread.NORM_PRIORITY);
}
return thread;
}
}
}