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 }