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.DataInputStream;
    20  import java.io.File;
    21  import java.io.FileInputStream;
    22  import java.io.FilenameFilter;
    23  import java.io.IOException;
    24  import java.io.InputStream;
    25  import java.io.Serializable;
    26  import java.util.ArrayList;
    27  import java.util.Iterator;
    28  import java.util.List;
    29  import java.util.Locale;
    30  import java.util.StringTokenizer;
    31  import java.util.zip.ZipEntry;
    32  import java.util.zip.ZipFile;
    33
    34  /***
    35   * Responsible for loading (class) files from the CLASSPATH. Inspired by
    36   * sun.tools.ClassPath.
    37   *
    38   * @version $Id: ClassPath.java 386056 2006-03-15 11:31:56Z tcurdt $
    39   * @author  <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
    40   */
    41  public class ClassPath implements Serializable {
    42
    43      public static final ClassPath SYSTEM_CLASS_PATH = new ClassPath();
    44      private PathEntry[] paths;
    45      private String class_path;
    46
    47
    48      /***
    49       * Search for classes in given path.
    50       */
    51      public ClassPath(String class_path) {
    52          this.class_path = class_path;
    53          List vec = new ArrayList();
    54          for (StringTokenizer tok = new StringTokenizer(class_path, System
    55                  .getProperty("path.separator")); tok.hasMoreTokens();) {
    56              String path = tok.nextToken();
    57              if (!path.equals("")) {
    58                  File file = new File(path);
    59                  try {
    60                      if (file.exists()) {
    61                          if (file.isDirectory()) {
    62                              vec.add(new Dir(path));
    63                          } else {
    64                              vec.add(new Zip(new ZipFile(file)));
    65                          }
    66                      }
    67                  } catch (IOException e) {
    68                      System.err.println("CLASSPATH component " + file + ": " + e);
    69                  }
    70              }
    71          }
    72          paths = new PathEntry[vec.size()];
    73          vec.toArray(paths);
    74      }
    75
    76
    77      /***
    78       * Search for classes in CLASSPATH.
    79       * @deprecated Use SYSTEM_CLASS_PATH constant
    80       */
    81      public ClassPath() {
    82          this(getClassPath());
    83      }
    84
    85
    86      /*** @return used class path string
    87       */
    88      public String toString() {
    89          return class_path;
    90      }
    91
    92
    93      public int hashCode() {
    94          return class_path.hashCode();
    95      }
    96
    97
    98      public boolean equals( Object o ) {
    99          if (o instanceof ClassPath) {
    100             return class_path.equals(((ClassPath) o).class_path);
    101         }
    102         return false;
    103     }
    104
    105
    106     private static final void getPathComponents( String path, List list ) {
    107         if (path != null) {
    108             StringTokenizer tok = new StringTokenizer(path, File.pathSeparator);
    109             while (tok.hasMoreTokens()) {
    110                 String name = tok.nextToken();
    111                 File file = new File(name);
    112                 if (file.exists()) {
    113                     list.add(name);
    114                 }
    115             }
    116         }
    117     }
    118
    119
    120     /*** Checks for class path components in the following properties:
    121      * "java.class.path", "sun.boot.class.path", "java.ext.dirs"
    122      *
    123      * @return class path as used by default by BCEL
    124      */
    125     public static final String getClassPath() {
    126         String class_path = System.getProperty("java.class.path");
    127         String boot_path = System.getProperty("sun.boot.class.path");
    128         String ext_path = System.getProperty("java.ext.dirs");
    129         List list = new ArrayList();
    130         getPathComponents(class_path, list);
    131         getPathComponents(boot_path, list);
    132         List dirs = new ArrayList();
    133         getPathComponents(ext_path, dirs);
    134         for (Iterator e = dirs.iterator(); e.hasNext();) {
    135             File ext_dir = new File((String) e.next());
    136             String[] extensions = ext_dir.list(new FilenameFilter() {
    137
    138                 public boolean accept( File dir, String name ) {
    139                     name = name.toLowerCase(Locale.ENGLISH);
    140                     return name.endsWith(".zip") || name.endsWith(".jar");
    141                 }
    142             });
    143             if (extensions != null) {
    144                 for (int i = 0; i < extensions.length; i++) {
    145                     list.add(ext_dir.getPath() + File.separatorChar + extensions[i]);
    146                 }
    147             }
    148         }
    149         StringBuffer buf = new StringBuffer();
    150         for (Iterator e = list.iterator(); e.hasNext();) {
    151             buf.append((String) e.next());
    152             if (e.hasNext()) {
    153                 buf.append(File.pathSeparatorChar);
    154             }
    155         }
    156         return buf.toString().intern();
    157     }
    158
    159
    160     /***
    161      * @param name fully qualified class name, e.g. java.lang.String
    162      * @return input stream for class
    163      */
    164     public InputStream getInputStream( String name ) throws IOException {
    165         return getInputStream(name.replace('.', '/'), ".class");
    166     }
    167
    168
    169     /***
    170      * Return stream for class or resource on CLASSPATH.
    171      *
    172      * @param name fully qualified file name, e.g. java/lang/String
    173      * @param suffix file name ends with suff, e.g. .java
    174      * @return input stream for file on class path
    175      */
    176     public InputStream getInputStream( String name, String suffix ) throws IOException {
    177         InputStream is = null;
    178         try {
    179             is = getClass().getClassLoader().getResourceAsStream(name + suffix);
    180         } catch (Exception e) {
    181         }
    182         if (is != null) {
    183             return is;
    184         }
    185         return getClassFile(name, suffix).getInputStream();
    186     }
    187
    188
    189     /***
    190      * @param name fully qualified file name, e.g. java/lang/String
    191      * @param suffix file name ends with suff, e.g. .java
    192      * @return class file for the java class
    193      */
    194     public ClassFile getClassFile( String name, String suffix ) throws IOException {
    195         for (int i = 0; i < paths.length; i++) {
    196             ClassFile cf;
    197             if ((cf = paths[i].getClassFile(name, suffix)) != null) {
    198                 return cf;
    199             }
    200         }
    201         throw new IOException("Couldn't find: " + name + suffix);
    202     }
    203
    204
    205     /***
    206      * @param name fully qualified class name, e.g. java.lang.String
    207      * @return input stream for class
    208      */
    209     public ClassFile getClassFile( String name ) throws IOException {
    210         return getClassFile(name, ".class");
    211     }
    212
    213
    214     /***
    215      * @param name fully qualified file name, e.g. java/lang/String
    216      * @param suffix file name ends with suffix, e.g. .java
    217      * @return byte array for file on class path
    218      */
    219     public byte[] getBytes( String name, String suffix ) throws IOException {
    220         DataInputStream dis = null;
    221         try {
    222             InputStream is = getInputStream(name, suffix);
    223             if (is == null) {
    224                 throw new IOException("Couldn't find: " + name + suffix);
    225             }
    226             dis = new DataInputStream(is);
    227             byte[] bytes = new byte[is.available()];
    228             dis.readFully(bytes);
    229             return bytes;
    230         } finally {
    231             if (dis != null) {
    232                 dis.close();
    233             }
    234         }
    235     }
    236
    237
    238     /***
    239      * @return byte array for class
    240      */
    241     public byte[] getBytes( String name ) throws IOException {
    242         return getBytes(name, ".class");
    243     }
    244
    245
    246     /***
    247      * @param name name of file to search for, e.g. java/lang/String.java
    248      * @return full (canonical) path for file
    249      */
    250     public String getPath( String name ) throws IOException {
    251         int index = name.lastIndexOf('.');
    252         String suffix = "";
    253         if (index > 0) {
    254             suffix = name.substring(index);
    255             name = name.substring(0, index);
    256         }
    257         return getPath(name, suffix);
    258     }
    259
    260
    261     /***
    262      * @param name name of file to search for, e.g. java/lang/String
    263      * @param suffix file name suffix, e.g. .java
    264      * @return full (canonical) path for file, if it exists
    265      */
    266     public String getPath( String name, String suffix ) throws IOException {
    267         return getClassFile(name, suffix).getPath();
    268     }
    269
    270     private static abstract class PathEntry implements Serializable {
    271
    272         abstract ClassFile getClassFile( String name, String suffix ) throws IOException;
    273     }
    274
    275     /*** Contains information about file/ZIP entry of the Java class.
    276      */
    277     public interface ClassFile {
    278
    279         /*** @return input stream for class file.
    280          */
    281         public abstract InputStream getInputStream() throws IOException;
    282
    283
    284         /*** @return canonical path to class file.
    285          */
    286         public abstract String getPath();
    287
    288
    289         /*** @return base path of found class, i.e. class is contained relative
    290          * to that path, which may either denote a directory, or zip file
    291          */
    292         public abstract String getBase();
    293
    294
    295         /*** @return modification time of class file.
    296          */
    297         public abstract long getTime();
    298
    299
    300         /*** @return size of class file.
    301          */
    302         public abstract long getSize();
    303     }
    304
    305     private static class Dir extends PathEntry {
    306
    307         private String dir;
    308
    309
    310         Dir(String d) {
    311             dir = d;
    312         }
    313
    314
    315         ClassFile getClassFile( String name, String suffix ) throws IOException {
    316             final File file = new File(dir + File.separatorChar
    317                     + name.replace('.', File.separatorChar) + suffix);
    318             return file.exists() ? new ClassFile() {
    319
    320                 public InputStream getInputStream() throws IOException {
    321                     return new FileInputStream(file);
    322                 }
    323
    324
    325                 public String getPath() {
    326                     try {
    327                         return file.getCanonicalPath();
    328                     } catch (IOException e) {
    329                         return null;
    330                     }
    331                 }
    332
    333
    334                 public long getTime() {
    335                     return file.lastModified();
    336                 }
    337
    338
    339                 public long getSize() {
    340                     return file.length();
    341                 }
    342
    343
    344                 public String getBase() {
    345                     return dir;
    346                 }
    347             } : null;
    348         }
    349
    350
    351         public String toString() {
    352             return dir;
    353         }
    354     }
    355
    356     private static class Zip extends PathEntry {
    357
    358         private ZipFile zip;
    359
    360
    361         Zip(ZipFile z) {
    362             zip = z;
    363         }
    364
    365
    366         ClassFile getClassFile( String name, String suffix ) throws IOException {
    367             final ZipEntry entry = zip.getEntry(name.replace('.', '/') + suffix);
    368             return (entry != null) ? new ClassFile() {
    369
    370                 public InputStream getInputStream() throws IOException {
    371                     return zip.getInputStream(entry);
    372                 }
    373
    374
    375                 public String getPath() {
    376                     return entry.toString();
    377                 }
    378
    379
    380                 public long getTime() {
    381                     return entry.getTime();
    382                 }
    383
    384
    385                 public long getSize() {
    386                     return entry.getSize();
    387                 }
    388
    389
    390                 public String getBase() {
    391                     return zip.getName();
    392                 }
    393             } : null;
    394         }
    395     }
    396 }