1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.eclipse.jetty.webapp;
15
16 import java.io.File;
17 import java.io.IOException;
18 import java.net.MalformedURLException;
19 import java.net.URL;
20 import java.security.PermissionCollection;
21 import java.util.ArrayList;
22 import java.util.Collections;
23 import java.util.EventListener;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27
28 import javax.servlet.http.HttpSessionActivationListener;
29 import javax.servlet.http.HttpSessionAttributeListener;
30 import javax.servlet.http.HttpSessionBindingListener;
31 import javax.servlet.http.HttpSessionListener;
32
33 import org.eclipse.jetty.security.SecurityHandler;
34 import org.eclipse.jetty.server.Connector;
35 import org.eclipse.jetty.server.HandlerContainer;
36 import org.eclipse.jetty.server.Server;
37 import org.eclipse.jetty.server.handler.ContextHandler;
38 import org.eclipse.jetty.server.handler.ErrorHandler;
39 import org.eclipse.jetty.server.session.SessionHandler;
40 import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
41 import org.eclipse.jetty.servlet.ServletContextHandler;
42 import org.eclipse.jetty.servlet.ServletHandler;
43 import org.eclipse.jetty.util.LazyList;
44 import org.eclipse.jetty.util.Loader;
45 import org.eclipse.jetty.util.MultiException;
46 import org.eclipse.jetty.util.StringUtil;
47 import org.eclipse.jetty.util.URIUtil;
48 import org.eclipse.jetty.util.log.Log;
49 import org.eclipse.jetty.util.resource.Resource;
50 import org.eclipse.jetty.util.resource.ResourceCollection;
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65 public class WebAppContext extends ServletContextHandler implements WebAppClassLoader.Context
66 {
67 public static final String TEMPDIR = "javax.servlet.context.tempdir";
68 public static final String BASETEMPDIR = "org.eclipse.jetty.webapp.basetempdir";
69 public final static String WEB_DEFAULTS_XML="org/eclipse/jetty/webapp/webdefault.xml";
70 public final static String ERROR_PAGE="org.eclipse.jetty.server.error_page";
71 public final static String SERVER_CONFIG = "org.eclipse.jetty.webapp.configuration";
72 public final static String SERVER_SYS_CLASSES = "org.eclipse.jetty.webapp.systemClasses";
73 public final static String SERVER_SRV_CLASSES = "org.eclipse.jetty.webapp.serverClasses";
74
75 private static String[] __dftConfigurationClasses =
76 {
77 "org.eclipse.jetty.webapp.WebInfConfiguration",
78 "org.eclipse.jetty.webapp.WebXmlConfiguration",
79 "org.eclipse.jetty.webapp.MetaInfConfiguration",
80 "org.eclipse.jetty.webapp.FragmentConfiguration",
81 "org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
82 "org.eclipse.jetty.webapp.TagLibConfiguration"
83 } ;
84
85
86
87
88 public final static String[] __dftSystemClasses =
89 {
90 "java.",
91 "javax.",
92 "org.xml.",
93 "org.w3c.",
94 "org.apache.commons.logging.",
95 "org.eclipse.jetty.continuation.",
96 "org.eclipse.jetty.jndi.",
97 "org.eclipse.jetty.plus.jaas.",
98 "org.eclipse.jetty.websocket.",
99 "org.eclipse.jetty.servlet.DefaultServlet"
100 } ;
101
102
103
104
105
106 public final static String[] __dftServerClasses =
107 {
108 "-org.eclipse.jetty.continuation.",
109 "-org.eclipse.jetty.jndi.",
110 "-org.eclipse.jetty.plus.jaas.",
111 "-org.eclipse.jetty.websocket.",
112 "-org.eclipse.jetty.servlet.DefaultServlet",
113 "org.eclipse.jetty."
114 } ;
115
116 private String[] _configurationClasses = __dftConfigurationClasses;
117 private ClasspathPattern _systemClasses = null;
118 private ClasspathPattern _serverClasses = null;
119
120 private Configuration[] _configurations;
121 private String _defaultsDescriptor=WEB_DEFAULTS_XML;
122 private String _descriptor=null;
123 private final List<String> _overrideDescriptors = new ArrayList<String>();
124 private boolean _distributable=false;
125 private boolean _extractWAR=true;
126 private boolean _copyDir=false;
127 private boolean _copyWebInf=true;
128 private boolean _logUrlOnStart =false;
129 private boolean _parentLoaderPriority= Boolean.getBoolean("org.eclipse.jetty.server.webapp.parentLoaderPriority");
130 private PermissionCollection _permissions;
131
132 private File _tmpDir;
133 private String _war;
134 private String _extraClasspath;
135 private Throwable _unavailableException;
136
137 private Map _resourceAliases;
138 private boolean _ownClassLoader=false;
139 private boolean _configurationDiscovered=true;
140 private boolean _configurationClassesSet=false;
141 private boolean _configurationsSet=false;
142 private boolean _allowDuplicateFragmentNames = false;
143
144
145 private MetaData _metadata=new MetaData();
146
147 public static WebAppContext getCurrentWebAppContext()
148 {
149 ContextHandler.Context context=ContextHandler.getCurrentContext();
150 if (context!=null)
151 {
152 ContextHandler handler = context.getContextHandler();
153 if (handler instanceof WebAppContext)
154 return (WebAppContext)handler;
155 }
156 return null;
157 }
158
159
160 public WebAppContext()
161 {
162 super(SESSIONS|SECURITY);
163 _scontext=new Context();
164 setErrorHandler(new ErrorPageErrorHandler());
165 }
166
167
168
169
170
171
172 public WebAppContext(String webApp,String contextPath)
173 {
174 super(null,contextPath,SESSIONS|SECURITY);
175 _scontext=new Context();
176 setContextPath(contextPath);
177 setWar(webApp);
178 setErrorHandler(new ErrorPageErrorHandler());
179 }
180
181
182
183
184
185
186
187 public WebAppContext(HandlerContainer parent, String webApp, String contextPath)
188 {
189 super(parent,contextPath,SESSIONS|SECURITY);
190 _scontext=new Context();
191 setWar(webApp);
192 setErrorHandler(new ErrorPageErrorHandler());
193 }
194
195
196
197
198
199
200
201
202
203
204
205 public WebAppContext(SessionHandler sessionHandler, SecurityHandler securityHandler, ServletHandler servletHandler, ErrorHandler errorHandler) {
206 super(null, sessionHandler, securityHandler, servletHandler, errorHandler);
207 _scontext = new Context();
208 setErrorHandler(errorHandler != null ? errorHandler : new ErrorPageErrorHandler());
209 }
210
211
212
213
214
215 @Override
216 public void setDisplayName(String servletContextName)
217 {
218 super.setDisplayName(servletContextName);
219 ClassLoader cl = getClassLoader();
220 if (cl!=null && cl instanceof WebAppClassLoader && servletContextName!=null)
221 ((WebAppClassLoader)cl).setName(servletContextName);
222 }
223
224
225
226
227
228 public Throwable getUnavailableException()
229 {
230 return _unavailableException;
231 }
232
233
234
235
236
237
238
239
240
241
242 public void setResourceAlias(String alias, String uri)
243 {
244 if (_resourceAliases == null)
245 _resourceAliases= new HashMap(5);
246 _resourceAliases.put(alias, uri);
247 }
248
249
250 public Map getResourceAliases()
251 {
252 if (_resourceAliases == null)
253 return null;
254 return _resourceAliases;
255 }
256
257
258 public void setResourceAliases(Map map)
259 {
260 _resourceAliases = map;
261 }
262
263
264 public String getResourceAlias(String alias)
265 {
266 if (_resourceAliases == null)
267 return null;
268 return (String)_resourceAliases.get(alias);
269 }
270
271
272 public String removeResourceAlias(String alias)
273 {
274 if (_resourceAliases == null)
275 return null;
276 return (String)_resourceAliases.remove(alias);
277 }
278
279
280
281
282
283 @Override
284 public void setClassLoader(ClassLoader classLoader)
285 {
286 super.setClassLoader(classLoader);
287
288
289
290
291
292
293 if (classLoader!=null && classLoader instanceof WebAppClassLoader && getDisplayName()!=null)
294 ((WebAppClassLoader)classLoader).setName(getDisplayName());
295 }
296
297
298 @Override
299 public Resource getResource(String uriInContext) throws MalformedURLException
300 {
301 if (uriInContext==null || !uriInContext.startsWith(URIUtil.SLASH))
302 throw new MalformedURLException(uriInContext);
303
304 IOException ioe= null;
305 Resource resource= null;
306 int loop=0;
307 while (uriInContext!=null && loop++<100)
308 {
309 try
310 {
311 resource= super.getResource(uriInContext);
312 if (resource != null && resource.exists())
313 return resource;
314
315 uriInContext = getResourceAlias(uriInContext);
316 }
317 catch (IOException e)
318 {
319 Log.ignore(e);
320 if (ioe==null)
321 ioe= e;
322 }
323 }
324
325 if (ioe != null && ioe instanceof MalformedURLException)
326 throw (MalformedURLException)ioe;
327
328 return resource;
329 }
330
331
332
333
334
335
336
337 public boolean isConfigurationDiscovered()
338 {
339 return _configurationDiscovered;
340 }
341
342
343
344
345
346
347
348
349
350
351
352 public void setConfigurationDiscovered(boolean discovered)
353 {
354 _configurationDiscovered = discovered;
355 }
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372 public void preConfigure() throws Exception
373 {
374
375 loadConfigurations();
376
377
378 loadSystemClasses();
379
380
381 loadServerClasses();
382
383
384 _ownClassLoader=false;
385 if (getClassLoader()==null)
386 {
387 WebAppClassLoader classLoader = new WebAppClassLoader(this);
388 setClassLoader(classLoader);
389 _ownClassLoader=true;
390 }
391
392 if (Log.isDebugEnabled())
393 {
394 ClassLoader loader = getClassLoader();
395 Log.debug("Thread Context class loader is: " + loader);
396 loader=loader.getParent();
397 while(loader!=null)
398 {
399 Log.debug("Parent class loader is: " + loader);
400 loader=loader.getParent();
401 }
402 }
403
404
405 for (int i=0;i<_configurations.length;i++)
406 _configurations[i].preConfigure(this);
407 }
408
409
410 public void configure() throws Exception
411 {
412
413 for (int i=0;i<_configurations.length;i++)
414 _configurations[i].configure(this);
415 }
416
417
418 public void postConfigure() throws Exception
419 {
420
421 for (int i=0;i<_configurations.length;i++)
422 _configurations[i].postConfigure(this);
423 }
424
425
426
427
428
429 @Override
430 protected void doStart() throws Exception
431 {
432 try
433 {
434 _metadata.setAllowDuplicateFragmentNames(isAllowDuplicateFragmentNames());
435 preConfigure();
436 super.doStart();
437 postConfigure();
438
439 if (isLogUrlOnStart())
440 dumpUrl();
441 }
442 catch (Exception e)
443 {
444
445 Log.warn("Failed startup of context "+this, e);
446 _unavailableException=e;
447 setAvailable(false);
448 }
449 }
450
451
452
453
454
455 @Override
456 protected void doStop() throws Exception
457 {
458 super.doStop();
459
460 try
461 {
462 for (int i=_configurations.length;i-->0;)
463 _configurations[i].deconfigure(this);
464
465 if (_metadata != null)
466 _metadata.clear();
467 _metadata=new MetaData();
468
469 }
470 finally
471 {
472 if (_ownClassLoader)
473 setClassLoader(null);
474
475 setAvailable(true);
476 _unavailableException=null;
477 }
478 }
479
480
481 @Override
482 public void destroy()
483 {
484
485 MultiException mx=new MultiException();
486 if (_configurations!=null)
487 {
488 for (int i=_configurations.length;i-->0;)
489 {
490 try
491 {
492 _configurations[i].destroy(this);
493 }
494 catch(Exception e)
495 {
496 mx.add(e);
497 }
498 }
499 }
500 _configurations=null;
501 super.destroy();
502 mx.ifExceptionThrowRuntime();
503 }
504
505
506
507
508
509
510 private void dumpUrl()
511 {
512 Connector[] connectors = getServer().getConnectors();
513 for (int i=0;i<connectors.length;i++)
514 {
515 String connectorName = connectors[i].getName();
516 String displayName = getDisplayName();
517 if (displayName == null)
518 displayName = "WebApp@"+connectors.hashCode();
519
520 Log.info(displayName + " at http://" + connectorName + getContextPath());
521 }
522 }
523
524
525
526
527
528 public String[] getConfigurationClasses()
529 {
530 return _configurationClasses;
531 }
532
533
534
535
536
537 public Configuration[] getConfigurations()
538 {
539 return _configurations;
540 }
541
542
543
544
545
546
547 public String getDefaultsDescriptor()
548 {
549 return _defaultsDescriptor;
550 }
551
552
553
554
555
556
557
558 public String getOverrideDescriptor()
559 {
560 if (_overrideDescriptors.size()!=1)
561 return null;
562 return _overrideDescriptors.get(0);
563 }
564
565
566
567
568
569
570 public List<String> getOverrideDescriptors()
571 {
572 return Collections.unmodifiableList(_overrideDescriptors);
573 }
574
575
576
577
578
579 public PermissionCollection getPermissions()
580 {
581 return _permissions;
582 }
583
584
585
586
587
588
589 public String[] getServerClasses()
590 {
591 if (_serverClasses == null)
592 loadServerClasses();
593
594 return _serverClasses.getPatterns();
595 }
596
597 public void addServerClass(String classname)
598 {
599 if (_serverClasses == null)
600 loadServerClasses();
601
602 _serverClasses.addPattern(classname);
603 }
604
605
606
607
608
609
610 public String[] getSystemClasses()
611 {
612 if (_systemClasses == null)
613 loadSystemClasses();
614
615 return _systemClasses.getPatterns();
616 }
617
618
619 public void addSystemClass(String classname)
620 {
621 if (_systemClasses == null)
622 loadSystemClasses();
623
624 _systemClasses.addPattern(classname);
625 }
626
627
628 public boolean isServerClass(String name)
629 {
630 if (_serverClasses == null)
631 loadServerClasses();
632
633 return _serverClasses.match(name);
634 }
635
636
637 public boolean isSystemClass(String name)
638 {
639 if (_systemClasses == null)
640 loadSystemClasses();
641
642 return _systemClasses.match(name);
643 }
644
645
646 protected void loadSystemClasses()
647 {
648 if (_systemClasses != null)
649 return;
650
651
652
653 Server server = getServer();
654 if (server != null)
655 {
656 Object systemClasses = server.getAttribute(SERVER_SYS_CLASSES);
657 if (systemClasses != null && systemClasses instanceof String[])
658 _systemClasses = new ClasspathPattern((String[])systemClasses);
659 }
660
661 if (_systemClasses == null)
662 _systemClasses = new ClasspathPattern(__dftSystemClasses);
663 }
664
665
666 private void loadServerClasses()
667 {
668 if (_serverClasses != null)
669 return;
670
671
672
673 Server server = getServer();
674 if (server != null)
675 {
676 Object serverClasses = server.getAttribute(SERVER_SRV_CLASSES);
677 if (serverClasses != null || serverClasses instanceof String[])
678 _serverClasses = new ClasspathPattern((String[])serverClasses);
679 }
680
681 if (_serverClasses == null)
682 _serverClasses = new ClasspathPattern(__dftServerClasses);
683 }
684
685
686
687
688
689 public String getWar()
690 {
691 if (_war==null)
692 _war=getResourceBase();
693 return _war;
694 }
695
696
697 public Resource getWebInf() throws IOException
698 {
699 if (super.getBaseResource() == null)
700 return null;
701
702
703 Resource web_inf= super.getBaseResource().addPath("WEB-INF/");
704 if (!web_inf.exists() || !web_inf.isDirectory())
705 return null;
706
707 return web_inf;
708 }
709
710
711
712
713
714 public boolean isDistributable()
715 {
716 return _distributable;
717 }
718
719
720
721
722
723 public boolean isExtractWAR()
724 {
725 return _extractWAR;
726 }
727
728
729
730
731
732 public boolean isCopyWebDir()
733 {
734 return _copyDir;
735 }
736
737
738
739
740
741 public boolean isCopyWebInf()
742 {
743 return _copyWebInf;
744 }
745
746
747
748
749
750
751
752
753 public boolean isParentLoaderPriority()
754 {
755 return _parentLoaderPriority;
756 }
757
758
759
760 public String[] getDefaultConfigurationClasses ()
761 {
762 return __dftConfigurationClasses;
763 }
764
765
766
767 protected void loadConfigurations()
768 throws Exception
769 {
770
771 if (_configurations!=null)
772 return;
773
774
775 if (!_configurationClassesSet)
776 _configurationClasses=__dftConfigurationClasses;
777
778 _configurations = new Configuration[_configurationClasses.length];
779 for (int i = 0; i < _configurationClasses.length; i++)
780 {
781 _configurations[i]=(Configuration)Loader.loadClass(this.getClass(), _configurationClasses[i]).newInstance();
782 }
783 }
784
785
786 @Override
787 protected boolean isProtectedTarget(String target)
788 {
789 while (target.startsWith("//"))
790 target=URIUtil.compactPath(target);
791
792 return StringUtil.startsWithIgnoreCase(target, "/web-inf") || StringUtil.startsWithIgnoreCase(target, "/meta-inf");
793 }
794
795
796
797 @Override
798 public String toString()
799 {
800 return super.toString()+(_war==null?"":(","+_war));
801 }
802
803
804
805
806
807
808 public void setConfigurationClasses(String[] configurations)
809 {
810 if (isStarted())
811 throw new IllegalStateException();
812 _configurationClasses = configurations==null?null:(String[])configurations.clone();
813 _configurationClassesSet = true;
814 _configurations=null;
815 }
816
817
818
819
820
821 public void setConfigurations(Configuration[] configurations)
822 {
823 if (isStarted())
824 throw new IllegalStateException();
825 _configurations = configurations==null?null:(Configuration[])configurations.clone();
826 _configurationsSet = true;
827 }
828
829
830
831
832
833
834 public void setDefaultsDescriptor(String defaultsDescriptor)
835 {
836 _defaultsDescriptor = defaultsDescriptor;
837 }
838
839
840
841
842
843
844
845 public void setOverrideDescriptor(String overrideDescriptor)
846 {
847 _overrideDescriptors.clear();
848 _overrideDescriptors.add(overrideDescriptor);
849 }
850
851
852
853
854
855
856 public void setOverrideDescriptors(List<String> overrideDescriptors)
857 {
858 _overrideDescriptors.clear();
859 _overrideDescriptors.addAll(overrideDescriptors);
860 }
861
862
863
864
865
866
867 public void addOverrideDescriptor(String overrideDescriptor)
868 {
869 _overrideDescriptors.add(overrideDescriptor);
870 }
871
872
873
874
875
876 public String getDescriptor()
877 {
878 return _descriptor;
879 }
880
881
882
883
884
885 public void setDescriptor(String descriptor)
886 {
887 _descriptor=descriptor;
888 }
889
890
891
892
893
894 public void setDistributable(boolean distributable)
895 {
896 this._distributable = distributable;
897 }
898
899
900 @Override
901 public void setEventListeners(EventListener[] eventListeners)
902 {
903 if (_sessionHandler!=null)
904 _sessionHandler.clearEventListeners();
905
906 super.setEventListeners(eventListeners);
907
908 for (int i=0; eventListeners!=null && i<eventListeners.length;i ++)
909 {
910 EventListener listener = eventListeners[i];
911
912 if ((listener instanceof HttpSessionActivationListener)
913 || (listener instanceof HttpSessionAttributeListener)
914 || (listener instanceof HttpSessionBindingListener)
915 || (listener instanceof HttpSessionListener))
916 {
917 if (_sessionHandler!=null)
918 _sessionHandler.addEventListener(listener);
919 }
920
921 }
922 }
923
924
925
926
927
928
929 @Override
930 public void addEventListener(EventListener listener)
931 {
932 setEventListeners((EventListener[])LazyList.addToArray(getEventListeners(), listener, EventListener.class));
933 }
934
935
936
937
938
939
940 public void setExtractWAR(boolean extractWAR)
941 {
942 _extractWAR = extractWAR;
943 }
944
945
946
947
948
949 public void setCopyWebDir(boolean copy)
950 {
951 _copyDir = copy;
952 }
953
954
955
956
957
958 public void setCopyWebInf(boolean copyWebInf)
959 {
960 _copyWebInf = copyWebInf;
961 }
962
963
964
965
966
967 public void setParentLoaderPriority(boolean java2compliant)
968 {
969 _parentLoaderPriority = java2compliant;
970 }
971
972
973
974
975
976 public void setPermissions(PermissionCollection permissions)
977 {
978 _permissions = permissions;
979 }
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996 public void setServerClasses(String[] serverClasses)
997 {
998 _serverClasses = new ClasspathPattern(serverClasses);
999 }
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016 public void setSystemClasses(String[] systemClasses)
1017 {
1018 _systemClasses = new ClasspathPattern(systemClasses);
1019 }
1020
1021
1022
1023
1024
1025
1026
1027 public void setTempDirectory(File dir)
1028 {
1029 if (isStarted())
1030 throw new IllegalStateException("Started");
1031
1032 if (dir!=null)
1033 {
1034 try{dir=new File(dir.getCanonicalPath());}
1035 catch (IOException e){Log.warn(Log.EXCEPTION,e);}
1036 }
1037
1038 if (dir!=null && !dir.exists())
1039 {
1040 dir.mkdir();
1041 dir.deleteOnExit();
1042 }
1043
1044 if (dir!=null && ( !dir.exists() || !dir.isDirectory() || !dir.canWrite()))
1045 throw new IllegalArgumentException("Bad temp directory: "+dir);
1046
1047 try
1048 {
1049 if (dir!=null)
1050 dir=dir.getCanonicalFile();
1051 }
1052 catch(Exception e)
1053 {
1054 Log.warn(e);
1055 }
1056 _tmpDir=dir;
1057 setAttribute(TEMPDIR,_tmpDir);
1058 }
1059
1060
1061 public File getTempDirectory ()
1062 {
1063 return _tmpDir;
1064 }
1065
1066
1067
1068
1069
1070 public void setWar(String war)
1071 {
1072 _war = war;
1073 }
1074
1075
1076
1077
1078
1079
1080
1081
1082 public String getExtraClasspath()
1083 {
1084 return _extraClasspath;
1085 }
1086
1087
1088
1089
1090
1091
1092
1093 public void setExtraClasspath(String extraClasspath)
1094 {
1095 _extraClasspath=extraClasspath;
1096 }
1097
1098
1099 public boolean isLogUrlOnStart()
1100 {
1101 return _logUrlOnStart;
1102 }
1103
1104
1105
1106
1107
1108
1109
1110 public void setLogUrlOnStart(boolean logOnStart)
1111 {
1112 this._logUrlOnStart = logOnStart;
1113 }
1114
1115
1116
1117 @Override
1118 public void setServer(Server server)
1119 {
1120 super.setServer(server);
1121
1122
1123
1124
1125 if (!_configurationsSet && !_configurationClassesSet && server != null)
1126 {
1127 String[] serverConfigs = (String[])server.getAttribute(SERVER_CONFIG);
1128 if (serverConfigs != null)
1129 setConfigurationClasses(serverConfigs);
1130 }
1131 }
1132
1133
1134
1135 public boolean isAllowDuplicateFragmentNames()
1136 {
1137 return _allowDuplicateFragmentNames;
1138 }
1139
1140
1141
1142 public void setAllowDuplicateFragmentNames(boolean allowDuplicateFragmentNames)
1143 {
1144 _allowDuplicateFragmentNames = allowDuplicateFragmentNames;
1145 }
1146
1147
1148
1149 @Override
1150 protected void startContext()
1151 throws Exception
1152 {
1153 configure();
1154
1155
1156 _metadata.resolve(this);
1157
1158 super.startContext();
1159 }
1160
1161
1162 public class Context extends ServletContextHandler.Context
1163 {
1164
1165 public URL getResource(String path) throws MalformedURLException
1166 {
1167 Resource resource=WebAppContext.this.getResource(path);
1168 if (resource==null || !resource.exists())
1169 return null;
1170
1171
1172 if (resource.isDirectory() && resource instanceof ResourceCollection && !WebAppContext.this.isExtractWAR())
1173 {
1174 Resource[] resources = ((ResourceCollection)resource).getResources();
1175 for (int i=resources.length;i-->0;)
1176 {
1177 if (resources[i].getName().startsWith("jar:file"))
1178 return resources[i].getURL();
1179 }
1180 }
1181
1182 return resource.getURL();
1183 }
1184 }
1185
1186
1187 public MetaData getMetaData()
1188 {
1189 return _metadata;
1190 }
1191
1192 }