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 }