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