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.config.registry;
35
36 import static com.google.common.collect.FluentIterable.from;
37 import static info.magnolia.config.registry.decoration.DefinitionDecorators.appliesTo;
38 import static info.magnolia.config.registry.decoration.DefinitionDecorators.moduleDependencyBasedComparator;
39
40 import info.magnolia.config.NamedDefinition;
41 import info.magnolia.config.registry.decoration.CachingDefinitionDecorator;
42 import info.magnolia.config.registry.decoration.DefinitionDecorator;
43 import info.magnolia.module.ModuleRegistry;
44 import info.magnolia.objectfactory.Components;
45
46 import java.lang.reflect.Method;
47 import java.util.Collection;
48 import java.util.List;
49 import java.util.Set;
50
51 import javax.annotation.Nullable;
52
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56 import com.google.common.base.Function;
57 import com.google.common.base.Predicate;
58 import com.google.common.base.Predicates;
59 import com.google.common.collect.Collections2;
60 import com.google.common.collect.Lists;
61 import com.google.common.collect.Sets;
62 import com.thoughtworks.proxy.factory.CglibProxyFactory;
63 import com.thoughtworks.proxy.toys.decorate.Decorating;
64 import com.thoughtworks.proxy.toys.decorate.Decorator;
65
66
67
68
69
70
71 public abstract class AbstractRegistry<T> implements Registry<T> {
72
73 private static final Logger log = LoggerFactory.getLogger(AbstractRegistry.class);
74
75 private final RegistryMap<T> registryMap = new RegistryMap<>();
76
77 private final CglibProxyFactory proxyFactory;
78
79 private final Set<DefinitionDecorator<T>> definitionDecorators = Sets.newHashSet();
80
81 private final ModuleRegistry moduleRegistry;
82
83
84
85
86 @Deprecated
87 public AbstractRegistry() {
88 this(Components.getComponent(ModuleRegistry.class));
89 }
90
91 public AbstractRegistry(ModuleRegistry moduleRegistry) {
92 this.moduleRegistry = moduleRegistry;
93 this.proxyFactory = new CglibProxyFactory(false);
94 }
95
96 @Override
97 public void start() {
98 throw new IllegalStateException("not implemented yet");
99 }
100
101 protected RegistryMap<T> getRegistryMap() {
102 return registryMap;
103 }
104
105 @Override
106 public void register(DefinitionProvider<T> provider) {
107 getRegistryMap().put(onRegister(provider));
108 }
109
110 @Override
111 public Set<DefinitionMetadata> unregisterAndRegister(Collection<DefinitionMetadata> registeredIds, Collection<DefinitionProvider<T>> providers) {
112 final Collection<DefinitionProvider<T>> wrappedProviders = Collections2.transform(providers, new Function<DefinitionProvider<T>, DefinitionProvider<T>>() {
113 @Override
114 public DefinitionProvider<T> apply(DefinitionProvider<T> input) {
115 return onRegister(input);
116 }
117 });
118 return getRegistryMap().removeAndPutAll(registeredIds, wrappedProviders);
119 }
120
121
122
123
124
125
126
127
128 protected DefinitionProvider<T> onRegister(DefinitionProvider<T> provider) {
129 if (provider.isValid()) {
130 final T def = provider.get();
131 final T decoratedDef;
132 if (def instanceof NamedDefinition) {
133 decoratedDef = Decorating.proxy(def).visiting(new GetNameFromMetadata<>(provider)).build(proxyFactory);
134 } else {
135 decoratedDef = def;
136 }
137
138 return new SwappedDefinitionProviderWrapper<>(provider, decoratedDef);
139 } else {
140 return provider;
141 }
142 }
143
144 @Override
145 public DefinitionProvider<T> getProvider(final DefinitionMetadata id) {
146 final DefinitionProvider<T> provider = getRegistryMap().get(id);
147 if (provider == null) {
148 throw new NoSuchDefinitionException(getReferenceId(id));
149 }
150 return getDecoratedDefinitionProvider(provider);
151 }
152
153 @Override
154 public DefinitionProvider<T> getProvider(final String referenceId) {
155 final DefinitionProvider<T> provider = getRegistryMap().getByStringKey(referenceId);
156 if (provider == null) {
157 throw new NoSuchDefinitionException(referenceId);
158 }
159 return getDecoratedDefinitionProvider(provider);
160 }
161
162 protected final DefinitionProvider<T> getDecoratedDefinitionProvider(final DefinitionProvider<T> provider) {
163
164 final List<DefinitionDecorator<T>> decorators =
165 from(this.definitionDecorators).
166 filter(appliesTo(provider)).
167 toSortedList(moduleDependencyBasedComparator(moduleRegistry));
168
169
170
171 DefinitionProvider<T> decoratedProvider = provider;
172 for (final DefinitionDecorator<T> definitionDecorator : decorators) {
173 final DefinitionMetadata definitionProviderMetadata = provider.getMetadata();
174 log.debug("Decorating [{}] definition with the reference id [{}] with [{}]", definitionProviderMetadata.getType().name(), definitionProviderMetadata.getReferenceId(), definitionDecorator.toString());
175 decoratedProvider = definitionDecorator.decorate(decoratedProvider);
176 }
177
178 return decoratedProvider;
179 }
180
181 @Override
182 public Collection<DefinitionProvider<T>> getAllProviders() {
183 return Collections2.transform(getAllMetadata(), new Function<DefinitionMetadata, DefinitionProvider<T>>() {
184 @Nullable
185 @Override
186 public DefinitionProvider<T> apply(@Nullable DefinitionMetadata input) {
187 return getProvider(input);
188 }
189 });
190 }
191
192 @Override
193 public Collection<DefinitionMetadata> getAllMetadata() {
194 return getRegistryMap().keySet();
195 }
196
197 @Override
198 public Collection<T> getAllDefinitions() {
199 final Collection<DefinitionProvider<T>> validProviders = Collections2.filter(getAllProviders(), VALID);
200 return Lists.newArrayList(Collections2.transform(validProviders, new DefinitionProviderGet<T>()));
201 }
202
203 private final Predicate<DefinitionProvider<T>> VALID = new ValidDefinitionProvider<>();
204 private final Predicate<DefinitionProvider<T>> ALL = Predicates.alwaysTrue();
205 private final Function<DefinitionProvider<T>, T> GET = new DefinitionProviderGet<>();
206
207 private static class ValidDefinitionProvider<T> implements Predicate<DefinitionProvider<T>> {
208 @Override
209 public boolean apply(DefinitionProvider<T> input) {
210 return input.isValid();
211 }
212 }
213
214 private static class DefinitionProviderGet<T> implements Function<DefinitionProvider<T>, T> {
215 @Override
216 public T apply(DefinitionProvider<T> input) {
217 return input.get();
218 }
219 }
220
221 @Override
222 public DefinitionQuery<T> query() {
223 return new DefinitionQueryImpl<>(this);
224 }
225
226 @Override
227 public void addDecorator(DefinitionDecorator<T> definitionDecorator) {
228 final CachingDefinitionDecorator<T> cachingDecorator = new CachingDefinitionDecorator<>(definitionDecorator);
229
230
231 definitionDecorators.remove(cachingDecorator);
232
233
234 definitionDecorators.add(cachingDecorator);
235 }
236
237 @Override
238 public void removeDecorator(DefinitionDecorator<T> definitionDecorator) {
239
240 final DefinitionDecorator<T> toRemove = definitionDecorator instanceof CachingDefinitionDecorator ? definitionDecorator : new CachingDefinitionDecorator<>(definitionDecorator);
241 definitionDecorators.remove(toRemove);
242 }
243
244 @Override
245 public String getReferenceId(DefinitionReference definitionReference) {
246
247
248
249
250
251 return newMetadataBuilder().
252 relativeLocation(definitionReference.getRelativeLocation()).
253 name(definitionReference.getName()).
254 module(definitionReference.getModule()).
255 buildReferenceId();
256 }
257
258 private static class DefinitionQueryImpl<T> extends DefinitionQuery<T> {
259 private final Registry registry;
260
261 public DefinitionQueryImpl(Registry registry) {
262 this.registry = registry;
263 }
264
265 @Override
266 public Collection<DefinitionProvider<T>> findMultiple() {
267 return findMultipleOn(registry);
268 }
269
270 protected Collection<DefinitionProvider<T>> findMultipleOn(final Registry<T> registry) {
271 final Collection<DefinitionMetadata> allMetadata = registry.getAllMetadata();
272 final Collection<DefinitionMetadata> matchingMetas = Collections2.filter(allMetadata, new QueryPredicate<T>(this));
273
274 return Collections2.transform(matchingMetas, new Function<DefinitionMetadata, DefinitionProvider<T>>() {
275 @Override
276 public DefinitionProvider<T> apply(DefinitionMetadata md) {
277 return registry.getProvider(md);
278 }
279 });
280 }
281 }
282
283 private static class QueryPredicate<T> implements Predicate<DefinitionMetadata> {
284 private final DefinitionQuery query;
285
286 public QueryPredicate(DefinitionQuery query) {
287 this.query = query;
288 }
289
290 @Override
291 public boolean apply(DefinitionMetadata input) {
292 boolean match = true;
293 match &= match(query.getName(), input.getName());
294 match &= match(query.getModule(), input.getModule());
295 return match;
296 }
297
298 private boolean match(String queryParam, String actual) {
299 if (queryParam == null) {
300
301 return true;
302 }
303 return queryParam.equals(actual);
304 }
305 }
306
307 private static class GetNameFromMetadata<T> extends Decorator<T> {
308 private final DefinitionProvider<T> definitionProvider;
309
310 public GetNameFromMetadata(DefinitionProvider<T> definitionProvider) {
311 this.definitionProvider = definitionProvider;
312 }
313
314 @Override
315 public Object decorateResult(T proxy, Method method, Object[] args, Object result) {
316 if (result == null) {
317
318 if ("getName".equals(method.getName())) {
319 return definitionProvider.getMetadata().getName();
320 }
321 }
322 return result;
323 }
324 }
325
326 private static class SwappedDefinitionProviderWrapper<T> extends DefinitionProviderWrapper<T> {
327 private final T decoratedDef;
328
329 public SwappedDefinitionProviderWrapper(DefinitionProvider<T> provider, T decoratedDef) {
330 super(provider);
331 this.decoratedDef = decoratedDef;
332 }
333
334 @Override
335 public T get() {
336 return decoratedDef;
337 }
338 }
339 }