001: package it.geosolutions.utils.progress;
002:
003: import it.geosolutions.utils.imagemosaic.MosaicIndexBuilder;
004:
005: import java.util.ArrayList;
006: import java.util.List;
007:
008: import javax.swing.SwingUtilities;
009:
010: import org.apache.commons.cli2.CommandLine;
011: import org.apache.commons.cli2.Group;
012: import org.apache.commons.cli2.Option;
013: import org.apache.commons.cli2.builder.ArgumentBuilder;
014: import org.apache.commons.cli2.builder.DefaultOptionBuilder;
015: import org.apache.commons.cli2.commandline.Parser;
016: import org.apache.commons.cli2.option.DefaultOption;
017:
018: public abstract class ProgressManager {
019:
020: /**
021: * Private Class which simply fires the events using a copy of the listeners
022: * list in order to avoid problems with listeners that remove themselves or
023: * are removed by someone else
024: */
025: protected final static class ProgressEventDispatchThreadEventLauncher
026: implements Runnable {
027:
028: private ProcessingEvent event;
029:
030: private Object[] listeners;
031:
032: ProgressEventDispatchThreadEventLauncher() {
033: }
034:
035: synchronized void setEvent(final ProcessingEvent evt,
036: final Object[] listeners) {
037:
038: this .listeners = listeners;
039: this .event = evt;
040:
041: }
042:
043: /*
044: * (non-Javadoc)
045: *
046: * @see java.lang.Runnable#run()
047: */
048: public void run() {
049: final int numListeners = listeners.length;
050: if (event instanceof ExceptionEvent)
051: for (int i = 0; i < numListeners; i++)
052: ((ProcessingEventListener) listeners[i])
053: .exceptionOccurred((ExceptionEvent) this .event);
054: else
055: for (int i = 0; i < numListeners; i++)
056: ((ProcessingEventListener) listeners[i])
057: .getNotification(this .event);
058: }
059:
060: }
061:
062: /**
063: * Options for the command line.
064: */
065: protected final List cmdOpts = new ArrayList(5);
066:
067: protected final Parser cmdParser = new Parser();
068:
069: protected final ArgumentBuilder arguments = new ArgumentBuilder();
070:
071: /**
072: * Set this to false for command line UIs where the delayed event sending may prevent some
073: * messages to be seen before the tool exits, to true for real GUI where you don't want
074: * the processing to be blocked too long, or when you have slow listeners in general.
075: */
076: protected final boolean sendDelayedMessages = false;
077:
078: /** Event launcher. */
079: private ProgressEventDispatchThreadEventLauncher eventLauncher = new ProgressEventDispatchThreadEventLauncher();
080:
081: /**
082: * Proper way to stop a thread is not by calling Thread.stop() but by using
083: * a shared variable that can be checked in order to notify a terminating
084: * condition.
085: */
086: private volatile boolean stopThread = false;
087:
088: /**
089: * List containing all the objects that want to be notified during
090: * processing.
091: */
092: private List notificationListeners = new ArrayList();
093:
094: /**
095: * Default priority for the underlying {@link Thread}.
096: */
097: private static int DEFAULT_PRIORITY = Thread.NORM_PRIORITY;
098:
099: protected final DefaultOptionBuilder optionBuilder = new DefaultOptionBuilder();
100:
101: protected Group optionsGroup;
102:
103: protected CommandLine cmdLine;
104:
105: protected Option helpOpt;
106:
107: protected DefaultOption priorityOpt;
108:
109: /**
110: * Default priority for the underlying {@link Thread}.
111: */
112: protected int priority = DEFAULT_PRIORITY;
113:
114: protected DefaultOption versionOpt;
115:
116: public ProgressManager() {
117: super ();
118: }
119:
120: /**
121: * Adding a listener for the notifications.
122: *
123: * @param listener
124: */
125: public final synchronized void addProcessingEventListener(
126: final ProcessingEventListener listener) {
127: notificationListeners.add(listener);
128: }
129:
130: /**
131: * Removing a listener.
132: *
133: * @param listener
134: */
135: public final synchronized void removeProcessingEventListener(
136: final ProcessingEventListener listener) {
137: notificationListeners.remove(listener);
138: }
139:
140: /**
141: * Removing all the listeners.
142: *
143: */
144: public final synchronized void removeAllProcessingEventListeners() {
145: notificationListeners.clear();
146:
147: }
148:
149: /**
150: * Firing an event to listeners in order to inform them about what we are
151: * doing and about the percentage of work already carried out.
152: *
153: * @param string
154: * The message to show.
155: * @param percentage
156: * The percentage for the process.
157: */
158: protected synchronized void fireEvent(final String string,
159: final double percentage) {
160: final String newLine = System.getProperty("line.separator");
161: final StringBuffer message = new StringBuffer("Thread Name ");
162: message.append(Thread.currentThread().getName())
163: .append(newLine);
164: message.append(this .getClass().toString()).append(newLine)
165: .append(string);
166: final ProcessingEvent evt = new ProcessingEvent(this , string,
167: percentage);
168: ProgressEventDispatchThreadEventLauncher eventLauncher = new ProgressEventDispatchThreadEventLauncher();
169: eventLauncher.setEvent(evt, this .notificationListeners
170: .toArray());
171: sendEvent(eventLauncher);
172: }
173:
174: protected void sendEvent(
175: ProgressEventDispatchThreadEventLauncher eventLauncher) {
176: if (sendDelayedMessages)
177: SwingUtilities.invokeLater(eventLauncher);
178: else
179: eventLauncher.run();
180: }
181:
182: /**
183: * Firing an exception event to listeners in order to inform them that processing
184: * broke and we can no longer proceed
185: *
186: * @param string
187: * The message to show.
188: * @param percentage
189: * The percentage for the process.
190: * @param ex
191: * the actual exception occurred
192: */
193: protected synchronized void fireException(final String string,
194: final double percentage, Exception ex) {
195: final String newLine = System.getProperty("line.separator");
196: final StringBuffer message = new StringBuffer("Thread Name ");
197: message.append(Thread.currentThread().getName())
198: .append(newLine);
199: message.append(this .getClass().toString()).append(newLine)
200: .append(string);
201: final ExceptionEvent evt = new ExceptionEvent(this , string,
202: percentage, ex);
203: ProgressEventDispatchThreadEventLauncher eventLauncher = new ProgressEventDispatchThreadEventLauncher();
204: eventLauncher.setEvent(evt, this .notificationListeners
205: .toArray());
206: sendEvent(eventLauncher);
207: }
208:
209: /**
210: * Firing an exception event to listeners in order to inform them that processing
211: * broke and we can no longer proceed. This is a convenience method, it will call
212: * {@link #fireException(String, double, Exception)} with the exception message and -1 as
213: * percentage.
214: *
215: * @param ex
216: * the actual exception occurred
217: */
218: protected synchronized void fireException(Exception ex) {
219: fireException(ExceptionEvent.getMessageFromException(ex), -1,
220: ex);
221: }
222:
223: /**
224: * Should this thread be stopped?
225: *
226: */
227: public final boolean getStopThread() {
228: return stopThread;
229: }
230:
231: /**
232: * Stop this thread.
233: *
234: * @param stop
235: */
236: public final void stopThread() {
237: stopThread = true;
238: }
239:
240: /**
241: * Cleans up the {@link MosaicIndexBuilder}.
242: *
243: */
244: public void dispose() {
245: removeAllProcessingEventListeners();
246: }
247:
248: public abstract void run();
249:
250: }
|