Package net.sourceforge.retroweaver.translator

Source Code of net.sourceforge.retroweaver.translator.NameTranslator

package net.sourceforge.retroweaver.translator;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import net.sourceforge.retroweaver.RetroWeaverException;

import org.objectweb.asm.Type;

/**
* Substitutes JDK 1.5 classes for their mirrors.
*
* Out of the box, Retroweaver supports:
*   all new language features and their associated runtime
*     (autoboxing, generics, annotations, extended for loop, static import, varargs)
*   java.util.concurrent
*   TODO: full list of what is supported
*
* Additional runtime support can be added to Retroweaver by writing a mirror class and adding it
* to the class path. A mirror class can be one of two types: class or methods mirror.
*
* 1) Class mirror: Retroweaver replaces every single reference to the JDK 1.5 class directly with the mirror
* class.
*
* 2) Methods mirror: Retroweaver replaces calls to the JDK 1.5 class with static calls to the mirror
* class. Mirrors for instance calls are different from mirrors from static calls in that Retroweaver
* adds the JDK 1.5 object as the first parameter to the mirror. For example, a static call to
* java.lang.Integer.valueOf( int ) is replaced directly by net.sourceforge.retroweaver.runtime.java.lang.Integer_.valueOf( int ).
* However, an instance call to Class.getAnnotations() is replaced with a static call to
* net.sourceforge.retroweaver.runtime.java.lang.Class_.getAnnotations( Class ). Notice how the receiver (Class) is
* added as the first parameter to the mirror call.
*
* In order for Retroweaver to find your mirror classes, you must place them in Retroweaver's class path and
* register their mirror namespace. A mirror namespace defines the prefix of the package being
* replaced and the prefix of the package doing the replacing. For example, the namespace for the
* java.util.concurrent backport mirrors is "java.util.concurrent/edu.emory.mathcs.backport.java.util.concurrent".
* Retroweaver has a default mirror namespace "/net.sourceforge.retroweaver.runtime".
* As an example, java.lang.annotation.Annotation is replaced with
* net.sourceforge.retroweaver.runtime.java.lang.annotation.Annotation. In order to differentiate class mirrors
* from methods mirrors, a methods mirror must have exactly one trailing underscore in its class name:
* for example, net.sourceforge.retroweaver.runtime.java.lang.Class_
*
*/

public class NameTranslator {

  private static final NameSpace defaultNamespace = new NameSpace("", "net.sourceforge.retroweaver.runtime");

  private static final NameSpace concurrentNamespace = new NameSpace("java.util.concurrent", "edu.emory.mathcs.backport.java.util.concurrent");

  /**
   * Only select classes from the java.util concurrent package can be mirrored
   */
  private static final String[] javaUtilClasses = new String[] {
      "AbstractQueue",
      "ArrayDeque",
      "Deque",
      "NavigableMap",
      "NavigableSet",
      "PriorityQueue",
      "Queue"
  };

  private static final Mirror noMirror = new NoMirror();

  private final List<NameSpace> namespaces = new LinkedList<NameSpace>();

  private final Map<String, Mirror> mirrors = new HashMap<String, Mirror>();

  private static final NameTranslator generalTranslator ;

  public static final NameTranslator getGeneralTranslator() {
    return generalTranslator;
  }

  private static final NameTranslator stringBuilderTranslator;

  public static final NameTranslator getStringBuilderTranslator() {
    return stringBuilderTranslator;
  }

  private NameTranslator() {
    // private constructor
  }

  static {
    generalTranslator = new NameTranslator();
    generalTranslator.addNameSpace(defaultNamespace);
    generalTranslator.addNameSpace(concurrentNamespace);
    for (String s: javaUtilClasses) {
      NameSpace n = new NameSpace("java.util." + s, "edu.emory.mathcs.backport.java.util." + s);
      generalTranslator.addNameSpace(n);
    }
   
    // special rule around StringBuilder
    stringBuilderTranslator = new NameTranslator();
    stringBuilderTranslator.mirrors.put("java/lang/StringBuilder", new ClassMirror(StringBuffer.class));
  }

  /**
   * Adds a new runtime subsystem for the name translation. For instance
   * the concurrency backport translation is done with the NameSpace
   * "java.util.concurrent", "edu.emory.mathcs.backport.java.util.concurrent"
   */
  public void addNameSpace(NameSpace nameSpace) {
    namespaces.add(nameSpace);
  }

  /**
   * Returns either a class or methods mirror
   * Returns noMirror if there is no match
   */
  protected Mirror getMirror(final String class_) {
    if (class_ == null) {
      return noMirror;
    }

    // See if we can find an existing mirror
    final Mirror cachedMirror = mirrors.get(class_);

    if (cachedMirror != null) {
      return cachedMirror;
    }

    // Perform the lookup (on both class and methods if necessary)
    for (NameSpace n : namespaces) {
      String mirrorClass = n.getMirrorClassName(class_);

      if (mirrorClass == null) {
        continue;
      }

      mirrorClass = mirrorClass.replace('/', '.');

      // Attempt class mirror first
      try {
        final Class clazz = Class.forName(mirrorClass);
        final Mirror mirror = new ClassMirror(clazz);
        mirrors.put(class_, mirror);
        return mirror;
      } catch (ClassNotFoundException e) { // NOPMD by xlv
      }

      // Attempt methods mirror
      mirrorClass += '_';
      try {
        final Class clazz = Class.forName(mirrorClass);
        final Mirror mirror = new MethodsMirror(clazz);
        mirrors.put(class_, mirror);

        return mirror;
      } catch (ClassNotFoundException e) { // NOPMD by xlv
      }
    }

    // No matches in any of the namespaces
    mirrors.put(class_, noMirror);
    return noMirror;
  }

