KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tools > ant > taskdefs > Definer


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */

18
19 package org.apache.tools.ant.taskdefs;
20
21 import java.io.File JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.io.InputStream JavaDoc;
24 import java.net.URL JavaDoc;
25 import java.util.Map JavaDoc;
26 import java.util.HashMap JavaDoc;
27 import java.util.Enumeration JavaDoc;
28 import java.util.Locale JavaDoc;
29 import java.util.NoSuchElementException JavaDoc;
30 import java.util.Properties JavaDoc;
31
32 import org.apache.tools.ant.AntTypeDefinition;
33 import org.apache.tools.ant.ComponentHelper;
34 import org.apache.tools.ant.BuildException;
35 import org.apache.tools.ant.Project;
36 import org.apache.tools.ant.ProjectHelper;
37 import org.apache.tools.ant.MagicNames;
38 import org.apache.tools.ant.util.FileUtils;
39 import org.apache.tools.ant.types.EnumeratedAttribute;
40
41 /**
42  * Base class for Taskdef and Typedef - handles all
43  * the attributes for Typedef. The uri and class
44  * handling is handled by DefBase
45  *
46  * @since Ant 1.4
47  */

48 public abstract class Definer extends DefBase {
49
50     /**
51      * the extension of an antlib file for autoloading.
52      * {@value[
53      */

54     private static final String JavaDoc ANTLIB_XML = "/antlib.xml";
55
56     private static class ResourceStack extends ThreadLocal JavaDoc {
57         public Object JavaDoc initialValue() {
58             return new HashMap JavaDoc();
59         }
60         Map JavaDoc getStack() {
61             return (Map JavaDoc) get();
62         }
63     }
64     private static ResourceStack resourceStack = new ResourceStack();
65     private String JavaDoc name;
66     private String JavaDoc classname;
67     private File JavaDoc file;
68     private String JavaDoc resource;
69
70     private int format = Format.PROPERTIES;
71     private boolean definerSet = false;
72     private int onError = OnError.FAIL;
73     private String JavaDoc adapter;
74     private String JavaDoc adaptTo;
75
76     private Class JavaDoc adapterClass;
77     private Class JavaDoc adaptToClass;
78
79     /**
80      * Enumerated type for onError attribute
81      *
82      * @see EnumeratedAttribute
83      */

84     public static class OnError extends EnumeratedAttribute {
85         /** Enumerated values */
86         public static final int FAIL = 0, REPORT = 1, IGNORE = 2, FAIL_ALL = 3;
87
88         /**
89          * text value of onerror option {@value}
90          */

91         public static final String JavaDoc POLICY_FAIL = "fail";
92         /**
93          * text value of onerror option {@value}
94          */

95         public static final String JavaDoc POLICY_REPORT = "report";
96         /**
97          * text value of onerror option {@value}
98          */

99         public static final String JavaDoc POLICY_IGNORE = "ignore";
100         /**
101          * text value of onerror option {@value}
102          */

103         public static final String JavaDoc POLICY_FAILALL = "failall";
104
105         /**
106          * Constructor
107          */

108         public OnError() {
109             super();
110         }
111
112         /**
113          * Constructor using a string.
114          * @param value the value of the attribute
115          */

116         public OnError(String JavaDoc value) {
117             setValue(value);
118         }
119
120         /**
121          * get the values
122          * @return an array of the allowed values for this attribute.
123          */

124         public String JavaDoc[] getValues() {
125             return new String JavaDoc[] {POLICY_FAIL, POLICY_REPORT, POLICY_IGNORE, POLICY_FAILALL};
126         }
127     }
128
129     /**
130      * Enumerated type for format attribute
131      *
132      * @see EnumeratedAttribute
133      */

134     public static class Format extends EnumeratedAttribute {
135         /** Enumerated values */
136         public static final int PROPERTIES = 0, XML = 1;
137
138         /**
139          * get the values
140          * @return an array of the allowed values for this attribute.
141          */

142         public String JavaDoc[] getValues() {
143             return new String JavaDoc[] {"properties", "xml"};
144         }
145     }
146
147     /**
148      * What to do if there is an error in loading the class.
149      * <dl>
150      * <li>error - throw build exception</li>
151      * <li>report - output at warning level</li>
152      * <li>ignore - output at debug level</li>
153      * </dl>
154      *
155      * @param onError an <code>OnError</code> value
156      */

157     public void setOnError(OnError onError) {
158         this.onError = onError.getIndex();
159     }
160
161     /**
162      * Sets the format of the file or resource
163      * @param format the enumerated value - xml or properties
164      */

165     public void setFormat(Format format) {
166         this.format = format.getIndex();
167     }
168
169     /**
170      * @return the name for this definition
171      */

172     public String JavaDoc getName() {
173         return name;
174     }
175
176     /**
177      * @return the file containing definitions
178      */

179     public File JavaDoc getFile() {
180         return file;
181     }
182
183     /**
184      * @return the resource containing definitions
185      */

186     public String JavaDoc getResource() {
187         return resource;
188     }
189
190
191     /**
192      * Run the definition.
193      *
194      * @exception BuildException if an error occurs
195      */

196     public void execute() throws BuildException {
197         ClassLoader JavaDoc al = createLoader();
198
199         if (!definerSet) {
200             //we arent fully defined yet. this is an error unless
201
//we are in an antlib, in which case the resource name is determined
202
//automatically.
203
//NB: URIs in the ant core package will be "" at this point.
204
if (getURI() == null) {
205                 throw new BuildException(
206                         "name, file or resource attribute of "
207                                 + getTaskName() + " is undefined",
208                         getLocation());
209             }
210
211             if (getURI().startsWith(MagicNames.ANTLIB_PREFIX)) {
212                 //convert the URI to a resource
213
String JavaDoc uri1 = getURI();
214                 setResource(makeResourceFromURI(uri1));
215             } else {
216                 throw new BuildException(
217                         "Only antlib URIs can be located from the URI alone,"
218                                 + "not the URI " + getURI());
219             }
220         }
221
222         if (name != null) {
223             if (classname == null) {
224                 throw new BuildException(
225                     "classname attribute of " + getTaskName() + " element "
226                     + "is undefined", getLocation());
227             }
228             addDefinition(al, name, classname);
229         } else {
230             if (classname != null) {
231                 String JavaDoc msg = "You must not specify classname "
232                     + "together with file or resource.";
233                 throw new BuildException(msg, getLocation());
234             }
235             Enumeration JavaDoc/*<URL>*/ urls = null;
236             if (file != null) {
237                 final URL JavaDoc url = fileToURL();
238                 if (url == null) {
239                     return;
240                 }
241                 urls = new Enumeration JavaDoc() {
242                     private boolean more = true;
243                     public boolean hasMoreElements() {
244                         return more;
245                     }
246                     public Object JavaDoc nextElement() throws NoSuchElementException JavaDoc {
247                         if (more) {
248                             more = false;
249                             return url;
250                         } else {
251                             throw new NoSuchElementException JavaDoc();
252                         }
253                     }
254                 };
255             } else {
256                 urls = resourceToURLs(al);
257             }
258
259             while (urls.hasMoreElements()) {
260                 URL JavaDoc url = (URL JavaDoc) urls.nextElement();
261
262                 int fmt = this.format;
263                 if (url.toString().toLowerCase(Locale.US).endsWith(".xml")) {
264                     fmt = Format.XML;
265                 }
266
267                 if (fmt == Format.PROPERTIES) {
268                     loadProperties(al, url);
269                     break;
270                 } else {
271                     if (resourceStack.getStack().get(url) != null) {
272                         log("Warning: Recursive loading of " + url
273                             + " ignored"
274                             + " at " + getLocation()
275                             + " originally loaded at "
276                             + resourceStack.getStack().get(url),
277                             Project.MSG_WARN);
278                     } else {
279                         try {
280                             resourceStack.getStack().put(url, getLocation());
281                             loadAntlib(al, url);
282                         } finally {
283                             resourceStack.getStack().remove(url);
284                         }
285                     }
286                 }
287             }
288         }
289     }
290
291     /**
292      * This is where the logic to map from a URI to an antlib resource
293      * is kept.
294      * @param uri the xml namespace uri that to convert.
295      * @return the name of a resource. It may not exist
296      */

297
298     public static String JavaDoc makeResourceFromURI(String JavaDoc uri) {
299         String JavaDoc path = uri.substring(MagicNames.ANTLIB_PREFIX.length());
300         String JavaDoc resource;
301         if (path.startsWith("//")) {
302             //handle new style full paths to an antlib, in which
303
//all but the forward slashes are allowed.
304
resource = path.substring("//".length());
305             if (!resource.endsWith(".xml")) {
306                 //if we haven't already named an XML file, it gets antlib.xml
307
resource = resource + ANTLIB_XML;
308             }
309         } else {
310             //convert from a package to a path
311
resource = path.replace('.', '/') + ANTLIB_XML;
312         }
313         return resource;
314     }
315
316     /**
317      * Convert a file to a file: URL.
318      *
319      * @return the URL, or null if it isn't valid and the active error policy
320      * is not to raise a fault
321      * @throws BuildException if the file is missing/not a file and the
322      * policy requires failure at this point.
323      */

324     private URL JavaDoc fileToURL() {
325         String JavaDoc message = null;
326         if (!(file.exists())) {
327             message = "File " + file + " does not exist";
328         }
329         if (message == null && !(file.isFile())) {
330             message = "File " + file + " is not a file";
331         }
332         try {
333             if (message == null) {
334                 return file.toURL();
335             }
336         } catch (Exception JavaDoc ex) {
337             message =
338                 "File " + file + " cannot use as URL: "
339                 + ex.toString();
340         }
341         // Here if there is an error
342
switch (onError) {
343             case OnError.FAIL_ALL:
344                 throw new BuildException(message);
345             case OnError.FAIL:
346                 // Fall Through
347
case OnError.REPORT:
348                 log(message, Project.MSG_WARN);
349                 break;
350             case OnError.IGNORE:
351                 // log at a lower level
352
log(message, Project.MSG_VERBOSE);
353                 break;
354             default:
355                 // Ignore the problem
356
break;
357         }
358         return null;
359     }
360
361     private Enumeration JavaDoc/*<URL>*/ resourceToURLs(ClassLoader JavaDoc classLoader) {
362         Enumeration JavaDoc ret;
363         try {
364             ret = classLoader.getResources(resource);
365         } catch (IOException JavaDoc e) {
366             throw new BuildException(
367                 "Could not fetch resources named " + resource,
368                 e, getLocation());
369         }
370         if (!ret.hasMoreElements()) {
371             String JavaDoc message = "Could not load definitions from resource "
372                 + resource + ". It could not be found.";
373             switch (onError) {
374                 case OnError.FAIL_ALL:
375                     throw new BuildException(message);
376                 case OnError.FAIL:
377                 case OnError.REPORT:
378                     log(message, Project.MSG_WARN);
379                     break;
380                 case OnError.IGNORE:
381                     log(message, Project.MSG_VERBOSE);
382                     break;
383                 default:
384                     // Ignore the problem
385
break;
386             }
387         }
388         return ret;
389     }
390
391     /**
392      * Load type definitions as properties from a URL.
393      *
394      * @param al the classloader to use
395      * @param url the url to get the definitions from
396      */

397     protected void loadProperties(ClassLoader JavaDoc al, URL JavaDoc url) {
398         InputStream JavaDoc is = null;
399         try {
400             is = url.openStream();
401             if (is == null) {
402                 log("Could not load definitions from " + url,
403                     Project.MSG_WARN);
404                 return;
405             }
406             Properties JavaDoc props = new Properties JavaDoc();
407             props.load(is);
408             Enumeration JavaDoc keys = props.keys();
409             while (keys.hasMoreElements()) {
410                 name = ((String JavaDoc) keys.nextElement());
411                 classname = props.getProperty(name);
412                 addDefinition(al, name, classname);
413             }
414         } catch (IOException JavaDoc ex) {
415             throw new BuildException(ex, getLocation());
416         } finally {
417             FileUtils.close(is);
418         }
419     }
420
421     /**
422      * Load an antlib from a URL.
423      *
424      * @param classLoader the classloader to use.
425      * @param url the url to load the definitions from.
426      */

427     private void loadAntlib(ClassLoader JavaDoc classLoader, URL JavaDoc url) {
428         try {
429             Antlib antlib = Antlib.createAntlib(getProject(), url, getURI());
430             antlib.setClassLoader(classLoader);
431             antlib.setURI(getURI());
432             antlib.execute();
433         } catch (BuildException ex) {
434             throw ProjectHelper.addLocationToBuildException(
435                 ex, getLocation());
436         }
437     }
438
439     /**
440      * Name of the property file to load
441      * ant name/classname pairs from.
442      * @param file the file
443      */

444     public void setFile(File JavaDoc file) {
445         if (definerSet) {
446             tooManyDefinitions();
447         }
448         definerSet = true;
449         this.file = file;
450     }
451
452     /**
453      * Name of the property resource to load
454      * ant name/classname pairs from.
455      * @param res the resource to use
456      */

457     public void setResource(String JavaDoc res) {
458         if (definerSet) {
459             tooManyDefinitions();
460         }
461         definerSet = true;
462         this.resource = res;
463     }
464
465     /**
466      * Antlib attribute, sets resource and uri.
467      * uri is set the antlib value and, resource is set
468      * to the antlib.xml resource in the classpath.
469      * For example antlib="antlib:org.acme.bland.cola"
470      * corresponds to uri="antlib:org.acme.bland.cola"
471      * resource="org/acme/bland/cola/antlib.xml".
472      * ASF Bugzilla Bug 31999
473      * @param antlib the value to set.
474      */

475     public void setAntlib(String JavaDoc antlib) {
476         if (definerSet) {
477             tooManyDefinitions();
478         }
479         if (!antlib.startsWith("antlib:")) {
480             throw new BuildException(
481                 "Invalid antlib attribute - it must start with antlib:");
482         }
483         setURI(antlib);
484         this.resource = antlib.substring("antlib:".length()).replace('.', '/')
485             + "/antlib.xml";
486         definerSet = true;
487     }
488
489     /**
490      * Name of the definition
491      * @param name the name of the definition
492      */

493     public void setName(String JavaDoc name) {
494         if (definerSet) {
495             tooManyDefinitions();
496         }
497         definerSet = true;
498         this.name = name;
499     }
500
501     /**
502      * Returns the classname of the object we are defining.
503      * May be <code>null</code>.
504      * @return the class name
505      */

506     public String JavaDoc getClassname() {
507         return classname;
508     }
509
510     /**
511      * The full class name of the object being defined.
512      * Required, unless file or resource have
513      * been specified.
514      * @param classname the name of the class
515      */

516     public void setClassname(String JavaDoc classname) {
517         this.classname = classname;
518     }
519
520     /**
521      * Set the class name of the adapter class.
522      * An adapter class is used to proxy the
523      * definition class. It is used if the
524      * definition class is not assignable to
525      * the adaptto class, or if the adaptto
526      * class is not present.
527      *
528      * @param adapter the name of the adapter class
529      */

530
531     public void setAdapter(String JavaDoc adapter) {
532         this.adapter = adapter;
533     }
534
535     /**
536      * Set the adapter class.
537      *
538      * @param adapterClass the class to use to adapt the definition class
539      */

540     protected void setAdapterClass(Class JavaDoc adapterClass) {
541         this.adapterClass = adapterClass;
542     }
543
544     /**
545      * Set the classname of the class that the definition
546      * must be compatible with, either directly or
547      * by use of the adapter class.
548      *
549      * @param adaptTo the name of the adaptto class
550      */

551     public void setAdaptTo(String JavaDoc adaptTo) {
552         this.adaptTo = adaptTo;
553     }
554
555     /**
556      * Set the class for adaptToClass, to be
557      * used by derived classes, used instead of
558      * the adaptTo attribute.
559      *
560      * @param adaptToClass the class for adapto.
561      */

562     protected void setAdaptToClass(Class JavaDoc adaptToClass) {
563         this.adaptToClass = adaptToClass;
564     }
565
566
567     /**
568      * Add a definition using the attributes of Definer
569      *
570      * @param al the ClassLoader to use
571      * @param name the name of the definition
572      * @param classname the classname of the definition
573      * @exception BuildException if an error occurs
574      */

575     protected void addDefinition(ClassLoader JavaDoc al, String JavaDoc name, String JavaDoc classname)
576         throws BuildException {
577         Class JavaDoc cl = null;
578         try {
579             try {
580                 name = ProjectHelper.genComponentName(getURI(), name);
581
582                 if (onError != OnError.IGNORE) {
583                     cl = Class.forName(classname, true, al);
584                 }
585
586                 if (adapter != null) {
587                     adapterClass = Class.forName(adapter, true, al);
588                 }
589
590                 if (adaptTo != null) {
591                     adaptToClass = Class.forName(adaptTo, true, al);
592                 }
593
594                 AntTypeDefinition def = new AntTypeDefinition();
595                 def.setName(name);
596                 def.setClassName(classname);
597                 def.setClass(cl);
598                 def.setAdapterClass(adapterClass);
599                 def.setAdaptToClass(adaptToClass);
600                 def.setClassLoader(al);
601                 if (cl != null) {
602                     def.checkClass(getProject());
603                 }
604                 ComponentHelper.getComponentHelper(getProject())
605                     .addDataTypeDefinition(def);
606             } catch (ClassNotFoundException JavaDoc cnfe) {
607                 String JavaDoc msg = getTaskName() + " class " + classname
608                     + " cannot be found";
609                 throw new BuildException(msg, cnfe, getLocation());
610             } catch (NoClassDefFoundError JavaDoc ncdfe) {
611                 String JavaDoc msg = getTaskName() + " A class needed by class "
612                     + classname + " cannot be found: " + ncdfe.getMessage();
613                 throw new BuildException(msg, ncdfe, getLocation());
614             }
615         } catch (BuildException ex) {
616             switch (onError) {
617                 case OnError.FAIL_ALL:
618                 case OnError.FAIL:
619                     throw ex;
620                 case OnError.REPORT:
621                     log(ex.getLocation() + "Warning: " + ex.getMessage(),
622                         Project.MSG_WARN);
623                     break;
624                 default:
625                     log(ex.getLocation() + ex.getMessage(),
626                         Project.MSG_DEBUG);
627             }
628         }
629     }
630
631     /**
632      * handle too many definitions by raising an exception.
633      * @throws BuildException always.
634      */

635     private void tooManyDefinitions() {
636         throw new BuildException(
637             "Only one of the attributes name, file and resource"
638             + " can be set", getLocation());
639     }
640 }
641
Popular Tags