/*
* 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);
}
}
}
}