KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > hivemind > service > impl > BuilderFactoryLogic


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.service.impl;
16
17 import java.lang.reflect.Constructor JavaDoc;
18 import java.lang.reflect.InvocationTargetException JavaDoc;
19 import java.lang.reflect.Method JavaDoc;
20 import java.lang.reflect.Modifier JavaDoc;
21 import java.util.ArrayList JavaDoc;
22 import java.util.Collection JavaDoc;
23 import java.util.Collections JavaDoc;
24 import java.util.Comparator JavaDoc;
25 import java.util.HashSet JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.List JavaDoc;
28 import java.util.Set JavaDoc;
29
30 import org.apache.commons.logging.Log;
31 import org.apache.hivemind.ApplicationRuntimeException;
32 import org.apache.hivemind.HiveMind;
33 import org.apache.hivemind.Location;
34 import org.apache.hivemind.ServiceImplementationFactoryParameters;
35 import org.apache.hivemind.internal.Module;
36 import org.apache.hivemind.service.Autowiring;
37 import org.apache.hivemind.service.AutowiringStrategy;
38 import org.apache.hivemind.service.EventLinker;
39 import org.apache.hivemind.util.ConstructorUtils;
40 import org.apache.hivemind.util.PropertyUtils;
41
42 /**
43  * Created by {@link org.apache.hivemind.service.impl.BuilderFactory} for each service to be
44  * created; encapsulates all the direct and indirect parameters used to construct a service.
45  *
46  * @author Howard Lewis Ship
47  */

