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.ArrayList; 018 import java.util.List; 019 020 import org.apache.hivemind.ApplicationRuntimeException; 021 import org.apache.hivemind.HiveMind; 022 import org.apache.hivemind.PoolManageable; 023 import org.apache.hivemind.ShutdownCoordinator; 024 import org.apache.hivemind.events.RegistryShutdownListener; 025 import org.apache.hivemind.impl.ConstructableServicePoint; 026 import org.apache.hivemind.impl.ProxyUtils; 027 import org.apache.hivemind.internal.Module; 028 import org.apache.hivemind.service.ThreadCleanupListener; 029 import org.apache.hivemind.service.ThreadEventNotifier; 030 031 /** 032 * Similar to the 033 * {@link org.apache.hivemind.impl.servicemodel.ThreadedServiceModel threaded service model}, 034 * except that, once created, services are pooled for later use. 035 * 036 * @author Howard Lewis Ship 037 */ 038 public class PooledServiceModel extends AbstractServiceModelImpl 039 { 040 /** 041 * Name of a method in the deferred proxy that is used to obtain the constructed service. 042 */ 043 protected static final String SERVICE_ACCESSOR_METHOD_NAME = "_service"; 044 045 private Object _serviceProxy; 046 047 private ThreadEventNotifier _notifier; 048 049 private ThreadLocal _activeService; 050 051 private List _servicePool; 052 053 /** @since 1.1 */ 054 055 private Class _serviceInterface; 056 057 /** 058 * Shared, null implementation of PoolManageable. 059 */ 060 private static final PoolManageable NULL_MANAGEABLE = new PoolManageable() 061 { 062 public void activateService() 063 { 064 } 065 066 public void passivateService() 067 { 068 } 069 }; 070 071 private class PooledService implements ThreadCleanupListener 072 { 073 private Object _core; 074 075 private PoolManageable _managed; 076 077 /** 078 * @param service 079 * the full service implementation, including any interceptors 080 * @param core 081 * the core service implementation, which may optionally implement 082 * {@link PoolManageable} 083 */ 084 PooledService(Object core) 085 { 086 _core = core; 087 088 if (core instanceof PoolManageable) 089 _managed = (PoolManageable) core; 090 else 091 _managed = NULL_MANAGEABLE; 092 } 093 094 public void threadDidCleanup() 095 { 096 unbindPooledServiceFromCurrentThread(this); 097 } 098 099 void activate() 100 { 101 _managed.activateService(); 102 } 103 104 void passivate() 105 { 106 _managed.passivateService(); 107 } 108 109 /** 110 * Returns the configured service implementation. 111 */ 112 public Object getService() 113 { 114 return _core; 115 } 116 117 } 118 119 public PooledServiceModel(ConstructableServicePoint servicePoint) 120 { 121 super(servicePoint); 122 123 _serviceInterface = servicePoint.getServiceInterface(); 124 } 125 126 public synchronized Object getService() 127 { 128 if (_notifier == null) 129 { 130 Module module = getServicePoint().getModule(); 131 132 _notifier = (ThreadEventNotifier) module.getService( 133 HiveMind.THREAD_EVENT_NOTIFIER_SERVICE, 134 ThreadEventNotifier.class); 135 } 136 137 if (_serviceProxy == null) 138 _serviceProxy = constructServiceProxy(); 139 140 return _serviceProxy; 141 } 142 143 /** 144 * Constructs the service proxy and returns it, wrapped in any interceptors. 145 */ 146 private Object constructServiceProxy() 147 { 148 ConstructableServicePoint servicePoint = getServicePoint(); 149 150 if (_log.isDebugEnabled()) 151 _log.debug("Creating PooledProxy for service " + servicePoint.getExtensionPointId()); 152 153 Object proxy = ProxyUtils.createDelegatingProxy( 154 "PooledProxy", 155 this, 156 "getServiceImplementationForCurrentThread", 157 servicePoint); 158 159 Object intercepted = addInterceptors(proxy); 160 161 RegistryShutdownListener outerProxy = ProxyUtils 162 .createOuterProxy(intercepted, servicePoint); 163 164 ShutdownCoordinator coordinator = servicePoint.getShutdownCoordinator(); 165 166 coordinator.addRegistryShutdownListener(outerProxy); 167 168 return outerProxy; 169 } 170 171 public synchronized Object getServiceImplementationForCurrentThread() 172 { 173 if (_activeService == null) 174 _activeService = new ThreadLocal(); 175 176 PooledService pooled = (PooledService) _activeService.get(); 177 178 if (pooled == null) 179 { 180 pooled = obtainPooledService(); 181 182 pooled.activate(); 183 184 _notifier.addThreadCleanupListener(pooled); 185 _activeService.set(pooled); 186 } 187 188 return pooled.getService(); 189 } 190 191 private PooledService obtainPooledService() 192 { 193 PooledService result = getServiceFromPool(); 194 195 if (result == null) 196 result = constructPooledService(); 197 198 return result; 199 } 200 201 private synchronized PooledService getServiceFromPool() 202 { 203 int count = _servicePool == null ? 0 : _servicePool.size(); 204 205 if (count == 0) 206 return null; 207 208 return (PooledService) _servicePool.remove(count - 1); 209 } 210 211 private synchronized void returnServiceToPool(PooledService pooled) 212 { 213 if (_servicePool == null) 214 _servicePool = new ArrayList(); 215 216 _servicePool.add(pooled); 217 } 218 219 private synchronized PooledService constructPooledService() 220 { 221 try 222 { 223 Object core = constructCoreServiceImplementation(); 224 225 // This is related to bean services. 226 227 if (!_serviceInterface.isInstance(core)) 228 core = constructBridgeProxy(core); 229 if( core instanceof RegistryShutdownListener ) 230 { 231 getShutdownCoordinatorService().addRegistryShutdownListener( ( RegistryShutdownListener )core ); 232 } 233 return new PooledService(core); 234 } 235 catch (Exception ex) 236 { 237 throw new ApplicationRuntimeException(ServiceModelMessages.unableToConstructService( 238 getServicePoint(), 239 ex), ex); 240 } 241 } 242 243 private void unbindPooledServiceFromCurrentThread(PooledService pooled) 244 { 245 _notifier.removeThreadCleanupListener(pooled); 246 247 _activeService.set(null); 248 249 pooled.passivate(); 250 251 returnServiceToPool(pooled); 252 } 253 254 /** 255 * Invokes {@link #getServiceImplementationForCurrentThread()} to instantiate an instance of the 256 * service. 257 */ 258 public void instantiateService() 259 { 260 getServiceImplementationForCurrentThread(); 261 } 262 263 }