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

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

/*
* 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.
*/
/*
* JxtaBiDiPipeWrapper.java
* for now (like the Jxta samples) we use
* this primarily for receiving messages
*
* Created on February 7, 2006, 11:37 AM
*
*/

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

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.SocketTimeoutException;
import java.security.AccessController;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Collections;
import java.util.Date;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import java.util.logging.Logger;
import java.util.logging.Level;
import com.sun.logging.LogDomains;

import net.jxta.credential.AuthenticationCredential;
import net.jxta.credential.Credential;
import net.jxta.document.AdvertisementFactory;
import net.jxta.document.MimeMediaType;
import net.jxta.document.StructuredDocumentFactory;
import net.jxta.document.XMLDocument;
import net.jxta.endpoint.ByteArrayMessageElement;
import net.jxta.endpoint.Message;
import net.jxta.endpoint.MessageElement;
import net.jxta.endpoint.Messenger;
import net.jxta.endpoint.StringMessageElement;
import net.jxta.exception.PeerGroupException;
import net.jxta.impl.membership.pse.StringAuthenticator;
import net.jxta.membership.InteractiveAuthenticator;
import net.jxta.membership.MembershipService;
import net.jxta.peer.PeerID;
import net.jxta.peergroup.PeerGroup;
import net.jxta.peergroup.PeerGroupFactory;
import net.jxta.pipe.InputPipe;
import net.jxta.pipe.OutputPipe;
import net.jxta.pipe.PipeMsgEvent;
import net.jxta.pipe.PipeMsgListener;
import net.jxta.pipe.PipeService;
import net.jxta.protocol.PipeAdvertisement;
import net.jxta.rendezvous.RendezVousService;
import net.jxta.rendezvous.RendezvousEvent;
import net.jxta.rendezvous.RendezvousListener;
import net.jxta.util.JxtaBiDiPipe;

import org.apache.catalina.Globals;
import org.apache.catalina.LifecycleException;

import com.sun.enterprise.web.ServerConfigLookup;

/**
*
* @author Larry White
*/
public class JxtaBiDiPipeWrapper implements PipeMsgListener, RendezvousListener, Runnable {
   
    private PeerGroup netPeerGroup = null;
    private PipeAdvertisement pipeAdv;
    private PeerID peerID;
    private JxtaBiDiPipe pipe;
    private boolean waitForRendezvous = false;
    private boolean stopped = false;
    private volatile boolean attemptingConnection = false;
    private String rendezvousLock = "Rendezvous Lock";
    private RendezVousService rendezvous;
    private final static String SenderMessage = "pipe_tutorial";
    private final static String InstanceNameMessage = "instance_name";
    private final static String completeLock = "completeLock";
    private final static String CLUSTER_MEMBERS = "cluster_members";
    private int count = 0;
   
    private final static String MESSAGE_ID =
        ReplicationState.MESSAGE_ID;
    private final static String MESSAGE_COMMAND =
        ReplicationState.MESSAGE_COMMAND;
    private final static String RETURN_MSG_COMMAND =
        ReplicationState.RETURN_MSG_COMMAND;
    private final static String MESSAGE_READY
        = ReplicationState.MESSAGE_READY;
    private final static String ReadyMessage
        = ReplicationState.ReadyMessage;
    private final static String MESSAGE_BROADCAST_NETWORK_PARTITION_ADVISORY
        = ReplicationState.MESSAGE_BROADCAST_NETWORK_PARTITION_ADVISORY;

    public final static String LOGGER_MEM_REP
        = ReplicationState.LOGGER_MEM_REP;   
   
    /**
     * The logger to use for logging ALL web container related messages.
     */
    //private static final Logger _logger
    //    = LogDomains.getLogger(LogDomains.WEB_LOGGER);
    private static final Logger _logger
        = Logger.getLogger(LOGGER_MEM_REP);    
    private static final Logger _pipelogger = ReplicationUtil.getPipeLogger();
   
    /**
    * The helper class used to manage retryable errors from the HA store
    */
    protected JxtaConnectErrorManager errorMgr = null;
   
    /**
    * The number of seconds to wait before timing out a transaction
    * Default is 5 minutes.
    */
    protected String timeoutSecs = new Long(5 * 60).toString();
   
    private CountDownLatch doneSignal = new CountDownLatch(1);
   
    /** Creates a new instance of JxtaBiDiPipeWrapper */
    public JxtaBiDiPipeWrapper() {
        long timeout = new Long(timeoutSecs).longValue();
        errorMgr = new JxtaConnectErrorManager(timeout);
    }
   
    public JxtaConnectErrorManager getErrorManager() {
        long timeout = new Long(timeoutSecs).longValue();
        return new JxtaConnectErrorManager(timeout);
    }   
   
    /**
     *  start
     *
     *@param  args  command line args
     */
    public void start() {

        this.startJxta(false);
        String partnerName = this.getReplicateToInstanceName();
        try {
            String value = System.getProperty("RDVWAIT", "false");
            this.waitForRendezvous = Boolean.valueOf(value).booleanValue();

            this.pipeAdv = JxtaUtil.getPipeAdvertisement(this.getReplicateToInstanceName());
            /* FIXME - moving this to run method
            int numPipes = this.getNumberOfPipes();      
            createPipes(numPipes);
            initializePropagatedPipes();
            sentTestPropagatedMessage();
             */
           
            /* FIXME: check later on this - comment this waiting out for now
            this.waitUntilCompleted();
            this.netPeerGroup.stopApp();
            this.netPeerGroup.unref();
             */
        } catch (Exception e) {
            if (_logger.isLoggable(Level.FINEST)) {
                _logger.log(Level.FINEST, "failed to bind the JxtaBiDiPipe", e);
            }            
        }
        doneSignal = new CountDownLatch(1);
        // run on this thread
        //this.run();
        Thread acceptThread = new Thread(this);
        acceptThread.setDaemon(true);
        acceptThread.start();
        long startTime = 0L;
        if (_logger.isLoggable(Level.FINE)) {
            startTime = System.currentTimeMillis();
        }
        int awaitTimeInSeconds = calculateAwaitTimeForStartup();
        if (_logger.isLoggable(Level.FINE)) {
            _logger.fine("awaitTimeInSeconds = " + awaitTimeInSeconds);
        }       
        try {
            doneSignal.await(awaitTimeInSeconds, TimeUnit.SECONDS);
        } catch(InterruptedException ex) {}       
        if (_logger.isLoggable(Level.FINE)) {
            _logger.fine("JxtaBiDiPipeWrapper after a wait: wait time = " + (System.currentTimeMillis() - startTime));
        }
        //if our partner did not start we must reshape
        testStartupAndReshapeIfNecessary(partnerName);
        ReplicationResponseRepository.getInstance().start();
        try {
            JxtaReplicationSender.createInstance().start();
        } catch (LifecycleException ex) {
            ;
        }
        ReplicationHealthChecker healthChecker
            = ReplicationHealthChecker.getInstance();       
        healthChecker.setInstanceStartTime(System.currentTimeMillis());
        LoadProcessingGovernor loadProcessingGovernor
            = LoadProcessingGovernor.getInstance();       
    }
   
    private int calculateAwaitTimeForStartup() {
        int result = 60; //seconds
        ReplicationHealthChecker healthChecker
            = ReplicationHealthChecker.getInstance();
        int numberOfClusterMembers
            = healthChecker.getCurrentGroupMembersViaAdminAndExtras().size();
        if(numberOfClusterMembers == 1) {
            return result;
        }
        int numberOfPipes = this.getNumberOfPipes();
        return numberOfPipes * 15;
    }   
   
    void testStartupAndReshapeIfNecessary(String partnerName) {
        if (_logger.isLoggable(Level.FINE)) {
            _logger.fine("testStartupAndReshapeIfNecessary...");
        }
        //FIXME for testing
        areAllCurrentPipesOk();
        if(areCurrentPipesOk()) {
            if (_logger.isLoggable(Level.FINE)) {
                _logger.fine("JxtaBiDiPipeWrapper>>startup completed successfully: no reshape needed");
            }            
            return;
        }
        if(this.isAttemptingConnection()) {
            if (_logger.isLoggable(Level.FINE)) {
                _logger.fine("JxtaBiDiPipeWrapper>>startup partner failed: reshape needed");
            }           
            setAttemptingConnection(false);
            this.respondToFailure(partnerName, true);
        }
    }
   
