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.util.ArrayList;
018 import java.util.Iterator;
019 import java.util.List;
020
021 import org.apache.commons.logging.Log;
022 import org.apache.commons.logging.LogFactory;
023 import org.apache.hivemind.ApplicationRuntimeException;
024 import org.apache.hivemind.HiveMind;
025 import org.apache.hivemind.Occurances;
026 import org.apache.hivemind.ShutdownCoordinator;
027 import org.apache.hivemind.events.RegistryShutdownListener;
028 import org.apache.hivemind.internal.ServiceImplementationConstructor;
029 import org.apache.hivemind.internal.ServiceInterceptorContribution;
030 import org.apache.hivemind.internal.ServiceModel;
031 import org.apache.hivemind.internal.ServiceModelFactory;
032 import org.apache.hivemind.order.Orderer;
033 import org.apache.hivemind.schema.Schema;
034 import org.apache.hivemind.service.InterfaceSynthesizer;
035 import org.apache.hivemind.util.ToStringBuilder;
036
037 /**
038 * Abstract implementation of {@link org.apache.hivemind.internal.ServicePoint}. Provides some of
039 * the machinery for creating new service instances, delegating most of it to the
040 * {@link org.apache.hivemind.internal.ServiceModel} instace for the service.
041 *
042 * @author Howard Lewis Ship
043 */
044 public final class ServicePointImpl extends AbstractExtensionPoint implements
045 ConstructableServicePoint
046 {
047 private Object _service;
048
049 private boolean _building;
050
051 private String _serviceInterfaceName;
052
053 private Class _serviceInterface;
054
055 private Class _declaredInterface;
056
057 private ServiceImplementationConstructor _defaultServiceConstructor;
058
059 private ServiceImplementationConstructor _serviceConstructor;
060
061 private List _interceptorContributions;
062
063 private boolean _interceptorsOrdered;
064
065 private Schema _parametersSchema;
066
067 private Occurances _parametersCount;
068
069 private String _serviceModel;
070
071 private ShutdownCoordinator _shutdownCoordinator;
072
073 private ServiceModel _serviceModelObject;
074
075 protected void extendDescription(ToStringBuilder builder)
076 {
077 if (_service != null)
078 builder.append("service", _service);
079
080 builder.append("serviceInterfaceName", _serviceInterfaceName);
081 builder.append("defaultServiceConstructor", _defaultServiceConstructor);
082 builder.append("serviceConstructor", _serviceConstructor);
083 builder.append("interceptorContributions", _interceptorContributions);
084 builder.append("parametersSchema", _parametersSchema);
085 builder.append("parametersCount", _parametersCount);
086 builder.append("serviceModel", _serviceModel);
087
088 if (_building)
089 builder.append("building", _building);
090 }
091
092 public void addInterceptorContribution(ServiceInterceptorContribution contribution)
093 {
094 if (_interceptorContributions == null)
095 _interceptorContributions = new ArrayList();
096
097 _interceptorContributions.add(contribution);
098 }
099
100 public synchronized Class getServiceInterface()
101 {
102 if (_serviceInterface == null)
103 _serviceInterface = lookupServiceInterface();
104
105 return _serviceInterface;
106 }
107
108 public synchronized Class getDeclaredInterface()
109 {
110 if (_declaredInterface == null)
111 _declaredInterface = lookupDeclaredInterface();
112
113 return _declaredInterface;
114 }
115
116 /** @since 1.1 */
117
118 public String getServiceInterfaceClassName()
119 {
120 return _serviceInterfaceName;
121 }
122
123 private Class lookupDeclaredInterface()
124 {
125 Class result = null;
126
127 try
128 {
129 result = getModule().resolveType(_serviceInterfaceName);
130 }
131 catch (Exception ex)
132 {
133 throw new ApplicationRuntimeException(ImplMessages.badInterface(
134 _serviceInterfaceName,
135 getExtensionPointId()), getLocation(), ex);
136 }
137
138 return result;
139 }
140
141 private Class lookupServiceInterface()
142 {
143 Class declaredInterface = getDeclaredInterface();
144
145 if (declaredInterface.isInterface())
146 return declaredInterface;
147
148 // Not an interface ... a class. Synthesize an interface from the class itself.
149
150 InterfaceSynthesizer is = (InterfaceSynthesizer) getModule().getService(
151 HiveMind.INTERFACE_SYNTHESIZER_SERVICE,
152 InterfaceSynthesizer.class);
153
154 return is.synthesizeInterface(declaredInterface);
155 }
156
157 public void setServiceConstructor(ServiceImplementationConstructor contribution,
158 boolean defaultConstructor)
159 {
160 if (defaultConstructor)
161 _defaultServiceConstructor = contribution;
162 else
163 _serviceConstructor = contribution;
164 }
165
166 public void setServiceInterfaceName(String string)
167 {
168 _serviceInterfaceName = string;
169 }
170
171 public void setParametersSchema(Schema schema)
172 {
173 _parametersSchema = schema;
174 }
175
176 public Schema getParametersSchema()
177 {
178 return _parametersSchema;
179 }
180
181 public ServiceImplementationConstructor getServiceConstructor(boolean defaultConstructor)
182 {
183 return defaultConstructor ? _defaultServiceConstructor : _serviceConstructor;
184 }
185
186 /**
187 * Invoked by {@link #getService(Class)} to get a service implementation from the
188 * {@link ServiceModel}.
189 * <p>
190 * TODO: I'm concerned that this synchronized method could cause a deadlock. It would take a LOT
191 * (mutually dependent services in multiple threads being realized at the same time).
192 */
193 private synchronized Object getService()
194 {
195 if (_service == null)
196 {
197
198 if (_building)
199 throw new ApplicationRuntimeException(ImplMessages.recursiveServiceBuild(this));
200
201 _building = true;
202
203 try
204 {
205
206 ServiceModelFactory factory = getModule().getServiceModelFactory(getServiceModel());
207
208 _serviceModelObject = factory.createServiceModelForService(this);
209
210 _service = _serviceModelObject.getService();
211 }
212 finally
213 {
214 _building = false;
215 }
216 }
217
218 return _service;
219 }
220
221 public Object getService(Class serviceInterface)
222 {
223 Object result = getService();
224
225 if (!serviceInterface.isAssignableFrom(result.getClass()))
226 {
227 throw new ApplicationRuntimeException(ImplMessages.serviceWrongInterface(
228 this,
229 serviceInterface), getLocation(), null);
230 }
231
232 return result;
233 }
234
235 public String getServiceModel()
236 {
237 return _serviceModel;
238 }
239
240 public void setServiceModel(String model)
241 {
242 _serviceModel = model;
243 }
244
245 public void clearConstructorInformation()
246 {
247 _serviceConstructor = null;
248 _interceptorContributions = null;
249 }
250
251 // Hm. Does this need to be synchronized?
252
253 public List getOrderedInterceptorContributions()
254 {
255 if (!_interceptorsOrdered)
256 {
257 _interceptorContributions = orderInterceptors();
258 _interceptorsOrdered = true;
259 }
260
261 return _interceptorContributions;
262 }
263
264 private List orderInterceptors()
265 {
266 if (HiveMind.isEmpty(_interceptorContributions))
267 return null;
268
269 // Any error logging should go to the extension point
270 // we're constructing.
271
272 Log log = LogFactory.getLog(getExtensionPointId());
273
274 Orderer orderer = new Orderer(log, getModule().getErrorHandler(), ImplMessages
275 .interceptorContribution());
276
277 Iterator i = _interceptorContributions.iterator();
278 while (i.hasNext())
279 {
280 ServiceInterceptorContribution sic = (ServiceInterceptorContribution) i.next();
281
282 // Sort them into runtime excecution order. When we build
283 // the interceptor stack we'll apply them in reverse order,
284 // building outward from the core service implementation.
285
286 orderer.add(sic, sic.getName(), sic.getPrecedingInterceptorIds(), sic
287 .getFollowingInterceptorIds());
288 }
289
290 return orderer.getOrderedObjects();
291 }
292
293 public void setShutdownCoordinator(ShutdownCoordinator coordinator)
294 {
295 _shutdownCoordinator = coordinator;
296 }
297
298 public void addRegistryShutdownListener(RegistryShutdownListener listener)
299 {
300 _shutdownCoordinator.addRegistryShutdownListener(listener);
301 }
302
303 /**
304 * Forces the service into existence.
305 */
306 public void forceServiceInstantiation()
307 {
308 getService();
309
310 _serviceModelObject.instantiateService();
311 }
312
313 public Occurances getParametersCount()
314 {
315 return _parametersCount;
316 }
317
318 public void setParametersCount(Occurances occurances)
319 {
320 _parametersCount = occurances;
321 }
322
323 /**
324 * Returns the service constructor, if defined, or the default service constructor. The default
325 * service constructor comes from the <service-point> itself; other modules can override
326 * this default using an <implementation> element.
327 */
328
329 public ServiceImplementationConstructor getServiceConstructor()
330 {
331 return _serviceConstructor == null ? _defaultServiceConstructor : _serviceConstructor;
332 }
333 }