/*
* 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.appserv.util.cache.BaseCache;
import com.sun.enterprise.web.ServerConfigLookup;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.AbstractMap;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.HashMap;
import java.util.zip.GZIPOutputStream;
import org.apache.catalina.session.IOUtilsCaller;
import org.apache.catalina.session.WebIOUtilsFactory;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sun.logging.LogDomains;
public class ReplicationUtil {
private final static Logger _salogger
= Logger.getLogger(ReplicationState.LOGGER_MEM_REP + ".availability");
private final static Logger _pipelogger
= Logger.getLogger(ReplicationState.LOGGER_MEM_REP + ".pipe");
protected static final Logger logger
= Logger.getLogger(ReplicationState.LOGGER_MEM_REP);
public static Logger getSALogger() {
return _salogger;
}
public static Logger getPipeLogger() {
return _pipelogger;
}
private static final String instanceName
= new ServerConfigLookup().getServerName();
private static final String clusterName
= new ServerConfigLookup().getClusterName();
private final static int MAX_OUTPUT_PIPES = 10;
public final static String EXTENDED_UTILITY_CLASS_NAME
= "org.jvnet.glassfish.comms.replication.sessmgmt.ExtendedReplicationUtil";
private static AtomicBoolean _repUtilCreated = new AtomicBoolean(false);
private static volatile ReplicationUtil _replicationUtil = null;
public static ReplicationUtil createReplicationUtil() {
if (!_repUtilCreated.get()) {
synchronized (_repUtilCreated) {
if (!_repUtilCreated.get()) {
_replicationUtil = new ReplicationUtil();
try {
_replicationUtil =
(ReplicationUtil) (Class.forName(EXTENDED_UTILITY_CLASS_NAME)).newInstance();
} catch (Exception ex) {
;
}
_repUtilCreated.set(true);
}
}
}
return _replicationUtil;
}
/**
* Gets the server instance name
*/
public static String getInstanceName() {
return instanceName;
/*
ServerConfigLookup lookup = new ServerConfigLookup();
return lookup.getServerName();
*/
}
/**
* Gets the cluster name
*/
public static String getClusterName() {
return clusterName;
}
private static final boolean synchronousConfigured
= new ServerConfigLookup().isSynchronousReplication();
/**
* returns if synchronous (ack-based) replication is enabled.
* Also temporarily, when synchronous is enabled it also stops
* usage of store pools
*/
public static boolean isSynchronousReplicationConfigured() {
return synchronousConfigured;
}
public static String getProcessMethodName(ReplicationState message) {
String command = message.getCommand();
return "process" + camelCase(command);
}
/**
* Strips out any non-alpha characters from the given input string, and
* camelCases the result.
*
* @param inputString
*/
public static String camelCase(String inputString) {
String strippedString = stripNonAlphas(inputString);
String firstLetter = (strippedString.substring(0, 1)).toUpperCase();
String remainingPart =
(strippedString.substring(1, strippedString.length())).toLowerCase();
return firstLetter + remainingPart;
}
/**
* Strips out any non-alpha characters from the given input string.
*
* @param inputString
*/
public static String stripNonAlphas(String inputString) {
StringBuilder sb = new StringBuilder(inputString.length());
for (int i=0; i<inputString.length(); i++) {
char nextChar = inputString.charAt(i);
if (Character.isLetter(nextChar)) {
sb.append(nextChar);
}
}
return sb.toString();
}
public static long parseLong(String s) {
long result = -1L;
try {
if (s != null) { // return -1L if s is null
result = Long.parseLong(s);
}
} catch (NumberFormatException ex) {
;
}
return result;
}
public static int parseInt(String s) {
int result = -1;
try {
result = Integer.parseInt(s);
} catch (NumberFormatException ex) {
;
}
return result;
}
public static void printExpatList(HashMap expatMap, String mapName, long startTime) {
long duration = (System.currentTimeMillis() - startTime);
int size = expatMap != null ? expatMap.size() : 0;
logger.info("ExpatListDump for " + mapName + " took " +
duration + " milliseconds, size of expat = " + size);
if (logger.isLoggable(Level.FINEST)) {
Iterator it = expatMap.values().iterator();
for (int count = 0; it.hasNext(); ++count) {
logger.finest("expatElement[" + count + "] = " + it.next());
}
}
}
// Stuff taken from SipStoreBase. Refactored to allow sharing across all SIP and DF artifacts.
/**
* A utility class used to call into services from IOUtils
*/
static private IOUtilsCaller webUtilsCaller = null;
/**
* Create serialized byte[] for <code>obj</code>.
*
* @param obj - serialize obj
* @return byte[] containing serialized data stream for obj
*/
static public byte[] getByteArray(Serializable obj)
throws IOException {
return getByteArray(obj, false);
}
static public byte[] getByteArray(Serializable obj, boolean compress)
throws IOException {
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
IOUtilsCaller utilsCaller = null;
byte[] obs;
try {
bos = new ByteArrayOutputStream();
if( (utilsCaller = getWebUtilsCaller()) != null) {
try {
if (compress) {
oos = utilsCaller.createObjectOutputStream(
new GZIPOutputStream(bos), true);
} else {
oos = utilsCaller.createObjectOutputStream(bos, true);
}
} catch (Exception ex) {}
}
//use normal ObjectOutputStream if there is a failure during stream creation
if (oos == null) {
if (compress) {
oos = new ObjectOutputStream(new GZIPOutputStream(bos));
} else {
oos = new ObjectOutputStream(bos);
}
}
writeObject(obj, oos);
oos.flush();
oos.close();
oos = null;
obs = bos.toByteArray();
} finally {
if ( oos != null ) {
oos.close();
}
}
return obs;
}
static public void writeObject(Object obj, ObjectOutputStream oos)
throws IOException {
if ( obj == null ) {
return;
}
oos.writeObject(obj);
}
public static void writeHashMap(AbstractMap map, ObjectOutputStream oos)
throws IOException {
oos.writeInt(map.size());
Collection mapList = map.values();
Iterator it = mapList.iterator();
while(it.hasNext()) {
oos.writeObject(it.next());
}
}
public static void writeBaseCache(BaseCache cache, ObjectOutputStream oos)
throws IOException {
oos.writeInt(cache.getEntryCount());
Iterator it = cache.values();
while(it.hasNext()) {
oos.writeObject(it.next());
}
}
/**
* get the utility class used to call into services from IOUtils
*/
static public IOUtilsCaller getWebUtilsCaller() {
if(webUtilsCaller == null) {
WebIOUtilsFactory factory = new WebIOUtilsFactory();
webUtilsCaller = factory.createWebIOUtil();
}
return webUtilsCaller;
}
public static int getNumberExpectedRespondants() {
ReplicationHealthChecker healthChecker = ReplicationHealthChecker.getInstance();
List conservativeList = healthChecker.getConservativeMemberList(null);
if(conservativeList == null) {
return 0;
} else {
return conservativeList.size() - 1;
}
}
public static int getNumberExpectedLbEnabledRespondants() {
ReplicationHealthChecker healthChecker = ReplicationHealthChecker.getInstance();
List l = healthChecker.getLbEnabledList();
if (l == null)
return 0;
return l.size() - 1;
}
public static int getNumberOfPipes() {
ServerConfigLookup lookup = new ServerConfigLookup();
int result = lookup.getNumberOfReplicationPipesFromConfig();
if(result < 1) {
result = 1;
}
return result;
}
public static boolean isRollingUpgradeEnabled() {
ServerConfigLookup lookup = new ServerConfigLookup();
return lookup.isRollingUpgradeEnabled();
}
public static int getNumberOfOutputPipes() {
int numberOfPipes = ReplicationUtil.getNumberOfPipes();
if(numberOfPipes > MAX_OUTPUT_PIPES) {
return numberOfPipes = MAX_OUTPUT_PIPES;
}
return numberOfPipes;
}
//instance methods over-ridden by ExtendedReplicationUtil
/**
* Gets the actual server instance (i.e, with respect to the actual
* cluster shape) to which the given SipApplicationSession id currently
* maps.
*
* @param sasId the SipApplicationSession id to be mapped
*
* @return the server instance to which the specified
* SipApplicationSession id currently maps
*/
public String getActualServerInstance(String sasId) {
return null;
}
/**
* Gets the actual server instance (i.e, with respect to the actual
* cluster shape) to which the given beKey currently
* maps.
*
* @param beKey the beKey to be mapped
*
* @return the server instance to which the specified
* beKey currently maps
*/
public String getActualServerInstanceForBeKey(String beKey) {
return null;
}
/**
* Gets the server instance that would be mapped to the specified key in case the current
* instance handling the request becomes unhealthy. So instance is selected from exsiting
* set of working instances, excluding current instance.
* @param beKey the key
* @return the fail-over server instance that is mapped to the specified key
*/
public String getFailoverServerInstanceForBeKey(String beKey) {
return null;
}
/**
* Extracts the application (hash) key portion of the given
* SipApplicationSession id and returns it.
*
* Format: see {@link #createSasId(String, String, String)}
*
* @param sasId the SipApplicationSession id
*
* @return the application (hash) key portion of the given
* SipApplicationSession id
*/
public String getSipApplicationKey(String sasId) {
return null;
}
public boolean isInstanceLoadBalancedByCLB() {
return false;
}
public static boolean checkIsInstanceLoadBalancedByCLB() {
ReplicationUtil util = ReplicationUtil.createReplicationUtil();
return util.isInstanceLoadBalancedByCLB();
}
public static void handleErrorMsg(String errorMsg, Logger logger, RollingUpgradeContext ctx) {
ctx.addError(errorMsg);
logger.log(Level.WARNING, errorMsg);
}
public static void configureLoadBalancer() {
ReplicationUtil util = ReplicationUtil.createReplicationUtil();
util.doConfigureLoadBalancer();
}
protected void doConfigureLoadBalancer() {
// Handle HTTP case -- for now, there is nothing to do as the state
// of the HTTP load balancer doesn't affect replication
}
}