1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.objectfactory.guice;
35
36 import info.magnolia.cms.core.SystemProperty;
37 import info.magnolia.objectfactory.ComponentProvider;
38 import info.magnolia.objectfactory.Components;
39 import info.magnolia.objectfactory.configuration.ComponentConfigurer;
40 import info.magnolia.objectfactory.configuration.ComponentProviderConfiguration;
41
42 import java.util.ArrayList;
43 import java.util.List;
44 import java.util.Optional;
45
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49 import com.google.inject.AbstractModule;
50 import com.google.inject.Binding;
51 import com.google.inject.CreationException;
52 import com.google.inject.Guice;
53 import com.google.inject.Injector;
54 import com.google.inject.Module;
55 import com.google.inject.Stage;
56 import com.google.inject.spi.DefaultElementVisitor;
57 import com.google.inject.spi.Element;
58 import com.google.inject.spi.Elements;
59 import com.google.inject.util.Modules;
60 import com.mycila.guice.ext.closeable.CloseableModule;
61 import com.mycila.guice.ext.jsr250.Jsr250Module;
62
63
64
65
66 public class GuiceComponentProviderBuilder {
67
68 private static final Logger log = LoggerFactory.getLogger(GuiceComponentProviderBuilder.class);
69 private ComponentProviderConfiguration configuration;
70 private boolean exposeGlobally;
71 private GuiceComponentProvider parent;
72 private final List<Module> extraModules = new ArrayList<>();
73 private Stage stage;
74
75 public GuiceComponentProviderBuilder exposeGlobally() {
76 this.exposeGlobally = true;
77 return this;
78 }
79
80 public GuiceComponentProviderBuilder withConfiguration(ComponentProviderConfiguration configuration) {
81 this.configuration = configuration;
82 return this;
83 }
84
85 public GuiceComponentProviderBuilder withParent(GuiceComponentProvider parent) {
86 this.parent = parent;
87 return this;
88 }
89
90 public GuiceComponentProviderBuilder inStage(Stage stage) {
91 this.stage = stage;
92 return this;
93 }
94
95 public void addModule(Module module) {
96 this.extraModules.add(module);
97 }
98
99 public GuiceComponentProvider build(ComponentConfigurer... configurers) {
100
101 if (configuration == null) {
102 configuration = new ComponentProviderConfiguration();
103 }
104
105
106 for (ComponentConfigurer configurer : configurers) {
107 configuration.addConfigurer(configurer);
108 }
109
110
111 for (ComponentConfigurer configurer : configuration.getConfigurers()) {
112 configurer.doWithConfiguration(parent, configuration);
113 }
114
115
116 final GuiceComponentProviderr.html#GuiceComponentProvider">GuiceComponentProvider componentProvider = new GuiceComponentProvider(configuration.getAnnotatedTypeMappings(), parent);
117 if (exposeGlobally) {
118 Components.setComponentProvider(componentProvider);
119 }
120
121 Module module = new AbstractModule() {
122 @Override
123 protected void configure() {
124
125
126 if (Boolean.valueOf(SystemProperty.getProperty("magnolia.jsr250.enabled", "true"))) {
127
128 install(new Jsr250Module());
129 }
130
131 install(new GuiceComponentConfigurationModule(configuration));
132
133 for (Module extraModule : extraModules) {
134 binder().install(extraModule);
135 }
136
137 install(new CloseableModule());
138 }
139 };
140
141 module = ensureComponentProviderBinding(module, componentProvider);
142
143 if (parent != null) {
144 GuiceParentBindingsModuletml#GuiceParentBindingsModule">GuiceParentBindingsModule parentBindingsModule = new GuiceParentBindingsModule(parent.getInjector());
145 module = Modules.override(parentBindingsModule).with(module);
146 }
147
148 try {
149 Injector injector = Guice.createInjector(resolveStageToUse(), module);
150 injector.injectMembers(componentProvider);
151 return componentProvider;
152 } catch (CreationException e) {
153 log.error("Magnolia failed to load module configuration with types {} and components {}. Please ensure you don't have any legacy modules present in your web application.", configuration.getAnnotatedTypeMappings(), configuration.getAnnotatedComponents(), e);
154 throw e;
155 }
156
157 }
158
159
160
161
162
163 private Module ensureComponentProviderBinding(Module module, GuiceComponentProvider fallbackComponentProviderInstance) {
164 final DefaultElementVisitor<Boolean> isComponentProviderBinding = new DefaultElementVisitor<Boolean>() {
165 @Override
166 public <T> Boolean visit(Binding<T> binding) {
167 return ComponentProvider.class.isAssignableFrom(binding.getKey().getTypeLiteral().getRawType());
168 }
169
170 @Override
171 protected Boolean visitOther(Element element) {
172 return false;
173 }
174 };
175
176 List<Element> elements = new ArrayList<>(Elements.getElements(module));
177
178 final Optional<Element> componentProviderBinding = elements.stream()
179 .filter(element -> element.acceptVisitor(isComponentProviderBinding))
180 .findFirst();
181
182 if (!componentProviderBinding.isPresent()) {
183 module = Modules.override(module).with(new AbstractModule() {
184 @Override
185 protected void configure() {
186
187 bind(ComponentProvider.class).toInstance(fallbackComponentProviderInstance);
188 }
189 });
190 }
191
192 return module;
193 }
194
195 public GuiceComponentProvider build() {
196 return build(new GuiceContextAndScopesConfigurer(), new GuicePropertyConfigurer());
197 }
198
199 private Stage resolveStageToUse() {
200 if (stage != null) {
201 return stage;
202 }
203 if (parent != null) {
204 return parent.getInjector().getInstance(Stage.class);
205 }
206 return Stage.PRODUCTION;
207 }
208 }