Package: ImagingTask
ImagingTask
name | instruction | branch | complexity | line | method | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
ImagingTask() |
|
|
|
|
|
||||||||||||||||||||
ImagingTask(String, int) |
|
|
|
|
|
||||||||||||||||||||
addStatisticsSample(String, long) |
|
|
|
|
|
||||||||||||||||||||
dispose() |
|
|
|
|
|
||||||||||||||||||||
equals(Object) |
|
|
|
|
|
||||||||||||||||||||
execute() |
|
|
|
|
|
||||||||||||||||||||
execute(EditableImage, Operation, String) |
|
|
|
|
|
||||||||||||||||||||
execute2(EditableImage, Operation, String) |
|
|
|
|
|
||||||||||||||||||||
execute2AndDispose(EditableImage, Operation, String) |
|
|
|
|
|
||||||||||||||||||||
executeAndDispose(EditableImage, Operation, String) |
|
|
|
|
|
||||||||||||||||||||
getId() |
|
|
|
|
|
||||||||||||||||||||
getName() |
|
|
|
|
|
||||||||||||||||||||
getResult() |
|
|
|
|
|
||||||||||||||||||||
getStatistics() |
|
|
|
|
|
||||||||||||||||||||
getThrowable() |
|
|
|
|
|
||||||||||||||||||||
hashCode() |
|
|
|
|
|
||||||||||||||||||||
isRemoteExecutionOk() |
|
|
|
|
|
||||||||||||||||||||
mega(long) |
|
|
|
|
|
||||||||||||||||||||
prepare(ImagingTaskProcessor) |
|
|
|
|
|
||||||||||||||||||||
registerTime(String, EditableImage) |
|
|
|
|
|
||||||||||||||||||||
setResult(EditableImage) |
|
|
|
|
|
||||||||||||||||||||
setThrowable(Throwable) |
|
|
|
|
|
||||||||||||||||||||
static {...} |
|
|
|
|
|
||||||||||||||||||||
toString() |
|
|
|
|
|
Coverage
1: /*
2: * *********************************************************************************************************************
3: *
4: * Mistral: open source imaging engine
5: * http://tidalwave.it/projects/mistral
6: *
7: * Copyright (C) 2003 - 2023 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
12: * the License. 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
17: * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
18: * specific language governing permissions and limitations under the License.
19: *
20: * *********************************************************************************************************************
21: *
22: * git clone https://bitbucket.org/tidalwave/mistral-src
23: * git clone https://github.com/tidalwave-it/mistral-src
24: *
25: * *********************************************************************************************************************
26: */
27: package it.tidalwave.image.processor;
28:
29: import javax.annotation.Nonnull;
30: import java.io.Serializable;
31: import it.tidalwave.image.EditableImage;
32: import it.tidalwave.image.op.Operation;
33: import lombok.extern.slf4j.Slf4j;
34:
35: /***********************************************************************************************************************
36: *
37: * Encapsulates an unit of image processing.
38: *
39: * Concrete implementations of this class MUST BE serializable.
40: *
41: * @author Fabrizio Giudici
42: *
43: **********************************************************************************************************************/
44: @Slf4j public abstract class ImagingTask implements Serializable
45: {
46: static final long serialVersionUID = 8564150248239203504L;
47:
48: private static final long MEGA = 1024 * 1024;
49:
50: private static int uniqueIdCounter;
51:
52: /**
53: * The name of this task.
54: */
55: private String name;
56:
57: private EditableImage result;
58:
59: /**
60: * The unique id of this task. It's used for implementing equals() and hashcode() as in a distributed environment
61: * every sort of things can happen to an ImagingTask, as they are possibly created on different computing nodes and
62: * serialized back and forth.
63: */
64: private Serializable uniqueId;
65:
66: /**
67: * This id is used only for logging.
68: */
69: private int loggingId;
70:
71: /**
72: * The statistics of this task.
73: */
74: private Statistics statistics = new Statistics();
75:
76: /**
77: * A throwable if the task ended with an error.
78: */
79: private Throwable throwable;
80:
81: public long latestExecutionTime; // FIXME
82:
83: private boolean serializeByFile;
84:
85: /*******************************************************************************************************************
86: *
87: * For serialization.
88: *
89: ******************************************************************************************************************/
90: public ImagingTask()
91: {
92: }
93:
94: /*******************************************************************************************************************
95: *
96: * Creates a new instance of ImagingTask. Subclasses must *not* perform
97: * any initialization here: they should use <code>prepare()</code> instead.
98: * This constructor must return very quickly.
99: *
100: ******************************************************************************************************************/
101: public ImagingTask (final String name, final int loggingId)
102: {
103: serializeByFile = false; // ImagingTaskProcessor.getInstance().hasFileAccess();
104: this.name = name;
105: this.loggingId = loggingId;
106: this.uniqueId = Long.toHexString(System.currentTimeMillis())
107: + "-" + Long.toHexString(uniqueIdCounter++); // FIXME: use a UUID instead
108: }
109:
110: /*******************************************************************************************************************
111: *
112: * Returns the name of this task.
113: *
114: * @return the task name
115: *
116: ******************************************************************************************************************/
117: public String getName()
118: {
119: return name + " #" + loggingId;
120: }
121:
122: /*******************************************************************************************************************
123: *
124: * Returns the unique id of this task.
125: *
126: * @return the task id
127: *
128: ******************************************************************************************************************/
129: public Serializable getId()
130: {
131: return uniqueId;
132: }
133:
134: /*******************************************************************************************************************
135: *
136: * This method is performed <i>in a local context</i> before the task is
137: * scheduled to run - that is, this method is performed in a serialized
138: * fashion, possibly on a single computing node (depending on the processing
139: * engine). Subclasses can override this method for customizing
140: * the behaviour (that must not be computing intensive).
141: *
142: * The <code>processor</code> parameter can be used to query some properties
143: * of the <code>ImagingTaskProcessor</code> that could be used for alternate
144: * preparing strategies.
145: *
146: * The <code>super</code> method must be always called.
147: *
148: * @param processor the processor
149: *
150: ******************************************************************************************************************/
151: public void prepare (final ImagingTaskProcessor processor)
152: throws Exception
153: {
154: }
155:
156: /*******************************************************************************************************************
157: *
158: * Concrete implementations should provide the task core in this method.
159: * This method is performed in a distributed context, if available.
160: *
161: ******************************************************************************************************************/
162: protected abstract void run()
163: throws Exception;
164:
165: /*******************************************************************************************************************
166: *
167: * Returns the result of this task. Must be implemented by subclasses.
168: *
169: * @return the result
170: *
171: ******************************************************************************************************************/
172: public final EditableImage getResult()
173: {
174: return result;
175: }
176:
177: protected final void setResult (final EditableImage result)
178: {
179: this.result = result;
180: }
181:
182: /*******************************************************************************************************************
183: *
184: * If the task ended with an error, a Throwable is returned by this method.
185: *
186: * @return the throwable
187: *
188: ******************************************************************************************************************/
189: public Throwable getThrowable()
190: {
191: return throwable;
192: }
193:
194: public void setThrowable (final Throwable throwable)
195: {
196: this.throwable = throwable;
197: }
198:
199: /*******************************************************************************************************************
200: *
201: * If this method return <code>true</code> (the default), this task can be
202: * executed remotely. Otherwise it will be scheduled on the local node.
203: * Usually tasks which computation time is very quick and much shorter than
204: * the overhead to serialize data back and forth should return
205: * <code>false</code>.
206: *
207: * @return true if the task can be scheduled remotely
208: *
209: ******************************************************************************************************************/
210: public boolean isRemoteExecutionOk()
211: {
212: return true;
213: }
214:
215: /*******************************************************************************************************************
216: *
217: * Returns the statistics collected by this task.
218: *
219: * @return the statistics
220: *
221: ******************************************************************************************************************/
222: public Statistics getStatistics()
223: {
224: return statistics;
225: }
226:
227: /*******************************************************************************************************************
228: *
229: * Subclasses should release all the allocated resources when this method
230: * is called.
231: *
232: ******************************************************************************************************************/
233: public void dispose()
234: {
235: result = null;
236: // DO NOT dispose() result as it could be used by others!
237: }
238:
239: /*******************************************************************************************************************
240: *
241: * {@inheritDoc}
242: *
243: ******************************************************************************************************************/
244: @Override
245: public final String toString()
246: {
247: return getName() + " [" + uniqueId + "]";
248: }
249:
250: /*******************************************************************************************************************
251: *
252: * See the comment about uniqueId.
253: *
254: ******************************************************************************************************************/
255: @Override
256: public final int hashCode()
257: {
258: return uniqueId.hashCode();
259: }
260:
261: /*******************************************************************************************************************
262: *
263: * See the comment about uniqueId.
264: *
265: ******************************************************************************************************************/
266: @Override
267: public final boolean equals (final Object object)
268: {
269:• if (!(object instanceof ImagingTask))
270: {
271: return false;
272: }
273:
274: final var task = (ImagingTask)object;
275: return this.uniqueId.equals(task.uniqueId);
276: }
277:
278: /*******************************************************************************************************************
279: *
280: * Executes the task. This method is only called by the framework.
281: *
282: ******************************************************************************************************************/
283: public final void execute()
284: {
285: try
286: {
287: log.info("Starting " + name);
288: var time = System.currentTimeMillis();
289:
290: try
291: {
292: run();
293: }
294: finally
295: {
296: time = System.currentTimeMillis() - time;
297: addStatisticsSample("TOTAL", time);
298: log.info("STATS: " + getName() + " completed in " + time + " msec");
299:
300: final var runtime = Runtime.getRuntime();
301: final var totalMemory = runtime.totalMemory();
302: final var freeMemory = runtime.freeMemory();
303: final var usedMemory = totalMemory - freeMemory;
304: log.info("STATS: memory " + "used: " + mega(usedMemory)
305: + ", total: " + mega(totalMemory)
306: + ", max: " + mega(runtime.maxMemory())
307: + ", free: " + mega(freeMemory));
308: }
309: }
310: catch (Throwable e)
311: {
312: throwable = e;
313: log.error("Task failed: " + getName() + ", " + e);
314: log.error("execute()", e);
315: e.printStackTrace(System.err);
316: }
317:
318: log.info("Completed " + getName());
319: }
320:
321: /*******************************************************************************************************************
322: *
323: *
324: *
325: ******************************************************************************************************************/
326: public void addStatisticsSample (final String name, final long value)
327: {
328: statistics.addSample(this.name + "." + name, value);
329: }
330:
331: /*******************************************************************************************************************
332: *
333: * Updates statistics about execution time, about the latest performed
334: * operation on the given image.
335: *
336: * @param name the statistics name
337: * @param image the image
338: *
339: ******************************************************************************************************************/
340: protected void registerTime (final @Nonnull String name, final @Nonnull EditableImage image)
341: {
342: addStatisticsSample(name, image.getLatestOperationDuration().toMillis());
343: }
344:
345: /*******************************************************************************************************************
346: *
347: * Executes an operation adding the elapsed time to the statistics.
348: *
349: * @param image the image to process
350: * @param operation the operation to execute
351: * @param operationName the name used for the statistics
352: * @return the operation (as a convenience in case it carries
353: * results)
354: *
355: ******************************************************************************************************************/
356: protected <T extends Operation> T execute (final @Nonnull EditableImage image,
357: final @Nonnull T operation,
358: final @Nonnull String operationName)
359: {
360: image.executeInPlace(operation);
361: image.setNickName(operationName);
362: registerTime(operationName, image);
363: return operation;
364: }
365:
366: /*******************************************************************************************************************
367: *
368: * The same as execute(), but the operand image is disposed before returning.
369: *
370: * @param image the image to process
371: * @param operation the operation to execute
372: * @param operationName the name used for the statistics
373: * @return the operation (as a convenience in case it carries
374: * results)
375: *
376: ******************************************************************************************************************/
377: protected <T extends Operation> T executeAndDispose (final @Nonnull EditableImage image,
378: final @Nonnull T operation,
379: final @Nonnull String operationName)
380: {
381: final var result = execute(image, operation, operationName);
382: image.dispose();
383: return result;
384: }
385:
386: /*******************************************************************************************************************
387: *
388: * Executes an operation adding the elapsed time to the statistics.
389: *
390: * @param image the image to process
391: * @param operation the operation to execute
392: * @param operationName the name used for the statistics
393: * @return the result
394: *
395: ******************************************************************************************************************/
396: @Nonnull
397: protected EditableImage execute2 (final @Nonnull EditableImage image,
398: final @Nonnull Operation operation,
399: final @Nonnull String operationName)
400: {
401: final var result = image.execute(operation);
402: result.setNickName(operationName);
403: registerTime(operationName, result);
404: return result;
405: }
406:
407: /*******************************************************************************************************************
408: *
409: * The same as execute2(), but the operand image is disposed before returning.
410: *
411: * @param image the image to process
412: * @param operation the operation to execute
413: * @param operationName the name used for the statistics
414: * @return the result
415: *
416: ******************************************************************************************************************/
417: @Nonnull
418: protected EditableImage execute2AndDispose (final @Nonnull EditableImage image,
419: final @Nonnull Operation operation,
420: final @Nonnull String operationName)
421: {
422: final var result = execute2(image, operation, operationName);
423: image.dispose();
424: result.setNickName(operationName);
425: return result;
426: }
427:
428: /*******************************************************************************************************************
429: *
430: *
431: ******************************************************************************************************************/
432: @Nonnull
433: private static String mega (final long l)
434: {
435: return "" + ((l + MEGA / 2) / MEGA) + "M";
436: }
437: }