View Javadoc

1   package org.eclipse.jetty.webapp;
2   
3   import java.io.File;
4   import java.io.IOException;
5   import java.net.URI;
6   import java.net.URISyntaxException;
7   import java.net.URL;
8   import java.net.URLClassLoader;
9   import java.util.ArrayList;
10  import java.util.List;
11  import java.util.regex.Pattern;
12  
13  import org.eclipse.jetty.server.Connector;
14  import org.eclipse.jetty.server.Server;
15  import org.eclipse.jetty.util.IO;
16  import org.eclipse.jetty.util.PatternMatcher;
17  import org.eclipse.jetty.util.URIUtil;
18  import org.eclipse.jetty.util.log.Log;
19  import org.eclipse.jetty.util.resource.JarResource;
20  import org.eclipse.jetty.util.resource.Resource;
21  import org.eclipse.jetty.util.resource.ResourceCollection;
22  
23  public class WebInfConfiguration extends AbstractConfiguration
24  {
25      public static final String TEMPDIR_CONFIGURED = "org.eclipse.jetty.tmpdirConfigured";
26      public static final String CONTAINER_JAR_PATTERN = "org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern";
27      public static final String WEBINF_JAR_PATTERN = "org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern";
28      
29      /**
30       * If set, to a list of URLs, these resources are added to the context
31       * resource base as a resource collection. 
32       */
33      public static final String RESOURCE_URLS = "org.eclipse.jetty.resources";
34      
35      protected Resource _preUnpackBaseResource;
36      
37      @Override
38      public void preConfigure(final WebAppContext context) throws Exception
39      {
40          // Look for a work directory
41          File work = findWorkDirectory(context);
42          if (work != null)
43              makeTempDirectory(work, context, false);
44          
45          //Make a temp directory for the webapp if one is not already set
46          resolveTempDirectory(context);
47          
48          //Extract webapp if necessary
49          unpack (context);
50  
51          
52          //Apply an initial ordering to the jars which governs which will be scanned for META-INF
53          //info and annotations. The ordering is based on inclusion patterns.       
54          String tmp = (String)context.getAttribute(WEBINF_JAR_PATTERN);
55          Pattern webInfPattern = (tmp==null?null:Pattern.compile(tmp));
56          tmp = (String)context.getAttribute(CONTAINER_JAR_PATTERN);
57          Pattern containerPattern = (tmp==null?null:Pattern.compile(tmp));
58  
59          //Apply ordering to container jars - if no pattern is specified, we won't
60          //match any of the container jars
61          PatternMatcher containerJarNameMatcher = new PatternMatcher ()
62          {
63              public void matched(URI uri) throws Exception
64              {
65                  context.getMetaData().addContainerJar(Resource.newResource(uri));
66              }      
67          };
68          ClassLoader loader = context.getClassLoader();
69          while (loader != null && (loader instanceof URLClassLoader))
70          {
71              URL[] urls = ((URLClassLoader)loader).getURLs();
72              if (urls != null)
73              {
74                  URI[] containerUris = new URI[urls.length];
75                  int i=0;
76                  for (URL u : urls)
77                  {
78                      try 
79                      {
80                          containerUris[i] = u.toURI();
81                      }
82                      catch (URISyntaxException e)
83                      {
84                          containerUris[i] = new URI(u.toString().replaceAll(" ", "%20"));
85                      }  
86                      i++;
87                  }
88                  containerJarNameMatcher.match(containerPattern, containerUris, false);
89              }
90              loader = loader.getParent();
91          }
92          
93          //Apply ordering to WEB-INF/lib jars
94          PatternMatcher webInfJarNameMatcher = new PatternMatcher ()
95          {
96              @Override
97              public void matched(URI uri) throws Exception
98              {
99                  context.getMetaData().addWebInfJar(Resource.newResource(uri));
100             }      
101         };
102         List<Resource> jars = findJars(context);
103        
104         //Convert to uris for matching
105         URI[] uris = null;
106         if (jars != null)
107         {
108             uris = new URI[jars.size()];
109             int i=0;
110             for (Resource r: jars)
111             {
112                 uris[i++] = r.getURI();
113             }
114         }
115         webInfJarNameMatcher.match(webInfPattern, uris, true); //null is inclusive, no pattern == all jars match 
116     }
117     
118 
119     @Override
120     public void configure(WebAppContext context) throws Exception
121     {
122         //cannot configure if the context is already started
123         if (context.isStarted())
124         {
125             if (Log.isDebugEnabled()){Log.debug("Cannot configure webapp "+context+" after it is started");}
126             return;
127         }
128 
129         Resource web_inf = context.getWebInf();
130 
131         // Add WEB-INF classes and lib classpaths
132         if (web_inf != null && web_inf.isDirectory() && context.getClassLoader() instanceof WebAppClassLoader)
133         {
134             // Look for classes directory
135             Resource classes= web_inf.addPath("classes/");
136             if (classes.exists())
137                 ((WebAppClassLoader)context.getClassLoader()).addClassPath(classes);
138 
139             // Look for jars
140             Resource lib= web_inf.addPath("lib/");
141             if (lib.exists() || lib.isDirectory())
142                 ((WebAppClassLoader)context.getClassLoader()).addJars(lib);
143         }
144         
145         // Look for extra resource
146         @SuppressWarnings("unchecked")
147         List<Resource> resources = (List<Resource>)context.getAttribute(RESOURCE_URLS);
148         if (resources!=null)
149         {
150             Resource[] collection=new Resource[resources.size()+1];
151             int i=0;
152             collection[i++]=context.getBaseResource();
153             for (Resource resource : resources)
154                 collection[i++]=resource;
155             context.setBaseResource(new ResourceCollection(collection));
156         }
157     }
158 
159     @Override
160     public void deconfigure(WebAppContext context) throws Exception
161     {
162         // delete temp directory if we had to create it or if it isn't called work
163         Boolean tmpdirConfigured = (Boolean)context.getAttribute(TEMPDIR_CONFIGURED);
164         
165         if (context.getTempDirectory()!=null && (tmpdirConfigured == null || !tmpdirConfigured.booleanValue()) && !isTempWorkDirectory(context.getTempDirectory()))
166         {
167             IO.delete(context.getTempDirectory());
168             context.setTempDirectory(null);
169             
170             //clear out the context attributes for the tmp dir only if we had to
171             //create the tmp dir
172             context.setAttribute(TEMPDIR_CONFIGURED, null);
173             context.setAttribute(WebAppContext.TEMPDIR, null);
174         }
175 
176         
177         //reset the base resource back to what it was before we did any unpacking of resources
178         context.setBaseResource(_preUnpackBaseResource);
179     }
180     
181     /* ------------------------------------------------------------ */
182     /**
183      * @see org.eclipse.jetty.webapp.AbstractConfiguration#cloneConfigure(org.eclipse.jetty.webapp.WebAppContext, org.eclipse.jetty.webapp.WebAppContext)
184      */
185     @Override
186     public void cloneConfigure(WebAppContext template, WebAppContext context) throws Exception
187     {
188         File tmpDir=File.createTempFile(WebInfConfiguration.getCanonicalNameForWebAppTmpDir(context),"",template.getTempDirectory().getParentFile());
189         if (tmpDir.exists())
190         {
191             IO.delete(tmpDir);
192         }
193         tmpDir.mkdir();
194         tmpDir.deleteOnExit();
195         context.setTempDirectory(tmpDir);
196     }
197 
198 
199     /* ------------------------------------------------------------ */
200     /**
201      * Get a temporary directory in which to unpack the war etc etc.
202      * The algorithm for determining this is to check these alternatives
203      * in the order shown:
204      * 
205      * <p>A. Try to use an explicit directory specifically for this webapp:</p>
206      * <ol>
207      * <li>
208      * Iff an explicit directory is set for this webapp, use it. Do NOT set
209      * delete on exit.
210      * </li>
211      * <li>
212      * Iff javax.servlet.context.tempdir context attribute is set for
213      * this webapp && exists && writeable, then use it. Do NOT set delete on exit.
214      * </li>
215      * </ol>
216      * 
217      * <p>B. Create a directory based on global settings. The new directory 
218      * will be called "Jetty_"+host+"_"+port+"__"+context+"_"+virtualhost
219      * Work out where to create this directory:
220      * <ol>
221      * <li>
222      * Iff $(jetty.home)/work exists create the directory there. Do NOT
223      * set delete on exit. Do NOT delete contents if dir already exists.
224      * </li>
225      * <li>
226      * Iff WEB-INF/work exists create the directory there. Do NOT set
227      * delete on exit. Do NOT delete contents if dir already exists.
228      * </li>
229      * <li>
230      * Else create dir in $(java.io.tmpdir). Set delete on exit. Delete
231      * contents if dir already exists.
232      * </li>
233      * </ol>
234      */
235     public void resolveTempDirectory (WebAppContext context)
236     {
237         //If a tmp directory is already set, we're done
238         File tmpDir = context.getTempDirectory();
239         if (tmpDir != null && tmpDir.isDirectory() && tmpDir.canWrite())
240         {
241             context.setAttribute(TEMPDIR_CONFIGURED, Boolean.TRUE);
242             return; // Already have a suitable tmp dir configured
243         }
244         
245 
246         // No temp directory configured, try to establish one.
247         // First we check the context specific, javax.servlet specified, temp directory attribute
248         File servletTmpDir = asFile(context.getAttribute(WebAppContext.TEMPDIR));
249         if (servletTmpDir != null && servletTmpDir.isDirectory() && servletTmpDir.canWrite())
250         {
251             // Use as tmpDir
252             tmpDir = servletTmpDir;
253             // Ensure Attribute has File object
254             context.setAttribute(WebAppContext.TEMPDIR,tmpDir);
255             // Set as TempDir in context.
256             context.setTempDirectory(tmpDir);
257             return;
258         }
259 
260         try
261         {
262             // Put the tmp dir in the work directory if we had one
263             File work =  new File(System.getProperty("jetty.home"),"work");
264             if (work.exists() && work.canWrite() && work.isDirectory())
265             {
266                 makeTempDirectory(work, context, false); //make a tmp dir inside work, don't delete if it exists
267             }
268             else
269             {
270                 File baseTemp = asFile(context.getAttribute(WebAppContext.BASETEMPDIR));
271                 if (baseTemp != null && baseTemp.isDirectory() && baseTemp.canWrite())
272                 {
273                     // Use baseTemp directory (allow the funky Jetty_0_0_0_0.. subdirectory logic to kick in
274                     makeTempDirectory(baseTemp,context,false);
275                 }
276                 else
277                 {
278                     makeTempDirectory(new File(System.getProperty("java.io.tmpdir")),context,true); //make a tmpdir, delete if it already exists
279                 }
280             }
281         }
282         catch(Exception e)
283         {
284             tmpDir=null;
285             Log.ignore(e);
286         }
287 
288         //Third ... Something went wrong trying to make the tmp directory, just make
289         //a jvm managed tmp directory
290         if (context.getTempDirectory() == null)
291         {
292             try
293             {
294                 // Last resort
295                 tmpDir=File.createTempFile("JettyContext","");
296                 if (tmpDir.exists())
297                     IO.delete(tmpDir);
298                 tmpDir.mkdir();
299                 tmpDir.deleteOnExit();
300                 context.setTempDirectory(tmpDir);
301             }
302             catch(IOException e)
303             {
304                 Log.warn("tmpdir",e); System.exit(1);
305             }
306         }
307     }
308     
309     /**
310      * Given an Object, return File reference for object.
311      * Typically used to convert anonymous Object from getAttribute() calls to a File object.
312      * @param fileattr the file attribute to analyze and return from (supports type File and type String, all others return null)
313      * @return the File object, null if null, or null if not a File or String
314      */
315     private File asFile(Object fileattr)
316     {
317         if (fileattr == null)
318         {
319             return null;
320         }
321         if (fileattr instanceof File)
322         {
323             return (File)fileattr;
324         }
325         if (fileattr instanceof String)
326         {
327             return new File((String)fileattr);
328         }
329         return null;
330     }
331 
332 
333 
334     public void makeTempDirectory (File parent, WebAppContext context, boolean deleteExisting)
335     throws IOException
336     {
337         if (parent != null && parent.exists() && parent.canWrite() && parent.isDirectory())
338         {
339             String temp = getCanonicalNameForWebAppTmpDir(context);                    
340             File tmpDir = new File(parent,temp);
341 
342             if (deleteExisting && tmpDir.exists())
343             {
344                 if (!IO.delete(tmpDir))
345                 {
346                     if(Log.isDebugEnabled())Log.debug("Failed to delete temp dir "+tmpDir);
347                 }
348             
349                 //If we can't delete the existing tmp dir, create a new one
350                 if (tmpDir.exists())
351                 {
352                     String old=tmpDir.toString();
353                     tmpDir=File.createTempFile(temp+"_","");
354                     if (tmpDir.exists())
355                         IO.delete(tmpDir);
356                     Log.warn("Can't reuse "+old+", using "+tmpDir);
357                 } 
358             }
359             
360             if (!tmpDir.exists())
361                 tmpDir.mkdir();
362 
363             //If the parent is not a work directory
364             if (!isTempWorkDirectory(tmpDir))
365             {
366                 tmpDir.deleteOnExit();
367                 //TODO why is this here?
368                 File sentinel = new File(tmpDir, ".active");
369                 if(!sentinel.exists())
370                     sentinel.mkdir();
371             }
372 
373             if(Log.isDebugEnabled())
374                 Log.debug("Set temp dir "+tmpDir);
375             context.setTempDirectory(tmpDir);
376         }
377     }
378     
379     
380     public void unpack (WebAppContext context) throws IOException
381     {
382         Resource web_app = context.getBaseResource();
383         _preUnpackBaseResource = context.getBaseResource();
384         
385         if (web_app == null)
386         {
387             String war = context.getWar();
388             if (war!=null && war.length()>0)
389                 web_app = context.newResource(war);
390             else
391                 web_app=context.getBaseResource();
392 
393             // Accept aliases for WAR files
394             if (web_app.getAlias() != null)
395             {
396                 Log.debug(web_app + " anti-aliased to " + web_app.getAlias());
397                 web_app = context.newResource(web_app.getAlias());
398             }
399 
400             if (Log.isDebugEnabled())
401                 Log.debug("Try webapp=" + web_app + ", exists=" + web_app.exists() + ", directory=" + web_app.isDirectory());
402 
403             // Is the WAR usable directly?
404             if (web_app.exists() && !web_app.isDirectory() && !web_app.toString().startsWith("jar:"))
405             {
406                 // No - then lets see if it can be turned into a jar URL.
407                 Resource jarWebApp = JarResource.newJarResource(web_app);
408                 if (jarWebApp.exists() && jarWebApp.isDirectory())
409                     web_app= jarWebApp;
410             }
411 
412             // If we should extract or the URL is still not usable
413             if (web_app.exists()  && (
414                     (context.isCopyWebDir() && web_app.getFile() != null && web_app.getFile().isDirectory()) ||
415                     (context.isExtractWAR() && web_app.getFile() != null && !web_app.getFile().isDirectory()) ||
416                     (context.isExtractWAR() && web_app.getFile() == null) || 
417                     !web_app.isDirectory())
418                             )
419             {
420                 // Look for sibling directory.
421                 File extractedWebAppDir = null;
422 
423                 if (war!=null)
424                 {
425                     // look for a sibling like "foo/" to a "foo.war"
426                     File warfile=Resource.newResource(war).getFile();
427                     if (warfile!=null && warfile.getName().toLowerCase().endsWith(".war"))
428                     {
429                         File sibling = new File(warfile.getParent(),warfile.getName().substring(0,warfile.getName().length()-4));
430                         if (sibling.exists() && sibling.isDirectory() && sibling.canWrite())
431                             extractedWebAppDir=sibling;
432                     }
433                 }
434                 
435                 if (extractedWebAppDir==null)
436                     // Then extract it if necessary to the temporary location
437                     extractedWebAppDir= new File(context.getTempDirectory(), "webapp");
438 
439                 if (web_app.getFile()!=null && web_app.getFile().isDirectory())
440                 {
441                     // Copy directory
442                     Log.info("Copy " + web_app + " to " + extractedWebAppDir);
443                     web_app.copyTo(extractedWebAppDir);
444                 }
445                 else
446                 {
447                     if (!extractedWebAppDir.exists())
448                     {
449                         //it hasn't been extracted before so extract it
450                         extractedWebAppDir.mkdir();
451                         Log.info("Extract " + web_app + " to " + extractedWebAppDir);
452                         Resource jar_web_app = JarResource.newJarResource(web_app);
453                         jar_web_app.copyTo(extractedWebAppDir);
454                     }
455                     else
456                     {
457                         //only extract if the war file is newer
458                         if (web_app.lastModified() > extractedWebAppDir.lastModified())
459                         {
460                             IO.delete(extractedWebAppDir);
461                             extractedWebAppDir.mkdir();
462                             Log.info("Extract " + web_app + " to " + extractedWebAppDir);
463                             Resource jar_web_app = JarResource.newJarResource(web_app);
464                             jar_web_app.copyTo(extractedWebAppDir);
465                         }
466                     }
467                 } 
468                 web_app = Resource.newResource(extractedWebAppDir.getCanonicalPath());
469             }
470 
471             // Now do we have something usable?
472             if (!web_app.exists() || !web_app.isDirectory())
473             {
474                 Log.warn("Web application not found " + war);
475                 throw new java.io.FileNotFoundException(war);
476             }
477         
478             context.setBaseResource(web_app);
479             
480             if (Log.isDebugEnabled())
481                 Log.debug("webapp=" + web_app);
482         }
483         
484         
485 
486         // Do we need to extract WEB-INF/lib?
487         if (context.isCopyWebInf())
488         {
489             Resource web_inf= web_app.addPath("WEB-INF/");
490 
491             if (web_inf instanceof ResourceCollection ||
492                     web_inf.exists() && 
493                     web_inf.isDirectory() && 
494                     (web_inf.getFile()==null || !web_inf.getFile().isDirectory()))
495             {       
496                 File extractedWebInfDir= new File(context.getTempDirectory(), "webinf");
497                 if (extractedWebInfDir.exists())
498                     IO.delete(extractedWebInfDir);
499                 extractedWebInfDir.mkdir();
500                 Resource web_inf_lib = web_inf.addPath("lib/");
501                 File webInfDir=new File(extractedWebInfDir,"WEB-INF");
502                 webInfDir.mkdir();
503 
504                 if (web_inf_lib.exists())
505                 {
506                     File webInfLibDir = new File(webInfDir, "lib");
507                     if (webInfLibDir.exists())
508                         IO.delete(webInfLibDir);
509                     webInfLibDir.mkdir();
510 
511                     Log.info("Copying WEB-INF/lib " + web_inf_lib + " to " + webInfLibDir);
512                     web_inf_lib.copyTo(webInfLibDir);
513                 }
514 
515                 Resource web_inf_classes = web_inf.addPath("classes/");
516                 if (web_inf_classes.exists())
517                 {
518                     File webInfClassesDir = new File(webInfDir, "classes");
519                     if (webInfClassesDir.exists())
520                         IO.delete(webInfClassesDir);
521                     webInfClassesDir.mkdir();
522                     Log.info("Copying WEB-INF/classes from "+web_inf_classes+" to "+webInfClassesDir.getAbsolutePath());
523                     web_inf_classes.copyTo(webInfClassesDir);
524                 }
525 
526                 web_inf=Resource.newResource(extractedWebInfDir.getCanonicalPath());
527 
528                 ResourceCollection rc = new ResourceCollection(web_inf,web_app);
529 
530                 if (Log.isDebugEnabled())
531                     Log.debug("context.resourcebase = "+rc);
532 
533                 context.setBaseResource(rc);
534             }   
535         }
536     }
537     
538     
539     public File findWorkDirectory (WebAppContext context) throws IOException
540     {
541         if (context.getBaseResource() != null)
542         {
543             Resource web_inf = context.getWebInf();
544             if (web_inf !=null && web_inf.exists())
545             {
546                return new File(web_inf.getFile(),"work");
547             }
548         }
549         return null;
550     }
551     
552     
553     /**
554      * Check if the tmpDir itself is called "work", or if the tmpDir
555      * is in a directory called "work".
556      * @return true if File is a temporary or work directory
557      */
558     public boolean isTempWorkDirectory (File tmpDir)
559     {
560         if (tmpDir == null)
561             return false;
562         if (tmpDir.getName().equalsIgnoreCase("work"))
563             return true;
564         File t = tmpDir.getParentFile();
565         if (t == null)
566             return false;
567         return (t.getName().equalsIgnoreCase("work"));
568     }
569     
570     
571     /**
572      * Create a canonical name for a webapp temp directory.
573      * The form of the name is:
574      *  <code>"Jetty_"+host+"_"+port+"__"+resourceBase+"_"+context+"_"+virtualhost+base36_hashcode_of_whole_string</code>
575      *  
576      *  host and port uniquely identify the server
577      *  context and virtual host uniquely identify the webapp
578      * @return the canonical name for the webapp temp directory
579      */
580     public static String getCanonicalNameForWebAppTmpDir (WebAppContext context)
581     {
582         StringBuffer canonicalName = new StringBuffer();
583         canonicalName.append("jetty-");
584        
585         //get the host and the port from the first connector 
586         Server server=context.getServer();
587         if (server!=null)
588         {
589             Connector[] connectors = context.getServer().getConnectors();
590 
591             if (connectors.length>0)
592             {
593                 //Get the host
594                 String host = (connectors==null||connectors[0]==null?"":connectors[0].getHost());
595                 if (host == null)
596                     host = "0.0.0.0";
597                 canonicalName.append(host);
598                 
599                 //Get the port
600                 canonicalName.append("-");
601                 //try getting the real port being listened on
602                 int port = (connectors==null||connectors[0]==null?0:connectors[0].getLocalPort());
603                 //if not available (eg no connectors or connector not started), 
604                 //try getting one that was configured.
605                 if (port < 0)
606                     port = connectors[0].getPort();
607                 canonicalName.append(port);
608                 canonicalName.append("-");
609             }
610         }
611 
612        
613         //Resource  base
614         try
615         {
616             Resource resource = context.getBaseResource();
617             if (resource == null)
618             {
619                 if (context.getWar()==null || context.getWar().length()==0)
620                     resource=context.newResource(context.getResourceBase());
621                 
622                 // Set dir or WAR
623                 resource = context.newResource(context.getWar());
624             }
625                 
626             String tmp = URIUtil.decodePath(resource.getURL().getPath());
627             if (tmp.endsWith("/"))
628                 tmp = tmp.substring(0, tmp.length()-1);
629             if (tmp.endsWith("!"))
630                 tmp = tmp.substring(0, tmp.length() -1);
631             //get just the last part which is the filename
632             int i = tmp.lastIndexOf("/");
633             canonicalName.append(tmp.substring(i+1, tmp.length()));
634             canonicalName.append("-");
635         }
636         catch (Exception e)
637         {
638             Log.warn("Can't generate resourceBase as part of webapp tmp dir name", e);
639         }
640             
641         //Context name
642         String contextPath = context.getContextPath();
643         contextPath=contextPath.replace('/','_');
644         contextPath=contextPath.replace('\\','_');
645         canonicalName.append(contextPath);
646         
647         //Virtual host (if there is one)
648         canonicalName.append("-");
649         String[] vhosts = context.getVirtualHosts();
650         if (vhosts == null || vhosts.length <= 0)
651             canonicalName.append("any");
652         else
653             canonicalName.append(vhosts[0]);
654         
655         // sanitize
656         for (int i=0;i<canonicalName.length();i++)
657         {
658             char c=canonicalName.charAt(i);
659             if (!Character.isJavaIdentifierPart(c) && "-.".indexOf(c)<0)
660                 canonicalName.setCharAt(i,'.');
661         }        
662 
663         canonicalName.append("-");
664         return canonicalName.toString();
665     }
666     
667     /**
668      * Look for jars in WEB-INF/lib
669      * @param context
670      * @return the list of jar resources found within context 
671      * @throws Exception
672      */
673     protected List<Resource> findJars (WebAppContext context) 
674     throws Exception
675     {
676         List<Resource> jarResources = new ArrayList<Resource>();
677         
678         Resource web_inf = context.getWebInf();
679         if (web_inf==null || !web_inf.exists())
680             return null;
681         
682         Resource web_inf_lib = web_inf.addPath("/lib");
683        
684         
685         if (web_inf_lib.exists() && web_inf_lib.isDirectory())
686         {
687             String[] files=web_inf_lib.list();
688             for (int f=0;files!=null && f<files.length;f++)
689             {
690                 try 
691                 {
692                     Resource file = web_inf_lib.addPath(files[f]);
693                     String fnlc = file.getName().toLowerCase();
694                     int dot = fnlc.lastIndexOf('.');
695                     String extension = (dot < 0 ? null : fnlc.substring(dot));
696                     if (extension != null && (extension.equals(".jar") || extension.equals(".zip")))
697                     {
698                         jarResources.add(file);
699                     }
700                 }
701                 catch (Exception ex)
702                 {
703                     Log.warn(Log.EXCEPTION,ex);
704                 }
705             }
706         }
707         return jarResources;
708     }
709 }