KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > idaremedia > antx > starters > ManagerTask


1 /**
2  * $Id: ManagerTask.java 186 2007-03-16 13:42:35Z ssmc $
3  * Copyright 2004 iDare Media, Inc. All rights reserved.
4  *
5  * Originally written by iDare Media, Inc. for release into the public domain. This
6  * library, source form and binary form, is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public License (LGPL) as published
8  * by the Free Software Foundation; either version 2.1 of the License, or (at your option)
9  * any later version.<p>
10  *
11  * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
12  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13  * See the GNU LGPL for more details.<p>
14  *
15  * You should have received a copy of the GNU Lesser General Public License along with this
16  * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite
17  * 330, Boston, MA 02111-1307 USA. The GNU LGPL can be found online at
18  * http://www.fsf.org/copyleft/lesser.html<p>
19  *
20  * This product has been influenced by several projects within the open-source community.
21  * The JWare developers wish to acknowledge the open-source community's support. For more
22  * information regarding the open-source products used within JWare, please visit the
23  * JWare website.
24  *----------------------------------------------------------------------------------------*
25  * WEBSITE- http://www.jware.info EMAIL- inquiries@jware.info
26  *----------------------------------------------------------------------------------------*
27  **/

28
29 package com.idaremedia.antx.starters;
30
31 import java.lang.reflect.Method JavaDoc;
32 import java.lang.reflect.Modifier JavaDoc;
33 import java.util.List JavaDoc;
34 import java.util.Map JavaDoc;
35
36 import org.apache.tools.ant.BuildException;
37 import org.apache.tools.ant.Project;
38
39 import com.idaremedia.antx.AntXFixture;
40 import com.idaremedia.antx.AssertableLibDefinition;
41 import com.idaremedia.antx.Iteration;
42 import com.idaremedia.antx.apis.Requester;
43 import com.idaremedia.antx.helpers.Tk;
44 import com.idaremedia.antx.ownhelpers.LocalTk;
45 import com.idaremedia.antx.parameters.RecoveryEnabled;
46
47 /**
48  * Skeleton for an fixture management task that can perform any of a small set of
49  * allowed actions. Typically manager tasks usually support (at least) an "install"
50  * and an "uninstall" action although these are not necessary.
51  * <p/>
52  * When initialized, a manager task will inspect its method table for all <em>public</em>
53  * void methods that begin with the action verb "<span class="src">do</span>" as in
54  * "<span class="src">doInstall</span>" or "<span class="src">doResolve</span>". <em>The
55  * case of the leading "do" must be all lowercase.</em> The part of the method name
56  * that follows the "do" is called the action's name (it is
57  * {@linkplain com.idaremedia.antx.helpers.Tk#lowercaseFrom(String) normalized} so
58  * capitalization does not matter). In the preceding example, having a public
59  * "<span class="src">doInstall</span>" method means you have a
60  * "<span class="src">install</span>" action available. Each action method must return
61  * no outputs and take a single <span class="src">Map</span> parameter. This
62  * readonly map contains any options specified by the script and/or the application
63  * caller. Whether or not this parameter can be <i>null</i> is subclass defined (the
64  * incoming parameter is passed as-is from <span class="src">doAction</span>).
65  * <p/>
66  * The base manager task does not enforce any particular script-facing form (simple
67  * error handling aside); subclasses must decide how a script triggers a particular
68  * action. Simple manager tasks usually support a simple "<span class="src">action</span>"
69  * parameter without any control options. More complex manager tasks can create
70  * individual instantiable tasks from a common superclass. However the action name is
71  * determined, subclasses must call the inherited
72  * {@linkplain #doAction doAction(&#8230;)} utility method to call the matching method.
73  * <p/>
74  * Manager tasks should be antlib-compatible. This implies that a manager task
75  * must take care with its dependencies as well as the actual Ant-based operations it
76  * performs because it is likely to be executed early in an execution iteration as part
77  * of its initialization.
78  *
79  * @since JWare/AntX 0.5
80  * @author ssmc, &copy;2004 <a HREF="http://www.jware.info">iDare&nbsp;Media,&nbsp;Inc.</a>
81  * @version 0.5
82  * @.safety single
83  * @.group impl,helper
84  **/

