001: /*
002: * Copyright 2002-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.context.weaving;
018:
019: import java.lang.instrument.ClassFileTransformer;
020:
021: import org.apache.commons.logging.Log;
022: import org.apache.commons.logging.LogFactory;
023:
024: import org.springframework.beans.factory.BeanClassLoaderAware;
025: import org.springframework.instrument.InstrumentationSavingAgent;
026: import org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver;
027: import org.springframework.instrument.classloading.LoadTimeWeaver;
028: import org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver;
029: import org.springframework.instrument.classloading.glassfish.GlassFishLoadTimeWeaver;
030: import org.springframework.instrument.classloading.oc4j.OC4JLoadTimeWeaver;
031: import org.springframework.instrument.classloading.weblogic.WebLogicLoadTimeWeaver;
032:
033: /**
034: * Default {@link LoadTimeWeaver} bean for use in an application context,
035: * decorating an automatically detected internal <code>LoadTimeWeaver</code>.
036: *
037: * <p>Typically registered for the default bean name
038: * "<code>loadTimeWeaver</code>"; the most convenient way to achieve this is
039: * Spring's <code><context:load-time-weaver></code> XML tag.
040: *
041: * <p>This class implements a runtime environment check for obtaining the
042: * appropriate weaver implementation: As of Spring 2.5, it detects Sun's
043: * GlassFish, Oracle's OC4J, BEA's WebLogic 10,
044: * {@link InstrumentationSavingAgent Spring's VM agent} and any
045: * {@link ClassLoader} supported by Spring's {@link ReflectiveLoadTimeWeaver}
046: * (for example the
047: * {@link org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader}).
048: *
049: * @author Juergen Hoeller
050: * @author Ramnivas Laddad
051: * @since 2.5
052: * @see org.springframework.context.ConfigurableApplicationContext#LOAD_TIME_WEAVER_BEAN_NAME
053: */
054: public class DefaultContextLoadTimeWeaver implements LoadTimeWeaver,
055: BeanClassLoaderAware {
056:
057: protected final Log logger = LogFactory.getLog(getClass());
058:
059: private LoadTimeWeaver loadTimeWeaver;
060:
061: public void setBeanClassLoader(ClassLoader classLoader) {
062: LoadTimeWeaver serverSpecificLoadTimeWeaver = createServerSpecificLoadTimeWeaver(classLoader);
063: if (serverSpecificLoadTimeWeaver != null) {
064: if (logger.isInfoEnabled()) {
065: logger
066: .info("Determined server-specific load-time weaver: "
067: + serverSpecificLoadTimeWeaver
068: .getClass().getName());
069: }
070: this .loadTimeWeaver = serverSpecificLoadTimeWeaver;
071: } else if (InstrumentationSavingAgent.getInstrumentation() != null) {
072: logger.info("Found Spring's JVM agent for instrumentation");
073: this .loadTimeWeaver = new InstrumentationLoadTimeWeaver();
074: } else {
075: try {
076: this .loadTimeWeaver = new ReflectiveLoadTimeWeaver();
077: logger
078: .info("Using a reflective load-time weaver for class loader: "
079: + this .loadTimeWeaver
080: .getInstrumentableClassLoader());
081: } catch (IllegalStateException ex) {
082: throw new IllegalStateException(
083: ex.getMessage()
084: + " Specify a custom LoadTimeWeaver "
085: + "or start your Java virtual machine with Spring's agent: -javaagent:spring-agent.jar");
086: }
087: }
088: }
089:
090: /*
091: * This method never fails, allowing to try other possible ways to use an
092: * server-agnostic weaver. This non-failure logic is required since
093: * determining a load-time weaver based on the ClassLoader name alone may
094: * legitimately fail due to other mismatches. Specific case in point: the
095: * use of WebLogicLoadTimeWeaver works for WLS 10 but fails due to the lack
096: * of a specific method (addInstanceClassPreProcessor) for any earlier
097: * versions even though the ClassLoader name is the same.
098: */
099: protected LoadTimeWeaver createServerSpecificLoadTimeWeaver(
100: ClassLoader classLoader) {
101: try {
102: if (classLoader.getClass().getName().startsWith("weblogic")) {
103: return new WebLogicLoadTimeWeaver(classLoader);
104: } else if (classLoader.getClass().getName().startsWith(
105: "oracle")) {
106: return new OC4JLoadTimeWeaver(classLoader);
107: } else if (isMatchingClassLoaderInHierarchy(classLoader,
108: "com.sun.enterprise")) {
109: return new GlassFishLoadTimeWeaver(classLoader);
110: }
111: } catch (IllegalStateException ex) {
112: logger
113: .info("Could not obtain server-specific LoadTimeWeaver: "
114: + ex.getMessage());
115: }
116: return null;
117: }
118:
119: /**
120: * Try to find a ClassLoader with matching name in the entire ClassLoader hierarchy.
121: * Used for GlassFish detection, where the web app ClassLoader might be from the
122: * embedded Tomcat - but its parent is going to be a GlassFish ClassLoader.
123: */
124: private boolean isMatchingClassLoaderInHierarchy(
125: ClassLoader classLoader, String loaderName) {
126: return (classLoader != null && (classLoader.getClass()
127: .getName().startsWith(loaderName) || isMatchingClassLoaderInHierarchy(
128: classLoader.getParent(), loaderName)));
129: }
130:
131: public void addTransformer(ClassFileTransformer transformer) {
132: this .loadTimeWeaver.addTransformer(transformer);
133: }
134:
135: public ClassLoader getInstrumentableClassLoader() {
136: return this .loadTimeWeaver.getInstrumentableClassLoader();
137: }
138:
139: public ClassLoader getThrowawayClassLoader() {
140: return this.loadTimeWeaver.getThrowawayClassLoader();
141: }
142:
143: }
|