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.io.Serializable;
018 import java.lang.reflect.Modifier;
019
020 import org.apache.hivemind.internal.Module;
021 import org.apache.hivemind.internal.ServicePoint;
022 import org.apache.hivemind.internal.ser.ServiceSerializationHelper;
023 import org.apache.hivemind.service.BodyBuilder;
024 import org.apache.hivemind.service.ClassFab;
025 import org.apache.hivemind.service.ClassFabUtils;
026 import org.apache.hivemind.service.ClassFactory;
027 import org.apache.hivemind.service.MethodIterator;
028 import org.apache.hivemind.service.MethodSignature;
029
030 /**
031 * Class used to assist service extension points in creating proxies.
032 *
033 * @author Howard Lewis Ship
034 */
035 public final class ProxyBuilder
036 {
037 private ServicePoint _point;
038
039 private Class _serviceInterface;
040
041 private ClassFab _classFab;
042
043 private String _type;
044
045 public ProxyBuilder(String type, ServicePoint point)
046 {
047 this(type, point, false);
048 }
049
050 /**
051 * Constructs a new builder. The type will be incorporated into value returned by the
052 * <code>toString()</code> method. The service extension point is used to identify the service
053 * interface and service id.
054 *
055 * @param type
056 * used as part of the <code>toString()</code> method's return value
057 * @param point
058 * the service point for which this proxy is being constructed
059 * @param outerProxy
060 * if false, then the proxy can extend the service points service interface always.
061 * If true and the service point's declared interface is actually a bean class (not
062 * an interface), then the proxy will be a subclass of that bean.
063 */
064 public ProxyBuilder(String type, ServicePoint point, boolean outerProxy)
065 {
066 _point = point;
067 _type = type;
068 _serviceInterface = point.getServiceInterface();
069
070 Class declaredInterface = point.getDeclaredInterface();
071
072 Module module = point.getModule();
073 ClassFactory factory = (ClassFactory) module.getService(
074 "hivemind.ClassFactory",
075 ClassFactory.class);
076
077 boolean extendBeanClass = outerProxy && !declaredInterface.isInterface();
078 Class baseClass = extendBeanClass ? declaredInterface : Object.class;
079
080 _classFab = factory.newClass(ClassFabUtils.generateClassName(_serviceInterface), baseClass);
081
082 if (!extendBeanClass)
083 _classFab.addInterface(_serviceInterface);
084
085 // Not exactly certain this will work with non-interface beans that already
086 // are serializable!
087
088 if (outerProxy)
089 addSerializable(point.getExtensionPointId());
090 }
091
092 /** @since 1.1 */
093 private void addSerializable(String pointId)
094 {
095 _classFab.addInterface(Serializable.class);
096
097 BodyBuilder bb = new BodyBuilder();
098
099 bb.add(
100 "return {0}.getServiceSerializationSupport().getServiceTokenForService(\"{1}\");",
101 ServiceSerializationHelper.class.getName(),
102 pointId);
103
104 MethodSignature sig = new MethodSignature(Object.class, "writeReplace", null, null);
105
106 _classFab.addMethod(Modifier.PRIVATE, sig, bb.toString());
107 }
108
109 public ClassFab getClassFab()
110 {
111 return _classFab;
112 }
113
114 /**
115 * Creates the service methods for the class.
116 *
117 * @param indirection
118 * the name of a variable, or a method invocation snippet, used to redirect the
119 * invocation on the proxy to the actual service implementation.
120 */
121 public void addServiceMethods(String indirection)
122 {
123 BodyBuilder builder = new BodyBuilder();
124
125 MethodIterator mi = new MethodIterator(_serviceInterface);
126 while (mi.hasNext())
127 {
128 MethodSignature m = mi.next();
129 if( !_classFab.containsMethod( m ) )
130 {
131 builder.clear();
132 builder.begin();
133 builder.add("return ($r) ");
134 builder.add(indirection);
135 builder.add(".");
136 builder.add(m.getName());
137 builder.addln("($$);");
138 builder.end();
139 _classFab.addMethod(Modifier.PUBLIC, m, builder.toString());
140 }
141 }
142
143 if (!mi.getToString())
144 ClassFabUtils.addToStringMethod(_classFab, "<" + _type + " for "
145 + _point.getExtensionPointId() + "(" + _serviceInterface.getName() + ")>");
146 }
147 }