001 // Copyright 2004, 2005 The Apache Software Foundation 002 // 003 // Licensed under the Apache License, Version 2.0 (the "License"); 004 // you may not use this file except in compliance with the License. 005 // You may obtain a copy of the License at 006 // 007 // http://www.apache.org/licenses/LICENSE-2.0 008 // 009 // Unless required by applicable law or agreed to in writing, software 010 // distributed under the License is distributed on an "AS IS" BASIS, 011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012 // See the License for the specific language governing permissions and 013 // limitations under the License. 014 015 package org.apache.hivemind.lib.impl; 016 017 import java.lang.reflect.Constructor; 018 import java.lang.reflect.Modifier; 019 import java.rmi.RemoteException; 020 021 import org.apache.hivemind.ApplicationRuntimeException; 022 import org.apache.hivemind.ServiceImplementationFactory; 023 import org.apache.hivemind.ServiceImplementationFactoryParameters; 024 import org.apache.hivemind.impl.BaseLocatable; 025 import org.apache.hivemind.internal.Module; 026 import org.apache.hivemind.lib.NameLookup; 027 import org.apache.hivemind.lib.RemoteExceptionCoordinator; 028 import org.apache.hivemind.service.BodyBuilder; 029 import org.apache.hivemind.service.ClassFab; 030 import org.apache.hivemind.service.ClassFabUtils; 031 import org.apache.hivemind.service.ClassFactory; 032 import org.apache.hivemind.service.MethodIterator; 033 import org.apache.hivemind.service.MethodSignature; 034 035 /** 036 * An implementation of {@link org.apache.hivemind.ServiceImplementationFactory} 037 * that can create a proxy to a stateless session EJB. Using this factory, it is 038 * easy to create a HiveMind service wrapper around the actual EJB. 039 * 040 * <p> 041 * The parameters for the factory are used to identify the JNDI name of the 042 * session EJB's home interface. 043 * 044 * @author Howard Lewis Ship 045 */ 046 public class EJBProxyFactory extends BaseLocatable implements ServiceImplementationFactory 047 { 048 private NameLookup _nameLookup; 049 private RemoteExceptionCoordinator _coordinator; 050 private ClassFactory _classFactory; 051 052 public Object createCoreServiceImplementation(ServiceImplementationFactoryParameters factoryParameters) 053 { 054 EJBProxyParameters proxyParameters = (EJBProxyParameters) factoryParameters.getParameters().get(0); 055 String jndiName = proxyParameters.getJndiName(); 056 String homeInterfaceClassName = proxyParameters.getHomeInterfaceClassName(); 057 058 // The service interface is the remote interface. 059 060 Module module = factoryParameters.getInvokingModule(); 061 Class serviceInterface = factoryParameters.getServiceInterface(); 062 063 Class homeInterface = module.resolveType(homeInterfaceClassName); 064 065 String proxyClassName = ClassFabUtils.generateClassName(serviceInterface); 066 067 ClassFab classFab = 068 _classFactory.newClass( 069 proxyClassName, 070 AbstractEJBProxy.class); 071 072 classFab.addInterface(serviceInterface); 073 074 classFab.addField("_remote", serviceInterface); 075 076 addClearCachedMethod(classFab); 077 078 addLookupMethod(classFab, homeInterface, serviceInterface, jndiName); 079 080 addServiceMethods(classFab, serviceInterface, factoryParameters.getServiceId(), jndiName); 081 082 addConstructor(classFab); 083 084 Class proxyClass = classFab.createClass(); 085 086 return invokeConstructor(proxyClass, proxyParameters.getNameLookup(_nameLookup)); 087 } 088 089 private void addClearCachedMethod(ClassFab classFab) 090 { 091 classFab.addMethod( 092 Modifier.PROTECTED, 093 new MethodSignature(void.class, "_clearCachedReferences", null, null), 094 "_remote = null;"); 095 } 096 097 private void addLookupMethod( 098 ClassFab classFab, 099 Class homeInterface, 100 Class remoteInterface, 101 String jndiName) 102 { 103 String homeInterfaceName = homeInterface.getName(); 104 105 BodyBuilder builder = new BodyBuilder(); 106 107 builder.begin(); 108 109 builder.addln("if (_remote != null)"); 110 builder.addln(" return _remote;"); 111 112 builder.add(homeInterfaceName); 113 builder.add(" home = ("); 114 builder.add(homeInterfaceName); 115 builder.add(") _lookup("); 116 builder.addQuoted(jndiName); 117 builder.addln(");"); 118 119 builder.add("try"); 120 builder.begin(); 121 builder.add("_remote = home.create();"); 122 builder.end(); 123 builder.add("catch (javax.ejb.CreateException ex)"); 124 builder.begin(); 125 builder.add("throw new java.rmi.RemoteException(ex.getMessage(), ex);"); 126 builder.end(); 127 128 builder.add("return _remote;"); 129 130 builder.end(); 131 132 classFab.addMethod( 133 Modifier.SYNCHRONIZED + Modifier.PRIVATE, 134 new MethodSignature( 135 remoteInterface, 136 "_lookupRemote", 137 null, 138 new Class[] { RemoteException.class }), 139 builder.toString()); 140 141 } 142 143 private void addServiceMethods( 144 ClassFab classFab, 145 Class serviceInterface, 146 String serviceId, 147 String jndiName) 148 { 149 MethodIterator mi = new MethodIterator(serviceInterface); 150 151 while (mi.hasNext()) 152 { 153 addServiceMethod(classFab, mi.next()); 154 } 155 156 if (!mi.getToString()) 157 addToStringMethod(classFab, serviceInterface, serviceId, jndiName); 158 } 159 160 private void addServiceMethod(ClassFab classFab, MethodSignature sig) 161 { 162 String methodName = sig.getName(); 163 164 boolean isVoid = sig.getReturnType().equals(Void.TYPE); 165 166 BodyBuilder builder = new BodyBuilder(); 167 168 builder.begin(); 169 170 builder.addln("boolean first = true;"); 171 builder.add("while (true)"); 172 builder.begin(); 173 174 builder.add("try"); 175 builder.begin(); 176 177 if (!isVoid) 178 builder.add("return "); 179 180 builder.add("_lookupRemote()."); 181 builder.add(methodName); 182 builder.addln("($$);"); 183 184 if (isVoid) 185 builder.addln("return;"); 186 187 builder.end(); // try 188 189 builder.add("catch (java.rmi.RemoteException ex)"); 190 builder.begin(); 191 192 builder.addln("if (first)"); 193 builder.begin(); 194 195 builder.addln("_handleRemoteException(ex);"); 196 builder.addln("first = false;"); 197 198 builder.end(); // if 199 builder.addln("else"); 200 builder.add(" throw ex;"); 201 builder.end(); // catch 202 builder.end(); // while 203 builder.end(); 204 205 classFab.addMethod(Modifier.PUBLIC, sig, builder.toString()); 206 } 207 208 private void addToStringMethod( 209 ClassFab classFab, 210 Class serviceInterface, 211 String serviceId, 212 String jndiName) 213 { 214 ClassFabUtils.addToStringMethod( 215 classFab, 216 ImplMessages.ejbProxyDescription(serviceId, serviceInterface, jndiName)); 217 } 218 219 private void addConstructor(ClassFab classFab) 220 { 221 classFab.addConstructor( 222 new Class[] { NameLookup.class, RemoteExceptionCoordinator.class }, 223 null, 224 "super($1, $2);"); 225 } 226 227 private Object invokeConstructor(Class proxyClass, NameLookup nameLookup) 228 { 229 try 230 { 231 Constructor c = 232 proxyClass.getConstructor( 233 new Class[] { NameLookup.class, RemoteExceptionCoordinator.class }); 234 235 return c.newInstance(new Object[] { nameLookup, _coordinator }); 236 } 237 catch (Exception ex) 238 { 239 throw new ApplicationRuntimeException(ex); 240 } 241 } 242 243 public void setClassFactory(ClassFactory factory) 244 { 245 _classFactory = factory; 246 } 247 248 public void setCoordinator(RemoteExceptionCoordinator coordinator) 249 { 250 _coordinator = coordinator; 251 } 252 253 public void setNameLookup(NameLookup lookup) 254 { 255 _nameLookup = lookup; 256 } 257 258 }