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    }