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