85
86 public abstract class ManagerTask extends AssertableLibDefinition
87     implements RecoveryEnabled
88 {
89     /**
90      * Initializes a new manager task.
91      * @param iam CV-label (non-null)
92      **/

93     protected ManagerTask(String JavaDoc iam)
94     {
95         super(iam);
96     }
97
98
99
100     /**
101      * Struct that keeps the script facing action name associated
102      * with its matching class method.
103      * @since JWare/AntX 0.5
104      * @author ssmc, &copy;2004 <a HREF="http://www.jware.info">iDare&nbsp;Media,&nbsp;Inc.</a>
105      * @version 0.5
106      */

107     private static class ActionEntry
108     {
109         Method JavaDoc method;
110         String JavaDoc name;
111
112         ActionEntry(String JavaDoc name, Method JavaDoc method) {
113             this.name = name;
114             this.method = method;
115         }
116         boolean matches(String JavaDoc othername) {
117             return this.name.equals(othername);
118         }
119         void call(ManagerTask target, Map JavaDoc params) {
120             try {
121                 method.invoke(target, new Object JavaDoc[]{params});
122             } catch(Exception JavaDoc anyX) {
123                 if (anyX instanceof BuildException) {
124                     throw ((BuildException)anyX);
125                 }
126                 throw new BuildException(anyX,target.getLocation());
127             }
128         }
129         public String JavaDoc toString() {
130             return this.name;
131         }
132     }
133
134
135
136     /**
137      * Creates and adds a new method descriptor to this
138      * manager's set of actions.
139      * @param name normalized action name (non-null)
140      * @param method the associated class method (non-null)
141      **/

142     private void newActionMethod(String JavaDoc name, Method JavaDoc method)
143     {
144         if (m_actors==null) {
145             m_actors = AntXFixture.newList();
146         }
147         m_actors.add(new ActionEntry(name,method));
148     }
149
150
151
152     /**
153      * Searches for a matching method descript for the given
154      * action name. Will return <i>null</i> if no match.
155      * @param name action name (non-null)
156      * @return descriptor or <i>null</i>
157      **/

158     private ActionEntry findActionMethod(String JavaDoc name)
159     {
160         if (m_actors!=null) {
161             name = Tk.lowercaseFrom(name);
162             for (int i=0,N=m_actors.size();i<N;i++) {
163                 ActionEntry e = (ActionEntry)m_actors.get(i);
164                 if (e.matches(name)) {
165                     return e;
166                 }
167             }
168         }
169         return null;
170     }
171
172
173
174     /**
175      * Inspects this manager task and creates a table of all
176      * public "do" methods. This method must be called at
177      * initialization time or <em>before</em> this task is
178      * executed. Can be called multiple times; will create the
179      * set only once.
180      **/

181     private void buildActionMethods()
182     {
183         if (m_actors==null) {
184             verify_(Modifier.isPublic(getClass().getModifiers()), "init- public class");
185             Method JavaDoc[] methods = getClass().getMethods();
186             String JavaDoc loc = LocalTk.purtyLocation(getLocation());
187             final boolean logit = getProject()!=null;
188             for (int i=0;i<methods.length;i++) {
189                 Method JavaDoc m = methods[i];
190                 String JavaDoc name = m.getName();
191                 Class JavaDoc returnType = m.getReturnType();
192                 Class JavaDoc[] args = m.getParameterTypes();
193
194                 if (name.startsWith("do") && !name.equals("do") &&
195                     java.lang.Void.TYPE.equals(returnType) &&
196                     args.length == 1 &&
197                     Map JavaDoc.class.equals(args[0])) {
198
199                     String JavaDoc actionname = Tk.lowercaseFrom(name.substring(2));
200                     newActionMethod(actionname, m);
201                     if (logit) {
202                         log("Recording action '"+actionname+"' @ "+loc, Project.MSG_DEBUG);
203                     }
204                 }
205             }
206         }
207     }
208
209
210
211     /**
212      * Returns the number of valid actions this tasks knows about.
213      * Will return zero if this task has not been initialized or there
214      * are no public "do" action methods.
215      **/

216     public int actionMethodCount()
217     {
218         return m_actors==null ? 0 : m_actors.size();
219     }
220
221
222
223     /**
224      * Builds this task's set of callable actions.
225      */

226     protected void initonce()
227     {
228         super.initonce();
229         buildActionMethods();
230     }
231
232
233
234     /**
235      * Called to trigger the action method associated with the
236      * given name. Subclasses can extend this method to do pre-filtering
237      * before callling this inherited method (where the action's
238      * name <em>must</em> match a "do" method's name).
239      * @param action name of action to trigger (non-null)
240      * @param params generic parameters to method
241      * @param clnt [optional] external problem handler (non-null)
242      * @throws BuildException if unknown action and haltiferror is true.
243      **/

244     protected void doAction(String JavaDoc action, Map JavaDoc params, Requester clnt)
245     {
246         require_(action!=null,"do- nonzro action");
247         ActionEntry e = findActionMethod(action);
248         if (e!=null) {
249             e.call(this,params);
250         }
251         else {
252             if (clnt==null) {
253                 clnt = new Requester.ForComponent(this);
254             }
255             String JavaDoc error = Iteration.uistrs().get("task.manager.err.unknown.operation",action);
256             if (isHaltIfError()) {
257                 clnt.problem(error, Project.MSG_ERR);
258                 throw new BuildException(error, clnt.getLocation());
259             }
260             clnt.problem(error, Project.MSG_WARN);
261         }
262     }
263
264
265
266     /**
267      * Ensures this task's set of callable actions have been
268      * constructed. This backup call is performed in case the application
269      * fails to call the <span class="src">init</span> method for
270      * a programmatically created manager task.
271      */

272     protected void verifyCanExecute_(String JavaDoc calr)
273     {
274         super.verifyCanExecute_(calr);
275         buildActionMethods();
276     }
277
278
279
280     /**
281      * Returns a delimited string of all of this task's valid action
282      * names. The caller supplies the name separating token. Must be
283      * called <em>after</em> this task's actions have been determined
284      * (i&#46;e&#46; after this task has been initialized). This method
285      * is useful when generating error messages or diagnostics.
286      * @param separator the separator token (pass <i>null</i> to use "|")
287      * @return string of action names or empty string if none.
288      **/

289     public final String JavaDoc validActionNames(String JavaDoc separator)
290     {
291         if (m_actors!=null) {
292             StringBuffer JavaDoc sb = AntXFixture.newStringBuffer();
293             if (separator==null) {
294                 separator = "|";
295             }
296             for (int i=0,N=m_actors.size();i<N;i++) {
297                 ActionEntry e = (ActionEntry)m_actors.get(i);
298                 if (i>0) {
299                     sb.append(separator);
300                 }
301                 sb.append(e.name);
302             }
303             return sb.substring(0);
304         }
305         return "";
306     }
307
308
309
310     /**
311      * Tells this task whether to signal an build error if it does not
312      * recognize the requested action or is unable to complete
313      * the action successfully.
314      * @param halt <i>false</i> if should continue.
315      */

316     public void setHaltIfError(boolean halt)
317     {
318         m_willHalt = halt;
319     }
320
321
322
323     /**
324      * Returns <i>true</i> if this task will signal an error if it is
325      * unable to complete the action. Defaults to <i>true</i> if not
326      * set explicitly.
327      * @see #setHaltIfError setHaltIfError()
328      */

329     public boolean isHaltIfError()
330     {
331         return m_willHalt;
332     }
333
334
335
336     private List JavaDoc m_actors;
337     private boolean m_willHalt=true;//NB:die by default!
338
}
339
340 /* end-of-ManagerTask.java */
Popular Tags