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