001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.geronimo.corba.util; 018 019 import net.sf.cglib.core.NamingPolicy; 020 import net.sf.cglib.core.Predicate; 021 import net.sf.cglib.proxy.Callback; 022 import net.sf.cglib.proxy.CallbackFilter; 023 import net.sf.cglib.proxy.Enhancer; 024 import net.sf.cglib.proxy.FixedValue; 025 import net.sf.cglib.proxy.MethodInterceptor; 026 import net.sf.cglib.proxy.NoOp; 027 import org.apache.commons.logging.Log; 028 import org.apache.commons.logging.LogFactory; 029 import org.apache.geronimo.gbean.GBeanLifecycle; 030 031 import java.lang.reflect.Method; 032 import java.lang.reflect.Modifier; 033 034 035 /** 036 * @version $Revision: 451417 $ $Date: 2006-09-29 13:13:22 -0700 (Fri, 29 Sep 2006) $ 037 */ 038 public class DynamicStubClassLoader extends ClassLoader implements GBeanLifecycle { 039 private final static Log log = LogFactory.getLog(DynamicStubClassLoader.class); 040 private final static String PACKAGE_PREFIX = "org.omg.stub."; 041 042 private boolean stopped = true; 043 044 public synchronized Class loadClass(final String name) throws ClassNotFoundException { 045 if (stopped) { 046 throw new ClassNotFoundException("DynamicStubClassLoader is stopped"); 047 } 048 049 if (log.isDebugEnabled()) { 050 log.debug("Load class " + name); 051 } 052 053 ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 054 055 // check if the stub already exists first 056 try { 057 return classLoader.loadClass(name); 058 } catch (ClassNotFoundException e) { 059 if (log.isDebugEnabled()) { 060 log.debug("Unable to load class from the context class loader"); 061 } 062 } 063 064 // if this is not a class from the org.omb.stub name space don't attempt to generate 065 if (!name.startsWith(PACKAGE_PREFIX)) { 066 if (log.isDebugEnabled()) { 067 log.debug("Could not load class: " + name); 068 } 069 throw new ClassNotFoundException("Could not load class: " + name); 070 } 071 072 // load the interfaces class we are attempting to create a stub for 073 Class iface = loadStubInterfaceClass(name, classLoader); 074 075 // create the stub builder 076 try { 077 Enhancer enhancer = new Enhancer(); 078 enhancer.setSuperclass(ClientContextHolderStub.class); 079 enhancer.setInterfaces(new Class[]{iface}); 080 enhancer.setCallbackFilter(FILTER); 081 enhancer.setCallbackTypes(new Class[]{NoOp.class, MethodInterceptor.class, FixedValue.class}); 082 enhancer.setUseFactory(false); 083 enhancer.setClassLoader(classLoader); 084 enhancer.setNamingPolicy(new NamingPolicy() { 085 public String getClassName(String s, String s1, Object o, Predicate predicate) { 086 return name; 087 } 088 }); 089 090 // generate the class 091 Class result = enhancer.createClass(); 092 assert result != null; 093 094 StubMethodInterceptor interceptor = new StubMethodInterceptor(iface); 095 Ids ids = new Ids(iface); 096 Enhancer.registerStaticCallbacks(result, new Callback[]{NoOp.INSTANCE, interceptor, ids}); 097 098 if (log.isDebugEnabled()) { 099 log.debug("result: " + result.getName()); 100 } 101 return result; 102 } catch (RuntimeException e) { 103 log.error("Unable to generate stub: " + name, e); 104 throw e; 105 } catch (Error e) { 106 log.error("Unable to generate stub: " + name, e); 107 throw e; 108 } 109 } 110 111 private Class loadStubInterfaceClass(String name, ClassLoader classLoader) throws ClassNotFoundException { 112 try { 113 int begin = name.lastIndexOf('.') + 1; 114 String iPackage = name.substring(13, begin); 115 String iName = iPackage + name.substring(begin + 1, name.length() - 5); 116 117 return classLoader.loadClass(iName); 118 } catch (ClassNotFoundException e) { 119 // don't log exceptions from CosNaming because it attempts to load every 120 // class bound into the name server 121 boolean shouldLog = true; 122 StackTraceElement[] stackTrace = e.getStackTrace(); 123 for (int i = 0; i < stackTrace.length; i++) { 124 StackTraceElement stackTraceElement = stackTrace[i]; 125 if (stackTraceElement.getClassName().equals("org.omg.CosNaming.NamingContextExtPOA") && 126 stackTraceElement.getMethodName().equals("_invoke")) { 127 shouldLog = false; 128 break; 129 } 130 } 131 if (shouldLog) { 132 log.error("Unable to generate stub", e); 133 } 134 135 throw new ClassNotFoundException("Unable to generate stub", e); 136 } 137 } 138 139 private static final CallbackFilter FILTER = new CallbackFilter() { 140 public int accept(Method method) { 141 // we don't intercept non-public methods like finalize 142 if (!Modifier.isPublic(method.getModifiers())) { 143 return 0; 144 } 145 146 if (method.getReturnType().equals(String[].class) && method.getParameterTypes().length == 0 && method.getName().equals("_ids")) { 147 return 2; 148 } 149 150 if (Modifier.isAbstract(method.getModifiers())) { 151 return 1; 152 } 153 154 return 0; 155 } 156 }; 157 158 private static final class Ids implements FixedValue { 159 private final String[] typeIds; 160 161 public Ids(Class type) { 162 typeIds = Util.createCorbaIds(type); 163 } 164 165 public Object loadObject() throws Exception { 166 return typeIds; 167 } 168 } 169 170 public synchronized void doStart() throws Exception { 171 UtilDelegateImpl.setClassLoader(this); 172 stopped = false; 173 } 174 175 public synchronized void doStop() throws Exception { 176 stopped = true; 177 log.debug("Stopped"); 178 } 179 180 public synchronized void doFail() { 181 stopped = true; 182 log.warn("Failed"); 183 } 184 185 }