001: /*
002: * Copyright 2002-2006 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.instrument.classloading;
018:
019: import java.lang.instrument.ClassFileTransformer;
020: import java.lang.instrument.IllegalClassFormatException;
021: import java.security.ProtectionDomain;
022: import java.util.ArrayList;
023: import java.util.List;
024:
025: /**
026: * ClassFileTransformer-based weaver, allowing for a list of transformers to be
027: * applied on a class byte array. Normally used inside class loaders.
028: *
029: * <p>Note: This class is deliberately implemented for minimal external dependencies,
030: * since it is included in weaver jars (to be deployed into application servers).
031: *
032: * @author Rod Johnson
033: * @author Costin Leau
034: * @author Juergen Hoeller
035: * @since 2.0
036: */
037: public class WeavingTransformer {
038:
039: private final ClassLoader classLoader;
040:
041: private final List<ClassFileTransformer> transformers = new ArrayList<ClassFileTransformer>();
042:
043: /**
044: * Create a new WeavingTransformer for the current context class loader.
045: */
046: public WeavingTransformer() {
047: this (null);
048: }
049:
050: /**
051: * Create a new WeavingTransformer for the given class loader.
052: * @param classLoader the ClassLoader to build a transformer for
053: */
054: public WeavingTransformer(ClassLoader classLoader) {
055: this .classLoader = (classLoader != null ? classLoader
056: : getDefaultClassLoader());
057: }
058:
059: /**
060: * Add a class file transformer to be applied by this weaver.
061: * @param transformer the class file transformer to register
062: */
063: public void addTransformer(ClassFileTransformer transformer) {
064: if (transformer == null) {
065: throw new IllegalArgumentException(
066: "Transformer must not be null");
067: }
068: this .transformers.add(transformer);
069: }
070:
071: /**
072: * Apply transformation on a given class byte definition.
073: * The method will always return a non-null byte array (if no transformation has taken place
074: * the array content will be identical to the original one).
075: *
076: * @param className the full qualified name of the class in dot format (i.e. some.package.SomeClass)
077: * @param bytes class byte definition
078: * @return (possibly transformed) class byte definition
079: */
080: public byte[] transformIfNecessary(String className, byte[] bytes) {
081: String internalName = className.replace(".", "/");
082: return transformIfNecessary(className, internalName, bytes,
083: null);
084: }
085:
086: /**
087: * Apply transformation on a given class byte definition.
088: * The method will always return a non-null byte array (if no transformation has taken place
089: * the array content will be identical to the original one).
090: *
091: * @param className the full qualified name of the class in dot format (i.e. some.package.SomeClass)
092: * @param internalName class name internal name in / format (i.e. some/package/SomeClass)
093: * @param bytes class byte definition
094: * @param pd protection domain to be used (can be null)
095: *
096: * @return (possibly transformed) class byte definition
097: */
098: public byte[] transformIfNecessary(String className,
099: String internalName, byte[] bytes, ProtectionDomain pd) {
100: byte[] result = bytes;
101: for (ClassFileTransformer cft : this .transformers) {
102: try {
103: byte[] transformed = cft.transform(this .classLoader,
104: internalName, null, pd, result);
105: if (transformed != null) {
106: result = transformed;
107: }
108: } catch (IllegalClassFormatException ex) {
109: throw new IllegalStateException(
110: "Class file transformation failed", ex);
111: }
112: }
113: return result;
114: }
115:
116: /**
117: * See ClassUtils. We don't depend on that to avoid pulling in more of Spring.
118: * @see org.springframework.util.ClassUtils#getDefaultClassLoader()
119: */
120: protected ClassLoader getDefaultClassLoader() {
121: ClassLoader cl = Thread.currentThread().getContextClassLoader();
122: if (cl == null) {
123: // No thread context class loader -> use class loader of this class.
124: cl = getClass().getClassLoader();
125: }
126: return cl;
127: }
128:
129: }
|