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.io.IOException;
020import java.util.List;
021import java.util.concurrent.atomic.AtomicBoolean;
022
023import javax.jms.ResourceAllocationException;
024
025import org.apache.activemq.advisory.AdvisorySupport;
026import org.apache.activemq.broker.Broker;
027import org.apache.activemq.broker.BrokerService;
028import org.apache.activemq.broker.ConnectionContext;
029import org.apache.activemq.broker.ProducerBrokerExchange;
030import org.apache.activemq.broker.region.policy.DeadLetterStrategy;
031import org.apache.activemq.broker.region.policy.SlowConsumerStrategy;
032import org.apache.activemq.command.ActiveMQDestination;
033import org.apache.activemq.command.ActiveMQTopic;
034import org.apache.activemq.command.Message;
035import org.apache.activemq.command.MessageAck;
036import org.apache.activemq.command.MessageDispatchNotification;
037import org.apache.activemq.command.ProducerInfo;
038import org.apache.activemq.filter.NonCachedMessageEvaluationContext;
039import org.apache.activemq.security.SecurityContext;
040import org.apache.activemq.state.ProducerState;
041import org.apache.activemq.store.MessageStore;
042import org.apache.activemq.thread.Scheduler;
043import org.apache.activemq.usage.MemoryUsage;
044import org.apache.activemq.usage.SystemUsage;
045import org.apache.activemq.usage.TempUsage;
046import org.apache.activemq.usage.Usage;
047import org.slf4j.Logger;
048
049/**
050 *
051 */
052public abstract class BaseDestination implements Destination {
053    /**
054     * The maximum number of messages to page in to the destination from
055     * persistent storage
056     */
057    public static final int MAX_PAGE_SIZE = 200;
058    public static final int MAX_BROWSE_PAGE_SIZE = MAX_PAGE_SIZE * 2;
059    public static final long EXPIRE_MESSAGE_PERIOD = 30 * 1000;
060    public static final long DEFAULT_INACTIVE_TIMEOUT_BEFORE_GC = 60 * 1000;
061    public static final int MAX_PRODUCERS_TO_AUDIT = 64;
062    public static final int MAX_AUDIT_DEPTH = 10000;
063    public static final String DUPLICATE_FROM_STORE_MSG_PREFIX = "duplicate from store for ";
064
065    protected final AtomicBoolean started = new AtomicBoolean();
066    protected final ActiveMQDestination destination;
067    protected final Broker broker;
068    protected final MessageStore store;
069    protected SystemUsage systemUsage;
070    protected MemoryUsage memoryUsage;
071    private boolean producerFlowControl = true;
072    private boolean alwaysRetroactive = false;
073    protected long lastBlockedProducerWarnTime = 0l;
074    protected long blockedProducerWarningInterval = DEFAULT_BLOCKED_PRODUCER_WARNING_INTERVAL;
075
076    private int maxProducersToAudit = 1024;
077    private int maxAuditDepth = 2048;
078    private boolean enableAudit = true;
079    private int maxPageSize = MAX_PAGE_SIZE;
080    private int maxBrowsePageSize = MAX_BROWSE_PAGE_SIZE;
081    private boolean useCache = true;
082    private int minimumMessageSize = 1024;
083    private boolean lazyDispatch = false;
084    private boolean advisoryForSlowConsumers;
085    private boolean advisoryForFastProducers;
086    private boolean advisoryForDiscardingMessages;
087    private boolean advisoryWhenFull;
088    private boolean advisoryForDelivery;
089    private boolean advisoryForConsumed;
090    private boolean sendAdvisoryIfNoConsumers;
091    private boolean includeBodyForAdvisory;
092    protected final DestinationStatistics destinationStatistics = new DestinationStatistics();
093    protected final BrokerService brokerService;
094    protected final Broker regionBroker;
095    protected DeadLetterStrategy deadLetterStrategy = DEFAULT_DEAD_LETTER_STRATEGY;
096    protected long expireMessagesPeriod = EXPIRE_MESSAGE_PERIOD;
097    private int maxExpirePageSize = MAX_BROWSE_PAGE_SIZE;
098    protected int cursorMemoryHighWaterMark = 70;
099    protected int storeUsageHighWaterMark = 100;
100    private SlowConsumerStrategy slowConsumerStrategy;
101    private boolean prioritizedMessages;
102    private long inactiveTimeoutBeforeGC = DEFAULT_INACTIVE_TIMEOUT_BEFORE_GC;
103    private boolean gcIfInactive;
104    private boolean gcWithNetworkConsumers;
105    private long lastActiveTime=0l;
106    private boolean reduceMemoryFootprint = false;
107    protected final Scheduler scheduler;
108    private boolean disposed = false;
109    private boolean doOptimzeMessageStorage = true;
110    /*
111     * percentage of in-flight messages above which optimize message store is disabled
112     */
113    private int optimizeMessageStoreInFlightLimit = 10;
114    private boolean persistJMSRedelivered;
115
116    /**
117     * @param brokerService
118     * @param store
119     * @param destination
120     * @param parentStats
121     * @throws Exception
122     */
123    public BaseDestination(BrokerService brokerService, MessageStore store, ActiveMQDestination destination, DestinationStatistics parentStats) throws Exception {
124        this.brokerService = brokerService;
125        this.broker = brokerService.getBroker();
126        this.store = store;
127        this.destination = destination;
128        // let's copy the enabled property from the parent DestinationStatistics
129        this.destinationStatistics.setEnabled(parentStats.isEnabled());
130        this.destinationStatistics.setParent(parentStats);
131        this.systemUsage = new SystemUsage(brokerService.getProducerSystemUsage(), destination.toString());
132        this.memoryUsage = this.systemUsage.getMemoryUsage();
133        this.memoryUsage.setUsagePortion(1.0f);
134        this.regionBroker = brokerService.getRegionBroker();
135        this.scheduler = brokerService.getBroker().getScheduler();
136    }
137
138    /**
139     * initialize the destination
140     *
141     * @throws Exception
142     */
143    public void initialize() throws Exception {
144        // Let the store know what usage manager we are using so that he can
145        // flush messages to disk when usage gets high.
146        if (store != null) {
147            store.setMemoryUsage(this.memoryUsage);
148        }
149    }
150
151    /**
152     * @return the producerFlowControl
153     */
154    @Override
155    public boolean isProducerFlowControl() {
156        return producerFlowControl;
157    }
158
159    /**
160     * @param producerFlowControl the producerFlowControl to set
161     */
162    @Override
163    public void setProducerFlowControl(boolean producerFlowControl) {
164        this.producerFlowControl = producerFlowControl;
165    }
166
167    @Override
168    public boolean isAlwaysRetroactive() {
169        return alwaysRetroactive;
170    }
171
172    @Override
173    public void setAlwaysRetroactive(boolean alwaysRetroactive) {
174        this.alwaysRetroactive = alwaysRetroactive;
175    }
176
177    /**
178     * Set's the interval at which warnings about producers being blocked by
179     * resource usage will be triggered. Values of 0 or less will disable
180     * warnings
181     *
182     * @param blockedProducerWarningInterval the interval at which warning about
183     *            blocked producers will be triggered.
184     */
185    @Override
186    public void setBlockedProducerWarningInterval(long blockedProducerWarningInterval) {
187        this.blockedProducerWarningInterval = blockedProducerWarningInterval;
188    }
189
190    /**
191     *
192     * @return the interval at which warning about blocked producers will be
193     *         triggered.
194     */
195    @Override
196    public long getBlockedProducerWarningInterval() {
197        return blockedProducerWarningInterval;
198    }
199
200    /**
201     * @return the maxProducersToAudit
202     */
203    @Override
204    public int getMaxProducersToAudit() {
205        return maxProducersToAudit;
206    }
207
208    /**
209     * @param maxProducersToAudit the maxProducersToAudit to set
210     */
211    @Override
212    public void setMaxProducersToAudit(int maxProducersToAudit) {
213        this.maxProducersToAudit = maxProducersToAudit;
214    }
215
216    /**
217     * @return the maxAuditDepth
218     */
219    @Override
220    public int getMaxAuditDepth() {
221        return maxAuditDepth;
222    }
223
224    /**
225     * @param maxAuditDepth the maxAuditDepth to set
226     */
227    @Override
228    public void setMaxAuditDepth(int maxAuditDepth) {
229        this.maxAuditDepth = maxAuditDepth;
230    }
231
232    /**
233     * @return the enableAudit
234     */
235    @Override
236    public boolean isEnableAudit() {
237        return enableAudit;
238    }
239
240    /**
241     * @param enableAudit the enableAudit to set
242     */
243    @Override
244    public void setEnableAudit(boolean enableAudit) {
245        this.enableAudit = enableAudit;
246    }
247
248    @Override
249    public void addProducer(ConnectionContext context, ProducerInfo info) throws Exception {
250        destinationStatistics.getProducers().increment();
251        this.lastActiveTime=0l;
252    }
253
254    @Override
255    public void removeProducer(ConnectionContext context, ProducerInfo info) throws Exception {
256        destinationStatistics.getProducers().decrement();
257    }
258
259    @Override
260    public void addSubscription(ConnectionContext context, Subscription sub) throws Exception{
261        destinationStatistics.getConsumers().increment();
262        this.lastActiveTime=0l;
263    }
264
265    @Override
266    public void removeSubscription(ConnectionContext context, Subscription sub, long lastDeliveredSequenceId) throws Exception{
267        destinationStatistics.getConsumers().decrement();
268        this.lastActiveTime=0l;
269    }
270
271
272    @Override
273    public final MemoryUsage getMemoryUsage() {
274        return memoryUsage;
275    }
276
277    @Override
278    public void setMemoryUsage(MemoryUsage memoryUsage) {
279        this.memoryUsage = memoryUsage;
280    }
281
282    @Override
283    public TempUsage getTempUsage() {
284        return systemUsage.getTempUsage();
285    }
286
287    @Override
288    public DestinationStatistics getDestinationStatistics() {
289        return destinationStatistics;
290    }
291
292    @Override
293    public ActiveMQDestination getActiveMQDestination() {
294        return destination;
295    }
296
297    @Override
298    public final String getName() {
299        return getActiveMQDestination().getPhysicalName();
300    }
301
302    @Override
303    public final MessageStore getMessageStore() {
304        return store;
305    }
306
307    @Override
308    public boolean isActive() {
309        boolean isActive = destinationStatistics.getConsumers().getCount() > 0 ||
310                           destinationStatistics.getProducers().getCount() > 0;
311        if (isActive && isGcWithNetworkConsumers() && destinationStatistics.getConsumers().getCount() > 0) {
312            isActive = hasRegularConsumers(getConsumers());
313        }
314        return isActive;
315    }
316
317    @Override
318    public int getMaxPageSize() {
319        return maxPageSize;
320    }
321
322    @Override
323    public void setMaxPageSize(int maxPageSize) {
324        this.maxPageSize = maxPageSize;
325    }
326
327    @Override
328    public int getMaxBrowsePageSize() {
329        return this.maxBrowsePageSize;
330    }
331
332    @Override
333    public void setMaxBrowsePageSize(int maxPageSize) {
334        this.maxBrowsePageSize = maxPageSize;
335    }
336
337    public int getMaxExpirePageSize() {
338        return this.maxExpirePageSize;
339    }
340
341    public void setMaxExpirePageSize(int maxPageSize) {
342        this.maxExpirePageSize = maxPageSize;
343    }
344
345    public void setExpireMessagesPeriod(long expireMessagesPeriod) {
346        this.expireMessagesPeriod = expireMessagesPeriod;
347    }
348
349    public long getExpireMessagesPeriod() {
350        return expireMessagesPeriod;
351    }
352
353    @Override
354    public boolean isUseCache() {
355        return useCache;
356    }
357
358    @Override
359    public void setUseCache(boolean useCache) {
360        this.useCache = useCache;
361    }
362
363    @Override
364    public int getMinimumMessageSize() {
365        return minimumMessageSize;
366    }
367
368    @Override
369    public void setMinimumMessageSize(int minimumMessageSize) {
370        this.minimumMessageSize = minimumMessageSize;
371    }
372
373    @Override
374    public boolean isLazyDispatch() {
375        return lazyDispatch;
376    }
377
378    @Override
379    public void setLazyDispatch(boolean lazyDispatch) {
380        this.lazyDispatch = lazyDispatch;
381    }
382
383    protected long getDestinationSequenceId() {
384        return regionBroker.getBrokerSequenceId();
385    }
386
387    /**
388     * @return the advisoryForSlowConsumers
389     */
390    public boolean isAdvisoryForSlowConsumers() {
391        return advisoryForSlowConsumers;
392    }
393
394    /**
395     * @param advisoryForSlowConsumers the advisoryForSlowConsumers to set
396     */
397    public void setAdvisoryForSlowConsumers(boolean advisoryForSlowConsumers) {
398        this.advisoryForSlowConsumers = advisoryForSlowConsumers;
399    }
400
401    /**
402     * @return the advisoryForDiscardingMessages
403     */
404    public boolean isAdvisoryForDiscardingMessages() {
405        return advisoryForDiscardingMessages;
406    }
407
408    /**
409     * @param advisoryForDiscardingMessages the advisoryForDiscardingMessages to
410     *            set
411     */
412    public void setAdvisoryForDiscardingMessages(boolean advisoryForDiscardingMessages) {
413        this.advisoryForDiscardingMessages = advisoryForDiscardingMessages;
414    }
415
416    /**
417     * @return the advisoryWhenFull
418     */
419    public boolean isAdvisoryWhenFull() {
420        return advisoryWhenFull;
421    }
422
423    /**
424     * @param advisoryWhenFull the advisoryWhenFull to set
425     */
426    public void setAdvisoryWhenFull(boolean advisoryWhenFull) {
427        this.advisoryWhenFull = advisoryWhenFull;
428    }
429
430    /**
431     * @return the advisoryForDelivery
432     */
433    public boolean isAdvisoryForDelivery() {
434        return advisoryForDelivery;
435    }
436
437    /**
438     * @param advisoryForDelivery the advisoryForDelivery to set
439     */
440    public void setAdvisoryForDelivery(boolean advisoryForDelivery) {
441        this.advisoryForDelivery = advisoryForDelivery;
442    }
443
444    /**
445     * @return the advisoryForConsumed
446     */
447    public boolean isAdvisoryForConsumed() {
448        return advisoryForConsumed;
449    }
450
451    /**
452     * @param advisoryForConsumed the advisoryForConsumed to set
453     */
454    public void setAdvisoryForConsumed(boolean advisoryForConsumed) {
455        this.advisoryForConsumed = advisoryForConsumed;
456    }
457
458    /**
459     * @return the advisdoryForFastProducers
460     */
461    public boolean isAdvisoryForFastProducers() {
462        return advisoryForFastProducers;
463    }
464
465    /**
466     * @param advisoryForFastProducers the advisdoryForFastProducers to set
467     */
468    public void setAdvisoryForFastProducers(boolean advisoryForFastProducers) {
469        this.advisoryForFastProducers = advisoryForFastProducers;
470    }
471
472    public boolean isSendAdvisoryIfNoConsumers() {
473        return sendAdvisoryIfNoConsumers;
474    }
475
476    public void setSendAdvisoryIfNoConsumers(boolean sendAdvisoryIfNoConsumers) {
477        this.sendAdvisoryIfNoConsumers = sendAdvisoryIfNoConsumers;
478    }
479
480    public boolean isIncludeBodyForAdvisory() {
481        return includeBodyForAdvisory;
482    }
483
484    public void setIncludeBodyForAdvisory(boolean includeBodyForAdvisory) {
485        this.includeBodyForAdvisory = includeBodyForAdvisory;
486    }
487
488    /**
489     * @return the dead letter strategy
490     */
491    @Override
492    public DeadLetterStrategy getDeadLetterStrategy() {
493        return deadLetterStrategy;
494    }
495
496    /**
497     * set the dead letter strategy
498     *
499     * @param deadLetterStrategy
500     */
501    public void setDeadLetterStrategy(DeadLetterStrategy deadLetterStrategy) {
502        this.deadLetterStrategy = deadLetterStrategy;
503    }
504
505    @Override
506    public int getCursorMemoryHighWaterMark() {
507        return this.cursorMemoryHighWaterMark;
508    }
509
510    @Override
511    public void setCursorMemoryHighWaterMark(int cursorMemoryHighWaterMark) {
512        this.cursorMemoryHighWaterMark = cursorMemoryHighWaterMark;
513    }
514
515    /**
516     * called when message is consumed
517     *
518     * @param context
519     * @param messageReference
520     */
521    @Override
522    public void messageConsumed(ConnectionContext context, MessageReference messageReference) {
523        if (advisoryForConsumed) {
524            broker.messageConsumed(context, messageReference);
525        }
526    }
527
528    /**
529     * Called when message is delivered to the broker
530     *
531     * @param context
532     * @param messageReference
533     */
534    @Override
535    public void messageDelivered(ConnectionContext context, MessageReference messageReference) {
536        this.lastActiveTime = 0L;
537        if (advisoryForDelivery) {
538            broker.messageDelivered(context, messageReference);
539        }
540    }
541
542    /**
543     * Called when a message is discarded - e.g. running low on memory This will
544     * happen only if the policy is enabled - e.g. non durable topics
545     *
546     * @param context
547     * @param messageReference
548     */
549    @Override
550    public void messageDiscarded(ConnectionContext context, Subscription sub, MessageReference messageReference) {
551        if (advisoryForDiscardingMessages) {
552            broker.messageDiscarded(context, sub, messageReference);
553        }
554    }
555
556    /**
557     * Called when there is a slow consumer
558     *
559     * @param context
560     * @param subs
561     */
562    @Override
563    public void slowConsumer(ConnectionContext context, Subscription subs) {
564        if (advisoryForSlowConsumers) {
565            broker.slowConsumer(context, this, subs);
566        }
567        if (slowConsumerStrategy != null) {
568            slowConsumerStrategy.slowConsumer(context, subs);
569        }
570    }
571
572    /**
573     * Called to notify a producer is too fast
574     *
575     * @param context
576     * @param producerInfo
577     */
578    @Override
579    public void fastProducer(ConnectionContext context, ProducerInfo producerInfo) {
580        if (advisoryForFastProducers) {
581            broker.fastProducer(context, producerInfo, getActiveMQDestination());
582        }
583    }
584
585    /**
586     * Called when a Usage reaches a limit
587     *
588     * @param context
589     * @param usage
590     */
591    @Override
592    public void isFull(ConnectionContext context, Usage<?> usage) {
593        if (advisoryWhenFull) {
594            broker.isFull(context, this, usage);
595        }
596    }
597
598    @Override
599    public void dispose(ConnectionContext context) throws IOException {
600        if (this.store != null) {
601            this.store.removeAllMessages(context);
602            this.store.dispose(context);
603        }
604        this.destinationStatistics.setParent(null);
605        this.memoryUsage.stop();
606        this.disposed = true;
607    }
608
609    @Override
610    public boolean isDisposed() {
611        return this.disposed;
612    }
613
614    /**
615     * Provides a hook to allow messages with no consumer to be processed in
616     * some way - such as to send to a dead letter queue or something..
617     */
618    protected void onMessageWithNoConsumers(ConnectionContext context, Message msg) throws Exception {
619        if (!msg.isPersistent()) {
620            if (isSendAdvisoryIfNoConsumers()) {
621                // allow messages with no consumers to be dispatched to a dead
622                // letter queue
623                if (destination.isQueue() || !AdvisorySupport.isAdvisoryTopic(destination)) {
624
625                    Message message = msg.copy();
626                    // The original destination and transaction id do not get
627                    // filled when the message is first sent,
628                    // it is only populated if the message is routed to another
629                    // destination like the DLQ
630                    if (message.getOriginalDestination() != null) {
631                        message.setOriginalDestination(message.getDestination());
632                    }
633                    if (message.getOriginalTransactionId() != null) {
634                        message.setOriginalTransactionId(message.getTransactionId());
635                    }
636
637                    ActiveMQTopic advisoryTopic;
638                    if (destination.isQueue()) {
639                        advisoryTopic = AdvisorySupport.getNoQueueConsumersAdvisoryTopic(destination);
640                    } else {
641                        advisoryTopic = AdvisorySupport.getNoTopicConsumersAdvisoryTopic(destination);
642                    }
643                    message.setDestination(advisoryTopic);
644                    message.setTransactionId(null);
645
646                    // Disable flow control for this since since we don't want
647                    // to block.
648                    boolean originalFlowControl = context.isProducerFlowControl();
649                    try {
650                        context.setProducerFlowControl(false);
651                        ProducerBrokerExchange producerExchange = new ProducerBrokerExchange();
652                        producerExchange.setMutable(false);
653                        producerExchange.setConnectionContext(context);
654                        producerExchange.setProducerState(new ProducerState(new ProducerInfo()));
655                        context.getBroker().send(producerExchange, message);
656                    } finally {
657                        context.setProducerFlowControl(originalFlowControl);
658                    }
659
660                }
661            }
662        }
663    }
664
665    @Override
666    public void processDispatchNotification(MessageDispatchNotification messageDispatchNotification) throws Exception {
667    }
668
669    public final int getStoreUsageHighWaterMark() {
670        return this.storeUsageHighWaterMark;
671    }
672
673    public void setStoreUsageHighWaterMark(int storeUsageHighWaterMark) {
674        this.storeUsageHighWaterMark = storeUsageHighWaterMark;
675    }
676
677    protected final void waitForSpace(ConnectionContext context,ProducerBrokerExchange producerBrokerExchange, Usage<?> usage, String warning) throws IOException, InterruptedException, ResourceAllocationException {
678        waitForSpace(context, producerBrokerExchange, usage, 100, warning);
679    }
680
681    protected final void waitForSpace(ConnectionContext context, ProducerBrokerExchange producerBrokerExchange, Usage<?> usage, int highWaterMark, String warning) throws IOException, InterruptedException, ResourceAllocationException {
682        if (!context.isNetworkConnection() && systemUsage.isSendFailIfNoSpace()) {
683            if (isFlowControlLogRequired()) {
684                getLog().info("sendFailIfNoSpace, forcing exception on send, usage: {}: {}", usage, warning);
685            } else {
686                getLog().debug("sendFailIfNoSpace, forcing exception on send, usage: {}: {}", usage, warning);
687            }
688            throw new ResourceAllocationException(warning);
689        }
690        if (!context.isNetworkConnection() && systemUsage.getSendFailIfNoSpaceAfterTimeout() != 0) {
691            if (!usage.waitForSpace(systemUsage.getSendFailIfNoSpaceAfterTimeout(), highWaterMark)) {
692                if (isFlowControlLogRequired()) {
693                    getLog().info("sendFailIfNoSpaceAfterTimeout expired, forcing exception on send, usage: {}: {}", usage, warning);
694                } else {
695                    getLog().debug("sendFailIfNoSpaceAfterTimeout expired, forcing exception on send, usage: {}: {}", usage, warning);
696                }
697                throw new ResourceAllocationException(warning);
698            }
699        } else {
700            long start = System.currentTimeMillis();
701            producerBrokerExchange.blockingOnFlowControl(true);
702            destinationStatistics.getBlockedSends().increment();
703            while (!usage.waitForSpace(1000, highWaterMark)) {
704                if (context.getStopping().get()) {
705                    throw new IOException("Connection closed, send aborted.");
706                }
707
708                if (isFlowControlLogRequired()) {
709                    getLog().warn("{}: {} (blocking for: {}s)", new Object[]{ usage, warning, new Long(((System.currentTimeMillis() - start) / 1000))});
710                } else {
711                    getLog().debug("{}: {} (blocking for: {}s)", new Object[]{ usage, warning, new Long(((System.currentTimeMillis() - start) / 1000))});
712                }
713            }
714            long finish = System.currentTimeMillis();
715            long totalTimeBlocked = finish - start;
716            destinationStatistics.getBlockedTime().addTime(totalTimeBlocked);
717            producerBrokerExchange.incrementTimeBlocked(this,totalTimeBlocked);
718            producerBrokerExchange.blockingOnFlowControl(false);
719        }
720    }
721
722    protected boolean isFlowControlLogRequired() {
723        boolean answer = false;
724        if (blockedProducerWarningInterval > 0) {
725            long now = System.currentTimeMillis();
726            if (lastBlockedProducerWarnTime + blockedProducerWarningInterval <= now) {
727                lastBlockedProducerWarnTime = now;
728                answer = true;
729            }
730        }
731        return answer;
732    }
733
734    protected abstract Logger getLog();
735
736    public void setSlowConsumerStrategy(SlowConsumerStrategy slowConsumerStrategy) {
737        this.slowConsumerStrategy = slowConsumerStrategy;
738    }
739
740    @Override
741    public SlowConsumerStrategy getSlowConsumerStrategy() {
742        return this.slowConsumerStrategy;
743    }
744
745
746    @Override
747    public boolean isPrioritizedMessages() {
748        return this.prioritizedMessages;
749    }
750
751    public void setPrioritizedMessages(boolean prioritizedMessages) {
752        this.prioritizedMessages = prioritizedMessages;
753        if (store != null) {
754            store.setPrioritizedMessages(prioritizedMessages);
755        }
756    }
757
758    /**
759     * @return the inactiveTimeoutBeforeGC
760     */
761    @Override
762    public long getInactiveTimeoutBeforeGC() {
763        return this.inactiveTimeoutBeforeGC;
764    }
765
766    /**
767     * @param inactiveTimeoutBeforeGC the inactiveTimeoutBeforeGC to set
768     */
769    public void setInactiveTimeoutBeforeGC(long inactiveTimeoutBeforeGC) {
770        this.inactiveTimeoutBeforeGC = inactiveTimeoutBeforeGC;
771    }
772
773    /**
774     * @return the gcIfInactive
775     */
776    public boolean isGcIfInactive() {
777        return this.gcIfInactive;
778    }
779
780    /**
781     * @param gcIfInactive the gcIfInactive to set
782     */
783    public void setGcIfInactive(boolean gcIfInactive) {
784        this.gcIfInactive = gcIfInactive;
785    }
786
787    /**
788     * Indicate if it is ok to gc destinations that have only network consumers
789     * @param gcWithNetworkConsumers
790     */
791    public void setGcWithNetworkConsumers(boolean gcWithNetworkConsumers) {
792        this.gcWithNetworkConsumers = gcWithNetworkConsumers;
793    }
794
795    public boolean isGcWithNetworkConsumers() {
796        return gcWithNetworkConsumers;
797    }
798
799    @Override
800    public void markForGC(long timeStamp) {
801        if (isGcIfInactive() && this.lastActiveTime == 0 && isActive() == false
802                && destinationStatistics.messages.getCount() == 0 && getInactiveTimeoutBeforeGC() > 0l) {
803            this.lastActiveTime = timeStamp;
804        }
805    }
806
807    @Override
808    public boolean canGC() {
809        boolean result = false;
810        final long currentLastActiveTime = this.lastActiveTime;
811        if (isGcIfInactive() && currentLastActiveTime != 0l && destinationStatistics.messages.getCount() == 0L ) {
812            if ((System.currentTimeMillis() - currentLastActiveTime) >= getInactiveTimeoutBeforeGC()) {
813                result = true;
814            }
815        }
816        return result;
817    }
818
819    public void setReduceMemoryFootprint(boolean reduceMemoryFootprint) {
820        this.reduceMemoryFootprint = reduceMemoryFootprint;
821    }
822
823    public boolean isReduceMemoryFootprint() {
824        return this.reduceMemoryFootprint;
825    }
826
827    @Override
828    public boolean isDoOptimzeMessageStorage() {
829        return doOptimzeMessageStorage;
830    }
831
832    @Override
833    public void setDoOptimzeMessageStorage(boolean doOptimzeMessageStorage) {
834        this.doOptimzeMessageStorage = doOptimzeMessageStorage;
835    }
836
837    public int getOptimizeMessageStoreInFlightLimit() {
838        return optimizeMessageStoreInFlightLimit;
839    }
840
841    public void setOptimizeMessageStoreInFlightLimit(int optimizeMessageStoreInFlightLimit) {
842        this.optimizeMessageStoreInFlightLimit = optimizeMessageStoreInFlightLimit;
843    }
844
845
846    @Override
847    public abstract List<Subscription> getConsumers();
848
849    protected boolean hasRegularConsumers(List<Subscription> consumers) {
850        boolean hasRegularConsumers = false;
851        for (Subscription subscription: consumers) {
852            if (!subscription.getConsumerInfo().isNetworkSubscription()) {
853                hasRegularConsumers = true;
854                break;
855            }
856        }
857        return hasRegularConsumers;
858    }
859
860    public ConnectionContext createConnectionContext() {
861        ConnectionContext answer = new ConnectionContext();
862        answer.setBroker(this.broker);
863        answer.getMessageEvaluationContext().setDestination(getActiveMQDestination());
864        answer.setSecurityContext(SecurityContext.BROKER_SECURITY_CONTEXT);
865        return answer;
866    }
867
868    protected MessageAck convertToNonRangedAck(MessageAck ack, MessageReference node) {
869        // the original ack may be a ranged ack, but we are trying to delete
870        // a specific
871        // message store here so we need to convert to a non ranged ack.
872        if (ack.getMessageCount() > 0) {
873            // Dup the ack
874            MessageAck a = new MessageAck();
875            ack.copy(a);
876            ack = a;
877            // Convert to non-ranged.
878            ack.setMessageCount(1);
879        }
880        // always use node messageId so we can access entry/data Location
881        ack.setFirstMessageId(node.getMessageId());
882        ack.setLastMessageId(node.getMessageId());
883        return ack;
884    }
885
886    protected boolean isDLQ() {
887        return destination.isDLQ();
888    }
889
890    @Override
891    public void duplicateFromStore(Message message, Subscription subscription) {
892        ConnectionContext connectionContext = createConnectionContext();
893        getLog().warn("{}{}, redirecting {} for dlq processing", DUPLICATE_FROM_STORE_MSG_PREFIX, destination, message.getMessageId());
894        Throwable cause = new Throwable(DUPLICATE_FROM_STORE_MSG_PREFIX + destination);
895        message.setRegionDestination(this);
896        broker.getRoot().sendToDeadLetterQueue(connectionContext, message, null, cause);
897        MessageAck messageAck = new MessageAck(message, MessageAck.POISON_ACK_TYPE, 1);
898        messageAck.setPoisonCause(cause);
899        try {
900            acknowledge(connectionContext, subscription, messageAck, message);
901        } catch (IOException e) {
902            getLog().error("Failed to acknowledge duplicate message {} from {} with {}", message.getMessageId(), destination, messageAck);
903        }
904    }
905
906    public void setPersistJMSRedelivered(boolean persistJMSRedelivered) {
907        this.persistJMSRedelivered = persistJMSRedelivered;
908    }
909
910    public boolean isPersistJMSRedelivered() {
911        return persistJMSRedelivered;
912    }
913
914    public SystemUsage getSystemUsage() {
915        return systemUsage;
916    }
917}