/*
* 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.
*/
/*
*/
package com.sun.messaging.jmq.jmsserver.service;
import java.util.List;
import java.util.Vector;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Iterator;
import com.sun.messaging.jmq.util.DestType;
import com.sun.messaging.jmq.jmsserver.Globals;
import com.sun.messaging.jmq.jmsserver.util.MQThread;
import com.sun.messaging.jmq.jmsserver.core.Consumer;
import com.sun.messaging.jmq.jmsserver.core.Destination;
import com.sun.messaging.jmq.jmsserver.core.DestinationUID;
import com.sun.messaging.jmq.jmsserver.core.BrokerAddress;
import com.sun.messaging.jmq.jmsserver.service.imq.IMQConnection;
import com.sun.messaging.jmq.jmsserver.resources.BrokerResources;
import com.sun.messaging.jmq.jmsserver.data.handlers.InfoRequestHandler;
import com.sun.messaging.jmq.util.log.Logger;
/**
*/
public class ConsumerInfoNotifyManager implements Runnable
{
/**
* consumer info types (protocol)
*/
private static final int CONSUMER_NOT_READY = 0;
private static final int CONSUMER_READY = 1;
private static final int CONSUMER_ALL_EVENT = -1;
private static boolean DEBUG = false;
private Logger logger = Globals.getLogger();
private MQThread notifyThread = null;
private Vector eventQueue = new Vector();
private ConnectionManager cm = null;
private boolean shutdown = false;
private boolean requested = false;
public ConsumerInfoNotifyManager(ConnectionManager cm) {
this.cm = cm;
if (Globals.getLogger().getLevel() <= Logger.DEBUG) DEBUG = true;
}
private synchronized void wakeup() {
createNotifyThread();
notifyAll();
}
private void createNotifyThread() {
if (notifyThread == null) {
notifyThread = new MQThread(this, "ConsumerInfoNotifyManager");
notifyThread.setDaemon(true);
notifyThread.start();
}
}
protected synchronized void shutdown() {
shutdown = true;
eventQueue.clear();
notifyAll();
}
public void run() {
ArrayList pendingEvents = new ArrayList();
while (!shutdown) {
boolean dowait =true;
List list = null;
synchronized(eventQueue) {
list = new ArrayList(eventQueue);
}
if (list.size() > 0 && pendingEvents.size() > 0) {
Iterator itr = list.iterator();
Object e = null;
while(itr.hasNext()) {
e = itr.next();
if (!pendingEvents.contains(e)) {
dowait = false;
break;
}
}
} else if (pendingEvents.size() == 0) {
dowait = eventQueue.isEmpty();
}
synchronized (this) {
if (dowait || eventQueue.isEmpty()) {
try {
wait();
} catch (InterruptedException inte) {}
}
}
if (shutdown) {
return;
}
HashMap notifications = new HashMap();
Object[] events = eventQueue.toArray();
Object o = null;
for (int i = 0; i < events.length && !shutdown; i++) {
o = events[i];
if (DEBUG) {
logger.log(logger.INFO, "Processing "+o);
}
if (o instanceof ConsumerAddedEvent) {
ConsumerAddedEvent e = (ConsumerAddedEvent)o;
IMQConnection conn = (IMQConnection)cm.getConnection(e.connid);
if (e.dest.getAllActiveConsumerCount() > 0) {
if (conn == null || conn.isConnectionStarted()) {
notifications.put(e.dest.getDestinationUID(),
new ConsumerInfoNotification(
e.dest.getDestinationUID(),
e.dest.getType(), CONSUMER_READY));
} else {
pendingEvents.add(o);
continue;
}
} else {
notifications.put(e.dest.getDestinationUID(),
new ConsumerInfoNotification(
e.dest.getDestinationUID(),
e.dest.getType(), CONSUMER_NOT_READY));
}
eventQueue.remove(o);
pendingEvents.remove(o);
continue;
}
if (o instanceof RemoteConsumerAddedEvent) {
RemoteConsumerAddedEvent e = (RemoteConsumerAddedEvent)o;
if (e.dest.getAllActiveConsumerCount() > 0) {
notifications.put(e.dest.getDestinationUID(),
new ConsumerInfoNotification(
e.dest.getDestinationUID(),
e.dest.getType(), CONSUMER_READY));
} else {
notifications.put(e.dest.getDestinationUID(),
new ConsumerInfoNotification(
e.dest.getDestinationUID(),
e.dest.getType(), CONSUMER_NOT_READY));
}
eventQueue.remove(o);
continue;
}
if (o instanceof ConsumerRemovedEvent) {
ConsumerRemovedEvent e = (ConsumerRemovedEvent)o;
if (e.dest.getAllActiveConsumerCount() == 0) {
notifications.put(e.dest.getDestinationUID(),
new ConsumerInfoNotification(
e.dest.getDestinationUID(),
e.dest.getType(), CONSUMER_NOT_READY));
}
eventQueue.remove(o);
continue;
}
if (o instanceof ConnectionStartedEvent) {
ConnectionStartedEvent e = (ConnectionStartedEvent)o;
for (int j = 0; j < events.length && !shutdown; j++) {
Object oo = events[j];
if (oo instanceof ConsumerAddedEvent) {
ConsumerAddedEvent ee = (ConsumerAddedEvent)oo;
IMQConnection conn = (IMQConnection)cm.getConnection(ee.connid);
if (conn != null && conn == e.conn &&
ee.dest.getAllActiveConsumerCount() > 0) {
notifications.put(ee.dest.getDestinationUID(),
new ConsumerInfoNotification(
ee.dest.getDestinationUID(),
ee.dest.getType(), CONSUMER_READY));
pendingEvents.remove(ee);
}
}
}
eventQueue.remove(e);
continue;
}
if (o instanceof ConsumerInfoRequestEvent) {
boolean foundmatch = false;
boolean hasconsumer = false;
boolean notifyadded = false;
ConsumerInfoRequestEvent e = (ConsumerInfoRequestEvent)o;
Iterator itr = Destination.getAllDestinations();
while (itr.hasNext()) {
Destination d = (Destination)itr.next();
if (d.isInternal()) {
continue;
}
if ((!e.duid.isWildcard() && d.getDestinationUID().equals(e.duid))) {
foundmatch = true;
if (d.getAllActiveConsumerCount() == 0) {
notifications.put(d.getDestinationUID(),
new ConsumerInfoNotification(
d.getDestinationUID(),
d.getType(), CONSUMER_NOT_READY,
((ConsumerInfoRequestEvent)o).infoType, true));
notifyadded = true;
break;
}
hasconsumer = true;
Iterator itrr = d.getAllActiveConsumers().iterator();
while (itrr.hasNext()) {
Consumer c = (Consumer)itrr.next();
IMQConnection conn = (IMQConnection)cm.getConnection(c.getConnectionUID());
BrokerAddress ba = c.getConsumerUID().getBrokerAddress();
if ((conn != null && conn.isConnectionStarted()) ||
(ba != null && ba != Globals.getMyAddress())) {
notifications.put(d.getDestinationUID(),
new ConsumerInfoNotification(
d.getDestinationUID(),
d.getType(), CONSUMER_READY,
((ConsumerInfoRequestEvent)o).infoType, true));
notifyadded = true;
break;
}
}
break;
}
if (e.duid.isWildcard() && DestinationUID.match(d.getDestinationUID(), e.duid)) {
foundmatch = true;
if (d.getAllActiveConsumerCount() == 0) {
continue;
}
hasconsumer = true;
Iterator itrr = d.getAllActiveConsumers().iterator();
while (itrr.hasNext()) {
Consumer c = (Consumer)itrr.next();
IMQConnection conn = (IMQConnection)cm.getConnection(c.getConnectionUID());
BrokerAddress ba = c.getConsumerUID().getBrokerAddress();
if ((conn != null && conn.isConnectionStarted()) ||
(ba != null && ba != Globals.getMyAddress())) {
notifications.put(d.getDestinationUID(),
new ConsumerInfoNotification(
d.getDestinationUID(),
e.destType, CONSUMER_READY,
((ConsumerInfoRequestEvent)o).infoType, true));
notifyadded = true;
break;
}
}
if (notifyadded) {
break;
}
}
}
if (!foundmatch || (foundmatch && !hasconsumer && !notifyadded)) {
notifications.put(e.duid,
new ConsumerInfoNotification(
e.duid,
e.destType, CONSUMER_NOT_READY,
((ConsumerInfoRequestEvent)o).infoType, true));
}
eventQueue.remove(o);
}
}
Iterator itr = notifications.values().iterator();
ConsumerInfoNotification cin = null;
while (itr.hasNext()) {
cin = (ConsumerInfoNotification)itr.next();
if (DEBUG) {
logger.log(logger.INFO, "Sending "+cin);
}
if (cin.shouldNotify()) {
cm.sendConsumerInfo(InfoRequestHandler.REQUEST_CONSUMER_INFO,
cin.duid, cin.destType, cin.infoType, cin.sendToWildcard);
}
}
notifications.clear();
}
}
public void remoteConsumerAdded(Destination dest) {
if (!requested) return;
eventQueue.add(new RemoteConsumerAddedEvent(dest));
wakeup();
}
public void consumerAdded(Destination dest, Connection conn) {
if (!requested) return;
eventQueue.add(new ConsumerAddedEvent(dest,
(conn == null ? null: conn.getConnectionUID())));
wakeup();
}
public void consumerRemoved(Destination dest) {
if (!requested) return;
eventQueue.add(new ConsumerRemovedEvent(dest));
wakeup();
}
public void connectionStarted(Connection conn) {
if (!requested) return;
eventQueue.add(new ConnectionStartedEvent(conn));
wakeup();
}
public void consumerInfoRequested(Connection conn, DestinationUID duid, int destType) {
consumerInfoRequested(conn, duid, destType, CONSUMER_ALL_EVENT);
}
public void consumerInfoRequested(Connection conn, DestinationUID duid,
int destType, int infoType) {
requested = true;
eventQueue.add(new ConsumerInfoRequestEvent(conn, duid, destType, infoType));
wakeup();
}
protected static String toString(int infoType) {
switch (infoType) {
case CONSUMER_NOT_READY: return "CONSUMER_NOT_READY";
case CONSUMER_READY: return "CONSUMER_READY";
case CONSUMER_ALL_EVENT: return "CONSUMER_ALL_EVENT";
default: return "UNKNOWN";
}
}
class RemoteConsumerAddedEvent {
Destination dest = null;
public RemoteConsumerAddedEvent(Destination dest) {
this.dest = dest;
}
public String toString() {
return "RemoteConsumerAddedEvent: dest="+dest;
}
}
class ConsumerAddedEvent {
Destination dest = null;
ConnectionUID connid = null;
public ConsumerAddedEvent(Destination dest, ConnectionUID connid) {
this.dest = dest;
this.connid = connid;
}
public String toString() {
return "ConsumerAddedEvent: dest="+dest+", conn="+connid;
}
}
class ConsumerRemovedEvent {
Destination dest = null;
public ConsumerRemovedEvent(Destination dest) {
this.dest = dest;
}
public String toString() {
return "ConsumerRemovedEvent: dest="+dest;
}
}
class ConnectionStartedEvent {
Connection conn = null;
public ConnectionStartedEvent(Connection conn) {
this.conn = conn;
}
public String toString() {
return "ConnectionStartedEvent: conn="+conn;
}
}
class ConsumerInfoRequestEvent {
Connection conn = null;
DestinationUID duid = null;
int destType;
int infoType;
public ConsumerInfoRequestEvent(Connection conn,
DestinationUID duid,
int destType, int infoType) {
this.conn = conn;
this.duid = duid;
this.destType = destType;
this.infoType = infoType;
}
public String toString() {
return "ConsumerInfoRequestEvent: conn="+conn+", duid="+duid+
", destType="+DestType.toString(destType)+
", infoType="+ConsumerInfoNotifyManager.toString(infoType);
}
}
class ConsumerInfoNotification {
DestinationUID duid = null;
int destType;
int infoType;
int requestInfoType = CONSUMER_ALL_EVENT;
boolean sendToWildcard = false;
public ConsumerInfoNotification(DestinationUID duid,
int destType, int infoType) {
this.duid = duid;
this.destType = destType;
this.infoType = infoType;
if (infoType != CONSUMER_NOT_READY) {
sendToWildcard = true;
}
}
public ConsumerInfoNotification(DestinationUID duid,
int destType, int infoType,
int requestInfoType,
boolean sendToWildcard) {
this.duid = duid;
this.destType = destType;
this.infoType = infoType;
this.requestInfoType = requestInfoType;
this.sendToWildcard = sendToWildcard;
}
public boolean shouldNotify() {
if (requestInfoType == CONSUMER_ALL_EVENT) {
return true;
}
return (requestInfoType == infoType);
}
public String toString() {
return "ConsumerInfoNotification: duid="+duid+", destType="+
DestType.toString(destType)+", infoType="+ConsumerInfoNotifyManager.toString(infoType);
}
}
}