Open Source Repository

Home /spring/spring-context-3.0.5 | Repository Home



org/springframework/instrument/classloading/glassfish/GlassFishClassLoaderAdapter.java
/*
 * Copyright 2002-2009 the original author or authors.
 
 * 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.
 */

package org.springframework.instrument.classloading.glassfish;

import java.lang.instrument.ClassFileTransformer;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * Reflective wrapper around the GlassFish class loader. Used to
 * encapsulate the classloader-specific methods (discovered and
 * called through reflection) from the load-time weaver.
 
 <p>Supports GlassFish V1, V2 and V3 (currently in beta).
 
 @author Costin Leau
 @since 3.0
 */
class GlassFishClassLoaderAdapter {

  static final String INSTRUMENTABLE_CLASSLOADER_GLASSFISH_V2 = "com.sun.enterprise.loader.InstrumentableClassLoader";

  static final String INSTRUMENTABLE_CLASSLOADER_GLASSFISH_V3 = "org.glassfish.api.deployment.InstrumentableClassLoader";

  private static final String CLASS_TRANSFORMER = "javax.persistence.spi.ClassTransformer";


  private final ClassLoader classLoader;

  private final Method addTransformer;

  private final Method copy;

  private final boolean glassFishV3;


  public GlassFishClassLoaderAdapter(ClassLoader classLoader) {
    Class<?> instrumentableLoaderClass;
    boolean glassV3 = false;
    try {
      // try the V1/V2 API first
      instrumentableLoaderClass = classLoader.loadClass(INSTRUMENTABLE_CLASSLOADER_GLASSFISH_V2);
    }
    catch (ClassNotFoundException ex) {
      // fall back to V3
      try {
        instrumentableLoaderClass = classLoader.loadClass(INSTRUMENTABLE_CLASSLOADER_GLASSFISH_V3);
        glassV3 = true;
      }
      catch (ClassNotFoundException cnfe) {
        throw new IllegalStateException("Could not initialize GlassFish LoadTimeWeaver because " +
            "GlassFish (V1, V2 or V3) API classes are not available", ex);
      }
    }
    try {
      Class<?> classTransformerClass =
          (glassV3 ? ClassFileTransformer.class : classLoader.loadClass(CLASS_TRANSFORMER));

      this.addTransformer = instrumentableLoaderClass.getMethod("addTransformer", classTransformerClass);
      this.copy = instrumentableLoaderClass.getMethod("copy");
    }
    catch (Exception ex) {
      throw new IllegalStateException(
          "Could not initialize GlassFish LoadTimeWeaver because GlassFish API classes are not available", ex);
    }

    ClassLoader clazzLoader = null;
    // Detect transformation-aware ClassLoader by traversing the hierarchy
    // (as in GlassFish, Spring can be loaded by the WebappClassLoader).
    for (ClassLoader cl = classLoader; cl != null && clazzLoader == null; cl = cl.getParent()) {
      if (instrumentableLoaderClass.isInstance(cl)) {
        clazzLoader = cl;
      }
    }

    if (clazzLoader == null) {
      throw new IllegalArgumentException(classLoader + " and its parents are not suitable ClassLoaders: A [" +
          instrumentableLoaderClass.getName() "] implementation is required.");
    }

    this.classLoader = clazzLoader;
    this.glassFishV3 = glassV3;
  }

  public void addTransformer(ClassFileTransformer transformer) {
    try {
      this.addTransformer.invoke(this.classLoader,
          (this.glassFishV3 ? transformer : new ClassTransformerAdapter(transformer)));
    }
    catch (InvocationTargetException ex) {
      throw new IllegalStateException("GlassFish addTransformer method threw exception ", ex.getCause());
    }
    catch (Exception ex) {
      throw new IllegalStateException("Could not invoke GlassFish addTransformer method", ex);
    }
  }

  public ClassLoader getClassLoader() {
    return this.classLoader;
  }

  public ClassLoader getThrowawayClassLoader() {
    try {
      return (ClassLoaderthis.copy.invoke(this.classLoader);
    }
    catch (InvocationTargetException ex) {
      throw new IllegalStateException("GlassFish copy method threw exception ", ex.getCause());
    }
    catch (Exception ex) {
      throw new IllegalStateException("Could not invoke GlassFish copy method", ex);
    }
  }

}