source: other-projects/trunk/gs3-release-maker/apache-ant-1.6.5/src/main/org/apache/tools/ant/taskdefs/Definer.java@ 14627

Last change on this file since 14627 was 14627, checked in by oranfry, 17 years ago

initial import of the gs3-release-maker

File size: 15.6 KB
Line 
1/*
2 * Copyright 2001-2004 The Apache Software Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18package org.apache.tools.ant.taskdefs;
19
20import java.io.File;
21import java.io.IOException;
22import java.io.InputStream;
23import java.net.URL;
24import java.util.Map;
25import java.util.HashMap;
26import java.util.Enumeration;
27import java.util.Locale;
28import java.util.NoSuchElementException;
29import java.util.Properties;
30
31import org.apache.tools.ant.AntTypeDefinition;
32import org.apache.tools.ant.ComponentHelper;
33import org.apache.tools.ant.BuildException;
34import org.apache.tools.ant.Project;
35import org.apache.tools.ant.ProjectHelper;
36import org.apache.tools.ant.types.EnumeratedAttribute;
37
38/**
39 * Base class for Taskdef and Typedef - handles all
40 * the attributes for Typedef. The uri and class
41 * handling is handled by DefBase
42 *
43 * @since Ant 1.4
44 */
45public abstract class Definer extends DefBase {
46 private static class ResourceStack extends ThreadLocal {
47 public Object initialValue() {
48 return new HashMap();
49 }
50 Map getStack() {
51 return (Map) get();
52 }
53 }
54 private static ResourceStack resourceStack = new ResourceStack();
55 private String name;
56 private String classname;
57 private File file;
58 private String resource;
59
60 private int format = Format.PROPERTIES;
61 private boolean definerSet = false;
62 private int onError = OnError.FAIL;
63 private String adapter;
64 private String adaptTo;
65
66 private Class adapterClass;
67 private Class adaptToClass;
68
69 /**
70 * Enumerated type for onError attribute
71 *
72 * @see EnumeratedAttribute
73 */
74 public static class OnError extends EnumeratedAttribute {
75 /** Enumerated values */
76 public static final int FAIL = 0, REPORT = 1, IGNORE = 2;
77 /**
78 * Constructor
79 */
80 public OnError() {
81 super();
82 }
83
84 /**
85 * Constructor using a string.
86 * @param value the value of the attribute
87 */
88 public OnError(String value) {
89 setValue(value);
90 }
91
92 /**
93 * get the values
94 * @return an array of the allowed values for this attribute.
95 */
96 public String[] getValues() {
97 return new String[] {"fail", "report", "ignore"};
98 }
99 }
100
101 /**
102 * Enumerated type for format attribute
103 *
104 * @see EnumeratedAttribute
105 */
106 public static class Format extends EnumeratedAttribute {
107 /** Enumerated values */
108 public static final int PROPERTIES = 0, XML = 1;
109
110 /**
111 * get the values
112 * @return an array of the allowed values for this attribute.
113 */
114 public String[] getValues() {
115 return new String[] {"properties", "xml"};
116 }
117 }
118
119 /**
120 * What to do if there is an error in loading the class.
121 * <dl>
122 * <li>error - throw build exception</li>
123 * <li>report - output at warning level</li>
124 * <li>ignore - output at debug level</li>
125 * </dl>
126 *
127 * @param onError an <code>OnError</code> value
128 */
129 public void setOnError(OnError onError) {
130 this.onError = onError.getIndex();
131 }
132
133 /**
134 * Sets the format of the file or resource
135 * @param format the enumerated value - xml or properties
136 */
137 public void setFormat(Format format) {
138 this.format = format.getIndex();
139 }
140
141 /**
142 * @return the name for this definition
143 */
144 public String getName() {
145 return name;
146 }
147
148 /**
149 * @return the file containing definitions
150 */
151 public File getFile() {
152 return file;
153 }
154
155 /**
156 * @return the resource containing definitions
157 */
158 public String getResource() {
159 return resource;
160 }
161
162
163 /**
164 * Run the definition.
165 *
166 * @exception BuildException if an error occurs
167 */
168 public void execute() throws BuildException {
169 ClassLoader al = createLoader();
170
171 if (!definerSet) {
172 throw new BuildException(
173 "name, file or resource attribute of "
174 + getTaskName() + " is undefined", getLocation());
175 }
176
177 if (name != null) {
178 if (classname == null) {
179 throw new BuildException(
180 "classname attribute of " + getTaskName() + " element "
181 + "is undefined", getLocation());
182 }
183 addDefinition(al, name, classname);
184 } else {
185 if (classname != null) {
186 String msg = "You must not specify classname "
187 + "together with file or resource.";
188 throw new BuildException(msg, getLocation());
189 }
190 Enumeration/*<URL>*/ urls = null;
191 if (file != null) {
192 final URL url = fileToURL();
193 if (url == null) {
194 return;
195 }
196 urls = new Enumeration() {
197 private boolean more = true;
198 public boolean hasMoreElements() {
199 return more;
200 }
201 public Object nextElement() throws NoSuchElementException {
202 if (more) {
203 more = false;
204 return url;
205 } else {
206 throw new NoSuchElementException();
207 }
208 }
209 };
210 } else {
211 urls = resourceToURLs(al);
212 }
213
214 while (urls.hasMoreElements()) {
215 URL url = (URL) urls.nextElement();
216
217 int format = this.format;
218 if (url.toString().toLowerCase(Locale.US).endsWith(".xml")) {
219 format = Format.XML;
220 }
221
222 if (format == Format.PROPERTIES) {
223 loadProperties(al, url);
224 break;
225 } else {
226 if (resourceStack.getStack().get(url) != null) {
227 log("Warning: Recursive loading of " + url
228 + " ignored"
229 + " at " + getLocation()
230 + " originally loaded at "
231 + resourceStack.getStack().get(url),
232 Project.MSG_WARN);
233 } else {
234 try {
235 resourceStack.getStack().put(url, getLocation());
236 loadAntlib(al, url);
237 } finally {
238 resourceStack.getStack().remove(url);
239 }
240 }
241 }
242 }
243 }
244 }
245
246 private URL fileToURL() {
247 if (!(file.exists())) {
248 log("File " + file + " does not exist", Project.MSG_WARN);
249 return null;
250 }
251 if (!(file.isFile())) {
252 log("File " + file + " is not a file", Project.MSG_WARN);
253 return null;
254 }
255 try {
256 return file.toURL();
257 } catch (Exception ex) {
258 log("File " + file + " cannot use as URL: "
259 + ex.toString(), Project.MSG_WARN);
260 return null;
261 }
262 }
263
264 private Enumeration/*<URL>*/ resourceToURLs(ClassLoader classLoader) {
265 Enumeration ret;
266 try {
267 ret = classLoader.getResources(resource);
268 } catch (IOException e) {
269 throw new BuildException(
270 "Could not fetch resources named " + resource,
271 e, getLocation());
272 }
273 if (!ret.hasMoreElements()) {
274 if (onError != OnError.IGNORE) {
275 log("Could not load definitions from resource "
276 + resource + ". It could not be found.",
277 Project.MSG_WARN);
278 }
279 }
280 return ret;
281 }
282
283 /**
284 * Load type definitions as properties from a url.
285 *
286 * @param al the classloader to use
287 * @param url the url to get the definitions from
288 */
289 protected void loadProperties(ClassLoader al, URL url) {
290 InputStream is = null;
291 try {
292 is = url.openStream();
293 if (is == null) {
294 log("Could not load definitions from " + url,
295 Project.MSG_WARN);
296 return;
297 }
298 Properties props = new Properties();
299 props.load(is);
300 Enumeration keys = props.keys();
301 while (keys.hasMoreElements()) {
302 name = ((String) keys.nextElement());
303 classname = props.getProperty(name);
304 addDefinition(al, name, classname);
305 }
306 } catch (IOException ex) {
307 throw new BuildException(ex, getLocation());
308 } finally {
309 if (is != null) {
310 try {
311 is.close();
312 } catch (IOException e) {
313 // ignore
314 }
315 }
316 }
317 }
318
319 /**
320 * Load an antlib from a url.
321 *
322 * @param classLoader the classloader to use.
323 * @param url the url to load the definitions from.
324 */
325 private void loadAntlib(ClassLoader classLoader, URL url) {
326 try {
327 Antlib antlib = Antlib.createAntlib(getProject(), url, getURI());
328 antlib.setClassLoader(classLoader);
329 antlib.setURI(getURI());
330 antlib.perform();
331 } catch (BuildException ex) {
332 throw ProjectHelper.addLocationToBuildException(
333 ex, getLocation());
334 }
335 }
336
337 /**
338 * Name of the property file to load
339 * ant name/classname pairs from.
340 * @param file the file
341 */
342 public void setFile(File file) {
343 if (definerSet) {
344 tooManyDefinitions();
345 }
346 definerSet = true;
347 this.file = file;
348 }
349
350 /**
351 * Name of the property resource to load
352 * ant name/classname pairs from.
353 * @param res the resource to use
354 */
355 public void setResource(String res) {
356 if (definerSet) {
357 tooManyDefinitions();
358 }
359 definerSet = true;
360 this.resource = res;
361 }
362
363 /**
364 * Name of the definition
365 * @param name the name of the definition
366 */
367 public void setName(String name) {
368 if (definerSet) {
369 tooManyDefinitions();
370 }
371 definerSet = true;
372 this.name = name;
373 }
374
375 /**
376 * Returns the classname of the object we are defining.
377 * May be <code>null</code>.
378 * @return the class name
379 */
380 public String getClassname() {
381 return classname;
382 }
383
384 /**
385 * The full class name of the object being defined.
386 * Required, unless file or resource have
387 * been specified.
388 * @param classname the name of the class
389 */
390 public void setClassname(String classname) {
391 this.classname = classname;
392 }
393
394 /**
395 * Set the class name of the adapter class.
396 * An adapter class is used to proxy the
397 * definition class. It is used if the
398 * definition class is not assignable to
399 * the adaptto class, or if the adaptto
400 * class is not present.
401 *
402 * @param adapter the name of the adapter class
403 */
404
405 public void setAdapter(String adapter) {
406 this.adapter = adapter;
407 }
408
409 /**
410 * Set the adapter class.
411 *
412 * @param adapterClass the class to use to adapt the definition class
413 */
414 protected void setAdapterClass(Class adapterClass) {
415 this.adapterClass = adapterClass;
416 }
417
418 /**
419 * Set the classname of the class that the definition
420 * must be compatible with, either directly or
421 * by use of the adapter class.
422 *
423 * @param adaptTo the name of the adaptto class
424 */
425 public void setAdaptTo(String adaptTo) {
426 this.adaptTo = adaptTo;
427 }
428
429 /**
430 * Set the class for adaptToClass, to be
431 * used by derived classes, used instead of
432 * the adaptTo attribute.
433 *
434 * @param adaptToClass the class for adapto.
435 */
436 protected void setAdaptToClass(Class adaptToClass) {
437 this.adaptToClass = adaptToClass;
438 }
439
440
441 /**
442 * Add a definition using the attributes of Definer
443 *
444 * @param al the ClassLoader to use
445 * @param name the name of the definition
446 * @param classname the classname of the definition
447 * @exception BuildException if an error occurs
448 */
449 protected void addDefinition(ClassLoader al, String name, String classname)
450 throws BuildException {
451 Class cl = null;
452 try {
453 try {
454 name = ProjectHelper.genComponentName(getURI(), name);
455
456 if (onError != OnError.IGNORE) {
457 cl = Class.forName(classname, true, al);
458 }
459
460 if (adapter != null) {
461 adapterClass = Class.forName(adapter, true, al);
462 }
463
464 if (adaptTo != null) {
465 adaptToClass = Class.forName(adaptTo, true, al);
466 }
467
468 AntTypeDefinition def = new AntTypeDefinition();
469 def.setName(name);
470 def.setClassName(classname);
471 def.setClass(cl);
472 def.setAdapterClass(adapterClass);
473 def.setAdaptToClass(adaptToClass);
474 def.setClassLoader(al);
475 if (cl != null) {
476 def.checkClass(getProject());
477 }
478 ComponentHelper.getComponentHelper(getProject())
479 .addDataTypeDefinition(def);
480 } catch (ClassNotFoundException cnfe) {
481 String msg = getTaskName() + " class " + classname
482 + " cannot be found";
483 throw new BuildException(msg, cnfe, getLocation());
484 } catch (NoClassDefFoundError ncdfe) {
485 String msg = getTaskName() + " A class needed by class "
486 + classname + " cannot be found: " + ncdfe.getMessage();
487 throw new BuildException(msg, ncdfe, getLocation());
488 }
489 } catch (BuildException ex) {
490 switch (onError) {
491 case OnError.FAIL:
492 throw ex;
493 case OnError.REPORT:
494 log(ex.getLocation() + "Warning: " + ex.getMessage(),
495 Project.MSG_WARN);
496 break;
497 default:
498 log(ex.getLocation() + ex.getMessage(),
499 Project.MSG_DEBUG);
500 }
501 }
502 }
503
504 private void tooManyDefinitions() {
505 throw new BuildException(
506 "Only one of the attributes name,file,resource"
507 + " can be set", getLocation());
508 }
509}
Note: See TracBrowser for help on using the repository browser.