/*
* 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.
*/
/*
*InputPipeWrapper.java
*
* Created on March 22, 2006, 12:02 PM
*
*/
package com.sun.enterprise.ee.web.sessmgmt;
import java.io.IOException;
import java.security.AccessController;
import java.util.logging.Logger;
import java.util.logging.Level;
import com.sun.logging.LogDomains;
import com.sun.enterprise.web.ServerConfigLookup;
import org.apache.catalina.Globals;
import java.util.List;
import net.jxta.document.AdvertisementFactory;
import net.jxta.document.StructuredDocumentFactory;
import net.jxta.document.XMLDocument;
import net.jxta.endpoint.Message;
import net.jxta.endpoint.MessageElement;
import net.jxta.pipe.InputPipe;
import net.jxta.pipe.PipeMsgEvent;
import net.jxta.pipe.PipeMsgListener;
import net.jxta.protocol.RouteAdvertisement;
/**
*
* @author Larry White
*/
public class InputPipeWrapper extends AbstractPipeWrapper implements PipeMsgListener {
private final static String InstanceNameMessage
= ReplicationState.InstanceNameMessage;
private final static String ReadyMessage
= ReplicationState.ReadyMessage;
private final static String MESSAGE_MODE =
ReplicationState.MESSAGE_MODE;
private final static String BULK_MESSAGE_MODE =
ReplicationState.BULK_MESSAGE_MODE;
private final static String MESSAGE_ID
= ReplicationState.MESSAGE_ID;
private final static String MESSAGE_COMMAND
= ReplicationState.MESSAGE_COMMAND;
private final static String MESSAGE_BROADCAST_QUERY
= ReplicationState.MESSAGE_BROADCAST_QUERY;
private final static String RETURN_BROADCAST_MSG_COMMAND
= ReplicationState.RETURN_BROADCAST_MSG_COMMAND;
private final static String MESSAGE_BROADCAST_LOAD_RECEIVED
= ReplicationState.MESSAGE_BROADCAST_LOAD_RECEIVED;
private final static String MESSAGE_READY
= ReplicationState.MESSAGE_READY;
private final static Level TRACE_LEVEL = Level.FINE;
public final static String MESSAGE_SEND_START_TIME =
ReplicationState.MESSAGE_SEND_START_TIME;
private static final Logger _logger = LogDomains.getLogger(LogDomains.WEB_LOGGER);
private static final Logger _pipelogger = ReplicationUtil.getPipeLogger();
/**
* Creates a new instance of InputPipeWrapper
*/
public InputPipeWrapper() {
}
/** Creates a new instance of InputPipeWrapper */
public InputPipeWrapper(String name, InputPipe pipe) {
_name = name;
_pipe = pipe;
}
/**
* 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
* all incoming messages must have an InstanceNameMessage element
*@param event message event
*/
public void pipeMsgEvent(PipeMsgEvent event) {
Message msg = null;
try {
// grab the message from the event
msg = event.getMessage();
//displayKeyMessageElements(msg);
if (msg == null) {
if (_logger.isLoggable(Level.FINEST)) {
_logger.finest("Received an empty message, returning");
}
return;
}
ReplicationUtil repUtil = ReplicationUtil.createReplicationUtil();
if (repUtil.isInstanceLoadBalancedByCLB()) {
MessageProcessor.getInstance().pipeMsgEvent(event, null);
return;
}
// get the message element named InstanceNameMessage
MessageElement instanceNameMsgElement =
msg.getMessageElement(InstanceNameMessage, InstanceNameMessage);
//ignore broadcasts from yourself
String returnInstance = null;
if(instanceNameMsgElement != null) {
returnInstance = instanceNameMsgElement.toString();
if (_logger.isLoggable(Level.FINE)) {
_logger.fine("InputPipeWrapper:incoming propagated msg from: " + returnInstance);
}
}
if(returnInstance.equalsIgnoreCase(getInstanceName())) {
return;
}
MessageElement readyMsgElement = msg.getMessageElement(ReadyMessage, ReadyMessage);
if(readyMsgElement != null) {
try {
Thread.currentThread().sleep(2000L);
} catch(InterruptedException ex) {}
if (_pipelogger.isLoggable(Level.FINE)) {
_pipelogger.fine("readyMsgElement=" + readyMsgElement.toString() + " from: " + returnInstance);
}
JoinNotificationEventHandler.checkAndDoJoinFor(returnInstance);
}
MessageElement bulkMsgElement = msg.getMessageElement(BULK_MESSAGE_MODE, BULK_MESSAGE_MODE);
if (bulkMsgElement != null) {
processBulkMessage(msg, bulkMsgElement);
return;
}
MessageElement idMsgElement = msg.getMessageElement(MESSAGE_ID, MESSAGE_ID);
if(idMsgElement != null) {
if (_logger.isLoggable(Level.FINE)) {
_logger.fine("idMsgElement=" + idMsgElement.toString());
}
}
MessageElement commandMsgElement =
msg.getMessageElement(MESSAGE_COMMAND, MESSAGE_COMMAND);
if(commandMsgElement != null) {
String theCommand = commandMsgElement.toString();
if(isBroadcastMethod(theCommand)) {
//processQueryMessage(msg, idMsgElement, returnInstance);
ReplicationMessageRouter receiver = getRouter();
ReplicationState state = createReplicationState(msg);
processQueryState(state, receiver);
}
}
} catch (Exception e) {
if (_logger.isLoggable(Level.FINEST)) {
_logger.log(Level.FINEST, "caught exception", e);
}
return;
}
}
class ReceivedMessageWrapper
implements Runnable {
ReplicationMessageRouter receiver;
ReplicationState state;
ReceivedMessageWrapper(ReplicationMessageRouter receiver, ReplicationState state) {
this.receiver = receiver;
this.state = state;
}
public void run() {
try {
//handleReceivedMessage(msg);
receiver.processQueryMessage(state, state.getInstanceName());
} catch (Exception ex) {
if (_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE, "caught exception", ex);
}
}
}
}
private ReplicationMessageRouter getRouter() {
ReplicationMessageRouter receiver = null;
if (Globals.IS_SECURITY_ENABLED) {
receiver = (ReplicationMessageRouter)
AccessController.doPrivileged(
new PrivilegedGetReplicationMessageRouter());
} else {
receiver = ReplicationMessageRouter.createInstance();
}
return receiver;
}
private boolean isBroadcastMethod(String theCommand) {
ReplicationMessageRouter receiver = getRouter();
return receiver.isBroadcastMethod(theCommand);
}
private boolean isExpensiveMethod(String theCommand) {
ReplicationMessageRouter receiver = getRouter();
return receiver.isExpensiveMethod(theCommand);
}
private void displayKeyMessageElements(Message msg) {
if (_logger.isLoggable(Level.FINE)) {
_logger.fine("PropagatedPipeWrapper>>pipeMsgEvent:msg=" + msg);
}
MessageElement instanceNameMsgElement =
msg.getMessageElement(InstanceNameMessage, InstanceNameMessage);
String returnInstance = null;
if(instanceNameMsgElement != null) {
returnInstance = instanceNameMsgElement.toString();
if (_logger.isLoggable(Level.FINE) && !isMessageFromYourself(returnInstance)) {
_logger.fine("PropagatedPipeWrapper>>pipeMsgEvent:fromInstance=" + returnInstance);
}
}
MessageElement idMsgElement = msg.getMessageElement(MESSAGE_ID, MESSAGE_ID);
if(idMsgElement != null && _logger.isLoggable(Level.FINE)) {
_logger.fine("idMsgElement=" + idMsgElement.toString());
}
MessageElement commandMsgElement =
msg.getMessageElement(MESSAGE_COMMAND, MESSAGE_COMMAND);
if(commandMsgElement != null) {
String theCommand = commandMsgElement.toString();
if (_logger.isLoggable(Level.FINE)) {
_logger.fine("incoming msg to broadcast pipe:command=" + theCommand);
}
}
}
private void processQueryMessage(Message msg, MessageElement idMsgElement, String returnInstance) {
if (_logger.isLoggable(Level.FINER)) {
_logger.entering("InputPipeWrapper", "processQueryMessage", new Object[] { msg, idMsgElement, returnInstance});
}
if (idMsgElement.toString() == null) {
if (_logger.isLoggable(Level.FINE)) {
_logger.fine("null id msg received");
}
return;
}
ReplicationState state = this.createReplicationState(msg);
ReplicationMessageRouter receiver = getRouter();
receiver.processQueryMessage(state, returnInstance);
}
private ReplicationState createReplicationState(Message msg) {
ReplicationState result
= ReplicationState.createBroadcastReplicationState(msg);
//adding route advertisment to this input query state
RouteAdvertisement routeAdv = getRouteAdvertisement(msg);
result.setRouteAdvertisement(routeAdv);
return result;
}
private void addRoutesTo(List<ReplicationState>states, Message msg) {
RouteAdvertisement routeAdv = getRouteAdvertisement(msg);
for(int i=0; i<states.size(); i++) {
ReplicationState nextState = states.get(i);
nextState.setRouteAdvertisement(routeAdv);
}
}
//begin unicast code
private static final String NAMESPACE = ReplicationState.NAMESPACE;
private static final String ROUTEADV = ReplicationState.ROUTEADV;
RouteAdvertisement getRouteAdvertisement(Message msg) {
RouteAdvertisement routeAdv = null;
MessageElement routeElement = msg.getMessageElement(NAMESPACE, ROUTEADV);
if(routeElement != null) {
try {
XMLDocument asDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(
routeElement.getMimeType(), routeElement.getStream());
routeAdv = (RouteAdvertisement)
AdvertisementFactory.newAdvertisement(asDoc);
} catch (IOException io) {
io.printStackTrace();
}
}
return routeAdv;
}
//end unicast code
//begin bulk message handling
private void processBulkMessage(Message msg, MessageElement idMsgElement) {
if (_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE, ">>InputPipeWrapper: processBulkMessage...");
}
//_logger.log(Level.INFO, ">>InputPipeWrapper: processBulkMessage...");
printMessageReceiptStats(msg);
ReplicationMessageRouter receiver = getRouter();
//check if this is a return bulk message and act accordingly
//System.out.println("<<processBulkMessage:isVoidReturnMessage=" + ReplicationState.isVoidMethodReturnMessage(msg));
//System.out.println("<<processBulkMessage:isAckRequiredForMessage=" + ReplicationState.isAckRequiredForMessage(msg));
//System.out.println("<<processBulkMessage:isResponseMessage=" + ReplicationState.isResponseMessage(msg));
/*
* no acks here so leaving this out
if(!ReplicationState.isAckRequiredForMessage(msg)
&& !ReplicationState.isVoidMethodReturnMessage(msg)
&& ReplicationState.isResponseMessage(msg)) {
List<String> ackIds = ReplicationState.extractAckIdsListFromMessage(msg);
//iterate and deliver acks to each id in ackIds list and return
processAcks(ackIds, receiver);
return;
}
*/
List<ReplicationState> states = ReplicationState.extractBulkReplicationStatesFromMessage(msg);
addRoutesTo(states, msg);
//send ack if required FIXME: remove after testing not sending any acks here
//this.checkSendImmediateBulkAck(msg, states);
//_logger.log(Level.INFO, ">>InputPipeWrapper: states size = " + states.size());
for (ReplicationState state : states) {
if (_logger.isLoggable(TRACE_LEVEL)) {
_logger.log(TRACE_LEVEL, "<<InputPipeWrapper: receiving id: " + state.getId() + "[ver:" + state.getVersion() + "]");
_logger.log(TRACE_LEVEL, "<<InputPipeWrapper: receiving nextState isResponse " + state.isResponseState() + " state = " + state);
}
processQueryState(state, receiver);
}
if (_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE, "<<InputPipeWrapper: processBulkMessage complete...");
}
}
private void processQueryState(ReplicationState state, ReplicationMessageRouter receiver) {
if(state.isResponseState()) {
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("InputPipeWrapper:response command = " + state.getCommand());
}
processQueryResponse(state, receiver);
} else {
processQueryNonResponse(state, receiver);
}
}
private void processQueryResponse(ReplicationState state, ReplicationMessageRouter receiver) {
if(state.getCommand() != null && state.getCommand().equalsIgnoreCase("unicastResponse")) {
receiver.processUnicastQueryResponse(state);
} else {
//this is a load response which gets processed quickly
receiver.processQueryResponse(state);
}
}
private void processQueryNonResponse(ReplicationState state, ReplicationMessageRouter receiver) {
//not a response - only use separate thread for expensive commands
if(isExpensiveMethod(state.getCommand())) {
Runnable r = new ReceivedMessageWrapper(receiver, state);
JxtaReplicationSender.executeTask(r);
} else {
receiver.processQueryMessage(state, state.getInstanceName());
}
}
private void printMessageReceiptStats(Message receivedMessage) {
if(!this.getReplicationMeasurementEnabled()) {
return;
}
int measurementInterval = this.getReplicationMeasurementInterval();
long id = -1L;
MessageElement idMsgElement =
receivedMessage.getMessageElement(MESSAGE_ID, MESSAGE_ID);
if(idMsgElement != null) {
id = (Long.decode(idMsgElement.toString())).longValue();
//System.out.println("messageReceived: bulkId = " + id);
}
if(id % measurementInterval != 0) {
return;
}
//get send start time for measurements
long sendStartTime = -1L;
MessageElement sendStartMsgElement =
receivedMessage.getMessageElement(MESSAGE_SEND_START_TIME, MESSAGE_SEND_START_TIME);
if(sendStartMsgElement != null) {
sendStartTime =
(Long.decode(sendStartMsgElement.toString())).longValue();
if(sendStartTime > 0L) {
//System.out.println("message receipt time: " + (System.currentTimeMillis() - sendStartTime));
}
}
_logger.log(Level.INFO, "messageReceiptSucceeded: bulkId = " + id + " receiptTime = "
+ (System.currentTimeMillis() - sendStartTime) + " from partner: " + getPartnerInstanceName());
}
Boolean _replicationMeasurementEnabled = null;
private boolean getReplicationMeasurementEnabled() {
if(_replicationMeasurementEnabled == null) {
ServerConfigLookup lookup = new ServerConfigLookup();
_replicationMeasurementEnabled
= new Boolean(lookup.getReplicationMeasurementEnabledFromConfig());
}
return _replicationMeasurementEnabled.booleanValue();
}
int _replicationMeasurementInterval = -1;
private int getReplicationMeasurementInterval() {
if(_replicationMeasurementInterval == -1) {
ServerConfigLookup lookup = new ServerConfigLookup();
_replicationMeasurementInterval
= lookup.getReplicationMeasurementIntervalFromConfig();
}
return _replicationMeasurementInterval;
}
private void processAcks(List<String> acksList, ReplicationMessageRouter receiver) {
//_logger.log(Level.INFO, ">>InputPipeWrapper:processAcks: acksList size = " + acksList.size());
for(int i=0; i<acksList.size(); i++) {
//_logger.log(Level.INFO,"processAcks:nextIdToAck:" + acksList.get(i));
ReplicationState nextState = new ReplicationState(acksList.get(i));
receiver.processResponse(nextState);
}
}
//end bulk message handling
public void cleanup() {
if (_pipelogger.isLoggable(Level.FINER)) {
_pipelogger.entering("InputPipeWrapper", "cleanup", _pipe);
}
if(_pipe != null) {
_pipe.close();
if (_pipelogger.isLoggable(Level.FINE)) {
_pipelogger.fine("InputPipeWrapper>>_pipe.close() called for " + _name);
}
}
_pipe = null;
_name = null;
}
void setPipe(InputPipe pipe) {
_pipe = pipe;
}
private InputPipe _pipe = null;
private String _name = null;
}