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.module.model.ComponentDefinition;
37 import info.magnolia.objectfactory.ComponentFactory;
38 import info.magnolia.objectfactory.annotation.LazySingleton;
39 import info.magnolia.objectfactory.annotation.LocalScoped;
40 import info.magnolia.objectfactory.annotation.SessionScoped;
41 import info.magnolia.objectfactory.configuration.ComponentConfiguration;
42 import info.magnolia.objectfactory.configuration.ComponentProviderConfiguration;
43 import info.magnolia.objectfactory.configuration.ConfiguredComponentConfiguration;
44 import info.magnolia.objectfactory.configuration.ImplementationConfiguration;
45 import info.magnolia.objectfactory.configuration.InstanceConfiguration;
46 import info.magnolia.objectfactory.configuration.ProviderConfiguration;
47
48 import java.lang.annotation.Annotation;
49 import java.util.Map;
50
51 import javax.inject.Provider;
52 import javax.inject.Singleton;
53
54 import com.google.inject.util.Providers;
55 import org.apache.commons.lang3.StringUtils;
56
57 import com.google.inject.AbstractModule;
58 import com.google.inject.Module;
59 import com.google.inject.binder.ScopedBindingBuilder;
60
61
62
63
64
65 public class GuiceComponentConfigurationModule extends AbstractModule {
66
67 private final ComponentProviderConfiguration configuration;
68
69 public GuiceComponentConfigurationModule(ComponentProviderConfiguration configuration) {
70 this.configuration = configuration;
71 }
72
73 @Override
74 protected void configure() {
75
76 for (Map.Entry<Class, ComponentConfiguration> entry : configuration.getComponents().entrySet()) {
77 bindConfiguration(entry.getValue());
78 }
79
80 for (Object configurer : configuration.getConfigurers()) {
81 if (configurer instanceof Module) {
82 install((Module) configurer);
83 }
84 }
85 }
86
87 private <T> void bindConfiguration(ComponentConfiguration<T> configuration) {
88 if (configuration instanceof ImplementationConfiguration) {
89 bindImplementation((ImplementationConfiguration<T>) configuration);
90 } else if (configuration instanceof InstanceConfiguration) {
91 bindInstance((InstanceConfiguration<T>) configuration);
92 } else if (configuration instanceof ProviderConfiguration) {
93 bindProvider((ProviderConfiguration<T>) configuration);
94 } else if (configuration instanceof ConfiguredComponentConfiguration) {
95 ConfiguredComponentConfiguration<T> configured = (ConfiguredComponentConfiguration<T>) configuration;
96 if (configured.isObserved()) {
97 bindObservedComponent(configured);
98 } else {
99 bindConfiguredComponent(configured);
100 }
101 } else {
102 throw new IllegalStateException("Component configuration is ambiguous for component with type [" + configuration.getType() + "]");
103 }
104 }
105
106 private <T> void bindConfiguredComponent(ConfiguredComponentConfiguration<T> configuration) {
107 Provider<T> provider = new GuiceConfiguredComponentProvider<T>(configuration.getWorkspace(), configuration.getPath());
108 ScopedBindingBuilder builder = bindProvider(configuration.getType(), provider);
109 bindInScope(builder, configuration);
110 }
111
112 private <T> void bindObservedComponent(ConfiguredComponentConfiguration<T> configuration) {
113 Class<T> key = configuration.getType();
114 Provider<T> provider = new GuiceObservedComponentProvider<T>(configuration.getWorkspace(), configuration.getPath(), key);
115 ScopedBindingBuilder builder = bindProvider(configuration.getType(), provider);
116 bindInScope(builder, configuration);
117 }
118
119 private <T> void bindProvider(ProviderConfiguration<T> configuration) {
120 Class<?> factoryClass = configuration.getProviderClass();
121
122 if (ComponentFactory.class.isAssignableFrom(factoryClass)) {
123 Provider<T> provider = GuiceUtils.providerForComponentFactory((Class<? extends ComponentFactory<T>>) factoryClass);
124 ScopedBindingBuilder builder = bindProvider(configuration.getType(), provider);
125 bindInScope(builder, configuration);
126 } else if (Provider.class.isAssignableFrom(factoryClass)) {
127 ScopedBindingBuilder builder = bindProvider(configuration.getType(), (Class<? extends Provider<T>>) factoryClass);
128 bindInScope(builder, configuration);
129 } else {
130 throw new IllegalStateException("Unsupported provider class [" + factoryClass + "] for component with type [" + configuration.getType() + "]");
131 }
132 }
133
134 private <T> void bindInstance(InstanceConfiguration<T> configuration) {
135 Class<T> key = configuration.getType();
136 Object instance = configuration.getInstance();
137 if (instance instanceof Provider) {
138 bindProvider(configuration.getType(), (Provider<T>) instance);
139 } else if (instance instanceof ComponentFactory) {
140 bindProvider(configuration.getType(), GuiceUtils.providerForComponentFactory((ComponentFactory<T>) instance));
141 } else {
142 bind(key).toInstance((T) instance);
143 }
144
145 }
146
147 private <T> void bindImplementation(ImplementationConfiguration<T> configuration) {
148 Class<T> key = configuration.getType();
149 Class<? extends T> implementation = configuration.getImplementation();
150
151 ScopedBindingBuilder builder;
152 if (key.equals(implementation)) {
153 builder = bind(implementation);
154 } else {
155 builder = bind(key).to(implementation);
156 }
157 bindInScope(builder, configuration);
158 }
159
160 private <T> ScopedBindingBuilder bindProvider(Class<T> type, Provider<T> provider) {
161 return bind(type).toProvider(Providers.guicify(provider));
162 }
163
164 private <T> ScopedBindingBuilder bindProvider(Class<T> type, Class<? extends Provider<T>> provider) {
165 return bind(type).toProvider(provider);
166 }
167
168 private <T> void bindInScope(ScopedBindingBuilder builder, ComponentConfiguration<T> configuration) {
169 Class<? extends Annotation> scopeAnnotation = getScope(configuration);
170 if (scopeAnnotation != null) {
171 builder.in(scopeAnnotation);
172 }
173 }
174
175 private Class<? extends Annotation> getScope(ComponentConfiguration<?> componentConfiguration) {
176 String scope = componentConfiguration.getScope();
177 if (StringUtils.isEmpty(scope)) {
178 return null;
179 }
180 if (ComponentDefinition.SCOPE_SINGLETON.equalsIgnoreCase(scope) && !componentConfiguration.isLazy()) {
181 return Singleton.class;
182 }
183 if (ComponentDefinition.SCOPE_SINGLETON.equalsIgnoreCase(scope) && componentConfiguration.isLazy()) {
184 return LazySingleton.class;
185 }
186 if (ComponentDefinition.SCOPE_LOCAL.equalsIgnoreCase(scope)) {
187 return LocalScoped.class;
188 }
189 if (ComponentDefinition.SCOPE_SESSION.equalsIgnoreCase(scope)) {
190 return SessionScoped.class;
191 }
192 throw new IllegalStateException("Unknown scope [" + scope + "] for component with type [" + componentConfiguration.getType() + "]");
193 }
194 }