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.pooled.interfaces;
023:
024: import java.io.IOException;
025: import java.io.InputStream;
026: import java.io.ObjectInputStream;
027: import java.io.ObjectStreamClass;
028: import java.lang.ref.WeakReference;
029: import java.lang.reflect.Method;
030: import java.lang.reflect.Proxy;
031: import java.util.Collections;
032: import java.util.Map;
033: import java.util.WeakHashMap;
034:
035: import EDU.oswego.cs.dl.util.concurrent.ConcurrentHashMap;
036: import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap;
037:
038: /**
039: * An ObjectInputStream subclass used by the MarshalledValue class to
040: * ensure the classes and proxies are loaded using the thread context
041: * class loader.
042: *
043: * @author Scott.Stark@jboss.org
044: * @author Clebert.Suconic@jboss.org
045: * @version $Revision: 59315 $
046: */
047: public class OptimizedObjectInputStream extends ObjectInputStream {
048: /** A class wide cache of proxy classes populated by resolveProxyClass */
049: private static Map classCache;
050: private static ConcurrentReaderHashMap objectStreamClassCache;
051: private static Method lookupStreamClass = null;
052:
053: static {
054: useClassCache(true);
055: try {
056: lookupStreamClass = ObjectStreamClass.class
057: .getDeclaredMethod("lookup", new Class[] {
058: Class.class, boolean.class });
059: lookupStreamClass.setAccessible(true);
060: } catch (Exception ex) {
061: ex.printStackTrace();
062: }
063: }
064:
065: /** Enable local caching of resolved proxy classes. This can only be used
066: * if there is a single ULR and no redeployment of the proxy classes.
067: *
068: * @param flag true to enable caching, false to disable it
069: */
070: public static void useClassCache(boolean flag) {
071: if (flag == true) {
072: classCache = Collections.synchronizedMap(new WeakHashMap());
073: objectStreamClassCache = new ConcurrentReaderHashMap();
074: } else {
075: classCache = null;
076: objectStreamClassCache = null;
077: }
078: }
079:
080: /** Clear the current proxy cache.
081: *
082: */
083: public static void flushClassCache() {
084: classCache.clear();
085: objectStreamClassCache.clear();
086: }
087:
088: private static Class forName(String className)
089: throws ClassNotFoundException {
090: Class clazz = null;
091:
092: if (classCache != null) {
093:
094: ConcurrentHashMap subCache = (ConcurrentHashMap) classCache
095: .get(Thread.currentThread().getContextClassLoader());
096: if (subCache == null) {
097: classCache.put(Thread.currentThread()
098: .getContextClassLoader(),
099: new ConcurrentHashMap());
100: subCache = (ConcurrentHashMap) classCache.get(Thread
101: .currentThread().getContextClassLoader());
102: }
103:
104: WeakReference ref = (WeakReference) subCache.get(className);
105: if (ref != null) {
106: clazz = (Class) ref.get();
107: }
108: if (clazz == null) {
109: if (ref != null)
110: subCache.remove(className);
111: ClassLoader loader = Thread.currentThread()
112: .getContextClassLoader();
113: try {
114: clazz = loader.loadClass(className);
115: } catch (ClassNotFoundException e) {
116: /* Use the Class.forName call which will resolve array classes. We
117: do not use this by default as this can result in caching of stale
118: values across redeployments.
119: */
120: clazz = Class.forName(className, false, loader);
121: }
122: subCache.put(className, new WeakReference(clazz));
123: }
124: } else {
125: clazz = Thread.currentThread().getContextClassLoader()
126: .loadClass(className);
127: }
128: return clazz;
129: }
130:
131: /**
132: * Creates a new instance of MarshalledValueOutputStream
133: */
134: public OptimizedObjectInputStream(InputStream is)
135: throws IOException {
136: super (is);
137: }
138:
139: protected static ObjectStreamClass lookup(Class clazz) {
140: Object[] args = { clazz, Boolean.TRUE };
141: try {
142: return (ObjectStreamClass) lookupStreamClass.invoke(null,
143: args);
144: } catch (Exception ex) {
145: ex.printStackTrace();
146: }
147: return null;
148: }
149:
150: protected ObjectStreamClass readClassDescriptor()
151: throws IOException, ClassNotFoundException {
152: if (CompatibilityVersion.pooledInvokerLegacy) {
153: String className = readUTF();
154: ObjectStreamClass osc = null;
155: if (objectStreamClassCache != null) {
156: osc = (ObjectStreamClass) objectStreamClassCache
157: .get(className);
158: }
159: if (osc == null) {
160: Class clazz = forName(className);
161: osc = ObjectStreamClass.lookup(clazz);
162: if (osc == null)
163: osc = lookup(clazz);
164: if (osc == null)
165: throw new IOException(
166: "Unable to readClassDescriptor for class "
167: + className);
168: if (objectStreamClassCache != null)
169: objectStreamClassCache.put(className, osc);
170: }
171: return osc;
172: } else {
173: return super .readClassDescriptor();
174: }
175: }
176:
177: /**
178: * Use the thread context class loader to resolve the class
179: *
180: * @throws IOException Any exception thrown by the underlying OutputStream.
181: */
182: protected Class resolveClass(ObjectStreamClass v)
183: throws IOException, ClassNotFoundException {
184: String className = v.getName();
185: return forName(className);
186: }
187:
188: protected Class resolveProxyClass(String[] interfaces)
189: throws IOException, ClassNotFoundException {
190: // Load the interfaces from the cache or thread context class loader
191: ClassLoader loader = Thread.currentThread()
192: .getContextClassLoader();
193: Class[] ifaceClasses = new Class[interfaces.length];
194: for (int i = 0; i < interfaces.length; i++) {
195: String className = interfaces[i];
196: Class iface = forName(className);
197: ifaceClasses[i] = iface;
198: }
199:
200: return Proxy.getProxyClass(loader, ifaceClasses);
201: }
202: }
|