Clover coverage report - groovy - 1.0-beta-7
Coverage timestamp: Wed Sep 29 2004 16:55:52 BST
file stats: LOC: 469   Methods: 20
NCLOC: 311   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.8 2004/07/13 12:17:45 jstrachan 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.BuildException;
 59   
 import org.apache.tools.ant.BuildLogger;
 60   
 import org.apache.tools.ant.IntrospectionHelper;
 61   
 import org.apache.tools.ant.NoBannerLogger;
 62   
 import org.apache.tools.ant.Project;
 63   
 import org.apache.tools.ant.Task;
 64   
 import org.apache.tools.ant.TaskAdapter;
 65   
 import org.apache.tools.ant.TaskContainer;
 66   
 import org.apache.tools.ant.types.DataType;
 67   
 import org.codehaus.groovy.ant.FileScanner;
 68   
 import org.codehaus.groovy.runtime.InvokerHelper;
 69   
 
 70   
 /**
 71   
  * Allows Ant tasks to be used with GroovyMarkup 
 72   
  * 
 73   
  * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
 74   
  * @version $Revision: 1.8 $
 75   
  */
 76   
 public class AntBuilder extends BuilderSupport {
 77   
 
 78   
     private static final Class[] addTaskParamTypes = { String.class };
 79   
 
 80   
     private Logger log = Logger.getLogger(getClass().getName());
 81   
     private Project project;
 82   
 
 83  0
     public AntBuilder() {
 84  0
         this.project = createProject();
 85   
     }
 86   
 
 87  0
     public AntBuilder(Project project) {
 88  0
         this.project = project;
 89   
     }
 90   
 
 91   
     /**
 92   
      * @return Factory method to create new Project instances
 93   
      */
 94  0
     protected Project createProject() {
 95  0
         Project project = new Project();
 96  0
         BuildLogger logger = new NoBannerLogger();
 97   
 
 98  0
         logger.setMessageOutputLevel(org.apache.tools.ant.Project.MSG_INFO);
 99  0
         logger.setOutputPrintStream(System.out);
 100  0
         logger.setErrorPrintStream(System.err);
 101   
 
 102  0
         project.addBuildListener(logger);
 103   
 
 104  0
         project.init();
 105  0
         project.getBaseDir();
 106  0
         return project;
 107   
     }
 108   
 
 109  0
     protected void setParent(Object parent, Object child) {
 110   
     }
 111   
 
 112  0
     protected void nodeCompleted(Object parent, Object node) {
 113  0
         if (node instanceof Task) {
 114  0
             Task task = (Task) node;
 115  0
             task.perform();
 116   
         }
 117   
     }
 118   
 
 119  0
     protected Object createNode(Object tagName) {
 120  0
         return createNode(tagName.toString(), Collections.EMPTY_MAP);
 121   
     }
 122   
 
 123  0
     protected Object createNode(Object name, Object value) {
 124  0
         Object task = createNode(name);
 125  0
         setText(task, value.toString());
 126  0
         return task;
 127   
     }
 128   
 
 129  0
     protected Object createNode(Object name, Map attributes, Object value) {
 130  0
         Object task = createNode(name, attributes);
 131  0
         setText(task, value.toString());
 132  0
         return task;
 133   
     }
 134   
     
 135  0
     protected Object createNode(Object name, Map attributes) {
 136   
 
 137  0
         if (name.equals("fileScanner")) {
 138  0
             return new FileScanner(project);
 139   
         }
 140   
         
 141  0
         String tagName = name.toString();
 142  0
         Object answer = null;
 143   
 
 144  0
         Object parentObject = getCurrent();
 145  0
         Object parentTask = getParentTask();
 146   
 
 147   
         // lets assume that Task instances are not nested inside other Task instances
 148   
         // for example <manifest> inside a <jar> should be a nested object, where as 
 149   
         // if the parent is not a Task the <manifest> should create a ManifestTask
 150   
         //
 151   
         // also its possible to have a root Ant tag which isn't a task, such as when
 152   
         // defining <fileset id="...">...</fileset>
 153   
 
 154  0
         Object nested = null;
 155  0
         if (parentObject != null && !(parentTask instanceof TaskContainer)) {
 156  0
             nested = createNestedObject(parentObject, tagName);
 157   
         }
 158   
 
 159  0
         Task task = null;
 160  0
         if (nested == null) {
 161  0
             task = createTask(tagName);
 162  0
             if (task != null) {
 163  0
                 if (log.isLoggable(Level.FINE)) {
 164  0
                     log.fine("Creating an ant Task for name: " + tagName);
 165   
                 }
 166   
 
 167   
                 // the following algorithm follows the lifetime of a tag
 168   
                 // http://jakarta.apache.org/ant/manual/develop.html#writingowntask
 169   
                 // kindly recommended by Stefan Bodewig
 170   
 
 171   
                 // create and set its project reference
 172  0
                 if (task instanceof TaskAdapter) {
 173  0
                     answer = ((TaskAdapter) task).getProxy();
 174   
                 }
 175   
                 else {
 176  0
                     answer = task;
 177   
                 }
 178   
 
 179   
                 // set the task ID if one is given
 180  0
                 Object id = attributes.remove("id");
 181  0
                 if (id != null) {
 182  0
                     project.addReference((String) id, task);
 183   
                 }
 184   
 
 185   
                 // now lets initialize
 186  0
                 task.init();
 187   
 
 188   
                 // now lets set any attributes of this tag...
 189  0
                 setBeanProperties(task, attributes);
 190   
             }
 191   
         }
 192   
 
 193  0
         if (task == null) {
 194  0
             if (nested == null) {
 195  0
                 if (log.isLoggable(Level.FINE)) {
 196  0
                     log.fine("Trying to create a data type for tag: " + tagName);
 197   
                 }
 198  0
                 nested = createDataType(tagName);
 199   
             }
 200   
             else {
 201  0
                 if (log.isLoggable(Level.FINE)) {
 202  0
                     log.fine("Created nested property tag: " + tagName);
 203   
                 }
 204   
             }
 205   
 
 206  0
             if (nested != null) {
 207  0
                 answer = nested;
 208   
 
 209   
                 // set the task ID if one is given
 210  0
                 Object id = attributes.remove("id");
 211  0
                 if (id != null) {
 212  0
                     project.addReference((String) id, nested);
 213   
                 }
 214   
 
 215  0
                 try {
 216  0
                     InvokerHelper.setProperty(nested, "name", tagName);
 217   
                 }
 218   
                 catch (Exception e) {
 219   
                 }
 220   
 
 221   
                 // now lets set any attributes of this tag...
 222  0
                 setBeanProperties(nested, attributes);
 223   
 
 224   
                 // now lets add it to its parent
 225  0
                 if (parentObject != null) {
 226  0
                     IntrospectionHelper ih = IntrospectionHelper.getHelper(parentObject.getClass());
 227  0
                     try {
 228  0
                         if (log.isLoggable(Level.FINE)) {
 229  0
                             log.fine(
 230   
                                 "About to set the: "
 231   
                                     + tagName
 232   
                                     + " property on: "
 233   
                                     + parentObject
 234   
                                     + " to value: "
 235   
                                     + nested
 236   
                                     + " with type: "
 237   
                                     + nested.getClass());
 238   
                         }
 239   
 
 240  0
                         ih.storeElement(project, parentObject, nested, tagName);
 241   
                     }
 242   
                     catch (Exception e) {
 243  0
                         log.log(Level.WARNING, "Caught exception setting nested: " + tagName, e);
 244   
                     }
 245   
 
 246   
                     // now try to set the property for good measure
 247   
                     // as the storeElement() method does not
 248   
                     // seem to call any setter methods of non-String types
 249  0
                     try {
 250  0
                         InvokerHelper.setProperty(parentObject, tagName, nested);
 251   
                     }
 252   
                     catch (Exception e) {
 253  0
                         log.fine("Caught exception trying to set property: " + tagName + " on: " + parentObject);
 254   
                     }
 255   
                 }
 256   
             }
 257   
             else {
 258  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?");
 259   
             }
 260   
         }
 261   
 
 262  0
         return answer;
 263   
     }
 264   
 
 265  0
     protected void setText(Object task, String text) {
 266   
         // now lets set the addText() of the body content, if its applicaable
 267  0
         Method method = getAccessibleMethod(task.getClass(), "addText", addTaskParamTypes);
 268  0
         if (method != null) {
 269  0
             Object[] args = { text };
 270  0
             try {
 271  0
                 method.invoke(task, args);
 272   
             }
 273   
             catch (Exception e) {
 274  0
                 log.log(Level.WARNING, "Cannot call addText on: " + task + ". Reason: " + e, e);
 275   
             }
 276   
         }
 277   
     }
 278   
 
 279  0
     protected Method getAccessibleMethod(Class theClass, String name, Class[] paramTypes) {
 280  0
         while (true) {
 281  0
             try {
 282  0
                 Method answer = theClass.getDeclaredMethod(name, paramTypes);
 283  0
                 if (answer != null) {
 284  0
                     return answer;
 285   
                 }
 286   
             }
 287   
             catch (Exception e) {
 288   
                 // ignore
 289   
             }
 290  0
             theClass = theClass.getSuperclass();
 291  0
             if (theClass == null) {
 292  0
                 return null;
 293   
             }
 294   
         }
 295   
     }
 296   
 
 297  0
     public Project getAntProject() {
 298  0
         return project;
 299   
     }
 300   
 
 301   
     // Implementation methods
 302   
     //-------------------------------------------------------------------------
 303  0
     protected void setBeanProperties(Object object, Map map) {
 304  0
         for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
 305  0
             Map.Entry entry = (Map.Entry) iter.next();
 306  0
             String name = (String) entry.getKey();
 307  0
             Object value = entry.getValue();
 308  0
             setBeanProperty(object, name, ((value == null) ? null : value.toString()));
 309   
         }
 310   
     }
 311   
 
 312  0
     protected void setBeanProperty(Object object, String name, Object value) {
 313  0
         if (log.isLoggable(Level.FINE)) {
 314  0
             log.fine("Setting bean property on: " + object + " name: " + name + " value: " + value);
 315   
         }
 316   
 
 317  0
         IntrospectionHelper ih = IntrospectionHelper.getHelper(object.getClass());
 318   
 
 319  0
         if (value instanceof String) {
 320  0
             try {
 321  0
                 ih.setAttribute(getAntProject(), object, name.toLowerCase(), (String) value);
 322  0
                 return;
 323   
             }
 324   
             catch (Exception e) {
 325   
                 // ignore: not a valid property
 326   
             }
 327   
         }
 328   
 
 329  0
         try {
 330   
 
 331  0
             ih.storeElement(getAntProject(), object, value, name);
 332   
         }
 333   
         catch (Exception e) {
 334   
 
 335  0
             InvokerHelper.setProperty(object, name, value);
 336   
         }
 337   
     }
 338   
 
 339   
     /**
 340   
      * Creates a nested object of the given object with the specified name
 341   
      */
 342  0
     protected Object createNestedObject(Object object, String name) {
 343  0
         Object dataType = null;
 344  0
         if (object != null) {
 345  0
             IntrospectionHelper ih = IntrospectionHelper.getHelper(object.getClass());
 346   
 
 347  0
             if (ih != null) {
 348  0
                 try {
 349  0
                     dataType = ih.createElement(getAntProject(), object, name.toLowerCase());
 350   
                 }
 351   
                 catch (BuildException be) {
 352  0
                     log.log(Level.SEVERE, "Caught: " + be, be);
 353   
                 }
 354   
             }
 355   
         }
 356  0
         if (dataType == null) {
 357  0
             dataType = createDataType(name);
 358   
         }
 359  0
         return dataType;
 360   
     }
 361   
 
 362  0
     protected Object createDataType(String name) {
 363  0
         Object dataType = null;
 364   
 
 365  0
         Class type = (Class) getAntProject().getDataTypeDefinitions().get(name);
 366   
 
 367  0
         if (type != null) {
 368   
 
 369  0
             Constructor ctor = null;
 370  0
             boolean noArg = false;
 371   
 
 372   
             // DataType can have a "no arg" constructor or take a single
 373   
             // Project argument.
 374  0
             try {
 375  0
                 ctor = type.getConstructor(new Class[0]);
 376  0
                 noArg = true;
 377   
             }
 378   
             catch (NoSuchMethodException nse) {
 379  0
                 try {
 380  0
                     ctor = type.getConstructor(new Class[] { Project.class });
 381  0
                     noArg = false;
 382   
                 }
 383   
                 catch (NoSuchMethodException nsme) {
 384  0
                     log.log(Level.INFO, "datatype '" + name + "' didn't have a constructor with an Ant Project", nsme);
 385   
                 }
 386   
             }
 387   
 
 388  0
             if (noArg) {
 389  0
                 dataType = createDataType(ctor, new Object[0], name, "no-arg constructor");
 390   
             }
 391   
             else {
 392  0
                 dataType = createDataType(ctor, new Object[] { getAntProject()}, name, "an Ant project");
 393   
             }
 394  0
             if (dataType != null) {
 395  0
                 ((DataType) dataType).setProject(getAntProject());
 396   
             }
 397   
         }
 398   
 
 399  0
         return dataType;
 400   
     }
 401   
 
 402   
     /**
 403   
      * @return an object create with the given constructor and args.
 404   
      * @param ctor a constructor to use creating the object
 405   
      * @param args the arguments to pass to the constructor
 406   
      * @param name the name of the data type being created
 407   
      * @param argDescription a human readable description of the args passed
 408   
      */
 409  0
     protected Object createDataType(Constructor ctor, Object[] args, String name, String argDescription) {
 410  0
         try {
 411  0
             Object datatype = ctor.newInstance(args);
 412  0
             return datatype;
 413   
         }
 414   
         catch (InstantiationException ie) {
 415  0
             log.log(Level.SEVERE, "datatype '" + name + "' couldn't be created with " + argDescription, ie);
 416   
         }
 417   
         catch (IllegalAccessException iae) {
 418  0
             log.log(Level.SEVERE, "datatype '" + name + "' couldn't be created with " + argDescription, iae);
 419   
         }
 420   
         catch (InvocationTargetException ite) {
 421  0
             log.log(Level.SEVERE, "datatype '" + name + "' couldn't be created with " + argDescription, ite);
 422   
         }
 423  0
         return null;
 424   
     }
 425   
 
 426   
     /**
 427   
      * @param taskName the name of the task to create
 428   
      * @return a newly created task
 429   
      */
 430  0
     protected Task createTask(String taskName) {
 431  0
         return createTask(taskName, (Class) getAntProject().getTaskDefinitions().get(taskName));
 432   
     }
 433   
 
 434  0
     protected Task createTask(String taskName, Class taskType) {
 435  0
         if (taskType == null) {
 436  0
             return null;
 437   
         }
 438  0
         try {
 439  0
             Object o = taskType.newInstance();
 440  0
             Task task = null;
 441  0
             if (o instanceof Task) {
 442  0
                 task = (Task) o;
 443   
             }
 444   
             else {
 445  0
                 TaskAdapter taskA = new TaskAdapter();
 446  0
                 taskA.setProxy(o);
 447  0
                 task = taskA;
 448   
             }
 449   
 
 450  0
             task.setProject(getAntProject());
 451  0
             task.setTaskName(taskName);
 452   
 
 453  0
             return task;
 454   
         }
 455   
         catch (Exception e) {
 456  0
             log.log(Level.WARNING, "Could not create task: " + taskName + ". Reason: " + e, e);
 457  0
             return null;
 458   
         }
 459   
     }
 460   
 
 461  0
     protected Task getParentTask() {
 462  0
         Object current = getCurrent();
 463  0
         if (current instanceof Task) {
 464  0
             return (Task) current;
 465   
         }
 466  0
         return null;
 467   
     }
 468   
 }
 469