001 /* 002 Copyright (C) 2001 Renaud Pawlak <renaud@aopsys.com> 003 004 This program is free software; you can redistribute it and/or modify 005 it under the terms of the GNU Lesser General Public License as 006 published by the Free Software Foundation; either version 2 of the 007 License, or (at your option) any later version. 008 009 This program is distributed in the hope that it will be useful, 010 but WITHOUT ANY WARRANTY; without even the implied warranty of 011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 GNU Lesser General Public License for more details. 013 014 You should have received a copy of the GNU Lesser Generaly Public License 015 along with this program; if not, write to the Free Software 016 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 017 018 package org.objectweb.jac.core.dist; 019 020 import java.io.FileInputStream; 021 import java.util.Hashtable; 022 import org.apache.log4j.Logger; 023 024 /** 025 * DistdClassLoader is a class loader that load classes from a remote 026 * JAC container (the class repository site). 027 * 028 * @see RemoteContainer#getByteCodeFor(String) 029 * 030 * @author <a href="http://cedric.cnam.fr/~pawlak/index-english.html">Renaud Pawlak</a> */ 031 032 public class DistdClassLoader extends ClassLoader { 033 static Logger logger = Logger.getLogger("dist.classloader"); 034 035 /** loadedClasses is a hashtable of classes that have been 036 loaded. */ 037 protected transient Hashtable loadedClasses = new Hashtable(); 038 039 /** loadedByteCodes is a hashtable of byte codes that have been 040 remotely load (so that this site may be used as an intermediate 041 class repository. */ 042 protected Hashtable loadedByteCodes = new Hashtable(); 043 044 /** Bootstrapping flag (do not load classes while true). */ 045 public boolean bootstrapping = true; 046 047 /** The class repository site. */ 048 public static String classRepositoryName = null; 049 050 /** 051 * Overrides the default mechanism to load classes (only for 052 * non-java classes). The behavior is the following :<p> 053 * 054 * <ul> 055 * <li>check whether the class is already loaded</li> 056 * <li>try to load it from the class repository site</li> 057 * <li>if success, store its bytecode (see getByteCode)</li> 058 * <li>try to load it from the local filesystem</li> 059 * <li>if all these failed, delegate to the parent</li> 060 * </ul> 061 * 062 * @param name the name for the class to load 063 * @return the loaded class 064 */ 065 066 public Class loadClass(String name) 067 throws ClassNotFoundException { 068 069 /** Do not reload the same class */ 070 if (name.equals(getClass().getName())) { 071 logger.debug("Do not reload "+getClass().getName()); 072 return getClass(); 073 } 074 075 Class cl; 076 if (name.startsWith("java.")) { 077 logger.debug("Get system class "+name+" from parent classloader"); 078 cl = getParent().loadClass(name); 079 loadedClasses.put(name, cl); 080 return cl; 081 } 082 083 /** Check whether already loaded */ 084 cl = (Class)loadedClasses.get(name); 085 086 if (cl == null) { 087 088 byte[] bc = null; 089 090 /** Check if we know a class repository to download the bytecode */ 091 092 if ( (!bootstrapping) && classRepositoryName != null ) { 093 094 /** Download the bytecode */ 095 logger.debug("Downloading "+name+" from "+classRepositoryName); 096 RemoteContainer rc = RemoteContainer.resolve(classRepositoryName); 097 try { 098 bc = rc.getByteCodeFor(name); 099 } catch(Exception e) { 100 logger.debug("Failed to get bytecode for "+name+ 101 " from "+classRepositoryName+": "+e); 102 } 103 if (bc != null) { 104 loadedByteCodes.put(name, bc); 105 } 106 } 107 108 /** Check if download was successfully performed */ 109 110 if (bc == null) { 111 112 /** Try to load it from the local filesystem */ 113 logger.debug("Loading "+name+" from local FS"); 114 try { 115 FileInputStream in = new FileInputStream( 116 getParent().getResource(name.replace('.','/')+".class").getFile()); 117 bc = new byte[in.available()]; 118 in.read(bc); 119 } catch (Exception e) { 120 /** If failed, delegate to the parent classloader */ 121 cl = getParent().loadClass(name); 122 loadedClasses.put(name, cl); 123 return cl; 124 } 125 126 } 127 128 if (bc != null) { 129 /** Define the class from the bytecode */ 130 try { 131 cl = defineClass(name, bc, 0, bc.length); 132 loadedClasses.put(name, cl); 133 } catch (Exception e) { 134 /** Bytecode was corrupted or some error occured */ 135 logger.error("Cannot load class "+name,e); 136 } 137 } 138 139 } else { 140 logger.debug("Already loaded "+name); 141 } 142 143 return cl; 144 } 145 146 /** 147 * Gets the bytecode for a given remotely loaded class name. 148 * 149 * @param className the name of the class 150 * @return the corresponding bytecode */ 151 152 public byte[] getByteCode (String className) { 153 byte[] bc = (byte[])loadedByteCodes.get (className); 154 if (bc == null) { 155 } 156 return bc; 157 } 158 159 }