001    /*
002     * Operation
003     * 
004     * Copyright (c) 2000, 2001, 2002 Marco Schmidt <marcoschmidt@users.sourceforge.net>
005     * All rights reserved.
006     */
007    
008    package net.sourceforge.jiu.ops;
009    
010    import java.util.Vector;
011    import net.sourceforge.jiu.ops.MissingParameterException;
012    import net.sourceforge.jiu.ops.OperationFailedException;
013    import net.sourceforge.jiu.ops.ProgressListener;
014    import net.sourceforge.jiu.ops.WrongParameterException;
015    
016    /**
017     * <p>
018     * Base class for all operations.
019     * </p>
020     * <p>
021     * It supports progress notification.
022     * All classes that want to be notified by a new progress level of the operation
023     * (defined as value between 0.0f (nothing has been done so far) to 1.0f
024     * (operation finished)) must implement the {@link ProgressListener} interface.
025     * </p>
026     * <p>
027     * An abortion state is stored in each Operation object.
028     * It should be queried by a running operation from time to time 
029     * (via {@link #getAbort()} - if it returns <code>true</code>,
030     * the operation should terminate and return control to the caller.
031     * The abort state can be modified using {@link #setAbort(boolean)}.
032     * </p>
033     * @author Marco Schmidt
034     */
035    public abstract class Operation
036    {
037     /* <p>
038     * This class class contains a generic system to add parameters to an operation.
039     * Whether an item becomes a parameter is often unclear and must be decided by
040     * the operation implementor.
041     * As an example: one could create an image rotation class with a numerical parameter
042     * for the degrees of rotation.
043     * One could also define a class of its own for each 90, 180 and 270 degrees
044     * (excluding other values).
045     * </p>
046     * <p>
047     * The generic parameter system is insufficient in some situations.
048     * Example: A parameter can be defined to be of class Integer or Long, but it cannot
049     * be forced to be in a certain interval.
050     * Even if such a case could be solved by a specially-designed class, checking
051     * of parameters (and maybe their relations among each other) can be done by
052     * overriding the {@link #checkParams()} method.
053     * </p>
054     */
055            private boolean abort;
056            private Vector progressListeners;
057    //      private Vector params;
058    
059            /**
060             * This constructor creates two internal empty lists for progress listeners and parameters.
061             */
062            public Operation()
063            {
064                    abort = false;
065                    progressListeners = new Vector();
066    //              params = new Vector();
067            }
068    
069            /**
070             * Adds a new parameter to the internal list of parameters for this operation.
071             *
072             * @param parameter the Parameter object to be added
073             *
074             * @throws IllegalArgumentException if the oarameter is null or if a parameter of the 
075             *  same name has already been added to the internal list of parameter
076             */
077    /*      public void addParam(Parameter parameter) throws IllegalArgumentException
078            {
079                    if (parameter == null)
080                    {
081                            throw new IllegalArgumentException("Parameter must be non-null.");
082                    }
083                    String name = parameter.getName();
084                    Parameter paramInVector = getParam(name);
085                    if (paramInVector != null)
086                    {
087                            throw new IllegalArgumentException("Parameter of the name \"" + name + "\" already exists in internal parameter list.");
088                    }
089                    params.addElement(parameter);
090            }*/
091    
092            /**
093             * Adds the argument progress listener to the internal list of
094             * progress listeners.
095             * Does not check if the argument already exists in that list, so you have
096             * to check for duplicates yourself.
097             *
098             * @param progressListener the progress listener to be added
099             */
100            public void addProgressListener(ProgressListener progressListener)
101            {
102                    if (progressListener == null)
103                    {
104                            return;
105                    }
106                    if (!progressListeners.contains(progressListener))
107                    {
108                            progressListeners.addElement(progressListener);
109                    }
110            }
111    
112            /**
113             * Adds several progress listeners to this operation object.
114             * @param progressListeners contains zero or more objects implementing ProgressListener; 
115             *  each will be added by calling {@link #addProgressListener} on it
116             */
117            public void addProgressListeners(Vector progressListeners)
118            {
119                    if (progressListeners != null)
120                    {
121                            int index = 0;
122                            while (index < progressListeners.size())
123                            {
124                                    ProgressListener listener = (ProgressListener)progressListeners.elementAt(index++);
125                                    addProgressListener(listener);
126                            }
127                    }
128            }
129    
130            /**
131             * Calls the {@link Parameter#check()} method of each {@link Parameter}
132             * object in the internal list of parameters.
133             * Will throw an exception if at least one parameter with a required value
134             * has not been initialized.
135             *
136             * @throws MissingParameterException if at least one parameter is not properly initialized
137             */
138    /*      public void checkParams() throws MissingParameterException
139            {
140                    int index = 0;
141                    while (index < params.size())
142                    {
143                            Parameter param = (Parameter)params.elementAt(index++);
144                            param.check();
145                    }
146            }*/
147    
148            /**
149             * Returns the current abort status.
150             * If <code>true</code>, a running operation should terminate what it is doing
151             * (return from {@link #process()}).
152             * @return abort status
153             * @see #setAbort
154             */
155            public boolean getAbort()
156            {
157                    return abort;
158            }
159    
160            /**
161             * Returns the number of parameters currently defined for this operation.
162             * @return number of defined parameters
163             */
164    /*      public int getNumParams()
165            {
166                    return params.size();
167            }*/
168    
169    /*      private Parameter getParam(String paramName)
170            {
171                    if (paramName == null || paramName.length() < 1)
172                    {
173                            return null;
174                    }
175                    int index = 0;
176                    while (index < params.size())
177                    {
178                            Parameter param = (Parameter)params.elementAt(index++);
179                            if (paramName.equals(param.getName()))
180                            {
181                                    return param;
182                            }
183                    }
184                    return null;
185            }*/
186    
187            /**
188             * Returns a Parameter object from the internal list of parameters.
189             * @param index zero-based index of the parameter; must be smaller than {@link #getNumParams()}
190             */
191    /*      public Parameter getParam(int index)
192            {
193                    return (Parameter)params.elementAt(index);
194            }*/
195    
196    /*      public Object getParamValue(int index)
197            {
198                    Parameter param = getParam(index);
199                    if (param == null)
200                    {
201                            return null;
202                    }
203                    else
204                    {
205                            return param.getValue();
206                    }
207            }*/
208    
209            /**
210             * This method does the actual work of the operation.
211             * It must be called after all parameters have been given to the operation object.
212             * @throws WrongParameterException if at least one of the input parameters was 
213             *  not initialized appropriately (values out of the valid interval, etc.)
214             * @throws MissingParameterException if any mandatory parameter was not given to the operation
215             * @throws OperationFailedException 
216             */
217            public void process() throws 
218                    MissingParameterException, 
219                    OperationFailedException, 
220                    WrongParameterException
221            {
222            }
223    
224            /**
225             * Removes the argument progress listener from the internal list of
226             * progress listeners.
227             * @param progressListener the progress listener to be removed
228             */
229            public void removeProgressListener(ProgressListener progressListener)
230            {
231                    progressListeners.removeElement(progressListener);
232            }
233    
234            /**
235             * Sets a new abort status.
236             * @param newAbortStatus the new status
237             * @see #getAbort
238             */
239            public void setAbort(boolean newAbortStatus)
240            {
241                    abort = newAbortStatus;
242            }
243    
244            /**
245             * This method will notify all registered progress listeners
246             * about a new progress level.
247             * The argument must be from 0.0f to 1.0f where 0.0f marks the
248             * beginning and 1.0f completion.
249             * The progress value should not be smaller than any value that
250             * was previously set.
251             * @param progress new progress value, from 0.0 to 1.0
252             */
253            public void setProgress(float progress)
254            {
255                    if (progress < 0.0f || progress > 1.0f)
256                    {
257                            throw new IllegalArgumentException("Progress values must be from" +
258                                    " 0.0f to 1.0f; got " + progress);
259                    }
260                    int index = 0;
261                    while (index < progressListeners.size())
262                    {
263                            ProgressListener pl = 
264                                    (ProgressListener)progressListeners.elementAt(index++);
265                            if (pl != null)
266                            {
267                                    pl.setProgress(progress);
268                            }
269                    }
270            }
271    
272            /**
273             * This method will notify all registered progress listeners
274             * about a new progress level.
275             * Simply checks the arguments and calls <code>setProgress((float)zeroBasedIndex / (float)totalItems);</code>.
276             * @param zeroBasedIndex the index of the item that was just processed, zero-based
277             * @param totalItems the number of items that will be processed
278             */
279            public void setProgress(int zeroBasedIndex, int totalItems)
280            {
281                    if (zeroBasedIndex < 0 || zeroBasedIndex >= totalItems ||
282                        totalItems < 1)
283                    {
284                            throw new IllegalArgumentException("No valid arguments " +
285                                    " zeroBasedIndex=" + zeroBasedIndex + ", totalItems=" +
286                                    totalItems);
287                    }
288                    setProgress((float)zeroBasedIndex / (float)totalItems);
289            }
290    }