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.impl; 016 017 import java.lang.reflect.Constructor; 018 import java.lang.reflect.Modifier; 019 020 import org.apache.hivemind.ApplicationRuntimeException; 021 import org.apache.hivemind.events.RegistryShutdownListener; 022 import org.apache.hivemind.internal.ServiceModel; 023 import org.apache.hivemind.internal.ServicePoint; 024 import org.apache.hivemind.service.BodyBuilder; 025 import org.apache.hivemind.service.ClassFab; 026 import org.apache.hivemind.service.ClassFabUtils; 027 import org.apache.hivemind.service.MethodSignature; 028 import org.apache.hivemind.util.ConstructorUtils; 029 030 /** 031 * Contains some common code used to create proxies that defer to a service model method for thier 032 * service. 033 * 034 * @author Howard Lewis Ship 035 */ 036 public final class ProxyUtils 037 { 038 public static final String SERVICE_ACCESSOR_METHOD_NAME = "_service"; 039 040 public static final String DELEGATE_ACCESSOR_METHOD_NAME = "_delegate"; 041 042 private ProxyUtils() 043 { 044 // Prevent instantiation 045 } 046 047 /** 048 * Creates a class that implements the service interface. Implements a private synchronized 049 * method, _service(), that constructs the service as needed, and has each service interface 050 * method re-invoke on _service(). Adds a toString() method if the service interface does not 051 * define toString(). 052 */ 053 public static Object createDelegatingProxy(String type, ServiceModel serviceModel, 054 String delegationMethodName, ServicePoint servicePoint) 055 { 056 ProxyBuilder builder = new ProxyBuilder(type, servicePoint.getModule(), 057 servicePoint.getServiceInterface(), servicePoint.getDeclaredInterface(), false); 058 059 ClassFab classFab = builder.getClassFab(); 060 061 addConstructor(classFab, serviceModel); 062 063 addServiceAccessor(classFab, delegationMethodName, servicePoint); 064 065 builder.addServiceMethods(SERVICE_ACCESSOR_METHOD_NAME + "()"); 066 067 Class proxyClass = classFab.createClass(); 068 069 try 070 { 071 Constructor c = proxyClass.getConstructor(new Class[] 072 { String.class, serviceModel.getClass() }); 073 074 return c.newInstance(new Object[] 075 { servicePoint.getExtensionPointId(), serviceModel }); 076 } 077 catch (Exception ex) 078 { 079 throw new ApplicationRuntimeException(ex); 080 } 081 } 082 083 /** 084 * Constructs an outer proxy (for the threaded or pooled service). The outer proxy listens to 085 * the shutdown coordinator, and delegates from the declared interface (which may in fact be a 086 * bean) to the service interface. 087 * <p> 088 * The outer proxy is a {@link RegistryShutdownListener}; it can be registered for 089 * notifications and will respond by throwing an exception when service methods are invoked. 090 * 091 * @param delegate 092 * An object, implementing the service interface, that the proxy should delegate to. 093 * @param servicePoint 094 * for which the proxy is being constructed 095 * @since 1.1 096 */ 097 098 public static RegistryShutdownListener createOuterProxy(Object delegate, 099 ServicePoint servicePoint) 100 { 101 ProxyBuilder builder = new ProxyBuilder("OuterProxy", servicePoint.getModule(), 102 servicePoint.getServiceInterface(), servicePoint.getDeclaredInterface(), true); 103 104 ClassFab classFab = builder.getClassFab(); 105 106 addDelegateAccessor(classFab, servicePoint, delegate); 107 108 builder.addServiceMethods(DELEGATE_ACCESSOR_METHOD_NAME + "()"); 109 110 Class proxyClass = classFab.createClass(); 111 112 try 113 { 114 return (RegistryShutdownListener) ConstructorUtils.invokeConstructor( 115 proxyClass, 116 new Object[] 117 { servicePoint.getExtensionPointId(), delegate }); 118 } 119 catch (Exception ex) 120 { 121 throw new ApplicationRuntimeException(ex); 122 } 123 } 124 125 /** @since 1.1 */ 126 127 private static void addDelegateAccessor(ClassFab classFab, ServicePoint servicePoint, 128 Object delegate) 129 { 130 classFab.addField("_shutdown", boolean.class); 131 132 Class delegateClass = ClassFabUtils.getInstanceClass(classFab, delegate, servicePoint 133 .getServiceInterface()); 134 135 classFab.addField("_delegate", delegateClass); 136 137 classFab.addConstructor(new Class[] 138 { String.class, delegateClass }, null, "{ this($1); _delegate = $2; }"); 139 140 classFab.addInterface(RegistryShutdownListener.class); 141 if( RegistryShutdownListener.class.isAssignableFrom( delegateClass ) ) 142 { 143 classFab.addMethod(Modifier.PUBLIC | Modifier.FINAL, new MethodSignature(void.class, 144 "registryDidShutdown", null, null), "{ _delegate.registryDidShutdown(); _delegate = null; _shutdown = true; }"); 145 } 146 else 147 { 148 classFab.addMethod(Modifier.PUBLIC | Modifier.FINAL, new MethodSignature(void.class, 149 "registryDidShutdown", null, null), "{ _delegate = null; _shutdown = true; }"); 150 } 151 BodyBuilder builder = new BodyBuilder(); 152 153 builder.begin(); 154 155 builder.addln("if (_shutdown)"); 156 builder.addln(" throw org.apache.hivemind.HiveMind#createRegistryShutdownException();"); 157 158 builder.add("return _delegate;"); 159 160 builder.end(); 161 162 classFab.addMethod(Modifier.FINAL | Modifier.PRIVATE, new MethodSignature(delegateClass, 163 DELEGATE_ACCESSOR_METHOD_NAME, null, null), builder.toString()); 164 } 165 166 /** 167 * Adds a field, _serviceExtensionPoint, whose type matches this class, and a constructor which 168 * sets the field. 169 */ 170 private static void addConstructor(ClassFab classFab, ServiceModel model) 171 { 172 Class modelClass = model.getClass(); 173 174 classFab.addField("_serviceModel", modelClass); 175 176 classFab.addConstructor(new Class[] 177 { String.class, modelClass }, null, "{ this($1); _serviceModel = $2; }"); 178 } 179 180 /** 181 * We construct a method that always goes through this service model's 182 * {@link #getServiceImplementationForCurrentThread()} method. 183 */ 184 private static void addServiceAccessor(ClassFab classFab, String serviceModelMethodName, 185 ServicePoint servicePoint) 186 { 187 Class serviceInterface = servicePoint.getServiceInterface(); 188 189 classFab.addField(SERVICE_ACCESSOR_METHOD_NAME, serviceInterface); 190 191 BodyBuilder builder = new BodyBuilder(); 192 builder.begin(); 193 194 builder.add("return ("); 195 builder.add(serviceInterface.getName()); 196 builder.add(") _serviceModel."); 197 builder.add(serviceModelMethodName); 198 builder.add("();"); 199 200 builder.end(); 201 202 classFab.addMethod(Modifier.PRIVATE | Modifier.FINAL, new MethodSignature(serviceInterface, 203 SERVICE_ACCESSOR_METHOD_NAME, null, null), builder.toString()); 204 } 205 }