KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > hivemind > lib > pipeline > BridgeBuilder


1 // Copyright 2004, 2005 The Apache Software Foundation
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15 package org.apache.hivemind.lib.pipeline;
16
17 import java.lang.reflect.Constructor JavaDoc;
18 import java.lang.reflect.Modifier JavaDoc;
19 import java.util.ArrayList JavaDoc;
20 import java.util.Iterator JavaDoc;
21 import java.util.List JavaDoc;
22
23 import org.apache.hivemind.ApplicationRuntimeException;
24 import org.apache.hivemind.ErrorLog;
25 import org.apache.hivemind.service.BodyBuilder;
26 import org.apache.hivemind.service.ClassFab;
27 import org.apache.hivemind.service.ClassFabUtils;
28 import org.apache.hivemind.service.ClassFactory;
29 import org.apache.hivemind.service.MethodIterator;
30 import org.apache.hivemind.service.MethodSignature;
31
32 /**
33  * Used by the {@link org.apache.hivemind.lib.pipeline.PipelineAssembler} class to create bridge
34  * classes and to create instances of briddge classes.
35  *
36  * @author Howard Lewis Ship
37  */

38 class BridgeBuilder
39 {
40     private ErrorLog _errorLog;
41
42     private String JavaDoc _serviceId;
43
44     private Class JavaDoc _serviceInterface;
45
46     private Class JavaDoc _filterInterface;
47
48     private ClassFab _classFab;
49
50     private FilterMethodAnalyzer _filterMethodAnalyzer;
51
52     private Constructor JavaDoc _constructor;
53
54     BridgeBuilder(ErrorLog errorLog, String JavaDoc serviceId, Class JavaDoc serviceInterface,
55             Class JavaDoc filterInterface, ClassFactory classFactory)
56     {
57         _errorLog = errorLog;
58         _serviceId = serviceId;
59         _serviceInterface = serviceInterface;
60         _filterInterface = filterInterface;
61
62         String JavaDoc name = ClassFabUtils.generateClassName(_serviceInterface);
63
64         _classFab = classFactory.newClass(name, Object JavaDoc.class);
65
66         _filterMethodAnalyzer = new FilterMethodAnalyzer(serviceInterface);
67     }
68
69     private void createClass()
70     {
71         List JavaDoc serviceMethods = new ArrayList JavaDoc();
72         List JavaDoc filterMethods = new ArrayList JavaDoc();
73
74         createInfrastructure();
75
76         MethodIterator mi = new MethodIterator(_serviceInterface);
77
78         while (mi.hasNext())
79         {
80             serviceMethods.add(mi.next());
81         }
82
83         boolean toStringMethodExists = mi.getToString();
84
85         mi = new MethodIterator(_filterInterface);
86
87         while (mi.hasNext())
88         {
89             filterMethods.add(mi.next());
90         }
91
92         while (!serviceMethods.isEmpty())
93         {
94             MethodSignature ms = (MethodSignature) serviceMethods.remove(0);
95
96             addBridgeMethod(ms, filterMethods);
97         }
98
99         reportExtraFilterMethods(filterMethods);
100
101         if (!toStringMethodExists)
102             ClassFabUtils.addToStringMethod(_classFab, PipelineMessages.bridgeInstanceDescription(
103                     _serviceId,
104                     _serviceInterface));
105
106         Class JavaDoc bridgeClass = _classFab.createClass();
107
108         _constructor = bridgeClass.getConstructors()[0];
109     }
110
111     private void createInfrastructure()
112     {
113         _classFab.addField("_next", _serviceInterface);
114         _classFab.addField("_filter", _filterInterface);
115
116         _classFab.addConstructor(new Class JavaDoc[]
117         { _serviceInterface, _filterInterface }, null, "{ _next = $1; _filter = $2; }");
118
119         _classFab.addInterface(_serviceInterface);
120     }
121
122     /**
123      * Instantiates a bridge object.
124      *
125      * @param nextBridge
126      * the next Bridge object in the pipeline, or the terminator service
127      * @param filter
128      * the filter object for this step of the pipeline
129      */

130     public Object JavaDoc instantiateBridge(Object JavaDoc nextBridge, Object JavaDoc filter)
131     {
132         if (_constructor == null)
133             createClass();
134
135         try
136         {
137             return _constructor.newInstance(new Object JavaDoc[]
138             { nextBridge, filter });
139         }
140         catch (Exception JavaDoc ex)
141         {
142             throw new ApplicationRuntimeException(ex);
143         }
144     }
145
146     private void reportExtraFilterMethods(List JavaDoc filterMethods)
147     {
148         Iterator JavaDoc i = filterMethods.iterator();
149
150         while (i.hasNext())
151         {
152             MethodSignature ms = (MethodSignature) i.next();
153
154             _errorLog.error(PipelineMessages.extraFilterMethod(
155                     ms,
156                     _filterInterface,
157                     _serviceInterface,
158                     _serviceId), null, null);
159         }
160     }
161
162     /**
163      * Finds a matching method in filterMethods for the given service method. A matching method has
164      * the same signature as the service interface method, but with an additional parameter matching
165      * the service interface itself.
166      * <p>
167      * The matching method signature from the list of filterMethods is removed and code generation
168      * strategies for making the two methods call each other are added.
169      */

170     private void addBridgeMethod(MethodSignature ms, List JavaDoc filterMethods)
171     {
172         Iterator JavaDoc i = filterMethods.iterator();
173
174         while (i.hasNext())
175         {
176             MethodSignature fms = (MethodSignature) i.next();
177
178             int position = _filterMethodAnalyzer.findServiceInterfacePosition(ms, fms);
179
180             if (position >= 0)
181             {
182                 addBridgeMethod(position, ms, fms);
183                 i.remove();
184                 return;
185             }
186         }
187
188         String JavaDoc message = PipelineMessages.unmatchedServiceMethod(ms, _filterInterface);
189
190         _errorLog.error(message, null, null);
191
192         BodyBuilder b = new BodyBuilder();
193
194         b.add("throw new org.apache.hivemind.ApplicationRuntimeException(");
195         b.addQuoted(message);
196         b.addln(");");
197
198         _classFab.addMethod(Modifier.PUBLIC, ms, b.toString());
199     }
200
201     /**
202      * Adds a method to the class which bridges from the service method to the corresponding method
203      * in the filter interface. The next service (either another Bridge, or the terminator at the
204      * end of the pipeline) is passed to the filter).
205      */

206     private void addBridgeMethod(int position, MethodSignature ms, MethodSignature fms)
207     {
208         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(100);
209
210         if (ms.getReturnType() != void.class)
211             buffer.append("return ");
212
213         buffer.append("_filter.");
214         buffer.append(ms.getName());
215         buffer.append("(");
216
217         boolean comma = false;
218         int filterParameterCount = fms.getParameterTypes().length;
219
220         for (int i = 0; i < position; i++)
221         {
222             if (comma)
223                 buffer.append(", ");
224
225             buffer.append("$");
226             // Add one to the index to get the parameter symbol ($0 is the implicit
227
// this parameter).
228
buffer.append(i + 1);
229
230             comma = true;
231         }
232
233         if (comma)
234             buffer.append(", ");
235
236         // _next is the variable in -this- Bridge that points to the -next- Bridge
237
// or the terminator for the pipeline. The filter is expected to reinvoke the
238
// method on the _next that's passed to it.
239

240         buffer.append("_next");
241
242         for (int i = position + 1; i < filterParameterCount; i++)
243         {
244             buffer.append(", $");
245             buffer.append(i);
246         }
247
248         buffer.append(");");
249
250         // This should work, unless the exception types turn out to not be compatble. We still
251
// don't do a check on that, and not sure that Javassist does either!
252

253         _classFab.addMethod(Modifier.PUBLIC, ms, buffer.toString());
254     }
255
256 }
Popular Tags