| 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: ProjectClassLoader.java 4613 2012-09-22 10:07:08Z schulte $ | 
| 29 |  * | 
| 30 |  */ | 
| 31 | package org.jomc.ant; | 
| 32 |   | 
| 33 | import java.io.Closeable; | 
| 34 | import java.io.File; | 
| 35 | import java.io.FileOutputStream; | 
| 36 | import java.io.IOException; | 
| 37 | import java.io.InputStream; | 
| 38 | import java.io.OutputStream; | 
| 39 | import java.net.MalformedURLException; | 
| 40 | import java.net.URL; | 
| 41 | import java.net.URLClassLoader; | 
| 42 | import java.util.ArrayList; | 
| 43 | import java.util.Collections; | 
| 44 | import java.util.Enumeration; | 
| 45 | import java.util.HashSet; | 
| 46 | import java.util.Iterator; | 
| 47 | import java.util.List; | 
| 48 | import java.util.Set; | 
| 49 | import javax.xml.bind.JAXBElement; | 
| 50 | import javax.xml.bind.JAXBException; | 
| 51 | import org.apache.commons.io.IOUtils; | 
| 52 | import org.apache.commons.lang.StringUtils; | 
| 53 | import org.apache.tools.ant.Project; | 
| 54 | import org.apache.tools.ant.types.Path; | 
| 55 | import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement; | 
| 56 | import org.jomc.modlet.ModelContext; | 
| 57 | import org.jomc.modlet.ModelContextFactory; | 
| 58 | import org.jomc.modlet.ModelException; | 
| 59 | import org.jomc.modlet.Modlet; | 
| 60 | import org.jomc.modlet.ModletObject; | 
| 61 | import org.jomc.modlet.Modlets; | 
| 62 | import org.jomc.modlet.ObjectFactory; | 
| 63 | import org.jomc.modlet.Schema; | 
| 64 | import org.jomc.modlet.Schemas; | 
| 65 | import org.jomc.modlet.Service; | 
| 66 | import org.jomc.modlet.Services; | 
| 67 | import org.jomc.util.ParseException; | 
| 68 | import org.jomc.util.TokenMgrError; | 
| 69 | import org.jomc.util.VersionParser; | 
| 70 |   | 
| 71 | /** | 
| 72 |  * Class loader supporting JOMC resources backed by a project. | 
| 73 |  * | 
| 74 |  * @author <a href="mailto:cs@schulte.it">Christian Schulte</a> | 
| 75 |  * @version $JOMC: ProjectClassLoader.java 4613 2012-09-22 10:07:08Z schulte $ | 
| 76 |  */ | 
| 77 | public class ProjectClassLoader extends URLClassLoader | 
| 78 | { | 
| 79 |   | 
| 80 |     /** Constant to prefix relative resource names with. */ | 
| 81 |     private static final String ABSOLUTE_RESOURCE_NAME_PREFIX = "/org/jomc/ant/"; | 
| 82 |   | 
| 83 |     /** Empty URL array. */ | 
| 84 |     private static final URL[] NO_URLS = | 
| 85 |     { | 
| 86 |     }; | 
| 87 |   | 
| 88 |     /** Set of modlet names to exclude. */ | 
| 89 |     private Set<String> modletExcludes; | 
| 90 |   | 
| 91 |     /** Excluded modlets. */ | 
| 92 |     private Modlets excludedModlets; | 
| 93 |   | 
| 94 |     /** Set of service class names to exclude. */ | 
| 95 |     private Set<String> serviceExcludes; | 
| 96 |   | 
| 97 |     /** Excluded services. */ | 
| 98 |     private Services excludedServices; | 
| 99 |   | 
| 100 |     /** Set of schema public ids to exclude. */ | 
| 101 |     private Set<String> schemaExcludes; | 
| 102 |   | 
| 103 |     /** Excluded schemas. */ | 
| 104 |     private Schemas excludedSchemas; | 
| 105 |   | 
| 106 |     /** Set of providers to exclude. */ | 
| 107 |     private Set<String> providerExcludes; | 
| 108 |   | 
| 109 |     /** Set of excluded providers. */ | 
| 110 |     private Set<String> excludedProviders; | 
| 111 |   | 
| 112 |     /** The project the class loader is associated with. */ | 
| 113 |     private final Project project; | 
| 114 |   | 
| 115 |     /** Set of modlet resource locations to filter. */ | 
| 116 |     private Set<String> modletResourceLocations; | 
| 117 |   | 
| 118 |     /** Set of provider resource locations to filter. */ | 
| 119 |     private Set<String> providerResourceLocations; | 
| 120 |   | 
| 121 |     /** Set of temporary resources. */ | 
| 122 |     private final Set<File> temporaryResources = new HashSet<File>(); | 
| 123 |   | 
| 124 |     /** | 
| 125 |      * Creates a new {@code ProjectClassLoader} instance taking a project and a class path. | 
| 126 |      * | 
| 127 |      * @param project The project to which this class loader is to belong. | 
| 128 |      * @param classpath The class path to use for loading. | 
| 129 |      * | 
| 130 |      * @throws MalformedURLException if {@code classpath} contains unsupported elements. | 
| 131 |      */ | 
| 132 |     public ProjectClassLoader( final Project project, final Path classpath ) throws MalformedURLException | 
| 133 |     { | 
| 134 |         super( NO_URLS, ProjectClassLoader.class.getClassLoader() ); | 
| 135 |   | 
| 136 |         for ( final String name : classpath.list() ) | 
| 137 |         { | 
| 138 |             final File resolved = project.resolveFile( name ); | 
| 139 |             this.addURL( resolved.toURI().toURL() ); | 
| 140 |         } | 
| 141 |   | 
| 142 |         this.project = project; | 
| 143 |     } | 
| 144 |   | 
| 145 |     /** | 
| 146 |      * Gets the project of the instance. | 
| 147 |      * | 
| 148 |      * @return The project of the instance. | 
| 149 |      */ | 
| 150 |     public final Project getProject() | 
| 151 |     { | 
| 152 |         return this.project; | 
| 153 |     } | 
| 154 |   | 
| 155 |     /** | 
| 156 |      * Finds a resource with a given name. | 
| 157 |      * | 
| 158 |      * @param name The name of the resource to search. | 
| 159 |      * | 
| 160 |      * @return An {@code URL} object for reading the resource or {@code null}, if no resource matching {@code name} is | 
| 161 |      * found. | 
| 162 |      */ | 
| 163 |     @Override | 
| 164 |     public URL findResource( final String name ) | 
| 165 |     { | 
| 166 |         try | 
| 167 |         { | 
| 168 |             URL resource = super.findResource( name ); | 
| 169 |   | 
| 170 |             if ( resource != null ) | 
| 171 |             { | 
| 172 |                 if ( this.getProviderResourceLocations().contains( name ) ) | 
| 173 |                 { | 
| 174 |                     resource = this.filterProviders( resource ); | 
| 175 |                 } | 
| 176 |                 else if ( this.getModletResourceLocations().contains( name ) ) | 
| 177 |                 { | 
| 178 |                     resource = this.filterModlets( resource ); | 
| 179 |                 } | 
| 180 |             } | 
| 181 |   | 
| 182 |             return resource; | 
| 183 |         } | 
| 184 |         catch ( final IOException e ) | 
| 185 |         { | 
| 186 |             this.getProject().log( Messages.getMessage( e ), Project.MSG_ERR ); | 
| 187 |             return null; | 
| 188 |         } | 
| 189 |         catch ( final JAXBException e ) | 
| 190 |         { | 
| 191 |             String message = Messages.getMessage( e ); | 
| 192 |             if ( message == null && e.getLinkedException() != null ) | 
| 193 |             { | 
| 194 |                 message = Messages.getMessage( e.getLinkedException() ); | 
| 195 |             } | 
| 196 |   | 
| 197 |             this.getProject().log( message, Project.MSG_ERR ); | 
| 198 |             return null; | 
| 199 |         } | 
| 200 |         catch ( final ModelException e ) | 
| 201 |         { | 
| 202 |             this.getProject().log( Messages.getMessage( e ), Project.MSG_ERR ); | 
| 203 |             return null; | 
| 204 |         } | 
| 205 |     } | 
| 206 |   | 
| 207 |     /** | 
| 208 |      * Gets all resources matching a given name. | 
| 209 |      * | 
| 210 |      * @param name The name of the resources to get. | 
| 211 |      * | 
| 212 |      * @return An enumeration of {@code URL} objects of found resources. | 
| 213 |      * | 
| 214 |      * @throws IOException if getting resources fails. | 
| 215 |      */ | 
| 216 |     @Override | 
| 217 |     public Enumeration<URL> findResources( final String name ) throws IOException | 
| 218 |     { | 
| 219 |         final Enumeration<URL> allResources = super.findResources( name ); | 
| 220 |         Enumeration<URL> enumeration = allResources; | 
| 221 |   | 
| 222 |         if ( this.getProviderResourceLocations().contains( name ) ) | 
| 223 |         { | 
| 224 |             enumeration = new Enumeration<URL>() | 
| 225 |             { | 
| 226 |   | 
| 227 |                 public boolean hasMoreElements() | 
| 228 |                 { | 
| 229 |                     return allResources.hasMoreElements(); | 
| 230 |                 } | 
| 231 |   | 
| 232 |                 public URL nextElement() | 
| 233 |                 { | 
| 234 |                     try | 
| 235 |                     { | 
| 236 |                         return filterProviders( allResources.nextElement() ); | 
| 237 |                     } | 
| 238 |                     catch ( final IOException e ) | 
| 239 |                     { | 
| 240 |                         getProject().log( Messages.getMessage( e ), Project.MSG_ERR ); | 
| 241 |                         return null; | 
| 242 |                     } | 
| 243 |                 } | 
| 244 |   | 
| 245 |             }; | 
| 246 |         } | 
| 247 |         else if ( this.getModletResourceLocations().contains( name ) ) | 
| 248 |         { | 
| 249 |             enumeration = new Enumeration<URL>() | 
| 250 |             { | 
| 251 |   | 
| 252 |                 public boolean hasMoreElements() | 
| 253 |                 { | 
| 254 |                     return allResources.hasMoreElements(); | 
| 255 |                 } | 
| 256 |   | 
| 257 |                 public URL nextElement() | 
| 258 |                 { | 
| 259 |                     try | 
| 260 |                     { | 
| 261 |                         return filterModlets( allResources.nextElement() ); | 
| 262 |                     } | 
| 263 |                     catch ( final IOException e ) | 
| 264 |                     { | 
| 265 |                         getProject().log( Messages.getMessage( e ), Project.MSG_ERR ); | 
| 266 |                         return null; | 
| 267 |                     } | 
| 268 |                     catch ( final JAXBException e ) | 
| 269 |                     { | 
| 270 |                         String message = Messages.getMessage( e ); | 
| 271 |                         if ( message == null && e.getLinkedException() != null ) | 
| 272 |                         { | 
| 273 |                             message = Messages.getMessage( e.getLinkedException() ); | 
| 274 |                         } | 
| 275 |   | 
| 276 |                         getProject().log( message, Project.MSG_ERR ); | 
| 277 |                         return null; | 
| 278 |                     } | 
| 279 |                     catch ( final ModelException e ) | 
| 280 |                     { | 
| 281 |                         getProject().log( Messages.getMessage( e ), Project.MSG_ERR ); | 
| 282 |                         return null; | 
| 283 |                     } | 
| 284 |                 } | 
| 285 |   | 
| 286 |             }; | 
| 287 |         } | 
| 288 |   | 
| 289 |         return enumeration; | 
| 290 |     } | 
| 291 |   | 
| 292 |     /** | 
| 293 |      * Gets a set of modlet resource locations to filter. | 
| 294 |      * <p>This accessor method returns a reference to the live set, not a snapshot. Therefore any modification you make | 
| 295 |      * to the returned set will be present inside the object. This is why there is no {@code set} method for the | 
| 296 |      * modlet resource locations property.</p> | 
| 297 |      * | 
| 298 |      * @return A set of modlet resource locations to filter. | 
| 299 |      */ | 
| 300 |     public final Set<String> getModletResourceLocations() | 
| 301 |     { | 
| 302 |         if ( this.modletResourceLocations == null ) | 
| 303 |         { | 
| 304 |             this.modletResourceLocations = new HashSet<String>(); | 
| 305 |         } | 
| 306 |   | 
| 307 |         return this.modletResourceLocations; | 
| 308 |     } | 
| 309 |   | 
| 310 |     /** | 
| 311 |      * Gets a set of provider resource locations to filter. | 
| 312 |      * <p>This accessor method returns a reference to the live set, not a snapshot. Therefore any modification you make | 
| 313 |      * to the returned set will be present inside the object. This is why there is no {@code set} method for the | 
| 314 |      * provider resource locations property.</p> | 
| 315 |      * | 
| 316 |      * @return A set of provider resource locations to filter. | 
| 317 |      */ | 
| 318 |     public final Set<String> getProviderResourceLocations() | 
| 319 |     { | 
| 320 |         if ( this.providerResourceLocations == null ) | 
| 321 |         { | 
| 322 |             this.providerResourceLocations = new HashSet<String>(); | 
| 323 |         } | 
| 324 |   | 
| 325 |         return this.providerResourceLocations; | 
| 326 |     } | 
| 327 |   | 
| 328 |     /** | 
| 329 |      * Gets a set of modlet names to exclude. | 
| 330 |      * <p>This accessor method returns a reference to the live set, not a snapshot. Therefore any modification you make | 
| 331 |      * to the returned set will be present inside the object. This is why there is no {@code set} method for the | 
| 332 |      * modlet excludes property.</p> | 
| 333 |      * | 
| 334 |      * @return A set of modlet names to exclude. | 
| 335 |      */ | 
| 336 |     public final Set<String> getModletExcludes() | 
| 337 |     { | 
| 338 |         if ( this.modletExcludes == null ) | 
| 339 |         { | 
| 340 |             this.modletExcludes = new HashSet<String>(); | 
| 341 |         } | 
| 342 |   | 
| 343 |         return this.modletExcludes; | 
| 344 |     } | 
| 345 |   | 
| 346 |     /** | 
| 347 |      * Gets a set of modlet names excluded by default. | 
| 348 |      * | 
| 349 |      * @return An unmodifiable set of modlet names excluded by default. | 
| 350 |      * | 
| 351 |      * @throws IOException if reading configuration resources fails. | 
| 352 |      */ | 
| 353 |     public static Set<String> getDefaultModletExcludes() throws IOException | 
| 354 |     { | 
| 355 |         return readDefaultExcludes( ABSOLUTE_RESOURCE_NAME_PREFIX + "DefaultModletExcludes" ); | 
| 356 |     } | 
| 357 |   | 
| 358 |     /** | 
| 359 |      * Gets a set of modlets excluded during resource loading. | 
| 360 |      * <p>This accessor method returns a reference to the live set, not a snapshot. Therefore any modification you make | 
| 361 |      * to the returned set will be present inside the object. This is why there is no {@code set} method for the | 
| 362 |      * excluded modlets property.</p> | 
| 363 |      * | 
| 364 |      * @return A set of modlets excluded during resource loading. | 
| 365 |      */ | 
| 366 |     public final Modlets getExcludedModlets() | 
| 367 |     { | 
| 368 |         if ( this.excludedModlets == null ) | 
| 369 |         { | 
| 370 |             this.excludedModlets = new Modlets(); | 
| 371 |         } | 
| 372 |   | 
| 373 |         return this.excludedModlets; | 
| 374 |     } | 
| 375 |   | 
| 376 |     /** | 
| 377 |      * Gets a set of provider names to exclude. | 
| 378 |      * <p>This accessor method returns a reference to the live set, not a snapshot. Therefore any modification you make | 
| 379 |      * to the returned set will be present inside the object. This is why there is no {@code set} method for the | 
| 380 |      * provider excludes property.</p> | 
| 381 |      * | 
| 382 |      * @return A set of providers to exclude. | 
| 383 |      */ | 
| 384 |     public final Set<String> getProviderExcludes() | 
| 385 |     { | 
| 386 |         if ( this.providerExcludes == null ) | 
| 387 |         { | 
| 388 |             this.providerExcludes = new HashSet<String>(); | 
| 389 |         } | 
| 390 |   | 
| 391 |         return this.providerExcludes; | 
| 392 |     } | 
| 393 |   | 
| 394 |     /** | 
| 395 |      * Gets a set of provider names excluded by default. | 
| 396 |      * | 
| 397 |      * @return An unmodifiable set of provider names excluded by default. | 
| 398 |      * | 
| 399 |      * @throws IOException if reading configuration resources fails. | 
| 400 |      */ | 
| 401 |     public static Set<String> getDefaultProviderExcludes() throws IOException | 
| 402 |     { | 
| 403 |         return readDefaultExcludes( ABSOLUTE_RESOURCE_NAME_PREFIX + "DefaultProviderExcludes" ); | 
| 404 |     } | 
| 405 |   | 
| 406 |     /** | 
| 407 |      * Gets a set of providers excluded during resource loading. | 
| 408 |      * <p>This accessor method returns a reference to the live set, not a snapshot. Therefore any modification you make | 
| 409 |      * to the returned set will be present inside the object. This is why there is no {@code set} method for the | 
| 410 |      * excluded providers property.</p> | 
| 411 |      * | 
| 412 |      * @return A set of providers excluded during resource loading. | 
| 413 |      */ | 
| 414 |     public final Set<String> getExcludedProviders() | 
| 415 |     { | 
| 416 |         if ( this.excludedProviders == null ) | 
| 417 |         { | 
| 418 |             this.excludedProviders = new HashSet<String>(); | 
| 419 |         } | 
| 420 |   | 
| 421 |         return this.excludedProviders; | 
| 422 |     } | 
| 423 |   | 
| 424 |     /** | 
| 425 |      * Gets a set of service class names to exclude. | 
| 426 |      * <p>This accessor method returns a reference to the live set, not a snapshot. Therefore any modification you make | 
| 427 |      * to the returned set will be present inside the object. This is why there is no {@code set} method for the | 
| 428 |      * service excludes property.</p> | 
| 429 |      * | 
| 430 |      * @return A set of service class names to exclude. | 
| 431 |      */ | 
| 432 |     public final Set<String> getServiceExcludes() | 
| 433 |     { | 
| 434 |         if ( this.serviceExcludes == null ) | 
| 435 |         { | 
| 436 |             this.serviceExcludes = new HashSet<String>(); | 
| 437 |         } | 
| 438 |   | 
| 439 |         return this.serviceExcludes; | 
| 440 |     } | 
| 441 |   | 
| 442 |     /** | 
| 443 |      * Gets a set of service class names excluded by default. | 
| 444 |      * | 
| 445 |      * @return An unmodifiable set of service class names excluded by default. | 
| 446 |      * | 
| 447 |      * @throws IOException if reading configuration resources fails. | 
| 448 |      */ | 
| 449 |     public static Set<String> getDefaultServiceExcludes() throws IOException | 
| 450 |     { | 
| 451 |         return readDefaultExcludes( ABSOLUTE_RESOURCE_NAME_PREFIX + "DefaultServiceExcludes" ); | 
| 452 |     } | 
| 453 |   | 
| 454 |     /** | 
| 455 |      * Gets a set of services excluded during resource loading. | 
| 456 |      * <p>This accessor method returns a reference to the live set, not a snapshot. Therefore any modification you make | 
| 457 |      * to the returned set will be present inside the object. This is why there is no {@code set} method for the | 
| 458 |      * excluded services property.</p> | 
| 459 |      * | 
| 460 |      * @return Services excluded during resource loading. | 
| 461 |      */ | 
| 462 |     public final Services getExcludedServices() | 
| 463 |     { | 
| 464 |         if ( this.excludedServices == null ) | 
| 465 |         { | 
| 466 |             this.excludedServices = new Services(); | 
| 467 |         } | 
| 468 |   | 
| 469 |         return this.excludedServices; | 
| 470 |     } | 
| 471 |   | 
| 472 |     /** | 
| 473 |      * Gets a set of schema public identifiers to exclude. | 
| 474 |      * <p>This accessor method returns a reference to the live set, not a snapshot. Therefore any modification you make | 
| 475 |      * to the returned set will be present inside the object. This is why there is no {@code set} method for the | 
| 476 |      * schema excludes property.</p> | 
| 477 |      * | 
| 478 |      * @return A set of schema public identifiers to exclude. | 
| 479 |      */ | 
| 480 |     public final Set<String> getSchemaExcludes() | 
| 481 |     { | 
| 482 |         if ( this.schemaExcludes == null ) | 
| 483 |         { | 
| 484 |             this.schemaExcludes = new HashSet<String>(); | 
| 485 |         } | 
| 486 |   | 
| 487 |         return this.schemaExcludes; | 
| 488 |     } | 
| 489 |   | 
| 490 |     /** | 
| 491 |      * Gets a set of schema public identifiers excluded by default. | 
| 492 |      * | 
| 493 |      * @return An unmodifiable set of schema public identifiers excluded by default. | 
| 494 |      * | 
| 495 |      * @throws IOException if reading configuration resources fails. | 
| 496 |      */ | 
| 497 |     public static Set<String> getDefaultSchemaExcludes() throws IOException | 
| 498 |     { | 
| 499 |         return readDefaultExcludes( ABSOLUTE_RESOURCE_NAME_PREFIX + "DefaultSchemaExcludes" ); | 
| 500 |     } | 
| 501 |   | 
| 502 |     /** | 
| 503 |      * Gets a set of schemas excluded during resource loading. | 
| 504 |      * <p>This accessor method returns a reference to the live set, not a snapshot. Therefore any modification you make | 
| 505 |      * to the returned set will be present inside the object. This is why there is no {@code set} method for the | 
| 506 |      * excluded schemas property.</p> | 
| 507 |      * | 
| 508 |      * @return Schemas excluded during resource loading. | 
| 509 |      */ | 
| 510 |     public final Schemas getExcludedSchemas() | 
| 511 |     { | 
| 512 |         if ( this.excludedSchemas == null ) | 
| 513 |         { | 
| 514 |             this.excludedSchemas = new Schemas(); | 
| 515 |         } | 
| 516 |   | 
| 517 |         return this.excludedSchemas; | 
| 518 |     } | 
| 519 |   | 
| 520 |     /** | 
| 521 |      * Closes the class loader. | 
| 522 |      * @throws IOException if closing the class loader fails. | 
| 523 |      */ | 
| 524 |     @Override | 
| 525 |     @IgnoreJRERequirement | 
| 526 |     public void close() throws IOException | 
| 527 |     { | 
| 528 |         for ( final Iterator<File> it = this.temporaryResources.iterator(); it.hasNext(); ) | 
| 529 |         { | 
| 530 |             final File temporaryResource = it.next(); | 
| 531 |   | 
| 532 |             if ( temporaryResource.exists() && temporaryResource.delete() ) | 
| 533 |             { | 
| 534 |                 it.remove(); | 
| 535 |             } | 
| 536 |         } | 
| 537 |   | 
| 538 |         if ( Closeable.class.isAssignableFrom( ProjectClassLoader.class ) ) | 
| 539 |         { | 
| 540 |             super.close(); | 
| 541 |         } | 
| 542 |     } | 
| 543 |   | 
| 544 |     /** | 
| 545 |      * Removes temporary resources. | 
| 546 |      * @throws Throwable if finalization fails. | 
| 547 |      */ | 
| 548 |     @Override | 
| 549 |     protected void finalize() throws Throwable | 
| 550 |     { | 
| 551 |         for ( final Iterator<File> it = this.temporaryResources.iterator(); it.hasNext(); ) | 
| 552 |         { | 
| 553 |             final File temporaryResource = it.next(); | 
| 554 |   | 
| 555 |             if ( temporaryResource.exists() && !temporaryResource.delete() ) | 
| 556 |             { | 
| 557 |                 temporaryResource.deleteOnExit(); | 
| 558 |             } | 
| 559 |   | 
| 560 |             it.remove(); | 
| 561 |         } | 
| 562 |   | 
| 563 |         super.finalize(); | 
| 564 |     } | 
| 565 |   | 
| 566 |     private URL filterProviders( final URL resource ) throws IOException | 
| 567 |     { | 
| 568 |         InputStream in = null; | 
| 569 |         boolean suppressExceptionOnClose = true; | 
| 570 |   | 
| 571 |         try | 
| 572 |         { | 
| 573 |             URL filteredResource = resource; | 
| 574 |             in = resource.openStream(); | 
| 575 |             final List<String> lines = IOUtils.readLines( in, "UTF-8" ); | 
| 576 |             final List<String> filteredLines = new ArrayList<String>( lines.size() ); | 
| 577 |   | 
| 578 |             for ( String line : lines ) | 
| 579 |             { | 
| 580 |                 if ( !this.getProviderExcludes().contains( line.trim() ) ) | 
| 581 |                 { | 
| 582 |                     filteredLines.add( line.trim() ); | 
| 583 |                 } | 
| 584 |                 else | 
| 585 |                 { | 
| 586 |                     this.getExcludedProviders().add( line.trim() ); | 
| 587 |                     this.getProject().log( Messages.getMessage( "providerExclusion", resource.toExternalForm(), | 
| 588 |                                                                 line.trim() ), Project.MSG_DEBUG ); | 
| 589 |   | 
| 590 |                 } | 
| 591 |             } | 
| 592 |   | 
| 593 |             if ( lines.size() != filteredLines.size() ) | 
| 594 |             { | 
| 595 |                 OutputStream out = null; | 
| 596 |                 final File tmpResource = File.createTempFile( this.getClass().getName(), ".rsrc" ); | 
| 597 |                 this.temporaryResources.add( tmpResource ); | 
| 598 |   | 
| 599 |                 try | 
| 600 |                 { | 
| 601 |                     out = new FileOutputStream( tmpResource ); | 
| 602 |                     IOUtils.writeLines( filteredLines, System.getProperty( "line.separator", "\n" ), out, "UTF-8" ); | 
| 603 |                     suppressExceptionOnClose = false; | 
| 604 |                 } | 
| 605 |                 finally | 
| 606 |                 { | 
| 607 |                     try | 
| 608 |                     { | 
| 609 |                         if ( out != null ) | 
| 610 |                         { | 
| 611 |                             out.close(); | 
| 612 |                         } | 
| 613 |   | 
| 614 |                         suppressExceptionOnClose = true; | 
| 615 |                     } | 
| 616 |                     catch ( final IOException e ) | 
| 617 |                     { | 
| 618 |                         if ( suppressExceptionOnClose ) | 
| 619 |                         { | 
| 620 |                             this.project.log( Messages.getMessage( e ), e, Project.MSG_ERR ); | 
| 621 |                         } | 
| 622 |                         else | 
| 623 |                         { | 
| 624 |                             throw e; | 
| 625 |                         } | 
| 626 |                     } | 
| 627 |                 } | 
| 628 |   | 
| 629 |                 filteredResource = tmpResource.toURI().toURL(); | 
| 630 |             } | 
| 631 |   | 
| 632 |             suppressExceptionOnClose = false; | 
| 633 |             return filteredResource; | 
| 634 |         } | 
| 635 |         finally | 
| 636 |         { | 
| 637 |             try | 
| 638 |             { | 
| 639 |                 if ( in != null ) | 
| 640 |                 { | 
| 641 |                     in.close(); | 
| 642 |                 } | 
| 643 |             } | 
| 644 |             catch ( final IOException e ) | 
| 645 |             { | 
| 646 |                 if ( suppressExceptionOnClose ) | 
| 647 |                 { | 
| 648 |                     this.project.log( Messages.getMessage( e ), e, Project.MSG_ERR ); | 
| 649 |                 } | 
| 650 |                 else | 
| 651 |                 { | 
| 652 |                     throw e; | 
| 653 |                 } | 
| 654 |             } | 
| 655 |         } | 
| 656 |     } | 
| 657 |   | 
| 658 |     private URL filterModlets( final URL resource ) throws ModelException, IOException, JAXBException | 
| 659 |     { | 
| 660 |         InputStream in = null; | 
| 661 |         boolean suppressExceptionOnClose = true; | 
| 662 |   | 
| 663 |         try | 
| 664 |         { | 
| 665 |             URL filteredResource = resource; | 
| 666 |             final ModelContext modelContext = ModelContextFactory.newInstance().newModelContext(); | 
| 667 |             in = resource.openStream(); | 
| 668 |             final JAXBElement<?> e = | 
| 669 |                 (JAXBElement<?>) modelContext.createUnmarshaller( ModletObject.MODEL_PUBLIC_ID ).unmarshal( in ); | 
| 670 |   | 
| 671 |             final Object o = e.getValue(); | 
| 672 |             Modlets modlets = null; | 
| 673 |             boolean filtered = false; | 
| 674 |   | 
| 675 |             if ( o instanceof Modlets ) | 
| 676 |             { | 
| 677 |                 modlets = (Modlets) o; | 
| 678 |             } | 
| 679 |             else if ( o instanceof Modlet ) | 
| 680 |             { | 
| 681 |                 modlets = new Modlets(); | 
| 682 |                 modlets.getModlet().add( (Modlet) o ); | 
| 683 |             } | 
| 684 |   | 
| 685 |             if ( modlets != null ) | 
| 686 |             { | 
| 687 |                 for ( final Iterator<Modlet> it = modlets.getModlet().iterator(); it.hasNext(); ) | 
| 688 |                 { | 
| 689 |                     final Modlet m = it.next(); | 
| 690 |   | 
| 691 |                     if ( this.getModletExcludes().contains( m.getName() ) ) | 
| 692 |                     { | 
| 693 |                         it.remove(); | 
| 694 |                         filtered = true; | 
| 695 |                         this.addExcludedModlet( m ); | 
| 696 |                         this.getProject().log( Messages.getMessage( "modletExclusion", resource.toExternalForm(), | 
| 697 |                                                                     m.getName() ), Project.MSG_DEBUG ); | 
| 698 |   | 
| 699 |                         continue; | 
| 700 |                     } | 
| 701 |   | 
| 702 |                     if ( this.filterModlet( m, resource.toExternalForm() ) ) | 
| 703 |                     { | 
| 704 |                         filtered = true; | 
| 705 |                     } | 
| 706 |                 } | 
| 707 |   | 
| 708 |                 if ( filtered ) | 
| 709 |                 { | 
| 710 |                     final File tmpResource = File.createTempFile( this.getClass().getName(), ".rsrc" ); | 
| 711 |                     this.temporaryResources.add( tmpResource ); | 
| 712 |                     modelContext.createMarshaller( ModletObject.MODEL_PUBLIC_ID ).marshal( | 
| 713 |                         new ObjectFactory().createModlets( modlets ), tmpResource ); | 
| 714 |   | 
| 715 |                     filteredResource = tmpResource.toURI().toURL(); | 
| 716 |                 } | 
| 717 |             } | 
| 718 |   | 
| 719 |             suppressExceptionOnClose = false; | 
| 720 |             return filteredResource; | 
| 721 |         } | 
| 722 |         finally | 
| 723 |         { | 
| 724 |             try | 
| 725 |             { | 
| 726 |                 if ( in != null ) | 
| 727 |                 { | 
| 728 |                     in.close(); | 
| 729 |                 } | 
| 730 |             } | 
| 731 |             catch ( final IOException e ) | 
| 732 |             { | 
| 733 |                 if ( suppressExceptionOnClose ) | 
| 734 |                 { | 
| 735 |                     this.project.log( Messages.getMessage( e ), e, Project.MSG_ERR ); | 
| 736 |                 } | 
| 737 |                 else | 
| 738 |                 { | 
| 739 |                     throw e; | 
| 740 |                 } | 
| 741 |             } | 
| 742 |         } | 
| 743 |     } | 
| 744 |   | 
| 745 |     private boolean filterModlet( final Modlet modlet, final String resourceInfo ) | 
| 746 |     { | 
| 747 |         boolean filteredSchemas = false; | 
| 748 |         boolean filteredServices = false; | 
| 749 |   | 
| 750 |         if ( modlet.getSchemas() != null ) | 
| 751 |         { | 
| 752 |             final Schemas schemas = new Schemas(); | 
| 753 |   | 
| 754 |             for ( Schema s : modlet.getSchemas().getSchema() ) | 
| 755 |             { | 
| 756 |                 if ( !this.getSchemaExcludes().contains( s.getPublicId() ) ) | 
| 757 |                 { | 
| 758 |                     schemas.getSchema().add( s ); | 
| 759 |                 } | 
| 760 |                 else | 
| 761 |                 { | 
| 762 |                     this.getProject().log( Messages.getMessage( "schemaExclusion", resourceInfo, s.getPublicId() ), | 
| 763 |                                            Project.MSG_DEBUG ); | 
| 764 |   | 
| 765 |                     this.addExcludedSchema( s ); | 
| 766 |                     filteredSchemas = true; | 
| 767 |                 } | 
| 768 |             } | 
| 769 |   | 
| 770 |             if ( filteredSchemas ) | 
| 771 |             { | 
| 772 |                 modlet.setSchemas( schemas ); | 
| 773 |             } | 
| 774 |         } | 
| 775 |   | 
| 776 |         if ( modlet.getServices() != null ) | 
| 777 |         { | 
| 778 |             final Services services = new Services(); | 
| 779 |   | 
| 780 |             for ( Service s : modlet.getServices().getService() ) | 
| 781 |             { | 
| 782 |                 if ( !this.getServiceExcludes().contains( s.getClazz() ) ) | 
| 783 |                 { | 
| 784 |                     services.getService().add( s ); | 
| 785 |                 } | 
| 786 |                 else | 
| 787 |                 { | 
| 788 |                     this.getProject().log( Messages.getMessage( "serviceExclusion", resourceInfo, s.getClazz() ), | 
| 789 |                                            Project.MSG_DEBUG ); | 
| 790 |   | 
| 791 |                     this.addExcludedService( s ); | 
| 792 |                     filteredServices = true; | 
| 793 |                 } | 
| 794 |             } | 
| 795 |   | 
| 796 |             if ( filteredServices ) | 
| 797 |             { | 
| 798 |                 modlet.setServices( services ); | 
| 799 |             } | 
| 800 |         } | 
| 801 |   | 
| 802 |         return filteredSchemas || filteredServices; | 
| 803 |     } | 
| 804 |   | 
| 805 |     private void addExcludedModlet( final Modlet modlet ) | 
| 806 |     { | 
| 807 |         try | 
| 808 |         { | 
| 809 |             final Modlet m = this.getExcludedModlets().getModlet( modlet.getName() ); | 
| 810 |   | 
| 811 |             if ( m != null ) | 
| 812 |             { | 
| 813 |                 if ( m.getVersion() != null && modlet.getVersion() != null | 
| 814 |                      && VersionParser.compare( m.getVersion(), modlet.getVersion() ) < 0 ) | 
| 815 |                 { | 
| 816 |                     this.getExcludedModlets().getModlet().remove( m ); | 
| 817 |                     this.getExcludedModlets().getModlet().add( modlet ); | 
| 818 |                 } | 
| 819 |             } | 
| 820 |             else | 
| 821 |             { | 
| 822 |                 this.getExcludedModlets().getModlet().add( modlet ); | 
| 823 |             } | 
| 824 |         } | 
| 825 |         catch ( final ParseException e ) | 
| 826 |         { | 
| 827 |             this.getProject().log( Messages.getMessage( e ), e, Project.MSG_WARN ); | 
| 828 |         } | 
| 829 |         catch ( final TokenMgrError e ) | 
| 830 |         { | 
| 831 |             this.getProject().log( Messages.getMessage( e ), e, Project.MSG_WARN ); | 
| 832 |         } | 
| 833 |     } | 
| 834 |   | 
| 835 |     private void addExcludedSchema( final Schema schema ) | 
| 836 |     { | 
| 837 |         if ( this.getExcludedSchemas().getSchemaBySystemId( schema.getSystemId() ) == null ) | 
| 838 |         { | 
| 839 |             this.getExcludedSchemas().getSchema().add( schema ); | 
| 840 |         } | 
| 841 |     } | 
| 842 |   | 
| 843 |     private void addExcludedService( final Service service ) | 
| 844 |     { | 
| 845 |         for ( int i = 0, s0 = this.getExcludedServices().getService().size(); i < s0; i++ ) | 
| 846 |         { | 
| 847 |             final Service s = this.getExcludedServices().getService().get( i ); | 
| 848 |   | 
| 849 |             if ( s.getIdentifier().equals( service.getIdentifier() ) && s.getClazz().equals( service.getClazz() ) ) | 
| 850 |             { | 
| 851 |                 return; | 
| 852 |             } | 
| 853 |         } | 
| 854 |   | 
| 855 |         this.getExcludedServices().getService().add( service ); | 
| 856 |     } | 
| 857 |   | 
| 858 |     private static Set<String> readDefaultExcludes( final String location ) throws IOException | 
| 859 |     { | 
| 860 |         InputStream resource = null; | 
| 861 |         boolean suppressExceptionOnClose = true; | 
| 862 |         Set<String> defaultExcludes = null; | 
| 863 |   | 
| 864 |         try | 
| 865 |         { | 
| 866 |             resource = ProjectClassLoader.class.getResourceAsStream( location ); | 
| 867 |   | 
| 868 |             if ( resource != null ) | 
| 869 |             { | 
| 870 |                 final List<String> lines = IOUtils.readLines( resource, "UTF-8" ); | 
| 871 |                 defaultExcludes = new HashSet<String>( lines.size() ); | 
| 872 |   | 
| 873 |                 for ( String line : lines ) | 
| 874 |                 { | 
| 875 |                     final String trimmed = line.trim(); | 
| 876 |   | 
| 877 |                     if ( trimmed.contains( "#" ) || StringUtils.isEmpty( trimmed ) ) | 
| 878 |                     { | 
| 879 |                         continue; | 
| 880 |                     } | 
| 881 |   | 
| 882 |                     defaultExcludes.add( trimmed ); | 
| 883 |                 } | 
| 884 |             } | 
| 885 |   | 
| 886 |             suppressExceptionOnClose = false; | 
| 887 |             return defaultExcludes != null | 
| 888 |                    ? Collections.unmodifiableSet( defaultExcludes ) : Collections.<String>emptySet(); | 
| 889 |   | 
| 890 |         } | 
| 891 |         finally | 
| 892 |         { | 
| 893 |             try | 
| 894 |             { | 
| 895 |                 if ( resource != null ) | 
| 896 |                 { | 
| 897 |                     resource.close(); | 
| 898 |                 } | 
| 899 |             } | 
| 900 |             catch ( final IOException e ) | 
| 901 |             { | 
| 902 |                 if ( !suppressExceptionOnClose ) | 
| 903 |                 { | 
| 904 |                     throw e; | 
| 905 |                 } | 
| 906 |             } | 
| 907 |         } | 
| 908 |     } | 
| 909 |   | 
| 910 | } |