Clover coverage report - groovy - 1.0-beta-8
Coverage timestamp: Fri Dec 17 2004 14:55:55 GMT
file stats: LOC: 489   Methods: 21
NCLOC: 316   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
AntBuilder.java 0% 0% 0% 0%
coverage
 1   
 /*
 2   
  $Id: AntBuilder.java,v 1.9 2004/12/13 23:48:21 glaforge Exp $
 3   
 
 4   
  Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
 5   
 
 6   
  Redistribution and use of this software and associated documentation
 7   
  ("Software"), with or without modification, are permitted provided
 8   
  that the following conditions are met:
 9   
 
 10   
  1. Redistributions of source code must retain copyright
 11   
     statements and notices.  Redistributions must also contain a
 12   
     copy of this document.
 13   
 
 14   
  2. Redistributions in binary form must reproduce the
 15   
     above copyright notice, this list of conditions and the
 16   
     following disclaimer in the documentation and/or other
 17   
     materials provided with the distribution.
 18   
 
 19   
  3. The name "groovy" must not be used to endorse or promote
 20   
     products derived from this Software without prior written
 21   
     permission of The Codehaus.  For written permission,
 22   
     please contact info@codehaus.org.
 23   
 
 24   
  4. Products derived from this Software may not be called "groovy"
 25   
     nor may "groovy" appear in their names without prior written
 26   
     permission of The Codehaus. "groovy" is a registered
 27   
     trademark of The Codehaus.
 28   
 
 29   
  5. Due credit should be given to The Codehaus -
 30   
     http://groovy.codehaus.org/
 31   
 
 32   
  THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
 33   
  ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
 34   
  NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 35   
  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
 36   
  THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 37   
  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 38   
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 39   
  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 40   
  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 41   
  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 42   
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 43   
  OF THE POSSIBILITY OF SUCH DAMAGE.
 44   
 
 45   
  */
 46   
 package groovy.util;
 47   
 
 48   
 
 49   
 import java.lang.reflect.Constructor;
 50   
 import java.lang.reflect.InvocationTargetException;
 51   
 import java.lang.reflect.Method;
 52   
 import java.util.Collections;
 53   
 import java.util.Iterator;
 54   
 import java.util.Map;
 55   
 import java.util.logging.Level;
 56   
 import java.util.logging.Logger;
 57   
 
 58   
 import org.apache.tools.ant.*;
 59   
 import org.apache.tools.ant.types.DataType;
 60   
 import org.codehaus.groovy.ant.FileScanner;
 61   
 import org.codehaus.groovy.runtime.InvokerHelper;
 62   
 
 63   
 /**
 64   
  * Allows Ant tasks to be used with GroovyMarkup 
 65   
  * 
 66   
  * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>, changes by Dierk Koenig (dk)
 67   
  * @version $Revision: 1.9 $
 68   
  */
 69   
 public class AntBuilder extends BuilderSupport {
 70   
 
 71   
     private static final Class[] addTaskParamTypes = { String.class };
 72   
 
 73   
     private Logger log = Logger.getLogger(getClass().getName());
 74   
     private Project project;
 75   
 
 76  0
     public AntBuilder() {
 77  0
         this.project = createProject();
 78   
     }
 79   
 
 80  0
     public AntBuilder(Project project) {
 81  0
         this.project = project;
 82   
     }
 83   
 
 84   
     // dk: introduced for convenience in subclasses
 85  0
     protected Project getProject() {
 86  0
         return project;
 87   
     }
 88   
 
 89   
     /**
 90   
      * @return Factory method to create new Project instances
 91   
      */
 92  0
     protected Project createProject() {
 93  0
         Project project = new Project();
 94  0
         BuildLogger logger = new NoBannerLogger();
 95   
 
 96  0
         logger.setMessageOutputLevel(org.apache.tools.ant.Project.MSG_INFO);
 97  0
         logger.setOutputPrintStream(System.out);
 98  0
         logger.setErrorPrintStream(System.err);
 99   
 
 100  0
         project.addBuildListener(logger);
 101   
 
 102  0
         project.init();
 103  0
         project.getBaseDir();
 104  0
         return project;
 105   
     }
 106   
 
 107  0
     protected void setParent(Object parent, Object child) {
 108   
     }
 109   
 
 110   
     /**
 111   
      * Determines, when the ANT Task that is represented by the "node" should perform.
 112   
      * Node must be an ANT Task or no "perform" is called.
 113   
      * If node is an ANT Task, it performs right after complete contstruction.
 114   
      * If node is nested in a TaskContainer, calling "perform" is delegated to that
 115   
      * TaskContainer.
 116   
      * @param parent note: null when node is root
 117   
      * @param node the node that now has all its children applied
 118   
      */
 119  0
     protected void nodeCompleted(Object parent, Object node) {
 120  0
         if (parent instanceof TaskContainer) {
 121  0
             log.finest("parent is TaskContainer: no perform on nodeCompleted");
 122  0
             return; // parent will care about when children perform
 123   
         }
 124  0
         if (node instanceof Task) {
 125  0
             Task task = (Task) node;
 126  0
             task.perform();
 127   
         }
 128   
     }
 129   
 
 130  0
     protected Object createNode(Object tagName) {
 131  0
         return createNode(tagName.toString(), Collections.EMPTY_MAP);
 132   
     }
 133   
 
 134  0
     protected Object createNode(Object name, Object value) {
 135  0
         Object task = createNode(name);
 136  0
         setText(task, value.toString());
 137  0
         return task;
 138   
     }
 139   
 
 140  0
     protected Object createNode(Object name, Map attributes, Object value) {
 141  0
         Object task = createNode(name, attributes);
 142  0
         setText(task, value.toString());
 143  0
         return task;
 144   
     }
 145   
     
 146  0
     protected Object createNode(Object name, Map attributes) {
 147   
 
 148  0
         if (name.equals("fileScanner")) {
 149  0
             return new FileScanner(project);
 150   
         }
 151   
         
 152  0
         String tagName = name.toString();
 153  0
         Object answer = null;
 154   
 
 155  0
         Object parentObject = getCurrent();
 156  0
         Object parentTask = getParentTask();
 157   
 
 158   
         // lets assume that Task instances are not nested inside other Task instances
 159   
         // for example <manifest> inside a <jar> should be a nested object, where as 
 160   
         // if the parent is not a Task the <manifest> should create a ManifestTask
 161   
         //
 162   
         // also its possible to have a root Ant tag which isn't a task, such as when
 163   
         // defining <fileset id="...">...</fileset>
 164   
 
 165  0
         Object nested = null;
 166  0
         if (parentObject != null && !(parentTask instanceof TaskContainer)) {
 167  0
             nested = createNestedObject(parentObject, tagName);
 168   
         }
 169   
 
 170  0
         Task task = null;
 171  0
         if (nested == null) {
 172  0
             task = createTask(tagName);
 173  0
             if (task != null) {
 174  0
                 if (log.isLoggable(Level.FINE)) {
 175  0
                     log.fine("Creating an ant Task for name: " + tagName);
 176   
                 }
 177   
 
 178   
                 // the following algorithm follows the lifetime of a tag
 179   
                 // http://jakarta.apache.org/ant/manual/develop.html#writingowntask
 180   
                 // kindly recommended by Stefan Bodewig
 181   
 
 182   
                 // create and set its project reference
 183  0
                 if (task instanceof TaskAdapter) {
 184  0
                     answer = ((TaskAdapter) task).getProxy();
 185   
                 }
 186   
                 else {
 187  0
                     answer = task;
 188   
                 }
 189   
 
 190   
                 // set the task ID if one is given
 191  0
                 Object id = attributes.remove("id");
 192  0
                 if (id != null) {
 193  0
                     project.addReference((String) id, task);
 194   
                 }
 195   
 
 196   
                 // now lets initialize
 197  0
                 task.init();
 198   
 
 199   
                 // now lets set any attributes of this tag...
 200  0
                 setBeanProperties(task, attributes);
 201   
 
 202   
                 // dk: TaskContainers have their own adding logic
 203  0
                 if (parentObject instanceof TaskContainer){
 204  0
                     ((TaskContainer)parentObject).addTask(task);
 205   
                 }
 206   
             }
 207   
         }
 208   
 
 209  0
         if (task == null) {
 210  0
             if (nested == null) {
 211  0
                 if (log.isLoggable(Level.FINE)) {
 212  0
                     log.fine("Trying to create a data type for tag: " + tagName);
 213   
                 }
 214  0
                 nested = createDataType(tagName);
 215   
             }
 216   
             else {
 217  0
                 if (log.isLoggable(Level.FINE)) {
 218  0
                     log.fine("Created nested property tag: " + tagName);
 219   
                 }
 220   
             }
 221   
 
 222  0
             if (nested != null) {
 223  0
                 answer = nested;
 224   
 
 225   
                 // set the task ID if one is given
 226  0
                 Object id = attributes.remove("id");
 227  0
                 if (id != null) {
 228  0
                     project.addReference((String) id, nested);
 229   
                 }
 230   
 
 231  0
                 try {
 232  0
                     InvokerHelper.setProperty(nested, "name", tagName);
 233   
                 }
 234   
                 catch (Exception e) {
 235   
                 }
 236   
 
 237   
                 // now lets set any attributes of this tag...
 238  0
                 setBeanProperties(nested, attributes);
 239   
 
 240   
                 // now lets add it to its parent
 241  0
                 if (parentObject != null) {
 242  0
                     IntrospectionHelper ih = IntrospectionHelper.getHelper(parentObject.getClass());
 243  0
                     try {
 244  0
                         if (log.isLoggable(Level.FINE)) {
 245  0
                             log.fine(
 246   
                                 "About to set the: "
 247   
                                     + tagName
 248   
                                     + " property on: "
 249   
                                     + parentObject
 250   
                                     + " to value: "
 251   
                                     + nested
 252   
                                     + " with type: "
 253   
                                     + nested.getClass());
 254   
                         }
 255   
 
 256  0
                         ih.storeElement(project, parentObject, nested, tagName);
 257   
                     }
 258   
                     catch (Exception e) {
 259  0
                         log.log(Level.WARNING, "Caught exception setting nested: " + tagName, e);
 260   
                     }
 261   
 
 262   
                     // now try to set the property for good measure
 263   
                     // as the storeElement() method does not
 264   
                     // seem to call any setter methods of non-String types
 265  0
                     try {
 266  0
                         InvokerHelper.setProperty(parentObject, tagName, nested);
 267   
                     }
 268   
                     catch (Exception e) {
 269  0
                         log.fine("Caught exception trying to set property: " + tagName + " on: " + parentObject);
 270   
                     }
 271   
                 }
 272   
             }
 273   
             else {
 274  0
                 log.log(Level.WARNING, "Could not convert tag: " + tagName + " into an Ant task, data type or property. Maybe the task is not on the classpath?");
 275   
             }
 276   
         }
 277   
 
 278  0
         return answer;
 279   
     }
 280   
 
 281  0
     protected void setText(Object task, String text) {
 282   
         // now lets set the addText() of the body content, if its applicaable
 283  0
         Method method = getAccessibleMethod(task.getClass(), "addText", addTaskParamTypes);
 284  0
         if (method != null) {
 285  0
             Object[] args = { text };
 286  0
             try {
 287  0
                 method.invoke(task, args);
 288   
             }
 289   
             catch (Exception e) {
 290  0
                 log.log(Level.WARNING, "Cannot call addText on: " + task + ". Reason: " + e, e);
 291   
             }
 292   
         }
 293   
     }
 294   
 
 295  0
     protected Method getAccessibleMethod(Class theClass, String name, Class[] paramTypes) {
 296  0
         while (true) {
 297  0
             try {
 298  0
                 Method answer = theClass.getDeclaredMethod(name, paramTypes);
 299  0
                 if (answer != null) {
 300  0
                     return answer;
 301   
                 }
 302   
             }
 303   
             catch (Exception e) {
 304   
                 // ignore
 305   
             }
 306  0
             theClass = theClass.getSuperclass();
 307  0
             if (theClass == null) {
 308  0
                 return null;
 309   
             }
 310   
         }
 311   
     }
 312   
 
 313  0
     public Project getAntProject() {
 314  0
         return project;
 315   
     }
 316   
 
 317   
     // Implementation methods
 318   
     //-------------------------------------------------------------------------
 319  0
     protected void setBeanProperties(Object object, Map map) {
 320  0
         for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
 321  0
             Map.Entry entry = (Map.Entry) iter.next();
 322  0
             String name = (String) entry.getKey();
 323  0
             Object value = entry.getValue();
 324  0
             setBeanProperty(object, name, ((value == null) ? null : value.toString()));
 325   
         }
 326   
     }
 327   
 
 328  0
     protected void setBeanProperty(Object object, String name, Object value) {
 329  0
         if (log.isLoggable(Level.FINE)) {
 330  0
             log.fine("Setting bean property on: " + object + " name: " + name + " value: " + value);
 331   
         }
 332   
 
 333  0
         IntrospectionHelper ih = IntrospectionHelper.getHelper(object.getClass());
 334   
 
 335  0
         if (value instanceof String) {
 336  0
             try {
 337  0
                 ih.setAttribute(getAntProject(), object, name.toLowerCase(), (String) value);
 338  0
                 return;
 339   
             }
 340   
             catch (Exception e) {
 341   
                 // ignore: not a valid property
 342   
             }
 343   
         }
 344   
 
 345  0
         try {
 346   
 
 347  0
             ih.storeElement(getAntProject(), object, value, name);
 348   
         }
 349   
         catch (Exception e) {
 350   
 
 351  0
             InvokerHelper.setProperty(object, name, value);
 352   
         }
 353   
     }
 354   
 
 355   
     /**
 356   
      * Creates a nested object of the given object with the specified name
 357   
      */
 358  0
     protected Object createNestedObject(Object object, String name) {
 359  0
         Object dataType = null;
 360  0
         if (object != null) {
 361  0
             IntrospectionHelper ih = IntrospectionHelper.getHelper(object.getClass());
 362   
 
 363  0
             if (ih != null) {
 364  0
                 try {
 365   
                     // dk: the line below resolves the deprecation warning but may not work
 366   
                     // properly with namespaces.
 367  0
                     String namespaceUri = "";               // todo: how to set this?
 368  0
                     UnknownElement unknownElement = null;   // todo: what is expected here?
 369  0
                     dataType = ih.getElementCreator(getAntProject(), namespaceUri, object, name.toLowerCase(), unknownElement).create();
 370   
                 }
 371   
                 catch (BuildException be) {
 372  0
                     log.log(Level.SEVERE, "Caught: " + be, be);
 373   
                 }
 374   
             }
 375   
         }
 376  0
         if (dataType == null) {
 377  0
             dataType = createDataType(name);
 378   
         }
 379  0
         return dataType;
 380   
     }
 381   
 
 382  0
     protected Object createDataType(String name) {
 383  0
         Object dataType = null;
 384   
 
 385  0
         Class type = (Class) getAntProject().getDataTypeDefinitions().get(name);
 386   
 
 387  0
         if (type != null) {
 388   
 
 389  0
             Constructor ctor = null;
 390  0
             boolean noArg = false;
 391   
 
 392   
             // DataType can have a "no arg" constructor or take a single
 393   
             // Project argument.
 394  0
             try {
 395  0
                 ctor = type.getConstructor(new Class[0]);
 396  0
                 noArg = true;
 397   
             }
 398   
             catch (NoSuchMethodException nse) {
 399  0
                 try {
 400  0
                     ctor = type.getConstructor(new Class[] { Project.class });
 401  0
                     noArg = false;
 402   
                 }
 403   
                 catch (NoSuchMethodException nsme) {
 404  0
                     log.log(Level.INFO, "datatype '" + name + "' didn't have a constructor with an Ant Project", nsme);
 405   
                 }
 406   
             }
 407   
 
 408  0
             if (noArg) {
 409  0
                 dataType = createDataType(ctor, new Object[0], name, "no-arg constructor");
 410   
             }
 411   
             else {
 412  0
                 dataType = createDataType(ctor, new Object[] { getAntProject()}, name, "an Ant project");
 413   
             }
 414  0
             if (dataType != null) {
 415  0
                 ((DataType) dataType).setProject(getAntProject());
 416   
             }
 417   
         }
 418   
 
 419  0
         return dataType;
 420   
     }
 421   
 
 422   
     /**
 423   
      * @return an object create with the given constructor and args.
 424   
      * @param ctor a constructor to use creating the object
 425   
      * @param args the arguments to pass to the constructor
 426   
      * @param name the name of the data type being created
 427   
      * @param argDescription a human readable description of the args passed
 428   
      */
 429  0
     protected Object createDataType(Constructor ctor, Object[] args, String name, String argDescription) {
 430  0
         try {
 431  0
             Object datatype = ctor.newInstance(args);
 432  0
             return datatype;
 433   
         }
 434   
         catch (InstantiationException ie) {
 435  0
             log.log(Level.SEVERE, "datatype '" + name + "' couldn't be created with " + argDescription, ie);
 436   
         }
 437   
         catch (IllegalAccessException iae) {
 438  0
             log.log(Level.SEVERE, "datatype '" + name + "' couldn't be created with " + argDescription, iae);
 439   
         }
 440   
         catch (InvocationTargetException ite) {
 441  0
             log.log(Level.SEVERE, "datatype '" + name + "' couldn't be created with " + argDescription, ite);
 442   
         }
 443  0
         return null;
 444   
     }
 445   
 
 446   
     /**
 447   
      * @param taskName the name of the task to create
 448   
      * @return a newly created task
 449   
      */
 450  0
     protected Task createTask(String taskName) {
 451  0
         return createTask(taskName, (Class) getAntProject().getTaskDefinitions().get(taskName));
 452   
     }
 453   
 
 454  0
     protected Task createTask(String taskName, Class taskType) {
 455  0
         if (taskType == null) {
 456  0
             return null;
 457   
         }
 458  0
         try {
 459  0
             Object o = taskType.newInstance();
 460  0
             Task task = null;
 461  0
             if (o instanceof Task) {
 462  0
                 task = (Task) o;
 463   
             }
 464   
             else {
 465  0
                 TaskAdapter taskA = new TaskAdapter();
 466  0
                 taskA.setProxy(o);
 467  0
                 task = taskA;
 468   
             }
 469   
 
 470  0
             task.setProject(getAntProject());
 471  0
             task.setTaskName(taskName);
 472   
 
 473  0
             return task;
 474   
         }
 475   
         catch (Exception e) {
 476  0
             log.log(Level.WARNING, "Could not create task: " + taskName + ". Reason: " + e, e);
 477  0
             return null;
 478   
         }
 479   
     }
 480   
 
 481  0
     protected Task getParentTask() {
 482  0
         Object current = getCurrent();
 483  0
         if (current instanceof Task) {
 484  0
             return (Task) current;
 485   
         }
 486  0
         return null;
 487   
     }
 488   
 }
 489