Package com.sun.enterprise.ee.web.sessmgmt

Source Code of com.sun.enterprise.ee.web.sessmgmt.ReplicationState

/*
* 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.
*/
/*
* ReplicationState.java
*
* Created on November 22, 2005, 11:45 AM
*
*/

package com.sun.enterprise.ee.web.sessmgmt;

import com.sun.appserv.ha.util.Metadata;
import com.sun.appserv.ha.util.CompositeMetadata;
import com.sun.appserv.ha.util.SimpleMetadata;
import com.sun.appserv.ha.util.SimpleMetadataFactory;
import com.sun.appserv.ha.spi.BackingStoreException;
import com.sun.appserv.ha.uow.ReplicableEntity;
import com.sun.enterprise.ee.web.authenticator.SSOExtraParams;
import com.sun.enterprise.web.ServerConfigLookup;
import com.sun.logging.LogDomains;
import net.jxta.endpoint.ByteArrayMessageElement;
import net.jxta.endpoint.Message;
import net.jxta.endpoint.MessageElement;
import net.jxta.endpoint.StringMessageElement;
import net.jxta.protocol.RouteAdvertisement;
import org.apache.catalina.Session;
import org.apache.catalina.session.*;

import java.io.*;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.GZIPInputStream;

/**
*
* @author Larry White
*/
public class ReplicationState implements Serializable {
   
    /**
     * The logger to use for logging ALL web container related messages.
     */
    private final static Logger _logger
        = LogDomains.getLogger(LogDomains.WEB_LOGGER);
   
    public final static String LOGGER_MEM_REP
        = "com.sun.enterprise.ee.web.sessmgmt";

    public final static String MODE_WEB = "web";
    public final static String MODE_SSO = "sso";
    public final static String MODE_EJB = "ejb";
    public final static String MODE_SIP = "sip";
    public final static String MODE_STARTUP = "startup";     
    public final static String MESSAGE_MODE = "message_mode";
    public final static String BULK_MESSAGE_MODE = "bulk_message_mode";
    public final static String BULK_MESSAGE_ID = "bulk_message_id";   
    public final static String MESSAGE_ID = "message_id";
    public final static String SAS_PARENT_ID = "sas_parent_id";
    public final static String BEKEY = "bekey";
    public final static String IMMEDIATE_REPLICA_PARTNER = "immediate_replica_partner";
    final static String MESSAGE_APPID = "message_appid";
    final static String MESSAGE_VERSION = "message_version";
    final static String MESSAGE_COMMAND = "message_command";
    final static String MESSAGE_LAST_ACCESS = "message_last_access";
    final static String MESSAGE_MAX_INACTIVE = "message_max_inactive";
    //final static String MESSAGE_SSO_ID = "message_sso_id";
    //final static String MESSAGE_USER_NAME = "message_user_name";
    final static String MESSAGE_EXTRA_PARAM = "message_extra_param";
    public final static String MESSAGE_ACK_REQUIRED = "message_ack_required";
    public final static String MESSAGE_IS_NACK = "message_is_nack";
    public final static String MESSAGE_ACK_LIST_PROPERTY = "message_ack_list_property";
    public final static String MESSAGE_SEND_START_TIME = "message_send_start_time";
    final static String MESSAGE_QUERY_RESULT = "message_query_result";
    final static String MESSAGE_INSTANCE_NAME = "message_instance_name";   
    final static String MESSAGE_DATA = "message_data";
    final static String MESSAGE_TOTAL_STATES = "message_total_states";
    final static String MESSAGE_ACK_IDS_LIST = "message_ack_ids_list";
    final static String MESSAGE_TRUNK_DATA = "message_trunk_data";
    final static String MESSAGE_PROPERTIES_DATA = "message_properties_data";
    final static String MESSAGE_CONTAINER_EXTRA_PARAMS_DATA = "message_container_extra_params_data";
    final static String MESSAGE_READY = "ready";
    final static String MESSAGE_BIDI_STYLE = "message_bidi_style";
    final static String ReadyMessage = "ready";
    //used for unicast route advertisement
    public static final String NAMESPACE = "INSTANCE";
    public static final String ROUTEADV = "ROUTE";   
   
    final static String RETURN_MSG_COMMAND = "response";
    public final static String MESSAGE_BROADCAST_QUERY = "broadcastFindSession";
    public final static String RETURN_BROADCAST_MSG_COMMAND = "broadcastResponse";
    public final static String RETURN_UNICAST_MSG_COMMAND = "unicastResponse";
    public final static String MESSAGE_BROADCAST_LOAD_RECEIVED = "broadcastLoadReceived";
    public final static String MESSAGE_BROADCAST_LOAD_ADVISORY = "broadcastLoadAdvisory";
    public final static String MESSAGE_BROADCAST_PURGE_ADVISORY = "broadcastPurgeAdvisory";
    public final static String MESSAGE_BROADCAST_FIND_EXPAT_IDS = "broadcastFindExpatIds";
    public final static String MESSAGE_APPLICATION_STATUS_QUERY = "broadcastapplicationstatus";
    public final static String MESSAGE_BROADCAST_NETWORK_PARTITION_ADVISORY
        = "broadcastNetworkPartitionAdvisory";   
    final static String InstanceNameMessage = "instance_name";
    final static boolean METHOD_RETURN_VOID = true;
    //commands
    public final static String SAVE_COMMAND = "save";
    public final static String VALVE_SAVE_COMMAND = "valveSave";
    public final static String REMOVE_COMMAND = "remove";   
    public final static String UNDEPLOY_COMMAND = "undeploy";
    public final static String REMOVE_EXPIRED_COMMAND = "removeExpired";
    public final static String REMOVE_SYNCHRONIZED_COMMAND = "removeSynchronized";
    public final static String UPDATE_LAST_ACCESS_TIME_COMMAND = "updateLastAccessTime";
    public final static String SIZE_COMMAND = "size";
    public final static String COMPOSITE_SAVE_COMMAND = "compositeSave";
    public final static String REMOVE_IDS_COMMAND = "removeIds";
    final static String BULK_MESSAGE_COMMAND = "bulk_message_command";
   
    public final static String HC_COMMAND = "healthCheck";
    final static String RETURN_HC_MSG_COMMAND = "healthCheckResponse";
   
    public final static String DUPLICATE_IDS_SEMANTICS_PROPERTY
        = "duplicate_ids_semantics_property";
    public final static String WAIT_FOR_ACK_PROPERTY
        = "wait_for_ack_property";
    public final static String SUPPRESS_LOAD_ACK_PROPERTY
        = "suppress_load_ack_property";
    public final static String REPLICATION_COMPRESSION_PROPERTY
        = "replication_compression_property";
    public final static String SESSION_MANAGER_PROPERTY
        = "session_manager_property";
   
    public static final String ID = "id";

    public static final String ORIGINATING_INSTANCE_NAME = "originating_instance_name";
    public static final String IGNORE_REMOVE_INSTANCE_NAME = "ignore_remove_instance_name";
    public static final String WAIT_TIME = "wait_time";

    /**
     * Creates a new instance of ReplicationState
     */
    public ReplicationState() {
    }
   
    /**
     * Creates a new instance of ReplicationState
     * want this package protected
     */
    ReplicationState(Object id) {
        this();
        _id = id;
    }   
   
    /**
     * Creates a new instance of ReplicationState
     */
    public ReplicationState(String mode, Object id, String appId, long version, long lastAccess, long maxInactiveInterval, String extraParam, Object queryResult, String instanceName, String command, byte[] state, byte[] trunkState, byte[] containerExtraParamsState) {
        _mode = mode;
        _id = id;
        _appId = appId;
        _version = version;
        _maxInactiveInterval = maxInactiveInterval;
        _lastAccess = lastAccess;
        _extraParam = extraParam;
        _queryResult = queryResult;
        _instanceName = instanceName;
        _command = command;
        _state = state;
        _trunkState = trunkState;
        _containerExtraParamsState = containerExtraParamsState;
        _hc = _id.hashCode();
    }

   /**
    * Creates a new instance of ReplicationState cloned (shallow-copy)
    * from originalState
    * @param originalState
    */
   public static ReplicationState createReplicationStateFrom(ReplicationState originalState) {
       ReplicationState result =
           new ReplicationState(originalState.getMode(),
                   originalState.getId(),
                   originalState.getAppId(),
                   originalState.getVersion(),
                   originalState.getLastAccess(),
                   originalState.getMaxInactiveInterval(),
                   originalState.getExtraParam(),
                   originalState.getQueryResult(),
                   originalState.getInstanceName(),
                   originalState.getCommand(),
                   originalState.getState(),
                   originalState.getTrunkState(),
                   originalState.getContainerExtraParamsState());
       return result;
   }

    /**
     * the list of method names that are removes
     */
    private static List removeMethods
        = Arrays.asList(REMOVE_COMMAND, REMOVE_SYNCHRONIZED_COMMAND);

   
    /**
     * the list of method names with void return
     */   
    private static List voidReturnsMethods
        = Arrays.asList(SAVE_COMMAND,
            VALVE_SAVE_COMMAND, REMOVE_SYNCHRONIZED_COMMAND,
            REMOVE_COMMAND, UPDATE_LAST_ACCESS_TIME_COMMAND,
            COMPOSITE_SAVE_COMMAND, HC_COMMAND);
   
    /**
     * the list of method names that are hc (health check)
     */   
    private static List hcMethods
        = Arrays.asList(HC_COMMAND);    

    /**
     * the list of method names that are responses
     */   
    private static List responseMethods
        = Arrays.asList(RETURN_MSG_COMMAND,
            RETURN_BROADCAST_MSG_COMMAND,
            RETURN_UNICAST_MSG_COMMAND);

