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;
018
019import java.util.ArrayList;
020import java.util.HashMap;
021import java.util.Iterator;
022import java.util.List;
023import java.util.Map;
024import java.util.Set;
025import java.util.concurrent.ConcurrentHashMap;
026import java.util.concurrent.locks.ReentrantReadWriteLock;
027
028import javax.jms.IllegalStateException;
029import javax.jms.JMSException;
030
031import org.apache.activemq.advisory.AdvisorySupport;
032import org.apache.activemq.broker.ConnectionContext;
033import org.apache.activemq.broker.ConsumerBrokerExchange;
034import org.apache.activemq.broker.ProducerBrokerExchange;
035import org.apache.activemq.broker.region.policy.PolicyEntry;
036import org.apache.activemq.broker.region.virtual.CompositeDestinationFilter;
037import org.apache.activemq.command.ActiveMQDestination;
038import org.apache.activemq.command.ConsumerControl;
039import org.apache.activemq.command.ConsumerId;
040import org.apache.activemq.command.ConsumerInfo;
041import org.apache.activemq.command.Message;
042import org.apache.activemq.command.MessageAck;
043import org.apache.activemq.command.MessageDispatchNotification;
044import org.apache.activemq.command.MessagePull;
045import org.apache.activemq.command.ProducerInfo;
046import org.apache.activemq.command.RemoveSubscriptionInfo;
047import org.apache.activemq.command.Response;
048import org.apache.activemq.filter.DestinationFilter;
049import org.apache.activemq.filter.DestinationMap;
050import org.apache.activemq.security.SecurityContext;
051import org.apache.activemq.thread.TaskRunnerFactory;
052import org.apache.activemq.usage.SystemUsage;
053import org.apache.activemq.DestinationDoesNotExistException;
054import org.slf4j.Logger;
055import org.slf4j.LoggerFactory;
056
057/**
058 *
059 */
060public abstract class AbstractRegion implements Region {
061
062    private static final Logger LOG = LoggerFactory.getLogger(AbstractRegion.class);
063
064    protected final Map<ActiveMQDestination, Destination> destinations = new ConcurrentHashMap<ActiveMQDestination, Destination>();
065    protected final DestinationMap destinationMap = new DestinationMap();
066    protected final Map<ConsumerId, Subscription> subscriptions = new ConcurrentHashMap<ConsumerId, Subscription>();
067    protected final SystemUsage usageManager;
068    protected final DestinationFactory destinationFactory;
069    protected final DestinationStatistics destinationStatistics;
070    protected final RegionStatistics regionStatistics = new RegionStatistics();
071    protected final RegionBroker broker;
072    protected boolean autoCreateDestinations = true;
073    protected final TaskRunnerFactory taskRunnerFactory;
074    protected final ReentrantReadWriteLock destinationsLock = new ReentrantReadWriteLock();
075    protected final Map<ConsumerId, Object> consumerChangeMutexMap = new HashMap<ConsumerId, Object>();
076    protected boolean started;
077
078    public AbstractRegion(RegionBroker broker, DestinationStatistics destinationStatistics, SystemUsage memoryManager,
079            TaskRunnerFactory taskRunnerFactory, DestinationFactory destinationFactory) {
080        if (broker == null) {
081            throw new IllegalArgumentException("null broker");
082        }
083        this.broker = broker;
084        this.destinationStatistics = destinationStatistics;
085        this.usageManager = memoryManager;
086        this.taskRunnerFactory = taskRunnerFactory;
087        if (destinationFactory == null) {
088            throw new IllegalArgumentException("null destinationFactory");
089        }
090        this.destinationFactory = destinationFactory;
091    }
092
093    @Override
094    public final void start() throws Exception {
095        started = true;
096
097        Set<ActiveMQDestination> inactiveDests = getInactiveDestinations();
098        for (Iterator<ActiveMQDestination> iter = inactiveDests.iterator(); iter.hasNext();) {
099            ActiveMQDestination dest = iter.next();
100
101            ConnectionContext context = new ConnectionContext();
102            context.setBroker(broker.getBrokerService().getBroker());
103            context.setSecurityContext(SecurityContext.BROKER_SECURITY_CONTEXT);
104            context.getBroker().addDestination(context, dest, false);
105        }
106        destinationsLock.readLock().lock();
107        try{
108            for (Iterator<Destination> i = destinations.values().iterator(); i.hasNext();) {
109                Destination dest = i.next();
110                dest.start();
111            }
112        } finally {
113            destinationsLock.readLock().unlock();
114        }
115    }
116
117    @Override
118    public void stop() throws Exception {
119        started = false;
120        destinationsLock.readLock().lock();
121        try{
122            for (Iterator<Destination> i = destinations.values().iterator(); i.hasNext();) {
123                Destination dest = i.next();
124                dest.stop();
125            }
126        } finally {
127            destinationsLock.readLock().unlock();
128        }
129
130        destinationsLock.writeLock().lock();
131        try {
132            destinations.clear();
133            regionStatistics.getAdvisoryDestinations().reset();
134            regionStatistics.getDestinations().reset();
135            regionStatistics.getAllDestinations().reset();
136        } finally {
137            destinationsLock.writeLock().unlock();
138        }
139    }
140
141    @Override
142    public Destination addDestination(ConnectionContext context, ActiveMQDestination destination,
143            boolean createIfTemporary) throws Exception {
144
145        destinationsLock.writeLock().lock();
146        try {
147            Destination dest = destinations.get(destination);
148            if (dest == null) {
149                if (destination.isTemporary() == false || createIfTemporary) {
150                    // Limit the number of destinations that can be created if
151                    // maxDestinations has been set on a policy
152                    validateMaxDestinations(destination);
153
154                    LOG.debug("{} adding destination: {}", broker.getBrokerName(), destination);
155                    dest = createDestination(context, destination);
156                    // intercept if there is a valid interceptor defined
157                    DestinationInterceptor destinationInterceptor = broker.getDestinationInterceptor();
158                    if (destinationInterceptor != null) {
159                        dest = destinationInterceptor.intercept(dest);
160                    }
161                    dest.start();
162                    destinations.put(destination, dest);
163                    updateRegionDestCounts(destination, 1);
164                    destinationMap.put(destination, dest);
165                    addSubscriptionsForDestination(context, dest);
166                }
167                if (dest == null) {
168                    throw new DestinationDoesNotExistException(destination.getQualifiedName());
169                }
170            }
171            return dest;
172        } finally {
173            destinationsLock.writeLock().unlock();
174        }
175    }
176
177    public Map<ConsumerId, Subscription> getSubscriptions() {
178        return subscriptions;
179    }
180
181    /**
182     * Updates the counts in RegionStatistics based on whether or not the destination
183     * is an Advisory Destination or not
184     *
185     * @param destination the destination being used to determine which counters to update
186     * @param count the count to add to the counters
187     */
188    protected void updateRegionDestCounts(ActiveMQDestination destination, int count) {
189        if (destination != null) {
190            if (AdvisorySupport.isAdvisoryTopic(destination)) {
191                regionStatistics.getAdvisoryDestinations().add(count);
192            } else {
193                regionStatistics.getDestinations().add(count);
194            }
195            regionStatistics.getAllDestinations().add(count);
196        }
197    }
198
199    /**
200     * This method checks whether or not the destination can be created based on
201     * {@link PolicyEntry#getMaxDestinations}, if it has been set. Advisory
202     * topics are ignored.
203     *
204     * @param destination
205     * @throws Exception
206     */
207    protected void validateMaxDestinations(ActiveMQDestination destination)
208            throws Exception {
209        if (broker.getDestinationPolicy() != null) {
210            PolicyEntry entry = broker.getDestinationPolicy().getEntryFor(destination);
211            // Make sure the destination is not an advisory topic
212            if (entry != null && entry.getMaxDestinations() >= 0
213                    && !AdvisorySupport.isAdvisoryTopic(destination)) {
214                // If there is an entry for this destination, look up the set of
215                // destinations associated with this policy
216                // If a destination isn't specified, then just count up
217                // non-advisory destinations (ie count all destinations)
218                int destinationSize = (int) (entry.getDestination() != null ?
219                        destinationMap.get(entry.getDestination()).size() : regionStatistics.getDestinations().getCount());
220                if (destinationSize >= entry.getMaxDestinations()) {
221                    if (entry.getDestination() != null) {
222                        throw new IllegalStateException(
223                                "The maxmimum number of destinations allowed ("+ entry.getMaxDestinations() +
224                                ") for the policy " + entry.getDestination() + " has already been reached.");
225                    // No destination has been set (default policy)
226                    } else {
227                        throw new IllegalStateException("The maxmimum number of destinations allowed ("
228                                        + entry.getMaxDestinations() + ") has already been reached.");
229                    }
230                }
231            }
232        }
233    }
234
235    protected List<Subscription> addSubscriptionsForDestination(ConnectionContext context, Destination dest) throws Exception {
236        List<Subscription> rc = new ArrayList<Subscription>();
237        // Add all consumers that are interested in the destination.
238        for (Iterator<Subscription> iter = subscriptions.values().iterator(); iter.hasNext();) {
239            Subscription sub = iter.next();
240            if (sub.matches(dest.getActiveMQDestination())) {
241                try {
242                    ConnectionContext originalContext = sub.getContext() != null ? sub.getContext() : context;
243                    dest.addSubscription(originalContext, sub);
244                    rc.add(sub);
245                } catch (SecurityException e) {
246                    if (sub.isWildcard()) {
247                        LOG.debug("Subscription denied for " + sub + " to destination " +
248                            dest.getActiveMQDestination() +  ": " + e.getMessage());
249                    } else {
250                        throw e;
251                    }
252                }
253            }
254        }
255        return rc;
256
257    }
258
259    @Override
260    public void removeDestination(ConnectionContext context, ActiveMQDestination destination, long timeout)
261            throws Exception {
262
263        // No timeout.. then try to shut down right way, fails if there are
264        // current subscribers.
265        if (timeout == 0) {
266            for (Iterator<Subscription> iter = subscriptions.values().iterator(); iter.hasNext();) {
267                Subscription sub = iter.next();
268                if (sub.matches(destination)) {
269                    throw new JMSException("Destination still has an active subscription: " + destination);
270                }
271            }
272        }
273
274        if (timeout > 0) {
275            // TODO: implement a way to notify the subscribers that we want to
276            // take the down
277            // the destination and that they should un-subscribe.. Then wait up
278            // to timeout time before
279            // dropping the subscription.
280        }
281
282        LOG.debug("{} removing destination: {}", broker.getBrokerName(), destination);
283
284        destinationsLock.writeLock().lock();
285        try {
286            Destination dest = destinations.remove(destination);
287            if (dest != null) {
288                updateRegionDestCounts(destination, -1);
289
290                // timeout<0 or we timed out, we now force any remaining
291                // subscriptions to un-subscribe.
292                for (Iterator<Subscription> iter = subscriptions.values().iterator(); iter.hasNext();) {
293                    Subscription sub = iter.next();
294                    if (sub.matches(destination)) {
295                        dest.removeSubscription(context, sub, 0l);
296                    }
297                }
298                destinationMap.removeAll(destination);
299                dispose(context, dest);
300                DestinationInterceptor destinationInterceptor = broker.getDestinationInterceptor();
301                if (destinationInterceptor != null) {
302                    destinationInterceptor.remove(dest);
303                }
304
305            } else {
306                LOG.debug("Cannot remove a destination that doesn't exist: {}", destination);
307            }
308        } finally {
309            destinationsLock.writeLock().unlock();
310        }
311    }
312
313    /**
314     * Provide an exact or wildcard lookup of destinations in the region
315     *
316     * @return a set of matching destination objects.
317     */
318    @Override
319    @SuppressWarnings("unchecked")
320    public Set<Destination> getDestinations(ActiveMQDestination destination) {
321        destinationsLock.readLock().lock();
322        try{
323            return destinationMap.get(destination);
324        } finally {
325            destinationsLock.readLock().unlock();
326        }
327    }
328
329    @Override
330    public Map<ActiveMQDestination, Destination> getDestinationMap() {
331        return destinations;
332    }
333
334    @Override
335    @SuppressWarnings("unchecked")
336    public Subscription addConsumer(ConnectionContext context, ConsumerInfo info) throws Exception {
337        LOG.debug("{} adding consumer: {} for destination: {}", new Object[]{ broker.getBrokerName(), info.getConsumerId(), info.getDestination() });
338        ActiveMQDestination destination = info.getDestination();
339        if (destination != null && !destination.isPattern() && !destination.isComposite()) {
340            // lets auto-create the destination
341            lookup(context, destination,true);
342        }
343
344        Object addGuard;
345        synchronized (consumerChangeMutexMap) {
346            addGuard = consumerChangeMutexMap.get(info.getConsumerId());
347            if (addGuard == null) {
348                addGuard = new Object();
349                consumerChangeMutexMap.put(info.getConsumerId(), addGuard);
350            }
351        }
352        synchronized (addGuard) {
353            Subscription o = subscriptions.get(info.getConsumerId());
354            if (o != null) {
355                LOG.warn("A duplicate subscription was detected. Clients may be misbehaving. Later warnings you may see about subscription removal are a consequence of this.");
356                return o;
357            }
358
359            // We may need to add some destinations that are in persistent store
360            // but not active
361            // in the broker.
362            //
363            // TODO: think about this a little more. This is good cause
364            // destinations are not loaded into
365            // memory until a client needs to use the queue, but a management
366            // agent viewing the
367            // broker will not see a destination that exists in persistent
368            // store. We may want to
369            // eagerly load all destinations into the broker but have an
370            // inactive state for the
371            // destination which has reduced memory usage.
372            //
373            DestinationFilter.parseFilter(info.getDestination());
374
375            Subscription sub = createSubscription(context, info);
376
377            // At this point we're done directly manipulating subscriptions,
378            // but we need to retain the synchronized block here. Consider
379            // otherwise what would happen if at this point a second
380            // thread added, then removed, as would be allowed with
381            // no mutex held. Remove is only essentially run once
382            // so everything after this point would be leaked.
383
384            // Add the subscription to all the matching queues.
385            // But copy the matches first - to prevent deadlocks
386            List<Destination> addList = new ArrayList<Destination>();
387            destinationsLock.readLock().lock();
388            try {
389                for (Destination dest : (Set<Destination>) destinationMap.get(info.getDestination())) {
390                    addList.add(dest);
391                }
392            } finally {
393                destinationsLock.readLock().unlock();
394            }
395
396            List<Destination> removeList = new ArrayList<Destination>();
397            for (Destination dest : addList) {
398                try {
399                    dest.addSubscription(context, sub);
400                    removeList.add(dest);
401                } catch (SecurityException e){
402                    if (sub.isWildcard()) {
403                        LOG.debug("Subscription denied for " + sub + " to destination " +
404                            dest.getActiveMQDestination() + ": " + e.getMessage());
405                    } else {
406                        // remove partial subscriptions
407                        for (Destination remove : removeList) {
408                            try {
409                                remove.removeSubscription(context, sub, info.getLastDeliveredSequenceId());
410                            } catch (Exception ex) {
411                                LOG.error("Error unsubscribing " + sub + " from " + remove + ": " + ex.getMessage(), ex);
412                            }
413                        }
414                        throw e;
415                    }
416                }
417            }
418            removeList.clear();
419
420            if (info.isBrowser()) {
421                ((QueueBrowserSubscription) sub).destinationsAdded();
422            }
423
424            subscriptions.put(info.getConsumerId(), sub);
425
426            return sub;
427        }
428    }
429
430    /**
431     * Get all the Destinations that are in storage
432     *
433     * @return Set of all stored destinations
434     */
435    @SuppressWarnings("rawtypes")
436    public Set getDurableDestinations() {
437        return destinationFactory.getDestinations();
438    }
439
440    /**
441     * @return all Destinations that don't have active consumers
442     */
443    protected Set<ActiveMQDestination> getInactiveDestinations() {
444        Set<ActiveMQDestination> inactiveDests = destinationFactory.getDestinations();
445        destinationsLock.readLock().lock();
446        try {
447            inactiveDests.removeAll(destinations.keySet());
448        } finally {
449            destinationsLock.readLock().unlock();
450        }
451        return inactiveDests;
452    }
453
454    @Override
455    @SuppressWarnings("unchecked")
456    public void removeConsumer(ConnectionContext context, ConsumerInfo info) throws Exception {
457        LOG.debug("{} removing consumer: {} for destination: {}", new Object[]{ broker.getBrokerName(), info.getConsumerId(), info.getDestination() });
458
459        Subscription sub = subscriptions.remove(info.getConsumerId());
460        // The sub could be removed elsewhere - see ConnectionSplitBroker
461        if (sub != null) {
462
463            // remove the subscription from all the matching queues.
464            List<Destination> removeList = new ArrayList<Destination>();
465            destinationsLock.readLock().lock();
466            try {
467                for (Destination dest : (Set<Destination>) destinationMap.get(info.getDestination())) {
468                    removeList.add(dest);
469                }
470            } finally {
471                destinationsLock.readLock().unlock();
472            }
473            for (Destination dest : removeList) {
474                dest.removeSubscription(context, sub, info.getLastDeliveredSequenceId());
475            }
476
477            destroySubscription(sub);
478        }
479        synchronized (consumerChangeMutexMap) {
480            consumerChangeMutexMap.remove(info.getConsumerId());
481        }
482    }
483
484    protected void destroySubscription(Subscription sub) {
485        sub.destroy();
486    }
487
488    @Override
489    public void removeSubscription(ConnectionContext context, RemoveSubscriptionInfo info) throws Exception {
490        throw new JMSException("Invalid operation.");
491    }
492
493    @Override
494    public void send(final ProducerBrokerExchange producerExchange, Message messageSend) throws Exception {
495        final ConnectionContext context = producerExchange.getConnectionContext();
496
497        if (producerExchange.isMutable() || producerExchange.getRegionDestination() == null) {
498            final Destination regionDestination = lookup(context, messageSend.getDestination(),false);
499            producerExchange.setRegionDestination(regionDestination);
500        }
501
502        producerExchange.getRegionDestination().send(producerExchange, messageSend);
503
504        if (producerExchange.getProducerState() != null && producerExchange.getProducerState().getInfo() != null){
505            producerExchange.getProducerState().getInfo().incrementSentCount();
506        }
507    }
508
509    @Override
510    public void acknowledge(ConsumerBrokerExchange consumerExchange, MessageAck ack) throws Exception {
511        Subscription sub = consumerExchange.getSubscription();
512        if (sub == null) {
513            sub = subscriptions.get(ack.getConsumerId());
514            if (sub == null) {
515                if (!consumerExchange.getConnectionContext().isInRecoveryMode()) {
516                    LOG.warn("Ack for non existent subscription, ack: {}", ack);
517                    throw new IllegalArgumentException("The subscription does not exist: " + ack.getConsumerId());
518                } else {
519                    LOG.debug("Ack for non existent subscription in recovery, ack: {}", ack);
520                    return;
521                }
522            }
523            consumerExchange.setSubscription(sub);
524        }
525        sub.acknowledge(consumerExchange.getConnectionContext(), ack);
526    }
527
528    @Override
529    public Response messagePull(ConnectionContext context, MessagePull pull) throws Exception {
530        Subscription sub = subscriptions.get(pull.getConsumerId());
531        if (sub == null) {
532            throw new IllegalArgumentException("The subscription does not exist: " + pull.getConsumerId());
533        }
534        return sub.pullMessage(context, pull);
535    }
536
537    protected Destination lookup(ConnectionContext context, ActiveMQDestination destination,boolean createTemporary) throws Exception {
538        Destination dest = null;
539
540        destinationsLock.readLock().lock();
541        try {
542            dest = destinations.get(destination);
543        } finally {
544            destinationsLock.readLock().unlock();
545        }
546
547        if (dest == null) {
548            if (isAutoCreateDestinations()) {
549                // Try to auto create the destination... re-invoke broker
550                // from the
551                // top so that the proper security checks are performed.
552                context.getBroker().addDestination(context, destination, createTemporary);
553                dest = addDestination(context, destination, false);
554                // We should now have the dest created.
555                destinationsLock.readLock().lock();
556                try {
557                    dest = destinations.get(destination);
558                } finally {
559                    destinationsLock.readLock().unlock();
560                }
561            }
562
563            if (dest == null) {
564                throw new JMSException("The destination " + destination + " does not exist.");
565            }
566        }
567        return dest;
568    }
569
570    @Override
571    public void processDispatchNotification(MessageDispatchNotification messageDispatchNotification) throws Exception {
572        Subscription sub = subscriptions.get(messageDispatchNotification.getConsumerId());
573        if (sub != null) {
574            sub.processMessageDispatchNotification(messageDispatchNotification);
575        } else {
576            throw new JMSException("Slave broker out of sync with master - Subscription: "
577                    + messageDispatchNotification.getConsumerId() + " on "
578                    + messageDispatchNotification.getDestination() + " does not exist for dispatch of message: "
579                    + messageDispatchNotification.getMessageId());
580        }
581    }
582
583    /*
584     * For a Queue/TempQueue, dispatch order is imperative to match acks, so the
585     * dispatch is deferred till the notification to ensure that the
586     * subscription chosen by the master is used. AMQ-2102
587     */
588    protected void processDispatchNotificationViaDestination(MessageDispatchNotification messageDispatchNotification)
589            throws Exception {
590        Destination dest = null;
591        destinationsLock.readLock().lock();
592        try {
593            dest = destinations.get(messageDispatchNotification.getDestination());
594        } finally {
595            destinationsLock.readLock().unlock();
596        }
597
598        if (dest != null) {
599            dest.processDispatchNotification(messageDispatchNotification);
600        } else {
601            throw new JMSException("Slave broker out of sync with master - Destination: "
602                    + messageDispatchNotification.getDestination() + " does not exist for consumer "
603                    + messageDispatchNotification.getConsumerId() + " with message: "
604                    + messageDispatchNotification.getMessageId());
605        }
606    }
607
608    @Override
609    public void gc() {
610        for (Subscription sub : subscriptions.values()) {
611            sub.gc();
612        }
613
614        destinationsLock.readLock().lock();
615        try {
616            for (Destination dest : destinations.values()) {
617                dest.gc();
618            }
619        } finally {
620            destinationsLock.readLock().unlock();
621        }
622    }
623
624    protected abstract Subscription createSubscription(ConnectionContext context, ConsumerInfo info) throws Exception;
625
626    protected Destination createDestination(ConnectionContext context, ActiveMQDestination destination)
627            throws Exception {
628        return destinationFactory.createDestination(context, destination, destinationStatistics);
629    }
630
631    public boolean isAutoCreateDestinations() {
632        return autoCreateDestinations;
633    }
634
635    public void setAutoCreateDestinations(boolean autoCreateDestinations) {
636        this.autoCreateDestinations = autoCreateDestinations;
637    }
638
639    @Override
640    @SuppressWarnings("unchecked")
641    public void addProducer(ConnectionContext context, ProducerInfo info) throws Exception {
642        destinationsLock.readLock().lock();
643        try {
644            for (Destination dest : (Set<Destination>) destinationMap.get(info.getDestination())) {
645                dest.addProducer(context, info);
646            }
647        } finally {
648            destinationsLock.readLock().unlock();
649        }
650    }
651
652    /**
653     * Removes a Producer.
654     *
655     * @param context
656     *            the environment the operation is being executed under.
657     * @throws Exception
658     *             TODO
659     */
660    @Override
661    @SuppressWarnings("unchecked")
662    public void removeProducer(ConnectionContext context, ProducerInfo info) throws Exception {
663        destinationsLock.readLock().lock();
664        try {
665            for (Destination dest : (Set<Destination>) destinationMap.get(info.getDestination())) {
666                dest.removeProducer(context, info);
667            }
668        } finally {
669            destinationsLock.readLock().unlock();
670        }
671    }
672
673    protected void dispose(ConnectionContext context, Destination dest) throws Exception {
674        dest.dispose(context);
675        dest.stop();
676        destinationFactory.removeDestination(dest);
677    }
678
679    @Override
680    public void processConsumerControl(ConsumerBrokerExchange consumerExchange, ConsumerControl control) {
681        Subscription sub = subscriptions.get(control.getConsumerId());
682        if (sub != null && sub instanceof AbstractSubscription) {
683            ((AbstractSubscription) sub).setPrefetchSize(control.getPrefetch());
684            if (broker.getDestinationPolicy() != null) {
685                PolicyEntry entry = broker.getDestinationPolicy().getEntryFor(control.getDestination());
686                if (entry != null) {
687                    entry.configurePrefetch(sub);
688                }
689            }
690            LOG.debug("setting prefetch: {}, on subscription: {}; resulting value: {}", new Object[]{ control.getPrefetch(), control.getConsumerId(), sub.getConsumerInfo().getCurrentPrefetchSize()});
691            try {
692                lookup(consumerExchange.getConnectionContext(), control.getDestination(),false).wakeup();
693            } catch (Exception e) {
694                LOG.warn("failed to deliver post consumerControl dispatch-wakeup, to destination: {}", control.getDestination(), e);
695            }
696        }
697    }
698
699    @Override
700    public void reapplyInterceptor() {
701        destinationsLock.writeLock().lock();
702        try {
703            DestinationInterceptor destinationInterceptor = broker.getDestinationInterceptor();
704            Map<ActiveMQDestination, Destination> map = getDestinationMap();
705            for (ActiveMQDestination key : map.keySet()) {
706                Destination destination = map.get(key);
707                if (destination instanceof CompositeDestinationFilter) {
708                    destination = ((CompositeDestinationFilter) destination).next;
709                }
710                if (destinationInterceptor != null) {
711                    destination = destinationInterceptor.intercept(destination);
712                }
713                getDestinationMap().put(key, destination);
714                Destination prev = destinations.put(key, destination);
715                if (prev == null) {
716                    updateRegionDestCounts(key, 1);
717                }
718            }
719        } finally {
720            destinationsLock.writeLock().unlock();
721        }
722    }
723}