Project: ant4eclipse
/**********************************************************************
 * Copyright (c) 2005-2009 ant4eclipse project team. 
 * 
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the Eclipse Public License v1.0 
 * which accompanies this distribution, and is available at 
 * http://www.eclipse.org/legal/epl-v10.html 
 * 
 * Contributors: 
 *     Nils Hartmann, Daniel Kasmeroglu, Gerd Wuetherich 
 **********************************************************************/
package org.ant4eclipse.lib.jdt.ecj.internal.tools; 
 
import org.ant4eclipse.lib.core.Assure; 
import org.ant4eclipse.lib.core.ClassName; 
import org.ant4eclipse.lib.core.logging.A4ELogging; 
import org.ant4eclipse.lib.jdt.ecj.ClassFile; 
import org.ant4eclipse.lib.jdt.ecj.ClassFileLoader; 
import org.ant4eclipse.lib.jdt.ecj.SourceFile; 
import org.eclipse.jdt.internal.compiler.env.INameEnvironment; 
import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; 
 
/**
 * <p> 
 * Adapter class to utilize class file loaders in the eclipse java compiler. 
 * </p> 
 *  
 * @author Gerd Wuetherich ([email protected]
 * @author Nils Hartmann ([email protected]
 */
 
public class NameEnvironmentImpl implements INameEnvironment { 
 
  // the debug flag 
  private static boolean  DEBUG_ALL            = false
 
  // the debug flag 
  private static boolean  DEBUG_TYPE_NOT_FOUND = false
 
  static { 
    DEBUG_ALL = "true".equals(System.getProperty("ant4eclipse.debug.nameenv")); 
    DEBUG_TYPE_NOT_FOUND = "true".equals(System.getProperty("ant4eclipse.debug.nameenv.missingtypes")); 
  } 
 
  /** used to find binary type as requested by the compiler */ 
  private ClassFileLoader _classFileLoader; 
 
  /**
   * <p> 
   * Create a new instance of type {@link NameEnvironmentImpl}. 
   * </p> 
   *  
   * @param classFileLoader 
   *          the class file loader to use. 
   */
 
  public NameEnvironmentImpl(ClassFileLoader classFileLoader) { 
    Assure.notNull("classFileLoader", classFileLoader); 
    this._classFileLoader = classFileLoader; 
 
    if (DEBUG_ALL || DEBUG_TYPE_NOT_FOUND) { 
      A4ELogging.info("NameEnvironment tracing enabled."); 
    } 
 
  } 
 
  /**
   * @see org.eclipse.jdt.internal.compiler.env.INameEnvironment#cleanup() 
   */
 
  public void cleanup() { 
    // nothing to do here... 
  } 
 
  /**
   * {@inheritDoc} 
   */
 
  public NameEnvironmentAnswer findType(char[][] compoundTypeName) { 
 
    // convert char array to string(buffer) 
    StringBuffer buffer = new StringBuffer(); 
    for (int i = 0; i < compoundTypeName.length; i++) { 
      buffer.append(new String(compoundTypeName[i])); 
      if (i < compoundTypeName.length - 1) { 
        buffer.append("."); 
      } 
    } 
 
    // find class 
    NameEnvironmentAnswer answer = findClass(buffer.toString()); 
    return answer; 
 
  } 
 
  /**
   * {@inheritDoc} 
   */
 
  public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName) { 
 
    StringBuffer result = new StringBuffer(); 
    if (packageName != null) { 
      for (char[] element : packageName) { 
        result.append(new String(element)).append("."); 
      } 
    } 
    result.append(new String(typeName)); 
 
    return findClass(result.toString()); 
  } 
 
  /**
   * {@inheritDoc} 
   *  
   * This method returns true if the given packageName is a valid package. 
   *  
   * <p> 
   * Note that this method returns true regardless of any OSGi visibility constraints. 
   * <p> 
   * This method also returns true for top level packages 
   */
 
  public boolean isPackage(char[][] parentPackageName, char[] packageName) { 
 
    String qualifiedPackageName = toJavaName(parentPackageName); 
    if (qualifiedPackageName.length() > 0) { 
      qualifiedPackageName += "." + new String(packageName); 
    } else { 
      qualifiedPackageName = new String(packageName); 
    } 
 
    boolean packageFound = this._classFileLoader.hasPackage(qualifiedPackageName); 
 
    if (DEBUG_ALL) { 
      if (packageFound) { 
        A4ELogging.info("Package '%s' found...", qualifiedPackageName); 
      } else { 
        A4ELogging.info("Package '%s' not found...", qualifiedPackageName); 
      } 
    } 
 
    return packageFound; 
  } 
 
  /**
   * @param className 
   * @return 
   */
 
  protected NameEnvironmentAnswer findClass(String className) { 
    Assure.notNull("className", className); 
    return findClass(ClassName.fromQualifiedClassName(className)); 
  } 
 
  /**
   * <p> 
   * Returns a {@link NameEnvironmentAnswer} for the class that is represented by the given {@link ClassName} instance. 
   * </p> 
   *  
   * @param className 
   *          represents the class name 
   * @return a {@link NameEnvironmentAnswer} 
   */
 
  protected NameEnvironmentAnswer findClass(ClassName className) { 
 
    // load class file from class file loader 
    ClassFile classFile = this._classFileLoader.loadClass(className); 
 
    // return new NameEnvironmentAnswer if classFile was found 
    if (classFile != null) { 
 
      if (DEBUG_ALL) { 
        A4ELogging.info("Loading class '%s' from '%s'.", className.getQualifiedClassName(), classFile 
            .getLibraryLocation()); 
      } 
 
      return new NameEnvironmentAnswer(classFile.getBinaryType(), (classFile.hasAccessRestriction() ? classFile 
          .getAccessRestriction() : null)); 
    } 
 
    // load source file from class file loader 
    // TODO: AccessRestictions for source files!! 
    SourceFile sourceFile = this._classFileLoader.loadSource(className); 
 
    // load source file from class file loader 
    if (sourceFile != null) { 
 
      if (DEBUG_ALL) { 
        A4ELogging.info("Loading class '%s' as source from '%s'.", className.getQualifiedClassName(), sourceFile 
            .getSourceFile().getAbsolutePath()); 
      } 
 
      // TODO: AccessRestictions for source files!! 
      return new NameEnvironmentAnswer(new CompilationUnitImpl(sourceFile), null); 
    } 
 
    // else return null 
    if (DEBUG_TYPE_NOT_FOUND) { 
      A4ELogging.info("Could not load class '%s'.", className.getQualifiedClassName()); 
    } 
    return null
  } 
 
  /**
   * <p> 
   * Converts the given char array to a java name (e.g. "net.sf.ant4eclipse"). 
   * </p> 
   *  
   * @param array 
   *          the array to convert. 
   * @return the 
   */
 
  private static String toJavaName(char[][] array) { 
    StringBuffer result = new StringBuffer(); 
 
    if (array != null) { 
      for (int i = 0; i < array.length; i++) { 
        result.append(new String(array[i])); 
        if (i < array.length - 1) { 
          result.append("."); 
        } 
      } 
    } 
    return result.toString(); 
  } 
}