    public static 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;
        }
    }   
  
    public static SimpleMetadata createSimpleMetadataFrom(
            ReplicationState replicationState, boolean compressionEnabled)
            throws BackingStoreException {
        if(replicationState == null) {
            return null;
        }
        try {
            Object containerExtraParams = getContainerExtraParamFrom(
                    replicationState, compressionEnabled);
            SimpleMetadata result = SimpleMetadataFactory.createSimpleMetadata(replicationState.getVersion(),
                    replicationState.getLastAccess(), replicationState.getMaxInactiveInterval(),
                    replicationState.getState(),
                    containerExtraParams);
            return result;
        } catch (Exception ex) {
            throw new BackingStoreException("error during deserialization of extra parameters", ex);
        }
    }
   
    public static Object getContainerExtraParamFrom(ReplicationState queryResult,
                                                     boolean compressionEnabled)
            throws BackingStoreException {
        /* this logic may apply for EJB do not remove yet
        if(this.getMode() == MODE_SSO) {
            return queryResult.getExtraParam();
        }
         */
        //deserialize containerExtraParams if present
        //note: we assume extra param state is deserializable
        //using the system class loader
        Object containerExtraParams = null;
        byte[] containerExtraParamState = queryResult.getContainerExtraParamsState();
        if(containerExtraParamState != null) {
            try {
                containerExtraParams = getObjectValue(containerExtraParamState,
                        compressionEnabled);
            } catch (Exception ex) {
                throw new BackingStoreException("error during deserialization of extra parameters", ex);
            }
        }
        return containerExtraParams;
    }

    /**
     * create a response ReplicationState from the input ReplicationState
     * @param input
     */    
    public static ReplicationState createResponseFrom(ReplicationState input) {
        return new ReplicationState(
            input.getMode(),
            input.getId(),
            input.getAppId(),
            input.getVersion(),
            input.getLastAccess(),
            input.getMaxInactiveInterval(),
            input.getExtraParam(),
            input.getQueryResult(),
            input.getInstanceName(),
            RETURN_MSG_COMMAND,
            input.getState(),
            input.getTrunkState(),
            input.getContainerExtraParamsState());
   

    public static ReplicationState createQueryResponseFrom(ReplicableEntity session,
                                                           String appId,
                                                           String mode,
                                                           String command,
                                                           String origin,
                                                           boolean isCompressionEnabled,
                                                           boolean useUnicast) {
        byte[] containerExtraParamState = null;
        byte[] state = null;
        Serializable containerExtraParams
            = session.getExtraParameters();
        if(containerExtraParams != null) {
            try {
                containerExtraParamState
                    = ReplicationUtil.getByteArray(containerExtraParams, isCompressionEnabled);
                state = ReplicationUtil.getByteArray(session, isCompressionEnabled);
            } catch (IOException ex) {
                _logger.warning("Unable to serialize " + session +
                        ", error message = " + ex.getMessage());
                ; //deliberate no-op
            }
        }
        ReplicationState result = null;
        if(!useUnicast) {
            result = new ReplicationState(
                    mode,
                    session.getId(),
                    appId,
                    session.getVersion(),
                    0L,
                    0L,
                    null,
                    null,
                    null,
                    ReplicationState.RETURN_BROADCAST_MSG_COMMAND,
                    state,
                    null,
                    containerExtraParamState);
        } else {
            result = new ReplicationState(
                    mode,
                    session.getId(),
                    appId,
                    session.getVersion(),
                    0L,
                    0L,
                    command, //put original command in extraParam slot
                    null,
                    null,
                    ReplicationState.RETURN_UNICAST_MSG_COMMAND,
                    state,
                    null,
                    containerExtraParamState);
        }
        result.setProperties(session.getBeKey(), origin);
        return result;
    }

    /**
     * create a query response ReplicationState from the input ReplicationState
     * @param input
     */    
    public static ReplicationState createUnicastQueryResponseFrom(ReplicationState input, String queryCommand) {
        String extraParam = input.getExtraParam();
        //store original commend in extraParam if it exists
        if(queryCommand != null) {
            extraParam = queryCommand;
        }
        ReplicationState result = new ReplicationState(
            input.getMode(),
            input.getId(),
            input.getAppId(),
            input.getVersion(),
            input.getLastAccess(),
            input.getMaxInactiveInterval(),
            extraParam,
            input.getQueryResult(),
            input.getInstanceName(),
            RETURN_UNICAST_MSG_COMMAND,
            input.getState(),
            input.getTrunkState(),
            input.getContainerExtraParamsState());
        return result;
    }

    /**
     * create a query response ReplicationState from the input ReplicationState
     * @param input
     */
    public static ReplicationState createQueryResponseFrom(ReplicationState input) {
        ReplicationState result = new ReplicationState(
            input.getMode(),
            input.getId(),
            input.getAppId(),
            input.getVersion(),
            input.getLastAccess(),
            input.getMaxInactiveInterval(),
            input.getExtraParam(),
            input.getQueryResult(),
            input.getInstanceName(),
            RETURN_BROADCAST_MSG_COMMAND,
            input.getState(),
            input.getTrunkState(),
            input.getContainerExtraParamsState());
        return result;
    }
   
    /**
     * create a query response ReplicationState from the input ReplicationState
     * @param input
     * @param isNack is this a nack response
     */    
    public static ReplicationState createQueryResponseFrom(ReplicationState input, boolean isNack) {
        if(!isNack) {
            return createQueryResponseFrom(input);
        } else {
            ReplicationState result = new ReplicationState(
                input.getMode(),
                input.getId(),
                input.getAppId(),
                input.getVersion(),
                input.getLastAccess(),
                input.getMaxInactiveInterval(),
                input.getExtraParam(),
                input.getQueryResult(),
                input.getInstanceName(),
                RETURN_BROADCAST_MSG_COMMAND,
                null, //state do not pass state in a nack
                null, //trunkState do not pass in a nack
                null); //containerExtraParamsState do not pass in a nack
            result._isNack=true; //this is a nack
            //in the nack case the input is the queryState
            //and contains the route advertisement
            result.setRouteAdvertisement(input.getRouteAdvertisement());
            return result;
        }
    }

    /**
     * create a query response ReplicationState from the input ReplicationState
     * @param input
     * @param isNack is this a nack response
     */
    public static ReplicationState createUnicastQueryResponseFrom(ReplicationState input, boolean isNack) {
        if(!isNack) {
            return createUnicastQueryResponseFrom(input, input.getCommand());
        } else {
            ReplicationState result = new ReplicationState(
                input.getMode(),
                input.getId(),
                input.getAppId(),
                input.getVersion(),
                input.getLastAccess(),
                input.getMaxInactiveInterval(),
                input.getCommand(), //store original commend in extraParam
                input.getQueryResult(),
                input.getInstanceName(),
                RETURN_UNICAST_MSG_COMMAND,
                null, //state do not pass state in a nack
                null, //trunkState do not pass in a nack
                null); //containerExtraParamsState do not pass in a nack
            result._isNack=true; //this is a nack
            //in the nack case the input is the queryState
            //and contains the route advertisement
            result.setRouteAdvertisement(input.getRouteAdvertisement());
            return result;
        }
    }
   
    /**
     * create a query response ReplicationState from the input ReplicationState
     * @param input
     * @param extraParam extraParam for the response
     * @param queryResult queryResult for the response
     */    
    public static ReplicationState createQueryResponseFrom(ReplicationState input, String extraParam, String queryResult) {
        ReplicationState result = createQueryResponseFrom(input);
        result._extraParam=extraParam;
        result._queryResult = queryResult;
        result.setRouteAdvertisement(input.getRouteAdvertisement());
        return result;
    }     
   
    /**
     * create a query response ReplicationState from the input ReplicationState
     * @param input
     */    
    public static ReplicationState createQueryResponseFrom(ReplicationState input, byte[] returnState) {
        ReplicationState result = new ReplicationState(
            input.getMode(),
            input.getId(),
            input.getAppId(),
            input.getVersion(),
            input.getLastAccess(),
            input.getMaxInactiveInterval(),
            input.getExtraParam(),
            input.getQueryResult(),
            input.getInstanceName(),
            RETURN_BROADCAST_MSG_COMMAND,
            returnState,
            input.getTrunkState(),
            input.getContainerExtraParamsState());
        return result;
    }
   
    /**
     * create a query response ReplicationState from the input ReplicationState
     * @param input
     * @param isNack is this a nack response
     */    
    public static ReplicationState createQueryResponseFrom(ReplicationState input, byte[] returnState, boolean isNack) {
        if(!isNack) {
            return createQueryResponseFrom(input, returnState);
        } else {
            ReplicationState result = new ReplicationState(
                input.getMode(),
                input.getId(),
                input.getAppId(),
                input.getVersion(),
                input.getLastAccess(),
                input.getMaxInactiveInterval(),
                input.getExtraParam(),
                input.getQueryResult(),
                input.getInstanceName(),
                RETURN_BROADCAST_MSG_COMMAND,
                null, //state do not pass state in a nack
                null, //trunkState do not pass in a nack
                null); //containerExtraParamsState do not pass in a nack
            result._isNack=true; //this is a nack
            //in the nack case the input is the queryState
            //and contains the route advertisement
            result.setRouteAdvertisement(input.getRouteAdvertisement());
            return result;
        }
    }       
   
    /**
     * create a response ReplicationState from the input ReplicationState
     * @param input
     *
     * @param newState - updated state
     */    
    public static ReplicationState createUpdatedStateFrom(ReplicationState input, byte[] newState) {
        return new ReplicationState(
            input.getMode(),
            input.getId(),
            input.getAppId(),
            input.getVersion(),
            input.getLastAccess(),
            input.getMaxInactiveInterval(),
            input.getExtraParam(),
            input.getQueryResult(),
            input.getInstanceName(),
            RETURN_MSG_COMMAND,
            newState,
            input.getTrunkState(),
            input.getContainerExtraParamsState());
    }
   
    /**
     * create a response ReplicationState from the input ReplicationState
     * @param input
     * @param theCommand
     * @param newState - updated state
     */    
    public static ReplicationState createUpdatedStateFrom(ReplicationState input, String theCommand, byte[] newState) {
        return new ReplicationState(
            input.getMode(),
            input.getId(),
            input.getAppId(),
            input.getVersion(),
            input.getLastAccess(),
            input.getMaxInactiveInterval(),
            input.getExtraParam(),
            input.getQueryResult(),
            input.getInstanceName(),
            theCommand,
            newState,
            input.getTrunkState(),
            input.getContainerExtraParamsState());
    }   
   
    static List<ReplicationState> extractBulkReplicationStatesFromMessage(Message msg) {
        List<ReplicationState> states = null;
        byte[] data = null;
        MessageElement dataMsgElement =
            msg.getMessageElement(MESSAGE_DATA, MESSAGE_DATA);
        MessageElement totalStatesElement =
            msg.getMessageElement(MESSAGE_TOTAL_STATES, MESSAGE_TOTAL_STATES);
        if(dataMsgElement != null) {
            data = dataMsgElement.getBytes(false);
            ObjectInputStream ois = null;
            ByteArrayInputStream bis = null;
            try {
                bis = new ByteArrayInputStream(data);
                ois = new ObjectInputStream(bis);
                states = (List<ReplicationState>) ois.readObject();
            } catch (IOException ioEx) {
                _logger.log(Level.INFO, "ReplicationState: IOEx ", ioEx);
            } catch (ClassNotFoundException cnfEx) {
                _logger.log(Level.INFO, "ReplicationState: CNF ", cnfEx);
            } finally {
                try {
                    bis.close();
                } catch (Exception ex) {
                    if (_logger.isLoggable(Level.FINEST)) {
                        _logger.finest("error closing stream");
                    }
                }
                try {
                    ois.close();
                } catch (Exception ex) {
                    if (_logger.isLoggable(Level.FINEST)) {
                        _logger.finest("error closing stream");
                    }                   
                }
            }
        }
        return states;
    }
   

    /**
     * create a ReplicationState from the input msg
     * @param msg
     */     
    public static ReplicationState createReplicationState(Message msg) {
        //FIXME all messages should have a non-null mode check all
        // message creating code later
        String mode = MODE_WEB;
        String id = "";
        String appid = "";
        String bulkMode = null;
        String bulkId = "";
        long version = 0L;
        long lastAccess = 0L;
        long maxInactive = 0L;
        String extraParam = null;
        Object queryResult = null;
        String instanceName = null;
        byte[] data = null;
        byte[] trunkData = null;
        byte[] containerExtraParamsData = null;
        byte[] propertiesState = null;
        HashMap properties = null;
       
        MessageElement modeMsgElement =
            msg.getMessageElement(MESSAGE_MODE, MESSAGE_MODE);
        if(modeMsgElement != null) {
            mode = modeMsgElement.toString();
        }
        MessageElement idMsgElement =
            msg.getMessageElement(MESSAGE_ID, MESSAGE_ID);
        if(idMsgElement != null) {
            id = idMsgElement.toString();
        }
       
        //added for bulk messages
        MessageElement bulkModeMsgElement =
            msg.getMessageElement(BULK_MESSAGE_MODE, BULK_MESSAGE_MODE);
        if(bulkModeMsgElement != null) {
            bulkMode = bulkModeMsgElement.toString();
        }
        MessageElement bulkIdMsgElement =
            msg.getMessageElement(BULK_MESSAGE_ID, BULK_MESSAGE_ID);
        if(bulkIdMsgElement != null) {
            bulkId = bulkIdMsgElement.toString();
        }
        //end added for bulk messages
       
        MessageElement appidMsgElement =
            msg.getMessageElement(MESSAGE_APPID, MESSAGE_APPID);
        if(appidMsgElement != null) {
            appid = appidMsgElement.toString();
        }
        MessageElement versionMsgElement =
            msg.getMessageElement(MESSAGE_VERSION, MESSAGE_VERSION);
        if(versionMsgElement != null) {
            version =
                (Long.decode(versionMsgElement.toString())).longValue();
        }       
        MessageElement commandMsgElement =
            msg.getMessageElement(MESSAGE_COMMAND, MESSAGE_COMMAND);
        String command = commandMsgElement.toString();               
        MessageElement lastAccessMsgElement =
            msg.getMessageElement(MESSAGE_LAST_ACCESS, MESSAGE_LAST_ACCESS);
        if(lastAccessMsgElement != null) {
            lastAccess =
                (Long.decode(lastAccessMsgElement.toString())).longValue();
        }
        MessageElement maxInactiveMsgElement =
            msg.getMessageElement(MESSAGE_MAX_INACTIVE, MESSAGE_MAX_INACTIVE);
        if(maxInactiveMsgElement != null) {
            maxInactive =
                (Long.decode(maxInactiveMsgElement.toString())).longValue();
        }
        MessageElement instanceNameMsgElement =
            msg.getMessageElement(MESSAGE_INSTANCE_NAME, MESSAGE_INSTANCE_NAME);
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("ReplicationState>>createReplicationState:instanceNameMsgElement: " + instanceNameMsgElement);
        }       
        if(instanceNameMsgElement != null) {
            instanceName = instanceNameMsgElement.toString();
            if(_logger.isLoggable(Level.FINE)) {
                _logger.fine("ReplicationState>>createReplicationState:instanceNameString: " + instanceName);
            }           
        }
        MessageElement extraParamMsgElement =
            msg.getMessageElement(MESSAGE_EXTRA_PARAM, MESSAGE_EXTRA_PARAM);
        if(extraParamMsgElement != null) {
            extraParam = extraParamMsgElement.toString();
        }
        //FIXME assuming queryResult is a string encoding an Integer
        MessageElement queryResultMsgElement =
            msg.getMessageElement(MESSAGE_QUERY_RESULT, MESSAGE_QUERY_RESULT);
        if(queryResultMsgElement != null) {
            queryResult =
                Integer.decode(maxInactiveMsgElement.toString());
        }              
        MessageElement dataMsgElement =
            msg.getMessageElement(MESSAGE_DATA, MESSAGE_DATA);
        if(dataMsgElement != null) {
            data = dataMsgElement.getBytes(false);
        }
        MessageElement trunkDataMsgElement =
            msg.getMessageElement(MESSAGE_TRUNK_DATA, MESSAGE_TRUNK_DATA);
        if(trunkDataMsgElement != null) {
            trunkData = trunkDataMsgElement.getBytes(false);
        }
        MessageElement containerExtraParamsDataMsgElement =
            msg.getMessageElement(MESSAGE_CONTAINER_EXTRA_PARAMS_DATA, MESSAGE_CONTAINER_EXTRA_PARAMS_DATA);
        if(containerExtraParamsDataMsgElement != null) {
            containerExtraParamsData = containerExtraParamsDataMsgElement.getBytes(false);
        }
        MessageElement propertiesMsgElement =
            msg.getMessageElement(MESSAGE_PROPERTIES_DATA, MESSAGE_PROPERTIES_DATA);
        if(propertiesMsgElement != null) {
            propertiesState = propertiesMsgElement.getBytes(false);
            if(propertiesState != null) {
                try {
                    properties = (HashMap)getObjectValue(propertiesState);
                } catch (Exception ex) {
                    ;
                }
            }
        }       
       
        //added for bulk message support
        if (_logger.isLoggable(Level.FINE)) {
            _logger.fine("ReplicationState>>createReplicationState:bulkId = " + bulkId + " id = " + id +
                         " bulkMode = " + bulkMode + " mode = " + mode);
        }
        if(bulkId != null && bulkMode != null) {
            id = bulkId;
            mode = bulkMode;
        }
        //end added for bulk message support
       
        ReplicationState state =
            new ReplicationState(mode, id, appid, version, lastAccess, maxInactive, extraParam, queryResult, instanceName, command, data, trunkData, containerExtraParamsData);
        if(properties != null) {
            state.setProperties(properties);
        }
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("ReplicationState>>createReplicationState:creating ReplicationState: " + state);
        }              
        return state;
    }
   
    /**
     * create a broadcast query ReplicationState from the input
     * @param mode
     * @param id
     * @param appid
     * @param instanceName
     */    
    public static ReplicationState createBroadcastQueryState(String mode, String id, String appid, String instanceName) {
        //if version is not specified it will be created as -1L
        //and MESSAGE_BROADCAST_QUERY for backward compatibility
        return createBroadcastQueryState(mode, id, appid, -1L, instanceName, MESSAGE_BROADCAST_QUERY);
    }
   
    /**
     * create a broadcast query ReplicationState from the input
     * @param mode
     * @param id
     * @param appid
     * @param version
     * @param instanceName
     */    
    public static ReplicationState createBroadcastQueryState(String mode, String id, String appid, long version, String instanceName, String command) {
        return new ReplicationState(mode, id, appid, version, 0L, 0L, null, null, instanceName, command, null, null, null);
    }
   
    /**
     * create a broadcast query ReplicationState from the input
     * @param mode
     * @param id
     * @param appid
     * @param version
     * @param instanceName
     */    
    public static ReplicationState createBroadcastLoadReceivedState(String mode, String id, String appid, long version, String instanceName) {
        return new ReplicationState(mode, id, appid, version, 0L, 0L, null, null, instanceName, MESSAGE_BROADCAST_LOAD_RECEIVED, null, null, null);
    }

    /**
     * create a broadcast query ReplicationState from the input
     * @param mode
     * @param id
     * @param appid
     * @param version
     * @param instanceName
     * @param command
     */
    public static ReplicationState createBroadcastLoadReceivedState(String mode, String id, String appid, long version, String instanceName, String command) {
        String replicateToInstanceName = getImmediateReplicateToInstanceName();
        ReplicationState result = new ReplicationState(mode, id, appid, version, 0L, 0L, null, null, instanceName, command, null, null, null);
        result.setProperty(IMMEDIATE_REPLICA_PARTNER, replicateToInstanceName);
        return result;
    }

    private static String getImmediateReplicateToInstanceName() {
        ReplicationUtil util = ReplicationUtil.createReplicationUtil();
        if(util.isInstanceLoadBalancedByCLB()) {
            return null//FIXME
        } else {
            ReplicationHealthChecker healthChecker
                = ReplicationHealthChecker.getInstance();
            return healthChecker.getReshapeReplicateToInstanceName(null, 0L);
        }
    }
   
    /**
     * create a broadcast aquery ReplicationState from the input
     * @param mode
     * @param id
     * @param appid
     * @param version
     * @param instanceName
     */    
    public static ReplicationState createBroadcastPurgeState(String mode, String id, String appid, long version, String owningInstanceName, String instanceName) {
        //using extraParam slot for owningInstanceName for only this method
        return new ReplicationState(mode, id, appid, version, 0L, 0L, owningInstanceName, null, instanceName, MESSAGE_BROADCAST_PURGE_ADVISORY, null, null, null);
    }
   
    /**
     * create a broadcast aquery ReplicationState from the input
     * @param mode
     * @param id
     * @param appid
     * @param version
     * @param instanceName
     */    
    public static ReplicationState createBroadcastNetworkPartitionAdvisoryState(String mode, String id, String appid, long version, String owningInstanceName, String instanceName) {
        //using extraParam slot for owningInstanceName for only this method
        return new ReplicationState(mode, id, appid, version, 0L, 0L, owningInstanceName, null, instanceName, MESSAGE_BROADCAST_NETWORK_PARTITION_ADVISORY, null, null, null);
    }   
   
   
    /**
     * create a broadcast query ReplicationState from the input
     * @param mode
     * @param id
     * @param appid
     * @param version
     * @param instanceName
     * @param command
     */    
    public static ReplicationState createUnicastLoadAdvisoryState(String mode, String id, String appid, long version, String instanceName, String command) {
        return new ReplicationState(mode, id, appid, version, 0L, 0L, null, null, instanceName, command, null, null, null);
    }

    /**
     * create a unicast query ReplicationState from the input
     * @param mode
     * @param id
     * @param appid
     * @param version
     * @param instanceName
     * @param command
     */
    public static ReplicationState createUnicastLoadState(String mode, String id, String appid, long version, String instanceName, String command) {
        return new ReplicationState(mode, id, appid, version, 0L, 0L, null, null, instanceName, command, null, null, null);
    }
   
    /**
     * create a query ReplicationState from the input
     * @param mode
     * @param id
     * @param appid
     * @param command
     */    
    public static ReplicationState createQueryState(String mode, String id, String appid, String command) {
        return new ReplicationState(mode, id, appid, 0L, 0L, 0L, null, null, lookupInstanceName(), command, null, null, null);
    }
   
    /**
     * create a query ReplicationState from the input
     * @param mode
     * @param id
     * @param appid
     * @param queryResult
     */    
    public static ReplicationState createQueryStateResponse(String mode, String id, String appid, String sourceInstanceName, Object queryResult) {
        return new ReplicationState(mode, id, appid, 0L, 0L, 0L, null, queryResult, sourceInstanceName, RETURN_MSG_COMMAND, null, null, null);
    }   

    /**
     * create a broadcast ReplicationState from the input Message
     * @param msg
     */     
    public static ReplicationState createBroadcastReplicationState(Message msg) {
        //FIXME all messages should have a non-null mode check all
        // message creating code later
        String mode = MODE_WEB;
        long version = 0L;
        String extraParam = null;
        String queryResult = null;
        String instanceName = null;
        byte[] propertiesState = null;
        HashMap properties = null;
        boolean isNack = false;
        MessageElement modeMsgElement =
            msg.getMessageElement(MESSAGE_MODE, MESSAGE_MODE);
        if(modeMsgElement != null) {
            mode = modeMsgElement.toString();
        }
        MessageElement idMsgElement =
            msg.getMessageElement(MESSAGE_ID, MESSAGE_ID);
        String id = idMsgElement.toString();
        MessageElement appidMsgElement =
            msg.getMessageElement(MESSAGE_APPID, MESSAGE_APPID);
        String appid = appidMsgElement.toString();       
        MessageElement versionMsgElement =
            msg.getMessageElement(MESSAGE_VERSION, MESSAGE_VERSION);
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("ReplicationState:createBroadcastReplicationState:versMsgElem=" + versionMsgElement);
        }        
        if(versionMsgElement != null) {
            version =
                (Long.decode(versionMsgElement.toString())).longValue();
        }
        MessageElement extraParamMsgElement =
            msg.getMessageElement(MESSAGE_EXTRA_PARAM, MESSAGE_EXTRA_PARAM);
        if(extraParamMsgElement != null) {
            extraParam = extraParamMsgElement.toString();
        }
        MessageElement queryResultMsgElement =
            msg.getMessageElement(MESSAGE_QUERY_RESULT, MESSAGE_QUERY_RESULT);
        if(queryResultMsgElement != null) {
            queryResult = queryResultMsgElement.toString();
        }       
        MessageElement commandMsgElement =
            msg.getMessageElement(MESSAGE_COMMAND, MESSAGE_COMMAND);
        String command = commandMsgElement.toString();
        MessageElement instanceNameMsgElement =
            msg.getMessageElement(MESSAGE_INSTANCE_NAME, MESSAGE_INSTANCE_NAME);
        if(instanceNameMsgElement != null) {
            instanceName = instanceNameMsgElement.toString();
        }
        MessageElement nackMsgElement =
            msg.getMessageElement(MESSAGE_IS_NACK, MESSAGE_IS_NACK);
        if(nackMsgElement != null) {
            String isNackString = nackMsgElement.toString();
            if("Y".equalsIgnoreCase(isNackString)) {
                isNack = true;
            }
        }       
        /* don't need these message element - remove after testing
        //FIXME will need to add more later
        MessageElement lastAccessMsgElement =
            msg.getMessageElement(MESSAGE_LAST_ACCESS, MESSAGE_LAST_ACCESS);
        long lastAccess =
            (Long.decode(lastAccessMsgElement.toString())).longValue();
        MessageElement maxInactiveMsgElement =
            msg.getMessageElement(MESSAGE_MAX_INACTIVE, MESSAGE_MAX_INACTIVE);
        long maxInactive =
            (Long.decode(maxInactiveMsgElement.toString())).longValue();
        MessageElement instanceNameMsgElement =
            msg.getMessageElement(MESSAGE_INSTANCE_NAME, MESSAGE_INSTANCE_NAME);
        String instanceName = instanceNameMsgElement.toString();
        MessageElement extraParamMsgElement =
            msg.getMessageElement(MESSAGE_EXTRA_PARAM, MESSAGE_EXTRA_PARAM);
        String extraParam = extraParamMsgElement.toString();
         */
        byte[] data = null;
        MessageElement dataMsgElement =
            msg.getMessageElement(MESSAGE_DATA, MESSAGE_DATA);
        if(dataMsgElement != null) {
            data = dataMsgElement.getBytes(false);
        }
        byte[] trunkData = null;
        MessageElement trunkDataMsgElement =
            msg.getMessageElement(MESSAGE_TRUNK_DATA, MESSAGE_TRUNK_DATA);
        if(trunkDataMsgElement != null) {
            trunkData = trunkDataMsgElement.getBytes(false);
        }
       
        byte[] containerExtraParamsData = null;
        MessageElement containerExtraParamsMsgElement =
            msg.getMessageElement(MESSAGE_CONTAINER_EXTRA_PARAMS_DATA, MESSAGE_CONTAINER_EXTRA_PARAMS_DATA);
        if(containerExtraParamsMsgElement != null) {
            containerExtraParamsData = containerExtraParamsMsgElement.getBytes(false);
        }
        MessageElement propertiesMsgElement =
            msg.getMessageElement(MESSAGE_PROPERTIES_DATA, MESSAGE_PROPERTIES_DATA);
        if(propertiesMsgElement != null) {
            propertiesState = propertiesMsgElement.getBytes(false);
            if(propertiesState != null) {
                try {
                    properties = (HashMap)getObjectValue(propertiesState);
                } catch (Exception ex) {
                    ;
                }
            }
        }        
       
        ReplicationState state =
            new ReplicationState(mode, id, appid, version, 0L, 0L, extraParam, queryResult, instanceName, command, data, trunkData, containerExtraParamsData);
        if(properties != null) {
            state.setProperties(properties);
        }       
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("ReplicationState:createBroadcastReplicationState:creating ReplicationState from broadcast: " + state);
        }
        //set if response is nack
        state.setNack(isNack);
        return state;
    }   

    /**
     * create a Message from the input state
     * @param state
     */   
    public static Message createMessage(ReplicationState state) {
        return createMessage(state, false);
    }    

    /**
     * create a Message from the input state
     * @param state
     * @param isResponse is the created message a response
     */    
    public static Message createMessage(ReplicationState state, boolean isResponse) {
        Message msg = new Message();
        String mode = state.getMode();
        String id = (String)state.getId();
        String appid = state.getAppId();
        String command = state.getCommand();
        Long version = new Long(state.getVersion());
        Long lastAccess = new Long(state.getLastAccess());
        Long maxInactive = new Long(state.getMaxInactiveInterval());
        String extraParam = state.getExtraParam();
        //FIXME for now assuming this is a Long
        //for generality will have to serialize and use bytearray
        Integer queryResult = (Integer)state.getQueryResult();
        String instanceName = state.getInstanceName();
        if(instanceName == null) {
            //put existing instanceName for source if it is missing here
            instanceName = lookupInstanceName();
        }       
        byte[] data = state.getState();
        byte[] trunkData = state.getTrunkState();
        byte[] containerExtraParamData = state.getContainerExtraParamsState();
        boolean ackRequired = state.isAckRequired();
        HashMap properties = (HashMap)state.getProperties();
        byte[] propertiesState = null;
        try {
            propertiesState = ReplicationUtil.getByteArray(properties);
        } catch (Exception ex) {}
       
        long sendStartTime = state.getSendStartTime();
        //String data = "Message #" + i;
        msg.addMessageElement(MESSAGE_MODE,
                              new StringMessageElement(MESSAGE_MODE,
                                                       mode,
                                                       null));
        if(mode != null && mode.equalsIgnoreCase(BULK_MESSAGE_MODE)) {
            msg.addMessageElement(BULK_MESSAGE_MODE,
                    new StringMessageElement(BULK_MESSAGE_MODE,
                                             "BULK",
                                             null));
        }
        msg.addMessageElement(MESSAGE_ID,
                              new StringMessageElement(MESSAGE_ID,
                                                       id,
                                                       null));
        msg.addMessageElement(MESSAGE_ID,
                              new StringMessageElement(MESSAGE_ID,
                                                       id,
                                                       null));
        msg.addMessageElement(MESSAGE_APPID,
                              new StringMessageElement(MESSAGE_APPID,
                                                       appid,
                                                       null));
        msg.addMessageElement(MESSAGE_VERSION,
                              new StringMessageElement(MESSAGE_VERSION,
                                                       version.toString(),
                                                       null));        
        String theCommand = command;
        if(isResponse) {
            theCommand = RETURN_MSG_COMMAND;
        }
        msg.addMessageElement(MESSAGE_COMMAND,
                              new StringMessageElement(MESSAGE_COMMAND,
                                                       theCommand,
                                                       null));       
        msg.addMessageElement(MESSAGE_LAST_ACCESS,
                              new StringMessageElement(MESSAGE_LAST_ACCESS,
                                                       lastAccess.toString(),
                                                       null));
        msg.addMessageElement(MESSAGE_MAX_INACTIVE,
                              new StringMessageElement(MESSAGE_MAX_INACTIVE,
                                                       maxInactive.toString(),
                                                       null));
        if(extraParam != null) {
            msg.addMessageElement(MESSAGE_EXTRA_PARAM,
                              new StringMessageElement(MESSAGE_EXTRA_PARAM,
                                                       extraParam,
                                                       null));
        }
        if(queryResult != null) {
            msg.addMessageElement(MESSAGE_QUERY_RESULT,
                                  new StringMessageElement(MESSAGE_QUERY_RESULT,
                                                           queryResult.toString(),
                                                           null));
        }
        if(instanceName != null) {
            msg.addMessageElement(MESSAGE_INSTANCE_NAME,
                              new StringMessageElement(MESSAGE_INSTANCE_NAME,
                                                       instanceName,
                                                       null));
        }
        if(data != null) {
            msg.addMessageElement(MESSAGE_DATA,
                              new ByteArrayMessageElement(MESSAGE_DATA,
                                                       null,
                                                       data,
                                                       null));
        }
        if(trunkData != null) {
            msg.addMessageElement(MESSAGE_TRUNK_DATA,
                              new ByteArrayMessageElement(MESSAGE_TRUNK_DATA,
                                                       null,
                                                       trunkData,
                                                       null));
        }
        if(containerExtraParamData != null) {
            msg.addMessageElement(MESSAGE_CONTAINER_EXTRA_PARAMS_DATA,
                              new ByteArrayMessageElement(MESSAGE_CONTAINER_EXTRA_PARAMS_DATA,
                                                       null,
                                                       containerExtraParamData,
                                                       null));
        }
        if(propertiesState != null) {
            msg.addMessageElement(MESSAGE_PROPERTIES_DATA,
                              new ByteArrayMessageElement(MESSAGE_PROPERTIES_DATA,
                                                       null,
                                                       propertiesState,
                                                       null));
        }       
        //is ack required
        String ackRequiredString = "N";
        if(ackRequired) {
            ackRequiredString = "Y";
        }
        msg.addMessageElement(MESSAGE_ACK_REQUIRED,
                              new StringMessageElement(MESSAGE_ACK_REQUIRED,
                                                       ackRequiredString,
                                                       null));
        //a property not sent but available for quick-ack case
        msg.setMessageProperty(MESSAGE_ACK_REQUIRED, ackRequiredString);
        List ackIdsList = state.getAckIdsList();
        if(state.getAckIdsList() != null) {
            msg.setMessageProperty(MESSAGE_ACK_LIST_PROPERTY, ackIdsList);
        }
        //send start time for measurements
        if(sendStartTime != -1) {
            msg.addMessageElement(MESSAGE_SEND_START_TIME,
                                  new StringMessageElement(MESSAGE_SEND_START_TIME,
                                                           "" + sendStartTime,
                                                           null));
            msg.setMessageProperty(MESSAGE_SEND_START_TIME, ""+sendStartTime);
        }


        msg.addMessageElement(MESSAGE_BIDI_STYLE,
                              new StringMessageElement(MESSAGE_BIDI_STYLE,
                                                       "" + state.isBiDiStyle(),
                                                       null));
       
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("ReplicationState:createMessage:Sending Message id:" + id + " appid:" + appid + " command:" + command);
        }        
        return msg;
    }
   
    /**
     * create a Message from the input state
     * @param msgID
     * @param totalStates the number of total states
     * @param data the serialized list of ReplicationStates
     * this version creates a message with no ack required
     */    
    public static Message createBulkMessage(long msgID, int totalStates, byte[] data) {
        return createBulkMessage(msgID, totalStates, data, false);
    }
   
    /**
     * create a Message from the input state
     * @param msgID
     * @param totalStates the number of total states
     * @param data the serialized list of ReplicationStates
     * @param ackRequired does this message require an ack
     */    
    public static Message createBulkMessage(long msgID, int totalStates, byte[] data, boolean ackRequired) {
        Message msg = new Message();
       
        msg.addMessageElement(BULK_MESSAGE_MODE,
                new StringMessageElement(BULK_MESSAGE_MODE,
                                         "BULK",
                                         null));
       
        msg.addMessageElement(BULK_MESSAGE_ID,
                new StringMessageElement(BULK_MESSAGE_ID,
                                         ""+msgID,
                                         null));
       
        msg.setMessageProperty(BULK_MESSAGE_ID, ""+msgID);
       

        if (data != null) {
            msg.addMessageElement(MESSAGE_TOTAL_STATES,
                    new StringMessageElement(MESSAGE_TOTAL_STATES,
                                             ""+totalStates,
                                             null));
           
            msg.addMessageElement(MESSAGE_DATA,
                              new ByteArrayMessageElement(MESSAGE_DATA,
                                                       null,
                                                       data,
                                                       null));
        }
       
        //is ack required
        String ackRequiredString = "N";
        if(ackRequired) {
            ackRequiredString = "Y";
        }
        msg.addMessageElement(MESSAGE_ACK_REQUIRED,
                              new StringMessageElement(MESSAGE_ACK_REQUIRED,
                                                       ackRequiredString,
                                                       null));
       
        //send start time for measurements
        long sendStartTime = System.currentTimeMillis();
        msg.addMessageElement(MESSAGE_SEND_START_TIME,
                              new StringMessageElement(MESSAGE_SEND_START_TIME,
                                                       "" + sendStartTime,
                                                       null));
        msg.setMessageProperty(MESSAGE_SEND_START_TIME, ""+sendStartTime);

        if(_logger.isLoggable(Level.INFO)) {
            _logger.info("ReplicationState:createBulkMessage:Sending BULK_Message id:" + msgID +
                         "   size: " + data.length + " startTime=" + sendStartTime);
        }


        return msg;
    }
   
    /**
     * create a Message from the input state
     * @param msgID
     * @param totalStates the number of total states
     * @param data the serialized list of ReplicationStates
     * @param ackRequired does this message require an ack
     */    
    public static ReplicationState createBulkReplicationState(long msgID, List<String> ackIdsList, byte[] data, boolean ackRequired) {
        String id = "" + msgID;
        ReplicationState resultState =
            new ReplicationState(BULK_MESSAGE_MODE, //bulk mode
                id, //id 
                id,     //appid (does not matter in this bulk case; must be non null)
                -1//version
                0L//lastaccesstime
                0L, //maxInactiveInterval (seconds)               
                null,  // (extraParam)
                null, //queryResult not used here
                null, //instanceName
                VALVE_SAVE_COMMAND, //command (does not matter in this bulk case; must be non-null)
                data,      //state
                null,      //trunkState
                null);     //containerExtraParamState
        resultState.setAckRequired(ackRequired);
        resultState.setAckIdsList(ackIdsList);
        return resultState;
    }      

    /**
     * create an ack Message from the input
     * @param msg
     */    
    public static Message createAckMessageFrom(Message msg) {
        Message ackMsg = new Message();
       
        //echo the mode
        String mode = MODE_WEB;
        MessageElement modeMsgElement =
            msg.getMessageElement(MESSAGE_MODE, MESSAGE_MODE);
        if(modeMsgElement != null) {
            mode = modeMsgElement.toString();
        }       
        ackMsg.addMessageElement(MESSAGE_MODE,
                              new StringMessageElement(MESSAGE_MODE,
                                                       mode,
                                                       null));        
        //echo the id
        MessageElement idMsgElement =
        msg.getMessageElement(MESSAGE_ID, MESSAGE_ID);
        String id = idMsgElement.toString();
        ackMsg.addMessageElement(MESSAGE_ID,
                              new StringMessageElement(MESSAGE_ID,
                                                       id,
                                                       null));
        //echo the appid
        MessageElement appidMsgElement =
            msg.getMessageElement(MESSAGE_APPID, MESSAGE_APPID);
        String appid = appidMsgElement.toString();
        ackMsg.addMessageElement(MESSAGE_APPID,
                              new StringMessageElement(MESSAGE_APPID,
                                                       appid,
                                                       null));
        //********** test begin**********************
        //get the current command
        MessageElement commandMsgElement =
            msg.getMessageElement(MESSAGE_COMMAND, MESSAGE_COMMAND);
        String previousCommand = commandMsgElement.toString();
        String theCommand = RETURN_MSG_COMMAND;
        if(previousCommand.equals(ReplicationState.HC_COMMAND)) {
            theCommand = RETURN_HC_MSG_COMMAND;
        }
        //this is a return command
        /* FIXME replace next line with above - need to test
        String theCommand = RETURN_MSG_COMMAND;
         */       
        //********** test end  **********************
       

        ackMsg.addMessageElement(MESSAGE_COMMAND,
                              new StringMessageElement(MESSAGE_COMMAND,
                                                       theCommand,
                                                       null));

        return ackMsg;
    }
   
    /**
     * create an bulk ack Message from the input
     * @param msg
     */    
    public static Message createBulkAckMessageFrom(Message msg, List<ReplicationState> states) {
        List<String> ackIdsList = extractAckIdsList(states);
        //displayStringList(ackIdsList);
        byte[] listAckIds = null;
        try {
            listAckIds = getByteArray(ackIdsList);
        } catch (IOException ex) {
            //deliberate no-op
            ;
        }
       
        Message ackMsg = new Message();
       
        //echo the mode
        String mode = MODE_WEB;
        MessageElement modeMsgElement =
            msg.getMessageElement(MESSAGE_MODE, MESSAGE_MODE);
        if(modeMsgElement != null) {
            mode = modeMsgElement.toString();
        }       
        ackMsg.addMessageElement(MESSAGE_MODE,
                              new StringMessageElement(MESSAGE_MODE,
                                                       mode,
                                                       null));
       
        ackMsg.addMessageElement(BULK_MESSAGE_MODE,
                new StringMessageElement(BULK_MESSAGE_MODE,
                                         "BULK",
                                         null));
       
        //echo the id
        MessageElement idMsgElement =
        msg.getMessageElement(MESSAGE_ID, MESSAGE_ID);
        String id = idMsgElement.toString();
        ackMsg.addMessageElement(MESSAGE_ID,
                              new StringMessageElement(MESSAGE_ID,
                                                       id,
                                                       null));
        //echo the appid
        MessageElement appidMsgElement =
            msg.getMessageElement(MESSAGE_APPID, MESSAGE_APPID);
        String appid = appidMsgElement.toString();
        ackMsg.addMessageElement(MESSAGE_APPID,
                              new StringMessageElement(MESSAGE_APPID,
                                                       appid,
                                                       null));
        //********** test begin**********************
        //get the current command
        MessageElement commandMsgElement =
            msg.getMessageElement(MESSAGE_COMMAND, MESSAGE_COMMAND);
        String previousCommand = commandMsgElement.toString();
        String theCommand = RETURN_MSG_COMMAND;
        if(previousCommand.equals(ReplicationState.HC_COMMAND)) {
            theCommand = RETURN_HC_MSG_COMMAND;
        }
        //this is a return command
        /* FIXME replace next line with above - need to test
        String theCommand = RETURN_MSG_COMMAND;
         */       
        //********** test end  **********************
       

        ackMsg.addMessageElement(MESSAGE_COMMAND,
                              new StringMessageElement(MESSAGE_COMMAND,
                                                       theCommand,
                                                       null));
        //serialized list of ids to ack back to
        if(listAckIds != null) {
            ackMsg.addMessageElement(MESSAGE_ACK_IDS_LIST,
                              new ByteArrayMessageElement(MESSAGE_ACK_IDS_LIST,
                                                       null,
                                                       listAckIds,
                                                       null));
        }
              
        return ackMsg;
    }
   
    public static void displayStringList(List<String> stringList) {
        for(int i=0; i<stringList.size(); i++) {
            _logger.log(Level.INFO, "displayStringList:elem[" + i + "] = " + stringList.get(i));
        }
    }
   
    public static List<String> extractAckIdsList(List<ReplicationState> states) {
        List<String> ackIdsList = new ArrayList();
        for(int i=0; i<states.size(); i++) {
            ReplicationState nextState = states.get(i);
            //only add ids to ackIdsList that require an ack
            if(nextState != null && nextState.isAckRequired()) {
                ackIdsList.add((String)nextState.getId());
            }
        }
        return ackIdsList;
    }
   
   
    public static List<String> extractAllIdsList(List<ReplicationState> states) {
        List<String> allIdsList = new ArrayList();
        for(int i=0; i<states.size(); i++) {
            ReplicationState nextState = states.get(i);
            //provide the id[vers:xxx] for all states in list
            if(nextState != null) {
                allIdsList.add("Operation: " + nextState.getCommand() +
                               " AppId:" + nextState.getAppId() +
                               " Id:" +  nextState.getId() +
                               "[ver:" + nextState.getVersion() + "]");
            }
        }
        return allIdsList;
    }
   
    static List<String> extractAckIdsListFromMessage(Message msg) {
        List<String> result = new ArrayList();
        byte[] data = null;
        MessageElement ackIdsMsgElement =
            msg.getMessageElement(MESSAGE_ACK_IDS_LIST, MESSAGE_ACK_IDS_LIST);
        if(ackIdsMsgElement != null) {
            data = ackIdsMsgElement.getBytes(false);
        }
        try {
            result = (ArrayList)getObjectValue(data);
        } catch (Exception ex) {
            //deliberate no-op
            ;
        }
        return result;
    }

    /**
     * true means this is a broadcast message
     */   
    public static boolean isBroadcastState(ReplicationState state) {
        return (state.getCommand() != null
            && state.getCommand().equals(MESSAGE_BROADCAST_QUERY));
    }
   
    /**
     * true means void return
     */   
    public boolean isVoidMethodReturnState() {
        String methodName = this.getCommand();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("ReplicationState>>isVoidMethodReturnState:methodName = " + methodName);
        }       
        if(methodName == null) {
            return false;
        } else {
            return isMethodVoidReturn(methodName);
        }
    }   

    /**
     * true means void return command (i.e. method)
     */   
    static boolean isMethodVoidReturn(String methodName) {
        return voidReturnsMethods.contains(methodName);
    }
   
    /**
     * true means void return command (i.e. method)
     */   
    public static boolean isVoidMethodReturnMessage(Message msg) {       
        MessageElement commandMsgElement =
            msg.getMessageElement(MESSAGE_COMMAND, MESSAGE_COMMAND);
        String methodName = commandMsgElement.toString();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("ReplicationState>>isVoidMethodReturnMessage:methodName = " + methodName);
        }       
        if(methodName == null) {
            return false;
        } else {
            return isMethodVoidReturn(methodName);
        }
    }
   
    /**
     * true means state command is one of remove methods
     */   
    public boolean isRemoveMethodState() {
        String methodName = this.getCommand();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("ReplicationState>>isRemoveMethodState:methodName = " + methodName);
        }       
        if(methodName == null) {
            return false;
        } else {
            return isMethodRemove(methodName);
        }
    }    
   
    /**
     * true means one of remove commands (i.e. method)
     */   
    static boolean isMethodRemove(String methodName) {
        return removeMethods.contains(methodName);
    }
   
    ///
   
   /**
     * true means void return command (i.e. method)
     */   
    static boolean isMethodHC(String methodName) {
        return hcMethods.contains(methodName);
    }
   
    /**
     * true means void return command (i.e. method)
     */   
    public static boolean isHCMessage(Message msg) {       
        MessageElement commandMsgElement =
            msg.getMessageElement(MESSAGE_COMMAND, MESSAGE_COMMAND);
        String methodName = commandMsgElement.toString();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("ReplicationState>>isHCMessage:methodName = " + methodName);
        }       
        if(methodName == null) {
            return false;
        } else {
            return isMethodHC(methodName);
        }
    }
   
    /**
     * get extra param from message
     */   
    public static String getExtraParamFromMessage(Message msg) {
        String result = "";
        MessageElement extraParamMsgElement =
            msg.getMessageElement(MESSAGE_EXTRA_PARAM, MESSAGE_EXTRA_PARAM);
        if(extraParamMsgElement != null) {
            result = extraParamMsgElement.toString();
        }
        return result;
    }     
    ///

    /**
     * @param msg
     * true means a response message
     */   
    public static boolean isResponseMessage(Message msg) {       
        MessageElement commandMsgElement =
            msg.getMessageElement(MESSAGE_COMMAND, MESSAGE_COMMAND);
        String methodName = commandMsgElement.toString();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("ReplicationState>>isResponseMessage:methodName = " + methodName);
        }       
         if(methodName == null) {
            return false;
        } else {
            return isMethodResponse(methodName);
        }
    }   
   
    /**
     * true means ack is required
     */   
    public static boolean isAckRequiredForMessage(Message msg) {
        String ackRequiredString = "N";
        MessageElement ackRequiredMsgElement =
            msg.getMessageElement(MESSAGE_ACK_REQUIRED, MESSAGE_ACK_REQUIRED);
        if(ackRequiredMsgElement != null) {
            ackRequiredString = ackRequiredMsgElement.toString();
        }
        return("Y".equalsIgnoreCase(ackRequiredString));      
    }    
   
    /**
     * true means a response
     */   
    public boolean isResponseState() {
        String methodName = this.getCommand();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("ReplicationState>>isResponseState:methodName = " + methodName);
        }       
        if(methodName == null) {
            return false;
        } else {
            return isMethodResponse(methodName);
        }
    }
   
    /**
     * true means void return command (i.e. method)
     */   
    static boolean isMethodResponse(String methodName) {
        return responseMethods.contains(methodName);
    }   
   
    private static String lookupInstanceName() {
        return ReplicationUtil.getInstanceName();
    }
   
    /**
     * create a new Message based on the input
     * this is for a from msg
     * @param state
     * @param isResponse
     */    
    public static Message createBroadcastMessage(ReplicationState state, boolean isResponse) {
        String instanceName = ReplicationUtil.getInstanceName();
        return ReplicationState.createBroadcastMessage(state, isResponse, instanceName);
    }
   
    /**
     * create a new Message based on the input
     * this is for a return msg to the target instance
     * @param state
     * @param isResponse
     * @param instName
     */
    public static Message createBroadcastMessage(ReplicationState state, boolean isResponse, String instName) {
        String instanceName = ReplicationUtil.getInstanceName();
        //String instanceName = instName;
        Message msg = new Message();
        String mode = state.getMode();
        String id = (String)state.getId();
        String appid = state.getAppId();
        String versionString = Long.toString(state.getVersion());
        Long lastAccess = new Long(state.getLastAccess());
        Long maxInactive = new Long(state.getMaxInactiveInterval());       
        String extraParam = state.getExtraParam();
        String queryResult = (String)state.getQueryResult();
        String theCommand = state.getCommand();
        //String theCommand = MESSAGE_BROADCAST_QUERY;
        byte[] data = state.getState();
        byte[] trunkData = state.getTrunkState();
        byte[] containerExtraParamData = state.getContainerExtraParamsState();
        HashMap properties = (HashMap)state.getProperties();
        byte[] propertiesState = null;
        try {
            propertiesState = ReplicationUtil.getByteArray(properties);
        } catch (Exception ex) {}        
        /*
        if(isResponse) {
            theCommand = RETURN_BROADCAST_MSG_COMMAND;
        }
         */
        //is nack message
        boolean isNack = state._isNack;
      
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("ReplicationState>>createBroadcastMessage:instanceName=" + instanceName + " theCommand=" + theCommand);
        }        
        msg.addMessageElement(MESSAGE_MODE,
                              new StringMessageElement(MESSAGE_MODE,
                                                       mode,
                                                       null));
        if(mode != null && mode.equalsIgnoreCase(BULK_MESSAGE_MODE)) {
            msg.addMessageElement(BULK_MESSAGE_MODE,
                    new StringMessageElement(BULK_MESSAGE_MODE,
                                             "BULK",
                                             null));
        }       
        msg.addMessageElement(MESSAGE_ID,
                              new StringMessageElement(MESSAGE_ID,
                                                       id,
                                                       null));       
        msg.addMessageElement(MESSAGE_APPID,
                              new StringMessageElement(MESSAGE_APPID,
                                                       appid,
                                                       null));
        msg.addMessageElement(MESSAGE_VERSION,
                              new StringMessageElement(MESSAGE_VERSION,
                                                       versionString,
                                                       null));
        if(extraParam != null) {
            msg.addMessageElement(MESSAGE_EXTRA_PARAM,
                              new StringMessageElement(MESSAGE_EXTRA_PARAM,
                                                       extraParam,
                                                       null));
        }
        if(queryResult != null) {
            msg.addMessageElement(MESSAGE_QUERY_RESULT,
                              new StringMessageElement(MESSAGE_QUERY_RESULT,
                                                       queryResult,
                                                       null));
        }       
        msg.addMessageElement(MESSAGE_COMMAND,
                              new StringMessageElement(MESSAGE_COMMAND,
                                                       theCommand,
                                                       null));
        msg.addMessageElement(MESSAGE_LAST_ACCESS,
                              new StringMessageElement(MESSAGE_LAST_ACCESS,
                                                       lastAccess.toString(),
                                                       null));
        msg.addMessageElement(MESSAGE_MAX_INACTIVE,
                              new StringMessageElement(MESSAGE_MAX_INACTIVE,
                                                       maxInactive.toString(),
                                                       null));       
        msg.addMessageElement(InstanceNameMessage,
                              new StringMessageElement(InstanceNameMessage,
                                                       instanceName,
                                                       null));
        msg.addMessageElement(MESSAGE_INSTANCE_NAME,
                              new StringMessageElement(MESSAGE_INSTANCE_NAME,
                                                       instanceName,
                                                       null));
        //is nack message
        String isNackString = "N";
        if(isNack) {
            isNackString = "Y";
        }
        msg.addMessageElement(MESSAGE_IS_NACK,
                              new StringMessageElement(MESSAGE_IS_NACK,
                                                       isNackString,
                                                       null));         
        if(data != null) {
            msg.addMessageElement(MESSAGE_DATA,
                              new ByteArrayMessageElement(MESSAGE_DATA,
                                                       null,
                                                       data,
                                                       null));
        }
        if(trunkData != null) {
            msg.addMessageElement(MESSAGE_TRUNK_DATA,
                              new ByteArrayMessageElement(MESSAGE_TRUNK_DATA,
                                                       null,
                                                       trunkData,
                                                       null));
        }
        if(containerExtraParamData != null) {
            msg.addMessageElement(MESSAGE_CONTAINER_EXTRA_PARAMS_DATA,
                              new ByteArrayMessageElement(MESSAGE_CONTAINER_EXTRA_PARAMS_DATA,
                                                       null,
                                                       containerExtraParamData,
                                                       null));
        }
        if(propertiesState != null) {
            msg.addMessageElement(MESSAGE_PROPERTIES_DATA,
                              new ByteArrayMessageElement(MESSAGE_PROPERTIES_DATA,
                                                       null,
                                                       propertiesState,
                                                       null));
        }       

        msg.addMessageElement(ORIGINATING_INSTANCE_NAME,
                new StringMessageElement(ORIGINATING_INSTANCE_NAME, ReplicationUtil.getInstanceName(), null));
       
        return msg;
    }
   
    // begin Metadata related 

    /**
     * create a new ReplicationState based on the input
     * @param mode
     * @param id
     * @param appid
     * @param metaData can be SimpleMetadata
     */    
    public static ReplicationState createReplicationState(String mode, String id, String appid, Metadata metadata) {
        ReplicationState state = null;
        state = createReplicationStateFromSimpleMetadata(mode, id, appid, (SimpleMetadata) metadata);
        return state;
    }

    /**
     * create a new ReplicationState based on the input
     * @param mode
     * @param id
     * @param appid
     * @param simpleMetadata
     */    
    public static ReplicationState createReplicationStateFromSimpleMetadata(String mode, String id, String appid, SimpleMetadata simpleMetadata)
        {
                
        Object extraParams
            = simpleMetadata.getExtraParam();
        byte[] extraParamState = null;
        if(extraParams != null) {
            try {
                extraParamState
                    = getByteArray(extraParams);
            } catch (IOException ex) {
                ;   //deliberate no-op
            }
        }
        ReplicationState state =
            new ReplicationState(mode,   //mode
                id,                          //id
                appid,                       //appid
                simpleMetadata.getVersion(), //version
                simpleMetadata.getLastAccessTime(), //lastAccess
                simpleMetadata.getMaxInactiveInterval(), //maxInactive,
                null,                           //extraParam
                null,                           //queryResult
                null,                           //instanceName
                null,                           //command FIXME
                simpleMetadata.getState(),      //data
                null,                           //trunkState
                extraParamState);      //extraParamState
        if(_logger.isLoggable(Level.FINE)) {
            _logger.fine("ReplicationState>>createReplicationStateFromSimpleMetadata:state = " + state);
        }        
       return state;
    }
   
    static String extractExtraParamStringFrom(String mode, Object e) {
        if(mode.equals(MODE_SSO)) {
            //return (String)e; //reminder for possible use with ejb
            if(e == null) {
                return null;
            } else {
                return ((SSOExtraParams)e).username;
            }           
        }
        if(mode.equals(MODE_WEB)) {
            if(e == null) {
                return null;
            } else {
                return ((HttpSessionExtraParams)e).getSsoId();
            }
        }
        return null;
    }    
   
    /**
    * create a CompositeMetadata representing ReplicationState state
    *
    * @param state
    *   The ReplicationState
    *
    * @return
    *   A newly created CompositeMetadata object for the given state
    */
    public static CompositeMetadata createCompositeMetadataFrom(ReplicationState state) {
        if (state == null || state.getState() == null) {
            return null;
        }
        Collection entries = deserializeStatesCollection(state.getState());
        CompositeMetadata result
            = new CompositeMetadata(
                state.getVersion()//version
                state.getLastAccess(), //lastAccess
                state.getMaxInactiveInterval(), //maxInactive
                entries,                        //entries
                state.getTrunkState(),          //trunkState
                state.getExtraParam(),     //extraParam
                state.getContainerExtraParams()); //containerExtraParams
        return result;
    }
   
    private static Collection deserializeStatesCollectionPrevious(byte[] entriesState) {
        Collection result = new ArrayList();
        try {
            result = (Collection)getObjectValue(entriesState);
        } catch (ClassNotFoundException ex1) {
        } catch (IOException ex2) {}       
        return result;
    }
   
   
    private static Collection deserializeStatesCollection(byte[] entriesState) {
        Collection result = new ArrayList();
        try {
            result = (Collection)getAttributeValueCollection(entriesState);
        } catch (ClassNotFoundException ex1) {
        } catch (IOException ex2) {}       
        return result;
    }
   
    /**
    * Given a byte[] containing session data, return a session
    * object
    *
    * @param state
    *   The byte[] with the session attribute data
    *
    * @return
    *   A newly created object for the given session attribute data
    */
    public static Object getObjectValue(byte[] state)
        throws IOException, ClassNotFoundException
    {
        return getObjectValue(state, false);
    }   
   
    /**
    * Given a byte[] containing session data, return a session
    * object
    *
    * @param state
    *   The byte[] with the session attribute data
    * @param compress
    *   should compression be used
    *
    * @return
    *   A newly created object for the given session attribute data
    */
    public static Object getObjectValue(byte[] state, boolean compress)
        throws IOException, ClassNotFoundException
    {
        Object objectValue = null;
        InputStream is = null;
        BufferedInputStream bis = null;
        ByteArrayInputStream bais = null;
        ObjectInputStream ois = null;
           
        try
        {
            bais = new ByteArrayInputStream(state);
            bis = new BufferedInputStream(bais);
            if(compress) {           
                is = new GZIPInputStream(bis);
            } else {
                is = bis;
            }           
            ois = new ObjectInputStream(is);
           
            if(ois != null) {
                try {
                    objectValue = ois.readObject();
                }
                finally {
                    if (ois != null) {
                        try {
                            ois.close();
                            bis = null;
                        }
                        catch (IOException e) {
                        }
                    }
                }
            }
        }
        catch(ClassNotFoundException e)
        {
            // FIXME evaluate log level
            if (_logger.isLoggable(Level.FINE)) {
                _logger.log(Level.FINE, "Exception occurred in getAttributeValue", e);
            }
            throw e;
        }
        catch(IOException e)
        {
             // FIXME evaluate log level
//            if (_logger.isLoggable(Level.FINE)) {
//                _logger.fine("Exception occurred in getAttributeValue", e);
//            }
            throw e;
        }     

        return objectValue;
    }
       
    protected static Object getAttributeValueCollection(byte[] state)
        throws IOException, ClassNotFoundException
    {
        Collection attributeValueList = new ArrayList();
        BufferedInputStream bis = null;
        ByteArrayInputStream bais = null;
        ObjectInputStream ois = null;
           
        try
        {
            bais = new ByteArrayInputStream(state);
            bis = new BufferedInputStream(bais);
            ois = new ObjectInputStream(bis);
           
            if(ois != null) {
                try {                   
                    //first get List size
                    Object whatIsIt = ois.readObject();
                    int entriesSize = 0;
                    if(whatIsIt instanceof Integer) {
                        entriesSize = ((Integer)whatIsIt).intValue();
                    } else {
                        if (_logger.isLoggable(Level.FINE)) {
                            _logger.fine("ResplicationState>>getAttributeValueCollection: first obj not integer");
                        }
                    }
                    //int entriesSize = ((Integer) ois.readObject()).intValue();
                    //if (_logger.isLoggable(Level.FINE)) {
                    //    _logger.fine("entriesSize = " + entriesSize);
                    //}
                    //attributeValueList = new ArrayList(entriesSize);
                    for (int i = 0; i < entriesSize; i++) {
                        Object nextAttributeValue = ois.readObject();
                        attributeValueList.add(nextAttributeValue);
                    }                   
                   
                }
                finally {
                    if (ois != null) {
                        try {
                            ois.close();
                            bis = null;
                        }
                        catch (IOException e) {
                        }
                    }
                }
            }
        }
        catch(ClassNotFoundException e)
        {
            // FIXME evaluate log level
            if (_logger.isLoggable(Level.FINE)) {
                _logger.log(Level.FINE, "Exception occurred in getAttributeValue", e);
            }
            throw e;
        }
        catch(IOException e)
        {
              // FIXME evaluate log level
//            if (_logger.isLoggable(Level.FINE)) {
//                _logger.log(Level.FINE, "Exception occurred in getAttributeValue", e);
//            }
            throw e;
        }     

        return attributeValueList;       
    }   
   
    /**
    * Create an byte[] for the object that we can then pass to
    * the ReplicationState.
    *
    * @param obj
    *   The attribute value we are serializing
    *
    */
    protected static byte[] getByteArray(Object obj)
      throws IOException {
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        byte[] obs;
        try {
            bos = new ByteArrayOutputStream();
            //use normal ObjectOutputStream if there is a failure during stream creation
            if(oos == null) {
                oos = new ObjectOutputStream(new BufferedOutputStream(bos));
            }           
            oos.writeObject(obj);
            oos.close();
            oos = null;

            obs = bos.toByteArray();
        }
        finally {
            if ( oos != null )  {
                oos.close();
            }
        }

        return obs;
    }
   
    protected static byte[] getByteArrayFromCollection(Collection entries)
        throws IOException {
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        byte[] obs;
        try {
            bos = new ByteArrayOutputStream();
            //use normal ObjectOutputStream if there is a failure during stream creation
            if(oos == null) {
                oos = new ObjectOutputStream(new BufferedOutputStream(bos));
            }           
            //first write out the entriesSize
            int entriesSize = entries.size();
            oos.writeObject(Integer.valueOf(entriesSize));
            //then write out the entries
            Iterator it = entries.iterator();
            while(it.hasNext()) {
                oos.writeObject(it.next());
            }           
            oos.close();
            oos = null;

            obs = bos.toByteArray();
        }
        finally {
            if ( oos != null )  {
                oos.close();
            }
        }
        if(_logger.isLoggable(Level.FINE)) {
            _logger.log(Level.FINE,"size of attributes byte array: " + obs.length);
        }
        return obs;
    }
   
    // end Metadata related

    /**
     * is this state expired
     */   
    public boolean isExpired() {
        //-1 means no expiration
        if(this.getMaxInactiveInterval() == -1) {
            return false;
        }
        return ( (System.currentTimeMillis() - this.getLastAccess())
            > (this.getMaxInactiveInterval() * 1000) );
    }

    /**
     * is this message a return message from normal message
     * true if command is RETURN_MSG_COMMAND
     */   
    public boolean isReturnMessage() {
        String theCommand = this.getCommand();
        if(theCommand == null) {
            return false;
        } else {
            return theCommand.equals(RETURN_MSG_COMMAND);
        }
    }
   
    /**
     * is this message a return message from normal message
     * true if command is HC_COMMAND
     */   
    public boolean isHCMessage() {
        String theCommand = this.getCommand();
        if(theCommand == null) {
            return false;
        } else {
            return theCommand.equals(HC_COMMAND);
        }
    }            
   
    /**
     * is this message a return message from normal message
     * true if command is RETURN_HC_MSG_COMMAND
     */   
    public boolean isHCReturnMessage() {
        String theCommand = this.getCommand();
        if(theCommand == null) {
            return false;
        } else {
            return theCommand.equals(RETURN_HC_MSG_COMMAND);
        }
    }   
   
    /**
     * is this message a return message from a broadcast
     * true if command is RETURN_BROADCAST_MSG_COMMAND
     */
    public boolean isReturnFromBroadcastMessage() {
        String theCommand = this.getCommand();
        if(theCommand == null) {
            return false;
        } else {
            return theCommand.equals(RETURN_BROADCAST_MSG_COMMAND);
        }
    }
   
    /**
     * @return mode (e.g. MODE_WEB, MODE_EJB, MODE_SSO)
     */   
    public String getMode() {
        return _mode;
    }   
   
    /**
     * @return _id (key)
     */   
    public Object getId() {
        return _id;
    }
   
    /**
     *
     * @return _appId
     */   
    public String getAppId() {
        return _appId;
    }
   
    /**
     * @return version
     */   
    public long getVersion() {
        return _version;
    }
   
    /**
     * @param version the version
     */   
    public void setVersion(long version) {
        _version = version;
    }    
   
    /**
     * @return last access time
     */   
    public long getLastAccess() {
        return _lastAccess;
    }   
   
    /**
     * @param lastAccess last access time
     */   
    public void setLastAccess(long lastAccess) {
        _lastAccess = lastAccess;
    }   
   
    /**
     * @return max inactive interval (seconds)
     */   
    public long getMaxInactiveInterval() {
        return _maxInactiveInterval;
    }   
   
    /**
     * @return _extraParam
     */   
    public String getExtraParam() {
        return _extraParam;
    }
   
    /**
     * @param extraParam extraParam
     */   
    public void setExtraParam(String extraParam) {
        _extraParam = extraParam;
    }   
   
    /**
     * @return _queryResult
     */   
    public Object getQueryResult() {
        return _queryResult;
    }
   
    /**
     * @param queryResult queryResult
     */   
    public void setQueryResult(Object queryResult) {
        _queryResult = queryResult;
    }   
   
    /**
     * @return _instanceName
     */   
    public String getInstanceName() {
        return _instanceName;
    }   
   
    /**
     * @return _command
     */   
    public String getCommand() {
        return _command;
    }   

    /**
     * @return state
     */   
    public byte[] getState() {
        return _state;
    }
   
    /**
     * @return trunkState
     */   
    public byte[] getTrunkState() {
        return _trunkState;
    }
   
    /**
     * @return _containerExtraParamsState
     */   
    public byte[] getContainerExtraParamsState() {
        return _containerExtraParamsState;
    }
   
    /**
     * @param containerExtraParamsState containerExtraParamsState
     */   
    public void setContainerExtraParamsState(byte[] containerExtraParamsState) {
        _containerExtraParamsState = containerExtraParamsState;
        this.setDeserializedExtraParam(null);
    }
   
    /**
     * Return the Container's ExtraParams (deserialized).
     */
    public Object getContainerExtraParams() {
        if (_cachedDeserializedExtraParam != null) {
            return _cachedDeserializedExtraParam;
        } else if (_containerExtraParamsState != null) {
            try {
                _cachedDeserializedExtraParam = getObjectValue(_containerExtraParamsState);
            } catch (Exception ex) {
                _logger.warning("unable to deserialize ContainerExtraParams for appid: " + getAppId() + " id: " + getId() + ":version:" + getVersion());
            }
        }
        return _cachedDeserializedExtraParam;
    }
   
   
     public int hashCode() {
         return _hc;
     }
    
     public boolean equals(Object obj) {
         boolean result = false;
         if (obj instanceof ReplicationState) {
             ReplicationState other = (ReplicationState) obj;
             if ((_id.equals(other._id) && (_appId.equals(other._appId)))) {
                 result = true;
             }
         }
        
         return result;
     }   
   
     public boolean isAckRequired() {
         return _ackRequired;
     }
     public void setAckRequired(boolean ackRequired) {
         this._ackRequired = ackRequired;
     }
    
     public boolean isNack() {
         return _isNack;
     }    
    
     public void setNack(boolean isNack) {
         this._isNack = isNack;
     }    
        
     public long getSendStartTime() {
         return _sendStartTime;
     }
    
     public void setSendStartTime(long value) {
         _sendStartTime = value;
     }    
    
     public boolean isSent() {
         return _sentFlag.get();
     }
    
     public void setAckIdsList(List list) {
         _ackIdsList = list;
     }
    
     public List getAckIdsList() {
         return _ackIdsList;
     }
    
     public void setSent(boolean value) {
         _sentFlag.set(value);
     }
    
     public Object getDeserializedExtraParam() {
         return _cachedDeserializedExtraParam;
     }
    
     public void setDeserializedExtraParam(Object extraParam) {
         _cachedDeserializedExtraParam = extraParam;
     }
    
    public RouteAdvertisement getRouteAdvertisement(){
        return _routeAdvertisement;
    }
    
    public void setRouteAdvertisement(RouteAdvertisement routeAdvertisement) {
        _routeAdvertisement = routeAdvertisement;
    }
   
    public void setProperty(Object key, Object value) {
        if(properties != null) {
            properties.put(key, value);
        }
    }
 
    public Object getProperty(Object key) {
        return properties != null ? properties.get(key) : null;
    }
 
    public void setProperties(Map properties) {
        this.properties = properties;
    }
   
    public void setProperties(String beKey, String origin) {
        if(getProperties() == null) {
            setProperties(new HashMap());
        }
        setProperty(ReplicationState.BEKEY, beKey);
        setProperty(ReplicationState.ORIGINATING_INSTANCE_NAME, origin);
    }
   
    public void setState(byte[] state) {
        this._state = state;
    }
    public Map getProperties() {
        return properties;
    }   
    
   
    public String toString() {
        StringBuffer sb = new StringBuffer(100);
        sb.append("_mode=" + _mode + "\n");
        sb.append("_id=" + _id + "\n");
        sb.append("_appId=" + _appId + "\n");
        sb.append("_version=" + _version + "\n");
        sb.append("_command=" + _command + "\n");
        sb.append("_lastAccess=" + _lastAccess + "\n");
        sb.append("_maxInactiveInterval=" + _maxInactiveInterval + "\n");
        sb.append("_extraParam=" + _extraParam + "\n");
        sb.append("_queryResult=" + _queryResult + "\n");
        sb.append("_instanceName=" + _instanceName + "\n");
        sb.append("isExpired=" + this.isExpired() + "\n");
        sb.append("_ackRequired=" + this.isAckRequired() + "\n");
        sb.append("_isNack=" + _isNack + "\n");
        return sb.toString();
    }

    void setBiDiStyle(boolean value) {
        bidiStyle = value;
    }

    boolean isBiDiStyle() {
        return bidiStyle;
    }
   
    private List _ackIdsList = null;
    private String _mode = null;
    private Object _id = null;
    private String _appId = null;  
    private long _lastAccess = 0L;
    private long _maxInactiveInterval = 0L; //seconds
    private long _version = -1L;
    private String _extraParam = null;
    private Object _queryResult = null;
    String _instanceName = ReplicationUtil.getInstanceName();
    private String _command = null;
    private byte[] _state = null;
    private byte[] _trunkState = null;
    private byte[] _containerExtraParamsState = null;
    private boolean _ackRequired = false;
    private boolean _isNack = false;
    private int _hc;
    private volatile AtomicBoolean _sentFlag = new AtomicBoolean(false);
    private long _sendStartTime = -1L;
    private RouteAdvertisement _routeAdvertisement = null;
    private transient Object _cachedDeserializedExtraParam = null;
    private Map properties = new HashMap();
    private boolean bidiStyle;
}
TOP

Related Classes of com.sun.enterprise.ee.web.sessmgmt.ReplicationState

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.