View Javadoc

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 4256 2012-02-13 06:32:10Z schulte2005 $
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.lang.reflect.InvocationTargetException;
40  import java.net.MalformedURLException;
41  import java.net.URL;
42  import java.net.URLClassLoader;
43  import java.util.ArrayList;
44  import java.util.Collections;
45  import java.util.Enumeration;
46  import java.util.HashSet;
47  import java.util.Iterator;
48  import java.util.List;
49  import java.util.Set;
50  import javax.xml.bind.JAXBElement;
51  import javax.xml.bind.JAXBException;
52  import org.apache.commons.io.IOUtils;
53  import org.apache.commons.lang.StringUtils;
54  import org.apache.tools.ant.Project;
55  import org.apache.tools.ant.types.Path;
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:schulte2005@users.sourceforge.net">Christian Schulte</a>
75   * @version $JOMC: ProjectClassLoader.java 4256 2012-02-13 06:32:10Z schulte2005 $
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     public void close() throws IOException
525     {
526         for ( final Iterator<File> it = this.temporaryResources.iterator(); it.hasNext(); )
527         {
528             final File temporaryResource = it.next();
529 
530             if ( temporaryResource.exists() && temporaryResource.delete() )
531             {
532                 it.remove();
533             }
534         }
535 
536         if ( Closeable.class.isAssignableFrom( ProjectClassLoader.class ) )
537         { // JDK: As of JDK 7, super.close();
538             this.jdk7Close();
539         }
540     }
541 
542     /**
543      * Removes temporary resources.
544      * @throws Throwable if finalization fails.
545      */
546     @Override
547     protected void finalize() throws Throwable
548     {
549         for ( final Iterator<File> it = this.temporaryResources.iterator(); it.hasNext(); )
550         {
551             final File temporaryResource = it.next();
552 
553             if ( temporaryResource.exists() && !temporaryResource.delete() )
554             {
555                 temporaryResource.deleteOnExit();
556             }
557 
558             it.remove();
559         }
560 
561         super.finalize();
562     }
563 
564     private URL filterProviders( final URL resource ) throws IOException
565     {
566         InputStream in = null;
567         boolean suppressExceptionOnClose = true;
568 
569         try
570         {
571             URL filteredResource = resource;
572             in = resource.openStream();
573             final List<String> lines = IOUtils.readLines( in, "UTF-8" );
574             final List<String> filteredLines = new ArrayList<String>( lines.size() );
575 
576             for ( String line : lines )
577             {
578                 if ( !this.getProviderExcludes().contains( line.trim() ) )
579                 {
580                     filteredLines.add( line.trim() );
581                 }
582                 else
583                 {
584                     this.getExcludedProviders().add( line.trim() );
585                     this.getProject().log( Messages.getMessage( "providerExclusion", resource.toExternalForm(),
586                                                                 line.trim() ), Project.MSG_DEBUG );
587 
588                 }
589             }
590 
591             if ( lines.size() != filteredLines.size() )
592             {
593                 OutputStream out = null;
594                 final File tmpResource = File.createTempFile( this.getClass().getName(), ".rsrc" );
595                 this.temporaryResources.add( tmpResource );
596 
597                 try
598                 {
599                     out = new FileOutputStream( tmpResource );
600                     IOUtils.writeLines( filteredLines, System.getProperty( "line.separator", "\n" ), out, "UTF-8" );
601                     suppressExceptionOnClose = false;
602                 }
603                 finally
604                 {
605                     try
606                     {
607                         if ( out != null )
608                         {
609                             out.close();
610                         }
611 
612                         suppressExceptionOnClose = true;
613                     }
614                     catch ( final IOException e )
615                     {
616                         if ( suppressExceptionOnClose )
617                         {
618                             this.project.log( Messages.getMessage( e ), e, Project.MSG_ERR );
619                         }
620                         else
621                         {
622                             throw e;
623                         }
624                     }
625                 }
626 
627                 filteredResource = tmpResource.toURI().toURL();
628             }
629 
630             suppressExceptionOnClose = false;
631             return filteredResource;
632         }
633         finally
634         {
635             try
636             {
637                 if ( in != null )
638                 {
639                     in.close();
640                 }
641             }
642             catch ( final IOException e )
643             {
644                 if ( suppressExceptionOnClose )
645                 {
646                     this.project.log( Messages.getMessage( e ), e, Project.MSG_ERR );
647                 }
648                 else
649                 {
650                     throw e;
651                 }
652             }
653         }
654     }
655 
656     private URL filterModlets( final URL resource ) throws ModelException, IOException, JAXBException
657     {
658         InputStream in = null;
659         boolean suppressExceptionOnClose = true;
660 
661         try
662         {
663             URL filteredResource = resource;
664             final ModelContext modelContext = ModelContextFactory.newInstance().newModelContext();
665             in = resource.openStream();
666             final JAXBElement<?> e =
667                 (JAXBElement<?>) modelContext.createUnmarshaller( ModletObject.MODEL_PUBLIC_ID ).unmarshal( in );
668 
669             final Object o = e.getValue();
670             Modlets modlets = null;
671             boolean filtered = false;
672 
673             if ( o instanceof Modlets )
674             {
675                 modlets = (Modlets) o;
676             }
677             else if ( o instanceof Modlet )
678             {
679                 modlets = new Modlets();
680                 modlets.getModlet().add( (Modlet) o );
681             }
682 
683             if ( modlets != null )
684             {
685                 for ( final Iterator<Modlet> it = modlets.getModlet().iterator(); it.hasNext(); )
686                 {
687                     final Modlet m = it.next();
688 
689                     if ( this.getModletExcludes().contains( m.getName() ) )
690                     {
691                         it.remove();
692                         filtered = true;
693                         this.addExcludedModlet( m );
694                         this.getProject().log( Messages.getMessage( "modletExclusion", resource.toExternalForm(),
695                                                                     m.getName() ), Project.MSG_DEBUG );
696 
697                         continue;
698                     }
699 
700                     if ( this.filterModlet( m, resource.toExternalForm() ) )
701                     {
702                         filtered = true;
703                     }
704                 }
705 
706                 if ( filtered )
707                 {
708                     final File tmpResource = File.createTempFile( this.getClass().getName(), ".rsrc" );
709                     this.temporaryResources.add( tmpResource );
710                     modelContext.createMarshaller( ModletObject.MODEL_PUBLIC_ID ).marshal(
711                         new ObjectFactory().createModlets( modlets ), tmpResource );
712 
713                     filteredResource = tmpResource.toURI().toURL();
714                 }
715             }
716 
717             suppressExceptionOnClose = false;
718             return filteredResource;
719         }
720         finally
721         {
722             try
723             {
724                 if ( in != null )
725                 {
726                     in.close();
727                 }
728             }
729             catch ( final IOException e )
730             {
731                 if ( suppressExceptionOnClose )
732                 {
733                     this.project.log( Messages.getMessage( e ), e, Project.MSG_ERR );
734                 }
735                 else
736                 {
737                     throw e;
738                 }
739             }
740         }
741     }
742 
743     private boolean filterModlet( final Modlet modlet, final String resourceInfo )
744     {
745         boolean filteredSchemas = false;
746         boolean filteredServices = false;
747 
748         if ( modlet.getSchemas() != null )
749         {
750             final Schemas schemas = new Schemas();
751 
752             for ( Schema s : modlet.getSchemas().getSchema() )
753             {
754                 if ( !this.getSchemaExcludes().contains( s.getPublicId() ) )
755                 {
756                     schemas.getSchema().add( s );
757                 }
758                 else
759                 {
760                     this.getProject().log( Messages.getMessage( "schemaExclusion", resourceInfo, s.getPublicId() ),
761                                            Project.MSG_DEBUG );
762 
763                     this.addExcludedSchema( s );
764                     filteredSchemas = true;
765                 }
766             }
767 
768             if ( filteredSchemas )
769             {
770                 modlet.setSchemas( schemas );
771             }
772         }
773 
774         if ( modlet.getServices() != null )
775         {
776             final Services services = new Services();
777 
778             for ( Service s : modlet.getServices().getService() )
779             {
780                 if ( !this.getServiceExcludes().contains( s.getClazz() ) )
781                 {
782                     services.getService().add( s );
783                 }
784                 else
785                 {
786                     this.getProject().log( Messages.getMessage( "serviceExclusion", resourceInfo, s.getClazz() ),
787                                            Project.MSG_DEBUG );
788 
789                     this.addExcludedService( s );
790                     filteredServices = true;
791                 }
792             }
793 
794             if ( filteredServices )
795             {
796                 modlet.setServices( services );
797             }
798         }
799 
800         return filteredSchemas || filteredServices;
801     }
802 
803     private void addExcludedModlet( final Modlet modlet )
804     {
805         try
806         {
807             final Modlet m = this.getExcludedModlets().getModlet( modlet.getName() );
808 
809             if ( m != null )
810             {
811                 if ( m.getVersion() != null && modlet.getVersion() != null
812                      && VersionParser.compare( m.getVersion(), modlet.getVersion() ) < 0 )
813                 {
814                     this.getExcludedModlets().getModlet().remove( m );
815                     this.getExcludedModlets().getModlet().add( modlet );
816                 }
817             }
818             else
819             {
820                 this.getExcludedModlets().getModlet().add( modlet );
821             }
822         }
823         catch ( final ParseException e )
824         {
825             this.getProject().log( Messages.getMessage( e ), e, Project.MSG_WARN );
826         }
827         catch ( final TokenMgrError e )
828         {
829             this.getProject().log( Messages.getMessage( e ), e, Project.MSG_WARN );
830         }
831     }
832 
833     private void addExcludedSchema( final Schema schema )
834     {
835         if ( this.getExcludedSchemas().getSchemaBySystemId( schema.getSystemId() ) == null )
836         {
837             this.getExcludedSchemas().getSchema().add( schema );
838         }
839     }
840 
841     private void addExcludedService( final Service service )
842     {
843         for ( int i = 0, s0 = this.getExcludedServices().getService().size(); i < s0; i++ )
844         {
845             final Service s = this.getExcludedServices().getService().get( i );
846 
847             if ( s.getIdentifier().equals( service.getIdentifier() ) && s.getClazz().equals( service.getClazz() ) )
848             {
849                 return;
850             }
851         }
852 
853         this.getExcludedServices().getService().add( service );
854     }
855 
856     private void jdk7Close()
857     {
858         try
859         {
860             URLClassLoader.class.getMethod( "close" ).invoke( this );
861         }
862         catch ( final NoSuchMethodException e )
863         {
864             this.project.log( Messages.getMessage( e ), e, Project.MSG_DEBUG );
865         }
866         catch ( final IllegalAccessException e )
867         {
868             this.project.log( Messages.getMessage( e ), e, Project.MSG_DEBUG );
869         }
870         catch ( final InvocationTargetException e )
871         {
872             this.project.log( Messages.getMessage( e ), e, Project.MSG_DEBUG );
873         }
874     }
875 
876     private static Set<String> readDefaultExcludes( final String location ) throws IOException
877     {
878         InputStream resource = null;
879         boolean suppressExceptionOnClose = true;
880         Set<String> defaultExcludes = null;
881 
882         try
883         {
884             resource = ProjectClassLoader.class.getResourceAsStream( location );
885 
886             if ( resource != null )
887             {
888                 final List<String> lines = IOUtils.readLines( resource, "UTF-8" );
889                 defaultExcludes = new HashSet<String>( lines.size() );
890 
891                 for ( String line : lines )
892                 {
893                     final String trimmed = line.trim();
894 
895                     if ( trimmed.contains( "#" ) || StringUtils.isEmpty( trimmed ) )
896                     {
897                         continue;
898                     }
899 
900                     defaultExcludes.add( trimmed );
901                 }
902             }
903 
904             suppressExceptionOnClose = false;
905             return defaultExcludes != null
906                    ? Collections.unmodifiableSet( defaultExcludes ) : Collections.<String>emptySet();
907 
908         }
909         finally
910         {
911             try
912             {
913                 if ( resource != null )
914                 {
915                     resource.close();
916                 }
917             }
918             catch ( final IOException e )
919             {
920                 if ( !suppressExceptionOnClose )
921                 {
922                     throw e;
923                 }
924             }
925         }
926     }
927 
928 }