    /**
     *  Main processing method
     */
    public void run() {
        if (_pipelogger.isLoggable(Level.FINEST)) {
            _pipelogger.finest("JxtaBiDiPipeWrapper-run method");
        }
        //initialize propagated pipes earlier
        initializePropagatedPipes();       
        int numPipes = this.getNumberOfPipes();
        if (_pipelogger.isLoggable(Level.FINE)) {
            _pipelogger.fine("JxtaBiDiPipeWrapper-numPipes=" + numPipes);
        }
        ReplicationHealthChecker healthChecker = ReplicationHealthChecker.getInstance();
        String proposedPartner = healthChecker.getReshapeReplicateToInstanceName(null);
        if (_pipelogger.isLoggable(Level.FINE)) {
            _pipelogger.fine("about to connectToInstance: " + proposedPartner);
        }
        setAttemptingConnection(true);
        boolean pipesCreated = attemptConnectionNumberOfTries(3);
        //boolean pipesCreated = connectToInstance(proposedPartner, false);
        //boolean pipesCreated = createPipes(numPipes);
        if (_pipelogger.isLoggable(Level.FINE)) {
            _pipelogger.fine("JxtaBiDiPipeWrapper:run:pipesCreated=" + pipesCreated);
        }
        //only continue if pipes were created else give up
        if(pipesCreated) {   
            //initializePropagatedPipes();      
            sentTestPropagatedMessage();

            //we are connected so now ready to replicate
            if (_pipelogger.isLoggable(Level.FINEST)) {
                _pipelogger.finest("JxtaBiDiPipeWrapper:run() complete");
            }            
            ReplicationHealthChecker.setReplicationCommunicationOperational(true);
        } else {
            if (_pipelogger.isLoggable(Level.FINEST)) {
                _pipelogger.finest("JxtaBiDiPipeWrapper>>run was unsuccessful: quitting run");
            }             
            ReplicationHealthChecker.setReplicationCommunicationOperational(false);
        }
        setAttemptingConnection(false);
        if (_pipelogger.isLoggable(Level.FINE)) {
            _pipelogger.fine("doneSignal.countdown()");
        }
        doneSignal.countDown();
        ReplicationHealthChecker.setMostRecentReshapeTime(System.currentTimeMillis());
    }
   
    private boolean attemptConnectionNumberOfTries(int numberOfTries) {
        int count = 0;
        boolean result = false;
        ReplicationHealthChecker healthChecker = ReplicationHealthChecker.getInstance();
        while(count < numberOfTries) {
            String proposedPartner = healthChecker.getReshapeReplicateToInstanceName(null);
            if (_pipelogger.isLoggable(Level.FINE)) {
                _pipelogger.fine("about to connectToInstance: " + proposedPartner);
            }
            result = connectToInstance(proposedPartner, false);
            if (_pipelogger.isLoggable(Level.FINE)) {
                _pipelogger.fine("attemptConnectionNumberOfTries-proposedPartner: " + proposedPartner + " count: " + count + " result=" + result);
            }
            if(result) {
                break;
            } else {
                closeNonPropagatedSenderConnections();
                count++;
            }
        }
        return result;
    }

    /**
     *  interrupt connection attempt
     *  sleep for 15 seconds to allow thread to complete
     */   
    private void interruptConnectionAttempt() {
        setAttemptingConnection(false);
        try {
            Thread.currentThread().sleep(15000L);
        } catch (Exception ex) {
            //nothing to do deliberately eating
            assert true;
        }
    }
   
    void setAttemptingConnection(boolean value) {
        attemptingConnection = value;
    }
   
    boolean isAttemptingConnection() {
        return attemptingConnection;
    }
   
    /**
     *  considered alone if replication communication is down and we are not
     *  currently attempting communication
     */   
    boolean isAlone() {
        return !isAttemptingConnection() && !ReplicationHealthChecker.isReplicationCommunicationOperational();
    }
   
    String getInstanceName() {
        return ReplicationUtil.getInstanceName();
    }
   
    int getNumberOfPipes() {
        ServerConfigLookup lookup = new ServerConfigLookup();
        int result = lookup.getNumberOfReplicationPipesFromConfig();
        /*
        if(result < 2) {
            result = 2;
        }
         */
        if(result < 1) {
            result = 1;
        }
        return result;
    }   
   
    String getReplicateToInstanceName() {
        String myName = this.getInstanceName();
        SimpleInstanceArranger arranger = getSimpleArranger();
//        This commented out code would work with clustered stand-alone
//        instances - currently not using
//        if (_pipelogger.isLooggable(Level.FINE)) {
//            ArrayList instanceNamesTest = this.getClusterInstanceNamesList();    
//            _pipelogger.fine("testing lookup.getServerNamesInCluster");
//            for(int i=0; i<instanceNamesTest.size(); i++) {
//                boolean isEqual =
//                    ((String)instanceNamesTest.get(i)).equalsIgnoreCase((String)instanceNames.get(i));
//                _pipelogger.fine("instancesNameTest[" + i + "] = " + instanceNamesTest.get(i) +
//                              " instancesNames[" + i + "] = " + instanceNames.get(i) +
//                              " index[" + i + "] = " + isEqual);
//             }
//        }

        String result = arranger.getReplicaPeerName(myName);
        if (_logger.isLoggable(Level.FINEST)) {
            _logger.finest("getReplicaPeerName = " + result);
        }        
        return result;
    }
   
    String getReplicatedFromInstanceName() {
        String myName = this.getInstanceName();
        SimpleInstanceArranger arranger = getSimpleArranger();
        String result = arranger.getReplicatedFromPeerName(myName);
        if (_logger.isLoggable(Level.FINEST)) {
            _logger.finest("getReplicatedFromPeerName = " + result);
        }       
        return result;
    }

    /**
     *  get SimpleArranger initialized from domain.xml list
     *  of instances in the cluster
     */   
    SimpleInstanceArranger getSimpleArranger() {
        SimpleInstanceArranger arranger = new SimpleInstanceArranger();
        ReplicationHealthChecker healthChecker
            = ReplicationHealthChecker.getInstance();
        ArrayList instanceNames
            = (ArrayList)healthChecker.getCurrentGroupMembersViaAdminAndExtras();
        arranger.init(instanceNames);
        return arranger;
    }

    /**
     *  is our cluster exactly two instances replicating
     *  to each other
     */   
    boolean isSizeTwoCluster() {
        String replicatedFrom = getReplicatedFromInstanceName();
        String replicateTo = getReplicateToInstanceName();
        if(replicatedFrom == null || replicateTo == null) {
            return false;
        }
        return (replicatedFrom.equals(replicateTo));
    }

    /**
     *  get list of cluster instance names from the
     *  property "cluster_members" in <availability-service>
     */   
    ArrayList getClusterInstanceNamesList() {
        ArrayList instanceNames = new ArrayList();
        ServerConfigLookup lookup = new ServerConfigLookup();
        String instanceNamesString =
            lookup.getAvailabilityServicePropertyString(CLUSTER_MEMBERS);
        if(instanceNamesString == null) {
            return instanceNames;
        }
        String[] instancesArray = instanceNamesString.split(",");
        List instancesList = Arrays.asList(instancesArray);
        for(int i=0; i<instancesList.size(); i++) {
            if (_logger.isLoggable(Level.FINEST)) {
                _logger.finest("getClusterInstanceNamesList:elem" + i + " = " + ((String)instancesList.get(i)).trim() );
            }            
            instanceNames.add( ((String)instancesList.get(i)).trim() );
        }
        return instanceNames;
    }  
   
    /**
     *  initialize both the propagated output and input pipes
     */
    private void initializePropagatedPipes() {
        initializePropagatedOutputPipe();
        initializePropagatedInputPipeWrapper();
    }

    /**
     *  initialize the propagated output pipe
     */   
    private void initializePropagatedOutputPipe() {
        OutputPipe op = this.createPropagatedOutputPipe();
        if (_pipelogger.isLoggable(Level.FINEST)) {
            _pipelogger.finest("setting JxtaSenderPipeManagers bidipipewrapper = " + this);
        }
        JxtaSenderPipeManager.createInstance().setJxtaBiDiPipeWrapper(this);
        JxtaSenderPipeManager.createInstance().setPropagatedOutputPipe(op);
    }

    /**
     *  initialize the propagated input pipe
     */    
    private void initializePropagatedInputPipeWrapper() {
        InputPipeWrapper ipWrapper = this.createPropagatedInputPipeWrapper();
        JxtaReceiverPipeManager.createInstance().setPropagatedInputPipeWrapper(ipWrapper);
    }

    /**
     *  close both sender-side and receiver-side health pipes
     */   
    private void closeHealthPipes() {
        closeSenderHealthPipe();
        closeReceiverHealthPipe();
    }

