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