1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  package org.jomc.ant;
32  
33  import java.io.BufferedReader;
34  import java.io.BufferedWriter;
35  import java.io.Closeable;
36  import java.io.File;
37  import java.io.FileOutputStream;
38  import java.io.IOException;
39  import java.io.InputStream;
40  import java.io.InputStreamReader;
41  import java.io.OutputStream;
42  import java.io.OutputStreamWriter;
43  import java.net.MalformedURLException;
44  import java.net.URI;
45  import java.net.URISyntaxException;
46  import java.net.URL;
47  import java.net.URLClassLoader;
48  import java.util.Collections;
49  import java.util.Enumeration;
50  import java.util.HashSet;
51  import java.util.Iterator;
52  import java.util.LinkedList;
53  import java.util.List;
54  import java.util.Set;
55  import javax.xml.bind.JAXBElement;
56  import javax.xml.bind.JAXBException;
57  import org.apache.tools.ant.Project;
58  import org.apache.tools.ant.types.Path;
59  import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement;
60  import org.jomc.modlet.ModelContext;
61  import org.jomc.modlet.ModelContextFactory;
62  import org.jomc.modlet.ModelException;
63  import org.jomc.modlet.Modlet;
64  import org.jomc.modlet.ModletObject;
65  import org.jomc.modlet.Modlets;
66  import org.jomc.modlet.ObjectFactory;
67  import org.jomc.modlet.Schema;
68  import org.jomc.modlet.Schemas;
69  import org.jomc.modlet.Service;
70  import org.jomc.modlet.Services;
71  import org.jomc.util.ParseException;
72  import org.jomc.util.TokenMgrError;
73  import org.jomc.util.VersionParser;
74  
75  
76  
77  
78  
79  
80  
81  public class ProjectClassLoader extends URLClassLoader
82  {
83  
84      
85  
86  
87      private static final String ABSOLUTE_RESOURCE_NAME_PREFIX =
88          "/" + ProjectClassLoader.class.getPackage().getName().replace( '.', '/' ) + "/";
89  
90      
91  
92  
93      private static final URL[] NO_URLS =
94      {
95      };
96  
97      
98  
99  
100     private Set<String> modletExcludes;
101 
102     
103 
104 
105     private final Modlets excludedModlets = new Modlets();
106 
107     
108 
109 
110     private Set<String> serviceExcludes;
111 
112     
113 
114 
115     private final Services excludedServices = new Services();
116 
117     
118 
119 
120     private Set<String> schemaExcludes;
121 
122     
123 
124 
125     private final Schemas excludedSchemas = new Schemas();
126 
127     
128 
129 
130     private Set<String> providerExcludes;
131 
132     
133 
134 
135     private final Set<String> excludedProviders = Collections.synchronizedSet( new HashSet<String>( 128 ) );
136 
137     
138 
139 
140     private final Project project;
141 
142     
143 
144 
145     private Set<String> modletResourceLocations;
146 
147     
148 
149 
150     private Set<String> providerResourceLocations;
151 
152     
153 
154 
155     private final Set<File> temporaryResources = Collections.synchronizedSet( new HashSet<File>( 128 ) );
156 
157     
158 
159 
160 
161 
162 
163 
164 
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 
181 
182 
183 
184     public final Project getProject()
185     {
186         return this.project;
187     }
188 
189     
190 
191 
192 
193 
194 
195 
196 
197     @Override
198     public URL findResource( final String name ) 
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 
243 
244 
245 
246 
247 
248 
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             
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             
317             throw (IOException) new IOException( message ).initCause( e );
318         }
319         catch ( final ModelException e )
320         {
321             
322             throw (IOException) new IOException( Messages.getMessage( e ) ).initCause( e );
323         }
324     }
325 
326     
327 
328 
329 
330 
331 
332 
333 
334 
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 
348 
349 
350 
351 
352 
353 
354 
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 
368 
369 
370 
371 
372 
373 
374 
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 
388 
389 
390 
391 
392 
393     public static Set<String> getDefaultModletExcludes() throws IOException
394     {
395         return readDefaultExcludes( ABSOLUTE_RESOURCE_NAME_PREFIX + "DefaultModletExcludes" );
396     }
397 
398     
399 
400 
401 
402 
403 
404 
405 
406 
407 
408     public final Modlets getExcludedModlets()
409     {
410         return this.excludedModlets;
411     }
412 
413     
414 
415 
416 
417 
418 
419 
420 
421 
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 
435 
436 
437 
438 
439 
440     public static Set<String> getDefaultProviderExcludes() throws IOException
441     {
442         return readDefaultExcludes( ABSOLUTE_RESOURCE_NAME_PREFIX + "DefaultProviderExcludes" );
443     }
444 
445     
446 
447 
448 
449 
450 
451 
452 
453 
454 
455     public final Set<String> getExcludedProviders()
456     {
457         return this.excludedProviders;
458     }
459 
460     
461 
462 
463 
464 
465 
466 
467 
468 
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 
482 
483 
484 
485 
486 
487     public static Set<String> getDefaultServiceExcludes() throws IOException
488     {
489         return readDefaultExcludes( ABSOLUTE_RESOURCE_NAME_PREFIX + "DefaultServiceExcludes" );
490     }
491 
492     
493 
494 
495 
496 
497 
498 
499 
500 
501 
502     public final Services getExcludedServices()
503     {
504         return this.excludedServices;
505     }
506 
507     
508 
509 
510 
511 
512 
513 
514 
515 
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 
529 
530 
531 
532 
533 
534     public static Set<String> getDefaultSchemaExcludes() throws IOException
535     {
536         return readDefaultExcludes( ABSOLUTE_RESOURCE_NAME_PREFIX + "DefaultSchemaExcludes" );
537     }
538 
539     
540 
541 
542 
543 
544 
545 
546 
547 
548 
549     public final Schemas getExcludedSchemas()
550     {
551         return this.excludedSchemas;
552     }
553 
554     
555 
556 
557 
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 
581 
582 
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                 
955             }
956             finally
957             {
958                 try
959                 {
960                     if ( in != null )
961                     {
962                         in.close();
963                     }
964                 }
965                 catch ( final IOException e )
966                 {
967                     
968                 }
969             }
970         }
971     }
972 
973 }