/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2000-2010 Oracle and/or its affiliates. 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_1_1.html
* or packager/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 packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [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.
*/
/*
* @(#)InfoRequestHandler.java 1.11 06/28/07
*/
package com.sun.messaging.jmq.jmsserver.data.handlers;
import java.util.*;
import java.io.*;
import com.sun.messaging.jmq.jmsserver.data.PacketHandler;
import com.sun.messaging.jmq.util.log.Logger;
import com.sun.messaging.jmq.util.DestType;
import com.sun.messaging.jmq.io.*;
import com.sun.messaging.jmq.jmsserver.Globals;
import com.sun.messaging.jmq.jmsserver.core.DestinationUID;
import com.sun.messaging.jmq.jmsserver.resources.BrokerResources;
import com.sun.messaging.jmq.jmsserver.util.BrokerException;
import com.sun.messaging.jmq.jmsserver.cluster.*;
import com.sun.messaging.jmq.jmsserver.service.imq.IMQConnection;
import com.sun.messaging.jmq.jmsserver.service.ConsumerInfoNotifyManager;
/**
* Handler class which deals with the INFO_REQUEST message
* sent by a client after failover.
*/
public class InfoRequestHandler extends PacketHandler
{
private Logger logger = Globals.getLogger();
private BrokerResources rb = Globals.getBrokerResources();
public InfoRequestHandler()
{
}
public static final int REQUEST_STATUS_INFO = 1;
public static final int REQUEST_CLUSTER_INFO = 2;
public static final int REQUEST_CONSUMER_INFO = 3;
/**
* Method to handle INFO_REQUEST messages
*/
public boolean handle(IMQConnection con, Packet msg)
throws BrokerException
{
Hashtable pktprops = null;
try {
pktprops = msg.getProperties();
} catch (Exception ex) {
logger.log(Logger.INFO,"Internal Error: error "
+ " retrieving properties from INFO_REQUEST message ", ex);
pktprops = new Hashtable();
}
Integer level = (Integer)pktprops.get("JMQRequestType");
if (level == null) {
logger.log(logger.INFO,"No JMQRequestType set ");
level = new Integer(-1); //pick and invalid value
}
if (level.intValue() == REQUEST_CONSUMER_INFO) {
String destName = (String)pktprops.get("JMQDestination");
int destType = ((Integer)pktprops.get("JMQDestType")).intValue();
Boolean offb = (Boolean)pktprops.get("JMQRequestOff");
boolean off = (offb == null ? false:offb.booleanValue());
DestinationUID duid = DestinationUID.getUID(destName, destType);
if (off) {
con.removeConsumerInfoRequest(duid);
} else {
con.addConsumerInfoRequest(duid);
}
ConsumerInfoNotifyManager cm = Globals.getConnectionManager().
getConsumerInfoNotifyManager();
cm.consumerInfoRequested(con, duid, destType);
return true;
}
sendInfoPacket(level.intValue(), con, msg.getConsumerID());
return true;
}
// used by other method to get the INFO packet
public static void sendInfoPacket(int requestType, IMQConnection con, long consumerUID) {
Logger logger = Globals.getLogger();
ClusterManager cfg = Globals.getClusterManager();
String reason = null;
int status = Status.OK;
Packet pkt = new Packet(con.useDirectBuffers());
pkt.setPacketType(PacketType.INFO);
pkt.setConsumerID(consumerUID);
Hashtable replyprops = new Hashtable();
Hashtable bodyProperties = null;
if (cfg == null) {
status = Status.ERROR;
reason = "Internal Error: NOT VALID CLUSTER ";
logger.log(Logger.INFO,reason);
} else if (requestType == REQUEST_STATUS_INFO) {
ClusteredBroker cb = cfg.getLocalBroker();
// OK, set properties
bodyProperties = getInfo(cb);
try {
if (cb.getState() == BrokerState.SHUTDOWN_STARTED) {
long timeout = Globals.getBrokerStateHandler()
.getShutdownRemaining();
bodyProperties.put("ShutdownMS", new Long(timeout));
}
} catch (BrokerException ex) {
logger.logStack(Logger.INFO,"Internal Error: setting timeout ", ex);
}
} else if (requestType == REQUEST_CLUSTER_INFO) {
bodyProperties = getAllInfo();
} else {
status = Status.BAD_REQUEST;
reason = "Internal Error: Bad JMQRequestType set " + requestType;
logger.log(Logger.INFO,reason);
}
//XXX - TBD
// should we write out the contents in a less intensive way
// (e.g. use the same format used for properties)
// or just serialize Hashtable (which is whay we are doing now)
//
String list = null;
if (cfg != null) {
Iterator itr = cfg.getKnownBrokers(true);
Set s = new HashSet();
// ok get rid of dups
while (itr.hasNext()) {
ClusteredBroker cb = (ClusteredBroker)itr.next();
s.add(cb.getBrokerURL().toString());
}
// OK .. now convert to a string
itr = s.iterator();
while (itr.hasNext()) {
if (list == null) {
list = itr.next().toString();
} else {
list += "," + itr.next().toString();
}
}
if (list != null) {
replyprops.put("JMQBrokerList", list);
}
}
if (bodyProperties != null) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(bodyProperties);
oos.flush();
bos.flush();
pkt.setMessageBody(bos.toByteArray());
bos.close();
} catch (Exception ex) {
logger.log(Logger.WARNING,"XXX-L10N Internal Error "
+ " sending back broker data", ex);
}
}
// OK deal with properties, etc
replyprops.put("JMQRequestType", new Integer(requestType));
replyprops.put("JMQStatus", new Integer(status));
if (reason != null) {
replyprops.put("JMQReason", reason);
}
pkt.setProperties(replyprops);
con.sendControlMessage(pkt);
}
static Hashtable getAllInfo() {
ClusterManager cfg = Globals.getClusterManager();
if (cfg == null) return null;
Iterator itr = cfg.getKnownBrokers(true);
Hashtable ht = new Hashtable();
String nameList = "";
while (itr.hasNext()) {
ClusteredBroker bc = (ClusteredBroker)itr.next();
if (nameList.length() == 0) {
nameList = bc.getBrokerName();
} else {
nameList += ","+bc.getBrokerName();
}
ht.put(bc.getBrokerName(), getInfo(bc));
}
ht.put("BrokerIDs", nameList);
return ht;
}
static Hashtable getInfo(ClusteredBroker bc)
{
BrokerState state = null;
Logger logger = Globals.getLogger();
ClusterManager cfg = Globals.getClusterManager();
try {
state = bc.getState();
} catch (BrokerException ex) {
logger.log(Logger.INFO,"L10N-XXX Internal Error "
+ " unable to retrieve state", ex);
state = BrokerState.INITIALIZING;
}
Hashtable ht = new Hashtable();
ht.put("BrokerID", bc.getBrokerName());
ht.put("brokerURL", bc.getBrokerURL().toString());
ht.put("State", new Integer( mapStateToInt(state) ));
ht.put("StateString", state.toString());
ht.put("isLocal", Boolean.valueOf( bc.isLocalBroker()));
return ht;
}
static final int INITIALIZING = 1;
static final int RUNNING = 2;
static final int QUIESCE_STARTED = 3;
static final int QUIESCE_COMPLETE = 4;
static final int FAILOVER_STARTED = 5;
static final int FAILOVER_COMPLETE = 6;
static final int SHUTDOWN_STARTED = 7;
static final int SHUTDOWN_COMPLETE = 8;
static int mapStateToInt(BrokerState state)
{
if (state == BrokerState.INITIALIZING) {
return INITIALIZING;
} else if (state == BrokerState.OPERATING) {
return RUNNING;
} else if (state == BrokerState.QUIESCE_STARTED) {
return QUIESCE_STARTED;
} else if (state == BrokerState.QUIESCE_COMPLETED) {
return QUIESCE_COMPLETE;
} else if (state == BrokerState.SHUTDOWN_STARTED) {
return SHUTDOWN_STARTED;
} else if (state == BrokerState.SHUTDOWN_FAILOVER) {
return SHUTDOWN_COMPLETE;
} else if (state == BrokerState.SHUTDOWN_COMPLETE) {
return SHUTDOWN_COMPLETE;
} else if (state == BrokerState.FAILOVER_PENDING) {
return FAILOVER_STARTED;
} else if (state == BrokerState.FAILOVER_STARTED) {
return FAILOVER_STARTED;
} else if (state == BrokerState.FAILOVER_COMPLETE) {
return FAILOVER_COMPLETE;
} else if (state == BrokerState.FAILOVER_FAILED) {
return FAILOVER_COMPLETE;
}
return 0;
}
}