/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.activemq.broker.region.cursors; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Set; import org.apache.activemq.ActiveMQMessageAudit; import org.apache.activemq.broker.Broker; import org.apache.activemq.broker.ConnectionContext; import org.apache.activemq.broker.region.BaseDestination; import org.apache.activemq.broker.region.Destination; import org.apache.activemq.broker.region.MessageReference; import org.apache.activemq.broker.region.Subscription; import org.apache.activemq.command.MessageId; import org.apache.activemq.usage.SystemUsage; /** * Abstract method holder for pending message (messages awaiting disptach to a * consumer) cursor * * */ public abstract class AbstractPendingMessageCursor implements PendingMessageCursor { protected int memoryUsageHighWaterMark = 70; protected int maxBatchSize = BaseDestination.MAX_PAGE_SIZE; protected SystemUsage systemUsage; protected int maxProducersToAudit = BaseDestination.MAX_PRODUCERS_TO_AUDIT; protected int maxAuditDepth = BaseDestination.MAX_AUDIT_DEPTH; protected boolean enableAudit=true; protected ActiveMQMessageAudit audit; protected boolean useCache=true; private boolean cacheEnabled=true; private boolean started=false; protected MessageReference last = null; protected final boolean prioritizedMessages; public AbstractPendingMessageCursor(boolean prioritizedMessages) { this.prioritizedMessages=prioritizedMessages; } @Override public synchronized void start() throws Exception { if (!started && enableAudit && audit==null) { audit= new ActiveMQMessageAudit(maxAuditDepth,maxProducersToAudit); } started=true; } @Override public synchronized void stop() throws Exception { started=false; gc(); } @Override public void add(ConnectionContext context, Destination destination) throws Exception { } @Override @SuppressWarnings("unchecked") public List<MessageReference> remove(ConnectionContext context, Destination destination) throws Exception { return Collections.EMPTY_LIST; } @Override public boolean isRecoveryRequired() { return true; } @Override public void addMessageFirst(MessageReference node) throws Exception { } @Override public boolean addMessageLast(MessageReference node) throws Exception { return tryAddMessageLast(node, INFINITE_WAIT); } @Override public boolean tryAddMessageLast(MessageReference node, long maxWaitTime) throws Exception { return true; } @Override public void addRecoveredMessage(MessageReference node) throws Exception { addMessageLast(node); } @Override public void clear() { } @Override public boolean hasNext() { return false; } @Override public boolean isEmpty() { return false; } @Override public boolean isEmpty(Destination destination) { return isEmpty(); } @Override public MessageReference next() { return null; } @Override public void remove() { } @Override public void reset() { } @Override public int size() { return 0; } @Override public int getMaxBatchSize() { return maxBatchSize; } @Override public void setMaxBatchSize(int maxBatchSize) { this.maxBatchSize = maxBatchSize; } protected void fillBatch() throws Exception { } @Override public void resetForGC() { reset(); } @Override public void remove(MessageReference node) { } @Override public void gc() { } @Override public void setSystemUsage(SystemUsage usageManager) { this.systemUsage = usageManager; } @Override public boolean hasSpace() { // allow isFull to verify parent usage and otherwise enforce local memoryUsageHighWaterMark return systemUsage != null ? (!isFull() && systemUsage.getMemoryUsage().getPercentUsage() < memoryUsageHighWaterMark) : true; } @Override public boolean isFull() { return systemUsage != null ? systemUsage.getMemoryUsage().isFull() : false; } @Override public void release() { } @Override public boolean hasMessagesBufferedToDeliver() { return false; } /** * @return the memoryUsageHighWaterMark */ @Override public int getMemoryUsageHighWaterMark() { return memoryUsageHighWaterMark; } /** * @param memoryUsageHighWaterMark the memoryUsageHighWaterMark to set */ @Override public void setMemoryUsageHighWaterMark(int memoryUsageHighWaterMark) { this.memoryUsageHighWaterMark = memoryUsageHighWaterMark; } /** * @return the usageManager */ @Override public SystemUsage getSystemUsage() { return this.systemUsage; } /** * destroy the cursor * * @throws Exception */ @Override public void destroy() throws Exception { stop(); } /** * Page in a restricted number of messages * * @param maxItems maximum number of messages to return * @return a list of paged in messages */ @Override public LinkedList<MessageReference> pageInList(int maxItems) { throw new RuntimeException("Not supported"); } /** * @return the maxProducersToAudit */ @Override public int getMaxProducersToAudit() { return maxProducersToAudit; } /** * @param maxProducersToAudit the maxProducersToAudit to set */ @Override public synchronized void setMaxProducersToAudit(int maxProducersToAudit) { this.maxProducersToAudit = maxProducersToAudit; if (audit != null) { audit.setMaximumNumberOfProducersToTrack(maxProducersToAudit); } } /** * @return the maxAuditDepth */ @Override public int getMaxAuditDepth() { return maxAuditDepth; } /** * @param maxAuditDepth the maxAuditDepth to set */ @Override public synchronized void setMaxAuditDepth(int maxAuditDepth) { this.maxAuditDepth = maxAuditDepth; if (audit != null) { audit.setAuditDepth(maxAuditDepth); } } /** * @return the enableAudit */ @Override public boolean isEnableAudit() { return enableAudit; } /** * @param enableAudit the enableAudit to set */ @Override public synchronized void setEnableAudit(boolean enableAudit) { this.enableAudit = enableAudit; if (enableAudit && started && audit==null) { audit= new ActiveMQMessageAudit(maxAuditDepth,maxProducersToAudit); } } @Override public boolean isTransient() { return false; } /** * set the audit * @param audit new audit component */ @Override public void setMessageAudit(ActiveMQMessageAudit audit) { this.audit=audit; } /** * @return the audit */ @Override public ActiveMQMessageAudit getMessageAudit() { return audit; } @Override public boolean isUseCache() { return useCache; } @Override public void setUseCache(boolean useCache) { this.useCache = useCache; } public synchronized boolean isDuplicate(MessageId messageId) { boolean unique = recordUniqueId(messageId); rollback(messageId); return !unique; } /** * records a message id and checks if it is a duplicate * @param messageId * @return true if id is unique, false otherwise. */ public synchronized boolean recordUniqueId(MessageId messageId) { if (!enableAudit || audit==null) { return true; } return !audit.isDuplicate(messageId); } @Override public synchronized void rollback(MessageId id) { if (audit != null) { audit.rollback(id); } } public synchronized boolean isStarted() { return started; } public static boolean isPrioritizedMessageSubscriber(Broker broker,Subscription sub) { boolean result = false; Set<Destination> destinations = broker.getDestinations(sub.getActiveMQDestination()); if (destinations != null) { for (Destination dest:destinations) { if (dest.isPrioritizedMessages()) { result = true; break; } } } return result; } @Override public synchronized boolean isCacheEnabled() { return cacheEnabled; } public synchronized void setCacheEnabled(boolean val) { cacheEnabled = val; } @Override public void rebase() { } }