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