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); 057 058 ClassFab classFab = builder.getClassFab(); 059 060 addConstructor(classFab, serviceModel); 061 062 addServiceAccessor(classFab, delegationMethodName, servicePoint); 063 064 builder.addServiceMethods(SERVICE_ACCESSOR_METHOD_NAME + "()"); 065 066 Class proxyClass = classFab.createClass(); 067 068 try 069 { 070 Constructor c = proxyClass.getConstructor(new Class[] 071 { serviceModel.getClass() }); 072 073 return c.newInstance(new Object[] 074 { serviceModel }); 075 } 076 catch (Exception ex) 077 { 078 throw new ApplicationRuntimeException(ex); 079 } 080 } 081 082 /** 083 * Constructs an outer proxy (for the threaded or pooled service). The outer proxy listens to 084 * the shutdown coordinator, and delegates from the declared interface (which may in fact be a 085 * bean) to the service interface. 086 * <p> 087 * The outer proxy is a {@link RegistryShutdownListener}; it can be registered for 088 * notifications and will respond by throwing an exception when service methods are invoked. 089 * 090 * @param delegate 091 * An object, implementing the service interface, that the proxy should delegate to. 092 * @param servicePoint 093 * for which the proxy is being constructed 094 * @since 1.1 095 */ 096 097 public static RegistryShutdownListener createOuterProxy(Object delegate, 098 ServicePoint servicePoint) 099 { 100 ProxyBuilder builder = new ProxyBuilder("OuterProxy", servicePoint, true); 101 102 ClassFab classFab = builder.getClassFab(); 103 104 addDelegateAccessor(classFab, servicePoint, delegate); 105 106 builder.addServiceMethods(DELEGATE_ACCESSOR_METHOD_NAME + "()"); 107 108 Class proxyClass = classFab.createClass(); 109 110 try 111 { 112 return (RegistryShutdownListener) ConstructorUtils.invokeConstructor( 113 proxyClass, 114 new Object[] 115 { delegate }); 116 } 117 catch (Exception ex) 118 { 119 throw new ApplicationRuntimeException(ex); 120 } 121 } 122 123 /** @since 1.1 */ 124 125 private static void addDelegateAccessor(ClassFab classFab, ServicePoint servicePoint, 126 Object delegate) 127 { 128 classFab.addField("_shutdown", boolean.class); 129 130 Class delegateClass = ClassFabUtils.getInstanceClass(delegate, servicePoint 131 .getServiceInterface()); 132 133 classFab.addField("_delegate", delegateClass); 134 135 classFab.addConstructor(new Class[] 136 { delegateClass }, null, "{ super(); _delegate = $1; }"); 137 138 classFab.addInterface(RegistryShutdownListener.class); 139 if( RegistryShutdownListener.class.isAssignableFrom( delegateClass ) ) 140 { 141 classFab.addMethod(Modifier.PUBLIC | Modifier.FINAL, new MethodSignature(void.class, 142 "registryDidShutdown", null, null), "{ _delegate.registryDidShutdown(); _delegate = null; _shutdown = true; }"); 143 } 144 else 145 { 146 classFab.addMethod(Modifier.PUBLIC | Modifier.FINAL, new MethodSignature(void.class, 147 "registryDidShutdown", null, null), "{ _delegate = null; _shutdown = true; }"); 148 } 149 BodyBuilder builder = new BodyBuilder(); 150 151 builder.begin(); 152 153 builder.addln("if (_shutdown)"); 154 builder.addln(" throw org.apache.hivemind.HiveMind#createRegistryShutdownException();"); 155 156 builder.add("return _delegate;"); 157 158 builder.end(); 159 160 classFab.addMethod(Modifier.FINAL | Modifier.PRIVATE, new MethodSignature(delegateClass, 161 DELEGATE_ACCESSOR_METHOD_NAME, null, null), builder.toString()); 162 } 163 164 /** 165 * Adds a field, _serviceExtensionPoint, whose type matches this class, and a constructor which 166 * sets the field. 167 */ 168 private static void addConstructor(ClassFab classFab, ServiceModel model) 169 { 170 Class modelClass = model.getClass(); 171 172 classFab.addField("_serviceModel", modelClass); 173 174 classFab.addConstructor(new Class[] 175 { modelClass }, null, "{ super(); _serviceModel = $1; }"); 176 } 177 178 /** 179 * We construct a method that always goes through this service model's 180 * {@link #getServiceImplementationForCurrentThread())} method. 181 */ 182 private static void addServiceAccessor(ClassFab classFab, String serviceModelMethodName, 183 ServicePoint servicePoint) 184 { 185 Class serviceInterface = servicePoint.getServiceInterface(); 186 187 classFab.addField(SERVICE_ACCESSOR_METHOD_NAME, serviceInterface); 188 189 BodyBuilder builder = new BodyBuilder(); 190 builder.begin(); 191 192 builder.add("return ("); 193 builder.add(serviceInterface.getName()); 194 builder.add(") _serviceModel."); 195 builder.add(serviceModelMethodName); 196 builder.add("();"); 197 198 builder.end(); 199 200 classFab.addMethod(Modifier.PRIVATE | Modifier.FINAL, new MethodSignature(serviceInterface, 201 SERVICE_ACCESSOR_METHOD_NAME, null, null), builder.toString()); 202 } 203 }