1 /* 2 * ************************************************************************************************************************************************************* 3 * 4 * TheseFoolishThings: Miscellaneous utilities 5 * http://tidalwave.it/projects/thesefoolishthings 6 * 7 * Copyright (C) 2009 - 2025 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 jakarta.annotation.Nonnull; 30 import java.time.Duration; 31 import java.time.ZoneId; 32 import java.time.ZonedDateTime; 33 import java.time.temporal.ChronoUnit; 34 import java.util.UUID; 35 36 /*************************************************************************************************************************************************************** 37 * 38 * Represents a single task that is possibly decomposed in multiple subtasks and provides support for waiting for its 39 * completion. 40 * 41 * @author Fabrizio Giudici 42 * 43 **************************************************************************************************************************************************************/ 44 public interface Collaboration 45 { 46 /*********************************************************************************************************************************************************** 47 * 48 **********************************************************************************************************************************************************/ 49 public static final Collaboration NULL_COLLABORATION = new Collaboration() 50 { 51 @Override @Nonnull 52 public Object getOriginatingMessage() 53 { 54 return new Object(); 55 } 56 57 @Override 58 public boolean isCompleted() 59 { 60 return true; 61 } 62 63 @Override 64 public void waitForCompletion() 65 { 66 } 67 68 @Override @Nonnull 69 public ZonedDateTime getStartTime() 70 { 71 return ZonedDateTime.of( 72 0, 0, 0, 0, 0, 0, 0, ZoneId.systemDefault()); 73 } 74 75 @Override @Nonnull 76 public Duration getDuration() 77 { 78 return Duration.of(0, ChronoUnit.SECONDS); 79 } 80 81 @Override 82 public Object suspend() 83 { 84 return UUID.randomUUID(); 85 } 86 87 @Override 88 public void resume (@Nonnull final Object suspensionToken, @Nonnull final Runnable runnable) 89 { 90 } 91 92 @Override 93 public void resumeAndDie (@Nonnull final Object suspensionToken) 94 { 95 } 96 97 @Override 98 public boolean isSuspended() 99 { 100 return false; 101 } 102 103 @Override 104 public int getDeliveringMessagesCount() 105 { 106 return 0; 107 } 108 109 @Override 110 public int getPendingMessagesCount() 111 { 112 return 0; 113 } 114 115 @Override 116 public int getRunningThreadsCount() 117 { 118 return 0; 119 } 120 }; 121 122 /*********************************************************************************************************************************************************** 123 * A provider of a {@link Collaboration}. 124 **********************************************************************************************************************************************************/ 125 public static interface Provider 126 { 127 /*************************************************************************************************************** 128 * 129 * Returns the {@link Collaboration}. 130 * 131 * @return the {@code Collaboration} 132 * 133 **************************************************************************************************************/ 134 @Nonnull 135 public Collaboration getCollaboration(); 136 } 137 138 /*********************************************************************************************************************************************************** 139 * Returns the message that originated this {@code Collaboration}. 140 * 141 * @return the message 142 **********************************************************************************************************************************************************/ 143 @Nonnull 144 public Object getOriginatingMessage(); 145 146 /*********************************************************************************************************************************************************** 147 * Returns {@code true} if the {@code Collaboration} has been completed. 148 * 149 * @return {@code true} if the {@code Collaboration} has been completed 150 **********************************************************************************************************************************************************/ 151 public boolean isCompleted(); 152 153 /*********************************************************************************************************************************************************** 154 * Waits for the completion of this {@code Collaboration}. 155 * 156 * @throws InterruptedException if the wait is interrupted 157 **********************************************************************************************************************************************************/ 158 public void waitForCompletion() 159 throws InterruptedException; 160 161 /*********************************************************************************************************************************************************** 162 * Return the time when this {@code Collaboration} has been created. 163 * 164 * @return the creation time 165 **********************************************************************************************************************************************************/ 166 @Nonnull 167 public ZonedDateTime getStartTime(); 168 169 /*********************************************************************************************************************************************************** 170 * Return the duration of this {@code Collaboration}. 171 * 172 * @return the duration 173 **********************************************************************************************************************************************************/ 174 @Nonnull 175 public Duration getDuration(); 176 177 /*********************************************************************************************************************************************************** 178 * Sometimes a {@code Collaboration} must coordinate with the external world, waiting for an external asynchronous 179 * event that cannot be modeled with agents. For instance, a user intervention (e.g. by clicking a button) or an 180 * external piece of software that is not part of the {@code Collaboration} model. In this case, it can be marked 181 * as 'suspended' and in this case it won't be considered completed, even though there are no related pending 182 * messages or working threads. When the external event occurs, call 183 * {@link #resume(java.lang.Object, java.lang.Runnable)}. 184 * 185 * In order to support multiple reasons for suspension, a token is generated and returned. It must be passed to 186 * {@code resume()} for resuming. 187 * 188 * @see #resume(java.lang.Object, java.lang.Runnable) 189 * @see #isSuspended() 190 * 191 * @return a token representing the reason for the suspension 192 **********************************************************************************************************************************************************/ 193 public Object suspend(); 194 195 /*********************************************************************************************************************************************************** 196 * Resumes a suspended {@code Collaboration}. It executes the given {@link Runnable} which is expected to send new 197 * messages. 198 * 199 * @see #suspend() 200 * @see #isSuspended() 201 * 202 * @param suspensionToken the token representing the reason for the suspension 203 * @param resumerTask the code which resumes the {@code Collaboration} 204 **********************************************************************************************************************************************************/ 205 public void resume (@Nonnull Object suspensionToken, @Nonnull Runnable resumerTask); 206 207 /*********************************************************************************************************************************************************** 208 * Resumes a suspended {@code Collaboration} and lets it terminate without any further operation. 209 * 210 * @see #suspend() 211 * @see #resume(java.lang.Object, java.lang.Runnable) 212 * @see #isSuspended() 213 * 214 * @param suspensionToken the token representing the reason for the suspension 215 **********************************************************************************************************************************************************/ 216 public void resumeAndDie (@Nonnull Object suspensionToken); 217 218 /*********************************************************************************************************************************************************** 219 * Returns {@code true} when the current {@code Collaboration} is suspended. 220 * 221 * @see #suspend() 222 * @see #resume(java.lang.Object, java.lang.Runnable) 223 * 224 * @return {@code true} when it's suspended 225 **********************************************************************************************************************************************************/ 226 public boolean isSuspended(); 227 228 /*********************************************************************************************************************************************************** 229 * Returns the number of messages related to this {@code Collaboration} not yet delivered. 230 * 231 * @return the number of messages not yet delivered 232 **********************************************************************************************************************************************************/ 233 @Nonnegative 234 public int getDeliveringMessagesCount(); 235 236 /*********************************************************************************************************************************************************** 237 * Returns the number of messages related to this {@code Collaboration} not yet consumed. 238 * 239 * @return the number of messages not yet consumed 240 **********************************************************************************************************************************************************/ 241 @Nonnegative 242 public int getPendingMessagesCount(); 243 244 /*********************************************************************************************************************************************************** 245 * Returns the number of running threads assigned to this {@code Collaboration}. 246 * 247 * @return the number of threads 248 **********************************************************************************************************************************************************/ 249 @Nonnegative 250 public int getRunningThreadsCount(); 251 }