Coverage report

  %line %branch
org.apache.commons.jelly.tags.ant.AntTag
70% 
87% 

 1  
 /*
 2  
  * Copyright 2002,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  
 package org.apache.commons.jelly.tags.ant;
 18  
 
 19  
 import java.lang.reflect.Constructor;
 20  
 import java.lang.reflect.InvocationTargetException;
 21  
 import java.lang.reflect.Method;
 22  
 import java.util.Iterator;
 23  
 import java.util.Map;
 24  
 
 25  
 import org.apache.commons.beanutils.BeanUtils;
 26  
 import org.apache.commons.beanutils.MethodUtils;
 27  
 import org.apache.commons.jelly.JellyTagException;
 28  
 import org.apache.commons.jelly.MapTagSupport;
 29  
 import org.apache.commons.jelly.Tag;
 30  
 import org.apache.commons.jelly.XMLOutput;
 31  
 import org.apache.commons.jelly.expression.Expression;
 32  
 import org.apache.commons.jelly.impl.BeanSource;
 33  
 import org.apache.commons.jelly.impl.StaticTag;
 34  
 import org.apache.commons.logging.Log;
 35  
 import org.apache.commons.logging.LogFactory;
 36  
 import org.apache.tools.ant.BuildException;
 37  
 import org.apache.tools.ant.IntrospectionHelper;
 38  
 import org.apache.tools.ant.Project;
 39  
 import org.apache.tools.ant.Task;
 40  
 import org.apache.tools.ant.TaskAdapter;
 41  
 import org.apache.tools.ant.TaskContainer;
 42  
 import org.apache.tools.ant.types.DataType;
 43  
 
 44  
 /**
 45  
  * Tag supporting ant's Tasks as well as
 46  
  * dynamic runtime behaviour for 'unknown' tags.
 47  
  *
 48  
  * @author <a href="mailto:bob@eng.werken.com">bob mcwhirter</a>
 49  
  * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
 50  
  */
 51  4
 public class AntTag extends MapTagSupport implements TaskSource {
 52  
 
 53  
     /** The Log to which logging calls will be made. */
 54  4
     private static final Log log = LogFactory.getLog(AntTag.class);
 55  
 
 56  2
     private static final Class[] addTaskParamTypes = { String.class };
 57  
 
 58  
     /** store the name of the manifest tag for special handling */
 59  
     private static final String ANT_MANIFEST_TAG = "manifest";
 60  
 
 61  
     /** The name of this tag. */
 62  
     protected String tagName;
 63  
 
 64  
     /** The general object underlying this tag. */
 65  
     protected Object object;
 66  
 
 67  
     /** Task, if this tag represents a task. */
 68  
     protected Task task;
 69  
 
 70  
 
 71  
     /** Construct with a project and tag name.
 72  
      *
 73  
      *  @param tagName The name on the tag.
 74  
      */
 75  53
     public AntTag(String tagName) {
 76  53
         this.tagName = tagName;
 77  53
     }
 78  
 
 79  
     public String toString() {
 80  0
         return "[AntTag: name=" + getTagName() + "]";
 81  
     }
 82  
 
 83  
     // TaskSource interface
 84  
     //-------------------------------------------------------------------------
 85  
 
 86  
     /** Retrieve the general object underlying this tag.
 87  
      *
 88  
      *  @return The object underlying this tag.
 89  
      */
 90  
     public Object getTaskObject() {
 91  103
         return this.object;
 92  
     }
 93  
 
 94  
     /**
 95  
      * Allows nested tags to set a property on the task object of this tag
 96  
      */
 97  
     public void setTaskProperty(String name, Object value) throws JellyTagException {
 98  4
         Object object = getTaskObject();
 99  4
         if ( object != null ) {
 100  4
             setBeanProperty( object, name, value );
 101  
         }
 102  4
     }
 103  
 
 104  
     // Tag interface
 105  
     //-------------------------------------------------------------------------
 106  
     public void doTag(XMLOutput output) throws JellyTagException {
 107  
 
 108  53
         Project project = getAntProject();
 109  53
         String tagName = getTagName();
 110  53
         Object parentObject = findBeanAncestor();
 111  53
         Object parentTask = findParentTaskObject();
 112  
 
 113  
         // lets assume that Task instances are not nested inside other Task instances
 114  
         // for example <manifest> inside a <jar> should be a nested object, where as
 115  
         // if the parent is not a Task the <manifest> should create a ManifestTask
 116  
         //
 117  
         // also its possible to have a root Ant tag which isn't a task, such as when
 118  
         // defining <fileset id="...">...</fileset>
 119  
 
 120  53
         Object nested = null;
 121  53
         if (parentObject != null && !( parentTask instanceof TaskContainer) ) {
 122  49
             nested = createNestedObject( parentObject, tagName );
 123  
         }
 124  
 
 125  53
         if (nested == null) {
 126  31
             task = createTask( tagName );
 127  
 
 128  31
             if (task != null) {
 129  
 
 130  31
                 if ( log.isDebugEnabled() ) {
 131  0
                     log.debug( "Creating an ant Task for name: " + tagName );
 132  
                 }
 133  
 
 134  
                 // the following algorithm follows the lifetime of a tag
 135  
                 // http://jakarta.apache.org/ant/manual/develop.html#writingowntask
 136  
                 // kindly recommended by Stefan Bodewig
 137  
 
 138  
                 // create and set its project reference
 139  31
                 if ( task instanceof TaskAdapter ) {
 140  0
                     setObject( ((TaskAdapter)task).getProxy() );
 141  
                 }
 142  
                 else {
 143  31
                     setObject( task );
 144  
                 }
 145  
 
 146  
                 // set the task ID if one is given
 147  31
                 Object id = getAttributes().remove( "id" );
 148  31
                 if ( id != null ) {
 149  0
                     project.addReference( (String) id, task );
 150  
                 }
 151  
 
 152  
                 // ### we might want to spoof a Target setting here
 153  
 
 154  
                 // now lets initialize
 155  31
                 task.init();
 156  
 
 157  
                 // now lets invoke the body to call all the createXXX() or addXXX() methods
 158  31
                 String body = getBodyText();
 159  
 
 160  
                 // now lets set any attributes of this tag...
 161  31
                 setBeanProperties();
 162  
 
 163  
                 // now lets set the addText() of the body content, if its applicaable
 164  31
                 Method method = MethodUtils.getAccessibleMethod( task.getClass(),
 165  
                                                                  "addText",
 166  
                                                                  addTaskParamTypes );
 167  31
                 if (method != null) {
 168  4
                     Object[] args = { body };
 169  
                     try {
 170  4
                         method.invoke(this.task, args);
 171  4
                     }
 172  
                     catch (IllegalAccessException e) {
 173  0
                         throw new JellyTagException(e);
 174  
                     }
 175  
                     catch (InvocationTargetException e) {
 176  0
                         throw new JellyTagException(e);
 177  
                     }
 178  
                 }
 179  
 
 180  
                 // now lets set all the attributes of the child elements
 181  
                 // XXXX: to do!
 182  
 
 183  
                 // now we're ready to invoke the task
 184  
                 // XXX: should we call execute() or perform()?
 185  31
                 task.perform();
 186  
             }
 187  
         }
 188  
 
 189  52
         if (task == null) {
 190  
 
 191  22
             if (nested == null) {
 192  
 
 193  0
                 if ( log.isDebugEnabled() ) {
 194  0
                     log.debug( "Trying to create a data type for tag: " + tagName );
 195  
                 }
 196  0
                 nested = createDataType( tagName );
 197  
             }
 198  
             else {
 199  22
                 if ( log.isDebugEnabled() ) {
 200  0
                     log.debug( "Created nested property tag: " + tagName );
 201  
                 }
 202  
             }
 203  
 
 204  22
             if ( nested != null ) {
 205  22
                 setObject( nested );
 206  
 
 207  
                 // set the task ID if one is given
 208  22
                 Object id = getAttributes().remove( "id" );
 209  22
                 if ( id != null ) {
 210  2
                     project.addReference( (String) id, nested );
 211  
                 }
 212  
 
 213  
                 // TODO: work out why we always set the name attribute.
 214  
                 // See JELLY-105.
 215  
 //                try{
 216  
 //                    PropertyUtils.setProperty( nested, "name", tagName );
 217  
 //                }
 218  
 //                catch (Exception e) {
 219  
 //                    log.warn( "Caught exception setting nested name: " + tagName, e );
 220  
 //                }
 221  
 
 222  
                 // now lets invoke the body
 223  22
                 String body = getBodyText();
 224  
 
 225  
                 // now lets set any attributes of this tag...
 226  22
                 setBeanProperties();
 227  
 
 228  
                 // now lets add it to its parent
 229  22
                 if ( parentObject != null ) {
 230  22
                     IntrospectionHelper ih = IntrospectionHelper.getHelper( parentObject.getClass() );
 231  
                     try {
 232  22
                         if (log.isDebugEnabled()) {
 233  0
                             log.debug("About to set the: " + tagName
 234  
                                 + " property on: " + parentObject + " to value: "
 235  
                                 + nested + " with type: " + nested.getClass()
 236  
                             );
 237  
                         }
 238  
 
 239  22
                         ih.storeElement( project, parentObject, nested, tagName.toLowerCase() );
 240  22
                     }
 241  
                     catch (Exception e) {
 242  0
                         log.warn( "Caught exception setting nested: " + tagName, e );
 243  
                     }
 244  
 
 245  
                     // now try to set the property for good measure
 246  
                     // as the storeElement() method does not
 247  
                     // seem to call any setter methods of non-String types
 248  
                     try {
 249  22
                         BeanUtils.setProperty( parentObject, tagName, nested );
 250  22
                     }
 251  
                     catch (Exception e) {
 252  0
                         log.debug("Caught exception trying to set property: " + tagName + " on: " + parentObject);
 253  22
                     }
 254  
                 }
 255  
             }
 256  
             else {
 257  0
                 log.warn("Could not convert tag: " + tagName + " into an Ant task, data type or property");
 258  
 
 259  
                 // lets treat this tag as static XML...
 260  0
                 StaticTag tag = new StaticTag("", tagName, tagName);
 261  0
                 tag.setParent( getParent() );
 262  0
                 tag.setBody( getBody() );
 263  
 
 264  0
                 tag.setContext(context);
 265  
 
 266  0
                 for (Iterator iter = getAttributes().entrySet().iterator(); iter.hasNext();) {
 267  0
                     Map.Entry entry = (Map.Entry) iter.next();
 268  0
                     String name = (String) entry.getKey();
 269  0
                     Object value = entry.getValue();
 270  
 
 271  0
                     tag.setAttribute(name, value);
 272  
                 }
 273  
 
 274  0
                 tag.doTag(output);
 275  
             }
 276  
         }
 277  52
     }
 278  
 
 279  
 
 280  
     // Properties
 281  
     //-------------------------------------------------------------------------
 282  
     public String getTagName() {
 283  53
         return this.tagName;
 284  
     }
 285  
 
 286  
     /** Set the object underlying this tag.
 287  
      *
 288  
      *  @param object The object.
 289  
      */
 290  
     public void setObject(Object object) {
 291  53
         this.object = object;
 292  53
     }
 293  
 
 294  
     public Project getAntProject() {
 295  249
         Project project = AntTagLibrary.getProject(context);
 296  249
         if (project == null) {
 297  0
             throw new NullPointerException("No Ant Project object is available");
 298  
         }
 299  249
         return project;
 300  
     }
 301  
 
 302  
     // Implementation methods
 303  
     //-------------------------------------------------------------------------
 304  
 
 305  
     /**
 306  
      * Sets the properties on the Ant task
 307  
      */
 308  
     public void setBeanProperties() throws JellyTagException {
 309  53
         Object object = getTaskObject();
 310  53
         if ( object != null ) {
 311  53
             Map map = getAttributes();
 312  156
             for ( Iterator iter = map.entrySet().iterator(); iter.hasNext(); ) {
 313  50
                 Map.Entry entry = (Map.Entry) iter.next();
 314  50
                 String name = (String) entry.getKey();
 315  50
                 Object value = entry.getValue();
 316  50
                 setBeanProperty( object, name, value );
 317  
             }
 318  
         }
 319  53
     }
 320  
 
 321  
     public void setAttribute(String name, Object value) {
 322  52
         if ( value == null ) {
 323  
             // should we send in null?
 324  0
             super.setAttribute( name, "" );
 325  
         }
 326  
         else {
 327  52
             if ( value instanceof Expression )
 328  
             {
 329  0
                 super.setAttribute( name, ((Expression) value).evaluateRecurse(context) );
 330  
             }
 331  
             else
 332  
             {
 333  52
                 super.setAttribute( name, value.toString() );
 334  
             }
 335  
         }
 336  52
     }
 337  
 
 338  
     public void setBeanProperty(Object object, String name, Object value) throws JellyTagException {
 339  54
         if ( log.isDebugEnabled() ) {
 340  0
             log.debug( "Setting bean property on: "+  object + " name: " + name + " value: " + value );
 341  
         }
 342  
 
 343  54
         IntrospectionHelper ih = IntrospectionHelper.getHelper( object.getClass() );
 344  
 
 345  54
         if ( value instanceof String ) {
 346  
             try {
 347  54
                 ih.setAttribute( getAntProject(), object, name.toLowerCase(), (String) value );
 348  54
                 return;
 349  
             }
 350  0
             catch (Exception e) {
 351  
                 // ignore: not a valid property
 352  
             }
 353  
         }
 354  
 
 355  
         try {
 356  
 
 357  0
             ih.storeElement( getAntProject(), object, value, name );
 358  0
         }
 359  
         catch (Exception e) {
 360  
 
 361  0
             try {
 362  
                 // let any exceptions bubble up from here
 363  0
                 BeanUtils.setProperty( object, name, value );
 364  0
             }
 365  
             catch (IllegalAccessException ex) {
 366  0
                 throw new JellyTagException(ex);
 367  
             }
 368  
             catch (InvocationTargetException ex) {
 369  0
                 throw new JellyTagException(ex);
 370  
             }
 371  
         }
 372  0
     }
 373  
 
 374  
 
 375  
     /**
 376  
      * Creates a nested object of the given object with the specified name
 377  
      */
 378  
     public Object createNestedObject(Object object, String name) {
 379  49
         Object dataType = null;
 380  49
         if ( object != null ) {
 381  49
             IntrospectionHelper ih = IntrospectionHelper.getHelper( object.getClass() );
 382  
 
 383  49
             if ( ih != null ) {
 384  
                 try {
 385  49
                     dataType = ih.createElement( getAntProject(), object, name.toLowerCase() );
 386  20
                 } catch (BuildException be) {
 387  29
                     if (object instanceof Tag)
 388  
                     {
 389  29
                         if (log.isDebugEnabled()) {
 390  0
                             log.debug("Failed attempt to create an ant datatype for a jelly tag", be);
 391  
                         }
 392  
                     } else {
 393  0
                         log.error(be);
 394  
                     }
 395  
                 }
 396  
             }
 397  
         }
 398  
 
 399  49
         if ( dataType == null ) {
 400  29
             dataType = createDataType( name );
 401  
         }
 402  
 
 403  49
         return dataType;
 404  
     }
 405  
 
 406  
     public Object createDataType(String name) {
 407  
 
 408  29
         Object dataType = null;
 409  
 
 410  29
         Class type = (Class) getAntProject().getDataTypeDefinitions().get(name);
 411  
 
 412  29
         if ( type != null ) {
 413  
 
 414  2
             Constructor ctor = null;
 415  2
             boolean noArg = false;
 416  
 
 417  
             // DataType can have a "no arg" constructor or take a single
 418  
             // Project argument.
 419  
             try {
 420  2
                 ctor = type.getConstructor(new Class[0]);
 421  2
                 noArg = true;
 422  2
             }
 423  
             catch (NoSuchMethodException nse) {
 424  0
                 try {
 425  0
                     ctor = type.getConstructor(new Class[] { Project.class });
 426  0
                     noArg = false;
 427  0
                 } catch (NoSuchMethodException nsme) {
 428  0
                     log.info("datatype '" + name
 429  
                         + "' didn't have a constructor with an Ant Project", nsme);
 430  
                 }
 431  
             }
 432  
 
 433  2
             if (noArg) {
 434  2
                 dataType = createDataType(ctor, new Object[0], name, "no-arg constructor");
 435  
             }
 436  
             else {
 437  0
                 dataType = createDataType(ctor, new Object[] { getAntProject() }, name, "an Ant project");
 438  
             }
 439  2
             if (dataType != null) {
 440  2
                 ((DataType)dataType).setProject( getAntProject() );
 441  
             }
 442  
         }
 443  
 
 444  29
         return dataType;
 445  
     }
 446  
 
 447  
     /**
 448  
      * @return an object create with the given constructor and args.
 449  
      * @param ctor a constructor to use creating the object
 450  
      * @param args the arguments to pass to the constructor
 451  
      * @param name the name of the data type being created
 452  
      * @param argDescription a human readable description of the args passed
 453  
      */
 454  
     private Object createDataType(Constructor ctor, Object[] args, String name, String argDescription) {
 455  
         try {
 456  2
             Object datatype = ctor.newInstance(args);
 457  2
             return datatype;
 458  
         } catch (InstantiationException ie) {
 459  0
             log.error("datatype '" + name + "' couldn't be created with " + argDescription, ie);
 460  0
         } catch (IllegalAccessException iae) {
 461  0
             log.error("datatype '" + name + "' couldn't be created with " + argDescription, iae);
 462  0
         } catch (InvocationTargetException ite) {
 463  0
             log.error("datatype '" + name + "' couldn't be created with " + argDescription, ite);
 464  
         }
 465  0
         return null;
 466  
     }
 467  
 
 468  
     /**
 469  
      * @param taskName
 470  
      * @return
 471  
      * @throws JellyTagException
 472  
      */
 473  
     public Task createTask(String taskName) throws JellyTagException {
 474  31
         return createTask( taskName,
 475  
                            (Class) getAntProject().getTaskDefinitions().get( taskName ) );
 476  
     }
 477  
 
 478  
     public Task createTask(String taskName,
 479  
                            Class taskType) throws JellyTagException {
 480  
 
 481  31
         if (taskType == null) {
 482  0
             return null;
 483  
         }
 484  
 
 485  31
         Object o = null;
 486  
         try {
 487  31
             o = taskType.newInstance();
 488  31
         } catch (InstantiationException e) {
 489  0
             throw new JellyTagException(e);
 490  
         }
 491  
         catch (IllegalAccessException e) {
 492  0
             throw new JellyTagException(e);
 493  
         }
 494  
 
 495  31
         Task task = null;
 496  31
         if ( o instanceof Task ) {
 497  31
             task = (Task) o;
 498  
         }
 499  
         else {
 500  0
             TaskAdapter taskA=new TaskAdapter();
 501  0
             taskA.setProxy( o );
 502  0
             task=taskA;
 503  
         }
 504  
 
 505  31
         task.setProject(getAntProject());
 506  31
         task.setTaskName(taskName);
 507  
 
 508  31
         return task;
 509  
     }
 510  
 
 511  
     /**
 512  
      * Attempts to look up in the parent hierarchy for a tag that implements the
 513  
      * TaskSource interface, which returns an Ant Task object or that implements
 514  
      * BeanSource interface which creates a bean,
 515  
      * or will return the parent tag, which is also a bean.
 516  
      */
 517  
     protected Object findBeanAncestor() throws JellyTagException {
 518  53
         Tag tag = getParent();
 519  163
         while (tag != null) {
 520  81
             if (tag instanceof BeanSource) {
 521  1
                 BeanSource beanSource = (BeanSource) tag;
 522  1
                 return beanSource.getBean();
 523  
             }
 524  80
             if (tag instanceof TaskSource) {
 525  23
                 TaskSource taskSource = (TaskSource) tag;
 526  23
                 return taskSource.getTaskObject();
 527  
             }
 528  57
             tag = tag.getParent();
 529  
         }
 530  29
         return getParent();
 531  
     }
 532  
 
 533  
     /**
 534  
      * Walks the hierarchy until it finds a parent TaskSource and returns its source or returns null
 535  
      */
 536  
     protected Object findParentTaskObject() throws JellyTagException {
 537  53
         Tag tag = getParent();
 538  166
         while (tag != null) {
 539  83
             if (tag instanceof TaskSource) {
 540  23
                 TaskSource source = (TaskSource) tag;
 541  23
                 return source.getTaskObject();
 542  
             }
 543  60
             tag = tag.getParent();
 544  
         }
 545  30
         return null;
 546  
     }
 547  
 
 548  
 }

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.