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 }