1 /* 2 * ************************************************************************************************************************************************************* 3 * 4 * TheseFoolishThings: Miscellaneous utilities 5 * http://tidalwave.it/projects/thesefoolishthings 6 * 7 * Copyright (C) 2009 - 2024 by Tidalwave s.a.s. (http://tidalwave.it) 8 * 9 * ************************************************************************************************************************************************************* 10 * 11 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 12 * You may obtain a copy of the License at 13 * 14 * http://www.apache.org/licenses/LICENSE-2.0 15 * 16 * 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 17 * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 18 * 19 * ************************************************************************************************************************************************************* 20 * 21 * git clone https://bitbucket.org/tidalwave/thesefoolishthings-src 22 * git clone https://github.com/tidalwave-it/thesefoolishthings-src 23 * 24 * ************************************************************************************************************************************************************* 25 */ 26 package it.tidalwave.actor; 27 28 import javax.annotation.Nonnegative; 29 import javax.annotation.Nonnull; 30 import javax.inject.Provider; 31 import java.util.Optional; 32 import java.util.Timer; 33 import java.util.TimerTask; 34 import java.util.concurrent.TimeUnit; 35 import java.io.Serializable; 36 import it.tidalwave.actor.impl.DefaultCollaboration; 37 import it.tidalwave.actor.impl.Locator; 38 import it.tidalwave.actor.spi.CollaborationAwareMessageBus; 39 import it.tidalwave.util.As; 40 import lombok.EqualsAndHashCode; 41 import lombok.experimental.Delegate; 42 import lombok.extern.slf4j.Slf4j; 43 import static it.tidalwave.actor.MessageDecorator._MessageDecorator_; 44 45 /*************************************************************************************************************************************************************** 46 * 47 * A support class for implementing messages. 48 * 49 * @stereotype Message 50 * 51 * @author Fabrizio Giudici 52 * 53 **************************************************************************************************************************************************************/ 54 @Slf4j @EqualsAndHashCode(of = "collaboration") 55 public abstract class MessageSupport implements Collaboration.Provider, As, Serializable 56 { 57 // TODO: @Inject 58 private final Provider<CollaborationAwareMessageBus> messageBus = 59 Locator.createProviderFor(CollaborationAwareMessageBus.class); 60 61 @Nonnull 62 protected final DefaultCollaboration collaboration; 63 64 private final MessageDecorator sameMessageDecorator = new MessageDecorator.Same<>(this); 65 66 interface Exclusions 67 { 68 public <T> T maybeAs (Class<? extends T> type); 69 } 70 71 @Delegate(excludes = Exclusions.class) 72 private final As as = As.forObject(this); 73 74 /*********************************************************************************************************************************************************** 75 * 76 **********************************************************************************************************************************************************/ 77 protected MessageSupport() 78 { 79 this.collaboration = DefaultCollaboration.getOrCreateCollaboration(this); 80 } 81 82 /*********************************************************************************************************************************************************** 83 * @param collaboration the collaboration 84 **********************************************************************************************************************************************************/ 85 protected MessageSupport (@Nonnull final Collaboration collaboration) 86 { 87 this.collaboration = (DefaultCollaboration)collaboration; 88 } 89 90 /*********************************************************************************************************************************************************** 91 * Returns the {@link Collaboration} that this message is part of. 92 * 93 * @return the {@code Collaboration} 94 **********************************************************************************************************************************************************/ 95 @Override @Nonnull 96 public Collaboration getCollaboration() 97 { 98 return collaboration; 99 } 100 101 /*********************************************************************************************************************************************************** 102 * Sends this message, eventually performing a replacement (see {@link MessageDecorator} for further info). 103 * 104 * @return the {@code Collaboration} that this message is part of 105 **********************************************************************************************************************************************************/ 106 @Nonnull @SuppressWarnings("UnusedReturnValue") 107 public Collaboration send() 108 { 109 log.debug("send() - {}", this); 110 return findDecoratedMessage().sendDirectly(); 111 } 112 113 /*********************************************************************************************************************************************************** 114 * Sends this message directly, not performing any replacement (see {@link MessageDecorator} for further info). 115 * 116 * @return the {@code Collaboration} that this message is part of 117 **********************************************************************************************************************************************************/ 118 @Nonnull 119 public Collaboration sendDirectly() 120 { 121 log.debug("sendDirectly() - {}", this); 122 collaboration.registerDeliveringMessage(this); 123 messageBus.get().publish(this); 124 return collaboration; 125 } 126 127 /*********************************************************************************************************************************************************** 128 * Sends this message after a delay, eventually performing a replacement (see {@link MessageDecorator} for 129 * further info). 130 * 131 * @param delay the delay 132 * @param timeUnit the {@link TimeUnit} for the delay 133 * @return the {@code Collaboration} that this message is part of 134 **********************************************************************************************************************************************************/ 135 @Nonnull 136 public Collaboration sendLater (@Nonnegative final int delay, @Nonnull final TimeUnit timeUnit) 137 { 138 log.debug("sendLater({}, {}) - {}", delay, timeUnit, this); 139 final var message = findDecoratedMessage(); 140 collaboration.registerDeliveringMessage(message); 141 142 new Timer().schedule(new TimerTask() 143 { 144 @Override 145 public void run() 146 { 147 messageBus.get().publish(message); 148 } 149 }, TimeUnit.MILLISECONDS.convert(delay, timeUnit)); 150 151 return collaboration; 152 } 153 154 /*********************************************************************************************************************************************************** 155 * {@inheritDoc} 156 **********************************************************************************************************************************************************/ 157 @Override @Nonnull 158 public <T> Optional<T> maybeAs (@Nonnull final Class<? extends T> type) 159 { 160 final Optional<T> t = as.maybeAs(type); 161 162 return t.isPresent() 163 ? t 164 : type.equals(MessageDecorator.class) ? Optional.of(type.cast(sameMessageDecorator)) : Optional.empty(); 165 } 166 167 /*********************************************************************************************************************************************************** 168 * 169 **********************************************************************************************************************************************************/ 170 @Nonnull 171 private MessageSupport findDecoratedMessage() 172 { 173 final var decoratedMessage = this.as(_MessageDecorator_).getDecoratedMessage(); 174 return (decoratedMessage == this) ? this : decoratedMessage.findDecoratedMessage(); 175 // MessageSupport decoratedMessage = this.as(_MessageDecorator_).getDecoratedMessage(); 176 // 177 // if (decoratedMessage != this) 178 // { 179 // log.info("MESSAGE HAS BEEN DECORATED: {} -> {}", this, decoratedMessage); 180 // decoratedMessage = decoratedMessage.findDecoratedMessage(); 181 // } 182 // 183 // return decoratedMessage; 184 } 185 }