/**
*
* Copyright 2004 Protique Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**/
package org.codehaus.activemq.broker.impl;
import java.io.Serializable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.jms.DeliveryMode;
import javax.jms.JMSException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.activemq.broker.BrokerClient;
import org.codehaus.activemq.message.ActiveMQDestination;
import org.codehaus.activemq.message.ActiveMQObjectMessage;
import org.codehaus.activemq.message.ConnectionInfo;
import org.codehaus.activemq.message.ConsumerInfo;
import org.codehaus.activemq.message.Packet;
import org.codehaus.activemq.message.ProducerInfo;
import org.codehaus.activemq.util.IdGenerator;
import EDU.oswego.cs.dl.util.concurrent.ConcurrentHashMap;
import EDU.oswego.cs.dl.util.concurrent.CopyOnWriteArrayList;
/**
* Manages advisory subscriptions and messages
*
* @version $Revision: 1.3 $
*/
class AdvisorySupport {
private static final Log log = LogFactory.getLog(AdvisorySupport.class);
private Map advisoryConsumers = new ConcurrentHashMap();
private List consumers = new CopyOnWriteArrayList();
private List producers = new CopyOnWriteArrayList();
private List connections = new CopyOnWriteArrayList();
private IdGenerator idGen = new IdGenerator();
AdvisorySupport() {
}
/**
* Add an advisory Consumer
*
* @param advisory
* @param client
* @return true if a valid consumer
*/
boolean addAdvisory(ConsumerInfo advisory, BrokerClient client) {
boolean result = advisory != null && advisory.isAdvisory() && client != null;
if (result) {
advisoryConsumers.put(advisory, client);
for (Iterator i = consumers.iterator();i.hasNext();) {
ConsumerInfo info = (ConsumerInfo) i.next();
generateAdvisory(advisory, info);
}
for (Iterator i = producers.iterator();i.hasNext();) {
ProducerInfo info = (ProducerInfo) i.next();
generateAdvisory(advisory, info);
}
for (Iterator i = connections.iterator();i.hasNext();) {
ConnectionInfo info = (ConnectionInfo) i.next();
generateAdvisory(advisory, info);
}
}
return result;
}
/**
* remove an advisory Consumer
*
* @param info
* @param client
* @return true if successful
*/
boolean removeAdvisory(ConsumerInfo info, BrokerClient client) {
return advisoryConsumers.remove(info) != null;
}
/**
* Add a Consumer
*
* @param info
*/
void addConsumer(ConsumerInfo info) {
consumers.add(info);
for (Iterator i = advisoryConsumers.keySet().iterator();i.hasNext();) {
ConsumerInfo advisory = (ConsumerInfo) i.next();
generateAdvisory(advisory, info);
}
}
/**
* Remove a Consumer
*
* @param info
*/
void removeConsumer(ConsumerInfo info) {
consumers.remove(info);
for (Iterator i = advisoryConsumers.keySet().iterator();i.hasNext();) {
ConsumerInfo advisory = (ConsumerInfo) i.next();
generateAdvisory(advisory, info);
}
}
/**
* Add a Producer
*
* @param info
*/
void addProducer(ProducerInfo info) {
producers.add(info);
for (Iterator i = advisoryConsumers.keySet().iterator();i.hasNext();) {
ConsumerInfo advisory = (ConsumerInfo) i.next();
generateAdvisory(advisory, info);
}
}
/**
* Remove a Producer
*
* @param info
*/
void removeProducer(ProducerInfo info) {
producers.remove(info);
for (Iterator i = advisoryConsumers.keySet().iterator();i.hasNext();) {
ConsumerInfo advisory = (ConsumerInfo) i.next();
generateAdvisory(advisory, info);
}
}
/**
* Add a Connection
*
* @param info
*/
void addConnection(ConnectionInfo info) {
connections.add(info);
for (Iterator i = advisoryConsumers.keySet().iterator();i.hasNext();) {
ConsumerInfo advisory = (ConsumerInfo) i.next();
generateAdvisory(advisory, info);
}
}
/**
* Remove a Connection
*
* @param info
*/
void removeConnection(ConnectionInfo info) {
connections.remove(info);
for (Iterator i = advisoryConsumers.keySet().iterator();i.hasNext();) {
ConsumerInfo advisory = (ConsumerInfo) i.next();
generateAdvisory(advisory, info);
}
}
private void generateAdvisory(ConsumerInfo advisory, ConsumerInfo info) {
if (matchConsumer(advisory, info)) {
//find the client for ther advisory
BrokerClient client = (BrokerClient) advisoryConsumers.get(advisory);
String suffix = info.isStarted() ? "started" : "stopped";
String destName = ActiveMQDestination.CONSUMER_ADVISORY_PREFIX + info.getDestination() + suffix;
ActiveMQDestination dest = ActiveMQDestination.createDestination(advisory.getDestination()
.getDestinationType(), destName);
generateAdvisoryMessage(advisory, client, info, dest);
}
}
private void generateAdvisory(ConsumerInfo advisory, ProducerInfo info) {
if (matchProducer(advisory, info)) {
//find the client for ther advisory
BrokerClient client = (BrokerClient) advisoryConsumers.get(advisory);
String suffix = info.isStarted() ? "started" : "stopped";
String destName = ActiveMQDestination.CONSUMER_ADVISORY_PREFIX + info.getDestination() + suffix;
ActiveMQDestination dest = ActiveMQDestination.createDestination(advisory.getDestination()
.getDestinationType(), destName);
generateAdvisoryMessage(advisory, client, info, dest);
}
}
private void generateAdvisory(ConsumerInfo advisory, ConnectionInfo info) {
if (matchConnection(advisory, info)) {
//find the client for ther advisory
BrokerClient client = (BrokerClient) advisoryConsumers.get(advisory);
String suffix = info.isStarted() ? "started" : "stopped";
String destName = advisory.getDestination().getPhysicalName() + suffix;
ActiveMQDestination dest = ActiveMQDestination.createDestination(advisory.getDestination()
.getDestinationType(), destName);
generateAdvisoryMessage(advisory, client, info, dest);
}
}
boolean matchConsumer(ConsumerInfo advisory, ConsumerInfo info) {
boolean result = false;
if (advisory != null && advisory.getDestination() != null && info != null && info.getDestination() != null) {
ActiveMQDestination advisoryDestination = advisory.getDestination();
ActiveMQDestination destination = info.getDestination();
if (advisoryDestination.isConsumerAdvisory()) {
String pyhsicalName = advisory.getDestination().getPhysicalName();
String matchName = pyhsicalName.substring(ActiveMQDestination.CONSUMER_ADVISORY_PREFIX.length(),
pyhsicalName.length());
ActiveMQDestination match = ActiveMQDestination.createDestination(advisoryDestination
.getDestinationType(), matchName);
return match.matches(destination) || matchGeneralAdvisory(advisory, destination);
}
}
return result;
}
boolean matchProducer(ConsumerInfo advisory, ProducerInfo info) {
boolean result = false;
if (advisory != null && advisory.getDestination() != null && info != null && info.getDestination() != null) {
ActiveMQDestination advisoryDestination = advisory.getDestination();
ActiveMQDestination destination = info.getDestination();
if (advisoryDestination.isProducerAdvisory()) {
String pyhsicalName = advisory.getDestination().getPhysicalName();
String matchName = pyhsicalName.substring(ActiveMQDestination.PRODUCER_ADVISORY_PREFIX.length(),
pyhsicalName.length());
ActiveMQDestination match = ActiveMQDestination.createDestination(advisoryDestination
.getDestinationType(), matchName);
return match.matches(destination) || matchGeneralAdvisory(advisory, destination);
}
}
return result;
}
boolean matchConnection(ConsumerInfo advisory, ConnectionInfo info) {
boolean result = false;
if (advisory != null && advisory.getDestination() != null && info != null) {
result = advisory.getDestination().isConnectionAdvisory()
|| advisory.getDestination().matches(
ActiveMQDestination.createDestination(advisory.getDestination().getDestinationType(),
ActiveMQDestination.CONNECTION_ADVISORY_PREFIX));
}
return result;
}
/**
* A consumer could listen for all advisories
*
* @param advisory
* @param destination
* @return true if a general 'catch-all' advisory subscriber
*/
boolean matchGeneralAdvisory(ConsumerInfo advisory, ActiveMQDestination destination) {
boolean result = advisory.getDestination() != null && advisory.getDestination().isAdvisory();
if (result) {
String pyhsicalName = advisory.getDestination().getPhysicalName();
String matchName = pyhsicalName.substring(ActiveMQDestination.ADVISORY_PREFIX.length(), pyhsicalName
.length());
ActiveMQDestination match = ActiveMQDestination.createDestination(advisory.getDestination()
.getDestinationType(), matchName);
result = match.matches(destination);
}
return result;
}
private void generateAdvisoryMessage(final ConsumerInfo advisoryTarget, final BrokerClient targetClient,
final Packet payload, final ActiveMQDestination destination) {
ActiveMQObjectMessage advisoryMsg = new ActiveMQObjectMessage();
advisoryMsg.setJMSMessageID(idGen.generateId());
advisoryMsg.setJMSDestination(destination);
advisoryMsg.setExternalMessageId(true);
advisoryMsg.setDeliveryCount(DeliveryMode.NON_PERSISTENT);
try {
advisoryMsg.setObject((Serializable) payload);
}
catch (JMSException e) {
log.warn("caught an exception generating an advisory", e);
}
advisoryMsg.setConsumerNos(new int[]{advisoryTarget.getConsumerNo()});
targetClient.dispatch(advisoryMsg);
}
}