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