Source Code Cross Referenced for TclClassLoader.java in  » Scripting » jacl » tcl » lang » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Scripting » jacl » tcl.lang 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /* 
0002:         * TclClassLoader.java --
0003:         *
0004:         *	Implements the Class Loader for dynamically loading
0005:         *      Tcl packages.  When attempting to resolve and load a
0006:         *      new Package the loader looks in four places to find
0007:         *      the class.  In order they are:
0008:         *
0009:         *          1) The unique cache, "classes", inside the TclClassLoader.
0010:         *          2) Using the system class loader (via the context class loader).
0011:         *          3) Any paths passed into the constructor via the pathList variable.
0012:         *          4) Any path in the interps env(TCL_CLASSPATH) variable.
0013:         *
0014:         *      The class will be found if it is any of the above paths
0015:         *      or if it is in a jar file located in one of the paths.
0016:         *
0017:         * TclClassLoader.java --
0018:         *
0019:         *      A class that helps filter directory listings when
0020:         *      for jar/zip files during the class resolution stage.
0021:         *
0022:         * Copyright (c) 1997 by Sun Microsystems, Inc.
0023:         *
0024:         * See the file "license.terms" for information on usage and redistribution
0025:         * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
0026:         *
0027:         * RCS: @(#) $Id: TclClassLoader.java,v 1.15 2006/09/11 20:45:30 mdejong Exp $
0028:         */
0029:
0030:        package tcl.lang;
0031:
0032:        import java.util.*;
0033:        import java.util.zip.*;
0034:        import java.io.*;
0035:        import java.net.URL;
0036:
0037:        class TclClassLoader extends ClassLoader {
0038:
0039:            // Cache of classes loaded by this class loader. Typically, a
0040:            // class loader is defined on a per-interp basis, so this
0041:            // will cache instances of class data for each access in
0042:            // the interp. Different interpreters require different
0043:            // caches since the same class name could be loaded from
0044:            // two different locations in different interps.
0045:
0046:            private HashMap class_cache = new HashMap();
0047:
0048:            // Each instance can have a list of additional paths to search.  This
0049:            // needs to be stored on a per instance basis because classes may be
0050:            // resolved at later times.  classpath is passed into the constructor,
0051:            // and loadpath is extracted from the env(TCL_CLASSPATH) interp variable.
0052:
0053:            private String[] classpath = null;
0054:            private String[] loadpath = null;
0055:            private String cached_tclclasspath = null;
0056:
0057:            // Used only for error reporting when something went wrong with a class
0058:            // that was loaded out of a jar and we want to know which jar. Will
0059:            // be null unless the last searched class was found in a jar.
0060:
0061:            private String lastSearchedClassFile = null;
0062:            private String lastSearchedJarFile = null;
0063:
0064:            // Pointer to parent class loader. This value will never be null.
0065:
0066:            private ClassLoader parent;
0067:
0068:            // Pointer to interp, non-null when the value of env(TCL_CLASSPATH)
0069:            // should be used and checked for updates.
0070:
0071:            private Interp interp = null;
0072:
0073:            /*
0074:             *----------------------------------------------------------------------
0075:             *
0076:             * TclClassLoader --
0077:             *
0078:             *	TclClassLoader searches a possible -classpath path and the
0079:             *	env(TCL_CLASSPATH) path for classes and resources to load.
0080:             *	A TclClassLoader is defined on a per-interp basis, if a
0081:             *	specific command needs to search additional paths then
0082:             *	that search is done in a TclClassLoader() that has
0083:             *	the interp class loader as a parent. Note that a TclClassLoader
0084:             *	will always have a non-null parent.
0085:             *
0086:             *      The list of paths in pathList and env(TCL_CLASSPATH) can be relative
0087:             *      to the current interp dir.  The full path names are resolved,
0088:             *      before they are stored.
0089:             *
0090:             * Results:
0091:             *	None.
0092:             *
0093:             * Side effects:
0094:             *	Creates a new TclClassLoader object.
0095:             *
0096:             *----------------------------------------------------------------------
0097:             */
0098:
0099:            TclClassLoader(Interp interp, // Used to get env(TCL_CLASSPATH) and current
0100:                    // working dir
0101:                    TclObject pathList, // List of additional paths to search
0102:                    ClassLoader parent) // parent ClassLoader
0103:            {
0104:                super (parent);
0105:                if (parent == null) {
0106:                    throw new TclRuntimeError(
0107:                            "parent ClassLoader can't be null");
0108:                }
0109:                this .parent = parent;
0110:                this .interp = interp;
0111:                init(interp, pathList);
0112:            }
0113:
0114:            /*
0115:             *----------------------------------------------------------------------
0116:             *
0117:             * init --
0118:             *
0119:             *	TclClassLoader stores the values to classpath and env(TCL_CLASSPATH)
0120:             *      on a per object basis.  This is necessary because classes 
0121:             *      may not be loaded immediately, but classpath and loadpath
0122:             *      may change over time, or from object to to object.
0123:             *
0124:             *      The list of paths in pathList and env(TCL_CLASSPATH) can be relative
0125:             *      to the current interp dir.  The full path names are resolved,
0126:             *      before they are stored.
0127:             *
0128:             * Results:
0129:             *	
0130:             *
0131:             * Side effects:
0132:             *	
0133:             *
0134:             *----------------------------------------------------------------------
0135:             */
0136:
0137:            private void init(Interp interp, // Used to get env(TCL_CLASSPATH) and current
0138:                    // working dir
0139:                    TclObject pathList) // List of additional paths to search
0140:            {
0141:                TclObject[] elem;
0142:                int i;
0143:
0144:                try {
0145:                    boolean searchTclClasspath = true;
0146:
0147:                    // A TclClassLoader that is a child of the interp class loader
0148:                    // will search only on a passed in -classpath not env(TCL_CLASSPATH).
0149:
0150:                    if (parent instanceof  TclClassLoader) {
0151:                        if (pathList == null) {
0152:                            throw new TclRuntimeError(
0153:                                    "TclClassLoader is a child of the interp "
0154:                                            + "class loader but it does not have a -classpath to search");
0155:                        }
0156:                        searchTclClasspath = false;
0157:                    }
0158:
0159:                    if (pathList != null) {
0160:                        elem = TclList.getElements(interp, pathList);
0161:                        classpath = new String[elem.length];
0162:                        for (i = 0; i < elem.length; i++) {
0163:                            classpath[i] = absolutePath(interp, elem[i]
0164:                                    .toString());
0165:                        }
0166:                    }
0167:
0168:                    if (searchTclClasspath) {
0169:                        checkTclClasspath();
0170:                    }
0171:                } catch (TclException e) {
0172:                }
0173:            }
0174:
0175:            // Check the env(TCL_CLASSPATH) variable to see if it has changed since
0176:            // the last invocation. In the init case, the loadpath array is null.
0177:
0178:            private void checkTclClasspath() {
0179:                final boolean debug = false;
0180:                TclObject[] elems = null;
0181:
0182:                if (debug) {
0183:                    System.out.println("checkTclClasspath()");
0184:                }
0185:
0186:                try {
0187:                    TclObject tobj = interp.getVar("env", "TCL_CLASSPATH",
0188:                            TCL.GLOBAL_ONLY);
0189:                    String current_tclclasspath = tobj.toString();
0190:                    if (debug) {
0191:                        System.out.println("current_tclclasspath is: "
0192:                                + current_tclclasspath);
0193:                    }
0194:
0195:                    // env(TCL_CLASSPATH) is set to ""
0196:
0197:                    if (current_tclclasspath.length() == 0) {
0198:                        if (debug) {
0199:                            System.out.println("env(TCL_CLASSPATH) is \"\"");
0200:                        }
0201:
0202:                        cached_tclclasspath = "";
0203:                        loadpath = null;
0204:                        return;
0205:                    }
0206:
0207:                    if (debug) {
0208:                        System.out.println("comparing \"" + cached_tclclasspath
0209:                                + "\" to \"" + current_tclclasspath + "\"");
0210:                    }
0211:
0212:                    if ((cached_tclclasspath == null)
0213:                            || !current_tclclasspath
0214:                                    .equals(cached_tclclasspath)) {
0215:                        // env(TCL_CLASSPATH) has changed, reset cache and reparse
0216:
0217:                        if (debug) {
0218:                            System.out.println("resetting cache");
0219:                        }
0220:
0221:                        cached_tclclasspath = current_tclclasspath;
0222:                        elems = TclList.getElements(interp, tobj);
0223:                    }
0224:                } catch (TclException e) {
0225:                    // env(TCL_CLASSPATH) not set
0226:
0227:                    if (debug) {
0228:                        System.out
0229:                                .println("env(TCL_CLASSPATH) not set, TclException was: "
0230:                                        + e.getMessage());
0231:                    }
0232:
0233:                    interp.resetResult();
0234:                    cached_tclclasspath = null;
0235:                    loadpath = null;
0236:                    return;
0237:                }
0238:
0239:                if (elems == null) {
0240:                    // env(TCL_CLASSPATH) is the same value it was before
0241:
0242:                    if (debug) {
0243:                        System.out.println("env(TCL_CLASSPATH) unchanged");
0244:                    }
0245:                    return;
0246:                } else {
0247:                    // env(TCL_CLASSPATH) was changed, reparse path
0248:
0249:                    if (debug) {
0250:                        System.out
0251:                                .println("env(TCL_CLASSPATH) changed, reparsing");
0252:                    }
0253:
0254:                    loadpath = new String[elems.length];
0255:                    for (int i = 0; i < elems.length; i++) {
0256:                        loadpath[i] = absolutePath(interp, elems[i].toString());
0257:                    }
0258:                }
0259:            }
0260:
0261:            /*
0262:             *----------------------------------------------------------------------
0263:             *
0264:             * loadClass --
0265:             *
0266:             *	Resolves the specified name to a Class. This method differs
0267:             *      from the regular loadClass(String) because it always passes a
0268:             *      true resolveIt argument to loadClass(String, boolean).
0269:             *
0270:             * Results:
0271:             *	the resolved Class, or null if it was not found.
0272:             *
0273:             * Side effects:
0274:             *	ClassNotFoundException  if the class loader cannot find
0275:             *      a definition for the class.
0276:             *
0277:             *----------------------------------------------------------------------
0278:             */
0279:
0280:            public Class loadClass(String className) // The name of the desired Class.
0281:                    throws ClassNotFoundException, // The class could not be found.
0282:                    PackageNameException // The class is in the java or tcl package
0283:            // but it could not be loaded by system loader.
0284:            {
0285:                return loadClass(className, true);
0286:            }
0287:
0288:            /*
0289:             *----------------------------------------------------------------------
0290:             *
0291:             * loadClass --
0292:             *
0293:             *	Resolves the specified name to a Class. The method loadClass() is 
0294:             *      called by the JavaLoadCmd and via Interp.loadClass().
0295:             *
0296:             * Results:
0297:             *	the resolved Class, or null if it was not found.
0298:             *
0299:             * Side effects:
0300:             *	ClassNotFoundException  if the class loader cannot find
0301:             *      a definition for the class.
0302:             *
0303:             *----------------------------------------------------------------------
0304:             */
0305:
0306:            protected Class loadClass(String className, // The name of the desired Class.
0307:                    boolean resolveIt) // If true, then resolve all referenced classes.
0308:                    throws ClassNotFoundException, // The class could not be found.
0309:                    PackageNameException, // The classes package starts with java or tcl prefix.
0310:                    SecurityException // If something goes terribly wrong in defineClass().
0311:            {
0312:                Class result; // The Class that is loaded.             
0313:                byte[] classData = null; // The bytes that compose the class file.
0314:
0315:                final boolean debug = false;
0316:                final boolean printStack = false;
0317:
0318:                if (debug) {
0319:                    System.out.println("loadClass " + className);
0320:                }
0321:
0322:                // Check our local cache of classes 
0323:
0324:                result = (Class) class_cache.get(className);
0325:                if (result != null) {
0326:                    if (debug) {
0327:                        System.out.println("found class_cache entry for key "
0328:                                + className);
0329:                    }
0330:                    return result;
0331:                } else {
0332:                    if (debug) {
0333:                        System.out.println("no class_cache entry for key "
0334:                                + className);
0335:                    }
0336:                }
0337:
0338:                // Resolve with parent ClassLoader to see if it can resolve the class.
0339:                // The parent could be the system class loader, a thread context
0340:                // class loader, or the TclClassLoader for a specific interp.
0341:
0342:                try {
0343:                    if (debug) {
0344:                        if (parent == getSystemClassLoader()) {
0345:                            System.out
0346:                                    .println("Parent ClassLoader is SystemClassLoader");
0347:                        } else if (parent == Thread.currentThread()
0348:                                .getContextClassLoader()) {
0349:                            System.out
0350:                                    .println("Parent ClassLoader is ContextClassLoader");
0351:                        } else if (parent instanceof  TclClassLoader) {
0352:                            System.out
0353:                                    .println("Parent ClassLoader is interp TclClassLoader");
0354:                        } else {
0355:                            System.out.println("Parent ClassLoader is of type "
0356:                                    + parent.getClass().toString());
0357:                        }
0358:                        System.out.println("parent attempting load of class \""
0359:                                + className + "\"");
0360:                    }
0361:
0362:                    result = Class.forName(className, resolveIt, parent);
0363:
0364:                    // Don't cache classes resolved by a parent class loader, we assume the
0365:                    // parent will do any needed caching.
0366:
0367:                    if (debug) {
0368:                        System.out.println("parent load worked for class \""
0369:                                + className + "\"");
0370:                    }
0371:
0372:                    return result;
0373:                } catch (ClassNotFoundException e) {
0374:                    if (printStack) {
0375:                        e.printStackTrace(System.err);
0376:                    }
0377:                } catch (IllegalArgumentException e) {
0378:                    if (printStack) {
0379:                        e.printStackTrace(System.err);
0380:                    }
0381:                } catch (NoClassDefFoundError e) {
0382:                    if (printStack) {
0383:                        e.printStackTrace(System.err);
0384:                    }
0385:                } catch (IncompatibleClassChangeError e) {
0386:                    if (printStack) {
0387:                        e.printStackTrace(System.err);
0388:                    }
0389:                }
0390:
0391:                if (debug) {
0392:                    System.out.println("parent load did not work for class \""
0393:                            + className + "\"");
0394:                }
0395:
0396:                // Protect against attempts to load a class that contains the 'java'
0397:                // or 'tcl' prefix, but is not in the corresponding file structure.
0398:
0399:                if ((className.startsWith("java."))
0400:                        || (className.startsWith("tcl."))) {
0401:                    throw new PackageNameException(
0402:                            "Java loader failed to load the class "
0403:                                    + "and the TclClassLoader is not permitted to "
0404:                                    + "load classes in the tcl or java package at runtime, "
0405:                                    + "check your CLASSPATH.", className);
0406:                }
0407:
0408:                if (debug) {
0409:                    System.out
0410:                            .println("TclClassLoader attempting search for class \""
0411:                                    + className + "\"");
0412:                    if (classpath != null) {
0413:                        System.out.println("classpath is defined");
0414:                    } else {
0415:                        System.out.println("classpath is null");
0416:                    }
0417:                    if (loadpath != null) {
0418:                        System.out.println("loadpath is defined");
0419:                    } else {
0420:                        System.out.println("loadpath is null");
0421:                    }
0422:
0423:                }
0424:
0425:                // Try to load class from -classpath if it exists
0426:
0427:                if (classpath != null) {
0428:                    classData = getClassFromPath(classpath, className);
0429:                }
0430:                if (classData == null) {
0431:                    // -classpath does not exists or class was not found.
0432:                    // Check to see if env(TCL_CLASSPATH) was changed
0433:                    // since the last lookup and then search it for
0434:                    // possible matches.
0435:
0436:                    checkTclClasspath();
0437:                    if (loadpath != null) {
0438:                        classData = getClassFromPath(loadpath, className);
0439:                    }
0440:                }
0441:
0442:                if (classData == null) {
0443:                    throw new ClassNotFoundException(className);
0444:                }
0445:
0446:                // Define it (parse the class file)
0447:
0448:                // we have to include this catch for java.lang.NoClassDefFoundError
0449:                // because Sun seems to have changed the Spec for JDK 1.2
0450:                try {
0451:                    result = defineClass(className, classData, 0,
0452:                            classData.length);
0453:                } catch (NoClassDefFoundError err) {
0454:                    throw new ClassFormatError();
0455:                } catch (ClassFormatError err) {
0456:                    // This exception can be generated when the className argument
0457:                    // does not match the actual name of the class. For instance
0458:                    // if we try to define Test.class with data from tester/Test.class
0459:                    // we will get this error. Sadly, there does not seem to be any
0460:                    // to find out the real name of the class without knowing the
0461:                    // format of the .class file and parsing it.
0462:
0463:                    StringBuffer buf = new StringBuffer(50);
0464:                    buf.append(err.getMessage());
0465:                    buf.append(". ");
0466:                    if (lastSearchedClassFile != null) {
0467:                        buf.append(lastSearchedClassFile);
0468:                    } else {
0469:                        buf.append(className);
0470:                    }
0471:
0472:                    if (lastSearchedJarFile != null) {
0473:                        buf.append(" loaded from ");
0474:                        buf.append(lastSearchedJarFile);
0475:                    }
0476:
0477:                    buf.append(": class name does not match");
0478:                    buf.append(" the name defined in the classfile");
0479:
0480:                    throw new ClassFormatError(buf.toString());
0481:                }
0482:
0483:                if (result == null) {
0484:                    throw new ClassFormatError();
0485:                }
0486:                if (resolveIt) {
0487:                    resolveClass(result);
0488:                }
0489:
0490:                // Store it in our local cache
0491:
0492:                if (debug) {
0493:                    System.out.println("added class_cache entry for key "
0494:                            + className);
0495:                }
0496:
0497:                class_cache.put(className, result);
0498:
0499:                return result;
0500:            }
0501:
0502:            /*
0503:             *----------------------------------------------------------------------
0504:             *
0505:             * findResource --
0506:             *
0507:             *	Resolves the specified resource name to a URL via
0508:             *	a search of env(TCL_CLASSPATH). This method is
0509:             *	invoked by getResource() when a resource has not
0510:             *	been found by the system loader or the parent loader.
0511:             *
0512:             * Results:
0513:             *	the resolved URL, or null if it was not found.
0514:             *
0515:             * Side effects:
0516:             *	None.
0517:             *
0518:             *----------------------------------------------------------------------
0519:             */
0520:
0521:            protected URL findResource(String resName) // The name of the desired resource.
0522:                    throws PackageNameException // In case resource starts with java or tcl prefix
0523:            {
0524:                final boolean debug = false;
0525:                URL result = null;
0526:
0527:                if (debug) {
0528:                    System.out.println("findResource " + resName);
0529:                }
0530:
0531:                // FIXME: Support for relative resources with dots between them
0532:                // should be implemented and tested.
0533:
0534:                // Only know how to resolve absolute resources via TCL_CLASSPATH.
0535:
0536:                if (resName.length() == 0 || resName.charAt(0) != '/') {
0537:                    return null;
0538:                }
0539:                resName = resName.substring(1);
0540:
0541:                // Can't load resources that start with "java/" or "tcl/",
0542:                // these should have been resolved with the system loader.
0543:
0544:                if ((resName.startsWith("java/"))
0545:                        || (resName.startsWith("tcl/"))) {
0546:                    throw new PackageNameException("Can't load resource \""
0547:                            + resName
0548:                            + "\" with java or tcl prefix via TCL_CLASSPATH",
0549:                            resName);
0550:                }
0551:
0552:                if (debug) {
0553:                    System.out
0554:                            .println("TclClassLoader attempting search for resource \""
0555:                                    + resName + "\"");
0556:                    if (classpath != null) {
0557:                        System.out.println("classpath is defined");
0558:                    } else {
0559:                        System.out.println("classpath is null");
0560:                    }
0561:                    if (loadpath != null) {
0562:                        System.out.println("loadpath is defined");
0563:                    } else {
0564:                        System.out.println("loadpath is null");
0565:                    }
0566:                }
0567:
0568:                // Try to load URL from -classpath if it exists
0569:
0570:                if (classpath != null) {
0571:                    result = getURLFromPath(classpath, resName);
0572:                }
0573:                if (result == null) {
0574:                    // -classpath does not exists or class was not found.
0575:                    // Check to see if env(TCL_CLASSPATH) was changed
0576:                    // since the last lookup and then search it for
0577:                    // possible matches.
0578:
0579:                    checkTclClasspath();
0580:                    if (loadpath != null) {
0581:                        result = getURLFromPath(loadpath, resName);
0582:                    }
0583:                }
0584:
0585:                return result;
0586:
0587:                // FIXME: May also need to overload findResources() in order to
0588:                // get the proper resource loading WRT parents working. This
0589:                // would need to return a whole mess of URL objects, not sure
0590:                // how wasteful that is.
0591:            }
0592:
0593:            /*
0594:             *----------------------------------------------------------------------
0595:             *
0596:             * getResource --
0597:             *
0598:             *	Attempt to resolve a resource using the parent class loader
0599:             *	and then the tcl class loader. This method seems to be
0600:             *	needed because the JDK is not behaving the way it should
0601:             *	as it is not loading resources from the parent.
0602:             *
0603:             * Results:
0604:             *	the resolved URL, or null if it was not found.
0605:             *
0606:             * Side effects:
0607:             *	None.
0608:             *
0609:             *----------------------------------------------------------------------
0610:             */
0611:
0612:            public URL getResource(String resName) // The name of the desired resource.
0613:            {
0614:                final boolean debug = false;
0615:
0616:                URL res = null;
0617:
0618:                if (debug) {
0619:                    System.out.println("TclClassLoader.getResource(): "
0620:                            + resName);
0621:
0622:                    if (parent == getSystemClassLoader()) {
0623:                        System.out.println("parent is SystemClassLoader");
0624:                    }
0625:                    if (Interp.class.getClassLoader() == getSystemClassLoader()) {
0626:                        System.out
0627:                                .println("interp loader is SystemClassLoader");
0628:                    }
0629:                }
0630:
0631:                // Resource searching is kind of tricky. Calling Class.getResource()
0632:                // will search in the jar that the class was loaded from. This does
0633:                // not appear to be very well documented and was found only via
0634:                // testing the runtime impl. Note that this is not the same as
0635:                // calling Interp.class.getClassLoader().getResource() which
0636:                // will not search in the jar from the CLASSPATH.
0637:
0638:                if (res == null) {
0639:                    // Search in tcljava.jar, jacl.jar, or tclblend.jar.
0640:                    res = Interp.class.getResource(resName);
0641:
0642:                    if (debug) {
0643:                        if (res == null) {
0644:                            System.out
0645:                                    .println("did not find resource with jar visibility");
0646:                        } else {
0647:                            System.out
0648:                                    .println("found resource with jar visibility");
0649:                        }
0650:                    }
0651:                }
0652:
0653:                if (res == null) {
0654:                    // Search in parent class loader
0655:                    res = parent.getResource(resName);
0656:
0657:                    if (debug) {
0658:                        if (res == null) {
0659:                            System.out
0660:                                    .println("did not find resource in parent");
0661:                        } else {
0662:                            System.out.println("found resource in parent");
0663:                        }
0664:                    }
0665:                }
0666:
0667:                if (res == null) {
0668:                    // Search on env(TCL_CLASSPATH)
0669:                    res = findResource(resName);
0670:
0671:                    if (debug) {
0672:                        if (res == null) {
0673:                            System.out
0674:                                    .println("did not find resource in tcl class loader");
0675:                        } else {
0676:                            System.out
0677:                                    .println("found resource in tcl class loader");
0678:                        }
0679:                    }
0680:                }
0681:
0682:                return res;
0683:            }
0684:
0685:            /*
0686:             *----------------------------------------------------------------------
0687:             *
0688:             * defineClass --
0689:             *
0690:             *	Given an array of bytes that define a class, create the Class.
0691:             *      If the className is null, we are creating a lambda class.
0692:             *      Otherwise cache the className and definition in the loaders
0693:             *      cache.
0694:             *
0695:             * Results:
0696:             *	A Class object or null if it could not be defined.
0697:             *
0698:             * Side effects:
0699:             *	Cache the Class object in the classes Hashtable.
0700:             *
0701:             *----------------------------------------------------------------------
0702:             */
0703:
0704:            Class defineClass(String className, // Name of the class, possibly null.
0705:                    byte[] classData) // Binary data of the class structure.
0706:            {
0707:                Class result = null; // The Class object defined by classData.
0708:
0709:                // Create a class from the array of bytes
0710:
0711:                try {
0712:                    result = defineClass(null, classData, 0, classData.length);
0713:                } catch (ClassFormatError ex) {
0714:                    // Don't allow this exception to terminate execution, but
0715:                    // print some debug info to stderr since this will likely
0716:                    // be cause by a compiler bug and we want to know about that.
0717:
0718:                    System.err.println("TclClassLoader.defineClass():");
0719:                    System.err.println(ex.getClass().getName() + ": "
0720:                            + ex.getMessage());
0721:                } catch (LinkageError ex) {
0722:                    // Don't allow this exception to terminate execution, but
0723:                    // print some debug info to stderr since this will likely
0724:                    // be cause by a compiler bug and we want to know about that.
0725:
0726:                    System.err.println("TclClassLoader.defineClass():");
0727:                    System.err.println(ex.getClass().getName() + ": "
0728:                            + ex.getMessage());
0729:                }
0730:
0731:                if (result != null) {
0732:                    // If the name of the class is null, extract the className
0733:                    // from the Class object, and use that as the key.
0734:
0735:                    if (className == null) {
0736:                        className = result.getName();
0737:                    }
0738:
0739:                    // If a class was created,  then store the class
0740:                    // in the loaders cache.
0741:
0742:                    class_cache.put(className, result);
0743:                }
0744:
0745:                return (result);
0746:            }
0747:
0748:            /*
0749:             *----------------------------------------------------------------------
0750:             *
0751:             * getClassFromPath --
0752:             *
0753:             *	At this point, the class wasn't found in the cache or by the
0754:             *      parent loader.  Search through 'classpath' list and the 
0755:             *      Tcl environment TCL_CLASSPATH to see if the class file can be 
0756:             *      found and resolved.  If ".jar" or ".zip" files are found, 
0757:             *      search them for the class as well.
0758:             *
0759:             * Results:
0760:             *	an array of bytes that is the content of the className
0761:             *      file.  null is returned if the class could not be 
0762:             *      found or resolved (e.g. permissions error).
0763:             *
0764:             * Side effects:
0765:             *	None.
0766:             *
0767:             *----------------------------------------------------------------------
0768:             */
0769:
0770:            private byte[] getClassFromPath(String[] paths, String className) // the name of the class trying to be resolved
0771:            {
0772:                final boolean debug = false;
0773:                int i = 0;
0774:                byte[] classData = null; // The bytes that compose the class file.
0775:                String curDir; // The directory to search for the class file.
0776:                File file; // The class file.                            
0777:                int total; // Total number of bytes read from the stream
0778:
0779:                if (debug) {
0780:                    System.out.println("getClassFromPath for " + className);
0781:                }
0782:
0783:                // Search through the list of "paths" for the className.  
0784:                // ".jar" or ".zip" files found in the path will also be 
0785:                // searched.  Yhe first occurence found is returned.
0786:                lastSearchedClassFile = null;
0787:                lastSearchedJarFile = null;
0788:
0789:                if (paths != null) {
0790:                    // When the class being loaded implements other classes that are
0791:                    // not yet loaded, the TclClassLoader will recursively call this
0792:                    // procedure.  However the format of the class name is 
0793:                    // foo.bar.name and it needs to be foo/bar/name.  Convert to 
0794:                    // proper format.
0795:
0796:                    className = className.replace('.', '/') + ".class";
0797:
0798:                    for (i = 0; i < paths.length; i++) {
0799:                        curDir = paths[i].toString();
0800:                        try {
0801:                            if ((curDir.endsWith(".jar"))
0802:                                    || (curDir.endsWith(".zip"))) {
0803:                                // If curDir points to a jar file, search it
0804:                                // for the class.  If classData is not null
0805:                                // then the class was found in the jar file.
0806:
0807:                                classData = extractClassFromJar(curDir,
0808:                                        className);
0809:                                if (classData != null) {
0810:                                    return (classData);
0811:                                }
0812:                            } else {
0813:                                // If curDir and className point to an existing file,
0814:                                // then the class is found.  Extract the bytes from 
0815:                                // the file.
0816:
0817:                                file = new File(curDir, className);
0818:                                if (file.exists()) {
0819:                                    FileInputStream fi = new FileInputStream(
0820:                                            file);
0821:                                    classData = new byte[fi.available()];
0822:
0823:                                    total = fi.read(classData);
0824:                                    while (total != classData.length) {
0825:                                        total += fi.read(classData, total,
0826:                                                (classData.length - total));
0827:
0828:                                    }
0829:
0830:                                    // Set this so we can get the full name of the
0831:                                    // file we loaded the class from later
0832:                                    lastSearchedClassFile = file.toString();
0833:
0834:                                    return (classData);
0835:                                }
0836:                            }
0837:                        } catch (Exception e) {
0838:                            // No error thrown, because the class may be found
0839:                            // in subsequent paths.
0840:                        }
0841:                    }
0842:                    for (i = 0; i < paths.length; i++) {
0843:                        curDir = paths[i].toString();
0844:                        try {
0845:                            // The class was not found in the paths list.
0846:                            // Search all the directories in paths for 
0847:                            // any jar files, in an attempt to locate
0848:                            // the class inside a jar file.
0849:
0850:                            classData = getClassFromJar(curDir, className);
0851:
0852:                            if (classData != null) {
0853:                                return classData;
0854:                            }
0855:                        } catch (Exception e) {
0856:                            // No error thrown, because the class may be found
0857:                            // in subsequent paths.
0858:                        }
0859:                    }
0860:                }
0861:
0862:                // No matching classes found.
0863:
0864:                return null;
0865:            }
0866:
0867:            /*
0868:             *----------------------------------------------------------------------
0869:             *
0870:             * getClassFromJar --
0871:             *
0872:             *	Given a directory and a class to be found, get a list of 
0873:             *      ".jar" or ".zip" files in the current directory.  Call
0874:             *      extractClassFromJar to search the Jar file and extract 
0875:             *      the class if a match is found.
0876:             *
0877:             * Results:
0878:             *	An array of bytes that is the content of the className
0879:             *      file.  null is returned if the class could not be
0880:             *      resolved or found. 
0881:             *
0882:             * Side effects:
0883:             *	None.
0884:             *
0885:             *----------------------------------------------------------------------
0886:             */
0887:
0888:            private byte[] getClassFromJar(String curDir, // An absoulte path for a directory to search 
0889:                    String className) // The name of the class to extract from the jar file.
0890:                    throws IOException {
0891:                byte[] result = null; // The bytes that compose the class file.
0892:                String[] jarFiles; // The list of files in the curDir.
0893:                JarFilenameFilter jarFilter; // Filter the jarFiles list by only     
0894:                // accepting ".jar" or ".zip"
0895:
0896:                File file = new File(curDir);
0897:
0898:                if (!file.isDirectory()) {
0899:                    return null;
0900:                }
0901:
0902:                jarFilter = new JarFilenameFilter();
0903:                jarFiles = file.list(jarFilter);
0904:
0905:                if (jarFiles == null) {
0906:                    return null;
0907:                }
0908:
0909:                for (int i = 0; i < jarFiles.length; i++) {
0910:                    result = extractClassFromJar(curDir + File.separatorChar
0911:                            + jarFiles[i], className);
0912:                    if (result != null) {
0913:                        break;
0914:                    }
0915:                }
0916:                return result;
0917:            }
0918:
0919:            /*
0920:             *----------------------------------------------------------------------
0921:             *
0922:             * extractClassFromJar --
0923:             *
0924:             *	Look inside the jar file, jarName, for a ZipEntry that
0925:             *      matches the className.  If a match is found extract the
0926:             *      bytes from the input stream.
0927:             *
0928:             * Results:
0929:             *	An array of bytes that is the content of the className
0930:             *      file.  null is returned if the class could not be
0931:             *      resolved or found.
0932:             *
0933:             * Side effects:
0934:             *	None.
0935:             *
0936:             *----------------------------------------------------------------------
0937:             */
0938:
0939:            private byte[] extractClassFromJar(String jarName, // An absoulte path for a jar file to search.
0940:                    String className) // The name of the class to extract from the jar file.
0941:                    throws IOException {
0942:                final boolean debug = false;
0943:                ZipInputStream zin; // The jar file input stream.
0944:                ZipEntry entry; // A file contained in the jar file.
0945:                byte[] result; // The bytes that compose the class file.
0946:                int size; // Uncompressed size of the class file.
0947:                int total; // Number of bytes read from class file.
0948:
0949:                if (debug) {
0950:                    System.out.println("searching for " + className + " in "
0951:                            + jarName);
0952:                }
0953:
0954:                zin = new ZipInputStream(new FileInputStream(jarName));
0955:
0956:                try {
0957:                    while ((entry = zin.getNextEntry()) != null) {
0958:                        // see if the current ZipEntry's name equals 
0959:                        // the file we want to extract. If equal
0960:                        // get the extract and return the contents of the file.
0961:
0962:                        if (className.equals(entry.getName())) {
0963:                            size = getEntrySize(jarName, className);
0964:                            result = new byte[size];
0965:                            total = zin.read(result);
0966:                            while (total != size) {
0967:                                total += zin
0968:                                        .read(result, total, (size - total));
0969:                            }
0970:
0971:                            // Set these so we can determine which
0972:                            // Jar a class was extracted from later
0973:                            lastSearchedClassFile = className;
0974:                            lastSearchedJarFile = jarName;
0975:
0976:                            if (debug) {
0977:                                System.out.println("class " + className
0978:                                        + " found in " + jarName);
0979:                            }
0980:
0981:                            return result;
0982:                        }
0983:                    }
0984:                    if (debug) {
0985:                        System.out.println("class " + className
0986:                                + " not found in " + jarName);
0987:                    }
0988:                    return null;
0989:                } finally {
0990:                    zin.close();
0991:                }
0992:            }
0993:
0994:            /*
0995:             *----------------------------------------------------------------------
0996:             *
0997:             * getEntrySize --
0998:             *
0999:             *	For some reason, using ZipInputStreams, the ZipEntry returned
1000:             *      by getNextEntry() doesn't contain a valid uncompressed size, so
1001:             *      there is no way to determine how much to read.  Using the 
1002:             *      ZipFile object will return useful values for the size, but
1003:             *      the inputStream returned doesn't work.  The solution was to use
1004:             *      both methods to ultimtely extract the class, which results in 
1005:             *      an order n^2 algorithm.  Hopefully this will change...
1006:             *
1007:             * Results:
1008:             *	 The size of the uncompressed class file.
1009:             *
1010:             * Side effects:
1011:             *	None.
1012:             *
1013:             *----------------------------------------------------------------------
1014:             */
1015:
1016:            private int getEntrySize(String jarName, String className)
1017:                    throws IOException {
1018:                ZipEntry entry; // A file contained in the jar file.    
1019:                ZipFile zip; // Used to get the enum of ZipEntries.  
1020:                Enumeration e; // List of the contents of the jar file.
1021:
1022:                zip = new ZipFile(jarName);
1023:                e = zip.entries();
1024:
1025:                while (e.hasMoreElements()) {
1026:                    // see if the current ZipEntry's
1027:                    // name equals the file we want to extract.
1028:
1029:                    entry = (ZipEntry) e.nextElement();
1030:                    if (className.equals(entry.getName())) {
1031:                        zip.close();
1032:                        return ((int) entry.getSize());
1033:                    }
1034:                }
1035:                return (-1);
1036:            }
1037:
1038:            /*
1039:             *----------------------------------------------------------------------
1040:             *
1041:             * absolutePath --
1042:             *
1043:             *	Given a String, construct a File object.  If it is not an absoulte
1044:             *      path, then prepend the interps current working directory, to the
1045:             *      dirName.  
1046:             *
1047:             * Results:
1048:             *	The absolute path of dirName
1049:             *
1050:             * Side effects:
1051:             *	None.
1052:             *
1053:             *----------------------------------------------------------------------
1054:             */
1055:
1056:            private static String absolutePath(Interp interp, // the current Interp
1057:                    String dirName) // name of directory to be qualified
1058:            {
1059:                File dir;
1060:                String newName;
1061:
1062:                dir = new File(dirName);
1063:                if (!dir.isAbsolute()) {
1064:                    newName = interp.getWorkingDir().toString()
1065:                            + System.getProperty("file.separator") + dirName;
1066:                    dir = new File(newName);
1067:                }
1068:                return (dir.toString());
1069:            }
1070:
1071:            /*
1072:             *----------------------------------------------------------------------
1073:             *
1074:             * removeCache --
1075:             *
1076:             *	Remove the given className from the internal cache.
1077:             *
1078:             * Results:
1079:             *	|>None.<|
1080:             *
1081:             * Side effects:
1082:             *	|>None.<|
1083:             *
1084:             *----------------------------------------------------------------------
1085:             */
1086:
1087:            void removeCache(String className) {
1088:                // The cache could contain the key in the case where the load
1089:                // worked but the object could not be instantiated.
1090:
1091:                class_cache.remove(className);
1092:            }
1093:
1094:            /*
1095:             *----------------------------------------------------------------------
1096:             *
1097:             * getURLFromPath --
1098:             *
1099:             *	Given a resource name like "/testext/cmd.tcl" loop over
1100:             *	the classpath elements looking for a match to this resource
1101:             *	name. If ".jar" or ".zip" files are found, 
1102:             *      search them for the resource as well.
1103:             *
1104:             * Results:
1105:             *	A URL object.
1106:             *
1107:             * Side effects:
1108:             *	None.
1109:             *
1110:             *----------------------------------------------------------------------
1111:             */
1112:
1113:            private URL getURLFromPath(String[] paths, String resName) // the name of the resource trying to be resolved
1114:            {
1115:                final boolean debug = false;
1116:                int i = 0;
1117:                URL url = null;
1118:                String curDir; // The directory to search for the class file.
1119:                File file; // The class file.                            
1120:                int total; // Total number of bytes read from the stream
1121:
1122:                if (debug) {
1123:                    System.out.println("getURLFromPath for " + resName);
1124:                }
1125:
1126:                // Search through the list of "paths" for the resName.  
1127:                // ".jar" or ".zip" files found in the path will also be 
1128:                // searched.  Yhe first occurence found is returned.
1129:                lastSearchedClassFile = null;
1130:                lastSearchedJarFile = null;
1131:
1132:                if (paths != null) {
1133:                    for (i = 0; i < paths.length; i++) {
1134:                        curDir = paths[i].toString();
1135:                        try {
1136:                            if ((curDir.endsWith(".jar"))
1137:                                    || (curDir.endsWith(".zip"))) {
1138:                                // If curDir points to a jar file, search it
1139:                                // for the class.  If classData is not null
1140:                                // then the class was found in the jar file.
1141:
1142:                                url = extractURLFromJar(curDir, resName);
1143:                                if (url != null) {
1144:                                    return (url);
1145:                                }
1146:                            } else {
1147:                                // If curDir and url point to an existing file,
1148:                                // then the resource is found.
1149:
1150:                                file = new File(curDir, resName);
1151:                                if (file.exists()) {
1152:                                    url = file.toURL();
1153:                                    return (url);
1154:                                }
1155:                            }
1156:                        } catch (Exception e) {
1157:                            // No error thrown, because the class may be found
1158:                            // in subsequent paths.
1159:                        }
1160:                    }
1161:                    for (i = 0; i < paths.length; i++) {
1162:                        curDir = paths[i].toString();
1163:                        try {
1164:                            // The resource was not found in the paths list.
1165:                            // Search all the directories in paths for 
1166:                            // any jar files, in an attempt to locate
1167:                            // the class inside a jar file.
1168:
1169:                            url = getURLFromJar(curDir, resName);
1170:                            if (url != null) {
1171:                                return (url);
1172:                            }
1173:                        } catch (Exception e) {
1174:                            // No error thrown, because the resource may be found
1175:                            // in subsequent paths.
1176:                        }
1177:                    }
1178:                }
1179:
1180:                // No matching resource found.
1181:
1182:                return null;
1183:            }
1184:
1185:            /*
1186:             *----------------------------------------------------------------------
1187:             *
1188:             * getURLFromJar --
1189:             *
1190:             *	Given a directory and a resource to be found, get a list of 
1191:             *      ".jar" or ".zip" files in the current directory.  Call
1192:             *      extractURLFromJar to search the Jar file and extract
1193:             *      the resource if a match is found.
1194:             *
1195:             * Results:
1196:             *	A URL or null.
1197:             *
1198:             * Side effects:
1199:             *	None.
1200:             *
1201:             *----------------------------------------------------------------------
1202:             */
1203:
1204:            private URL getURLFromJar(String curDir, // An absoulte path for a directory to search 
1205:                    String resName) // The name of the resource to extract from the jar file.
1206:                    throws IOException {
1207:                URL result = null;
1208:                String[] jarFiles; // The list of files in the curDir.     
1209:                JarFilenameFilter jarFilter; // Filter the jarFiles list by only     
1210:                // accepting ".jar" or ".zip"
1211:
1212:                jarFilter = new JarFilenameFilter();
1213:                jarFiles = (new File(curDir)).list(jarFilter);
1214:
1215:                for (int i = 0; i < jarFiles.length; i++) {
1216:                    result = extractURLFromJar(curDir + File.separatorChar
1217:                            + jarFiles[i], resName);
1218:                    if (result != null) {
1219:                        break;
1220:                    }
1221:                }
1222:                return (result);
1223:            }
1224:
1225:            /*
1226:             *----------------------------------------------------------------------
1227:             *
1228:             * extractURLFromJar --
1229:             *
1230:             *	Look inside the jar file, jarName, for a ZipEntry that
1231:             *      matches the resName.  If a match is found then
1232:             *      generate a URL object.
1233:             *
1234:             * Results:
1235:             *	A URL object, or null.
1236:             *
1237:             * Side effects:
1238:             *	None.
1239:             *
1240:             *----------------------------------------------------------------------
1241:             */
1242:
1243:            private URL extractURLFromJar(String jarName, // An absoulte path for a jar file to search.
1244:                    String resName) // The name of the resource to extract from the jar file.
1245:                    throws IOException {
1246:                final boolean debug = false;
1247:                ZipInputStream zin; // The jar file input stream.
1248:                ZipEntry entry; // A file contained in the jar file.
1249:                URL result;
1250:                int size; // Uncompressed size of the class file.
1251:                int total; // Number of bytes read from class file.
1252:
1253:                if (debug) {
1254:                    System.out.println("searching for " + resName + " in "
1255:                            + jarName);
1256:                }
1257:
1258:                zin = new ZipInputStream(new FileInputStream(jarName));
1259:
1260:                try {
1261:                    while ((entry = zin.getNextEntry()) != null) {
1262:                        // see if the current ZipEntry's name equals 
1263:                        // the file we want to extract. If equal
1264:                        // get the extract and return the contents of the file.
1265:
1266:                        if (debug) {
1267:                            System.out.println("comparing " + resName + " to "
1268:                                    + entry.getName());
1269:                        }
1270:
1271:                        if (resName.equals(entry.getName())) {
1272:                            File file = new File(jarName);
1273:                            URL fileURL = file.toURL();
1274:                            URL jarURL = new URL("jar:" + fileURL.toString()
1275:                                    + "!/" + resName);
1276:                            if (debug) {
1277:                                System.out.println("match found: file is "
1278:                                        + file);
1279:                                System.out.println("fileURL is " + fileURL);
1280:                                System.out.println("jarURL is " + jarURL);
1281:                            }
1282:                            return jarURL;
1283:                        }
1284:                    }
1285:                    if (debug) {
1286:                        System.out.println("resource " + resName
1287:                                + " not found in " + jarName);
1288:                    }
1289:                    return null;
1290:                } finally {
1291:                    zin.close();
1292:                }
1293:            }
1294:
1295:        } // end TclClassLoader
1296:
1297:        /*
1298:         *
1299:         * TclClassLoader.java --
1300:         *
1301:         *      A class that helps filter directory listings when
1302:         *      for jar/zip files during the class resolution stage.
1303:         *
1304:         */
1305:
1306:        class JarFilenameFilter implements  FilenameFilter {
1307:
1308:            /*
1309:             *----------------------------------------------------------------------
1310:             *
1311:             * accept --
1312:             *
1313:             *	Used by the getClassFromJar method.  When list returns a list
1314:             *      of files in a directory, the list will only be of jar or zip
1315:             *      files.
1316:             *
1317:             * Results:
1318:             *	True if the file ends with .jar or .zip
1319:             *
1320:             * Side effects:
1321:             *	None.
1322:             *
1323:             *----------------------------------------------------------------------
1324:             */
1325:
1326:            public boolean accept(File dir, String name) {
1327:                if (name.endsWith(".jar") || name.endsWith(".zip")) {
1328:                    return (true);
1329:                } else {
1330:                    return (false);
1331:                }
1332:            }
1333:
1334:        } // end JarFilenameFilter
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.