    /**
     *  close sender-side health pipe
     */   
    private void closeSenderHealthPipe() {
        JxtaSenderPipeManager.createInstance().closeHealthPipeWrapper();
    }

    /**
     *  close receiver-side health pipe
     */   
    private void closeReceiverHealthPipe() {
        JxtaReceiverPipeManager.createInstance().closeHealthPipeWrapper();
    }   

    /**
     *  close both input and output propagated pipes
     */   
    private void closePropagatedPipes() {
        JxtaSenderPipeManager.createInstance().closePropagatedOutputPipe();
        JxtaReceiverPipeManager.createInstance().closePropagatedInputPipeWrapper();
    }    
   
    private void sentTestPropagatedMessage() {  
        OutputPipe outputPipe =
            JxtaSenderPipeManager.createInstance().getPropagatedOutputPipe();
        sendTestPropagatedMessages(outputPipe);
    }
   
    /**
     *  Send a series of messages over a pipe
     *
     * @param  pipe  Description of the Parameter
     */
    private void sendTestPropagatedMessages(OutputPipe pipe) {
        String instanceName = ReplicationUtil.getInstanceName();
        try {
            for (int i = 0; i < 1; i++) {
                Message msg = new Message();
                String data = "Propagated Message #" + i + " From Instance " + instanceName;
                msg.addMessageElement(SenderMessage,
                                      new StringMessageElement(SenderMessage,
                                                               data,
                                                               null));
                msg.addMessageElement(InstanceNameMessage,
                                      new StringMessageElement(InstanceNameMessage,
                                                               instanceName,
                                                               null));
                if(i == 0) {
                    String readyMsgString = MESSAGE_READY;
                    msg.addMessageElement(ReadyMessage,
                                          new StringMessageElement(ReadyMessage,
                                                                   readyMsgString,
                                                                   null));
                    if (_logger.isLoggable(Level.FINE)) {
                        _logger.fine("Sending :" + readyMsgString + ":" + instanceName);
                    }
                }
                if (_logger.isLoggable(Level.FINE)) {
                    _logger.fine("Sending :" + data);
                }
                pipe.send(msg);
            }
        } catch (Exception ie) {
            if (_logger.isLoggable(Level.FINE)) {
                _logger.log(Level.FINE, "handled exception in sendTestPropogateMesages", ie);
            }
        }
    }   
   
    OutputPipe createPropagatedOutputPipe() {

        String instanceName = ReplicationUtil.getInstanceName();
        PipeService pipeService = this.netPeerGroup.getPipeService();
        PipeAdvertisement pipeAdv = JxtaUtil.getPropagatedPipeAdvertisement();
        if (_pipelogger.isLoggable(Level.FINEST)) {
            _pipelogger.finest("prop pipe adv: " + pipeAdv);
        }       
        OutputPipe op = null;
        try {
            //op = pipeService.createOutputPipe(pipeAdv, Collections.singleton(JxtaUtil.getPeerID(instanceName)), 10000);
            op = pipeService.createOutputPipe(pipeAdv, 100);
        } catch (IOException ex) {
            //log this
        }
        return op;
    }
   
    private InputPipeWrapper createPropagatedInputPipeWrapper() {
       
        PipeService pipeService = this.netPeerGroup.getPipeService();
        PipeAdvertisement pipeAdv = JxtaUtil.getPropagatedPipeAdvertisement();
        InputPipe ip = null;
        InputPipeWrapper ipWrapper = new InputPipeWrapper();
        try {
            ip = pipeService.createInputPipe(pipeAdv, ipWrapper);
            ipWrapper.setPipe(ip);
        } catch (IOException ex) {
            // FIXME evaluate log level
            if (_pipelogger.isLoggable(Level.FINE)) {
                _pipelogger.log(Level.FINE, "caught exception in createPropagatedInputPipeWrapper", ex);
            }
        }
        return ipWrapper;
    }
   
     /**
     *  create n pipes (sender) and add them to
     * JxtaSenderPipeManager pool
     *
     *@param  numPipes
     *@returns boolean true if pipe creation successful - false otherwise
     */   
    private boolean createPipes(int numPipes) {
        PipeConnectionResult connectionResult = null;
        ArrayList pipeWrappers = new ArrayList();
        for (int i=0; i<numPipes; i++) {
            try {
                JxtaBiDiPipe nextPipe = new JxtaBiDiPipe();
                nextPipe.setReliable(true);
                PipeWrapper pipeWrapper = new PipeWrapper("sending_pipe#" + i, PipeWrapper.SENDER_PIPE, this.getReplicateToInstanceName(), nextPipe);
                /*
                if(i == 0) {
                    this.pipe = nextPipe;
                    //this.waitForRendezvousConnection();
                }
                 */
                //PipeWrapper pipeWrapper = new PipeWrapper("pipe#" + i, PipeWrapper.SENDER_PIPE, this.getReplicateToInstanceName(), nextPipe);
                //this.waitForRendezvousConnection();
                if (_pipelogger.isLoggable(Level.FINE)) {
                    _pipelogger.fine("JxtaBiDiPipeWrapper:run:before connectPipeWithRetries numPipes=" + numPipes);
                }       
                connectionResult = connectPipeWithRetries(nextPipe, pipeWrapper);
                if (_pipelogger.isLoggable(Level.FINE)) {
                    _pipelogger.fine("JxtaBiDiPipeWrapper:run:after connectPipeWithRetries:connectionResult=" +
                                 connectionResult.isConnected());
                }
                pipeWrapper = connectionResult.getPipeWrapper();
                //pipeWrapper = connectPipeWithRetries(nextPipe, pipeWrapper);               
                //if we timed out without a connection break
                //or if connection attempts are interrupted
                if(!connectionResult.isConnected() || !isAttemptingConnection()) {
                    if (_pipelogger.isLoggable(Level.FINE)) {
                        _pipelogger.fine("JxtaBiDiPipeWrapper>>unable to complete createPipes:breaking:i= " + i +
                        " connectionResult: " + connectionResult.isConnected() +
                        " isAttemptingConnection(): " + isAttemptingConnection())
                    }
                    break;
                }               
                //at this point we need to keep references around until data xchange
                //is complete
                if (_pipelogger.isLoggable(Level.FINEST)) {
                    _pipelogger.finest("JxtaBiDiPipe pipe # " + i + " created");
                }               
                if(i == 0) {
                    //JxtaReceiverPipeManager.createInstance().setReceiverPipe(this);
                    //JxtaReceiverPipeManager.createInstance().setHealthPipeWrapper(pipeWrapper);
                    JxtaSenderPipeManager.createInstance().setHealthPipeWrapper(pipeWrapper);
                } else {
                    pipeWrappers.add(pipeWrapper);
                }
            } catch (IOException ex) {
                //FIXME
            }
        }
        if (_pipelogger.isLoggable(Level.FINE)) {
            _pipelogger.fine("JxtaBiDiPipeWrapper>>createPipes stage one complete:connectionResultIsConnected:" +
                         connectionResult.isConnected());
        }
        if(connectionResult.isConnected()) {
            if (_pipelogger.isLoggable(Level.FINEST)) {
                _pipelogger.finest("sender pipe pool about to be initialized");
            }
            //JxtaReceiverPipeManager.createInstance().initPipePool(pipeWrappers);
            JxtaSenderPipeManager.createInstance().initPipePool(pipeWrappers);
            if (_pipelogger.isLoggable(Level.FINEST)) {
                _pipelogger.finest("sender pipe pool initialized");
            }
        }
        return connectionResult.isConnected();
    }
   
