KickJava   Java API By Example, From Geeks To Geeks.

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


1 /**
2  * $Id: MacroMaker.java 180 2007-03-15 12:56:38Z 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.util.Map JavaDoc;
32
33 import org.apache.tools.ant.BuildException;
34 import org.apache.tools.ant.Project;
35 import org.apache.tools.ant.Task;
36 import org.apache.tools.ant.TaskContainer;
37 import org.apache.tools.ant.UnknownElement;
38 import org.apache.tools.ant.taskdefs.MacroDef;
39
40 import com.idaremedia.antx.AssertableLibDefinition;
41 import com.idaremedia.antx.apis.Nameable;
42 import com.idaremedia.antx.helpers.Tk;
43 import com.idaremedia.antx.ownhelpers.TaskExaminer;
44 import com.idaremedia.antx.ownhelpers.UEContainerProxy;
45
46 /**
47  * Base implementation of a macro proxy that limits what gets put in the macro. This
48  * class is a <em>&lt;macrodef&gt;</em> builder; it always creates a macro in the
49  * enclosing project (the macro may, in turn, add its own type definition to the project).
50  *
51  * @since JWare/AntX 0.4
52  * @author ssmc, &copy;2004 <a HREF="http://www.jware.info">iDare&nbsp;Media,&nbsp;Inc.</a>
53  * @version 0.5
54  * @.safety single
55  * @.group impl,infra
56  * @.pattern GoF.Proxy
57  * @.pattern GoF.Builder
58  * @.expects Ant 1.6
59  **/

