Package

Source Code of Package

/*
* Copyright  2000-2004 The Apache Software Foundation
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*
*/
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.TreeMap;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;
import org.apache.bcel.Constants;
import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.Constant;
import org.apache.bcel.classfile.ConstantClass;
import org.apache.bcel.classfile.ConstantPool;
import org.apache.bcel.classfile.ConstantUtf8;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.util.ClassPath;

/**
* Package the client. Creates a jar file in the current directory
* that contains a minimal set of classes needed to run the client.
*
* Use BCEL to extract class names and read/write classes
* @author First Hop Ltd / Torsten Rueger
*/
public class Package {
 
  /**
   * The name of the resulting jar is Client.jar
   */
  static String defaultJar  = "Client.jar";
 
  /*
   * See usage() for arguments. Create an instance and run that
   *(just so not all members have to be static)
   */
  static void main(String args[]) {
    Package instance = new Package();
    try{
      instance.go(args);
    }catch(Exception e){
      e.printStackTrace();
      instance.usage();
    }
  }
 
  /**
   * We use a "default ClassPath object which uses the environments
   * CLASSPATH
   */
  ClassPath classPath = ClassPath.SYSTEM_CLASS_PATH;

  /**
   * A map for all Classes, the ones we're going to package.
   * Store class name against the JavaClass. From the JavaClass
   * we get the bytes to create the jar.
   */
  TreeMap allClasses = new TreeMap();
  /**
   * We start at the root classes, put them in here, then go through
   * this list, putting dependent classes in here and from there
   * into allClasses. Store class names against class names of their dependents
   */
  TreeMap dependents = new TreeMap();
  /**
   * Collect all classes that could not be found in the classpath.
   * Store class names against class names of their dependents
   */
  TreeMap notFound = new TreeMap();
  /**
   * See wheather we print the classes that were not found (default = false)
   */
  boolean showNotFound = false ;
  /**
   * Remember wheather to print allClasses at the end (default = false)
   */
  boolean printClasses = false ;
  /**
   * Wheather we log classes during processing (default = false)
   */
  boolean log = false ;

  public void usage(){
    System.out.println(" This program packages classes and all their dependents");
    System.out.println(" into one jar. Give all starting classes (your main)");
    System.out.println(" on the command line. Use / as separator, the .class is");
    System.out.println(" optional. We use the environments CLASSPATH to resolve");
    System.out.println(" classes. Anything but java.* packages are packaged.");
    System.out.println(" If you use Class.forName (or similar), be sure to");
    System.out.println(" include the classes that you load dynamically on the");
    System.out.println(" command line.\n");
    System.out.println(" These options are recognized:");
    System.out.println(" -e -error  Show errors, meaning classes that could not ");
    System.out.println("   resolved + the classes that referenced them.");
    System.out.println(" -l -log  Show classes as they are processed. This will");
    System.out.println("   include doubles, java classes and is difficult to");
    System.out.println("   read. I use it as a sort of progress monitor");
    System.out.println(" -s -show  Prints all the classes that were packaged");
    System.out.println("   in alphabetical order, which is ordered by package");
    System.out.println("   for the most part.");
  }
  /**
   * the main of this class
   */
  void go(String[] args) throws IOException {
    JavaClass clazz ;
    // sort the options
    for(int i = 0 ; i < args.length ; i++ ){
      if( args[i].startsWith("-e")  )  {
  showNotFound = true;
  continue;
      }
      if( args[i].startsWith("-s")  )  {
  printClasses = true ;
  continue;
      }
      if( args[i].startsWith("-l")  )  {
  log = true ;
  continue;
      }
      String clName = args[i];
      if(clName.endsWith(".class")) {
  clName = clName.substring(0,clName.length()-6);
      }
      clName = clName.replace('.','/');
      clazz = new ClassParser(classPath.getInputStream(clName),clName).parse();
      // here we create the root set of classes to process
      addDependents(clazz);
      System.out.println("Packaging for class: " + clName );
    }
    if( dependents.isEmpty() ){
       usage();
       return ;
    }
    System.out.println("Creating jar file: " + defaultJar );
    // starting processing: Grab from the dependents list an add back to it
    // and the allClasses list. see addDependents
    while(!dependents.isEmpty() ){
      String name = (String)dependents.firstKey();
      String from = (String) dependents.remove(name);
      if(allClasses.get(name) == null){
  try{
    InputStream is = classPath.getInputStream(name);
    clazz = new ClassParser(is, name).parse();
    addDependents(clazz);
  }catch( IOException e){
    //System.err.println("Error, class not found " + name );
    notFound.put(name,from);
  }
      }
    }
    if(printClasses) { // if wanted show all classes
      printAllClasses();
    }
    // create the jar
    JarOutputStream jarFile = new JarOutputStream(new FileOutputStream(defaultJar));
    jarFile.setLevel(5); // use compression
    Iterator keys = allClasses.keySet().iterator();
    int written = 0 ;
    while(keys.hasNext()){ // add entries for every class
      String name = (String)keys.next();
      JavaClass claz = (JavaClass) allClasses.get(name);
      ZipEntry zipEntry = new ZipEntry(name+".class");
      byte[] bytes = claz.getBytes() ;
      int length = bytes.length ;
      jarFile.putNextEntry(zipEntry);
      jarFile.write( bytes , 0 , length );
      written += length;  // for logging
    }
    jarFile.close();
    System.err.println("The jar file contains " + allClasses.size()
           +" classes and contains " +written+ " bytes");
    if( !notFound.isEmpty() ){
      System.err.println( notFound.size() +" classes could not be found");
      if(showNotFound){ // if wanted show the actual classes that we not found
  while(!notFound.isEmpty()){
    String name = (String)notFound.firstKey();
    System.err.println( name+ " (" + notFound.remove(name)+")");
  }
      }else{
  System.err.println("Use '-e' option to view classes that were not found");
      }
    }
  }