     /**
     *  create n pipes (sender) and add them to
     * JxtaSenderPipeManager pool
     *
     * @param  numPipes
     * @param  pipeAdvertisement to destination instance
     * @param  newPartnerInstance destination instance name
     */   
    private boolean createPipes(int numPipes, PipeAdvertisement pipeAdvertisement, String newPartnerInstance) {
        if (_pipelogger.isLoggable(Level.FINE)) {
            _pipelogger.fine("JxtaBiDiPipeWrapper>>createPipes:newPartnerInstance: " + newPartnerInstance);
        }
        PipeConnectionResult connectionResult = null;
        PeerID partnerPeerId = JxtaStarter.getPeerID(newPartnerInstance);
        ArrayList pipeWrappers = new ArrayList();
        for (int i=0; i<numPipes; i++) {
            try {
                JxtaBiDiPipe nextPipe = new JxtaBiDiPipe();
                nextPipe.setReliable(true);
                String nextPipeName = this.getSendingPipeNameFor(i, newPartnerInstance);
                //PipeWrapper pipeWrapper = new PipeWrapper("sending_pipe#" + i, PipeWrapper.SENDER_PIPE, newPartnerInstance, nextPipe);
                PipeWrapper pipeWrapper = new PipeWrapper(nextPipeName, PipeWrapper.SENDER_PIPE, newPartnerInstance, nextPipe);
                /*
                if(i == 0) {
                    this.pipe = nextPipe;
                    //this.waitForRendezvousConnection();
                }
                 */
                //PipeWrapper pipeWrapper = new PipeWrapper("pipe#" + i, PipeWrapper.SENDER_PIPE, this.getReplicateToInstanceName(), nextPipe);
                //this.waitForRendezvousConnection();
                if (_pipelogger.isLoggable(Level.FINEST)) {
                    _pipelogger.finest("JxtaBiDiPipeWrapper: Attempting to establish a connection");
                }
               
                connectionResult = connectPipeWithRetries(nextPipe, pipeWrapper, pipeAdvertisement, partnerPeerId);
                pipeWrapper = connectionResult.getPipeWrapper();
                //if we timed out without a connection break
                //or if connection attempts are interrupted
                if(!connectionResult.isConnected() || !isAttemptingConnection()) {
                    if (_pipelogger.isLoggable(Level.FINE)) {
                        _pipelogger.fine("JxtaBiDiPipeWrapper>>createPipes:breaking:i= " + i);
                    }
                    break;
                }                
                //pipeWrapper = connectPipeWithRetries(nextPipe, pipeWrapper, pipeAdvertisement);               
               
                //at this point we need to keep references around until data xchange
                //is complete
                if (_pipelogger.isLoggable(Level.FINEST)) {
                    _pipelogger.finest("JxtaBiDiPipe pipe # " + i + " created");
                }               
                if(i == 0) {
                    JxtaSenderPipeManager.createInstance().setHealthPipeWrapper(pipeWrapper);
                } else {
                    pipeWrappers.add(pipeWrapper);
                }
            } catch (IOException ex) {
                //FIXME evaluate log level
                if (_pipelogger.isLoggable(Level.FINE)) {
                    _pipelogger.log(Level.FINE, "IOException occurred in createPipes(numPipes=" + numPipes +
                                    ", newPartnerInstance=" + newPartnerInstance + ")", ex);                   
                }
            }
        }
        if (_pipelogger.isLoggable(Level.FINE)) {
            _pipelogger.fine("JxtaBiDiPipeWrapper>>createPipes stage one complete:connectionResultIsConnected:" +
                         connectionResult.isConnected());
        }
        if(connectionResult.isConnected()) {
            if (_pipelogger.isLoggable(Level.FINEST)) {
                _pipelogger.finest("sender pipe pool about to be initialized");
            }
            JxtaSenderPipeManager.createInstance().initPipePool(pipeWrappers);
            if (_pipelogger.isLoggable(Level.FINEST)) {
                _pipelogger.finest("sender pipe pool initialized");
            }            
        }
        return connectionResult.isConnected();
    }
   
    private String getSendingPipeNameFor(int i, String newPartnerInstance) {
        String thisInstanceName = ReplicationUtil.getInstanceName();
        String pipeTitle = "sending_pipe #" + i;
        if(i == 0) {
            pipeTitle = "sending_healthpipe";
        }
        return (thisInstanceName + " " + pipeTitle + " to " + newPartnerInstance);
    }
   
     /**
     *  create n pipes (sender) and add them to
     * JxtaSenderPipeManager pool
     *
     *@param  numPipes
     */   
    private void createPipesPrevious(int numPipes) {
        ArrayList pipeWrappers = new ArrayList();
        for (int i=0; i<numPipes; i++) {
            try {
                JxtaBiDiPipe nextPipe = new JxtaBiDiPipe();
                nextPipe.setReliable(true);
                PipeWrapper pipeWrapper = new PipeWrapper("sending_pipe#" + i, PipeWrapper.SENDER_PIPE, this.getReplicateToInstanceName(), nextPipe);
                /*
                if(i == 0) {
                    this.pipe = nextPipe;
                    this.waitForRendezvousConnection();
                }
                 */
                //PipeWrapper pipeWrapper = new PipeWrapper("pipe#" + i, PipeWrapper.SENDER_PIPE, this.getReplicateToInstanceName(), nextPipe);
                //this.waitForRendezvousConnection();
                if (_pipelogger.isLoggable(Level.FINEST)) {
                    _pipelogger.finest("JxtaBiDiPipeWrapper: Attempting to establish a connection");
                }
                nextPipe.connect(this.netPeerGroup,
                                null,
                                this.pipeAdv,
                                //60000,
                                300000,
                                // register as a message listener the pipeWrapper
                                pipeWrapper);
                nextPipe.setPipeEventListener(pipeWrapper);
                if (_pipelogger.isLoggable(Level.FINE)) {
                    _pipelogger.fine("Pipe connected to: " + this.getReplicateToInstanceName() + " name: " + pipeWrapper.getName());
                }
                //at this point we need to keep references around until data xchange
                //is complete
                if (_pipelogger.isLoggable(Level.FINEST)) {
                    _pipelogger.finest("JxtaBiDiPipe pipe # " + i + " created");
                }
                if(i == 0) {
                    JxtaSenderPipeManager.createInstance().setHealthPipeWrapper(pipeWrapper);
                } else {
                    pipeWrappers.add(pipeWrapper);
                }
            } catch (IOException ex) {
                //FIXME
            }
        }
        if (_pipelogger.isLoggable(Level.FINEST)) {
            _pipelogger.finest("sender pipe pool about to be initialized");
        }
        JxtaSenderPipeManager.createInstance().initPipePool(pipeWrappers);
        if (_pipelogger.isLoggable(Level.FINEST)) {
            _pipelogger.finest("sender pipe pool initialized");
        }
    }
   
    private PipeConnectionResult connectPipeWithRetries(JxtaBiDiPipe aPipe, PipeWrapper pipeWrapper) {
        return connectPipeWithRetries(aPipe, pipeWrapper, this.pipeAdv, this.peerID);
    }    
   
    private PipeConnectionResult connectPipeWithRetries(JxtaBiDiPipe aPipe,
            PipeWrapper pipeWrapper, PipeAdvertisement pipeAdvertisement, PeerID partnerPeerId) {
        PipeConnectionResult result = new PipeConnectionResult(pipeWrapper);
        JxtaConnectErrorManager anErrorMgr = getErrorManager();
        try {
            anErrorMgr.txStart();
            while ( ! anErrorMgr.isTxCompleted()  && isAttemptingConnection() && ! ReplicationHealthChecker.isStopping() ) {                
                try {                  
                    if (_pipelogger.isLoggable(Level.FINE)) {
                        _pipelogger.fine("calling aPipe.connect for name: " + pipeWrapper.getName());
                    }
                    //boolean isPipeOk = healthChecker.doPipeTest(pipeWrapper););
                    long startTime = System.currentTimeMillis();
                    aPipe.connect(this.netPeerGroup,
                            null,                           
                            pipeAdvertisement, //was this.pipeAdv,
                            //60000,
                            //300000,
                            30000,
                            // register as a message listener the pipeWrapper
                            pipeWrapper);
                    aPipe.setPipeEventListener(pipeWrapper);
                    result.setConnected(true);
                    if (_pipelogger.isLoggable(Level.FINE)) {
                        _pipelogger.fine("Pipe connected to: " + this.getReplicateToInstanceName() + "name: " + pipeWrapper.getName());
                    }
                //boolean isPipeOk = healthChecker.doPipeTest(pipeWrapper);
                //System.out.println("PipeWrapper: " + pipeWrapper.getName() + " ok: " + isPipeOk);
                //try {
                //    synchronized(pipeWrapper) {
                //        pipeWrapper.wait(10000L);
                //    }                                              
                //} catch (Exception ex) {
                //    ;
                //}
                //System.out.println("PipeWrapper: " + pipeWrapper.getName() + " HC_ack_recd: " + pipeWrapper.hasReceivedHCMessage());
                //System.out.println("connect for " + pipeWrapper.getName() + " took: " + (System.currentTimeMillis() - startTime) + " ms");
                /*
                if(!pipeWrapper.hasReceivedHCMessage()) {
                    throw new IOException();
                }
                 */
                    anErrorMgr.txEnd();
                   
                } catch (SocketTimeoutException e) {
                    if (_pipelogger.isLoggable(Level.FINE)) {
                        _pipelogger.log(Level.FINE, "SocketTimeoutException during call to aPipe.connect", e);
                    }
                    //handle SocketTimeoutException
                    result.setConnected(false);
                    anErrorMgr.checkError(e);
                } catch (IOException e1) {
                    if (_pipelogger.isLoggable(Level.FINE)) {
                        _pipelogger.log(Level.FINE, "calling aPipe.connect - IOException", e1);
                    }
                    //handle IOException
                    result.setConnected(false);
                    anErrorMgr.txEnd();
                } catch (Exception e2) {
                    if (_pipelogger.isLoggable(Level.FINE)) {
                        _pipelogger.log(Level.FINE, "calling aPipe.connect - other Exception", e2);
                    }
                    //handle any other exception (e.g. during shutdown)
                    result.setConnected(false);
                    anErrorMgr.txEnd();
                }               
            }  //end while
            anErrorMgr.txEnd();
        }   //end try
        catch (HATimeoutException tex) {
            // eat and log this exception
            //set pipeWrapper to null
            pipeWrapper = null;
            result.setPipeWrapper(null);
            if(_pipelogger.isLoggable(Level.FINE)) {
                _pipelogger.fine("JxtaBiDiPipeWrapper connectPipeWithRetries() timed out: " + tex.getMessage());
            }
        } finally {
            anErrorMgr.txEnd();
        }       

        return result;
    }
   
