53
53
import org .apache .qpid .proton .amqp .Symbol ;
54
54
import org .apache .qpid .proton .amqp .messaging .DeliveryAnnotations ;
55
55
import org .apache .qpid .proton .amqp .messaging .Properties ;
56
+ import org .apache .qpid .proton .amqp .transport .Target ;
56
57
import org .apache .qpid .proton .engine .Sender ;
57
58
import org .slf4j .Logger ;
58
59
import org .slf4j .LoggerFactory ;
@@ -89,9 +90,15 @@ public class AMQPMirrorControllerSource extends BasicMirrorController<Sender> im
89
90
// Capabilities
90
91
public static final Symbol MIRROR_CAPABILITY = Symbol .getSymbol ("amq.mirror" );
91
92
public static final Symbol QPID_DISPATCH_WAYPOINT_CAPABILITY = Symbol .valueOf ("qd.waypoint" );
93
+ public static final Symbol NO_FORWARD = Symbol .getSymbol ("amq.no.forward" );
94
+ public static final Symbol NO_FORWARD_SOURCE = Symbol .getSymbol ("amq.no.forward.source" );
95
+ public static final Symbol RECEIVER_ID_FILTER = Symbol .getSymbol ("amq.receiver.id.filter" );
92
96
93
97
public static final SimpleString INTERNAL_ID_EXTRA_PROPERTY = SimpleString .of (INTERNAL_ID .toString ());
94
98
public static final SimpleString INTERNAL_BROKER_ID_EXTRA_PROPERTY = SimpleString .of (BROKER_ID .toString ());
99
+ public static final SimpleString INTERNAL_NO_FORWARD = SimpleString .of (NO_FORWARD .toString ());
100
+ public static final SimpleString INTERNAL_NO_FORWARD_SOURCE = SimpleString .of (NO_FORWARD_SOURCE .toString ());
101
+ public static final SimpleString INTERNAL_RECEIVER_ID_FILTER = SimpleString .of (RECEIVER_ID_FILTER .toString ());
95
102
96
103
private static final ThreadLocal <RoutingContext > mirrorControlRouting = ThreadLocal .withInitial (() -> new RoutingContextImpl (null ));
97
104
@@ -230,12 +237,17 @@ public void addAddress(AddressInfo addressInfo) throws Exception {
230
237
public void deleteAddress (AddressInfo addressInfo ) throws Exception {
231
238
logger .trace ("{} deleteAddress {}" , server , addressInfo );
232
239
240
+ if (isBlockedByNoForward ()) {
241
+ return ;
242
+ }
243
+
233
244
if (invalidTarget (getControllerInUse ()) || addressInfo .isInternal ()) {
234
245
return ;
235
246
}
236
247
if (ignoreAddress (addressInfo .getName ())) {
237
248
return ;
238
249
}
250
+
239
251
if (deleteQueues ) {
240
252
Message message = createMessage (addressInfo .getName (), null , DELETE_ADDRESS , null , addressInfo .toJSON ());
241
253
routeMirrorCommand (server , message );
@@ -246,6 +258,10 @@ public void deleteAddress(AddressInfo addressInfo) throws Exception {
246
258
public void createQueue (QueueConfiguration queueConfiguration ) throws Exception {
247
259
logger .trace ("{} createQueue {}" , server , queueConfiguration );
248
260
261
+ if (isBlockedByNoForward ()) {
262
+ return ;
263
+ }
264
+
249
265
if (invalidTarget (getControllerInUse ()) || queueConfiguration .isInternal ()) {
250
266
if (logger .isTraceEnabled ()) {
251
267
logger .trace ("Rejecting ping pong on create {} as isInternal={} and mirror target = {}" , queueConfiguration , queueConfiguration .isInternal (), getControllerInUse ());
@@ -264,6 +280,7 @@ public void createQueue(QueueConfiguration queueConfiguration) throws Exception
264
280
}
265
281
return ;
266
282
}
283
+
267
284
if (addQueues ) {
268
285
Message message = createMessage (queueConfiguration .getAddress (), queueConfiguration .getName (), CREATE_QUEUE , null , queueConfiguration .toJSON ());
269
286
routeMirrorCommand (server , message );
@@ -276,6 +293,10 @@ public void deleteQueue(SimpleString address, SimpleString queue) throws Excepti
276
293
logger .trace ("{} deleteQueue {}/{}" , server , address , queue );
277
294
}
278
295
296
+ if (isBlockedByNoForward ()) {
297
+ return ;
298
+ }
299
+
279
300
if (invalidTarget (getControllerInUse ())) {
280
301
return ;
281
302
}
@@ -310,6 +331,14 @@ private boolean invalidTarget(MirrorController controller) {
310
331
return controller != null && sameNode (getRemoteMirrorId (), controller .getRemoteMirrorId ());
311
332
}
312
333
334
+ private boolean isBlockedByNoForward () {
335
+ return getControllerInUse () != null && getControllerInUse ().isNoForward ();
336
+ }
337
+
338
+ private boolean isBlockedByNoForward (Message message ) {
339
+ return isBlockedByNoForward () || Boolean .TRUE .equals (message .getBrokerProperty (INTERNAL_NO_FORWARD ));
340
+ }
341
+
313
342
private boolean ignoreAddress (SimpleString address ) {
314
343
if (address .startsWith (server .getConfiguration ().getManagementAddress ())) {
315
344
return true ;
@@ -338,6 +367,12 @@ Message copyMessageForPaging(Message message) {
338
367
public void sendMessage (Transaction tx , Message message , RoutingContext context ) {
339
368
SimpleString address = context .getAddress (message );
340
369
370
+ if (isBlockedByNoForward (message )) {
371
+ String remoteID = getRemoteMirrorId ();
372
+ logger .trace ("sendMessage::server {} is discarding the message because its source is setting a noForward policy" , server );
373
+ return ;
374
+ }
375
+
341
376
if (context .isInternal ()) {
342
377
logger .trace ("sendMessage::server {} is discarding send to avoid sending to internal queue" , server );
343
378
return ;
@@ -353,6 +388,8 @@ public void sendMessage(Transaction tx, Message message, RoutingContext context)
353
388
return ;
354
389
}
355
390
391
+ logger .trace ("sendMessage::{} send message {}" , server , message );
392
+
356
393
try {
357
394
context .setReusable (false );
358
395
@@ -467,6 +504,28 @@ public static void validateProtocolData(ReferenceIDSupplier referenceIDSupplier,
467
504
}
468
505
}
469
506
507
+ /**
508
+ * Checks if the message ref should be filtered or not.
509
+ * @param ref the message to filter
510
+ * @return true if the INTERNAL_RECEIVER_ID_FILTER annotation of the message is set to a different value
511
+ * that the remoteMirrorID, false otherwise.
512
+ */
513
+ public boolean filterMessage (MessageReference ref ) {
514
+ Object filterID = ref .getMessage ().getAnnotation (INTERNAL_RECEIVER_ID_FILTER );
515
+ if (filterID != null ) {
516
+ String remoteMirrorId = getRemoteMirrorId ();
517
+ if (remoteMirrorId != null ) {
518
+ if (remoteMirrorId .equals (filterID )){
519
+ return false ;
520
+ } else {
521
+ return true ;
522
+ }
523
+ }
524
+ return false ;
525
+ }
526
+ return false ;
527
+ }
528
+
470
529
/** This method will return the brokerID used by the message */
471
530
private static String setProtocolData (ReferenceIDSupplier referenceIDSupplier , MessageReference ref ) {
472
531
String brokerID = referenceIDSupplier .getServerID (ref );
@@ -543,6 +602,17 @@ public void preAcknowledge(final Transaction tx, final MessageReference ref, fin
543
602
logger .trace ("preAcknowledge::tx={}, ref={}, reason={}" , tx , ref , reason );
544
603
}
545
604
605
+ SimpleString noForwardSource = null ;
606
+ if (Boolean .TRUE .equals (ref .getMessage ().getBooleanProperty (INTERNAL_NO_FORWARD ))) {
607
+ noForwardSource = (SimpleString ) ref .getMessage ().getBrokerProperty (INTERNAL_NO_FORWARD_SOURCE );
608
+ String remoteMirrorId = getRemoteMirrorId ();
609
+ if (remoteMirrorId != null ) {
610
+ if (!SimpleString .of (remoteMirrorId ).equals (noForwardSource )) {
611
+ return ;
612
+ }
613
+ }
614
+ }
615
+
546
616
MirrorController controllerInUse = getControllerInUse ();
547
617
548
618
// Retried ACKs are not forwarded.
@@ -578,6 +648,9 @@ public void preAcknowledge(final Transaction tx, final MessageReference ref, fin
578
648
String nodeID = idSupplier .getServerID (ref ); // notice the brokerID will be null for any message generated on this broker.
579
649
long internalID = idSupplier .getID (ref );
580
650
Message messageCommand = createMessage (ref .getQueue ().getAddress (), ref .getQueue ().getName (), POST_ACK , nodeID , internalID , reason );
651
+ if (noForwardSource != null ) {
652
+ messageCommand .setBrokerProperty (INTERNAL_RECEIVER_ID_FILTER , noForwardSource );
653
+ }
581
654
if (sync ) {
582
655
OperationContext operationContext ;
583
656
operationContext = OperationContextImpl .getContext (server .getExecutorFactory ());
0 commit comments