001/* 002 * Copyright (C) 2005 Christian Schulte <cs@schulte.it> 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without 006 * modification, are permitted provided that the following conditions 007 * are met: 008 * 009 * o Redistributions of source code must retain the above copyright 010 * notice, this list of conditions and the following disclaimer. 011 * 012 * o Redistributions in binary form must reproduce the above copyright 013 * notice, this list of conditions and the following disclaimer in 014 * the documentation and/or other materials provided with the 015 * distribution. 016 * 017 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 018 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 019 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 020 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, 021 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 022 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 023 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 024 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 025 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 026 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 027 * 028 * $JOMC: ProjectClassLoader.java 5303 2016-08-30 02:31:20Z schulte $ 029 * 030 */ 031package org.jomc.ant; 032 033import java.io.BufferedReader; 034import java.io.BufferedWriter; 035import java.io.Closeable; 036import java.io.File; 037import java.io.FileOutputStream; 038import java.io.IOException; 039import java.io.InputStream; 040import java.io.InputStreamReader; 041import java.io.OutputStream; 042import java.io.OutputStreamWriter; 043import java.net.MalformedURLException; 044import java.net.URI; 045import java.net.URISyntaxException; 046import java.net.URL; 047import java.net.URLClassLoader; 048import java.util.Collections; 049import java.util.Enumeration; 050import java.util.HashSet; 051import java.util.Iterator; 052import java.util.LinkedList; 053import java.util.List; 054import java.util.Set; 055import javax.xml.bind.JAXBElement; 056import javax.xml.bind.JAXBException; 057import org.apache.tools.ant.Project; 058import org.apache.tools.ant.types.Path; 059import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement; 060import org.jomc.modlet.ModelContext; 061import org.jomc.modlet.ModelContextFactory; 062import org.jomc.modlet.ModelException; 063import org.jomc.modlet.Modlet; 064import org.jomc.modlet.ModletObject; 065import org.jomc.modlet.Modlets; 066import org.jomc.modlet.ObjectFactory; 067import org.jomc.modlet.Schema; 068import org.jomc.modlet.Schemas; 069import org.jomc.modlet.Service; 070import org.jomc.modlet.Services; 071import org.jomc.util.ParseException; 072import org.jomc.util.TokenMgrError; 073import org.jomc.util.VersionParser; 074 075/** 076 * Class loader supporting JOMC resources backed by a project. 077 * 078 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a> 079 * @version $JOMC: ProjectClassLoader.java 5303 2016-08-30 02:31:20Z schulte $ 080 */ 081public class ProjectClassLoader extends URLClassLoader 082{ 083 084 /** 085 * Constant to prefix relative resource names with. 086 */ 087 private static final String ABSOLUTE_RESOURCE_NAME_PREFIX = 088 "/" + ProjectClassLoader.class.getPackage().getName().replace( '.', '/' ) + "/"; 089 090 /** 091 * Empty URL array. 092 */ 093 private static final URL[] NO_URLS = 094 { 095 }; 096 097 /** 098 * Set of modlet names to exclude. 099 */ 100 private Set<String> modletExcludes; 101 102 /** 103 * Excluded modlets. 104 */ 105 private final Modlets excludedModlets = new Modlets(); 106 107 /** 108 * Set of service class names to exclude. 109 */ 110 private Set<String> serviceExcludes; 111 112 /** 113 * Excluded services. 114 */ 115 private final Services excludedServices = new Services(); 116 117 /** 118 * Set of schema public ids to exclude. 119 */ 120 private Set<String> schemaExcludes; 121 122 /** 123 * Excluded schemas. 124 */ 125 private final Schemas excludedSchemas = new Schemas(); 126 127 /** 128 * Set of providers to exclude. 129 */ 130 private Set<String> providerExcludes; 131 132 /** 133 * Set of excluded providers. 134 */ 135 private final Set<String> excludedProviders = Collections.synchronizedSet( new HashSet<String>( 128 ) ); 136 137 /** 138 * The project the class loader is associated with. 139 */ 140 private final Project project; 141 142 /** 143 * Set of modlet resource locations to filter. 144 */ 145 private Set<String> modletResourceLocations; 146 147 /** 148 * Set of provider resource locations to filter. 149 */ 150 private Set<String> providerResourceLocations; 151 152 /** 153 * Set of temporary resources. 154 */ 155 private final Set<File> temporaryResources = Collections.synchronizedSet( new HashSet<File>( 128 ) ); 156 157 /** 158 * Creates a new {@code ProjectClassLoader} instance taking a project and a class path. 159 * 160 * @param project The project to which this class loader is to belong. 161 * @param classpath The class path to use for loading. 162 * 163 * @throws MalformedURLException if {@code classpath} contains unsupported elements. 164 * @throws IOException if reading configuration resources fails. 165 */ 166 public ProjectClassLoader( final Project project, final Path classpath ) throws MalformedURLException, IOException 167 { 168 super( NO_URLS, ProjectClassLoader.class.getClassLoader() ); 169 170 for ( final String name : classpath.list() ) 171 { 172 final File resolved = project.resolveFile( name ); 173 this.addURL( resolved.toURI().toURL() ); 174 } 175 176 this.project = project; 177 } 178 179 /** 180 * Gets the project of the instance. 181 * 182 * @return The project of the instance. 183 */ 184 public final Project getProject() 185 { 186 return this.project; 187 } 188 189 /** 190 * Finds a resource with a given name. 191 * 192 * @param name The name of the resource to search. 193 * 194 * @return An {@code URL} object for reading the resource or {@code null}, if no resource matching {@code name} is 195 * found. 196 */ 197 @Override 198 public URL findResource( final String name ) //JDK: As of JDK 23 throws IOException 199 { 200 try 201 { 202 URL resource = super.findResource( name ); 203 204 if ( resource != null ) 205 { 206 if ( this.getProviderResourceLocations().contains( name ) ) 207 { 208 resource = this.filterProviders( resource ); 209 } 210 else if ( this.getModletResourceLocations().contains( name ) ) 211 { 212 resource = this.filterModlets( resource ); 213 } 214 } 215 216 return resource; 217 } 218 catch ( final IOException e ) 219 { 220 this.getProject().log( Messages.getMessage( e ), Project.MSG_ERR ); 221 return null; 222 } 223 catch ( final JAXBException e ) 224 { 225 String message = Messages.getMessage( e ); 226 if ( message == null && e.getLinkedException() != null ) 227 { 228 message = Messages.getMessage( e.getLinkedException() ); 229 } 230 231 this.getProject().log( message, Project.MSG_ERR ); 232 return null; 233 } 234 catch ( final ModelException e ) 235 { 236 this.getProject().log( Messages.getMessage( e ), Project.MSG_ERR ); 237 return null; 238 } 239 } 240 241 /** 242 * Finds all resources matching a given name. 243 * 244 * @param name The name of the resources to search. 245 * 246 * @return An enumeration of {@code URL} objects of resources matching name. 247 * 248 * @throws IOException if getting resources fails. 249 */ 250 @Override 251 public Enumeration<URL> findResources( final String name ) throws IOException 252 { 253 try 254 { 255 Enumeration<URL> resources = super.findResources( name ); 256 257 if ( this.getProviderResourceLocations().contains( name ) 258 || this.getModletResourceLocations().contains( name ) ) 259 { 260 final List<URI> filtered = new LinkedList<URI>(); 261 262 while ( resources.hasMoreElements() ) 263 { 264 final URL resource = resources.nextElement(); 265 266 if ( this.getProviderResourceLocations().contains( name ) ) 267 { 268 filtered.add( this.filterProviders( resource ).toURI() ); 269 } 270 else if ( this.getModletResourceLocations().contains( name ) ) 271 { 272 filtered.add( this.filterModlets( resource ).toURI() ); 273 } 274 } 275 276 final Iterator<URI> it = filtered.iterator(); 277 278 resources = new Enumeration<URL>() 279 { 280 281 public boolean hasMoreElements() 282 { 283 return it.hasNext(); 284 } 285 286 public URL nextElement() 287 { 288 try 289 { 290 return it.next().toURL(); 291 } 292 catch ( final MalformedURLException e ) 293 { 294 throw new AssertionError( e ); 295 } 296 } 297 298 }; 299 } 300 301 return resources; 302 } 303 catch ( final URISyntaxException e ) 304 { 305 // JDK: As of JDK 6, new IOException( message, e ); 306 throw (IOException) new IOException( Messages.getMessage( e ) ).initCause( e ); 307 } 308 catch ( final JAXBException e ) 309 { 310 String message = Messages.getMessage( e ); 311 if ( message == null && e.getLinkedException() != null ) 312 { 313 message = Messages.getMessage( e.getLinkedException() ); 314 } 315 316 // JDK: As of JDK 6, new IOException( message, e ); 317 throw (IOException) new IOException( message ).initCause( e ); 318 } 319 catch ( final ModelException e ) 320 { 321 // JDK: As of JDK 6, new IOException( message, e ); 322 throw (IOException) new IOException( Messages.getMessage( e ) ).initCause( e ); 323 } 324 } 325 326 /** 327 * Gets a set of modlet resource locations to filter. 328 * <p> 329 * This accessor method returns a reference to the live set, not a snapshot. Therefore any modification you make 330 * to the returned set will be present inside the object. This is why there is no {@code set} method for the 331 * modlet resource locations property. 332 * </p> 333 * 334 * @return A set of modlet resource locations to filter. 335 */ 336 public final Set<String> getModletResourceLocations() 337 { 338 if ( this.modletResourceLocations == null ) 339 { 340 this.modletResourceLocations = new HashSet<String>( 128 ); 341 } 342 343 return this.modletResourceLocations; 344 } 345 346 /** 347 * Gets a set of provider resource locations to filter. 348 * <p> 349 * This accessor method returns a reference to the live set, not a snapshot. Therefore any modification you make 350 * to the returned set will be present inside the object. This is why there is no {@code set} method for the 351 * provider resource locations property. 352 * </p> 353 * 354 * @return A set of provider resource locations to filter. 355 */ 356 public final Set<String> getProviderResourceLocations() 357 { 358 if ( this.providerResourceLocations == null ) 359 { 360 this.providerResourceLocations = new HashSet<String>( 128 ); 361 } 362 363 return this.providerResourceLocations; 364 } 365 366 /** 367 * Gets a set of modlet names to exclude. 368 * <p> 369 * This accessor method returns a reference to the live set, not a snapshot. Therefore any modification you make 370 * to the returned set will be present inside the object. This is why there is no {@code set} method for the 371 * modlet excludes property. 372 * </p> 373 * 374 * @return A set of modlet names to exclude. 375 */ 376 public final Set<String> getModletExcludes() 377 { 378 if ( this.modletExcludes == null ) 379 { 380 this.modletExcludes = new HashSet<String>( 128 ); 381 } 382 383 return this.modletExcludes; 384 } 385 386 /** 387 * Gets a set of modlet names excluded by default. 388 * 389 * @return An unmodifiable set of modlet names excluded by default. 390 * 391 * @throws IOException if reading configuration resources fails. 392 */ 393 public static Set<String> getDefaultModletExcludes() throws IOException 394 { 395 return readDefaultExcludes( ABSOLUTE_RESOURCE_NAME_PREFIX + "DefaultModletExcludes" ); 396 } 397 398 /** 399 * Gets a set of modlets excluded during resource loading. 400 * <p> 401 * This accessor method returns a reference to the live set, not a snapshot. Therefore any modification you make 402 * to the returned set will be present inside the object. This is why there is no {@code set} method for the 403 * excluded modlets property. 404 * </p> 405 * 406 * @return A set of modlets excluded during resource loading. 407 */ 408 public final Modlets getExcludedModlets() 409 { 410 return this.excludedModlets; 411 } 412 413 /** 414 * Gets a set of provider names to exclude. 415 * <p> 416 * This accessor method returns a reference to the live set, not a snapshot. Therefore any modification you make 417 * to the returned set will be present inside the object. This is why there is no {@code set} method for the 418 * provider excludes property. 419 * </p> 420 * 421 * @return A set of providers to exclude. 422 */ 423 public final Set<String> getProviderExcludes() 424 { 425 if ( this.providerExcludes == null ) 426 { 427 this.providerExcludes = new HashSet<String>( 128 ); 428 } 429 430 return this.providerExcludes; 431 } 432 433 /** 434 * Gets a set of provider names excluded by default. 435 * 436 * @return An unmodifiable set of provider names excluded by default. 437 * 438 * @throws IOException if reading configuration resources fails. 439 */ 440 public static Set<String> getDefaultProviderExcludes() throws IOException 441 { 442 return readDefaultExcludes( ABSOLUTE_RESOURCE_NAME_PREFIX + "DefaultProviderExcludes" ); 443 } 444 445 /** 446 * Gets a set of providers excluded during resource loading. 447 * <p> 448 * This accessor method returns a reference to the live set, not a snapshot. Therefore any modification you make 449 * to the returned set will be present inside the object. This is why there is no {@code set} method for the 450 * excluded providers property. 451 * </p> 452 * 453 * @return A set of providers excluded during resource loading. 454 */ 455 public final Set<String> getExcludedProviders() 456 { 457 return this.excludedProviders; 458 } 459 460 /** 461 * Gets a set of service class names to exclude. 462 * <p> 463 * This accessor method returns a reference to the live set, not a snapshot. Therefore any modification you make 464 * to the returned set will be present inside the object. This is why there is no {@code set} method for the 465 * service excludes property. 466 * </p> 467 * 468 * @return A set of service class names to exclude. 469 */ 470 public final Set<String> getServiceExcludes() 471 { 472 if ( this.serviceExcludes == null ) 473 { 474 this.serviceExcludes = new HashSet<String>( 128 ); 475 } 476 477 return this.serviceExcludes; 478 } 479 480 /** 481 * Gets a set of service class names excluded by default. 482 * 483 * @return An unmodifiable set of service class names excluded by default. 484 * 485 * @throws IOException if reading configuration resources fails. 486 */ 487 public static Set<String> getDefaultServiceExcludes() throws IOException 488 { 489 return readDefaultExcludes( ABSOLUTE_RESOURCE_NAME_PREFIX + "DefaultServiceExcludes" ); 490 } 491 492 /** 493 * Gets a set of services excluded during resource loading. 494 * <p> 495 * This accessor method returns a reference to the live set, not a snapshot. Therefore any modification you make 496 * to the returned set will be present inside the object. This is why there is no {@code set} method for the 497 * excluded services property. 498 * </p> 499 * 500 * @return Services excluded during resource loading. 501 */ 502 public final Services getExcludedServices() 503 { 504 return this.excludedServices; 505 } 506 507 /** 508 * Gets a set of schema public identifiers to exclude. 509 * <p> 510 * This accessor method returns a reference to the live set, not a snapshot. Therefore any modification you make 511 * to the returned set will be present inside the object. This is why there is no {@code set} method for the 512 * schema excludes property. 513 * </p> 514 * 515 * @return A set of schema public identifiers to exclude. 516 */ 517 public final Set<String> getSchemaExcludes() 518 { 519 if ( this.schemaExcludes == null ) 520 { 521 this.schemaExcludes = new HashSet<String>( 128 ); 522 } 523 524 return this.schemaExcludes; 525 } 526 527 /** 528 * Gets a set of schema public identifiers excluded by default. 529 * 530 * @return An unmodifiable set of schema public identifiers excluded by default. 531 * 532 * @throws IOException if reading configuration resources fails. 533 */ 534 public static Set<String> getDefaultSchemaExcludes() throws IOException 535 { 536 return readDefaultExcludes( ABSOLUTE_RESOURCE_NAME_PREFIX + "DefaultSchemaExcludes" ); 537 } 538 539 /** 540 * Gets a set of schemas excluded during resource loading. 541 * <p> 542 * This accessor method returns a reference to the live set, not a snapshot. Therefore any modification you make 543 * to the returned set will be present inside the object. This is why there is no {@code set} method for the 544 * excluded schemas property. 545 * </p> 546 * 547 * @return Schemas excluded during resource loading. 548 */ 549 public final Schemas getExcludedSchemas() 550 { 551 return this.excludedSchemas; 552 } 553 554 /** 555 * Closes the class loader. 556 * 557 * @throws IOException if closing the class loader fails. 558 */ 559 @Override 560 @IgnoreJRERequirement 561 public void close() throws IOException 562 { 563 for ( final Iterator<File> it = this.temporaryResources.iterator(); it.hasNext(); ) 564 { 565 final File temporaryResource = it.next(); 566 567 if ( temporaryResource.exists() && temporaryResource.delete() ) 568 { 569 it.remove(); 570 } 571 } 572 573 if ( Closeable.class.isAssignableFrom( ProjectClassLoader.class ) ) 574 { 575 super.close(); 576 } 577 } 578 579 /** 580 * Removes temporary resources. 581 * 582 * @throws Throwable if finalization fails. 583 */ 584 @Override 585 protected void finalize() throws Throwable 586 { 587 for ( final Iterator<File> it = this.temporaryResources.iterator(); it.hasNext(); ) 588 { 589 final File temporaryResource = it.next(); 590 591 if ( temporaryResource.exists() && !temporaryResource.delete() ) 592 { 593 temporaryResource.deleteOnExit(); 594 } 595 596 it.remove(); 597 } 598 599 super.finalize(); 600 } 601 602 private URL filterProviders( final URL resource ) throws IOException 603 { 604 InputStream in = null; 605 BufferedReader reader = null; 606 OutputStream out = null; 607 BufferedWriter writer = null; 608 URL filteredResource = resource; 609 final List<String> filteredLines = new LinkedList<String>(); 610 611 try 612 { 613 boolean filtered = false; 614 in = resource.openStream(); 615 reader = new BufferedReader( new InputStreamReader( in, "UTF-8" ) ); 616 617 for ( String line = reader.readLine(); line != null; line = reader.readLine() ) 618 { 619 String normalized = line.trim(); 620 621 if ( !this.getProviderExcludes().contains( normalized ) ) 622 { 623 filteredLines.add( normalized ); 624 } 625 else 626 { 627 filtered = true; 628 this.getExcludedProviders().add( normalized ); 629 this.getProject().log( Messages.getMessage( "providerExclusion", resource.toExternalForm(), 630 line.trim() ), Project.MSG_DEBUG ); 631 632 } 633 } 634 635 reader.close(); 636 reader = null; 637 in = null; 638 639 if ( filtered ) 640 { 641 final File tmpResource = File.createTempFile( this.getClass().getName(), ".rsrc" ); 642 this.temporaryResources.add( tmpResource ); 643 644 out = new FileOutputStream( tmpResource ); 645 writer = new BufferedWriter( new OutputStreamWriter( out, "UTF-8" ) ); 646 647 for ( final String line : filteredLines ) 648 { 649 writer.write( line ); 650 writer.newLine(); 651 } 652 653 writer.close(); 654 writer = null; 655 out = null; 656 657 filteredResource = tmpResource.toURI().toURL(); 658 } 659 660 return filteredResource; 661 } 662 finally 663 { 664 try 665 { 666 if ( reader != null ) 667 { 668 reader.close(); 669 } 670 } 671 catch ( final IOException e ) 672 { 673 this.project.log( Messages.getMessage( e ), e, Project.MSG_ERR ); 674 } 675 finally 676 { 677 try 678 { 679 if ( in != null ) 680 { 681 in.close(); 682 } 683 } 684 catch ( final IOException e ) 685 { 686 this.project.log( Messages.getMessage( e ), e, Project.MSG_ERR ); 687 } 688 finally 689 { 690 try 691 { 692 if ( writer != null ) 693 { 694 writer.close(); 695 } 696 } 697 catch ( final IOException e ) 698 { 699 this.project.log( Messages.getMessage( e ), e, Project.MSG_ERR ); 700 } 701 finally 702 { 703 try 704 { 705 if ( out != null ) 706 { 707 out.close(); 708 } 709 } 710 catch ( final IOException e ) 711 { 712 this.project.log( Messages.getMessage( e ), e, Project.MSG_ERR ); 713 } 714 } 715 } 716 } 717 } 718 } 719 720 private URL filterModlets( final URL resource ) throws ModelException, IOException, JAXBException 721 { 722 InputStream in = null; 723 724 try 725 { 726 URL filteredResource = resource; 727 in = resource.openStream(); 728 729 final ModelContext modelContext = ModelContextFactory.newInstance().newModelContext(); 730 final JAXBElement<?> e = 731 (JAXBElement<?>) modelContext.createUnmarshaller( ModletObject.MODEL_PUBLIC_ID ).unmarshal( in ); 732 733 in.close(); 734 in = null; 735 736 final Object o = e.getValue(); 737 Modlets modlets = null; 738 boolean filtered = false; 739 740 if ( o instanceof Modlets ) 741 { 742 modlets = (Modlets) o; 743 } 744 else if ( o instanceof Modlet ) 745 { 746 modlets = new Modlets(); 747 modlets.getModlet().add( (Modlet) o ); 748 } 749 750 if ( modlets != null ) 751 { 752 for ( final Iterator<Modlet> it = modlets.getModlet().iterator(); it.hasNext(); ) 753 { 754 final Modlet m = it.next(); 755 756 if ( this.getModletExcludes().contains( m.getName() ) ) 757 { 758 it.remove(); 759 filtered = true; 760 this.addExcludedModlet( m ); 761 this.getProject().log( Messages.getMessage( "modletExclusion", resource.toExternalForm(), 762 m.getName() ), Project.MSG_DEBUG ); 763 764 continue; 765 } 766 767 if ( this.filterModlet( m, resource.toExternalForm() ) ) 768 { 769 filtered = true; 770 } 771 } 772 773 if ( filtered ) 774 { 775 final File tmpResource = File.createTempFile( this.getClass().getName(), ".rsrc" ); 776 this.temporaryResources.add( tmpResource ); 777 modelContext.createMarshaller( ModletObject.MODEL_PUBLIC_ID ).marshal( 778 new ObjectFactory().createModlets( modlets ), tmpResource ); 779 780 filteredResource = tmpResource.toURI().toURL(); 781 } 782 } 783 784 return filteredResource; 785 } 786 finally 787 { 788 try 789 { 790 if ( in != null ) 791 { 792 in.close(); 793 } 794 } 795 catch ( final IOException e ) 796 { 797 this.project.log( Messages.getMessage( e ), e, Project.MSG_ERR ); 798 } 799 } 800 } 801 802 private boolean filterModlet( final Modlet modlet, final String resourceInfo ) 803 { 804 boolean filteredSchemas = false; 805 boolean filteredServices = false; 806 807 if ( modlet.getSchemas() != null ) 808 { 809 final Schemas schemas = new Schemas(); 810 811 for ( final Schema s : modlet.getSchemas().getSchema() ) 812 { 813 if ( !this.getSchemaExcludes().contains( s.getPublicId() ) ) 814 { 815 schemas.getSchema().add( s ); 816 } 817 else 818 { 819 this.getProject().log( Messages.getMessage( "schemaExclusion", resourceInfo, s.getPublicId() ), 820 Project.MSG_DEBUG ); 821 822 this.addExcludedSchema( s ); 823 filteredSchemas = true; 824 } 825 } 826 827 if ( filteredSchemas ) 828 { 829 modlet.setSchemas( schemas ); 830 } 831 } 832 833 if ( modlet.getServices() != null ) 834 { 835 final Services services = new Services(); 836 837 for ( final Service s : modlet.getServices().getService() ) 838 { 839 if ( !this.getServiceExcludes().contains( s.getClazz() ) ) 840 { 841 services.getService().add( s ); 842 } 843 else 844 { 845 this.getProject().log( Messages.getMessage( "serviceExclusion", resourceInfo, s.getClazz() ), 846 Project.MSG_DEBUG ); 847 848 this.addExcludedService( s ); 849 filteredServices = true; 850 } 851 } 852 853 if ( filteredServices ) 854 { 855 modlet.setServices( services ); 856 } 857 } 858 859 return filteredSchemas || filteredServices; 860 } 861 862 private synchronized void addExcludedModlet( final Modlet modlet ) 863 { 864 try 865 { 866 final Modlet m = this.getExcludedModlets().getModlet( modlet.getName() ); 867 868 if ( m != null ) 869 { 870 if ( m.getVersion() != null && modlet.getVersion() != null 871 && VersionParser.compare( m.getVersion(), modlet.getVersion() ) < 0 ) 872 { 873 this.getExcludedModlets().getModlet().remove( m ); 874 this.getExcludedModlets().getModlet().add( modlet ); 875 } 876 } 877 else 878 { 879 this.getExcludedModlets().getModlet().add( modlet ); 880 } 881 } 882 catch ( final ParseException e ) 883 { 884 this.getProject().log( Messages.getMessage( e ), e, Project.MSG_WARN ); 885 } 886 catch ( final TokenMgrError e ) 887 { 888 this.getProject().log( Messages.getMessage( e ), e, Project.MSG_WARN ); 889 } 890 } 891 892 private synchronized void addExcludedSchema( final Schema schema ) 893 { 894 if ( this.getExcludedSchemas().getSchemaBySystemId( schema.getSystemId() ) == null ) 895 { 896 this.getExcludedSchemas().getSchema().add( schema ); 897 } 898 } 899 900 private synchronized void addExcludedService( final Service service ) 901 { 902 for ( int i = 0, s0 = this.getExcludedServices().getService().size(); i < s0; i++ ) 903 { 904 final Service s = this.getExcludedServices().getService().get( i ); 905 906 if ( s.getIdentifier().equals( service.getIdentifier() ) && s.getClazz().equals( service.getClazz() ) ) 907 { 908 return; 909 } 910 } 911 912 this.getExcludedServices().getService().add( service ); 913 } 914 915 private static Set<String> readDefaultExcludes( final String location ) throws IOException 916 { 917 InputStream in = null; 918 BufferedReader reader = null; 919 final Set<String> defaultExcludes = new HashSet<String>(); 920 921 try 922 { 923 in = ProjectClassLoader.class.getResourceAsStream( location ); 924 assert in != null : "Expected resource '" + location + "' not found."; 925 reader = new BufferedReader( new InputStreamReader( in, "UTF-8" ) ); 926 927 for ( String line = reader.readLine(); line != null; line = reader.readLine() ) 928 { 929 final String normalized = line.trim(); 930 931 if ( normalized.length() > 0 && !normalized.contains( "#" ) ) 932 { 933 defaultExcludes.add( line.trim() ); 934 } 935 } 936 937 reader.close(); 938 reader = null; 939 in = null; 940 941 return Collections.unmodifiableSet( defaultExcludes ); 942 } 943 finally 944 { 945 try 946 { 947 if ( reader != null ) 948 { 949 reader.close(); 950 } 951 } 952 catch ( final IOException e ) 953 { 954 // Suppressed. 955 } 956 finally 957 { 958 try 959 { 960 if ( in != null ) 961 { 962 in.close(); 963 } 964 } 965 catch ( final IOException e ) 966 { 967 // Suppressed. 968 } 969 } 970 } 971 } 972 973}