KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > hivemind > lib > strategy > StrategyFactory


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.strategy;
16
17 import java.lang.reflect.Constructor JavaDoc;
18 import java.lang.reflect.Modifier JavaDoc;
19 import java.util.Iterator JavaDoc;
20 import java.util.List JavaDoc;
21
22 import org.apache.hivemind.ApplicationRuntimeException;
23 import org.apache.hivemind.HiveMind;
24 import org.apache.hivemind.ServiceImplementationFactory;
25 import org.apache.hivemind.ServiceImplementationFactoryParameters;
26 import org.apache.hivemind.lib.util.StrategyRegistry;
27 import org.apache.hivemind.lib.util.StrategyRegistryImpl;
28 import org.apache.hivemind.service.ClassFab;
29 import org.apache.hivemind.service.ClassFabUtils;
30 import org.apache.hivemind.service.ClassFactory;
31 import org.apache.hivemind.service.MethodIterator;
32 import org.apache.hivemind.service.MethodSignature;
33
34 /**
35  * Implementation of the <code>hivemind.lib.StrategyFactory</code> service that constructs a
36  * service where the first parameter of each method is used to selecte a strategy from an
37  * {@link org.apache.hivemind.lib.util.StrategyRegistry}. The method invocation is then delegated
38  * to the strategy instance.
39  * <p>
40  * The service factory parameter defines a configuration (of
41  * {@link org.apache.hivemind.lib.strategy.StrategyContribution}s) that provide the mapping from
42  * Java classes (or interfaces) to adapter instances.
43  *
44  * @author Howard M. Lewis Ship
45  * @since 1.1
46  */

47 public class StrategyFactory implements ServiceImplementationFactory
48 {
49     private ClassFactory _classFactory;
50
51     public Object JavaDoc createCoreServiceImplementation(
52             ServiceImplementationFactoryParameters factoryParameters)
53     {
54         StrategyRegistry ar = new StrategyRegistryImpl();
55
56         buildRegistry(factoryParameters, ar);
57
58         Class JavaDoc implClass = buildImplementationClass(factoryParameters);
59
60         try
61         {
62             Constructor JavaDoc c = implClass.getConstructors()[0];
63
64             return c.newInstance(new Object JavaDoc[]
65             { ar });
66         }
67         catch (Exception JavaDoc ex)
68         {
69             throw new ApplicationRuntimeException(ex.getMessage(), HiveMind
70                     .getLocation(factoryParameters.getFirstParameter()), ex);
71         }
72
73     }
74
75     // package private for testing purposes
76

77     void buildRegistry(ServiceImplementationFactoryParameters factoryParameters, StrategyRegistry ar)
78     {
79         Class JavaDoc serviceInterface = factoryParameters.getServiceInterface();
80
81         StrategyParameter p = (StrategyParameter) factoryParameters.getFirstParameter();
82
83         List JavaDoc contributions = p.getContributions();
84
85         Iterator JavaDoc i = contributions.iterator();
86
87         while (i.hasNext())
88         {
89             StrategyContribution c = (StrategyContribution) i.next();
90
91             try
92             {
93                 Object JavaDoc adapter = c.getStrategy();
94
95                 if (!serviceInterface.isAssignableFrom(adapter.getClass()))
96                     throw new ClassCastException JavaDoc(StrategyMessages.strategyWrongInterface(adapter, c
97                             .getRegisterClass(), serviceInterface));
98
99                 ar.register(c.getRegisterClass(), adapter);
100             }
101             catch (Exception JavaDoc ex)
102             {
103                 factoryParameters.getErrorLog().error(ex.getMessage(), c.getLocation(), ex);
104             }
105
106         }
107
108     }
109
110     // package private for testing purposes
111

112     private Class JavaDoc buildImplementationClass(ServiceImplementationFactoryParameters factoryParameters)
113     {
114         String JavaDoc name = ClassFabUtils.generateClassName(factoryParameters.getServiceInterface());
115
116         return buildImplementationClass(factoryParameters, name);
117     }
118
119     // package private for testing purposes
120

121     Class JavaDoc buildImplementationClass(ServiceImplementationFactoryParameters factoryParameters,
122             String JavaDoc name)
123     {
124         Class JavaDoc serviceInterface = factoryParameters.getServiceInterface();
125
126         ClassFab cf = _classFactory.newClass(name, Object JavaDoc.class);
127
128         cf.addInterface(serviceInterface);
129
130         cf.addField("_registry", StrategyRegistry.class);
131
132         cf.addConstructor(new Class JavaDoc[]
133         { StrategyRegistry.class }, null, "_registry = $1;");
134
135         // TODO: Should we add a check for $1 == null?
136

137         cf.addMethod(Modifier.PRIVATE, new MethodSignature(serviceInterface, "_getStrategy",
138                 new Class JavaDoc[]
139                 { Object JavaDoc.class }, null), "return (" + serviceInterface.getName()
140                 + ") _registry.getStrategy($1.getClass());");
141
142         MethodIterator i = new MethodIterator(serviceInterface);
143
144         while (i.hasNext())
145         {
146             MethodSignature sig = i.next();
147
148             if (proper(sig))
149             {
150                 addAdaptedMethod(cf, sig);
151             }
152             else
153             {
154                 ClassFabUtils.addNoOpMethod(cf, sig);
155
156                 factoryParameters.getErrorLog().error(
157                         StrategyMessages.improperServiceMethod(sig),
158                         HiveMind.getLocation(factoryParameters.getFirstParameter()),
159                         null);
160             }
161
162         }
163
164         if (!i.getToString())
165             ClassFabUtils.addToStringMethod(cf, StrategyMessages.toString(factoryParameters
166                     .getServiceId(), serviceInterface));
167
168         return cf.createClass();
169     }
170
171     private void addAdaptedMethod(ClassFab cf, MethodSignature sig)
172     {
173         String JavaDoc body = "return ($r) _getStrategy($1)." + sig.getName() + "($$);";
174
175         cf.addMethod(Modifier.PUBLIC, sig, body);
176     }
177
178     /**
179      * A "proper" method is one with at least one parameter and whose first parameter is an object
180      * (not primitive) type.
181      */

182
183     private boolean proper(MethodSignature sig)
184     {
185         Class JavaDoc[] parameterTypes = sig.getParameterTypes();
186
187         return parameterTypes != null && parameterTypes.length > 0
188                 && !parameterTypes[0].isPrimitive();
189     }
190
191     public void setClassFactory(ClassFactory classFactory)
192     {
193         _classFactory = classFactory;
194     }
195 }
Popular Tags