  /**
   * Translate an id or a method signature into its retroweaver runtime or
   * concurrent backport equivalent.
   *
   * @param name The <code>String</code> to translate.
   *
   * @return the translated name
   */
  protected String translate(final String name) {
    if (name == null) {
      return null;
    }

    final StringBuffer buffer = new StringBuffer();
    translate(false, name, buffer, 0, name.length());

    return buffer.toString();
  }

  /**
   * Translates the name only if it has a mirror.
   */
  private String getMirrorTranslation(final String name) {
    final Mirror mirror = getMirror(name);
    return mirror.exists() ? mirror.getTranslatedName() : name;
  }

  /**
   * Translates the name only if it represents a fully mirrored class.
   */
  public String getClassMirrorTranslation(final String name) {
    final Mirror mirror = getMirror(name);
    return mirror.isClassMirror() ? mirror.getTranslatedName() : name;
  }

  /**
   * Translates the name only if it represents a fully mirrored class.
   */
  public String getClassMirrorTranslationDescriptor(final String name) {
    if (name == null) {
      return null;
    }

    final StringBuffer buffer = new StringBuffer();
    translate(true, name, buffer, 0, name.length());

    return buffer.toString();
  }

  private void translate(final boolean classMirrorsOnly, final String in, final StringBuffer out, final int start, final int end) {
    if (start >= end) {
      return;
    }

    final char firstChar = in.charAt(start);

    switch (firstChar) {
    case 'Z': // boolean
    case 'B': // byte
    case 'C': // char
    case 'S': // short
    case 'I': // int
    case 'J': // long
    case 'F': // float
    case 'D': // double
    case '[': // type[]
    case 'V': // void
      out.append(firstChar);
      translate(classMirrorsOnly, in, out, start + 1, end);
      break;
    case 'L': // L fully-qualified-class;
      final int endName = in.indexOf(';', start + 1);
      if (endName == -1) {
        // false positive: it's an id, translate the entire string
        final String name = in.substring(start, end);
        final String newName = classMirrorsOnly?getClassMirrorTranslation(name):getMirrorTranslation(name);
        out.append(newName);
      } else {
        final String className = in.substring(start + 1, endName);
        final String newClassName = classMirrorsOnly?getClassMirrorTranslation(className):getMirrorTranslation(className);

        out.append('L').append(newClassName).append(';');
        translate(classMirrorsOnly, in, out, endName + 1, end);
      }
      break;
    case '(': // ( arg-types ) ret-type
      final int endArgs = in.indexOf(')', start + 1);
      if (endArgs == -1) {
        throw new RetroWeaverException("Class name parsing error: missing ')' in " + in);
      }

      out.append('(');
      if (endArgs != start + 1) {
        translate(classMirrorsOnly, in, out, start + 1, endArgs);
      }
      out.append(')');
      translate(classMirrorsOnly, in, out, endArgs + 1, end);
      break;
    default:
      // translate the entire string
      final String name = in.substring(start, end);
      final String newName = classMirrorsOnly?getClassMirrorTranslation(name):getMirrorTranslation(name);
      out.append(newName);
    }
  }


  /**
   * Translates a descriptor, specifically. Only translates names in the
   * descriptor, if they are represented by class mirrors.
   *
   */
  protected String translateMethodDescriptor(final String descriptor) {
    Type[] argTypes = Type.getArgumentTypes(descriptor);

    for (int i = 0; i < argTypes.length; ++i) {
      argTypes[i] = getMirrorType(argTypes[i]);
    }

    final Type returnType = getMirrorType(Type.getReturnType(descriptor));

    return Type.getMethodDescriptor(returnType, argTypes);
  }

  /**
   * Translates a simple type descriptor, specifically. Only translates names in the
   * descriptor, if they are represented by class mirrors.
   *
   */
  protected String translateDescriptor(final String descriptor) {
    Type type = Type.getType(descriptor);

    type = getMirrorType(type);

    return type.getDescriptor();
  }

  private Type getMirrorType(final Type type) {
    int numDimensions = 0;
    final Type basicType;

    if (type.getSort() == Type.ARRAY) {
      numDimensions = type.getDimensions();
      basicType = type.getElementType();
    } else {
      basicType = type;
    }

    if (basicType.getSort() != Type.OBJECT) {
      return type;
    }

    final Mirror mirror = getMirror(basicType.getInternalName());

    if (mirror.isClassMirror()) {
      final StringBuilder name = new StringBuilder();

      for (int i = 0; i < numDimensions; ++i) {
        name.append('[');
      }
      name.append('L').append(mirror.getTranslatedName()).append(';');

      return Type.getType(name.toString());
    }

    return type;
  }

}
TOP

Related Classes of net.sourceforge.retroweaver.translator.NameTranslator

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.