| 1 | /* | 
| 2 |  *   Copyright (C) Christian Schulte, 2005-206 | 
| 3 |  *   All rights reserved. | 
| 4 |  * | 
| 5 |  *   Redistribution and use in source and binary forms, with or without | 
| 6 |  *   modification, are permitted provided that the following conditions | 
| 7 |  *   are met: | 
| 8 |  * | 
| 9 |  *     o Redistributions of source code must retain the above copyright | 
| 10 |  *       notice, this list of conditions and the following disclaimer. | 
| 11 |  * | 
| 12 |  *     o Redistributions in binary form must reproduce the above copyright | 
| 13 |  *       notice, this list of conditions and the following disclaimer in | 
| 14 |  *       the documentation and/or other materials provided with the | 
| 15 |  *       distribution. | 
| 16 |  * | 
| 17 |  *   THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, | 
| 18 |  *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | 
| 19 |  *   AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | 
| 20 |  *   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, | 
| 21 |  *   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | 
| 22 |  *   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
| 23 |  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
| 24 |  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
| 25 |  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 
| 26 |  *   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
| 27 |  * | 
| 28 |  *   $JOMC: JomcTask.java 4613 2012-09-22 10:07:08Z schulte $ | 
| 29 |  * | 
| 30 |  */ | 
| 31 | package org.jomc.ant; | 
| 32 |   | 
| 33 | import java.io.BufferedReader; | 
| 34 | import java.io.File; | 
| 35 | import java.io.IOException; | 
| 36 | import java.io.InputStream; | 
| 37 | import java.io.StringReader; | 
| 38 | import java.io.StringWriter; | 
| 39 | import java.net.MalformedURLException; | 
| 40 | import java.net.SocketTimeoutException; | 
| 41 | import java.net.URI; | 
| 42 | import java.net.URISyntaxException; | 
| 43 | import java.net.URL; | 
| 44 | import java.net.URLConnection; | 
| 45 | import java.util.ArrayList; | 
| 46 | import java.util.Collection; | 
| 47 | import java.util.Enumeration; | 
| 48 | import java.util.HashSet; | 
| 49 | import java.util.Iterator; | 
| 50 | import java.util.LinkedList; | 
| 51 | import java.util.List; | 
| 52 | import java.util.Map; | 
| 53 | import java.util.Properties; | 
| 54 | import java.util.Set; | 
| 55 | import java.util.logging.Level; | 
| 56 | import javax.xml.bind.JAXBException; | 
| 57 | import javax.xml.bind.Marshaller; | 
| 58 | import javax.xml.transform.ErrorListener; | 
| 59 | import javax.xml.transform.Transformer; | 
| 60 | import javax.xml.transform.TransformerConfigurationException; | 
| 61 | import javax.xml.transform.TransformerException; | 
| 62 | import javax.xml.transform.TransformerFactory; | 
| 63 | import javax.xml.transform.stream.StreamSource; | 
| 64 | import org.apache.tools.ant.BuildException; | 
| 65 | import org.apache.tools.ant.Project; | 
| 66 | import org.apache.tools.ant.PropertyHelper; | 
| 67 | import org.apache.tools.ant.Task; | 
| 68 | import org.apache.tools.ant.types.Path; | 
| 69 | import org.apache.tools.ant.types.Reference; | 
| 70 | import org.jomc.ant.types.KeyValueType; | 
| 71 | import org.jomc.ant.types.NameType; | 
| 72 | import org.jomc.ant.types.PropertiesFormatType; | 
| 73 | import org.jomc.ant.types.PropertiesResourceType; | 
| 74 | import org.jomc.ant.types.ResourceType; | 
| 75 | import org.jomc.ant.types.TransformerResourceType; | 
| 76 | import org.jomc.model.ModelObject; | 
| 77 | import org.jomc.modlet.DefaultModelContext; | 
| 78 | import org.jomc.modlet.DefaultModletProvider; | 
| 79 | import org.jomc.modlet.Model; | 
| 80 | import org.jomc.modlet.ModelContext; | 
| 81 | import org.jomc.modlet.ModelContextFactory; | 
| 82 | import org.jomc.modlet.ModelException; | 
| 83 | import org.jomc.modlet.ModelValidationReport; | 
| 84 | import org.jomc.modlet.ModletProvider; | 
| 85 |   | 
| 86 | /** | 
| 87 |  * Base class for executing tasks. | 
| 88 |  * | 
| 89 |  * @author <a href="mailto:cs@schulte.it">Christian Schulte</a> | 
| 90 |  * @version $JOMC: JomcTask.java 4613 2012-09-22 10:07:08Z schulte $ | 
| 91 |  * @see #execute() | 
| 92 |  */ | 
| 93 | public class JomcTask extends Task | 
| 94 | { | 
| 95 |   | 
| 96 |     /** The class path to process. */ | 
| 97 |     private Path classpath; | 
| 98 |   | 
| 99 |     /** The identifier of the model to process. */ | 
| 100 |     private String model; | 
| 101 |   | 
| 102 |     /** {@code ModelContext} attributes to apply. */ | 
| 103 |     private List<KeyValueType> modelContextAttributes; | 
| 104 |   | 
| 105 |     /** The name of the {@code ModelContextFactory} implementation class backing the task. */ | 
| 106 |     private String modelContextFactoryClassName; | 
| 107 |   | 
| 108 |     /** Controls processing of models. */ | 
| 109 |     private boolean modelProcessingEnabled = true; | 
| 110 |   | 
| 111 |     /** The location to search for modlets. */ | 
| 112 |     private String modletLocation; | 
| 113 |   | 
| 114 |     /** The {@code http://jomc.org/modlet} namespace schema system id of the context backing the task. */ | 
| 115 |     private String modletSchemaSystemId; | 
| 116 |   | 
| 117 |     /** The location to search for providers. */ | 
| 118 |     private String providerLocation; | 
| 119 |   | 
| 120 |     /** The location to search for platform providers. */ | 
| 121 |     private String platformProviderLocation; | 
| 122 |   | 
| 123 |     /** The global transformation parameters to apply. */ | 
| 124 |     private List<KeyValueType> transformationParameters; | 
| 125 |   | 
| 126 |     /** The global transformation parameter resources to apply. */ | 
| 127 |     private List<PropertiesResourceType> transformationParameterResources; | 
| 128 |   | 
| 129 |     /** The global transformation output properties to apply. */ | 
| 130 |     private List<KeyValueType> transformationOutputProperties; | 
| 131 |   | 
| 132 |     /** The flag indicating JAXP schema validation of modlet resources is enabled. */ | 
| 133 |     private boolean modletResourceValidationEnabled = true; | 
| 134 |   | 
| 135 |     /** Property controlling the execution of the task. */ | 
| 136 |     private Object _if; | 
| 137 |   | 
| 138 |     /** Property controlling the execution of the task. */ | 
| 139 |     private Object unless; | 
| 140 |   | 
| 141 |     /** Creates a new {@code JomcTask} instance. */ | 
| 142 |     public JomcTask() | 
| 143 |     { | 
| 144 |         super(); | 
| 145 |     } | 
| 146 |   | 
| 147 |     /** | 
| 148 |      * Gets an object controlling the execution of the task. | 
| 149 |      * | 
| 150 |      * @return An object controlling the execution of the task or {@code null}. | 
| 151 |      * | 
| 152 |      * @see #setIf(java.lang.Object) | 
| 153 |      */ | 
| 154 |     public final Object getIf() | 
| 155 |     { | 
| 156 |         return this._if; | 
| 157 |     } | 
| 158 |   | 
| 159 |     /** | 
| 160 |      * Sets an object controlling the execution of the task. | 
| 161 |      * | 
| 162 |      * @param value The new object controlling the execution of the task or {@code null}. | 
| 163 |      * | 
| 164 |      * @see #getIf() | 
| 165 |      */ | 
| 166 |     public final void setIf( final Object value ) | 
| 167 |     { | 
| 168 |         this._if = value; | 
| 169 |     } | 
| 170 |   | 
| 171 |     /** | 
| 172 |      * Gets an object controlling the execution of the task. | 
| 173 |      * | 
| 174 |      * @return An object controlling the execution of the task or {@code null}. | 
| 175 |      * | 
| 176 |      * @see #setUnless(java.lang.Object) | 
| 177 |      */ | 
| 178 |     public final Object getUnless() | 
| 179 |     { | 
| 180 |         if ( this.unless == null ) | 
| 181 |         { | 
| 182 |             this.unless = Boolean.TRUE; | 
| 183 |         } | 
| 184 |   | 
| 185 |         return this.unless; | 
| 186 |     } | 
| 187 |   | 
| 188 |     /** | 
| 189 |      * Sets an object controlling the execution of the task. | 
| 190 |      * | 
| 191 |      * @param value The new object controlling the execution of the task or {@code null}. | 
| 192 |      * | 
| 193 |      * @see #getUnless() | 
| 194 |      */ | 
| 195 |     public final void setUnless( final Object value ) | 
| 196 |     { | 
| 197 |         this.unless = value; | 
| 198 |     } | 
| 199 |   | 
| 200 |     /** | 
| 201 |      * Creates a new {@code classpath} element instance. | 
| 202 |      * | 
| 203 |      * @return A new {@code classpath} element instance. | 
| 204 |      */ | 
| 205 |     public final Path createClasspath() | 
| 206 |     { | 
| 207 |         return this.getClasspath().createPath(); | 
| 208 |     } | 
| 209 |   | 
| 210 |     /** | 
| 211 |      * Gets the class path to process. | 
| 212 |      * | 
| 213 |      * @return The class path to process. | 
| 214 |      * | 
| 215 |      * @see #setClasspath(org.apache.tools.ant.types.Path) | 
| 216 |      */ | 
| 217 |     public final Path getClasspath() | 
| 218 |     { | 
| 219 |         if ( this.classpath == null ) | 
| 220 |         { | 
| 221 |             this.classpath = new Path( this.getProject() ); | 
| 222 |         } | 
| 223 |   | 
| 224 |         return this.classpath; | 
| 225 |     } | 
| 226 |   | 
| 227 |     /** | 
| 228 |      * Adds to the class path to process. | 
| 229 |      * | 
| 230 |      * @param value The path to add to the list of class path elements. | 
| 231 |      * | 
| 232 |      * @see #getClasspath() | 
| 233 |      */ | 
| 234 |     public final void setClasspath( final Path value ) | 
| 235 |     { | 
| 236 |         this.getClasspath().add( value ); | 
| 237 |     } | 
| 238 |   | 
| 239 |     /** | 
| 240 |      * Adds a reference to a class path defined elsewhere. | 
| 241 |      * | 
| 242 |      * @param value A reference to a class path. | 
| 243 |      * | 
| 244 |      * @see #getClasspath() | 
| 245 |      */ | 
| 246 |     public final void setClasspathRef( final Reference value ) | 
| 247 |     { | 
| 248 |         this.getClasspath().setRefid( value ); | 
| 249 |     } | 
| 250 |   | 
| 251 |     /** | 
| 252 |      * Gets the identifier of the model to process. | 
| 253 |      * | 
| 254 |      * @return The identifier of the model to process. | 
| 255 |      * | 
| 256 |      * @see #setModel(java.lang.String) | 
| 257 |      */ | 
| 258 |     public final String getModel() | 
| 259 |     { | 
| 260 |         if ( this.model == null ) | 
| 261 |         { | 
| 262 |             this.model = ModelObject.MODEL_PUBLIC_ID; | 
| 263 |         } | 
| 264 |   | 
| 265 |         return this.model; | 
| 266 |     } | 
| 267 |   | 
| 268 |     /** | 
| 269 |      * Sets the identifier of the model to process. | 
| 270 |      * | 
| 271 |      * @param value The new identifier of the model to process or {@code null}. | 
| 272 |      * | 
| 273 |      * @see #getModel() | 
| 274 |      */ | 
| 275 |     public final void setModel( final String value ) | 
| 276 |     { | 
| 277 |         this.model = value; | 
| 278 |     } | 
| 279 |   | 
| 280 |     /** | 
| 281 |      * Gets the {@code ModelContext} attributes to apply. | 
| 282 |      * <p>This accessor method returns a reference to the live list, not a snapshot. Therefore any modification you make | 
| 283 |      * to the returned list will be present inside the object. This is why there is no {@code set} method for the | 
| 284 |      * model context attributes property.</p> | 
| 285 |      * | 
| 286 |      * @return The  {@code ModelContext} attributes to apply. | 
| 287 |      * | 
| 288 |      * @see #createModelContextAttribute() | 
| 289 |      * @see #newModelContext(java.lang.ClassLoader) | 
| 290 |      */ | 
| 291 |     public final List<KeyValueType> getModelContextAttributes() | 
| 292 |     { | 
| 293 |         if ( this.modelContextAttributes == null ) | 
| 294 |         { | 
| 295 |             this.modelContextAttributes = new LinkedList<KeyValueType>(); | 
| 296 |         } | 
| 297 |   | 
| 298 |         return this.modelContextAttributes; | 
| 299 |     } | 
| 300 |   | 
| 301 |     /** | 
| 302 |      * Creates a new {@code modelContextAttribute} element instance. | 
| 303 |      * | 
| 304 |      * @return A new {@code modelContextAttribute} element instance. | 
| 305 |      * | 
| 306 |      * @see #getModelContextAttributes() | 
| 307 |      */ | 
| 308 |     public KeyValueType createModelContextAttribute() | 
| 309 |     { | 
| 310 |         final KeyValueType modelContextAttribute = new KeyValueType(); | 
| 311 |         this.getModelContextAttributes().add( modelContextAttribute ); | 
| 312 |         return modelContextAttribute; | 
| 313 |     } | 
| 314 |   | 
| 315 |     /** | 
| 316 |      * Gets the name of the {@code ModelContextFactory} implementation class backing the task. | 
| 317 |      * | 
| 318 |      * @return The name of the {@code ModelContextFactory} implementation class backing the task or {@code null}. | 
| 319 |      * | 
| 320 |      * @see #setModelContextFactoryClassName(java.lang.String) | 
| 321 |      */ | 
| 322 |     public final String getModelContextFactoryClassName() | 
| 323 |     { | 
| 324 |         return this.modelContextFactoryClassName; | 
| 325 |     } | 
| 326 |   | 
| 327 |     /** | 
| 328 |      * Sets the name of the {@code ModelContextFactory} implementation class backing the task. | 
| 329 |      * | 
| 330 |      * @param value The new name of the {@code ModelContextFactory} implementation class backing the task or | 
| 331 |      * {@code null}. | 
| 332 |      * | 
| 333 |      * @see #getModelContextFactoryClassName() | 
| 334 |      */ | 
| 335 |     public final void setModelContextFactoryClassName( final String value ) | 
| 336 |     { | 
| 337 |         this.modelContextFactoryClassName = value; | 
| 338 |     } | 
| 339 |   | 
| 340 |     /** | 
| 341 |      * Gets a flag indicating the processing of models is enabled. | 
| 342 |      * | 
| 343 |      * @return {@code true}, if processing of models is enabled; {@code false}, else. | 
| 344 |      * | 
| 345 |      * @see #setModelProcessingEnabled(boolean) | 
| 346 |      */ | 
| 347 |     public final boolean isModelProcessingEnabled() | 
| 348 |     { | 
| 349 |         return this.modelProcessingEnabled; | 
| 350 |     } | 
| 351 |   | 
| 352 |     /** | 
| 353 |      * Sets the flag indicating the processing of models is enabled. | 
| 354 |      * | 
| 355 |      * @param value {@code true}, to enable processing of models; {@code false}, to disable processing of models. | 
| 356 |      * | 
| 357 |      * @see #isModelProcessingEnabled() | 
| 358 |      */ | 
| 359 |     public final void setModelProcessingEnabled( final boolean value ) | 
| 360 |     { | 
| 361 |         this.modelProcessingEnabled = value; | 
| 362 |     } | 
| 363 |   | 
| 364 |     /** | 
| 365 |      * Gets the location searched for modlets. | 
| 366 |      * | 
| 367 |      * @return The location searched for modlets or {@code null}. | 
| 368 |      * | 
| 369 |      * @see #setModletLocation(java.lang.String) | 
| 370 |      */ | 
| 371 |     public final String getModletLocation() | 
| 372 |     { | 
| 373 |         return this.modletLocation; | 
| 374 |     } | 
| 375 |   | 
| 376 |     /** | 
| 377 |      * Sets the location to search for modlets. | 
| 378 |      * | 
| 379 |      * @param value The new location to search for modlets or {@code null}. | 
| 380 |      * | 
| 381 |      * @see #getModletLocation() | 
| 382 |      */ | 
| 383 |     public final void setModletLocation( final String value ) | 
| 384 |     { | 
| 385 |         this.modletLocation = value; | 
| 386 |     } | 
| 387 |   | 
| 388 |     /** | 
| 389 |      * Gets the {@code http://jomc.org/modlet} namespace schema system id of the context backing the task. | 
| 390 |      * | 
| 391 |      * @return The {@code http://jomc.org/modlet} namespace schema system id of the context backing the task or | 
| 392 |      * {@code null}. | 
| 393 |      * | 
| 394 |      * @see #setModletSchemaSystemId(java.lang.String) | 
| 395 |      */ | 
| 396 |     public final String getModletSchemaSystemId() | 
| 397 |     { | 
| 398 |         return this.modletSchemaSystemId; | 
| 399 |     } | 
| 400 |   | 
| 401 |     /** | 
| 402 |      * Sets the {@code http://jomc.org/modlet} namespace schema system id of the context backing the task. | 
| 403 |      * | 
| 404 |      * @param value The new {@code http://jomc.org/modlet} namespace schema system id of the context backing the task or | 
| 405 |      * {@code null}. | 
| 406 |      * | 
| 407 |      * @see #getModletSchemaSystemId() | 
| 408 |      */ | 
| 409 |     public final void setModletSchemaSystemId( final String value ) | 
| 410 |     { | 
| 411 |         this.modletSchemaSystemId = value; | 
| 412 |     } | 
| 413 |   | 
| 414 |     /** | 
| 415 |      * Gets the location searched for providers. | 
| 416 |      * | 
| 417 |      * @return The location searched for providers or {@code null}. | 
| 418 |      * | 
| 419 |      * @see #setProviderLocation(java.lang.String) | 
| 420 |      */ | 
| 421 |     public final String getProviderLocation() | 
| 422 |     { | 
| 423 |         return this.providerLocation; | 
| 424 |     } | 
| 425 |   | 
| 426 |     /** | 
| 427 |      * Sets the location to search for providers. | 
| 428 |      * | 
| 429 |      * @param value The new location to search for providers or {@code null}. | 
| 430 |      * | 
| 431 |      * @see #getProviderLocation() | 
| 432 |      */ | 
| 433 |     public final void setProviderLocation( final String value ) | 
| 434 |     { | 
| 435 |         this.providerLocation = value; | 
| 436 |     } | 
| 437 |   | 
| 438 |     /** | 
| 439 |      * Gets the location searched for platform provider resources. | 
| 440 |      * | 
| 441 |      * @return The location searched for platform provider resources or {@code null}. | 
| 442 |      * | 
| 443 |      * @see #setPlatformProviderLocation(java.lang.String) | 
| 444 |      */ | 
| 445 |     public final String getPlatformProviderLocation() | 
| 446 |     { | 
| 447 |         return this.platformProviderLocation; | 
| 448 |     } | 
| 449 |   | 
| 450 |     /** | 
| 451 |      * Sets the location to search for platform provider resources. | 
| 452 |      * | 
| 453 |      * @param value The new location to search for platform provider resources or {@code null}. | 
| 454 |      * | 
| 455 |      * @see #getPlatformProviderLocation() | 
| 456 |      */ | 
| 457 |     public final void setPlatformProviderLocation( final String value ) | 
| 458 |     { | 
| 459 |         this.platformProviderLocation = value; | 
| 460 |     } | 
| 461 |   | 
| 462 |     /** | 
| 463 |      * Gets the global transformation parameters to apply. | 
| 464 |      * <p>This accessor method returns a reference to the live list, not a snapshot. Therefore any modification you make | 
| 465 |      * to the returned list will be present inside the object. This is why there is no {@code set} method for the | 
| 466 |      * transformation parameters property.</p> | 
| 467 |      * | 
| 468 |      * @return The global transformation parameters to apply. | 
| 469 |      * | 
| 470 |      * @see #createTransformationParameter() | 
| 471 |      * @see #getTransformer(org.jomc.ant.types.TransformerResourceType) | 
| 472 |      */ | 
| 473 |     public final List<KeyValueType> getTransformationParameters() | 
| 474 |     { | 
| 475 |         if ( this.transformationParameters == null ) | 
| 476 |         { | 
| 477 |             this.transformationParameters = new LinkedList<KeyValueType>(); | 
| 478 |         } | 
| 479 |   | 
| 480 |         return this.transformationParameters; | 
| 481 |     } | 
| 482 |   | 
| 483 |     /** | 
| 484 |      * Creates a new {@code transformationParameter} element instance. | 
| 485 |      * | 
| 486 |      * @return A new {@code transformationParameter} element instance. | 
| 487 |      * | 
| 488 |      * @see #getTransformationParameters() | 
| 489 |      */ | 
| 490 |     public KeyValueType createTransformationParameter() | 
| 491 |     { | 
| 492 |         final KeyValueType transformationParameter = new KeyValueType(); | 
| 493 |         this.getTransformationParameters().add( transformationParameter ); | 
| 494 |         return transformationParameter; | 
| 495 |     } | 
| 496 |   | 
| 497 |     /** | 
| 498 |      * Gets the global transformation parameter resources to apply. | 
| 499 |      * <p>This accessor method returns a reference to the live list, not a snapshot. Therefore any modification you make | 
| 500 |      * to the returned list will be present inside the object. This is why there is no {@code set} method for the | 
| 501 |      * transformation parameter resources property.</p> | 
| 502 |      * | 
| 503 |      * @return The global transformation parameter resources to apply. | 
| 504 |      * | 
| 505 |      * @see #createTransformationParameterResource() | 
| 506 |      * @see #getTransformer(org.jomc.ant.types.TransformerResourceType) | 
| 507 |      */ | 
| 508 |     public final List<PropertiesResourceType> getTransformationParameterResources() | 
| 509 |     { | 
| 510 |         if ( this.transformationParameterResources == null ) | 
| 511 |         { | 
| 512 |             this.transformationParameterResources = new LinkedList<PropertiesResourceType>(); | 
| 513 |         } | 
| 514 |   | 
| 515 |         return this.transformationParameterResources; | 
| 516 |     } | 
| 517 |   | 
| 518 |     /** | 
| 519 |      * Creates a new {@code transformationParameterResource} element instance. | 
| 520 |      * | 
| 521 |      * @return A new {@code transformationParameterResource} element instance. | 
| 522 |      * | 
| 523 |      * @see #getTransformationParameterResources() | 
| 524 |      */ | 
| 525 |     public PropertiesResourceType createTransformationParameterResource() | 
| 526 |     { | 
| 527 |         final PropertiesResourceType transformationParameterResource = new PropertiesResourceType(); | 
| 528 |         this.getTransformationParameterResources().add( transformationParameterResource ); | 
| 529 |         return transformationParameterResource; | 
| 530 |     } | 
| 531 |   | 
| 532 |     /** | 
| 533 |      * Gets the global transformation output properties to apply. | 
| 534 |      * <p>This accessor method returns a reference to the live list, not a snapshot. Therefore any modification you make | 
| 535 |      * to the returned list will be present inside the object. This is why there is no {@code set} method for the | 
| 536 |      * transformation output properties property.</p> | 
| 537 |      * | 
| 538 |      * @return The global transformation output properties to apply. | 
| 539 |      * | 
| 540 |      * @see #createTransformationOutputProperty() | 
| 541 |      */ | 
| 542 |     public final List<KeyValueType> getTransformationOutputProperties() | 
| 543 |     { | 
| 544 |         if ( this.transformationOutputProperties == null ) | 
| 545 |         { | 
| 546 |             this.transformationOutputProperties = new LinkedList<KeyValueType>(); | 
| 547 |         } | 
| 548 |   | 
| 549 |         return this.transformationOutputProperties; | 
| 550 |     } | 
| 551 |   | 
| 552 |     /** | 
| 553 |      * Creates a new {@code transformationOutputProperty} element instance. | 
| 554 |      * | 
| 555 |      * @return A new {@code transformationOutputProperty} element instance. | 
| 556 |      * | 
| 557 |      * @see #getTransformationOutputProperties() | 
| 558 |      */ | 
| 559 |     public KeyValueType createTransformationOutputProperty() | 
| 560 |     { | 
| 561 |         final KeyValueType transformationOutputProperty = new KeyValueType(); | 
| 562 |         this.getTransformationOutputProperties().add( transformationOutputProperty ); | 
| 563 |         return transformationOutputProperty; | 
| 564 |     } | 
| 565 |   | 
| 566 |     /** | 
| 567 |      * Gets a flag indicating JAXP schema validation of modlet resources is enabled. | 
| 568 |      * | 
| 569 |      * @return {@code true}, if JAXP schema validation of modlet resources is enabled; {@code false}, else. | 
| 570 |      * | 
| 571 |      * @see #setModletResourceValidationEnabled(boolean) | 
| 572 |      */ | 
| 573 |     public final boolean isModletResourceValidationEnabled() | 
| 574 |     { | 
| 575 |         return this.modletResourceValidationEnabled; | 
| 576 |     } | 
| 577 |   | 
| 578 |     /** | 
| 579 |      * Sets the flag indicating JAXP schema validation of modlet resources is enabled. | 
| 580 |      * | 
| 581 |      * @param value {@code true}, to enable JAXP schema validation of modlet resources; {@code false}, to disable JAXP | 
| 582 |      * schema validation of modlet resources. | 
| 583 |      * | 
| 584 |      * @see #isModletResourceValidationEnabled() | 
| 585 |      */ | 
| 586 |     public final void setModletResourceValidationEnabled( final boolean value ) | 
| 587 |     { | 
| 588 |         this.modletResourceValidationEnabled = value; | 
| 589 |     } | 
| 590 |   | 
| 591 |     /** | 
| 592 |      * Called by the project to let the task do its work. | 
| 593 |      * | 
| 594 |      * @throws BuildException if execution fails. | 
| 595 |      * | 
| 596 |      * @see #getIf() | 
| 597 |      * @see #getUnless() | 
| 598 |      * @see #preExecuteTask() | 
| 599 |      * @see #executeTask() | 
| 600 |      * @see #postExecuteTask() | 
| 601 |      */ | 
| 602 |     @Override | 
| 603 |     public final void execute() throws BuildException | 
| 604 |     { | 
| 605 |         final PropertyHelper propertyHelper = PropertyHelper.getPropertyHelper( this.getProject() ); | 
| 606 |   | 
| 607 |         if ( propertyHelper.testIfCondition( this.getIf() ) && !propertyHelper.testUnlessCondition( this.getUnless() ) ) | 
| 608 |         { | 
| 609 |             try | 
| 610 |             { | 
| 611 |                 this.preExecuteTask(); | 
| 612 |                 this.executeTask(); | 
| 613 |             } | 
| 614 |             finally | 
| 615 |             { | 
| 616 |                 this.postExecuteTask(); | 
| 617 |             } | 
| 618 |         } | 
| 619 |     } | 
| 620 |   | 
| 621 |     /** | 
| 622 |      * Called by the {@code execute} method prior to the {@code executeTask} method. | 
| 623 |      * | 
| 624 |      * @throws BuildException if execution fails. | 
| 625 |      * | 
| 626 |      * @see #execute() | 
| 627 |      */ | 
| 628 |     public void preExecuteTask() throws BuildException | 
| 629 |     { | 
| 630 |         this.logSeparator(); | 
| 631 |         this.log( Messages.getMessage( "title" ) ); | 
| 632 |         this.logSeparator(); | 
| 633 |   | 
| 634 |         this.assertNotNull( "model", this.getModel() ); | 
| 635 |         this.assertKeysNotNull( this.getModelContextAttributes() ); | 
| 636 |         this.assertKeysNotNull( this.getTransformationParameters() ); | 
| 637 |         this.assertKeysNotNull( this.getTransformationOutputProperties() ); | 
| 638 |         this.assertLocationsNotNull( this.getTransformationParameterResources() ); | 
| 639 |     } | 
| 640 |   | 
| 641 |     /** | 
| 642 |      * Called by the {@code execute} method prior to the {@code postExecuteTask} method. | 
| 643 |      * | 
| 644 |      * @throws BuildException if execution fails. | 
| 645 |      * | 
| 646 |      * @see #execute() | 
| 647 |      */ | 
| 648 |     public void executeTask() throws BuildException | 
| 649 |     { | 
| 650 |         this.getProject().log( Messages.getMessage( "unimplementedTask", this.getClass().getName(), "executeTask" ), | 
| 651 |                                Project.MSG_WARN ); | 
| 652 |   | 
| 653 |     } | 
| 654 |   | 
| 655 |     /** | 
| 656 |      * Called by the {@code execute} method after the {@code preExecuteTask}/{@code executeTask} methods even if those | 
| 657 |      * methods threw an exception. | 
| 658 |      * | 
| 659 |      * @throws BuildException if execution fails. | 
| 660 |      * | 
| 661 |      * @see #execute() | 
| 662 |      */ | 
| 663 |     public void postExecuteTask() throws BuildException | 
| 664 |     { | 
| 665 |         this.logSeparator(); | 
| 666 |     } | 
| 667 |   | 
| 668 |     /** | 
| 669 |      * Gets a {@code Model} from a given {@code ModelContext}. | 
| 670 |      * | 
| 671 |      * @param context The context to get a {@code Model} from. | 
| 672 |      * | 
| 673 |      * @return The {@code Model} from {@code context}. | 
| 674 |      * | 
| 675 |      * @throws NullPointerException if {@code contexŧ} is {@code null}. | 
| 676 |      * @throws ModelException if getting the model fails. | 
| 677 |      * | 
| 678 |      * @see #getModel() | 
| 679 |      * @see #isModelProcessingEnabled() | 
| 680 |      */ | 
| 681 |     public Model getModel( final ModelContext context ) throws ModelException | 
| 682 |     { | 
| 683 |         if ( context == null ) | 
| 684 |         { | 
| 685 |             throw new NullPointerException( "context" ); | 
| 686 |         } | 
| 687 |   | 
| 688 |         Model foundModel = context.findModel( this.getModel() ); | 
| 689 |   | 
| 690 |         if ( foundModel != null && this.isModelProcessingEnabled() ) | 
| 691 |         { | 
| 692 |             foundModel = context.processModel( foundModel ); | 
| 693 |         } | 
| 694 |   | 
| 695 |         return foundModel; | 
| 696 |     } | 
| 697 |   | 
| 698 |     /** | 
| 699 |      * Creates an {@code URL} for a given resource location. | 
| 700 |      * <p>This method first searches the class path of the task for a single resource matching {@code location}. If | 
| 701 |      * such a resource is found, the URL of that resource is returned. If no such resource is found, an attempt is made | 
| 702 |      * to parse the given location to an URL. On successful parsing, that URL is returned. Failing that, the given | 
| 703 |      * location is interpreted as a file name relative to the project's base directory. If that file is found, the URL | 
| 704 |      * of that file is returned. Otherwise {@code null} is returned.</p> | 
| 705 |      * | 
| 706 |      * @param location The resource location to create an {@code URL} from. | 
| 707 |      * | 
| 708 |      * @return An {@code URL} for {@code location} or {@code null}, if parsing {@code location} to an URL fails and | 
| 709 |      * {@code location} points to a non-existent resource. | 
| 710 |      * | 
| 711 |      * @throws NullPointerException if {@code location} is {@code null}. | 
| 712 |      * @throws BuildException if creating an URL fails. | 
| 713 |      */ | 
| 714 |     public URL getResource( final String location ) throws BuildException | 
| 715 |     { | 
| 716 |         if ( location == null ) | 
| 717 |         { | 
| 718 |             throw new NullPointerException( "location" ); | 
| 719 |         } | 
| 720 |   | 
| 721 |         try | 
| 722 |         { | 
| 723 |             String absolute = location; | 
| 724 |             if ( !absolute.startsWith( "/" ) ) | 
| 725 |             { | 
| 726 |                 absolute = "/" + absolute; | 
| 727 |             } | 
| 728 |   | 
| 729 |             URL resource = this.getClass().getResource( absolute ); | 
| 730 |             if ( resource == null ) | 
| 731 |             { | 
| 732 |                 try | 
| 733 |                 { | 
| 734 |                     resource = new URL( location ); | 
| 735 |                 } | 
| 736 |                 catch ( final MalformedURLException e ) | 
| 737 |                 { | 
| 738 |                     this.log( e, Project.MSG_DEBUG ); | 
| 739 |                     resource = null; | 
| 740 |                 } | 
| 741 |             } | 
| 742 |   | 
| 743 |             if ( resource == null ) | 
| 744 |             { | 
| 745 |                 final File f = this.getProject().resolveFile( location ); | 
| 746 |   | 
| 747 |                 if ( f.isFile() ) | 
| 748 |                 { | 
| 749 |                     resource = f.toURI().toURL(); | 
| 750 |                 } | 
| 751 |             } | 
| 752 |   | 
| 753 |             return resource; | 
| 754 |         } | 
| 755 |         catch ( final MalformedURLException e ) | 
| 756 |         { | 
| 757 |             String m = Messages.getMessage( e ); | 
| 758 |             m = m == null ? "" : " " + m; | 
| 759 |   | 
| 760 |             throw new BuildException( Messages.getMessage( "malformedLocation", location, m ), e, this.getLocation() ); | 
| 761 |         } | 
| 762 |     } | 
| 763 |   | 
| 764 |     /** | 
| 765 |      * Creates an array of {@code URL}s for a given resource location. | 
| 766 |      * <p>This method first searches the given context for resources matching {@code location}. If such resources are | 
| 767 |      * found, an array of URLs of those resources is returned. If no such resources are found, an attempt is made | 
| 768 |      * to parse the given location to an URL. On successful parsing, that URL is returned. Failing that, the given | 
| 769 |      * location is interpreted as a file name relative to the project's base directory. If that file is found, the URL | 
| 770 |      * of that file is returned. Otherwise an empty array is returned.</p> | 
| 771 |      * | 
| 772 |      * @param context The context to search for resources. | 
| 773 |      * @param location The resource location to create an array of {@code URL}s from. | 
| 774 |      * | 
| 775 |      * @return An array of {@code URL}s for {@code location} or an empty array if parsing {@code location} to an URL | 
| 776 |      * fails and {@code location} points to non-existent resources. | 
| 777 |      * | 
| 778 |      * @throws NullPointerException if {@code context} or {@code location} is {@code null}. | 
| 779 |      * @throws BuildException if creating an URL array fails. | 
| 780 |      */ | 
| 781 |     public URL[] getResources( final ModelContext context, final String location ) throws BuildException | 
| 782 |     { | 
| 783 |         if ( context == null ) | 
| 784 |         { | 
| 785 |             throw new NullPointerException( "context" ); | 
| 786 |         } | 
| 787 |         if ( location == null ) | 
| 788 |         { | 
| 789 |             throw new NullPointerException( "location" ); | 
| 790 |         } | 
| 791 |   | 
| 792 |         final Set<URI> uris = new HashSet<URI>(); | 
| 793 |   | 
| 794 |         try | 
| 795 |         { | 
| 796 |             for ( final Enumeration<URL> e = context.findResources( location ); e.hasMoreElements(); ) | 
| 797 |             { | 
| 798 |                 uris.add( e.nextElement().toURI() ); | 
| 799 |             } | 
| 800 |         } | 
| 801 |         catch ( final URISyntaxException e ) | 
| 802 |         { | 
| 803 |             this.log( e, Project.MSG_DEBUG ); | 
| 804 |         } | 
| 805 |         catch ( final ModelException e ) | 
| 806 |         { | 
| 807 |             this.log( e, Project.MSG_DEBUG ); | 
| 808 |         } | 
| 809 |   | 
| 810 |         if ( uris.isEmpty() ) | 
| 811 |         { | 
| 812 |             try | 
| 813 |             { | 
| 814 |                 uris.add( new URL( location ).toURI() ); | 
| 815 |             } | 
| 816 |             catch ( final MalformedURLException e ) | 
| 817 |             { | 
| 818 |                 this.log( e, Project.MSG_DEBUG ); | 
| 819 |             } | 
| 820 |             catch ( final URISyntaxException e ) | 
| 821 |             { | 
| 822 |                 this.log( e, Project.MSG_DEBUG ); | 
| 823 |             } | 
| 824 |         } | 
| 825 |   | 
| 826 |         if ( uris.isEmpty() ) | 
| 827 |         { | 
| 828 |             final File f = this.getProject().resolveFile( location ); | 
| 829 |   | 
| 830 |             if ( f.isFile() ) | 
| 831 |             { | 
| 832 |                 uris.add( f.toURI() ); | 
| 833 |             } | 
| 834 |         } | 
| 835 |   | 
| 836 |         int i = 0; | 
| 837 |         final URL[] urls = new URL[ uris.size() ]; | 
| 838 |   | 
| 839 |         for ( URI uri : uris ) | 
| 840 |         { | 
| 841 |             try | 
| 842 |             { | 
| 843 |                 urls[i++] = uri.toURL(); | 
| 844 |             } | 
| 845 |             catch ( final MalformedURLException e ) | 
| 846 |             { | 
| 847 |                 String m = Messages.getMessage( e ); | 
| 848 |                 m = m == null ? "" : " " + m; | 
| 849 |   | 
| 850 |                 throw new BuildException( Messages.getMessage( "malformedLocation", uri.toASCIIString(), m ), e, | 
| 851 |                                           this.getLocation() ); | 
| 852 |   | 
| 853 |             } | 
| 854 |         } | 
| 855 |   | 
| 856 |         return urls; | 
| 857 |     } | 
| 858 |   | 
| 859 |     /** | 
| 860 |      * Creates an {@code URL} for a given directory location. | 
| 861 |      * <p>This method first attempts to parse the given location to an URL. On successful parsing, that URL is returned. | 
| 862 |      * Failing that, the given location is interpreted as a directory name relative to the project's base directory. If | 
| 863 |      * that directory is found, the URL of that directory is returned. Otherwise {@code null} is returned.</p> | 
| 864 |      * | 
| 865 |      * @param location The directory location to create an {@code URL} from. | 
| 866 |      * | 
| 867 |      * @return An {@code URL} for {@code location} or {@code null}, if parsing {@code location} to an URL fails and | 
| 868 |      * {@code location} points to a non-existent directory. | 
| 869 |      * | 
| 870 |      * @throws NullPointerException if {@code location} is {@code null}. | 
| 871 |      * @throws BuildException if creating an URL fails. | 
| 872 |      */ | 
| 873 |     public URL getDirectory( final String location ) throws BuildException | 
| 874 |     { | 
| 875 |         if ( location == null ) | 
| 876 |         { | 
| 877 |             throw new NullPointerException( "location" ); | 
| 878 |         } | 
| 879 |   | 
| 880 |         try | 
| 881 |         { | 
| 882 |             URL resource = null; | 
| 883 |   | 
| 884 |             try | 
| 885 |             { | 
| 886 |                 resource = new URL( location ); | 
| 887 |             } | 
| 888 |             catch ( final MalformedURLException e ) | 
| 889 |             { | 
| 890 |                 this.log( e, Project.MSG_DEBUG ); | 
| 891 |                 resource = null; | 
| 892 |             } | 
| 893 |   | 
| 894 |             if ( resource == null ) | 
| 895 |             { | 
| 896 |                 final File f = this.getProject().resolveFile( location ); | 
| 897 |   | 
| 898 |                 if ( f.isDirectory() ) | 
| 899 |                 { | 
| 900 |                     resource = f.toURI().toURL(); | 
| 901 |                 } | 
| 902 |             } | 
| 903 |   | 
| 904 |             return resource; | 
| 905 |         } | 
| 906 |         catch ( final MalformedURLException e ) | 
| 907 |         { | 
| 908 |             String m = Messages.getMessage( e ); | 
| 909 |             m = m == null ? "" : " " + m; | 
| 910 |   | 
| 911 |             throw new BuildException( Messages.getMessage( "malformedLocation", location, m ), e, this.getLocation() ); | 
| 912 |         } | 
| 913 |     } | 
| 914 |   | 
| 915 |     /** | 
| 916 |      * Creates a new {@code Transformer} for a given {@code TransformerResourceType}. | 
| 917 |      * | 
| 918 |      * @param resource The resource to create a {@code Transformer} of. | 
| 919 |      * | 
| 920 |      * @return A new {@code Transformer} for {@code resource} or {@code null}, if {@code resource} is not found and | 
| 921 |      * flagged optional. | 
| 922 |      * | 
| 923 |      * @throws TransformerConfigurationException if creating a new {@code Transformer} fails. | 
| 924 |      * | 
| 925 |      * @see #getTransformationParameterResources() | 
| 926 |      * @see #getTransformationParameters() | 
| 927 |      * @see #getResource(java.lang.String) | 
| 928 |      */ | 
| 929 |     public Transformer getTransformer( final TransformerResourceType resource ) throws TransformerConfigurationException | 
| 930 |     { | 
| 931 |         if ( resource == null ) | 
| 932 |         { | 
| 933 |             throw new NullPointerException( "resource" ); | 
| 934 |         } | 
| 935 |   | 
| 936 |         InputStream in = null; | 
| 937 |         boolean suppressExceptionOnClose = true; | 
| 938 |         final URL url = this.getResource( resource.getLocation() ); | 
| 939 |   | 
| 940 |         try | 
| 941 |         { | 
| 942 |             if ( url != null ) | 
| 943 |             { | 
| 944 |                 final ErrorListener errorListener = new ErrorListener() | 
| 945 |                 { | 
| 946 |   | 
| 947 |                     public void warning( final TransformerException exception ) throws TransformerException | 
| 948 |                     { | 
| 949 |                         if ( getProject() != null ) | 
| 950 |                         { | 
| 951 |                             getProject().log( Messages.getMessage( exception ), exception, Project.MSG_WARN ); | 
| 952 |                         } | 
| 953 |                     } | 
| 954 |   | 
| 955 |                     public void error( final TransformerException exception ) throws TransformerException | 
| 956 |                     { | 
| 957 |                         throw exception; | 
| 958 |                     } | 
| 959 |   | 
| 960 |                     public void fatalError( final TransformerException exception ) throws TransformerException | 
| 961 |                     { | 
| 962 |                         throw exception; | 
| 963 |                     } | 
| 964 |   | 
| 965 |                 }; | 
| 966 |   | 
| 967 |                 final URLConnection con = url.openConnection(); | 
| 968 |                 con.setConnectTimeout( resource.getConnectTimeout() ); | 
| 969 |                 con.setReadTimeout( resource.getReadTimeout() ); | 
| 970 |                 con.connect(); | 
| 971 |                 in = con.getInputStream(); | 
| 972 |   | 
| 973 |                 final TransformerFactory f = TransformerFactory.newInstance(); | 
| 974 |                 f.setErrorListener( errorListener ); | 
| 975 |                 final Transformer transformer = f.newTransformer( new StreamSource( in, url.toURI().toASCIIString() ) ); | 
| 976 |                 transformer.setErrorListener( errorListener ); | 
| 977 |   | 
| 978 |                 for ( Map.Entry<Object, Object> e : System.getProperties().entrySet() ) | 
| 979 |                 { | 
| 980 |                     transformer.setParameter( e.getKey().toString(), e.getValue() ); | 
| 981 |                 } | 
| 982 |   | 
| 983 |                 for ( final Iterator<Map.Entry<?, ?>> it = this.getProject().getProperties().entrySet().iterator(); | 
| 984 |                       it.hasNext(); ) | 
| 985 |                 { | 
| 986 |                     final Map.Entry<?, ?> e = it.next(); | 
| 987 |                     transformer.setParameter( e.getKey().toString(), e.getValue() ); | 
| 988 |                 } | 
| 989 |   | 
| 990 |                 for ( int i = 0, s0 = this.getTransformationParameterResources().size(); i < s0; i++ ) | 
| 991 |                 { | 
| 992 |                     for ( Map.Entry<Object, Object> e : | 
| 993 |                           this.getProperties( this.getTransformationParameterResources().get( i ) ).entrySet() ) | 
| 994 |                     { | 
| 995 |                         transformer.setParameter( e.getKey().toString(), e.getValue() ); | 
| 996 |                     } | 
| 997 |                 } | 
| 998 |   | 
| 999 |                 for ( int i = 0, s0 = this.getTransformationParameters().size(); i < s0; i++ ) | 
| 1000 |                 { | 
| 1001 |                     final KeyValueType p = this.getTransformationParameters().get( i ); | 
| 1002 |                     transformer.setParameter( p.getKey(), p.getObject( this.getLocation() ) ); | 
| 1003 |                 } | 
| 1004 |   | 
| 1005 |                 for ( int i = 0, s0 = this.getTransformationOutputProperties().size(); i < s0; i++ ) | 
| 1006 |                 { | 
| 1007 |                     final KeyValueType p = this.getTransformationOutputProperties().get( i ); | 
| 1008 |                     transformer.setOutputProperty( p.getKey(), p.getValue() ); | 
| 1009 |                 } | 
| 1010 |   | 
| 1011 |                 for ( int i = 0, s0 = resource.getTransformationParameterResources().size(); i < s0; i++ ) | 
| 1012 |                 { | 
| 1013 |                     for ( Map.Entry<Object, Object> e : | 
| 1014 |                           this.getProperties( resource.getTransformationParameterResources().get( i ) ).entrySet() ) | 
| 1015 |                     { | 
| 1016 |                         transformer.setParameter( e.getKey().toString(), e.getValue() ); | 
| 1017 |                     } | 
| 1018 |                 } | 
| 1019 |   | 
| 1020 |                 for ( int i = 0, s0 = resource.getTransformationParameters().size(); i < s0; i++ ) | 
| 1021 |                 { | 
| 1022 |                     final KeyValueType p = resource.getTransformationParameters().get( i ); | 
| 1023 |                     transformer.setParameter( p.getKey(), p.getObject( this.getLocation() ) ); | 
| 1024 |                 } | 
| 1025 |   | 
| 1026 |                 for ( int i = 0, s0 = resource.getTransformationOutputProperties().size(); i < s0; i++ ) | 
| 1027 |                 { | 
| 1028 |                     final KeyValueType p = resource.getTransformationOutputProperties().get( i ); | 
| 1029 |                     transformer.setOutputProperty( p.getKey(), p.getValue() ); | 
| 1030 |                 } | 
| 1031 |   | 
| 1032 |                 suppressExceptionOnClose = false; | 
| 1033 |                 return transformer; | 
| 1034 |             } | 
| 1035 |             else if ( resource.isOptional() ) | 
| 1036 |             { | 
| 1037 |                 this.log( Messages.getMessage( "transformerNotFound", resource.getLocation() ), Project.MSG_WARN ); | 
| 1038 |             } | 
| 1039 |             else | 
| 1040 |             { | 
| 1041 |                 throw new BuildException( Messages.getMessage( "transformerNotFound", resource.getLocation() ), | 
| 1042 |                                           this.getLocation() ); | 
| 1043 |   | 
| 1044 |             } | 
| 1045 |         } | 
| 1046 |         catch ( final URISyntaxException e ) | 
| 1047 |         { | 
| 1048 |             throw new BuildException( Messages.getMessage( e ), e, this.getLocation() ); | 
| 1049 |         } | 
| 1050 |         catch ( final SocketTimeoutException e ) | 
| 1051 |         { | 
| 1052 |             final String message = Messages.getMessage( e ); | 
| 1053 |   | 
| 1054 |             if ( resource.isOptional() ) | 
| 1055 |             { | 
| 1056 |                 this.getProject().log( Messages.getMessage( "resourceTimeout", message != null ? " " + message : "" ), | 
| 1057 |                                        e, Project.MSG_WARN ); | 
| 1058 |   | 
| 1059 |             } | 
| 1060 |             else | 
| 1061 |             { | 
| 1062 |                 throw new BuildException( Messages.getMessage( "resourceTimeout", message != null ? " " + message : "" ), | 
| 1063 |                                           e, this.getLocation() ); | 
| 1064 |   | 
| 1065 |             } | 
| 1066 |         } | 
| 1067 |         catch ( final IOException e ) | 
| 1068 |         { | 
| 1069 |             final String message = Messages.getMessage( e ); | 
| 1070 |   | 
| 1071 |             if ( resource.isOptional() ) | 
| 1072 |             { | 
| 1073 |                 this.getProject().log( Messages.getMessage( "resourceFailure", message != null ? " " + message : "" ), | 
| 1074 |                                        e, Project.MSG_WARN ); | 
| 1075 |   | 
| 1076 |             } | 
| 1077 |             else | 
| 1078 |             { | 
| 1079 |                 throw new BuildException( Messages.getMessage( "resourceFailure", message != null ? " " + message : "" ), | 
| 1080 |                                           e, this.getLocation() ); | 
| 1081 |   | 
| 1082 |             } | 
| 1083 |         } | 
| 1084 |         finally | 
| 1085 |         { | 
| 1086 |             try | 
| 1087 |             { | 
| 1088 |                 if ( in != null ) | 
| 1089 |                 { | 
| 1090 |                     in.close(); | 
| 1091 |                 } | 
| 1092 |             } | 
| 1093 |             catch ( final IOException e ) | 
| 1094 |             { | 
| 1095 |                 if ( suppressExceptionOnClose ) | 
| 1096 |                 { | 
| 1097 |                     this.logMessage( Level.SEVERE, Messages.getMessage( e ), e ); | 
| 1098 |                 } | 
| 1099 |                 else | 
| 1100 |                 { | 
| 1101 |                     throw new BuildException( Messages.getMessage( e ), e, this.getLocation() ); | 
| 1102 |                 } | 
| 1103 |             } | 
| 1104 |         } | 
| 1105 |   | 
| 1106 |         return null; | 
| 1107 |     } | 
| 1108 |   | 
| 1109 |     /** | 
| 1110 |      * Creates a new {@code Properties} instance from a {@code PropertiesResourceType}. | 
| 1111 |      * | 
| 1112 |      * @param propertiesResourceType The {@code PropertiesResourceType} specifying the properties to create. | 
| 1113 |      * | 
| 1114 |      * @return The properties for {@code propertiesResourceType}. | 
| 1115 |      * | 
| 1116 |      * @throws NullPointerException if {@code propertiesResourceType} is {@code null}. | 
| 1117 |      * @throws BuildException if loading properties fails. | 
| 1118 |      */ | 
| 1119 |     public Properties getProperties( final PropertiesResourceType propertiesResourceType ) throws BuildException | 
| 1120 |     { | 
| 1121 |         if ( propertiesResourceType == null ) | 
| 1122 |         { | 
| 1123 |             throw new NullPointerException( "propertiesResourceType" ); | 
| 1124 |         } | 
| 1125 |   | 
| 1126 |         InputStream in = null; | 
| 1127 |         boolean suppressExceptionOnClose = true; | 
| 1128 |         final Properties properties = new Properties(); | 
| 1129 |         final URL url = this.getResource( propertiesResourceType.getLocation() ); | 
| 1130 |   | 
| 1131 |         try | 
| 1132 |         { | 
| 1133 |             if ( url != null ) | 
| 1134 |             { | 
| 1135 |                 final URLConnection con = url.openConnection(); | 
| 1136 |                 con.setConnectTimeout( propertiesResourceType.getConnectTimeout() ); | 
| 1137 |                 con.setReadTimeout( propertiesResourceType.getReadTimeout() ); | 
| 1138 |                 con.connect(); | 
| 1139 |   | 
| 1140 |                 in = con.getInputStream(); | 
| 1141 |   | 
| 1142 |                 if ( propertiesResourceType.getFormat() == PropertiesFormatType.PLAIN ) | 
| 1143 |                 { | 
| 1144 |                     properties.load( in ); | 
| 1145 |                 } | 
| 1146 |                 else if ( propertiesResourceType.getFormat() == PropertiesFormatType.XML ) | 
| 1147 |                 { | 
| 1148 |                     properties.loadFromXML( in ); | 
| 1149 |                 } | 
| 1150 |             } | 
| 1151 |             else if ( propertiesResourceType.isOptional() ) | 
| 1152 |             { | 
| 1153 |                 this.log( Messages.getMessage( "propertiesNotFound", propertiesResourceType.getLocation() ), | 
| 1154 |                           Project.MSG_WARN ); | 
| 1155 |   | 
| 1156 |             } | 
| 1157 |             else | 
| 1158 |             { | 
| 1159 |                 throw new BuildException( Messages.getMessage( | 
| 1160 |                     "propertiesNotFound", propertiesResourceType.getLocation() ), this.getLocation() ); | 
| 1161 |   | 
| 1162 |             } | 
| 1163 |   | 
| 1164 |             suppressExceptionOnClose = false; | 
| 1165 |         } | 
| 1166 |         catch ( final SocketTimeoutException e ) | 
| 1167 |         { | 
| 1168 |             final String message = Messages.getMessage( e ); | 
| 1169 |   | 
| 1170 |             if ( propertiesResourceType.isOptional() ) | 
| 1171 |             { | 
| 1172 |                 this.getProject().log( Messages.getMessage( "resourceTimeout", message != null ? " " + message : "" ), | 
| 1173 |                                        e, Project.MSG_WARN ); | 
| 1174 |   | 
| 1175 |             } | 
| 1176 |             else | 
| 1177 |             { | 
| 1178 |                 throw new BuildException( Messages.getMessage( "resourceTimeout", message != null ? " " + message : "" ), | 
| 1179 |                                           e, this.getLocation() ); | 
| 1180 |   | 
| 1181 |             } | 
| 1182 |         } | 
| 1183 |         catch ( final IOException e ) | 
| 1184 |         { | 
| 1185 |             final String message = Messages.getMessage( e ); | 
| 1186 |   | 
| 1187 |             if ( propertiesResourceType.isOptional() ) | 
| 1188 |             { | 
| 1189 |                 this.getProject().log( Messages.getMessage( "resourceFailure", message != null ? " " + message : "" ), | 
| 1190 |                                        e, Project.MSG_WARN ); | 
| 1191 |   | 
| 1192 |             } | 
| 1193 |             else | 
| 1194 |             { | 
| 1195 |                 throw new BuildException( Messages.getMessage( "resourceFailure", message != null ? " " + message : "" ), | 
| 1196 |                                           e, this.getLocation() ); | 
| 1197 |   | 
| 1198 |             } | 
| 1199 |         } | 
| 1200 |         finally | 
| 1201 |         { | 
| 1202 |             try | 
| 1203 |             { | 
| 1204 |                 if ( in != null ) | 
| 1205 |                 { | 
| 1206 |                     in.close(); | 
| 1207 |                 } | 
| 1208 |             } | 
| 1209 |             catch ( final IOException e ) | 
| 1210 |             { | 
| 1211 |                 if ( suppressExceptionOnClose ) | 
| 1212 |                 { | 
| 1213 |                     this.logMessage( Level.SEVERE, Messages.getMessage( e ), e ); | 
| 1214 |                 } | 
| 1215 |                 else | 
| 1216 |                 { | 
| 1217 |                     throw new BuildException( Messages.getMessage( e ), e, this.getLocation() ); | 
| 1218 |                 } | 
| 1219 |             } | 
| 1220 |         } | 
| 1221 |   | 
| 1222 |         return properties; | 
| 1223 |     } | 
| 1224 |   | 
| 1225 |     /** | 
| 1226 |      * Creates a new {@code ProjectClassLoader} instance. | 
| 1227 |      * | 
| 1228 |      * @return A new {@code ProjectClassLoader} instance. | 
| 1229 |      * | 
| 1230 |      * @throws BuildException if creating a new class loader instance fails. | 
| 1231 |      */ | 
| 1232 |     public ProjectClassLoader newProjectClassLoader() throws BuildException | 
| 1233 |     { | 
| 1234 |         try | 
| 1235 |         { | 
| 1236 |             final ProjectClassLoader classLoader = new ProjectClassLoader( this.getProject(), this.getClasspath() ); | 
| 1237 |             classLoader.getModletExcludes().addAll( ProjectClassLoader.getDefaultModletExcludes() ); | 
| 1238 |             classLoader.getProviderExcludes().addAll( ProjectClassLoader.getDefaultProviderExcludes() ); | 
| 1239 |             classLoader.getSchemaExcludes().addAll( ProjectClassLoader.getDefaultSchemaExcludes() ); | 
| 1240 |             classLoader.getServiceExcludes().addAll( ProjectClassLoader.getDefaultServiceExcludes() ); | 
| 1241 |   | 
| 1242 |             if ( this.getModletLocation() != null ) | 
| 1243 |             { | 
| 1244 |                 classLoader.getModletResourceLocations().add( this.getModletLocation() ); | 
| 1245 |             } | 
| 1246 |             else | 
| 1247 |             { | 
| 1248 |                 classLoader.getModletResourceLocations().add( DefaultModletProvider.getDefaultModletLocation() ); | 
| 1249 |             } | 
| 1250 |   | 
| 1251 |             if ( this.getProviderLocation() != null ) | 
| 1252 |             { | 
| 1253 |                 classLoader.getProviderResourceLocations().add( | 
| 1254 |                     this.getProviderLocation() + "/" + ModletProvider.class.getName() ); | 
| 1255 |   | 
| 1256 |             } | 
| 1257 |             else | 
| 1258 |             { | 
| 1259 |                 classLoader.getProviderResourceLocations().add( | 
| 1260 |                     DefaultModelContext.getDefaultProviderLocation() + "/" + ModletProvider.class.getName() ); | 
| 1261 |   | 
| 1262 |             } | 
| 1263 |   | 
| 1264 |             return classLoader; | 
| 1265 |         } | 
| 1266 |         catch ( final IOException e ) | 
| 1267 |         { | 
| 1268 |             throw new BuildException( Messages.getMessage( e ), e, this.getLocation() ); | 
| 1269 |         } | 
| 1270 |     } | 
| 1271 |   | 
| 1272 |     /** | 
| 1273 |      * Creates a new {@code ModelContext} instance using a given class loader. | 
| 1274 |      * | 
| 1275 |      * @param classLoader The class loader to create a new {@code ModelContext} instance with. | 
| 1276 |      * | 
| 1277 |      * @return A new {@code ModelContext} instance backed by {@code classLoader}. | 
| 1278 |      * | 
| 1279 |      * @throws ModelException if creating a new {@code ModelContext} instance fails. | 
| 1280 |      */ | 
| 1281 |     public ModelContext newModelContext( final ClassLoader classLoader ) throws ModelException | 
| 1282 |     { | 
| 1283 |         final ModelContextFactory modelContextFactory; | 
| 1284 |         if ( this.modelContextFactoryClassName != null ) | 
| 1285 |         { | 
| 1286 |             modelContextFactory = ModelContextFactory.newInstance( this.getModelContextFactoryClassName() ); | 
| 1287 |         } | 
| 1288 |         else | 
| 1289 |         { | 
| 1290 |             modelContextFactory = ModelContextFactory.newInstance(); | 
| 1291 |         } | 
| 1292 |   | 
| 1293 |         final ModelContext modelContext = modelContextFactory.newModelContext( classLoader ); | 
| 1294 |         modelContext.setLogLevel( Level.ALL ); | 
| 1295 |         modelContext.setModletSchemaSystemId( this.getModletSchemaSystemId() ); | 
| 1296 |   | 
| 1297 |         modelContext.getListeners().add( new ModelContext.Listener() | 
| 1298 |         { | 
| 1299 |   | 
| 1300 |             @Override | 
| 1301 |             public void onLog( final Level level, final String message, final Throwable t ) | 
| 1302 |             { | 
| 1303 |                 super.onLog( level, message, t ); | 
| 1304 |                 logMessage( level, message, t ); | 
| 1305 |             } | 
| 1306 |   | 
| 1307 |         } ); | 
| 1308 |   | 
| 1309 |         if ( this.getProviderLocation() != null ) | 
| 1310 |         { | 
| 1311 |             modelContext.setAttribute( DefaultModelContext.PROVIDER_LOCATION_ATTRIBUTE_NAME, | 
| 1312 |                                        this.getProviderLocation() ); | 
| 1313 |   | 
| 1314 |         } | 
| 1315 |   | 
| 1316 |         if ( this.getPlatformProviderLocation() != null ) | 
| 1317 |         { | 
| 1318 |             modelContext.setAttribute( DefaultModelContext.PLATFORM_PROVIDER_LOCATION_ATTRIBUTE_NAME, | 
| 1319 |                                        this.getPlatformProviderLocation() ); | 
| 1320 |   | 
| 1321 |         } | 
| 1322 |   | 
| 1323 |         if ( this.getModletLocation() != null ) | 
| 1324 |         { | 
| 1325 |             modelContext.setAttribute( DefaultModletProvider.MODLET_LOCATION_ATTRIBUTE_NAME, this.getModletLocation() ); | 
| 1326 |         } | 
| 1327 |   | 
| 1328 |         modelContext.setAttribute( DefaultModletProvider.VALIDATING_ATTRIBUTE_NAME, | 
| 1329 |                                    this.isModletResourceValidationEnabled() ); | 
| 1330 |   | 
| 1331 |         for ( int i = 0, s0 = this.getModelContextAttributes().size(); i < s0; i++ ) | 
| 1332 |         { | 
| 1333 |             final KeyValueType kv = this.getModelContextAttributes().get( i ); | 
| 1334 |             final Object object = kv.getObject( this.getLocation() ); | 
| 1335 |   | 
| 1336 |             if ( object != null ) | 
| 1337 |             { | 
| 1338 |                 modelContext.setAttribute( kv.getKey(), object ); | 
| 1339 |             } | 
| 1340 |             else | 
| 1341 |             { | 
| 1342 |                 modelContext.clearAttribute( kv.getKey() ); | 
| 1343 |             } | 
| 1344 |         } | 
| 1345 |   | 
| 1346 |         return modelContext; | 
| 1347 |     } | 
| 1348 |   | 
| 1349 |     /** | 
| 1350 |      * Throws a {@code BuildException} on a given {@code null} value. | 
| 1351 |      * | 
| 1352 |      * @param attributeName The name of a mandatory attribute. | 
| 1353 |      * @param value The value of that attribute. | 
| 1354 |      * | 
| 1355 |      * @throws NullPointerException if {@code attributeName} is {@code null}. | 
| 1356 |      * @throws BuildException if {@code value} is {@code null}. | 
| 1357 |      */ | 
| 1358 |     public final void assertNotNull( final String attributeName, final Object value ) throws BuildException | 
| 1359 |     { | 
| 1360 |         if ( attributeName == null ) | 
| 1361 |         { | 
| 1362 |             throw new NullPointerException( "attributeName" ); | 
| 1363 |         } | 
| 1364 |   | 
| 1365 |         if ( value == null ) | 
| 1366 |         { | 
| 1367 |             throw new BuildException( Messages.getMessage( "mandatoryAttribute", attributeName ), this.getLocation() ); | 
| 1368 |         } | 
| 1369 |     } | 
| 1370 |   | 
| 1371 |     /** | 
| 1372 |      * Throws a {@code BuildException} on a {@code null} value of a {@code name} property of a given {@code NameType} | 
| 1373 |      * collection. | 
| 1374 |      * | 
| 1375 |      * @param names The collection holding the  {@code NameType} instances to test. | 
| 1376 |      * | 
| 1377 |      * @throws NullPointerException if {@code names} is {@code null}. | 
| 1378 |      * @throws BuildException if a {@code name} property of a given {@code NameType} from the {@code names} collection | 
| 1379 |      * holds a {@code null} value. | 
| 1380 |      */ | 
| 1381 |     public final void assertNamesNotNull( final Collection<? extends NameType> names ) throws BuildException | 
| 1382 |     { | 
| 1383 |         if ( names == null ) | 
| 1384 |         { | 
| 1385 |             throw new NullPointerException( "names" ); | 
| 1386 |         } | 
| 1387 |   | 
| 1388 |         for ( NameType n : names ) | 
| 1389 |         { | 
| 1390 |             this.assertNotNull( "name", n.getName() ); | 
| 1391 |         } | 
| 1392 |     } | 
| 1393 |   | 
| 1394 |     /** | 
| 1395 |      * Throws a {@code BuildException} on a {@code null} value of a {@code key} property of a given {@code KeyValueType} | 
| 1396 |      * collection. | 
| 1397 |      * | 
| 1398 |      * @param keys The collection holding the  {@code KeyValueType} instances to test. | 
| 1399 |      * | 
| 1400 |      * @throws NullPointerException if {@code keys} is {@code null}. | 
| 1401 |      * @throws BuildException if a {@code key} property of a given {@code KeyValueType} from the {@code keys} collection | 
| 1402 |      * holds a {@code null} value. | 
| 1403 |      */ | 
| 1404 |     public final void assertKeysNotNull( final Collection<? extends KeyValueType> keys ) throws BuildException | 
| 1405 |     { | 
| 1406 |         if ( keys == null ) | 
| 1407 |         { | 
| 1408 |             throw new NullPointerException( "keys" ); | 
| 1409 |         } | 
| 1410 |   | 
| 1411 |         for ( KeyValueType k : keys ) | 
| 1412 |         { | 
| 1413 |             this.assertNotNull( "key", k.getKey() ); | 
| 1414 |         } | 
| 1415 |     } | 
| 1416 |   | 
| 1417 |     /** | 
| 1418 |      * Throws a {@code BuildException} on a {@code null} value of a {@code location} property of a given | 
| 1419 |      * {@code ResourceType} collection. | 
| 1420 |      * | 
| 1421 |      * @param locations The collection holding the {@code ResourceType} instances to test. | 
| 1422 |      * | 
| 1423 |      * @throws NullPointerException if {@code locations} is {@code null}. | 
| 1424 |      * @throws BuildException if a {@code location} property of a given {@code ResourceType} from the {@code locations} | 
| 1425 |      * collection holds a {@code null} value. | 
| 1426 |      */ | 
| 1427 |     public final void assertLocationsNotNull( final Collection<? extends ResourceType> locations ) | 
| 1428 |         throws BuildException | 
| 1429 |     { | 
| 1430 |         if ( locations == null ) | 
| 1431 |         { | 
| 1432 |             throw new NullPointerException( "locations" ); | 
| 1433 |         } | 
| 1434 |   | 
| 1435 |         for ( ResourceType r : locations ) | 
| 1436 |         { | 
| 1437 |             assertNotNull( "location", r.getLocation() ); | 
| 1438 |   | 
| 1439 |             if ( r instanceof TransformerResourceType ) | 
| 1440 |             { | 
| 1441 |                 assertKeysNotNull( ( (TransformerResourceType) r ).getTransformationParameters() ); | 
| 1442 |                 assertLocationsNotNull( ( (TransformerResourceType) r ).getTransformationParameterResources() ); | 
| 1443 |                 assertKeysNotNull( ( (TransformerResourceType) r ).getTransformationOutputProperties() ); | 
| 1444 |             } | 
| 1445 |         } | 
| 1446 |     } | 
| 1447 |   | 
| 1448 |     /** Logs a separator string. */ | 
| 1449 |     public final void logSeparator() | 
| 1450 |     { | 
| 1451 |         this.log( Messages.getMessage( "separator" ) ); | 
| 1452 |     } | 
| 1453 |   | 
| 1454 |     /** | 
| 1455 |      * Logs a message at a given level. | 
| 1456 |      * | 
| 1457 |      * @param level The level to log at. | 
| 1458 |      * @param message The message to log. | 
| 1459 |      * | 
| 1460 |      * @throws BuildException if logging fails. | 
| 1461 |      */ | 
| 1462 |     public final void logMessage( final Level level, final String message ) throws BuildException | 
| 1463 |     { | 
| 1464 |         BufferedReader reader = null; | 
| 1465 |         boolean suppressExceptionOnClose = true; | 
| 1466 |   | 
| 1467 |         try | 
| 1468 |         { | 
| 1469 |             String line = null; | 
| 1470 |             reader = new BufferedReader( new StringReader( message ) ); | 
| 1471 |   | 
| 1472 |             while ( ( line = reader.readLine() ) != null ) | 
| 1473 |             { | 
| 1474 |                 if ( level.intValue() >= Level.SEVERE.intValue() ) | 
| 1475 |                 { | 
| 1476 |                     log( line, Project.MSG_ERR ); | 
| 1477 |                 } | 
| 1478 |                 else if ( level.intValue() >= Level.WARNING.intValue() ) | 
| 1479 |                 { | 
| 1480 |                     log( line, Project.MSG_WARN ); | 
| 1481 |                 } | 
| 1482 |                 else if ( level.intValue() >= Level.INFO.intValue() ) | 
| 1483 |                 { | 
| 1484 |                     log( line, Project.MSG_INFO ); | 
| 1485 |                 } | 
| 1486 |                 else | 
| 1487 |                 { | 
| 1488 |                     log( line, Project.MSG_DEBUG ); | 
| 1489 |                 } | 
| 1490 |             } | 
| 1491 |   | 
| 1492 |             suppressExceptionOnClose = false; | 
| 1493 |         } | 
| 1494 |         catch ( final IOException e ) | 
| 1495 |         { | 
| 1496 |             throw new BuildException( Messages.getMessage( e ), e, this.getLocation() ); | 
| 1497 |         } | 
| 1498 |         finally | 
| 1499 |         { | 
| 1500 |             try | 
| 1501 |             { | 
| 1502 |                 if ( reader != null ) | 
| 1503 |                 { | 
| 1504 |                     reader.close(); | 
| 1505 |                 } | 
| 1506 |             } | 
| 1507 |             catch ( final IOException e ) | 
| 1508 |             { | 
| 1509 |                 if ( suppressExceptionOnClose ) | 
| 1510 |                 { | 
| 1511 |                     this.log( e, Project.MSG_ERR ); | 
| 1512 |                 } | 
| 1513 |                 else | 
| 1514 |                 { | 
| 1515 |                     throw new BuildException( Messages.getMessage( e ), e, this.getLocation() ); | 
| 1516 |                 } | 
| 1517 |             } | 
| 1518 |         } | 
| 1519 |     } | 
| 1520 |   | 
| 1521 |     /** | 
| 1522 |      * Logs a message at a given level. | 
| 1523 |      * | 
| 1524 |      * @param level The level to log at. | 
| 1525 |      * @param message The message to log. | 
| 1526 |      * @param throwable The throwable to log. | 
| 1527 |      * | 
| 1528 |      * @throws BuildException if logging fails. | 
| 1529 |      */ | 
| 1530 |     public final void logMessage( final Level level, final String message, final Throwable throwable ) | 
| 1531 |         throws BuildException | 
| 1532 |     { | 
| 1533 |         this.logMessage( level, message ); | 
| 1534 |   | 
| 1535 |         if ( level.intValue() >= Level.SEVERE.intValue() ) | 
| 1536 |         { | 
| 1537 |             log( throwable, Project.MSG_ERR ); | 
| 1538 |         } | 
| 1539 |         else if ( level.intValue() >= Level.WARNING.intValue() ) | 
| 1540 |         { | 
| 1541 |             log( throwable, Project.MSG_WARN ); | 
| 1542 |         } | 
| 1543 |         else if ( level.intValue() >= Level.INFO.intValue() ) | 
| 1544 |         { | 
| 1545 |             log( throwable, Project.MSG_INFO ); | 
| 1546 |         } | 
| 1547 |         else | 
| 1548 |         { | 
| 1549 |             log( throwable, Project.MSG_DEBUG ); | 
| 1550 |         } | 
| 1551 |     } | 
| 1552 |   | 
| 1553 |     /** | 
| 1554 |      * Logs a validation report. | 
| 1555 |      * | 
| 1556 |      * @param context The context to use for logging the report. | 
| 1557 |      * @param report The report to log. | 
| 1558 |      * | 
| 1559 |      * @throws NullPointerException if {@code context} or {@code report} is {@code null}. | 
| 1560 |      * @throws BuildException if logging fails. | 
| 1561 |      */ | 
| 1562 |     public final void logValidationReport( final ModelContext context, final ModelValidationReport report ) | 
| 1563 |     { | 
| 1564 |         try | 
| 1565 |         { | 
| 1566 |             if ( !report.getDetails().isEmpty() ) | 
| 1567 |             { | 
| 1568 |                 this.logSeparator(); | 
| 1569 |                 Marshaller marshaller = null; | 
| 1570 |   | 
| 1571 |                 for ( ModelValidationReport.Detail detail : report.getDetails() ) | 
| 1572 |                 { | 
| 1573 |                     this.logMessage( detail.getLevel(), "o " + detail.getMessage() ); | 
| 1574 |   | 
| 1575 |                     if ( detail.getElement() != null ) | 
| 1576 |                     { | 
| 1577 |                         if ( marshaller == null ) | 
| 1578 |                         { | 
| 1579 |                             marshaller = context.createMarshaller( this.getModel() ); | 
| 1580 |                             marshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE ); | 
| 1581 |                         } | 
| 1582 |   | 
| 1583 |                         final StringWriter stringWriter = new StringWriter(); | 
| 1584 |                         marshaller.marshal( detail.getElement(), stringWriter ); | 
| 1585 |                         this.logMessage( Level.FINEST, stringWriter.toString() ); | 
| 1586 |                     } | 
| 1587 |                 } | 
| 1588 |             } | 
| 1589 |         } | 
| 1590 |         catch ( final ModelException e ) | 
| 1591 |         { | 
| 1592 |             throw new BuildException( Messages.getMessage( e ), e, this.getLocation() ); | 
| 1593 |         } | 
| 1594 |         catch ( final JAXBException e ) | 
| 1595 |         { | 
| 1596 |             String message = Messages.getMessage( e ); | 
| 1597 |             if ( message == null && e.getLinkedException() != null ) | 
| 1598 |             { | 
| 1599 |                 message = Messages.getMessage( e.getLinkedException() ); | 
| 1600 |             } | 
| 1601 |   | 
| 1602 |             throw new BuildException( message, e, this.getLocation() ); | 
| 1603 |         } | 
| 1604 |     } | 
| 1605 |   | 
| 1606 |     /** | 
| 1607 |      * Creates and returns a copy of this object. | 
| 1608 |      * | 
| 1609 |      * @return A copy of this object. | 
| 1610 |      */ | 
| 1611 |     @Override | 
| 1612 |     public JomcTask clone() | 
| 1613 |     { | 
| 1614 |         try | 
| 1615 |         { | 
| 1616 |             final JomcTask clone = (JomcTask) super.clone(); | 
| 1617 |             clone.classpath = (Path) ( this.classpath != null ? this.classpath.clone() : null ); | 
| 1618 |   | 
| 1619 |             if ( this.modelContextAttributes != null ) | 
| 1620 |             { | 
| 1621 |                 clone.modelContextAttributes = new ArrayList<KeyValueType>( this.modelContextAttributes.size() ); | 
| 1622 |   | 
| 1623 |                 for ( KeyValueType e : this.modelContextAttributes ) | 
| 1624 |                 { | 
| 1625 |                     clone.modelContextAttributes.add( e.clone() ); | 
| 1626 |                 } | 
| 1627 |             } | 
| 1628 |   | 
| 1629 |             if ( this.transformationParameters != null ) | 
| 1630 |             { | 
| 1631 |                 clone.transformationParameters = | 
| 1632 |                     new ArrayList<KeyValueType>( this.transformationParameters.size() ); | 
| 1633 |   | 
| 1634 |                 for ( KeyValueType e : this.transformationParameters ) | 
| 1635 |                 { | 
| 1636 |                     clone.transformationParameters.add( e.clone() ); | 
| 1637 |                 } | 
| 1638 |             } | 
| 1639 |   | 
| 1640 |             if ( this.transformationParameterResources != null ) | 
| 1641 |             { | 
| 1642 |                 clone.transformationParameterResources = | 
| 1643 |                     new ArrayList<PropertiesResourceType>( this.transformationParameterResources.size() ); | 
| 1644 |   | 
| 1645 |                 for ( PropertiesResourceType e : this.transformationParameterResources ) | 
| 1646 |                 { | 
| 1647 |                     clone.transformationParameterResources.add( e.clone() ); | 
| 1648 |                 } | 
| 1649 |             } | 
| 1650 |   | 
| 1651 |             if ( this.transformationOutputProperties != null ) | 
| 1652 |             { | 
| 1653 |                 clone.transformationOutputProperties = | 
| 1654 |                     new ArrayList<KeyValueType>( this.transformationOutputProperties.size() ); | 
| 1655 |   | 
| 1656 |                 for ( KeyValueType e : this.transformationOutputProperties ) | 
| 1657 |                 { | 
| 1658 |                     clone.transformationOutputProperties.add( e.clone() ); | 
| 1659 |                 } | 
| 1660 |             } | 
| 1661 |   | 
| 1662 |             return clone; | 
| 1663 |         } | 
| 1664 |         catch ( final CloneNotSupportedException e ) | 
| 1665 |         { | 
| 1666 |             throw new AssertionError( e ); | 
| 1667 |         } | 
| 1668 |     } | 
| 1669 |   | 
| 1670 | } |