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.servicemodel; 016 017 import java.util.List; 018 019 import org.apache.commons.logging.Log; 020 import org.apache.commons.logging.LogFactory; 021 import org.apache.hivemind.ApplicationRuntimeException; 022 import org.apache.hivemind.HiveMind; 023 import org.apache.hivemind.ShutdownCoordinator; 024 import org.apache.hivemind.definition.ImplementationConstructionContext; 025 import org.apache.hivemind.definition.ImplementationConstructor; 026 import org.apache.hivemind.definition.ImplementationDefinition; 027 import org.apache.hivemind.definition.InterceptorDefinition; 028 import org.apache.hivemind.events.RegistryShutdownListener; 029 import org.apache.hivemind.impl.ConstructableServicePoint; 030 import org.apache.hivemind.impl.InterceptorStackImpl; 031 import org.apache.hivemind.impl.ProxyBuilder; 032 import org.apache.hivemind.internal.ImplementationConstructionContextImpl; 033 import org.apache.hivemind.internal.Module; 034 import org.apache.hivemind.internal.RegistryInfrastructure; 035 import org.apache.hivemind.internal.ServiceModel; 036 import org.apache.hivemind.service.ClassFab; 037 import org.apache.hivemind.util.ConstructorUtils; 038 039 /** 040 * Base class for implementing {@link org.apache.hivemind.internal.ServiceModel}. 041 * 042 * @author Howard Lewis Ship 043 */ 044 public abstract class AbstractServiceModelImpl implements ServiceModel 045 { 046 /** 047 * This log is created from the log's service id, which is the appropriate place to log any 048 * messages related to creating (or managing) the service implementation, proxy, etc. Subclasses 049 * should make use of this Log as well. 050 */ 051 protected final Log _log; 052 053 private ConstructableServicePoint _servicePoint; 054 055 /** @since 1.1 */ 056 private Class _bridgeProxyClass; 057 058 public AbstractServiceModelImpl(ConstructableServicePoint servicePoint) 059 { 060 _log = LogFactory.getLog(servicePoint.getExtensionPointId()); 061 062 _servicePoint = servicePoint; 063 } 064 065 protected Object addInterceptors(Object core) 066 { 067 List interceptors = _servicePoint.getOrderedInterceptorContributions(); 068 069 int count = interceptors == null ? 0 : interceptors.size(); 070 071 if (count == 0) 072 return core; 073 074 InterceptorStackImpl stack = new InterceptorStackImpl(_log, _servicePoint, core); 075 076 // They are sorted into runtime execution order. Since we build from the 077 // core service impl outwarads, we have to reverse the runtime execution 078 // order to get the build order. 079 // That is, if user expects interceptors in order A B C (perhaps using 080 // the rules: A before B, C after B). 081 // Then that's the order for interceptors list: A B C 082 // To get that runtime execution order, we wrap C around the core, 083 // wrap B around C, and wrap A around B. 084 085 for (int i = count - 1; i >= 0; i--) 086 { 087 InterceptorDefinition id = (InterceptorDefinition) interceptors 088 .get(i); 089 090 stack.process(id); 091 } 092 093 // Whatever's on top is the final service. 094 095 return stack.peek(); 096 } 097 098 /** 099 * Constructs the core service implementation (by invoking the 100 * {@link ImplementationConstructor}), and checks that the result is non-null and 101 * assignable to the service interface. 102 */ 103 protected Object constructCoreServiceImplementation() 104 { 105 if (_log.isDebugEnabled()) 106 _log.debug("Constructing core service implementation for service " 107 + _servicePoint.getExtensionPointId()); 108 109 Class serviceInterface = _servicePoint.getServiceInterface(); 110 Class declaredInterface = _servicePoint.getDeclaredInterface(); 111 112 ImplementationDefinition implementationDefinition = _servicePoint.getImplementationDefinition(); 113 ImplementationConstructor constructor = implementationDefinition.getServiceConstructor(); 114 // Get a reference to the module that provided the implementation 115 String definingModuleId = implementationDefinition.getModuleId(); 116 117 Module definingModule = getRegistry().getModule(definingModuleId); 118 ImplementationConstructionContext context = new ImplementationConstructionContextImpl(definingModule, 119 _servicePoint); 120 Object result = constructor.constructCoreServiceImplementation(context); 121 122 if (result == null) 123 throw new ApplicationRuntimeException(ServiceModelMessages 124 .factoryReturnedNull(_servicePoint), constructor.getLocation(), null); 125 126 // The factory should provice something that either implements the service interface 127 // or the declared interface. Again, they are normally the same, but with services 128 // defined in terms of a class (not an interface), the service interface is 129 // synthetic, and the declared interface is the actual class. 130 131 if (!(serviceInterface.isInstance(result) || declaredInterface.isInstance(result))) 132 throw new ApplicationRuntimeException(ServiceModelMessages.factoryWrongInterface( 133 _servicePoint, 134 result, 135 serviceInterface), constructor.getLocation(), null); 136 137 HiveMind.setLocation(result, constructor.getLocation()); 138 139 return result; 140 } 141 142 private RegistryInfrastructure getRegistry() 143 { 144 return _servicePoint.getModule().getRegistry(); 145 } 146 147 /** 148 * Constructs the service implementation; this is invoked from 149 * {@link org.apache.hivemind.internal.ServicePoint#getService(Class)} (for singletons), or from 150 * the generated deferrable proxy (for most service models). Primarily, invokes 151 * {@link #constructNewServiceImplementation()} from within a block that checks for recursive 152 * builds. 153 */ 154 155 protected Object constructServiceImplementation() 156 { 157 Object result = constructNewServiceImplementation(); 158 159 // After succesfully building, we don't need 160 // some of the definition stuff again. 161 162 _servicePoint.clearConstructorInformation(); 163 164 return result; 165 } 166 167 /** 168 * Constructs a new implementation of the service, starting with a core implementation, then 169 * adding any interceptors. 170 */ 171 protected Object constructNewServiceImplementation() 172 { 173 try 174 { 175 Object core = constructCoreServiceImplementation(); 176 177 Object intercepted = addInterceptors(core); 178 179 return intercepted; 180 } 181 catch (Exception ex) 182 { 183 throw new ApplicationRuntimeException(ServiceModelMessages.unableToConstructService( 184 _servicePoint, 185 ex), ex); 186 } 187 188 } 189 190 public ConstructableServicePoint getServicePoint() 191 { 192 return _servicePoint; 193 } 194 195 /** 196 * Need to bridge from the service interface to the actual type. 197 * 198 * @since 1.1 199 */ 200 protected Object constructBridgeProxy(Object service) 201 { 202 Class bridgeProxyClass = getBridgeProxyClass(service); 203 204 return ConstructorUtils.invokeConstructor(bridgeProxyClass, new Object[] 205 { getServicePoint().getExtensionPointId(), service }); 206 } 207 208 /** 209 * Factored out of {@link #constructBridgeProxy(Object)} to keep the synchronized block as small 210 * as possible. 211 * 212 * @since 1.2 213 */ 214 private synchronized Class getBridgeProxyClass(Object service) 215 { 216 if (_bridgeProxyClass == null) 217 _bridgeProxyClass = constructBridgeProxyClass(service); 218 219 return _bridgeProxyClass; 220 } 221 222 /** 223 * Assumes that the factory will keep cranking out instances of the same class. 224 * 225 * @since 1.1 226 */ 227 228 private Class constructBridgeProxyClass(Object service) 229 { 230 ProxyBuilder builder = new ProxyBuilder("BridgeProxy", getServicePoint().getModule(), 231 getServicePoint().getServiceInterface(), getServicePoint().getDeclaredInterface(), false); 232 233 ClassFab cf = builder.getClassFab(); 234 235 Class serviceType = service.getClass(); 236 237 cf.addField("_service", serviceType); 238 239 cf.addConstructor(new Class[] 240 { String.class, serviceType }, null, "{ this($1); _service = $2; }"); 241 242 builder.addServiceMethods("_service"); 243 244 return cf.createClass(); 245 } 246 247 /** 248 * Invoked after creating a service implementation object; if the object implements 249 * {@link org.apache.hivemind.events.RegistryShutdownListener}, then the object is added as a 250 * listener. 251 * 252 * @param service 253 * the service implementation 254 * @see ShutdownCoordinator 255 * @since 1.2 256 */ 257 protected void registerWithShutdownCoordinator(Object service) 258 { 259 if (service instanceof RegistryShutdownListener) 260 { 261 ShutdownCoordinator coordinator = ((ShutdownCoordinator) getServicePoint().getModule() 262 .getService(ShutdownCoordinator.class)); 263 264 RegistryShutdownListener asListener = (RegistryShutdownListener) service; 265 coordinator.addRegistryShutdownListener(asListener); 266 } 267 } 268 }