60
61 public abstract class MacroMaker extends AssertableLibDefinition
62     implements StrictMacroDef, Nameable, TaskContainer
63 {
64     /**
65      * Assumed name of the builtin Ant
66      * <span class="src">&lt;macrodef&gt;</span> task.
67      **/

68     public static final String JavaDoc MACRO_TASKNAME="macrodef";
69
70
71     /**
72      * Initializes a new macro maker instance for a subclass.
73      * @param iam CV-label (non-null)
74      **/

75     protected MacroMaker(String JavaDoc iam)
76     {
77         super(iam);
78     }
79
80
81     /**
82      * Called to initialize this definition before any nested items
83      * are added or (script-facing) parameters applied. The default
84      * implementation creates the underlying macro definition.
85      * If you override this method, you must call this inherited
86      * method before using the underlying macro definition.
87      * @see #getMacro
88      **/

89     protected void initonce()
90     {
91         super.initonce();
92         if (getMacroImpl()==null) {
93             verifyInProject_("init");
94             createMacroImpl();
95         }
96     }
97
98
99     /**
100      * Execute this definition; same as {@linkplain #executeMacroImpl}
101      * by default. Subclasses can decorate the macro's execution by
102      * overriding this method.
103      **/

104     public void execute()
105     {
106         executeMacroImpl();
107     }
108
109
110     /**
111      * Installs this definition's underlying macro definition.
112      * @throws BuildException if macro definition does
113      **/

114     protected final void executeMacroImpl()
115     {
116         getMacro().execute();
117     }
118
119
120     /**
121      * Initializes this definition's enclosing project. If called
122      * after {@linkplain #init init()} it will also update our macro
123      * definition's project.
124      **/

125     public void setProject(Project P)
126     {
127         super.setProject(P);
128         if (getMacroImpl()!=null) {
129             getMacroImpl().setProject(P);
130         }
131     }
132
133
134     /**
135      * Sets a custom class loader for this definition. Will
136      * also update the underlying macro definition's loader.
137      * @param cL the class loader
138      **/

139     public void setAntlibClassLoader(ClassLoader JavaDoc cL)
140     {
141         super.setAntlibClassLoader(cL);
142         getMacro().setAntlibClassLoader(cL);
143     }
144
145
146     /**
147      * Sets this definition's namespace URI. Will also update the
148      * underlying macro definition's URI.
149      * @param uri the uri (non-null)
150      **/

151     public void setURI(String JavaDoc uri)
152     {
153         super.setURI(uri);
154         getMacro().setURI(getURI());
155     }
156
157
158     /**
159      * Sets this definition's and the macro's name. You must
160      * specify a definition name.
161      * @param name the macro's name (non-whitespace)
162      * @see #setId setId
163      **/

164     public final void setName(String JavaDoc name)
165     {
166         require_(!Tk.isWhitespace(name),"setName- nonzro name");
167         getMacro().setName(name);
168         m_macroName = name;
169     }
170
171
172     /**
173      * Returns this definition's marco's name. Will return
174      * <i>null</i> if name never set.
175      **/

176     public final String JavaDoc getName()
177     {
178         return m_macroName;
179     }
180
181
182     /**
183      * Sets this maker's global reference id and default macro
184      * name if one has not been defined explicitly. This method is
185      * a convenience that let's script authors use the builtin
186      * Ant <span class="src">id</span> attribute to create a
187      * reference and define the macro's name in single step.
188      **/

189     public void setId(String JavaDoc id)
190     {
191         if (m_macroName==null) {
192             m_macroName = id;
193         }
194     }
195
196
197     /**
198      * Adds a new attribute definition to this definition's macro.
199      * Subclasses should call this method from their script-facing
200      * APIs.
201      * @param attr the attribute definition (non-null)
202      **/

203     protected final void addMacroParameter(MacroDef.Attribute attr)
204     {
205         require_(attr!=null,"addAttr- nonzro attr");
206         getMacro().addConfiguredAttribute(attr);
207     }
208
209
210     /**
211      * Adds a new template element to this definition's macro.
212      * Subclasses should call this method from their script-facing
213      * APIs or at initialization time to install client-supplied
214      * elements.
215      * @param name the name of the element client will provide (non-null)
216      * @param optional <i>true</i> if this is an optional item
217      **/

218     protected final void addMacroElement(String JavaDoc name, boolean optional)
219     {
220         require_(name!=null,"addElem- nonzro name");
221         MacroDef.TemplateElement elem = new MacroDef.TemplateElement();
222         elem.setName(name);
223         elem.setOptional(optional);
224         getMacro().addConfiguredElement(elem);
225     }
226
227
228     /**
229      * Factory method for this definition's underlying macro
230      * definition. This default implementation creates a standard
231      * Ant <span class="src">&lt;macrodef&gt;</span>. Expects this
232      * task's project to be already initialized. If you override
233      * this method and do not use this default implementation, you
234      * <em>must</em> call {@linkplain #setMacroImpl setMacroImpl()}
235      * before returning.
236      * @see #getMacro
237      * @see #MACRO_TASKNAME
238      **/

239     protected MacroDef createMacroImpl()
240     {
241         Project P= getProject();
242         MacroDef impl = (MacroDef)P.createTask(MACRO_TASKNAME);
243         impl.setProject(P);
244         impl.setLocation(getLocation());
245         impl.setOwningTarget(getOwningTarget());
246         impl.init();
247         setMacroImpl(impl);
248         return getMacro();
249     }
250
251
252     /**
253      * Initializes this definition's underlying macro definition.
254      * This method must be called from the macro
255      * {@linkplain #createMacroImpl factory method}.
256      * @param impl the definition object (non-null)
257      * @.sideeffect A nested sequential is automatically added to
258      * macro definition.
259      **/

260     protected final void setMacroImpl(MacroDef impl)
261     {
262         require_(impl!=null,"setImpl- nonzro impl");
263         m_macroDefinition = impl;
264         m_macroMainImpl = m_macroDefinition.createSequential();
265         m_macroMain = m_macroMainImpl;//dflt adds directly to macro
266
}
267
268
269     /**
270      * Returns this definition's underlying macro definition.
271      * Will return <i>null</i> if macro not created yet.
272      * @see #getMacro
273      **/

274     private MacroDef getMacroImpl()
275     {
276         return m_macroDefinition;
277     }
278
279
280     /**
281      * Installs a single top-level task that encloses all tasks
282      * declared in this macro. This is useful to install automatic
283      * configuration or protected tasksets for macro's contents. This
284      * method can be called <em>once</em> at initialization time
285      * <em>after</em> the underlying macro has been created (usually
286      * as a customization to {@linkplain #createMacroImpl}). Use the
287      * returned handle to further tweak the body element's attributes
288      * or to manually add required nested elements.
289      * @param tag unqualified (task) name of top-level task (non-null)
290      * @param attrs [optional] automatic parameters for new task
291      * @param inheritNS <i>true</i> if this macro's namespace should
292      * be passed on to top-level element
293      * @see TaskExaminer#newUEProxy TaskExaminer.newUEProxy(&#8230;)
294      * @see #addImplTask addImplTask
295      **/

296     protected final UEContainerProxy installBodyWrap(String JavaDoc tag,
297                                                      Map JavaDoc attrs,
298                                                      boolean inheritNS)
299     {
300         verify_(m_macroMainImpl.getNested().isEmpty(),
301                 "instalBodyWrap- none installed");
302
303         Task nsSource=null;//NB:=>Ant namespace
304
if (inheritNS) {
305             nsSource = this;
306         }
307         UnknownElement rootItem =
308             TaskExaminer.newUEProxy(tag,attrs,nsSource,getProject());
309
310         m_macroMainImpl.addTask(rootItem);
311
312         UEContainerProxy bodyProxy = new UEContainerProxy(rootItem);
313         m_macroMain = bodyProxy;
314
315         return bodyProxy;
316     }
317
318
319     /**
320      * Returns this definition's underlying macro definition ensuring
321      * that said definition is not <i>null</i>. This accessor is exposed
322      * so that subclasses can tweak the non-body related macro parameters
323      * like attributes and elements directly. To modify the macro's
324      * main definition <em>use the {@linkplain #getMacroBody} method</em>.
325      * @throws IllegalStateException if macro definition not initialized
326      * @see #createMacroImpl
327      **/

328     protected final MacroDef getMacro()
329     {
330         ensure_(m_macroDefinition!=null,"macro- inited");
331         return m_macroDefinition;
332     }
333
334
335     /**
336      * Returns this definition's underlying macro's task container
337      * or body as we call it. The returned body is never <i>null</i>.
338      * Subclasses can add required task <em>proxies</em> directly
339      * to this container at initialization time.
340      * @throws IllegalStateException if macro definition not initialized
341      * @see #addImplTask addImplTask
342      **/

343     protected final TaskContainer getMacroBody()
344     {
345         ensure_(m_macroMain!=null,"macroBody- inited");
346         return m_macroMain;
347     }
348
349
350     /**
351      * Called to include the given task proxy in this definition's
352      * macro. The proxy is first screened through {@linkplain #includeTask
353      * includeTask()} before it is added to the underlying macro's
354      * <span class="src">&lt;sequential&gt;</span> list (or a top-level
355      * body wrapper). Note that this method is called <em>after</em> any
356      * explicit "<span class="src">add</span>" and/or
357      * "<span class="src">create</span>" methods in your subclass.
358      * @param task task proxy to be added (non-null UnknownElement)
359      * @throws BuildException if task is unacceptable
360      **/

361     public final void addTask(Task task)
362     {
363         require_(task instanceof UnknownElement,"addTask- proxy task");
364
365         Class JavaDoc taskClass = TaskExaminer.trueClass(task);
366
367         if (taskClass!=null && includeTask(taskClass, task)) {
368             getMacroBody().addTask(task);
369         } else {
370             String JavaDoc ermsg = uistrs().get("macro.nested.task.disallowed",
371                                         task.getTaskName(), this.getTaskName());
372             log(ermsg, Project.MSG_ERR);
373             throw new BuildException(ermsg,getLocation());
374         }
375     }
376
377
378     /**
379      * Returns <i>true</i> if a task of given class can be
380      * added to this definition's body. This method is the primary
381      * control mechanism that subclasses use to control what gets
382      * included in final macro. Return <i>false</i> if task
383      * should not be included (will trigger a build exception). This
384      * default method always returns <i>true</i>.
385      * @param taskClass candidate task's class (non-null)
386      * @param taskProxy task proxy item (non-null UnknownElement)
387      **/

388     protected boolean includeTask(Class JavaDoc taskClass, Task taskProxy)
389     {
390         return true;
391     }
392
393
394
395     /**
396      * Call to include an implementation defined (and required) nested
397      * macro task(set). This method is usually used in tandem with the
398      * body wrap functionality to install predefined special elements
399      * of a strict enclosing taskset. You can use the returned handle
400      * to add nested elements to a special task(set).
401      * @param tag unqualified (task) name of special task (non-null)
402      * @param attrs [optional] automatic parameters for new task
403      * @param inheritNS <i>true</i> if this macro's namespace should
404      * be passed on to new element
405      **/

406     protected final UEContainerProxy addImplTask(String JavaDoc tag, Map JavaDoc attrs,
407                                                  boolean inheritNS)
408     {
409         Task nsSource=null;//NB:=>Ant namespace
410
if (inheritNS) {
411             nsSource = this;
412         }
413         UnknownElement implItem =
414             TaskExaminer.newUEProxy(tag,attrs,nsSource,getProject());
415
416         getMacroBody().addTask(implItem);
417
418         return new UEContainerProxy(implItem);
419     }
420
421
422     private MacroDef m_macroDefinition;
423     private MacroDef.NestedSequential m_macroMainImpl;
424     private TaskContainer m_macroMain;
425     private String JavaDoc m_macroName;
426 }
427
428 /* end-of-MacroMaker.java */
429
Popular Tags