001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.invocation;
023:
024: import java.io.InputStream;
025: import java.io.IOException;
026: import java.io.ObjectInputStream;
027: import java.io.ObjectStreamClass;
028: import java.lang.reflect.Proxy;
029: import org.jboss.util.collection.WeakValueHashMap;
030:
031: import org.jboss.logging.Logger;
032:
033: /**
034: * An ObjectInputStream subclass used by the MarshalledValue class to
035: * ensure the classes and proxies are loaded using the thread context
036: * class loader.
037: *
038: * @author Scott.Stark@jboss.org
039: * @version $Revision: 57209 $
040: */
041: public class MarshalledValueInputStream extends ObjectInputStream {
042: private static Logger log = Logger
043: .getLogger(MarshalledValueInputStream.class);
044: /** A class wide cache of proxy classes populated by resolveProxyClass */
045: private static WeakValueHashMap classCache;
046:
047: /** Enable local caching of resolved proxy classes. This can only be used
048: * if there is a single ULR and no redeployment of the proxy classes.
049: *
050: * @param flag true to enable caching, false to disable it
051: */
052: public static void useClassCache(boolean flag) {
053: if (flag == true)
054: classCache = new WeakValueHashMap();
055: else
056: classCache = null;
057: }
058:
059: /** Clear the current proxy cache.
060: *
061: */
062: public static void flushClassCache() {
063: classCache.clear();
064: }
065:
066: /**
067: * Creates a new instance of MarshalledValueOutputStream
068: */
069: public MarshalledValueInputStream(InputStream is)
070: throws IOException {
071: super (is);
072: }
073:
074: /**
075: * Use the thread context class loader to resolve the class
076: *
077: * @throws IOException Any exception thrown by the underlying OutputStream.
078: */
079: protected Class resolveClass(ObjectStreamClass v)
080: throws IOException, ClassNotFoundException {
081: String className = v.getName();
082: Class resolvedClass = null;
083: // Check the class cache first if it exists
084: if (classCache != null) {
085: synchronized (classCache) {
086: resolvedClass = (Class) classCache.get(className);
087: }
088: }
089:
090: if (resolvedClass == null) {
091: ClassLoader loader = SecurityActions
092: .getContextClassLoader();
093: try {
094: resolvedClass = loader.loadClass(className);
095: } catch (ClassNotFoundException e) {
096: /* Use the super.resolveClass() call which will resolve array
097: classes and primitives. We do not use this by default as this can
098: result in caching of stale values across redeployments.
099: */
100: resolvedClass = super .resolveClass(v);
101: }
102: if (classCache != null) {
103: synchronized (classCache) {
104: classCache.put(className, resolvedClass);
105: }
106: }
107: }
108: return resolvedClass;
109: }
110:
111: protected Class resolveProxyClass(String[] interfaces)
112: throws IOException, ClassNotFoundException {
113: if (log.isTraceEnabled()) {
114: StringBuffer tmp = new StringBuffer("[");
115: for (int i = 0; i < interfaces.length; i++) {
116: if (i > 0)
117: tmp.append(',');
118: tmp.append(interfaces[i]);
119: }
120: tmp.append(']');
121: log.trace("resolveProxyClass called, ifaces="
122: + tmp.toString());
123: }
124:
125: // Load the interfaces from the cache or thread context class loader
126: ClassLoader loader = null;
127: Class[] ifaceClasses = new Class[interfaces.length];
128: for (int i = 0; i < interfaces.length; i++) {
129: Class iface = null;
130: String className = interfaces[i];
131: // Check the proxy cache if it exists
132: if (classCache != null) {
133: synchronized (classCache) {
134: iface = (Class) classCache.get(className);
135: }
136: }
137:
138: // Load the interface class using the thread context ClassLoader
139: if (iface == null) {
140: if (loader == null)
141: loader = Thread.currentThread()
142: .getContextClassLoader();
143: iface = loader.loadClass(className);
144: if (classCache != null) {
145: synchronized (classCache) {
146: classCache.put(className, iface);
147: }
148: }
149: }
150: ifaceClasses[i] = iface;
151: }
152:
153: return Proxy.getProxyClass(loader, ifaceClasses);
154: }
155: }
|