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 }