@SuppressWarnings("unchecked")
	/*pkg*/ <S> S findCachedService(Class<S> serviceClass, Scope scope) {

		assert serviceClass!=null:
			"Parameter \"serviceClass\" cannot be null";

		assert scope!=null:
			"Parameter \"scope\" cannot be null";

		Object result=null;

		switch (scope) {
			case REQUEST: {
				// Look in the request cache
				if (inRequest()) {
					assert threadRequestObjects.get()!=null;
					result=threadRequestObjects.get().get(serviceClass);

					// Remove from the cache if not consistent
//					if (!checkCacheConsistency(
//						serviceClass,result,Scope.REQUEST)) {
//						threadRequestObjects.get().remove(serviceClass);
//					}
				}
				break;
			}
			case APPLICATION: {

				// Try the thread-local cache first so that we can avoid
				// synchronization. Of course, this assumes that the local
				// cache will always be the same set of globally cached
				// objects, or a subset. If we eventually decide to manage
				// lifecycle of singletons, this assumption will be violated.
				Map<Class<?>,Object> cache=threadApplicationObjectCache.get();
				if (cache!=null) {
					result=cache.get(serviceClass);
					if (result!=null) {
						break;
					}
				}

				// If not in our local cache, look in the global 
				// singleton cache, which requires synchronization
				synchronized (APPLICATION_OBJECTS) {
					result=APPLICATION_OBJECTS.get(serviceClass);

					// Remove from the cache if not consistent
//					if (!checkCacheConsistency(
//						serviceClass,result,Scope.APPLICATION)) {
//						APPLICATION_OBJECTS.remove(serviceClass);
//					}

					// While we're synchronized, copy the singleton cache
					// to a thread local cache
					if (result!=null) {
						updateThreadSingletonCache();
					}
				}
				break;
			}
			case CLIENT_MANAGED: {
				// No caching; just instantiate a new object in the caller
				result=null;
				break;
			}
			default: {
				throw new UnsupportedOperationException(
					"Scope \""+scope+"\" not supported");
			}
		}

		return (S)result;
	}