1 /** 2 * Copyright (C) 2006 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.inject.internal; 18 19 import com.google.inject.internal.InjectorImpl.InjectorOptions; 20 21 import java.lang.reflect.Proxy; 22 import java.util.ArrayList; 23 import java.util.List; 24 25 /** 26 * Context of a dependency construction. Used to manage circular references. 27 * 28 * @author crazybob (at) google.com (Bob Lee) 29 */ 30 final class ConstructionContext<T> { 31 32 T currentReference; 33 boolean constructing; 34 35 List<DelegatingInvocationHandler<T>> invocationHandlers; 36 37 public T getCurrentReference() { 38 return currentReference; 39 } 40 41 public void removeCurrentReference() { 42 this.currentReference = null; 43 } 44 45 public void setCurrentReference(T currentReference) { 46 this.currentReference = currentReference; 47 } 48 49 public boolean isConstructing() { 50 return constructing; 51 } 52 53 public void startConstruction() { 54 this.constructing = true; 55 } 56 57 public void finishConstruction() { 58 this.constructing = false; 59 invocationHandlers = null; 60 } 61 62 public Object createProxy(Errors errors, InjectorOptions injectorOptions, 63 Class<?> expectedType) throws ErrorsException { 64 if (injectorOptions.disableCircularProxies) { 65 throw errors.circularProxiesDisabled(expectedType).toException(); 66 } 67 if (!expectedType.isInterface()) { 68 throw errors.cannotSatisfyCircularDependency(expectedType).toException(); 69 } 70 71 if (invocationHandlers == null) { 72 invocationHandlers = new ArrayList<DelegatingInvocationHandler<T>>(); 73 } 74 75 DelegatingInvocationHandler<T> invocationHandler = new DelegatingInvocationHandler<T>(); 76 invocationHandlers.add(invocationHandler); 77 78 // TODO: if I create a proxy which implements all the interfaces of 79 // the implementation type, I'll be able to get away with one proxy 80 // instance (as opposed to one per caller). 81 ClassLoader classLoader = BytecodeGen.getClassLoader(expectedType); 82 return expectedType.cast(Proxy.newProxyInstance(classLoader, 83 new Class[] { expectedType, CircularDependencyProxy.class }, invocationHandler)); 84 } 85 86 public void setProxyDelegates(T delegate) { 87 if (invocationHandlers != null) { 88 for (DelegatingInvocationHandler<T> handler : invocationHandlers) { 89 handler.setDelegate(delegate); 90 } 91 // initialization of each handler can happen no more than once 92 invocationHandlers = null; 93 } 94 } 95 } 96