48 public class BuilderFactoryLogic
49 {
50     /** @since 1.1 */
51     private ServiceImplementationFactoryParameters _factoryParameters;
52
53     private String JavaDoc _serviceId;
54
55     private BuilderParameter _parameter;
56
57     private Log _log;
58
59     private Module _contributingModule;
60
61     public BuilderFactoryLogic(ServiceImplementationFactoryParameters factoryParameters,
62             BuilderParameter parameter)
63     {
64         _factoryParameters = factoryParameters;
65         _parameter = parameter;
66
67         _log = _factoryParameters.getLog();
68         _serviceId = factoryParameters.getServiceId();
69         _contributingModule = factoryParameters.getInvokingModule();
70     }
71
72     public Object JavaDoc createService()
73     {
74         try
75         {
76             Object JavaDoc result = instantiateCoreServiceInstance();
77
78             setProperties(result);
79
80             registerForEvents(result);
81
82             invokeInitializer(result);
83
84             return result;
85         }
86         catch (Exception JavaDoc ex)
87         {
88             throw new ApplicationRuntimeException(ServiceMessages.failureBuildingService(
89                     _serviceId,
90                     ex), _parameter.getLocation(), ex);
91         }
92     }
93
94     private void error(String JavaDoc message, Location location, Throwable JavaDoc cause)
95     {
96         _factoryParameters.getErrorLog().error(message, location, cause);
97     }
98
99     private Object JavaDoc instantiateCoreServiceInstance()
100     {
101         Class JavaDoc serviceClass = _contributingModule.resolveType(_parameter.getClassName());
102
103         List JavaDoc parameters = _parameter.getParameters();
104
105         if (_parameter.getAutowireServices() && parameters.isEmpty())
106         {
107             return instantiateConstructorAutowiredInstance(serviceClass);
108         }
109
110         return instantiateExplicitConstructorInstance(serviceClass, parameters);
111     }
112
113     private Object JavaDoc instantiateExplicitConstructorInstance(Class JavaDoc serviceClass, List JavaDoc builderParameters)
114     {
115         int numberOfParams = builderParameters.size();
116         List JavaDoc constructorCandidates = getServiceConstructorsOfLength(serviceClass, numberOfParams);
117
118         outer: for (Iterator JavaDoc candidates = constructorCandidates.iterator(); candidates.hasNext();)
119         {
120             Constructor JavaDoc candidate = (Constructor JavaDoc) candidates.next();
121
122             Class JavaDoc[] parameterTypes = candidate.getParameterTypes();
123             
124             Object JavaDoc[] parameters = new Object JavaDoc[parameterTypes.length];
125
126             for (int i = 0; i < numberOfParams; i++)
127             {
128                 BuilderFacet facet = (BuilderFacet) builderParameters.get(i);
129
130                 if (!facet.isAssignableToType(_factoryParameters, parameterTypes[i]))
131                     continue outer;
132
133                 parameters[i] = facet.getFacetValue(_factoryParameters, parameterTypes[i]);
134             }
135
136             return ConstructorUtils.invoke(candidate, parameters);
137         }
138
139         throw new ApplicationRuntimeException(ServiceMessages.unableToFindExplicitConstructor(),
140                 _parameter.getLocation(), null);
141     }
142
143     private List JavaDoc getServiceConstructorsOfLength(Class JavaDoc serviceClass, int length)
144     {
145         List JavaDoc fixedLengthConstructors = new ArrayList JavaDoc();
146
147         Constructor JavaDoc[] constructors = serviceClass.getDeclaredConstructors();
148
149         for (int i = 0; i < constructors.length; i++)
150         {
151             if (!Modifier.isPublic(constructors[i].getModifiers()))
152                 continue;
153
154             Class JavaDoc[] parameterTypes = constructors[i].getParameterTypes();
155
156             if (parameterTypes.length != length)
157                 continue;
158
159             fixedLengthConstructors.add(constructors[i]);
160         }
161
162         return fixedLengthConstructors;
163     }
164
165     private Object JavaDoc instantiateConstructorAutowiredInstance(Class JavaDoc serviceClass)
166     {
167         List JavaDoc serviceConstructorCandidates = getOrderedServiceConstructors(serviceClass);
168
169         outer: for (Iterator JavaDoc candidates = serviceConstructorCandidates.iterator(); candidates
170                 .hasNext();)
171         {
172             Constructor JavaDoc candidate = (Constructor JavaDoc) candidates.next();
173
174             Class JavaDoc[] parameterTypes = candidate.getParameterTypes();
175
176             Object JavaDoc[] parameters = new Object JavaDoc[parameterTypes.length];
177
178             for (int i = 0; i < parameters.length; i++)
179             {
180                 BuilderFacet facet = _parameter.getFacetForType(
181                         _factoryParameters,
182                         parameterTypes[i]);
183
184                 if (facet != null && facet.canAutowireConstructorParameter())
185                     parameters[i] = facet.getFacetValue(_factoryParameters, parameterTypes[i]);
186                 else if (_contributingModule.containsService(parameterTypes[i]))
187                     parameters[i] = _contributingModule.getService(parameterTypes[i]);
188                 else
189                     continue outer;
190             }
191
192             return ConstructorUtils.invoke(candidate, parameters);
193         }
194
195         throw new ApplicationRuntimeException(ServiceMessages.unableToFindAutowireConstructor(),
196                 _parameter.getLocation(), null);
197     }
198
199     private List JavaDoc getOrderedServiceConstructors(Class JavaDoc serviceClass)
200     {
201         List JavaDoc orderedInterfaceConstructors = new ArrayList JavaDoc();
202
203         Constructor JavaDoc[] constructors = serviceClass.getDeclaredConstructors();
204
205         outer: for (int i = 0; i < constructors.length; i++)
206         {
207             if (!Modifier.isPublic(constructors[i].getModifiers()))
208                 continue;
209
210             Class JavaDoc[] parameterTypes = constructors[i].getParameterTypes();
211
212             if (parameterTypes.length > 0)
213             {
214                 Set JavaDoc seenTypes = new HashSet JavaDoc();
215
216                 for (int j = 0; j < parameterTypes.length; j++)
217                 {
218                     if (!parameterTypes[j].isInterface() || seenTypes.contains(parameterTypes[j]))
219                         continue outer;
220
221                     seenTypes.add(parameterTypes[j]);
222                 }
223             }
224
225             orderedInterfaceConstructors.add(constructors[i]);
226         }
227
228         Collections.sort(orderedInterfaceConstructors, new Comparator JavaDoc()
229         {
230             public int compare(Object JavaDoc o1, Object JavaDoc o2)
231             {
232                 return ((Constructor JavaDoc) o2).getParameterTypes().length
233                         - ((Constructor JavaDoc) o1).getParameterTypes().length;
234             }
235         });
236
237         return orderedInterfaceConstructors;
238     }
239
240     private void invokeInitializer(Object JavaDoc service)
241     {
242         String JavaDoc methodName = _parameter.getInitializeMethod();
243
244         boolean allowMissing = HiveMind.isBlank(methodName);
245
246         String JavaDoc searchMethodName = allowMissing ? "initializeService" : methodName;
247
248         try
249         {
250             findAndInvokeInitializerMethod(service, searchMethodName, allowMissing);
251         }
252         catch (InvocationTargetException JavaDoc ex)
253         {
254             Throwable JavaDoc cause = ex.getTargetException();
255
256             error(ServiceMessages.unableToInitializeService(_serviceId, searchMethodName, service
257                     .getClass(), cause), _parameter.getLocation(), cause);
258         }
259         catch (Exception JavaDoc ex)
260         {
261             error(ServiceMessages.unableToInitializeService(_serviceId, searchMethodName, service
262                     .getClass(), ex), _parameter.getLocation(), ex);
263         }
264     }
265
266     private void findAndInvokeInitializerMethod(Object JavaDoc service, String JavaDoc methodName,
267             boolean allowMissing) throws IllegalAccessException JavaDoc, InvocationTargetException JavaDoc,
268             NoSuchMethodException JavaDoc
269     {
270         Class JavaDoc serviceClass = service.getClass();
271
272         try
273         {
274             Method JavaDoc m = serviceClass.getMethod(methodName, (Class JavaDoc []) null);
275
276             m.invoke(service, (Object JavaDoc []) null);
277         }
278         catch (NoSuchMethodException JavaDoc ex)
279         {
280             if (allowMissing)
281                 return;
282
283             throw ex;
284         }
285     }
286
287     private void registerForEvents(Object JavaDoc result)
288     {
289         List JavaDoc eventRegistrations = _parameter.getEventRegistrations();
290
291         if (eventRegistrations.isEmpty())
292             return;
293
294         EventLinker linker = new EventLinkerImpl(_factoryParameters.getErrorLog());
295
296         Iterator JavaDoc i = eventRegistrations.iterator();
297         while (i.hasNext())
298         {
299             EventRegistration er = (EventRegistration) i.next();
300
301             // Will log any errors to the errorHandler
302

303             linker.addEventListener(er.getProducer(), er.getEventSetName(), result, er
304                     .getLocation());
305         }
306     }
307
308     private void setProperties(Object JavaDoc service)
309     {
310         List JavaDoc properties = _parameter.getProperties();
311         int count = properties.size();
312
313         // Track the writeable properties, removing names as they are wired or autowired.
314

315         Set JavaDoc writeableProperties = new HashSet JavaDoc(PropertyUtils.getWriteableProperties(service));
316
317         for (int i = 0; i < count; i++)
318         {
319             BuilderFacet facet = (BuilderFacet) properties.get(i);
320
321             String JavaDoc propertyName = wireProperty(service, facet);
322
323             if (propertyName != null)
324                 writeableProperties.remove(propertyName);
325         }
326
327         if (_parameter.getAutowireServices() && !writeableProperties.isEmpty())
328             autowireServices(service, writeableProperties);
329
330     }
331
332     /**
333      * Wire (or auto-wire) the property; return the name of the property actually set (if a property
334      * is set, which is not always the case).
335      */

336     private String JavaDoc wireProperty(Object JavaDoc service, BuilderFacet facet)
337     {
338         String JavaDoc propertyName = facet.getPropertyName();
339
340         try
341         {
342             // Autowire the property (if possible).
343

344             String JavaDoc autowirePropertyName = facet.autowire(service, _factoryParameters);
345
346             if (autowirePropertyName != null)
347                 return autowirePropertyName;
348
349             // There will be a facet for log, messages, service-id, etc. even if no
350
// property name is specified, so we skip it here. In many cases, those
351
// facets will have just done an autowire.
352

353             if (propertyName == null)
354                 return null;
355
356             Class JavaDoc targetType = PropertyUtils.getPropertyType(service, propertyName);
357
358             Object JavaDoc value = facet.getFacetValue(_factoryParameters, targetType);
359
360             PropertyUtils.write(service, propertyName, value);
361
362             if (_log.isDebugEnabled())
363                 _log.debug("Set property " + propertyName + " to " + value);
364
365             return propertyName;
366         }
367         catch (Exception JavaDoc ex)
368         {
369             error(ex.getMessage(), facet.getLocation(), ex);
370
371             return null;
372         }
373     }
374
375     private void autowireServices(Object JavaDoc service, Collection JavaDoc propertyNames)
376     {
377         Autowiring autowiring = (Autowiring) _contributingModule.getService(HiveMind.AUTOWIRING_SERVICE, Autowiring.class);
378         
379         String JavaDoc[] props = (String JavaDoc[]) propertyNames.toArray(new String JavaDoc[propertyNames.size()]);
380         autowiring.autowireProperties(AutowiringStrategy.BY_TYPE, service, props);
381     }
382
383
384 }
Popular Tags