View Javadoc

    1   /*
    2    * Copyright  2000-2004 The Apache Software Foundation
    3    *
    4    *  Licensed under the Apache License, Version 2.0 (the "License");
    5    *  you may not use this file except in compliance with the License.
    6    *  You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   *  Unless required by applicable law or agreed to in writing, software
    11   *  distributed under the License is distributed on an "AS IS" BASIS,
    12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   *  See the License for the specific language governing permissions and
    14   *  limitations under the License.
    15   *
    16   */
    17  package org.apache.bcel.util;
    18
    19  import java.io.IOException;
    20  import java.io.InputStream;
    21  import java.lang.ref.SoftReference;
    22  import java.util.HashMap;
    23  import java.util.Map;
    24  import org.apache.bcel.classfile.ClassParser;
    25  import org.apache.bcel.classfile.JavaClass;
    26
    27  /***
    28   * This repository is used in situations where a Class is created
    29   * outside the realm of a ClassLoader. Classes are loaded from
    30   * the file systems using the paths specified in the given
    31   * class path. By default, this is the value returned by
    32   * ClassPath.getClassPath().
    33   * <br>
    34   * It is designed to be used as a singleton, however it
    35   * can also be used with custom classpaths.
    36   *
    37   /**
    38   * Abstract definition of a class repository. Instances may be used
    39   * to load classes from different sources and may be used in the
    40   * Repository.setRepository method.
    41   *
    42   * @see org.apache.bcel.Repository
    43   *
    44   * @version $Id: SyntheticRepository.java 386056 2006-03-15 11:31:56Z tcurdt $
    45   * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
    46   * @author David Dixon-Peugh
    47   */
    48  public class SyntheticRepository implements Repository {
    49
    50      private static final String DEFAULT_PATH = ClassPath.getClassPath();
    51      private static Map _instances = new HashMap(); // CLASSPATH X REPOSITORY
    52      private ClassPath _path = null;
    53      private Map _loadedClasses = new HashMap(); // CLASSNAME X JAVACLASS
    54
    55
    56      private SyntheticRepository(ClassPath path) {
    57          _path = path;
    58      }
    59
    60
    61      public static SyntheticRepository getInstance() {
    62          return getInstance(ClassPath.SYSTEM_CLASS_PATH);
    63      }
    64
    65
    66      public static SyntheticRepository getInstance( ClassPath classPath ) {
    67          SyntheticRepository rep = (SyntheticRepository) _instances.get(classPath);
    68          if (rep == null) {
    69              rep = new SyntheticRepository(classPath);
    70              _instances.put(classPath, rep);
    71          }
    72          return rep;
    73      }
    74
    75
    76      /***
    77       * Store a new JavaClass instance into this Repository.
    78       */
    79      public void storeClass( JavaClass clazz ) {
    80          _loadedClasses.put(clazz.getClassName(), new SoftReference(clazz));
    81          clazz.setRepository(this);
    82      }
    83
    84
    85      /***
    86       * Remove class from repository
    87       */
    88      public void removeClass( JavaClass clazz ) {
    89          _loadedClasses.remove(clazz.getClassName());
    90      }
    91
    92
    93      /***
    94       * Find an already defined (cached) JavaClass object by name.
    95       */
    96      public JavaClass findClass( String className ) {
    97          SoftReference ref = (SoftReference) _loadedClasses.get(className);
    98          if (ref == null) {
    99              return null;
    100         }
    101         return (JavaClass) ref.get();
    102     }
    103
    104
    105     /***
    106      * Find a JavaClass object by name.
    107      * If it is already in this Repository, the Repository version
    108      * is returned.  Otherwise, the Repository's classpath is searched for
    109      * the class (and it is added to the Repository if found).
    110      *
    111      * @param className the name of the class
    112      * @return the JavaClass object
    113      * @throws ClassNotFoundException if the class is not in the
    114      *   Repository, and could not be found on the classpath
    115      */
    116     public JavaClass loadClass( String className ) throws ClassNotFoundException {
    117         if (className == null || className.equals("")) {
    118             throw new IllegalArgumentException("Invalid class name " + className);
    119         }
    120         className = className.replace('/', '.'); // Just in case, canonical form
    121         JavaClass clazz = findClass(className);
    122         if (clazz != null) {
    123             return clazz;
    124         }
    125         try {
    126             return loadClass(_path.getInputStream(className), className);
    127         } catch (IOException e) {
    128             throw new ClassNotFoundException("Exception while looking for class " + className
    129                     + ": " + e.toString());
    130         }
    131     }
    132
    133
    134     /***
    135      * Find the JavaClass object for a runtime Class object.
    136      * If a class with the same name is already in this Repository,
    137      * the Repository version is returned.  Otherwise, getResourceAsStream()
    138      * is called on the Class object to find the class's representation.
    139      * If the representation is found, it is added to the Repository.
    140      *
    141      * @see Class
    142      * @param clazz the runtime Class object
    143      * @return JavaClass object for given runtime class
    144      * @throws ClassNotFoundException if the class is not in the
    145      *   Repository, and its representation could not be found
    146      */
    147     public JavaClass loadClass( Class clazz ) throws ClassNotFoundException {
    148         String className = clazz.getName();
    149         JavaClass repositoryClass = findClass(className);
    150         if (repositoryClass != null) {
    151             return repositoryClass;
    152         }
    153         String name = className;
    154         int i = name.lastIndexOf('.');
    155         if (i > 0) {
    156             name = name.substring(i + 1);
    157         }
    158         return loadClass(clazz.getResourceAsStream(name + ".class"), className);
    159     }
    160
    161
    162     private JavaClass loadClass( InputStream is, String className ) throws ClassNotFoundException {
    163         try {
    164             if (is != null) {
    165                 ClassParser parser = new ClassParser(is, className);
    166                 JavaClass clazz = parser.parse();
    167                 storeClass(clazz);
    168                 return clazz;
    169             }
    170         } catch (IOException e) {
    171             throw new ClassNotFoundException("Exception while looking for class " + className
    172                     + ": " + e.toString());
    173         }
    174         throw new ClassNotFoundException("SyntheticRepository could not load " + className);
    175     }
    176
    177
    178     /*** ClassPath associated with the Repository.
    179      */
    180     public ClassPath getClassPath() {
    181         return _path;
    182     }
    183
    184
    185     /*** Clear all entries from cache.
    186      */
    187     public void clear() {
    188         _loadedClasses.clear();
    189     }
    190 }