    private PipeWrapper connectPipeWithRetriesLastGood(JxtaBiDiPipe aPipe, PipeWrapper pipeWrapper) {
        return connectPipeWithRetriesLastGood(aPipe, pipeWrapper, this.pipeAdv);
    }    
   
    private PipeWrapper connectPipeWithRetriesLastGood(JxtaBiDiPipe aPipe,
            PipeWrapper pipeWrapper, PipeAdvertisement pipeAdvertisement) {
        try {
            errorMgr.txStart();
            while ( ! errorMgr.isTxCompleted()  && ! ReplicationHealthChecker.isStopping() ) {                
                try {                   
                    aPipe.connect(this.netPeerGroup,
                            null,                           
                            pipeAdvertisement, //was this.pipeAdv,
                            //60000,
                            //300000,
                            15000,
                            // register as a message listener the pipeWrapper
                            pipeWrapper);
                    aPipe.setPipeEventListener(pipeWrapper);
                    System.out.println("Pipe connected to: " + this.getReplicateToInstanceName() + "name: " + pipeWrapper.getName());
                    errorMgr.txEnd();
                   
                } catch (IOException e) {
                    errorMgr.checkError(e);
                }
            }  //end while
            errorMgr.txEnd();
        }   //end try
        catch (HATimeoutException tex) {
            // eat and log this exception
            //set pipeWrapper to null
            pipeWrapper = null;
            if(_logger.isLoggable(Level.FINEST)) {
                _logger.finest("JxtaBiDiPipeWrapper connectPipeWithRetries() timed out: " + tex.getMessage());
            }
        } finally {
            errorMgr.txEnd();
        }       

        return pipeWrapper;
    }         
   
     /**
     *  create n pipes (sender) and add them to
     * JxtaSenderPipeManager pool
     *
     *@return PipeWrapper
     */   
    PipeWrapper createPipe() {
        PipeWrapper pipeWrapper = null;
        try {
            JxtaBiDiPipe aPipe = new JxtaBiDiPipe();
            aPipe.setReliable(true);
            pipeWrapper = new PipeWrapper("created_pipe", PipeWrapper.SENDER_PIPE, this.getReplicateToInstanceName(), aPipe);

            //this.waitForRendezvousConnection();
            if(_pipelogger.isLoggable(Level.FINEST)) {
                _pipelogger.finest("JxtaBiDiPipeWrapper: Attempting to establish a connection");
            }           
            aPipe.connect(this.netPeerGroup,
                            null,
                            this.pipeAdv,
                            //60000,
                            300000,
                            // register as a message listener the pipeWrapper
                            pipeWrapper);
            aPipe.setPipeEventListener(pipeWrapper);
            if (_pipelogger.isLoggable(Level.FINE)) {
                _pipelogger.fine("Pipe connected to: " + this.getReplicateToInstanceName() + "name: " + pipeWrapper.getName());
            }
            if(_pipelogger.isLoggable(Level.FINEST)) {
                _pipelogger.finest("new JxtaBiDiPipe pipe created: " + aPipe);
            }
        } catch (IOException ex) {
            //FIXME evaluate log level
            if (_pipelogger.isLoggable(Level.FINEST)) {
                _pipelogger.log(Level.FINEST, "IOException occurred during createPipe", ex);
            }
        }
        return pipeWrapper;
    }      
   
    /**
     *  Starts jxta
     */
    private void startJxta(boolean isServer) {        
        JxtaStarter jxtaStarter = JxtaStarter.createInstance();
        jxtaStarter.startJxta(isServer);
        this.netPeerGroup = jxtaStarter.getNetPeerGroup();
        RendezVousService theRendezvous = jxtaStarter.getRendezvous();
        if(theRendezvous != null) {
            theRendezvous.addListener(this);
        }
    }
   
    /**
     *  This is the PipeListener interface. Expect a call to this method
     *  When a message is received.
     *  when we get a message, print out the message on the console
     *
     *@param  event  message event
     */
    public void pipeMsgEvent(PipeMsgEvent event) {
        if(_logger.isLoggable(Level.FINEST)) {
            _logger.finest("JxtaBiDiPipeWrapper>>pipeMsgEvent");
        }
        Message msg = null;
        try {
            // grab the message from the event
            msg = event.getMessage();
            if(_logger.isLoggable(Level.FINEST)) {
                _logger.finest("JxtaBiDiPipeWrapper>>pipeMsgEvent:msg=" + msg);
            }          
            if (msg == null) {
                if(_logger.isLoggable(Level.FINEST)) {
                    _logger.finest("Received an empty message, returning");
                }
                return;
            }

            // get the message element named SenderMessage
            MessageElement msgElement = msg.getMessageElement(SenderMessage, SenderMessage);
            MessageElement idMsgElement = msg.getMessageElement(MESSAGE_ID, MESSAGE_ID);
            if(msgElement != null) {
                if(_logger.isLoggable(Level.FINEST)) {
                    _logger.finest("msgElement=" + msgElement.toString());
                }               
            }
            if(idMsgElement != null) {
                if(_logger.isLoggable(Level.FINEST)) {
                    _logger.finest("idMsgElement=" + idMsgElement.toString());
                }                
            }           

            // Get message
            if (msgElement != null) {
                this.processStartupMessage(msg, msgElement);
            } else {
                if (idMsgElement != null) {
                    this.processIdMessage(msg, idMsgElement);
                } else {
                    //this shouldn't happen
                }
            }
        } catch (Exception e) {
            if(_logger.isLoggable(Level.FINEST)) {
                _logger.log(Level.FINEST, "pipeMsgEvent", e);
            }            
            return;
        }
    }
   
    private void processStartupMessage(Message msg, MessageElement msgElement) {
        // Get message
        if (msgElement.toString() == null) {
            if(_logger.isLoggable(Level.FINEST)) {
                _logger.finest("null msg received");
            }            
        } else {
            /*
            if (_logger.isLoggable(Level.FINE)) {
                _logger.fine("Message  :"+ msgElement.toString());
            }
           
            //send back response if it isn't already a response
            if( !(msgElement.toString()).startsWith("RETURN_MSG_COMMAND")) {
                Message returnMsg = new Message();
                String returnData = "ReturnMessage  :"+ msgElement.toString();
                returnMsg.addMessageElement(SenderMessage,
                                      new StringMessageElement(SenderMessage,
                                                               returnData,
                                                               null));
                if (_logger.isLoggable(Level.FINE)) {
                     _logger.fine("SendingResponse :" + returnData);
                }

                //pipe.sendMessage(returnMsg);
                this.sendMessage(returnMsg);
            }

            //end send back response
             */
            count ++;
        }
    }
   
    private void processIdMessage(Message msg, MessageElement idMsgElement) {
        if (idMsgElement.toString() == null) {
            if(_logger.isLoggable(Level.FINEST)) {
                _logger.finest("null msg received");
            }             
        } else {
            if(_logger.isLoggable(Level.FINEST)) {
                _logger.finest("ID Message :"+ idMsgElement.toString());
            }             
            ReplicationState state = this.createReplicationState(msg);

            if(_logger.isLoggable(Level.FINEST)) {
                _logger.finest("ID Message is response: " + state.isReturnMessage());
            }            
            if ( !state.isReturnMessage() ) {   
                //can do it here more quickly but for now comment out
                //this.sendResponse(msg);
            } else {
                //this is an incoming response
                //this is done elsewhere take out after testing
                //this.processIdMessageResponse(state);
            }
            this.finishProcessIdMessage(state);
        }       
    }
   
