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: private ServicePoint _point;
037:
038: private Class _serviceInterface;
039:
040: private ClassFab _classFab;
041:
042: private String _type;
043:
044: public ProxyBuilder(String type, ServicePoint point) {
045: this (type, point, false);
046: }
047:
048: /**
049: * Constructs a new builder. The type will be incorporated into value returned by the
050: * <code>toString()</code> method. The service extension point is used to identify the service
051: * interface and service id.
052: *
053: * @param type
054: * used as part of the <code>toString()</code> method's return value
055: * @param point
056: * the service point for which this proxy is being constructed
057: * @param outerProxy
058: * if false, then the proxy can extend the service points service interface always.
059: * If true and the service point's declared interface is actually a bean class (not
060: * an interface), then the proxy will be a subclass of that bean.
061: */
062: public ProxyBuilder(String type, ServicePoint point,
063: boolean outerProxy) {
064: _point = point;
065: _type = type;
066: _serviceInterface = point.getServiceInterface();
067:
068: Class declaredInterface = point.getDeclaredInterface();
069:
070: Module module = point.getModule();
071: ClassFactory factory = (ClassFactory) module.getService(
072: "hivemind.ClassFactory", ClassFactory.class);
073:
074: boolean extendBeanClass = outerProxy
075: && !declaredInterface.isInterface();
076: Class baseClass = extendBeanClass ? declaredInterface
077: : Object.class;
078:
079: _classFab = factory.newClass(ClassFabUtils
080: .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: _classFab.addInterface(Serializable.class);
095:
096: BodyBuilder bb = new BodyBuilder();
097:
098: bb
099: .add(
100: "return {0}.getServiceSerializationSupport().getServiceTokenForService(\"{1}\");",
101: ServiceSerializationHelper.class.getName(),
102: pointId);
103:
104: MethodSignature sig = new MethodSignature(Object.class,
105: "writeReplace", null, null);
106:
107: _classFab.addMethod(Modifier.PRIVATE, sig, bb.toString());
108: }
109:
110: public ClassFab getClassFab() {
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: BodyBuilder builder = new BodyBuilder();
123:
124: MethodIterator mi = new MethodIterator(_serviceInterface);
125: while (mi.hasNext()) {
126: MethodSignature m = mi.next();
127: if (!_classFab.containsMethod(m)) {
128: builder.clear();
129: builder.begin();
130: builder.add("return ($r) ");
131: builder.add(indirection);
132: builder.add(".");
133: builder.add(m.getName());
134: builder.addln("($$);");
135: builder.end();
136: _classFab.addMethod(Modifier.PUBLIC, m, builder
137: .toString());
138: }
139: }
140:
141: if (!mi.getToString())
142: ClassFabUtils.addToStringMethod(_classFab, "<" + _type
143: + " for " + _point.getExtensionPointId() + "("
144: + _serviceInterface.getName() + ")>");
145: }
146: }
|