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