    private void sendMessage(Message msg) {
        JxtaReplicationSender jxtaReplicationSender =
            JxtaReplicationSender.createInstance();
        jxtaReplicationSender.sendOverPipe(msg);
    }
   
    private void sendResponse(Message msg) {
        Message responseMsg =
            this.alterIncomingMessageToResponse(msg);
        this.sendMessage(responseMsg);
    }
   
    private Message alterIncomingMessageToResponse(Message msg) {
        msg.replaceMessageElement(MESSAGE_COMMAND,
                              new StringMessageElement(MESSAGE_COMMAND,
                                                       RETURN_MSG_COMMAND,
                                                       null));
        return msg;
    }
   
    private ReplicationState createReplicationState(Message msg) {
        return ReplicationState.createReplicationState(msg);
    }
   
    private void finishProcessIdMessage(ReplicationState state) {
        JxtaReplicationReceiver receiver =
            JxtaReplicationReceiver.createInstance();
        receiver.processMessage(state);
    }      
   
    /**
     *  stop
     *
     */
    public void stop() {
        if(stopped) {
            return;
        }
        stopped = true;
        //flush caches during shutdown
        //repairOnCurrentThread();
        //no log message here
        ReplicationHealthChecker.setStopping(true);
        if(_pipelogger.isLoggable(Level.FINEST)) {
            _pipelogger.finest("JxtaBiDiPipeWrapper-stop() method");
        }
        try {
            JxtaReplicationSender.createInstance().stop();
        } catch (LifecycleException ex) {
            ;
        }
        closePipes();
        closeHealthPipes();
        closePropagatedPipes();
        ReplicationResponseRepository.getInstance().stop();       
        //we are stopped
        if(_pipelogger.isLoggable(Level.FINEST)) {
            _pipelogger.finest("JxtaBiDiPipeWrapper:stop() complete");
        }              
        //FIXME is this needed??
        synchronized(completeLock) {
            completeLock.notify();
        }       
    }
   
    public void closePipes() {
        JxtaSenderPipeManager pipeMgr
            = JxtaSenderPipeManager.createInstance();
        pipeMgr.closePooledPipes();
    }

    /**
     *  closeNonPropagatedSenderConnections
     *
     */   
    private void closeNonPropagatedSenderConnections() {
        closePipes();
        closeSenderHealthPipe();      
    }
   
    /**
     *  closeConnections
     *
     */
    public void closeConnections() {
        if(_pipelogger.isLoggable(Level.FINEST)) {
            _pipelogger.finest("JxtaBiDiPipeWrapper-closeConnections() method");
        }     
        this.stop();
    }
   
    /**
     *  restart
     *
     *@param  args  command line args
     */
    public void restart() {
        if(ReplicationHealthChecker.isStopping()) {
            return;
        }
        if(_pipelogger.isLoggable(Level.FINEST)) {
            _pipelogger.finest("JxtaBiDiPipeWrapper-restart() method");
        }       
        String newPartnerInstance = this.getReplicateToInstanceName();
        closeConnections();
        //this.startJxta(false);

        try {
            String value = System.getProperty("RDVWAIT", "false");
            this.waitForRendezvous = Boolean.valueOf(value).booleanValue();

            this.pipeAdv = JxtaUtil.getPipeAdvertisement(newPartnerInstance);
            this.peerID = JxtaStarter.getPeerID(newPartnerInstance);
           
            /* FIXME: check later on this - comment this waiting out for now
            this.waitUntilCompleted();
            this.netPeerGroup.stopApp();
            this.netPeerGroup.unref();
             */
        } catch (Exception e) {
            // FIXME evaluate log level
            if(_pipelogger.isLoggable(Level.FINEST)) {
                _pipelogger.log(Level.FINEST, "failed to bind the JxtaBiDiPipe", e);         
            }           
        }
        // run on this thread
        //this.run();
        Thread acceptThread = new Thread(this);
        acceptThread.setDaemon(true);
        acceptThread.start();
        try {
            //might have to put a timeout on this
            acceptThread.join();
        } catch (InterruptedException ex) {}
        //now do repair
        this.repair();
       
    }
   
    /**
     *  reshape
     *
     *@param  partnerInstanceName name of failed partner
     */
    public void reshape(String partnerInstanceName) {
        ReplicationHealthChecker healthChecker
            = ReplicationHealthChecker.getInstance();
        try {
            if(ReplicationHealthChecker.isStopping()) {
                return;
            }       
            healthChecker.displayCurrentGroupMembers();
            String newPartnerInstance
                = healthChecker.getReshapeReplicateToInstanceName(partnerInstanceName);
            if(_pipelogger.isLoggable(Level.FINE)) {
                _pipelogger.fine("JxtaBiDiPipeWrapper>>reshape:newPartnerInstance: " + newPartnerInstance +
                             " currentPartnerInstance: " + this.getCurrentPartnerInstanceName() +
                             " isAttemptingConnection:" + this.isAttemptingConnection());
            }
            //these following cases means nothing to do
            if( this.isAttemptingConnection() || newPartnerInstance == null) {
                return;
            }
            if( newPartnerInstance.equalsIgnoreCase(this.getCurrentPartnerInstanceName()) ) {
                //skip connect if proposed partner is already our partner
                //and our connection tests as ok
                boolean currentPipesOk = this.areCurrentPipesOk();
                if(_pipelogger.isLoggable(Level.FINE)) {
                    _pipelogger.fine("JxtaBiDiPipeWrapper>>reshape:before reshape - currentPipesOk = " + currentPipesOk);
                }
                if(currentPipesOk) {
                    return;
                }
            }           

            //not all connections; only sender side
            if(_pipelogger.isLoggable(Level.FINE)) {
                _pipelogger.fine("JxtaBiDiPipeWrapper>>reshape:beforeConnectToInstance:newPartnerInstance: " + newPartnerInstance +
                             " currentPartnerInstance: " + this.getCurrentPartnerInstanceName());
            }
            //we are re-establishing connections so must turn off replication
            ReplicationHealthChecker.setReplicationCommunicationOperational(false, true);
           
            closeNonPropagatedSenderConnectionsAndConnectToInstance(newPartnerInstance);

            if(_pipelogger.isLoggable(Level.FINE)) {
                _pipelogger.fine("JxtaBiDiPipeWrapper:end of reshape: new partner=" + getCurrentPartnerInstanceName());
            }
        } finally {
            resetSenderReconnectFlag();
        }
    }
   
    void resetSenderReconnectFlag() {
        JxtaReplicationSender sender
            = JxtaReplicationSender.createInstance();
        sender.confirmReconnectCompleted();
    }   
   
    /**
     *  respondToFailure
     *
     *@param  failedPartnerInstance name of failed instance
     * may or may not be our partner
     */
    public void respondToFailure(String failedPartnerInstance) {
        JxtaSenderPipeManager senderPipeMgr
            = JxtaSenderPipeManager.createInstance();
        if(!senderPipeMgr.isOurPartnerInstance(failedPartnerInstance)) {
            return;
        }
        this.reshape(failedPartnerInstance);
    }
   
    /**
     *  respondToFailure
     *
     *@param  failedPartnerInstance name of failed instance
     * may or may not be our partner
     *@param force will force a reshape
     */
    public void respondToFailure(String failedPartnerInstance, boolean force) {
        if(!force) {
            JxtaSenderPipeManager senderPipeMgr
                = JxtaSenderPipeManager.createInstance();
            if(!senderPipeMgr.isOurPartnerInstance(failedPartnerInstance)) {
                return;
            }
        }
        this.reshape(failedPartnerInstance);
    }
   
    private void sendNetworkPartitionAdvisory(String instanceName) {   
        ///send purge advisory for owningInstanceName
        String theCommand = MESSAGE_BROADCAST_NETWORK_PARTITION_ADVISORY;
        ReplicationState networkPartitionAdvisoryState =
                ReplicationState.createBroadcastNetworkPartitionAdvisoryState(
                "mode"//mode does not matter here
                "networkpartition", //id does not matter here
                "networkpartition", //appid does not matter here
                0L,
                getInstanceName(), //this instance is the owning instance
                getInstanceName());        
        JxtaReplicationSender sender
            = JxtaReplicationSender.createInstance();
        sender.sendOverPropagatedPipe(networkPartitionAdvisoryState, instanceName, false);

    }    
   
