001: /**
002: *
003: * Licensed to the Apache Software Foundation (ASF) under one or more
004: * contributor license agreements. See the NOTICE file distributed with
005: * this work for additional information regarding copyright ownership.
006: * The ASF licenses this file to You under the Apache License, Version 2.0
007: * (the "License"); you may not use this file except in compliance with
008: * the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */package org.apache.openejb.core.stateless;
018:
019: import junit.framework.TestCase;
020: import org.apache.openejb.assembler.classic.Assembler;
021: import org.apache.openejb.assembler.classic.ProxyFactoryInfo;
022: import org.apache.openejb.assembler.classic.SecurityServiceInfo;
023: import org.apache.openejb.assembler.classic.StatelessSessionContainerInfo;
024: import org.apache.openejb.assembler.classic.TransactionServiceInfo;
025: import org.apache.openejb.config.ConfigurationFactory;
026: import org.apache.openejb.core.ivm.EjbObjectInputStream;
027: import org.apache.openejb.core.ivm.IntraVmCopyMonitor;
028: import org.apache.openejb.core.ivm.naming.InitContextFactory;
029: import org.apache.openejb.jee.EjbJar;
030: import org.apache.openejb.jee.StatelessBean;
031:
032: import javax.ejb.CreateException;
033: import javax.ejb.EJBHome;
034: import javax.ejb.EJBObject;
035: import javax.ejb.SessionContext;
036: import javax.naming.InitialContext;
037: import java.io.ByteArrayInputStream;
038: import java.io.ByteArrayOutputStream;
039: import java.io.IOException;
040: import java.io.InputStream;
041: import java.io.ObjectInputStream;
042: import java.io.ObjectOutputStream;
043: import java.rmi.RemoteException;
044: import java.util.Arrays;
045: import java.util.List;
046: import java.util.Stack;
047:
048: /**
049: * @version $Revision: 602704 $ $Date: 2007-12-09 09:58:22 -0800 $
050: */
051: public class CrossClassLoaderProxyTest extends TestCase {
052:
053: public void testBusinessLocalInterface() throws Exception {
054:
055: InitialContext ctx = new InitialContext();
056:
057: Widget widget = (Widget) ctx.lookup("WidgetBeanLocal");
058:
059: // Do a business method...
060: Stack<Lifecycle> lifecycle = widget.getLifecycle();
061: assertNotNull("lifecycle", lifecycle);
062:
063: // Check the lifecycle of the bean
064: List expected = Arrays.asList(Lifecycle.values());
065:
066: assertEquals(join("\n", expected), join("\n", lifecycle));
067: }
068:
069: public void testBusinessRemoteInterface() throws Exception {
070:
071: InitialContext ctx = new InitialContext();
072:
073: RemoteWidget widget = (RemoteWidget) ctx
074: .lookup("WidgetBeanRemote");
075:
076: // Do a business method...
077: Stack<Lifecycle> lifecycle = widget.getLifecycle();
078: assertNotNull("lifecycle", lifecycle);
079: assertNotSame("is copy", lifecycle, WidgetBean.lifecycle);
080:
081: // Check the lifecycle of the bean
082: List expected = Arrays.asList(Lifecycle.values());
083:
084: assertEquals(join("\n", expected), join("\n", lifecycle));
085: }
086:
087: public void testRemoteInterface() throws Exception {
088:
089: InitialContext ctx = new InitialContext();
090: EJBHome home = (EJBHome) ctx.lookup("WidgetBeanRemoteHome");
091: assertNotNull("home", home);
092: assertTrue("home should be an instance of WidgetHome",
093: home instanceof WidgetHome);
094: CrossClassLoaderProxyTestObject.widgetHome = (WidgetHome) home;
095: CrossClassLoaderProxyTestObject proxyTestObject = new CrossClassLoaderProxyTestObject();
096: proxyTestObject.testRemoteInterface();
097: }
098:
099: public void testCrossClassLoaderRemoteInterface() throws Exception {
100: HackClassLoader loader = new HackClassLoader(getClass()
101: .getClassLoader());
102: ClassLoader oldClassLoader = Thread.currentThread()
103: .getContextClassLoader();
104: Thread.currentThread().setContextClassLoader(loader);
105: try {
106: Class testObjectClass = loader
107: .loadClass(CrossClassLoaderProxyTestObject.class
108: .getName());
109: assertFalse(CrossClassLoaderProxyTestObject.class
110: .equals(testObjectClass));
111:
112: Class widgetClass = (Class) testObjectClass.getField(
113: "widgetClass").get(null);
114: assertEquals(Widget.class, widgetClass);
115:
116: Class widgetHomeClass = (Class) testObjectClass.getField(
117: "widgetHomeClass").get(null);
118: assertFalse(WidgetHome.class.equals(widgetHomeClass));
119:
120: Class widgetRemoteClass = (Class) testObjectClass.getField(
121: "widgetRemoteClass").get(null);
122: assertFalse(WidgetRemote.class.equals(widgetRemoteClass));
123:
124: Object testObject = testObjectClass.newInstance();
125:
126: InitialContext ctx = new InitialContext();
127: EJBHome rawHome = (EJBHome) ctx
128: .lookup("WidgetBeanRemoteHome");
129:
130: EJBHome home = (EJBHome) copy(rawHome);
131: assertNotNull("home", home);
132: assertEquals(widgetHomeClass.getClassLoader(), home
133: .getClass().getClassLoader());
134: assertTrue(widgetHomeClass
135: .isAssignableFrom(home.getClass()));
136:
137: testObjectClass.getField("widgetHome")
138: .set(testObject, home);
139:
140: testObjectClass.getMethod("testRemoteInterface").invoke(
141: testObject);
142: } finally {
143: Thread.currentThread()
144: .setContextClassLoader(oldClassLoader);
145: }
146: }
147:
148: private static Object copy(Object source) throws Exception {
149: IntraVmCopyMonitor.preCrossClassLoaderOperation();
150: try {
151: ByteArrayOutputStream baos = new ByteArrayOutputStream(128);
152: ObjectOutputStream out = new ObjectOutputStream(baos);
153: out.writeObject(source);
154: out.close();
155:
156: ByteArrayInputStream bais = new ByteArrayInputStream(baos
157: .toByteArray());
158: ObjectInputStream in = new EjbObjectInputStream(bais);
159: Object copy = in.readObject();
160: return copy;
161: } finally {
162: IntraVmCopyMonitor.postCrossClassLoaderOperation();
163: }
164: }
165:
166: public static class HackClassLoader extends ClassLoader {
167: protected HackClassLoader(ClassLoader parent) {
168: super (parent);
169: }
170:
171: public Class loadClass(String name)
172: throws ClassNotFoundException {
173: return loadClass(name, false);
174: }
175:
176: protected synchronized Class loadClass(String name,
177: boolean resolve) throws ClassNotFoundException {
178: // see if we've already loaded it
179: Class c = findLoadedClass(name);
180: if (c != null) {
181: return c;
182: }
183:
184: if (!name
185: .equals("org.apache.openejb.core.stateless.CrossClassLoaderProxyTest$WidgetHome")
186: && !name
187: .equals("org.apache.openejb.core.stateless.CrossClassLoaderProxyTest$WidgetRemote")
188: && !name
189: .equals("org.apache.openejb.core.stateless.CrossClassLoaderProxyTestObject")) {
190: return super .loadClass(name, resolve);
191: }
192:
193: String resourceName = name.replace('.', '/') + ".class";
194: InputStream in = getResourceAsStream(resourceName);
195: if (in == null) {
196: throw new ClassNotFoundException(name);
197: }
198:
199: // 80% of class files are smaller then 6k
200: ByteArrayOutputStream bout = new ByteArrayOutputStream(
201: 8 * 1024);
202:
203: // copy the input stream into a byte array
204: byte[] bytes = new byte[0];
205: try {
206: byte[] buf = new byte[4 * 1024];
207: for (int count = -1; (count = in.read(buf)) >= 0;) {
208: bout.write(buf, 0, count);
209: }
210: bytes = bout.toByteArray();
211: } catch (IOException e) {
212: throw new ClassNotFoundException(name, e);
213: }
214:
215: // define the package
216: int packageEndIndex = name.lastIndexOf('.');
217: if (packageEndIndex != -1) {
218: String packageName = name.substring(0, packageEndIndex);
219: if (getPackage(packageName) == null) {
220: definePackage(packageName, null, null, null, null,
221: null, null, null);
222: }
223: }
224:
225: // define the class
226: try {
227: return defineClass(name, bytes, 0, bytes.length);
228: } catch (SecurityException e) {
229: // possible prohibited package: defer to the parent
230: return super .loadClass(name, resolve);
231: }
232: }
233:
234: public String toString() {
235: return "HackClassLoader";
236: }
237: }
238:
239: protected void setUp() throws Exception {
240: super .setUp();
241: System.setProperty(
242: javax.naming.Context.INITIAL_CONTEXT_FACTORY,
243: InitContextFactory.class.getName());
244:
245: ConfigurationFactory config = new ConfigurationFactory();
246: Assembler assembler = new Assembler();
247:
248: assembler.createProxyFactory(config
249: .configureService(ProxyFactoryInfo.class));
250: assembler.createTransactionManager(config
251: .configureService(TransactionServiceInfo.class));
252: assembler.createSecurityService(config
253: .configureService(SecurityServiceInfo.class));
254:
255: // containers
256: StatelessSessionContainerInfo statelessContainerInfo = config
257: .configureService(StatelessSessionContainerInfo.class);
258: statelessContainerInfo.properties.setProperty("TimeOut", "10");
259: statelessContainerInfo.properties.setProperty("PoolSize", "0");
260: statelessContainerInfo.properties.setProperty("StrictPooling",
261: "false");
262: assembler.createContainer(statelessContainerInfo);
263:
264: // Setup the descriptor information
265:
266: StatelessBean bean = new StatelessBean(WidgetBean.class);
267: bean.addBusinessLocal(Widget.class.getName());
268: bean.addBusinessRemote(RemoteWidget.class.getName());
269: bean.setHomeAndRemote(WidgetHome.class, WidgetRemote.class);
270: bean.addPostConstruct("init");
271: bean.addPreDestroy("destroy");
272:
273: EjbJar ejbJar = new EjbJar();
274: ejbJar.addEnterpriseBean(bean);
275:
276: assembler
277: .createApplication(config.configureApplication(ejbJar));
278:
279: WidgetBean.lifecycle.clear();
280: }
281:
282: private static String join(String delimeter, List items) {
283: StringBuffer sb = new StringBuffer();
284: for (Object item : items) {
285: sb.append(item.toString()).append(delimeter);
286: }
287: return sb.toString();
288: }
289:
290: public static interface Widget {
291: Stack<Lifecycle> getLifecycle();
292: }
293:
294: public static interface RemoteWidget extends Widget {
295:
296: }
297:
298: public static interface WidgetRemote extends EJBObject {
299: Stack<Lifecycle> getLifecycle();
300: }
301:
302: public static interface WidgetHome extends EJBHome {
303: WidgetRemote create() throws CreateException, RemoteException;
304: }
305:
306: public static enum Lifecycle {
307: CONSTRUCTOR, POST_CONSTRUCT, BUSINESS_METHOD, PRE_DESTROY
308: }
309:
310: public static class WidgetBean implements Widget, RemoteWidget {
311:
312: public static Stack<Lifecycle> lifecycle = new Stack<Lifecycle>();
313:
314: public WidgetBean() {
315: WidgetBean.lifecycle.push(Lifecycle.CONSTRUCTOR);
316: }
317:
318: public void setSessionContext(SessionContext sessionContext) {
319: //lifecycle.push(Lifecycle.INJECTION);
320: }
321:
322: public Stack<Lifecycle> getLifecycle() {
323: WidgetBean.lifecycle.push(Lifecycle.BUSINESS_METHOD);
324: return WidgetBean.lifecycle;
325: }
326:
327: public void init() {
328: WidgetBean.lifecycle.push(Lifecycle.POST_CONSTRUCT);
329: }
330:
331: public void destroy() {
332: WidgetBean.lifecycle.push(Lifecycle.PRE_DESTROY);
333: }
334: }
335: }
|