001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.jsp;
031:
032: import com.caucho.config.Config;
033: import com.caucho.config.ConfigException;
034: import com.caucho.config.types.FileSetType;
035: import com.caucho.jsp.cfg.*;
036: import com.caucho.loader.DynamicClassLoader;
037: import com.caucho.loader.EnvironmentLocal;
038: import com.caucho.log.Log;
039: import com.caucho.server.util.CauchoSystem;
040: import com.caucho.server.webapp.WebApp;
041: import com.caucho.util.Alarm;
042: import com.caucho.util.L10N;
043: import com.caucho.vfs.*;
044:
045: import java.io.IOException;
046: import java.io.InputStream;
047: import java.lang.ref.SoftReference;
048: import java.util.ArrayList;
049: import java.util.Enumeration;
050: import java.util.HashMap;
051: import java.util.jar.JarFile;
052: import java.util.logging.Level;
053: import java.util.logging.Logger;
054: import java.util.zip.ZipEntry;
055: import java.util.zip.ZipFile;
056:
057: /**
058: * Stores the parsed tlds.
059: */
060: public class TldManager {
061: static final L10N L = new L10N(TldManager.class);
062: private static final Logger log = Log.open(TldManager.class);
063:
064: private static ArrayList<TldPreload> _cauchoTaglibs;
065: private static ArrayList<TldPreload> _globalTaglibs;
066: private static ArrayList<Path> _globalPaths;
067:
068: private static EnvironmentLocal<TldManager> _localManager = new EnvironmentLocal<TldManager>();
069:
070: private JspResourceManager _resourceManager;
071: private WebApp _webApp;
072:
073: private HashMap<Path, SoftReference<TldTaglib>> _tldMap = new HashMap<Path, SoftReference<TldTaglib>>();
074:
075: private JspParseException _loadAllTldException;
076: private String _tldDir;
077: private FileSetType _tldFileSet;
078:
079: private boolean _isFastJsf = false;
080:
081: private volatile boolean _isInit;
082:
083: private Config _config = new Config();
084: private ArrayList<TldPreload> _preloadTaglibs;
085:
086: private TldManager(JspResourceManager resourceManager, WebApp app)
087: throws JspParseException, IOException {
088: _resourceManager = resourceManager;
089: _webApp = app;
090:
091: if (app != null) {
092: JspPropertyGroup jsp = app.getJsp();
093: if (jsp != null) {
094: _tldFileSet = jsp.getTldFileSet();
095:
096: _isFastJsf = jsp.isFastJsf();
097: }
098: }
099:
100: // JSF has a global listener hidden in one of the *.tld which
101: // requires Resin to search all the JSPs.
102: initGlobal();
103: }
104:
105: static TldManager create(JspResourceManager resourceManager,
106: WebApp app) throws JspParseException, IOException {
107:
108: TldManager manager = null;
109:
110: synchronized (_localManager) {
111: manager = _localManager.getLevel();
112:
113: if (manager != null)
114: return manager;
115:
116: manager = new TldManager(resourceManager, app);
117: _localManager.set(manager);
118: }
119:
120: return manager;
121: }
122:
123: /**
124: * Sets the webApp.
125: */
126: void setWebApp(WebApp webApp) {
127: _webApp = webApp;
128: }
129:
130: public String getSchema() {
131: return "com/caucho/jsp/cfg/jsp-tld.rnc";
132: }
133:
134: public void setTldDir(String tldDir) {
135: _tldDir = tldDir;
136: }
137:
138: public void setTldFileSet(FileSetType tldFileSet) {
139: _tldFileSet = tldFileSet;
140: }
141:
142: /**
143: * Loads all the .tld files in the WEB-INF and the META-INF for
144: * the entire classpath.
145: */
146: public synchronized void init() throws JspParseException,
147: IOException {
148: if (_isInit)
149: return;
150: _isInit = true;
151:
152: log.fine("Loading .tld files");
153:
154: String dir;
155:
156: if (_tldDir == null)
157: dir = "WEB-INF";
158: else if (_tldDir.startsWith("/"))
159: dir = _tldDir.substring(1);
160: else if (_tldDir.startsWith("WEB-INF"))
161: dir = _tldDir;
162: else
163: dir = "WEB-INF/" + _tldDir;
164:
165: FileSetType fileSet = _tldFileSet;
166: if (fileSet == null) {
167: fileSet = new FileSetType();
168: fileSet.setDir(_resourceManager.resolvePath(dir));
169: try {
170: fileSet.init();
171: } catch (Exception e) {
172: log.config(e.toString());
173: }
174: }
175:
176: ArrayList<TldPreload> taglibs = new ArrayList<TldPreload>();
177:
178: taglibs.addAll(_globalTaglibs);
179:
180: ArrayList<Path> paths = getClassPath();
181:
182: for (int i = 0; i < paths.size(); i++) {
183: Path subPath = paths.get(i);
184:
185: if (_globalPaths.contains(subPath))
186: continue;
187:
188: if (subPath instanceof JarPath)
189: loadJarTlds(taglibs,
190: ((JarPath) subPath).getContainer(), "META-INF");
191: else if (subPath.getPath().endsWith(".jar")) {
192: loadJarTlds(taglibs, subPath, "META-INF");
193: } else
194: loadAllTlds(taglibs, subPath.lookup("META-INF"), 64,
195: "META-INF");
196: }
197:
198: if (fileSet != null)
199: loadAllTlds(taglibs, fileSet);
200:
201: /*
202: for (int i = 0; i < taglibs.size(); i++) {
203: TldTaglib taglib = taglibs.get(i);
204:
205: if (taglib.getConfigException() != null &&
206: taglib.getURI() == null) {
207: _loadAllTldException = JspParseException.create(taglib.getConfigException());
208: }
209: }
210: */
211: taglibs.addAll(_cauchoTaglibs);
212:
213: _preloadTaglibs = taglibs;
214:
215: for (int i = 0; i < taglibs.size(); i++) {
216: try {
217: taglibs.get(i).initListeners(_webApp);
218: } catch (Exception e) {
219: throw new JspParseException(e);
220: }
221: }
222: }
223:
224: public synchronized void initGlobal() {
225: // loads tag libraries from the global context (so there's no
226: // need to reparse the jars for each web-app
227: if (_globalTaglibs == null) {
228: if (!Alarm.isTest()) {
229: log.info("Loading .tld files from global classpath");
230: }
231:
232: ArrayList<TldPreload> globalTaglibs = new ArrayList<TldPreload>();
233: ArrayList<TldPreload> cauchoTaglibs = new ArrayList<TldPreload>();
234:
235: Thread thread = Thread.currentThread();
236: ClassLoader oldLoader = thread.getContextClassLoader();
237: ClassLoader globalLoader = TldManager.class
238: .getClassLoader();
239: thread.setContextClassLoader(globalLoader);
240: try {
241: ArrayList<Path> paths = getClassPath(globalLoader);
242: _globalPaths = paths;
243:
244: loadClassPathTlds(globalTaglibs, paths, "");
245:
246: for (int i = globalTaglibs.size() - 1; i >= 0; i--) {
247: TldPreload tld = globalTaglibs.get(i);
248:
249: if (tld.getPath() == null
250: || tld.getPath().getPath() == null)
251: continue;
252:
253: String tldPathName = tld.getPath().getPath();
254:
255: if (tldPathName.startsWith("/com/caucho")) {
256: cauchoTaglibs.add(globalTaglibs.remove(i));
257: }
258: }
259: } catch (Exception e) {
260: log.log(Level.WARNING, e.toString(), e);
261: } finally {
262: thread.setContextClassLoader(oldLoader);
263: }
264:
265: _globalTaglibs = globalTaglibs;
266: _cauchoTaglibs = cauchoTaglibs;
267: }
268: }
269:
270: private void loadClassPathTlds(ArrayList<TldPreload> taglibs,
271: ArrayList<Path> paths, String prefix)
272: throws JspParseException, IOException {
273: for (int i = 0; i < paths.size(); i++) {
274: Path subPath = paths.get(i);
275:
276: if (subPath.getPath().endsWith(".jar")) {
277: loadJarTlds(taglibs, subPath, prefix);
278: } else if (prefix != null && !prefix.equals(""))
279: loadAllTlds(taglibs, subPath.lookup(prefix), 64, prefix);
280: else
281: loadAllTlds(taglibs, subPath.lookup("META-INF"), 64,
282: "META-INF");
283: }
284: }
285:
286: /*
287: ArrayList<TldTaglib> getTaglibs()
288: {
289: return new ArrayList<TldTaglib>(_preloadTaglibs);
290: }
291: */
292:
293: private void loadAllTlds(ArrayList<TldPreload> taglibs,
294: FileSetType fileSet) throws JspParseException, IOException {
295: for (Path path : fileSet.getPaths()) {
296: if (path.getPath().startsWith(".")) {
297: } else if ((path.getPath().endsWith(".tld") || path
298: .getPath().endsWith(".ftld"))
299: && path.isFile() && path.canRead()) {
300: try {
301: TldPreload taglib = parseTldPreload(path);
302:
303: taglibs.add(taglib);
304:
305: if (taglib.getURI() == null
306: && taglib.getConfigException() != null
307: && _loadAllTldException == null)
308: _loadAllTldException = new JspLineParseException(
309: taglib.getConfigException());
310: } catch (Exception e) {
311: log.warning(e.getMessage());
312: }
313: }
314: }
315: }
316:
317: private void loadAllTlds(ArrayList<TldPreload> taglibs, Path path,
318: int depth, String userPath) throws JspParseException,
319: IOException {
320: if (depth < 0)
321: throw new JspParseException(
322: L
323: .l(
324: "max depth exceeded while reading .tld files. Probable loop in filesystem detected at `{0}'.",
325: path));
326:
327: path.setUserPath(userPath);
328:
329: if (path.getPath().startsWith(".")) {
330: } else if ((path.getPath().endsWith(".tld") || path.getPath()
331: .endsWith(".ftld"))
332: && path.isFile() && path.canRead()) {
333: try {
334: TldPreload taglib = parseTldPreload(path);
335:
336: taglibs.add(taglib);
337:
338: if (taglib.getURI() == null
339: && taglib.getConfigException() != null
340: && _loadAllTldException == null)
341: _loadAllTldException = new JspLineParseException(
342: taglib.getConfigException());
343: } catch (Exception e) {
344: /*
345: if (_loadAllTldException == null) {
346: }
347: else if (e instanceof JspParseException)
348: _loadAllTldException = (JspParseException) e;
349: else
350: _loadAllTldException = new JspParseException(e);
351: */
352:
353: log.warning(e.getMessage());
354: }
355: } else if (path.isDirectory()) {
356: String[] fileNames = path.list();
357:
358: for (int i = 0; fileNames != null && i < fileNames.length; i++) {
359: String name = fileNames[i];
360:
361: ArrayList<Path> resources = path.getResources(name);
362:
363: for (int j = 0; resources != null
364: && j < resources.size(); j++) {
365: Path subpath = resources.get(j);
366:
367: loadAllTlds(taglibs, subpath, depth - 1, userPath
368: + "/" + name);
369: }
370: }
371: }
372: }
373:
374: private void loadJarTlds(ArrayList<TldPreload> taglibs,
375: Path jarBacking, String prefix) throws JspParseException,
376: IOException {
377: if (!jarBacking.canRead())
378: return;
379:
380: String nativePath = jarBacking.getNativePath();
381: ZipFile zipFile;
382: JarPath jar = JarPath.create(jarBacking);
383:
384: if (nativePath.endsWith(".jar"))
385: zipFile = new JarFile(nativePath);
386: else
387: zipFile = new ZipFile(nativePath);
388:
389: ArrayList<Path> tldPaths = new ArrayList<Path>();
390:
391: boolean isValidScan = false;
392:
393: ZipScanner scan = null;
394: try {
395: if (true)
396: scan = new ZipScanner(jarBacking);
397:
398: if (scan != null && scan.open()) {
399: while (scan.next()) {
400: String name = scan.getName();
401:
402: if (name.startsWith(prefix)
403: && name.endsWith(".tld")
404: || name.endsWith(".ftld")) {
405: tldPaths.add(jar.lookup(name));
406: }
407: }
408:
409: isValidScan = true;
410: }
411: } catch (Exception e) {
412: log.log(Level.INFO, e.toString(), e);
413: }
414:
415: if (!isValidScan) {
416: try {
417: Enumeration<? extends ZipEntry> en = zipFile.entries();
418: while (en.hasMoreElements()) {
419: ZipEntry entry = en.nextElement();
420: String name = entry.getName();
421:
422: if (name.startsWith(prefix)
423: && (name.endsWith(".tld") || name
424: .endsWith(".ftld"))) {
425: tldPaths.add(jar.lookup(name));
426: }
427: }
428: } finally {
429: zipFile.close();
430: }
431: }
432:
433: for (Path path : tldPaths) {
434: try {
435: TldPreload taglib = parseTldPreload(path);
436:
437: taglibs.add(taglib);
438:
439: if (taglib.getURI() == null
440: && taglib.getConfigException() != null
441: && _loadAllTldException == null)
442: _loadAllTldException = new JspLineParseException(
443: taglib.getConfigException());
444: } catch (Exception e) {
445: /*
446: if (_loadAllTldException == null) {
447: }
448: else if (e instanceof JspParseException)
449: _loadAllTldException = (JspParseException) e;
450: else
451: _loadAllTldException = new JspParseException(e);
452: */
453:
454: log.warning(e.getMessage());
455: }
456: }
457: }
458:
459: /**
460: * Returns the tld parsed at the given location.
461: */
462: TldTaglib parseTld(String uri, String mapLocation, String location)
463: throws JspParseException, IOException {
464: init();
465:
466: TldTaglib taglib = null;
467: TldTaglib jsfTaglib = null;
468:
469: for (int i = 0; i < _preloadTaglibs.size(); i++) {
470: TldPreload preload = _preloadTaglibs.get(i);
471:
472: if (uri.equals(preload.getURI())
473: && (mapLocation == null
474: || mapLocation
475: .equals(preload.getLocation()) || mapLocation
476: .equals(uri))) {
477: if (preload.isJsf()) {
478: if (_isFastJsf)
479: jsfTaglib = parseTld(preload.getPath());
480: } else if (taglib == null)
481: taglib = parseTld(preload.getPath());
482: }
483: }
484:
485: if (jsfTaglib != null && taglib != null) {
486: taglib.mergeJsf(jsfTaglib);
487:
488: return taglib;
489: } else if (taglib != null)
490: return taglib;
491:
492: return parseTld(location);
493: }
494:
495: /**
496: * Returns the tld parsed at the given location.
497: */
498: TldTaglib parseTld(String location) throws JspParseException,
499: IOException {
500: init();
501:
502: TldTaglib tld = findTld(location);
503:
504: /* XXX: jsp/18n0 handled on init
505: if (tld != null) {
506: try {
507: tld.init(_webApp);
508: } catch (Exception e) {
509: throw new JspParseException(e);
510: }
511: }
512: */
513:
514: return tld;
515: }
516:
517: /**
518: * Returns the tld parsed at the given location.
519: */
520: private TldTaglib findTld(String location)
521: throws JspParseException, IOException {
522: InputStream is = null;
523:
524: Path path;
525:
526: if (location.startsWith("file:")) {
527: path = _resourceManager.resolvePath(location);
528: } else if (location.indexOf(':') >= 0
529: && !location.startsWith("file:")
530: && location.indexOf(':') < location.indexOf('/')) {
531: if (_loadAllTldException != null)
532: throw _loadAllTldException;
533:
534: return null;
535: /* XXX: jsp/0316
536: throw new JspParseException(L.l("Unknown taglib `{0}'. Taglibs specified with an absolute URI must either be:\n1) specified in the web.xml\n2) defined in a jar's .tld in META-INF\n3) defined in a .tld in WEB-INF\n4) predefined by Resin",
537: location));
538: */
539: } else if (!location.startsWith("/"))
540: path = _resourceManager.resolvePath("WEB-INF/" + location);
541: else
542: path = _resourceManager.resolvePath("." + location);
543:
544: path.setUserPath(location);
545:
546: Path jar = null;
547:
548: if (location.endsWith(".jar")) {
549: path = findJar(location);
550:
551: if (path != null && path.exists()) {
552: jar = JarPath.create(path);
553: if (jar.lookup("META-INF/taglib.tld").exists())
554: return parseTld(jar.lookup("META-INF/taglib.tld"));
555: else if (jar.lookup("meta-inf/taglib.tld").exists())
556: return parseTld(jar.lookup("meta-inf/taglib.tld"));
557: else
558: throw new JspParseException(L.l(
559: "can't find META-INF/taglib.tld in `{0}'",
560: location));
561: } else {
562: throw new JspParseException(
563: L
564: .l(
565: "Can't find taglib `{0}'. A taglib uri ending in *.jar must point to an actual jar or match a URI in a .tld file.",
566: location));
567: }
568: } else if (path.exists() && path.canRead() && path.isFile())
569: return parseTld(path);
570:
571: if (_loadAllTldException != null)
572: throw _loadAllTldException;
573: else
574: throw new JspParseException(
575: L
576: .l(
577: "Can't find taglib-location `{0}'. The taglib-location must match a tag library either:\n1) by pointing to a .tld directly, relative to the application's root directory\n2) specified in the web.xml\n3) defined in a jar's .tld in META-INF\n4) defined in a .tld in WEB-INF\n5) predefined by Resin",
578: location));
579: }
580:
581: /**
582: * Parses the .tld
583: *
584: * @param is the input stream to the taglib
585: */
586: private TldTaglib parseTld(Path path) throws JspParseException,
587: IOException {
588: SoftReference<TldTaglib> taglibRef = _tldMap.get(path);
589: TldTaglib taglib;
590:
591: if (taglibRef != null) {
592: taglib = taglibRef.get();
593:
594: if (taglib != null && !taglib.isModified())
595: return taglib;
596: }
597:
598: ReadStream is = path.openRead();
599:
600: try {
601: taglib = parseTld(is);
602:
603: if (path instanceof JarPath)
604: taglib.setJarPath(path.lookup("/"));
605:
606: _tldMap.put(path, new SoftReference<TldTaglib>(taglib));
607:
608: return taglib;
609: } finally {
610: is.close();
611: }
612: }
613:
614: /**
615: * Parses the .tld
616: *
617: * @param is the input stream to the taglib
618: */
619: private TldTaglib parseTld(InputStream is)
620: throws JspParseException, IOException {
621: TldTaglib taglib = new TldTaglib();
622:
623: if (is instanceof ReadStream) {
624: Path path = ((ReadStream) is).getPath();
625:
626: path.setUserPath(path.getURL());
627: }
628:
629: String schema = null;
630:
631: if (_webApp.getJsp() == null
632: || _webApp.getJsp().isValidateTaglibSchema()) {
633: schema = getSchema();
634: }
635:
636: try {
637: Config config = new Config();
638: config.setEL(false);
639: config.configure(taglib, is, schema);
640: } catch (ConfigException e) {
641: log.warning(e.toString());
642: log.log(Level.FINER, e.toString(), e);
643:
644: taglib.setConfigException(e);
645: } catch (Exception e) {
646: log.warning(e.toString());
647: log.log(Level.FINER, e.toString(), e);
648:
649: taglib.setConfigException(e);
650: } finally {
651: is.close();
652: }
653:
654: /* XXX: jsp/18n0 handled on init
655: try {
656: taglib.init(_webApp);
657: } catch (Exception e) {
658: throw new JspParseException(e);
659: }
660: */
661:
662: return taglib;
663: }
664:
665: /**
666: * Parses the .tld
667: *
668: * @param path location of the taglib
669: */
670: private TldPreload parseTldPreload(Path path)
671: throws JspParseException, IOException {
672: ReadStream is = path.openRead();
673:
674: try {
675: TldPreload taglib = parseTldPreload(is);
676:
677: taglib.setPath(path);
678: String appDir = _webApp.getAppDir().getPath();
679: String tagPath = path.getPath();
680:
681: if (tagPath.startsWith(appDir))
682: taglib.setLocation(tagPath.substring(appDir.length()));
683:
684: return taglib;
685: } finally {
686: is.close();
687: }
688: }
689:
690: /**
691: * Parses the .tld
692: *
693: * @param is the input stream to the taglib
694: */
695: private TldPreload parseTldPreload(InputStream is)
696: throws JspParseException, IOException {
697: boolean isJsfTld = false;
698:
699: if (is instanceof ReadStream) {
700: Path path = ((ReadStream) is).getPath();
701:
702: isJsfTld = path.getPath().endsWith(".ftld");
703:
704: path.setUserPath(path.getURL());
705: }
706:
707: String schema = null;
708:
709: if (_webApp.getJsp() == null
710: || _webApp.getJsp().isValidateTaglibSchema()) {
711: schema = getSchema();
712: }
713:
714: TldPreload taglib;
715:
716: if (isJsfTld)
717: taglib = new JsfTldPreload();
718: else
719: taglib = new TldPreload();
720:
721: try {
722: _config.configure(taglib, is, schema);
723: } catch (ConfigException e) {
724: log.warning(e.toString());
725: log.log(Level.FINER, e.toString(), e);
726:
727: taglib.setConfigException(e);
728: } catch (Exception e) {
729: log.warning(e.toString());
730: log.log(Level.FINER, e.toString(), e);
731:
732: taglib.setConfigException(e);
733: } finally {
734: is.close();
735: }
736:
737: return taglib;
738: }
739:
740: /**
741: * Finds the path to the jar specified by the location.
742: *
743: * @param location the tag-location specified in the web.xml
744: *
745: * @return the found jar or null
746: */
747: private Path findJar(String location) {
748: Path path;
749:
750: if (location.startsWith("file:"))
751: path = Vfs.lookup(location);
752: else if (location.startsWith("/"))
753: path = _resourceManager.resolvePath("." + location);
754: else
755: path = _resourceManager.resolvePath(location);
756:
757: if (path.exists())
758: return path;
759:
760: DynamicClassLoader loader;
761: loader = (DynamicClassLoader) Thread.currentThread()
762: .getContextClassLoader();
763: String classPath = loader.getClassPath();
764: char sep = CauchoSystem.getPathSeparatorChar();
765:
766: int head = 0;
767: int tail = 0;
768:
769: while ((tail = classPath.indexOf(sep, head)) >= 0) {
770: String sub = classPath.substring(head, tail);
771:
772: path = Vfs.lookup(sub);
773:
774: if (sub.endsWith(location) && path.exists())
775: return path;
776:
777: head = tail + 1;
778: }
779:
780: if (classPath.length() <= head)
781: return null;
782:
783: String sub = classPath.substring(head);
784:
785: path = Vfs.lookup(sub);
786:
787: if (sub.endsWith(location) && path.exists())
788: return path;
789: else
790: return null;
791: }
792:
793: /**
794: * Adds the classpath as paths in the MergePath.
795: */
796: private ArrayList<Path> getClassPath() {
797: return getClassPath(Thread.currentThread()
798: .getContextClassLoader());
799: }
800:
801: /**
802: * Adds the classpath for the loader as paths in the MergePath.
803: *
804: * @param loader class loader whose classpath should be used to search.
805: */
806: private ArrayList<Path> getClassPath(ClassLoader loader) {
807: String classpath = null;
808:
809: if (loader instanceof DynamicClassLoader)
810: classpath = ((DynamicClassLoader) loader).getClassPath();
811: else
812: classpath = CauchoSystem.getClassPath();
813:
814: return getClassPath(classpath);
815: }
816:
817: /**
818: * Adds the classpath for the loader as paths in the MergePath.
819: *
820: * @param classpath class loader whose classpath should be used to search.
821: */
822: private ArrayList<Path> getClassPath(String classpath) {
823: ArrayList<Path> list = new ArrayList<Path>();
824:
825: char sep = CauchoSystem.getPathSeparatorChar();
826: int head = 0;
827: int tail = 0;
828: while (head < classpath.length()) {
829: tail = classpath.indexOf(sep, head);
830:
831: String segment = null;
832: if (tail < 0) {
833: segment = classpath.substring(head);
834: head = classpath.length();
835: } else {
836: segment = classpath.substring(head, tail);
837: head = tail + 1;
838: }
839:
840: if (!segment.equals("")) {
841: Path path = Vfs.lookup(segment);
842:
843: if (!list.contains(path))
844: list.add(path);
845: }
846: }
847:
848: return list;
849: }
850: }
|