    /**
     *  connectToNew
     *
     *@param  newPartnerInstance name of new partner
     *@param formerlyPartitionedInstance was the new partner formerly network partitioned
     */
    public void connectToNew(String newPartnerInstance, boolean formerlyPartitionedInstance) {
        ReplicationHealthChecker healthChecker
            = ReplicationHealthChecker.getInstance();
        /*
        if(ReplicationHealthChecker.isStopping() || !isAlone()) {
            return;
        }
         */
        if(_pipelogger.isLoggable(Level.FINE)) {
            _pipelogger.fine("JxtaBiDiPipeWrapper>>connectToNew:thisInstance = " + this.getInstanceName() +
                         " newPartnerInstance = " + newPartnerInstance +
                         " currentPartnerInstance = " + this.getCurrentPartnerInstanceName() +
                         " isStopping = " + ReplicationHealthChecker.isStopping());
        }
        if(ReplicationHealthChecker.isStopping()) {
            return;
        }
        //FIXME remove after test moved into isBetterReplicationPartner method
        //and stop or improve the check for same partner
        /*
        if( newPartnerInstance == null || newPartnerInstance.equalsIgnoreCase(this.getCurrentPartnerInstanceName()) ) {
            return;
        }
         */       
        //this following case means nothing to do
        if(!isBetterReplicationPartner(newPartnerInstance)) {
            return;
        }
        //send network partition advisory if partner was formerly partitioned
        if(formerlyPartitionedInstance) {
            if(_pipelogger.isLoggable(Level.FINE)) {
                _pipelogger.fine("JxtaBiDiPipeWrapper>>sendNetworkPartitionAdvisory to rejoining instance " + newPartnerInstance);
            }
            sendNetworkPartitionAdvisory(newPartnerInstance);
        }
        boolean currentPartnerHealthy = this.areCurrentPipesOk();
        if(_pipelogger.isLoggable(Level.FINE)) {
            _pipelogger.fine("JxtaBiDiPipeWrapper>>connectToNew:before reconnect - currentPartnerHealthy = " +
                    currentPartnerHealthy);
        }
        healthChecker.displayCurrentGroupMembers();
        //need to interrupt waiting
        if(_pipelogger.isLoggable(Level.FINE)) {
            _pipelogger.fine("JxtaBiDiPipeWrapper>>connectToNew:isAttemptingConnection = " + isAttemptingConnection());
        }
        if(isAttemptingConnection()) {
            //not all connections; only sender side
            //must use force reconnect to insure old connections get torn down
            //correctly
            interruptConnectionAttempt();
            closeNonPropagatedSenderConnectionsAndConnectToInstance(newPartnerInstance, true);
        } else {
            //not all connections; only sender side
            closeNonPropagatedSenderConnectionsAndConnectToInstance(newPartnerInstance);
        }
        /* FIXME was next 2 lines - needed to synchronize them
        closeNonPropagatedSenderConnections();
        connectToInstance(newPartnerInstance);
         */
        if(_pipelogger.isLoggable(Level.FINE)) {
            _pipelogger.fine("JxtaBiDiPipeWrapper:end of connectToNew: new partner=" + getCurrentPartnerInstanceName());
        }
        //FIXME remove after test
        currentPartnerHealthy = this.areCurrentPipesOk();
        if(_pipelogger.isLoggable(Level.FINE)) {
            _pipelogger.fine("JxtaBiDiPipeWrapper>>connectToNew:after reconnect - currentPartnerHealthy = " + currentPartnerHealthy);
        }
        //FIXME end remove after test
    }
   
    private synchronized void closeNonPropagatedSenderConnectionsAndConnectToInstance(String newPartnerInstance) {
        closeNonPropagatedSenderConnectionsAndConnectToInstance(newPartnerInstance, false);
    }   
   
    private synchronized void closeNonPropagatedSenderConnectionsAndConnectToInstance(String newPartnerInstance, boolean forceReconnect) {
        if(_pipelogger.isLoggable(Level.FINE)) {
            _pipelogger.fine("JxtaBiDiPipeWrapper>>closeNonPropagatedSenderConnectionsAndConnectToInstance:forceReconnect:" + forceReconnect);
        }
        // first check if proposed connections already exist and are good
        if(!forceReconnect) {
            if(checkIfProposedConnectionAlreadyOk(newPartnerInstance)) {
                if(_pipelogger.isLoggable(Level.FINE)) {
                    _pipelogger.fine("JxtaBiDiPipeWrapper>>closeNonPropagatedSenderConnectionsAndConnectToInstance:connections already good returning for: " + newPartnerInstance);
                }
                return;
            }
        }
        if(_pipelogger.isLoggable(Level.FINE)) {
            _pipelogger.fine("JxtaBiDiPipeWrapper>>closeNonPropagatedSenderConnectionsAndConnectToInstance:doing close and connect for: " + newPartnerInstance);
        }
        ReplicationHealthChecker.setReplicationCommunicationOperational(false, true);
        closeNonPropagatedSenderConnections();
        connectToInstance(newPartnerInstance);
    }
   
    boolean checkIfProposedConnectionAlreadyOk(String newPartnerInstance) {
        String currentPartnerInstance = this.getCurrentPartnerInstanceName();
        if(_pipelogger.isLoggable(Level.FINE)) {
            _pipelogger.fine("JxtaBiDiPipeWrapper>>checkIfProposedConnectionAlreadyOk: " + newPartnerInstance +
                         " currentPartnerInstance: " + currentPartnerInstance);
        }
        //check if we are already connected ok to newPartnerInstance
        if(currentPartnerInstance != null && currentPartnerInstance.equalsIgnoreCase(newPartnerInstance)) {
            //skip connect if proposed partner is already our partner
            //and our connection tests as ok
            boolean currentPipesOk = this.areCurrentPipesOk();
            if(_pipelogger.isLoggable(Level.FINE)) {
                _pipelogger.fine("JxtaBiDiPipeWrapper>>checkIfProposedConnectionAlreadyOk: - currentPipesOk = " + currentPipesOk);
            }
            return(currentPipesOk);
        } else {
            return false;
        }
    }
   
    boolean areAllCurrentPipesOk() {
        JxtaSenderPipeManager senderPipeManager
            = JxtaSenderPipeManager.createInstance();
        boolean result = senderPipeManager.testPooledPipes();
        String currentInstanceName = this.getInstanceName();
        String currentPartnerInstanceName = this.getCurrentPartnerInstanceName();
        if (_pipelogger.isLoggable(Level.FINE)) {
            _pipelogger.fine("JJxtaBiDiPipeWrapper>>areAllCurrentPipesOk from: " + currentInstanceName + " to: " + currentPartnerInstanceName + ": " + result);
        }
        return result;
    }   
   
    boolean areCurrentPipesOk() {
        ReplicationHealthChecker healthChecker
            = ReplicationHealthChecker.getInstance();
        String currentInstanceName = this.getInstanceName();
        String currentPartnerInstanceName = this.getCurrentPartnerInstanceName();
        boolean currentPartnerHealthy = healthChecker.doPipeTest();
        if(_pipelogger.isLoggable(Level.FINE)) {
            _pipelogger.fine("JxtaBiDiPipeWrapper>>areCurrentPipesOk from: " + currentInstanceName + " to: " + currentPartnerInstanceName + ": " + currentPartnerHealthy);       
        }
        if(currentPartnerHealthy) {
            ReplicationHealthChecker.setReplicationCommunicationOperational(true);
        }        
        return currentPartnerHealthy;
    }
   
    private boolean connectToInstance(String newPartnerInstance) {
        return connectToInstance(newPartnerInstance, true);
    }
   
