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 }