1 /*
2  * Copyright (C) 2011 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.grapher;
18 
19 import com.google.common.collect.ImmutableList;
20 import com.google.common.collect.Lists;
21 import com.google.inject.Binding;
22 import com.google.inject.spi.ConstructorBinding;
23 import com.google.inject.spi.ConvertedConstantBinding;
24 import com.google.inject.spi.DefaultBindingTargetVisitor;
25 import com.google.inject.spi.Dependency;
26 import com.google.inject.spi.HasDependencies;
27 import com.google.inject.spi.InstanceBinding;
28 import com.google.inject.spi.LinkedKeyBinding;
29 import com.google.inject.spi.ProviderBinding;
30 import com.google.inject.spi.ProviderInstanceBinding;
31 import com.google.inject.spi.ProviderKeyBinding;
32 import java.util.Collection;
33 import java.util.List;
34 
35 /**
36  * Default edge creator.
37  *
38  * @author bojand@google.com (Bojan Djordjevic)
39  */
40 final class DefaultEdgeCreator implements EdgeCreator {
41 
42   @Override
getEdges(Iterable<Binding<?>> bindings)43   public Iterable<Edge> getEdges(Iterable<Binding<?>> bindings) {
44     List<Edge> edges = Lists.newArrayList();
45     EdgeVisitor visitor = new EdgeVisitor();
46     for (Binding<?> binding : bindings) {
47       edges.addAll(binding.acceptTargetVisitor(visitor));
48     }
49     return edges;
50   }
51 
52   /**
53    * {@link BindingTargetVisitor} that adds edges to the graph based on the visited {@link Binding}.
54    */
55   private static final class EdgeVisitor
56       extends DefaultBindingTargetVisitor<Object, Collection<Edge>> {
57 
58     /**
59      * Returns a dependency edge for each {@link Dependency} in the binding. These will be from the
60      * given node ID to the {@link Dependency}'s {@link Key}.
61      *
62      * @param nodeId ID of the node that should be the tail of the dependency edges
63      * @param binding {@link Binding} for the dependencies
64      */
newDependencyEdges( NodeId nodeId, T binding)65     private <T extends Binding<?> & HasDependencies> Collection<Edge> newDependencyEdges(
66         NodeId nodeId, T binding) {
67       ImmutableList.Builder<Edge> builder = ImmutableList.builder();
68       for (Dependency<?> dependency : binding.getDependencies()) {
69         NodeId to = NodeId.newTypeId(dependency.getKey());
70         builder.add(new DependencyEdge(nodeId, to, dependency.getInjectionPoint()));
71       }
72       return builder.build();
73     }
74 
75     /**
76      * Visitor for {@link ConstructorBinding}s. These are for classes that Guice will instantiate to
77      * satisfy injection requests.
78      */
79     @Override
visit(ConstructorBinding<?> binding)80     public Collection<Edge> visit(ConstructorBinding<?> binding) {
81       return newDependencyEdges(NodeId.newTypeId(binding.getKey()), binding);
82     }
83 
84     /**
85      * Visitor for {@link ConvertedConstantBinding}. The {@link Binding}'s {@link Key} will be of an
86      * annotated primitive type, and the value of {@link ConvertedConstantBinding#getSourceKey()}
87      * will be of a {@link String} with the same annotation.
88      */
89     @Override
visit(ConvertedConstantBinding<?> binding)90     public Collection<Edge> visit(ConvertedConstantBinding<?> binding) {
91       return ImmutableList.<Edge>of(
92           new BindingEdge(
93               NodeId.newTypeId(binding.getKey()),
94               NodeId.newTypeId(binding.getSourceKey()),
95               BindingEdge.Type.CONVERTED_CONSTANT));
96     }
97 
98     /**
99      * Visitor for {@link InstanceBinding}. We then render any dependency edgess that the instance
100      * may have, which come either from {@link InjectionPoint}s (method and field) on the instance,
101      * or on {@link Dependency}s the instance declares through the {@link HasDependencies}
102      * interface.
103      */
104     @Override
visit(InstanceBinding<?> binding)105     public Collection<Edge> visit(InstanceBinding<?> binding) {
106       return new ImmutableList.Builder<Edge>()
107           .add(
108               new BindingEdge(
109                   NodeId.newTypeId(binding.getKey()),
110                   NodeId.newInstanceId(binding.getKey()),
111                   BindingEdge.Type.NORMAL))
112           .addAll(newDependencyEdges(NodeId.newInstanceId(binding.getKey()), binding))
113           .build();
114     }
115 
116     /**
117      * Visitor for {@link LinkedKeyBinding}. This is the standard {@link Binding} you get from
118      * binding an interface class to an implementation class. We draw a {@link BindingEdge} from the
119      * interface node to the node of the implementing class.
120      */
121     @Override
visit(LinkedKeyBinding<?> binding)122     public Collection<Edge> visit(LinkedKeyBinding<?> binding) {
123       return ImmutableList.<Edge>of(
124           new BindingEdge(
125               NodeId.newTypeId(binding.getKey()),
126               NodeId.newTypeId(binding.getLinkedKey()),
127               BindingEdge.Type.NORMAL));
128     }
129 
130     /**
131      * Visitor for {@link ProviderBinding}. These {@link Binding}s arise from an {@link
132      * InjectionPoint} for the {@link Provider} interface.
133      */
134     @Override
visit(ProviderBinding<?> binding)135     public Collection<Edge> visit(ProviderBinding<?> binding) {
136       return ImmutableList.<Edge>of(
137           new BindingEdge(
138               NodeId.newTypeId(binding.getKey()),
139               NodeId.newTypeId(binding.getProvidedKey()),
140               BindingEdge.Type.PROVIDER));
141     }
142 
143     /**
144      * Same as {@link #visit(InstanceBinding)}, but the binding edge is {@link
145      * BindingEdge.Type#PROVIDER}.
146      */
147     @Override
visit(ProviderInstanceBinding<?> binding)148     public Collection<Edge> visit(ProviderInstanceBinding<?> binding) {
149       return new ImmutableList.Builder<Edge>()
150           .add(
151               new BindingEdge(
152                   NodeId.newTypeId(binding.getKey()),
153                   NodeId.newInstanceId(binding.getKey()),
154                   BindingEdge.Type.PROVIDER))
155           .addAll(newDependencyEdges(NodeId.newInstanceId(binding.getKey()), binding))
156           .build();
157     }
158 
159     /**
160      * Same as {@link #visit(LinkedKeyBinding)}, but the binding edge is {@link
161      * BindingEdge.Type#PROVIDER}.
162      */
163     @Override
visit(ProviderKeyBinding<?> binding)164     public Collection<Edge> visit(ProviderKeyBinding<?> binding) {
165       return ImmutableList.<Edge>of(
166           new BindingEdge(
167               NodeId.newTypeId(binding.getKey()),
168               NodeId.newTypeId(binding.getProviderKey()),
169               BindingEdge.Type.PROVIDER));
170     }
171 
172     @Override
visitOther(Binding<?> binding)173     public Collection<Edge> visitOther(Binding<?> binding) {
174       return ImmutableList.of();
175     }
176   }
177 }
178