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 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 }