1477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit/**
2477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit * Copyright (C) 2008 Google Inc.
3477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit *
4477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit * Licensed under the Apache License, Version 2.0 (the "License");
5477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit * you may not use this file except in compliance with the License.
6477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit * You may obtain a copy of the License at
7477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit *
8477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit * http://www.apache.org/licenses/LICENSE-2.0
9477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit *
10477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit * Unless required by applicable law or agreed to in writing, software
11477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit * distributed under the License is distributed on an "AS IS" BASIS,
12477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit * See the License for the specific language governing permissions and
14477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit * limitations under the License.
15477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit */
16477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit
175ae41eb77073b47e75c2dcf3766137f2352fbaf9limpbizkitpackage com.google.inject.internal;
185ae41eb77073b47e75c2dcf3766137f2352fbaf9limpbizkit
195ae41eb77073b47e75c2dcf3766137f2352fbaf9limpbizkitimport com.google.inject.Binder;
205ae41eb77073b47e75c2dcf3766137f2352fbaf9limpbizkitimport com.google.inject.Binding;
215ae41eb77073b47e75c2dcf3766137f2352fbaf9limpbizkitimport com.google.inject.Key;
225ae41eb77073b47e75c2dcf3766137f2352fbaf9limpbizkitimport com.google.inject.Provider;
2376c24b172e5c4c4b6d51c10dd5c1f491a4033157limpbizkitimport com.google.inject.spi.ConstructorBinding;
2476c24b172e5c4c4b6d51c10dd5c1f491a4033157limpbizkitimport com.google.inject.spi.ConvertedConstantBinding;
2576c24b172e5c4c4b6d51c10dd5c1f491a4033157limpbizkitimport com.google.inject.spi.ExposedBinding;
26b3a8f0bda3259af41e639f1872c42377989704d9limpbizkitimport com.google.inject.spi.InjectionPoint;
2776c24b172e5c4c4b6d51c10dd5c1f491a4033157limpbizkitimport com.google.inject.spi.InstanceBinding;
2876c24b172e5c4c4b6d51c10dd5c1f491a4033157limpbizkitimport com.google.inject.spi.LinkedKeyBinding;
29c3f928404a91cf837d809dcc465ba43442bc1198limpbizkitimport com.google.inject.spi.PrivateElements;
3076c24b172e5c4c4b6d51c10dd5c1f491a4033157limpbizkitimport com.google.inject.spi.ProviderBinding;
3176c24b172e5c4c4b6d51c10dd5c1f491a4033157limpbizkitimport com.google.inject.spi.ProviderInstanceBinding;
3276c24b172e5c4c4b6d51c10dd5c1f491a4033157limpbizkitimport com.google.inject.spi.ProviderKeyBinding;
3376c24b172e5c4c4b6d51c10dd5c1f491a4033157limpbizkitimport com.google.inject.spi.UntargettedBinding;
34b7a02b02d81c830d148355c90bc309bcd66fb592sberlin
35477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkitimport java.util.Set;
36477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit
37477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit/**
38477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit * Handles {@link Binder#bind} and {@link Binder#bindConstant} elements.
39477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit *
40477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit * @author crazybob@google.com (Bob Lee)
41477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit * @author jessewilson@google.com (Jesse Wilson)
42477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit */
4307170cc3f59f08954c97e19f2d3cf165d3a8601asberlinfinal class BindingProcessor extends AbstractBindingProcessor {
44477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit
455fb9d927f35fb7a3eaba259c985710143231d4belimpbizkit  private final Initializer initializer;
46477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit
4707170cc3f59f08954c97e19f2d3cf165d3a8601asberlin  BindingProcessor(Errors errors, Initializer initializer, ProcessedBindingData bindingData) {
4807170cc3f59f08954c97e19f2d3cf165d3a8601asberlin    super(errors, bindingData);
495fb9d927f35fb7a3eaba259c985710143231d4belimpbizkit    this.initializer = initializer;
50477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit  }
51477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit
5203b81a6b931a06c7697e422b218e3734a7f262cclimpbizkit  @Override public <T> Boolean visit(Binding<T> command) {
5307170cc3f59f08954c97e19f2d3cf165d3a8601asberlin    Class<?> rawType = command.getKey().getTypeLiteral().getRawType();
5407170cc3f59f08954c97e19f2d3cf165d3a8601asberlin    if (Void.class.equals(rawType)) {
55759662bf0bdea0666dc10341efef685da7f2392climpbizkit      if (command instanceof ProviderInstanceBinding
568ad60eb50961e000c89099bb767489cf551d995bSam Berlin          && ((ProviderInstanceBinding) command).getUserSuppliedProvider()
578ad60eb50961e000c89099bb767489cf551d995bSam Berlin              instanceof ProviderMethod) {
58759662bf0bdea0666dc10341efef685da7f2392climpbizkit        errors.voidProviderMethod();
59759662bf0bdea0666dc10341efef685da7f2392climpbizkit      } else {
60759662bf0bdea0666dc10341efef685da7f2392climpbizkit        errors.missingConstantValues();
61759662bf0bdea0666dc10341efef685da7f2392climpbizkit      }
62d1fe130a70a1b881d7b27079954b0e9140ab324climpbizkit      return true;
63d1fe130a70a1b881d7b27079954b0e9140ab324climpbizkit    }
6407170cc3f59f08954c97e19f2d3cf165d3a8601asberlin
65477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit    if (rawType == Provider.class) {
66477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit      errors.bindingToProvider();
67477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit      return true;
68477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit    }
6907170cc3f59f08954c97e19f2d3cf165d3a8601asberlin
7007170cc3f59f08954c97e19f2d3cf165d3a8601asberlin    return command.acceptTargetVisitor(new Processor<T, Boolean>((BindingImpl<T>)command) {
71d51292d5a4a788b1275eb9ad55cf612e68640bbfSam Berlin      @Override
72920731718b6f3505cdfeefeabd789539603de18asberlin      public Boolean visit(ConstructorBinding<? extends T> binding) {
7307170cc3f59f08954c97e19f2d3cf165d3a8601asberlin        prepareBinding();
7444475647fc7ca0595e543a7f72efdd4c6862273elimpbizkit        try {
7544475647fc7ca0595e543a7f72efdd4c6862273elimpbizkit          ConstructorBindingImpl<T> onInjector = ConstructorBindingImpl.create(injector, key,
76c756777526309dc6c9ff2b5df80a8f811d390c09Sam Berlin              binding.getConstructor(), source, scoping, errors, false, false);
7744475647fc7ca0595e543a7f72efdd4c6862273elimpbizkit          scheduleInitialization(onInjector);
7844475647fc7ca0595e543a7f72efdd4c6862273elimpbizkit          putBinding(onInjector);
7944475647fc7ca0595e543a7f72efdd4c6862273elimpbizkit        } catch (ErrorsException e) {
8044475647fc7ca0595e543a7f72efdd4c6862273elimpbizkit          errors.merge(e.getErrors());
8144475647fc7ca0595e543a7f72efdd4c6862273elimpbizkit          putBinding(invalidBinding(injector, key, source));
8244475647fc7ca0595e543a7f72efdd4c6862273elimpbizkit        }
83920731718b6f3505cdfeefeabd789539603de18asberlin        return true;
8444475647fc7ca0595e543a7f72efdd4c6862273elimpbizkit      }
8576c24b172e5c4c4b6d51c10dd5c1f491a4033157limpbizkit
86d51292d5a4a788b1275eb9ad55cf612e68640bbfSam Berlin      @Override
87920731718b6f3505cdfeefeabd789539603de18asberlin      public Boolean visit(InstanceBinding<? extends T> binding) {
8807170cc3f59f08954c97e19f2d3cf165d3a8601asberlin        prepareBinding();
8976c24b172e5c4c4b6d51c10dd5c1f491a4033157limpbizkit        Set<InjectionPoint> injectionPoints = binding.getInjectionPoints();
9076c24b172e5c4c4b6d51c10dd5c1f491a4033157limpbizkit        T instance = binding.getInstance();
91bf2b16c06a5ff7c099fe60f9a46cfb130ce45962Christian Edward Gruber        @SuppressWarnings("unchecked") // safe to cast to binding<T> because
92bf2b16c06a5ff7c099fe60f9a46cfb130ce45962Christian Edward Gruber                                       // the processor was constructed w/ it
93fcbdf999a15039ecad6157c1bf44a835df826a27limpbizkit        Initializable<T> ref = initializer.requestInjection(
94bf2b16c06a5ff7c099fe60f9a46cfb130ce45962Christian Edward Gruber            injector, instance, (Binding<T>) binding, source, injectionPoints);
955fb9d927f35fb7a3eaba259c985710143231d4belimpbizkit        ConstantFactory<? extends T> factory = new ConstantFactory<T>(ref);
960cb8b860dc71a16dcc08658d4abc8e0cfe6f605elimpbizkit        InternalFactory<? extends T> scopedFactory
970cb8b860dc71a16dcc08658d4abc8e0cfe6f605elimpbizkit            = Scoping.scope(key, injector, factory, source, scoping);
98b3a8f0bda3259af41e639f1872c42377989704d9limpbizkit        putBinding(new InstanceBindingImpl<T>(injector, key, source, scopedFactory, injectionPoints,
99b3a8f0bda3259af41e639f1872c42377989704d9limpbizkit            instance));
100920731718b6f3505cdfeefeabd789539603de18asberlin        return true;
101477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit      }
102477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit
103d51292d5a4a788b1275eb9ad55cf612e68640bbfSam Berlin      @Override
104920731718b6f3505cdfeefeabd789539603de18asberlin      public Boolean visit(ProviderInstanceBinding<? extends T> binding) {
10507170cc3f59f08954c97e19f2d3cf165d3a8601asberlin        prepareBinding();
1068ad60eb50961e000c89099bb767489cf551d995bSam Berlin        javax.inject.Provider<? extends T> provider = binding.getUserSuppliedProvider();
10776c24b172e5c4c4b6d51c10dd5c1f491a4033157limpbizkit        Set<InjectionPoint> injectionPoints = binding.getInjectionPoints();
1088ad60eb50961e000c89099bb767489cf551d995bSam Berlin        Initializable<? extends javax.inject.Provider<? extends T>> initializable =
1098ad60eb50961e000c89099bb767489cf551d995bSam Berlin            initializer.<javax.inject.Provider<? extends T>>requestInjection(
1108ad60eb50961e000c89099bb767489cf551d995bSam Berlin                injector, provider, null, source, injectionPoints);
111d51292d5a4a788b1275eb9ad55cf612e68640bbfSam Berlin        // always visited with Binding<T>
112d51292d5a4a788b1275eb9ad55cf612e68640bbfSam Berlin        @SuppressWarnings("unchecked")
113c94f4506c70ea41068ed9c5a00ddf6711eb7357fsberlin        InternalFactory<T> factory = new InternalFactoryToInitializableAdapter<T>(
1145e6c93348c4250012801b6e41753789d760f06e4timofeyb            initializable, source,
115d51292d5a4a788b1275eb9ad55cf612e68640bbfSam Berlin            injector.provisionListenerStore.get((ProviderInstanceBinding<T>)binding));
1160cb8b860dc71a16dcc08658d4abc8e0cfe6f605elimpbizkit        InternalFactory<? extends T> scopedFactory
1170cb8b860dc71a16dcc08658d4abc8e0cfe6f605elimpbizkit            = Scoping.scope(key, injector, factory, source, scoping);
11876c24b172e5c4c4b6d51c10dd5c1f491a4033157limpbizkit        putBinding(new ProviderInstanceBindingImpl<T>(injector, key, source, scopedFactory, scoping,
11976c24b172e5c4c4b6d51c10dd5c1f491a4033157limpbizkit            provider, injectionPoints));
120920731718b6f3505cdfeefeabd789539603de18asberlin        return true;
121477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit      }
122477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit
123d51292d5a4a788b1275eb9ad55cf612e68640bbfSam Berlin      @Override
124920731718b6f3505cdfeefeabd789539603de18asberlin      public Boolean visit(ProviderKeyBinding<? extends T> binding) {
12507170cc3f59f08954c97e19f2d3cf165d3a8601asberlin        prepareBinding();
126f2f7225c4042900a691b125672f516656c381608limpbizkit        Key<? extends javax.inject.Provider<? extends T>> providerKey = binding.getProviderKey();
127d51292d5a4a788b1275eb9ad55cf612e68640bbfSam Berlin        // always visited with Binding<T>
128d51292d5a4a788b1275eb9ad55cf612e68640bbfSam Berlin        @SuppressWarnings("unchecked")
129c94f4506c70ea41068ed9c5a00ddf6711eb7357fsberlin        BoundProviderFactory<T> boundProviderFactory = new BoundProviderFactory<T>(
1305e6c93348c4250012801b6e41753789d760f06e4timofeyb            injector, providerKey, source,
1318ad60eb50961e000c89099bb767489cf551d995bSam Berlin            injector.provisionListenerStore.get((ProviderKeyBinding<T>) binding));
13207170cc3f59f08954c97e19f2d3cf165d3a8601asberlin        bindingData.addCreationListener(boundProviderFactory);
1335ae41eb77073b47e75c2dcf3766137f2352fbaf9limpbizkit        InternalFactory<? extends T> scopedFactory = Scoping.scope(
1340cb8b860dc71a16dcc08658d4abc8e0cfe6f605elimpbizkit            key, injector, (InternalFactory<? extends T>) boundProviderFactory, source, scoping);
135477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit        putBinding(new LinkedProviderBindingImpl<T>(
13676c24b172e5c4c4b6d51c10dd5c1f491a4033157limpbizkit            injector, key, source, scopedFactory, scoping, providerKey));
137920731718b6f3505cdfeefeabd789539603de18asberlin        return true;
138477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit      }
139477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit
140d51292d5a4a788b1275eb9ad55cf612e68640bbfSam Berlin      @Override
141920731718b6f3505cdfeefeabd789539603de18asberlin      public Boolean visit(LinkedKeyBinding<? extends T> binding) {
14207170cc3f59f08954c97e19f2d3cf165d3a8601asberlin        prepareBinding();
14376c24b172e5c4c4b6d51c10dd5c1f491a4033157limpbizkit        Key<? extends T> linkedKey = binding.getLinkedKey();
14476c24b172e5c4c4b6d51c10dd5c1f491a4033157limpbizkit        if (key.equals(linkedKey)) {
145477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit          errors.recursiveBinding();
146477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit        }
147477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit
14876c24b172e5c4c4b6d51c10dd5c1f491a4033157limpbizkit        FactoryProxy<T> factory = new FactoryProxy<T>(injector, key, linkedKey, source);
14907170cc3f59f08954c97e19f2d3cf165d3a8601asberlin        bindingData.addCreationListener(factory);
1500cb8b860dc71a16dcc08658d4abc8e0cfe6f605elimpbizkit        InternalFactory<? extends T> scopedFactory
1510cb8b860dc71a16dcc08658d4abc8e0cfe6f605elimpbizkit            = Scoping.scope(key, injector, factory, source, scoping);
15276c24b172e5c4c4b6d51c10dd5c1f491a4033157limpbizkit        putBinding(
15376c24b172e5c4c4b6d51c10dd5c1f491a4033157limpbizkit            new LinkedBindingImpl<T>(injector, key, source, scopedFactory, scoping, linkedKey));
154920731718b6f3505cdfeefeabd789539603de18asberlin        return true;
155477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit      }
156477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit
157d51292d5a4a788b1275eb9ad55cf612e68640bbfSam Berlin      @Override
15807170cc3f59f08954c97e19f2d3cf165d3a8601asberlin      public Boolean visit(UntargettedBinding<? extends T> untargetted) {
15907170cc3f59f08954c97e19f2d3cf165d3a8601asberlin        return false;
160477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit      }
161477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit
162d51292d5a4a788b1275eb9ad55cf612e68640bbfSam Berlin      @Override
163920731718b6f3505cdfeefeabd789539603de18asberlin      public Boolean visit(ExposedBinding<? extends T> binding) {
164aa07ab09a27d4b83e66fb1666e7c780821ed106dlimpbizkit        throw new IllegalArgumentException("Cannot apply a non-module element");
165fcbdf999a15039ecad6157c1bf44a835df826a27limpbizkit      }
166d51292d5a4a788b1275eb9ad55cf612e68640bbfSam Berlin
167d51292d5a4a788b1275eb9ad55cf612e68640bbfSam Berlin      @Override
168920731718b6f3505cdfeefeabd789539603de18asberlin      public Boolean visit(ConvertedConstantBinding<? extends T> binding) {
169477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit        throw new IllegalArgumentException("Cannot apply a non-module element");
170477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit      }
171d51292d5a4a788b1275eb9ad55cf612e68640bbfSam Berlin
172d51292d5a4a788b1275eb9ad55cf612e68640bbfSam Berlin      @Override
173920731718b6f3505cdfeefeabd789539603de18asberlin      public Boolean visit(ProviderBinding<? extends T> binding) {
174477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit        throw new IllegalArgumentException("Cannot apply a non-module element");
175477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit      }
17607170cc3f59f08954c97e19f2d3cf165d3a8601asberlin
17707170cc3f59f08954c97e19f2d3cf165d3a8601asberlin      @Override
17807170cc3f59f08954c97e19f2d3cf165d3a8601asberlin      protected Boolean visitOther(Binding<? extends T> binding) {
17907170cc3f59f08954c97e19f2d3cf165d3a8601asberlin        throw new IllegalStateException("BindingProcessor should override all visitations");
180477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit      }
181477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit    });
182477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit  }
183477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit
184aa07ab09a27d4b83e66fb1666e7c780821ed106dlimpbizkit  @Override public Boolean visit(PrivateElements privateElements) {
185aa07ab09a27d4b83e66fb1666e7c780821ed106dlimpbizkit    for (Key<?> key : privateElements.getExposedKeys()) {
186aa07ab09a27d4b83e66fb1666e7c780821ed106dlimpbizkit      bindExposed(privateElements, key);
187aa07ab09a27d4b83e66fb1666e7c780821ed106dlimpbizkit    }
188aa07ab09a27d4b83e66fb1666e7c780821ed106dlimpbizkit    return false; // leave the private elements for the PrivateElementsProcessor to handle
189aa07ab09a27d4b83e66fb1666e7c780821ed106dlimpbizkit  }
190aa07ab09a27d4b83e66fb1666e7c780821ed106dlimpbizkit
191aa07ab09a27d4b83e66fb1666e7c780821ed106dlimpbizkit  private <T> void bindExposed(PrivateElements privateElements, Key<T> key) {
192aa07ab09a27d4b83e66fb1666e7c780821ed106dlimpbizkit    ExposedKeyFactory<T> exposedKeyFactory = new ExposedKeyFactory<T>(key, privateElements);
19307170cc3f59f08954c97e19f2d3cf165d3a8601asberlin    bindingData.addCreationListener(exposedKeyFactory);
194aa07ab09a27d4b83e66fb1666e7c780821ed106dlimpbizkit    putBinding(new ExposedBindingImpl<T>(
195aa07ab09a27d4b83e66fb1666e7c780821ed106dlimpbizkit        injector, privateElements.getExposedSource(key), key, exposedKeyFactory, privateElements));
196aa07ab09a27d4b83e66fb1666e7c780821ed106dlimpbizkit  }
197477f9f9ce3e1077866b579e99cd33ab824f1ee69limpbizkit}
198