CompiledClass.java :  » Scripting » InstantJ » instantj » compile » Java Open Source

Java Open Source » Scripting » InstantJ 
InstantJ » instantj » compile » CompiledClass.java
/**
 * InstantJ
 * 
 * Copyright (C) 2002 Andy Thomas 
 * Additional changes (C) 2002 Nils Meier
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 */
package instantj.compile;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * (C) 2002 Andy Thomas 
 * This class represents a single compilation source files class instance. 
 * This includes the classes name and the bytes that form the class.
 */
public class CompiledClass implements Serializable {

  /** the compiled bytecode */
  private byte[] bytecode;

  /** the name of the class */
  private String name;
  
  /** inner classes */
  private Map inners = null;
  
  /** dependencies to other classes */
  private Map dependencies = null;
  
  /** cached mapping classloader2type */
  private transient Map cl2type = null;
  
  /**
   * Constructor
   */
  public CompiledClass(String name, byte[] bytecode) {
    this.bytecode = bytecode;
    this.name = name;
  }

  /**
   * Returns the code.
   * @return byte[]
   */
  public byte[] getByteCode() {
    return bytecode;
  }

  /**
   * Returns the name.
   * @return String
   */
  public String getName() {
    return name;
  }
  
  /**
   * Returns a (new) java type for this compiled class. The classloader
   * used wraps
   * <il>
   * <li>Thread.currentThread().getContextClassLoader() if not null
   * <li>getClass().getClassLoader() otherwise
   * </il>
   * and will return the same type for that classloader on successive calls.
   */
  public Class getType() {
    
    // nothing cached yet?
    if (cl2type==null) {
      cl2type = new HashMap();
    }
    
    // lookup ClassLoader
    ClassLoader cl = Thread.currentThread().getContextClassLoader();
    if (cl==null) cl = getClass().getClassLoader();
    
    // known?
    Class result = (Class)cl2type.get(cl);
    if (result==null) {
      result = new CL(cl).loadClass();
      cl2type.put(cl, result);
    }
    // done
    return result;
  }
  
  /**
   * Method addInnerClasses.
   * @param inners
   */
  public void addInnerClasses(Collection add) {
    // check argument
    if (add==null||add.size()==0) return;
    // check state
    if (inners==null) inners = new HashMap(); 
    // loop through list
    Iterator it = add.iterator();
    while (it.hasNext()) {
      CompiledClass cc = (CompiledClass)it.next();
      inners.put(cc.getName(), cc);
    }
    // done
  }
  
  /**
   * Add dependencies (other CompiledClasses)
   */
  public void addDependencies(Collection add) {
    // check argument
    if (add==null||add.size()==0) return;
    // check state
    if (dependencies==null) dependencies = new HashMap(); 
    // loop through list
    Iterator it = add.iterator();
    while (it.hasNext()) {
      CompiledClass cc = (CompiledClass)it.next();
      dependencies.put(cc.getName(), cc);
    }
    // done
  }
  
  /**
   * Builds a map of compiled classes
   */
  /*package*/ static Map map(Map map, Collection ccs) {
    
    // check for null
    if (ccs==null) return map;

    // loop over compiled classes
    Iterator it = ccs.iterator();
    while (it.hasNext()) {
      
      CompiledClass cc = (CompiledClass)it.next();
      
      // map next
      map.put(cc.getName(), cc);
      
      // map it's inner classes
      if (cc.inners!=null) map(map, cc.inners.values());
      
      // map it's dependencies
      if (cc.dependencies!=null) map(map, cc.dependencies.values());
      
    }
    
    // done
    return map;
  }

  /**
   * A classloader for the compiled class
   */  
  private class CL extends ClassLoader {
    
    /** instantiated classes */
    private Map classInstances = new HashMap();
  
    /**
     * Constructor
     */
    private CL(ClassLoader parent) {
      super(parent);
    }

    /**
     * @see java.lang.ClassLoader#findClass(java.lang.String)
     */
    protected Class findClass(String key) throws ClassNotFoundException {
      // loaded it already?
      Class result = (Class)classInstances.get(key);
      if (result!=null) return result;
      // maybe it's an inner type?
      if (inners!=null) {
        CompiledClass cc = (CompiledClass)inners.get(key);
        // .. have to load with this classloader
        if (cc!=null) return loadClass(cc);
      }
      // maybe it's a type we're depending on?
      if (dependencies!=null) {
        CompiledClass cc = (CompiledClass)dependencies.get(key);
        // .. have to use it's classloader
        if (cc!=null) return cc.getType();
      }
      
      // delegate
      return super.findClass(key);
    }
    
    /**
     * Loads the class from the contained byte-data
     * @return the Class
     */
    private Class loadClass() throws ClassFormatError {
      return loadClass(CompiledClass.this);
    }
    
    /**
     * Loads the class from given compiled class
     */
    private Class loadClass(CompiledClass cc) throws ClassFormatError {
      
      // Construct class
      Class result = defineClass(null,cc.bytecode,0,cc.bytecode.length);
  
      // Resolve it
      try {
        resolveClass(result);
      } catch (IncompatibleClassChangeError err) {
        // can't happen
      }
      
      // remember
      classInstances.put(cc.name, result);
  
      // Done
      return result;
    }
    
  } //CL
  
} //CompiledClass
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.