  /**
   * Print all classes that were packaged. Sort alphabetically for better
   * overview. Enabled by -s option
   */
  void printAllClasses(){
    ArrayList names = new ArrayList(allClasses.keySet());
    Collections.sort(names);
    for( int i = 0 ; i < names.size() ; i ++ ){
      String cl = (String)names.get(i);
      System.err.println(cl);
    }
  }
 
  /**
   *Add this class to allClasses. Then go through all its dependents
   * and add them to the dependents list if they are not in allClasses
   */
  void addDependents( JavaClass clazz ) throws IOException {
    String name = clazz.getClassName().replace('.', '/');
    allClasses.put( name , clazz );
    ConstantPool pool = clazz.getConstantPool();
    for( int i = 1 ; i < pool.getLength() ; i++){
      Constant cons =  pool.getConstant(i);
      //System.out.println("("+i+") " + cons );
      if( cons!=null && cons.getTag() == Constants.CONSTANT_Class ){
  int idx = ((ConstantClass)pool.getConstant(i)).getNameIndex();
  String clas = ((ConstantUtf8)pool.getConstant(idx)).getBytes();
  addClassString(clas,name);
      }
    }
  }

  /**
   * add given class to dependents (from is where its dependent from)
   * some fiddeling to be done because of array class notation
   */ 
  void addClassString(String clas,String from) throws IOException{
    if(log){
      System.out.println("processing: " + clas +" referenced by " + from);
    }
    // must check if it's an arrary (start with "[")
    if(clas.startsWith("[")) {
      if(clas.length() == 2 ) {
  // it's an array of built in type, ignore
  return;
      }
      if( 'L' == clas.charAt(1) ){
  // it's an array of objects, the class name is between [L and ;
  // like    [Ljava/lang/Object;
  addClassString(clas.substring(2,clas.length()-1),from);
  return;
      }
      if( '[' == clas.charAt(1) ){
  // it's an array of arrays, call recursive
  addClassString(clas.substring(1),from);
  return ;
      }
      throw new IOException("Can't recognize class name =" + clas);
    }

    if( !clas.startsWith("java/") && allClasses.get(clas) == null) {
      dependents.put(clas,from);
      //      System.out.println("       yes" );
    } else {
      //      System.out.println("       no" );
    }
  }
}
TOP

Related Classes of Package

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.