    private boolean connectToInstance(String newPartnerInstance, boolean repairNeeded) {
        String currentPartnerInstance = this.getCurrentPartnerInstanceName();
        if(_pipelogger.isLoggable(Level.FINE)) {
            _pipelogger.fine("JxtaBiDiPipeWrapper>>connectToInstance: " + newPartnerInstance +
                         " currentPartnerInstance: " + currentPartnerInstance);
        }

        JxtaReplicationSender sender = JxtaReplicationSender.createInstance();

        //check if we are already connected ok to newPartnerInstance
        if(currentPartnerInstance != null && currentPartnerInstance.equalsIgnoreCase(newPartnerInstance)) {
            //skip connect if proposed partner is already our partner
            //and our connection tests as ok
            boolean currentPipesOk = this.areCurrentPipesOk();
            if(_pipelogger.isLoggable(Level.FINE)) {
                _pipelogger.fine("JxtaBiDiPipeWrapper>>connectToInstance:before connect - currentPipesOk = " + currentPipesOk);
            }   
            if(currentPipesOk) {
                ReplicationHealthChecker.setReplicationCommunicationOperational(true);
                sender.confirmReconnectCompleted();
                return true;
            }           
        }
       
        boolean reshapeSuccessful = false;
        try {
            String value = System.getProperty("RDVWAIT", "false");
            this.waitForRendezvous = Boolean.valueOf(value).booleanValue();
            PipeAdvertisement pipeAdvertisement = JxtaUtil.getPipeAdvertisement(newPartnerInstance);
            if(_pipelogger.isLoggable(Level.FINE)) {
                _pipelogger.fine("pipeAdvertisement for: " + newPartnerInstance + " is: " + pipeAdvertisement +
                             " this.pipeAdv: " + this.pipeAdv);
            }
            int numPipes = this.getNumberOfPipes();
            long startTime = 0L;
            if(_pipelogger.isLoggable(Level.FINE)) {
                _pipelogger.fine("JxtaBiDiPipeWrapper>>connectToInstance-numPipes=" + numPipes +
                             " reshape pipeAdv=" + pipeAdvertisement);
                startTime = System.currentTimeMillis();
            }          
            setAttemptingConnection(true);          
            reshapeSuccessful = createPipes(numPipes, pipeAdvertisement, newPartnerInstance);         
            //want to bail out immediately returning false if createPipes has failed
            //this can cause a retry
            if(!reshapeSuccessful) {
                // Early return bypasses following invariants that should be set before returning from this method.
                //setAttemptingConnection(false);
                //ReplicationHealthChecker.setReplicationCommunicationOperational(reshapeSuccessful);
                return false;
            }           
            setAttemptingConnection(false);           
            if(_pipelogger.isLoggable(Level.FINE)) {
                _pipelogger.fine("JxtaBiDiPipeWrapper>>createPipes took " + (System.currentTimeMillis() - startTime) + " millis");
                //_logger.fine("JxtaBiDiPipeWrapper>>connectToInstance:reshapeSuccessful=" + reshapeSuccessful);    
            }
            //initializePropagatedPipes();
            //sentTestPropagatedMessage();
           
            /* FIXME: check later on this - comment this waiting out for now
            this.waitUntilCompleted();
            this.netPeerGroup.stopApp();
            this.netPeerGroup.unref();
             */
        } catch (Exception e) {
            // FIXME evaluate log level
            if(_pipelogger.isLoggable(Level.FINEST)) {
                _pipelogger.log(Level.FINEST, "failed to bind the JxtaBiDiPipe", e);
            }
            setAttemptingConnection(false);
        }
        // run on this thread
        //this.run();
        /* no we do this in-line in this thread (above)
        Thread acceptThread = new Thread(this);
        acceptThread.setDaemon(true);
        acceptThread.start();
        try {
            //might have to put a timeout on this
            acceptThread.join();
        } catch (InterruptedException ex) {}
         */
        //now do repair if reshape successful
        ReplicationHealthChecker.setReplicationCommunicationOperational(reshapeSuccessful);
        if(currentPartnerInstance != null && currentPartnerInstance.equalsIgnoreCase(newPartnerInstance)) {
            sender.confirmReconnectCompleted();
        }       
        if(reshapeSuccessful) {
            JxtaSenderPipeManager.createInstance().verifyPipePoolHealth();
            if(repairNeeded) {
                this.repair();
                this.sendPurgeAdvisory();
            }
        }
        return reshapeSuccessful;
    }
   
    private boolean isRepairDuringFailure() {
        ServerConfigLookup lookup = new ServerConfigLookup();
        return lookup.isRepairDuringFailure();
    }   
   
    private void repair() {
        if(ReplicationHealthChecker.isStopping() || !isRepairDuringFailure()) {
            return;
        }       
        //do the repair on background thread
        Thread repairThread = new Thread(new JxtaRepair());
        repairThread.setDaemon(true);
        repairThread.start();      
    }
   
    void repairOnCurrentThread() {
        //if cluster is stopping do not proceed
        if (_pipelogger.isLoggable(Level.FINE)) {
            _pipelogger.fine("repairOnCurrentThread:will skip if ClusterStopping: " + ReplicationHealthChecker.isClusterStopping());
        }        
        if(ReplicationHealthChecker.isClusterStopping() || !isRepairDuringFailure()) {
            return;
        }
        ReplicationHealthChecker.setFlushing(true);
        ReplicationMessageRouter router = null;
        try {
             if (Globals.IS_SECURITY_ENABLED) {
                 router = (ReplicationMessageRouter)
                     AccessController.doPrivileged(
                         new PrivilegedGetReplicationMessageRouter());
             } else {
                 router = ReplicationMessageRouter.createInstance();
             }           
            router.repairApps(System.currentTimeMillis(), false);
        } finally {
            ReplicationHealthChecker.setFlushing(false);
        }
    }
   
    void sendPurgeAdvisory() {
        if(ReplicationHealthChecker.isClusterStopping() || !isRepairDuringFailure()) {
            return;
        }       
        //send purge advisory for owningInstanceName
        String theCommand = ReplicationState.MESSAGE_BROADCAST_PURGE_ADVISORY;
        ReplicationState purgeAdvisoryState =
                ReplicationState.createBroadcastPurgeState(
                "mode"//mode does not matter here
                "purge", //id does not matter here
                "purge", //appid does not matter here
                0L,
                getInstanceName(), //this instance is the owning instance
                getInstanceName());    
        JxtaReplicationSender sender
            = JxtaReplicationSender.createInstance();
        sender.sendBroadcastQuery(purgeAdvisoryState);
   
   
    private String getCurrentPartnerInstanceName() {
        JxtaSenderPipeManager jxtaSenderPipeManager
            = JxtaSenderPipeManager.createInstance();
        return jxtaSenderPipeManager.getPartnerInstanceName();
    }
   
    private boolean isOurself(String instanceName) {
        if(instanceName == null) {
            return false;
        } else {
            return instanceName.equalsIgnoreCase(this.getInstanceName());
        }
    }
   
    boolean isBetterReplicationPartner(String proposedPartnerName) {
        if(proposedPartnerName == null) {
            return false;
        }               
        String currentInstanceName = this.getInstanceName();
        String currentPartnerInstanceName = this.getCurrentPartnerInstanceName();
        SimpleInstanceArranger arranger = this.getSimpleArranger();
        return arranger.isBetterOrSameAsReplicationPartner(proposedPartnerName,
            currentPartnerInstanceName, currentInstanceName);
        /* was this above allowing reconnect to current partner
        return arranger.isBetterReplicationPartner(proposedPartnerName,
            currentPartnerInstanceName, currentInstanceName);
         */
    }
   
    /**
     *  rendezvousEvent the rendezvous event
     *  This method is called when an rendevous event occurs, this example is
     *  only interested in a connection to a rendezvous.  Waiting for a rendezvous
     *  is beneficial when trying to connect to another node beyonf the local
     *  sub-net, or where multicast is not supported.
     *
     *@param  event   rendezvousEvent
     */
    public void rendezvousEvent(RendezvousEvent event) {
        if(_logger.isLoggable(Level.FINE)) {
                _logger.fine("rendezvousEvent:event=" + event.getType());
        }
        if (event.getType() == event.RDVCONNECT ||
            event.getType() == event.RDVRECONNECT) {
            synchronized(rendezvousLock) {
                rendezvousLock.notify();
            }
        }
    }
   
    /**
     * awaits a rendezvous connection
     */
    private void waitForRendezvousConnection() {
        if (waitForRendezvous && !rendezvous.isConnectedToRendezVous()) {
            if(_logger.isLoggable(Level.FINE)) {
                _logger.fine("Waiting for Rendezvous Connection");
            }
            try {
                synchronized(rendezvousLock) {
                    rendezvousLock.wait();
                }
                if(_logger.isLoggable(Level.FINE)) {
                    _logger.fine("Connected to Rendezvous");
                }
            } catch (InterruptedException e) {
                // got our notification
            }
        }
    }
   
    private void waitUntilCompleted() {
        try {
            if(_pipelogger.isLoggable(Level.FINE)) {
                _pipelogger.fine("Waiting for Messages.");
            }
            synchronized(completeLock) {
                completeLock.wait();
            }
            pipe.close();
            if(_pipelogger.isLoggable(Level.FINE)) {
                _pipelogger.fine("Done.");
            }
        } catch (Exception e) {
            // FIXME evaluate log level
            if(_pipelogger.isLoggable(Level.FINE)) {
                _pipelogger.log(Level.FINE, "Exception occurred in waitUntilCompleted", e);
            }
        }
    }
   
   
}
TOP

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

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.