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.cursors; 018 019import java.util.Collections; 020import java.util.LinkedList; 021import java.util.List; 022import java.util.Set; 023import org.apache.activemq.ActiveMQMessageAudit; 024import org.apache.activemq.broker.Broker; 025import org.apache.activemq.broker.ConnectionContext; 026import org.apache.activemq.broker.region.BaseDestination; 027import org.apache.activemq.broker.region.Destination; 028import org.apache.activemq.broker.region.MessageReference; 029import org.apache.activemq.broker.region.Subscription; 030import org.apache.activemq.command.MessageId; 031import org.apache.activemq.usage.SystemUsage; 032 033/** 034 * Abstract method holder for pending message (messages awaiting disptach to a 035 * consumer) cursor 036 * 037 * 038 */ 039public abstract class AbstractPendingMessageCursor implements PendingMessageCursor { 040 protected int memoryUsageHighWaterMark = 70; 041 protected int maxBatchSize = BaseDestination.MAX_PAGE_SIZE; 042 protected SystemUsage systemUsage; 043 protected int maxProducersToAudit = BaseDestination.MAX_PRODUCERS_TO_AUDIT; 044 protected int maxAuditDepth = BaseDestination.MAX_AUDIT_DEPTH; 045 protected boolean enableAudit=true; 046 protected ActiveMQMessageAudit audit; 047 protected boolean useCache=true; 048 private boolean cacheEnabled=true; 049 private boolean started=false; 050 protected MessageReference last = null; 051 protected final boolean prioritizedMessages; 052 053 public AbstractPendingMessageCursor(boolean prioritizedMessages) { 054 this.prioritizedMessages=prioritizedMessages; 055 } 056 057 058 @Override 059 public synchronized void start() throws Exception { 060 if (!started && enableAudit && audit==null) { 061 audit= new ActiveMQMessageAudit(maxAuditDepth,maxProducersToAudit); 062 } 063 started=true; 064 } 065 066 @Override 067 public synchronized void stop() throws Exception { 068 started=false; 069 gc(); 070 } 071 072 @Override 073 public void add(ConnectionContext context, Destination destination) throws Exception { 074 } 075 076 @Override 077 @SuppressWarnings("unchecked") 078 public List<MessageReference> remove(ConnectionContext context, Destination destination) throws Exception { 079 return Collections.EMPTY_LIST; 080 } 081 082 @Override 083 public boolean isRecoveryRequired() { 084 return true; 085 } 086 087 @Override 088 public void addMessageFirst(MessageReference node) throws Exception { 089 } 090 091 @Override 092 public boolean addMessageLast(MessageReference node) throws Exception { 093 return tryAddMessageLast(node, INFINITE_WAIT); 094 } 095 096 @Override 097 public boolean tryAddMessageLast(MessageReference node, long maxWaitTime) throws Exception { 098 return true; 099 } 100 101 @Override 102 public void addRecoveredMessage(MessageReference node) throws Exception { 103 addMessageLast(node); 104 } 105 106 @Override 107 public void clear() { 108 } 109 110 @Override 111 public boolean hasNext() { 112 return false; 113 } 114 115 @Override 116 public boolean isEmpty() { 117 return false; 118 } 119 120 @Override 121 public boolean isEmpty(Destination destination) { 122 return isEmpty(); 123 } 124 125 @Override 126 public MessageReference next() { 127 return null; 128 } 129 130 @Override 131 public void remove() { 132 } 133 134 @Override 135 public void reset() { 136 } 137 138 @Override 139 public int size() { 140 return 0; 141 } 142 143 @Override 144 public int getMaxBatchSize() { 145 return maxBatchSize; 146 } 147 148 @Override 149 public void setMaxBatchSize(int maxBatchSize) { 150 this.maxBatchSize = maxBatchSize; 151 } 152 153 protected void fillBatch() throws Exception { 154 } 155 156 @Override 157 public void resetForGC() { 158 reset(); 159 } 160 161 @Override 162 public void remove(MessageReference node) { 163 } 164 165 @Override 166 public void gc() { 167 } 168 169 @Override 170 public void setSystemUsage(SystemUsage usageManager) { 171 this.systemUsage = usageManager; 172 } 173 174 @Override 175 public boolean hasSpace() { 176 // allow isFull to verify parent usage and otherwise enforce local memoryUsageHighWaterMark 177 return systemUsage != null ? (!isParentFull() && systemUsage.getMemoryUsage().getPercentUsage() < memoryUsageHighWaterMark) : true; 178 } 179 180 boolean parentHasSpace(int waterMark) { 181 boolean result = true; 182 if (systemUsage != null) { 183 if (systemUsage.getMemoryUsage().getParent() != null) { 184 return systemUsage.getMemoryUsage().getParent().getPercentUsage() <= waterMark; 185 } 186 } 187 return result; 188 } 189 190 private boolean isParentFull() { 191 boolean result = false; 192 if (systemUsage != null) { 193 if (systemUsage.getMemoryUsage().getParent() != null) { 194 return systemUsage.getMemoryUsage().getParent().getPercentUsage() >= 100; 195 } 196 } 197 return result; 198 } 199 200 @Override 201 public boolean isFull() { 202 return systemUsage != null ? systemUsage.getMemoryUsage().isFull() : false; 203 } 204 205 @Override 206 public void release() { 207 } 208 209 @Override 210 public boolean hasMessagesBufferedToDeliver() { 211 return false; 212 } 213 214 /** 215 * @return the memoryUsageHighWaterMark 216 */ 217 @Override 218 public int getMemoryUsageHighWaterMark() { 219 return memoryUsageHighWaterMark; 220 } 221 222 /** 223 * @param memoryUsageHighWaterMark the memoryUsageHighWaterMark to set 224 */ 225 @Override 226 public void setMemoryUsageHighWaterMark(int memoryUsageHighWaterMark) { 227 this.memoryUsageHighWaterMark = memoryUsageHighWaterMark; 228 } 229 230 /** 231 * @return the usageManager 232 */ 233 @Override 234 public SystemUsage getSystemUsage() { 235 return this.systemUsage; 236 } 237 238 /** 239 * destroy the cursor 240 * 241 * @throws Exception 242 */ 243 @Override 244 public void destroy() throws Exception { 245 stop(); 246 } 247 248 /** 249 * Page in a restricted number of messages 250 * 251 * @param maxItems maximum number of messages to return 252 * @return a list of paged in messages 253 */ 254 @Override 255 public LinkedList<MessageReference> pageInList(int maxItems) { 256 throw new RuntimeException("Not supported"); 257 } 258 259 /** 260 * @return the maxProducersToAudit 261 */ 262 @Override 263 public synchronized int getMaxProducersToAudit() { 264 return maxProducersToAudit; 265 } 266 267 /** 268 * @param maxProducersToAudit the maxProducersToAudit to set 269 */ 270 @Override 271 public synchronized void setMaxProducersToAudit(int maxProducersToAudit) { 272 this.maxProducersToAudit = maxProducersToAudit; 273 if (audit != null) { 274 audit.setMaximumNumberOfProducersToTrack(maxProducersToAudit); 275 } 276 } 277 278 /** 279 * @return the maxAuditDepth 280 */ 281 @Override 282 public synchronized int getMaxAuditDepth() { 283 return maxAuditDepth; 284 } 285 286 287 /** 288 * @param maxAuditDepth the maxAuditDepth to set 289 */ 290 @Override 291 public synchronized void setMaxAuditDepth(int maxAuditDepth) { 292 this.maxAuditDepth = maxAuditDepth; 293 if (audit != null) { 294 audit.setAuditDepth(maxAuditDepth); 295 } 296 } 297 298 299 /** 300 * @return the enableAudit 301 */ 302 @Override 303 public boolean isEnableAudit() { 304 return enableAudit; 305 } 306 307 /** 308 * @param enableAudit the enableAudit to set 309 */ 310 @Override 311 public synchronized void setEnableAudit(boolean enableAudit) { 312 this.enableAudit = enableAudit; 313 if (enableAudit && started && audit==null) { 314 audit= new ActiveMQMessageAudit(maxAuditDepth,maxProducersToAudit); 315 } 316 } 317 318 @Override 319 public boolean isTransient() { 320 return false; 321 } 322 323 324 /** 325 * set the audit 326 * @param audit new audit component 327 */ 328 @Override 329 public void setMessageAudit(ActiveMQMessageAudit audit) { 330 this.audit=audit; 331 } 332 333 334 /** 335 * @return the audit 336 */ 337 @Override 338 public ActiveMQMessageAudit getMessageAudit() { 339 return audit; 340 } 341 342 @Override 343 public boolean isUseCache() { 344 return useCache; 345 } 346 347 @Override 348 public void setUseCache(boolean useCache) { 349 this.useCache = useCache; 350 } 351 352 public synchronized boolean isDuplicate(MessageId messageId) { 353 boolean unique = recordUniqueId(messageId); 354 rollback(messageId); 355 return !unique; 356 } 357 358 /** 359 * records a message id and checks if it is a duplicate 360 * @param messageId 361 * @return true if id is unique, false otherwise. 362 */ 363 public synchronized boolean recordUniqueId(MessageId messageId) { 364 if (!enableAudit || audit==null) { 365 return true; 366 } 367 return !audit.isDuplicate(messageId); 368 } 369 370 @Override 371 public synchronized void rollback(MessageId id) { 372 if (audit != null) { 373 audit.rollback(id); 374 } 375 } 376 377 public synchronized boolean isStarted() { 378 return started; 379 } 380 381 public static boolean isPrioritizedMessageSubscriber(Broker broker,Subscription sub) { 382 boolean result = false; 383 Set<Destination> destinations = broker.getDestinations(sub.getActiveMQDestination()); 384 if (destinations != null) { 385 for (Destination dest:destinations) { 386 if (dest.isPrioritizedMessages()) { 387 result = true; 388 break; 389 } 390 } 391 } 392 return result; 393 394 } 395 396 @Override 397 public synchronized boolean isCacheEnabled() { 398 return cacheEnabled; 399 } 400 401 public synchronized void setCacheEnabled(boolean val) { 402 cacheEnabled = val; 403 } 404 405 @Override 406 public void rebase() { 407 } 408}