001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.activemq.broker.region.virtual; 018 019import java.util.Collection; 020import java.util.Iterator; 021import java.util.LinkedList; 022import java.util.concurrent.CountDownLatch; 023import java.util.concurrent.atomic.AtomicReference; 024 025import org.apache.activemq.broker.Broker; 026import org.apache.activemq.broker.BrokerService; 027import org.apache.activemq.broker.ProducerBrokerExchange; 028import org.apache.activemq.broker.region.Destination; 029import org.apache.activemq.broker.region.DestinationFilter; 030import org.apache.activemq.command.ActiveMQDestination; 031import org.apache.activemq.command.Message; 032import org.apache.activemq.filter.MessageEvaluationContext; 033import org.apache.activemq.filter.NonCachedMessageEvaluationContext; 034 035/** 036 * Represents a composite {@link Destination} where send()s are replicated to 037 * each Destination instance. 038 */ 039public class CompositeDestinationFilter extends DestinationFilter { 040 041 private Collection forwardDestinations; 042 private boolean forwardOnly; 043 private boolean concurrentSend = false; 044 private boolean sendWhenNotMatched=false; 045 046 public CompositeDestinationFilter(Destination next, Collection forwardDestinations, boolean forwardOnly,boolean sendWhenNotMatched, boolean concurrentSend) { 047 super(next); 048 this.forwardDestinations = forwardDestinations; 049 this.forwardOnly = forwardOnly; 050 this.concurrentSend = concurrentSend; 051 this.sendWhenNotMatched = sendWhenNotMatched; 052 } 053 054 @Override 055 public void send(final ProducerBrokerExchange context, final Message message) throws Exception { 056 MessageEvaluationContext messageContext = null; 057 058 Collection<ActiveMQDestination> matchingDestinations = new LinkedList<ActiveMQDestination>(); 059 for (Iterator iter = forwardDestinations.iterator(); iter.hasNext();) { 060 ActiveMQDestination destination = null; 061 Object value = iter.next(); 062 063 if (value instanceof FilteredDestination) { 064 FilteredDestination filteredDestination = (FilteredDestination)value; 065 if (messageContext == null) { 066 messageContext = new NonCachedMessageEvaluationContext(); 067 messageContext.setMessageReference(message); 068 } 069 messageContext.setDestination(filteredDestination.getDestination()); 070 if (filteredDestination.matches(messageContext)) { 071 destination = filteredDestination.getDestination(); 072 } 073 } else if (value instanceof ActiveMQDestination) { 074 destination = (ActiveMQDestination)value; 075 } 076 if (destination == null) { 077 continue; 078 } 079 matchingDestinations.add(destination); 080 } 081 082 final CountDownLatch concurrent = new CountDownLatch(concurrentSend ? matchingDestinations.size() : 0); 083 final AtomicReference<Exception> exceptionAtomicReference = new AtomicReference<Exception>(); 084 final BrokerService brokerService = context.getConnectionContext().getBroker().getBrokerService(); 085 for (final ActiveMQDestination destination : matchingDestinations) { 086 if (concurrent.getCount() > 0) { 087 brokerService.getTaskRunnerFactory().execute(new Runnable() { 088 @Override 089 public void run() { 090 try { 091 if (exceptionAtomicReference.get() == null) { 092 doForward(context.copy(), message, brokerService.getRegionBroker(), destination); 093 } 094 } catch (Exception e) { 095 exceptionAtomicReference.set(e); 096 } finally { 097 concurrent.countDown(); 098 } 099 } 100 }); 101 } else { 102 doForward(context, message, brokerService.getRegionBroker(), destination); 103 } 104 } 105 if(sendWhenNotMatched) 106 { 107 if(matchingDestinations.size() <=0) { 108 super.send(context, message); 109 } 110 }else { 111 if (!forwardOnly) { 112 super.send(context, message); 113 } 114 } 115 116 concurrent.await(); 117 if (exceptionAtomicReference.get() != null) { 118 throw exceptionAtomicReference.get(); 119 } 120 } 121 122 private void doForward(ProducerBrokerExchange context, Message message, Broker regionBroker, ActiveMQDestination destination) throws Exception { 123 Message forwardedMessage = message.copy(); 124 forwardedMessage.setMemoryUsage(null); 125 126 forwardedMessage.setOriginalDestination( message.getDestination() ); 127 forwardedMessage.setDestination(destination); 128 129 // Send it back through the region broker for routing. 130 context.setMutable(true); 131 regionBroker.send(context, forwardedMessage); 132 } 133}