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 info.magnolia.config.registry.decoration.DefinitionDecorators.*;
37 import static java.util.stream.Collectors.toList;
38
39 import info.magnolia.config.registry.decoration.CachingDefinitionDecorator;
40 import info.magnolia.config.registry.decoration.DefinitionDecorator;
41 import info.magnolia.config.registry.validator.DefinitionValidator;
42 import info.magnolia.config.source.stub.ConfigurationSourceTypeStub;
43 import info.magnolia.module.ModuleRegistry;
44
45 import java.util.ArrayList;
46 import java.util.Collection;
47 import java.util.HashSet;
48 import java.util.List;
49 import java.util.Optional;
50 import java.util.Set;
51
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54
55
56
57
58
59
60 public abstract class AbstractRegistry<T> implements Registry<T> {
61
62 private static final Logger log = LoggerFactory.getLogger(AbstractRegistry.class);
63
64 private final RegistryMap<T> registryMap = new RegistryMap<>();
65
66 private final Set<DefinitionDecorator<T>> definitionDecorators = new HashSet<>();
67
68 private final Set<DefinitionValidator<T>> validators = new HashSet<>();
69
70 private final ModuleRegistry moduleRegistry;
71
72 public AbstractRegistry(ModuleRegistry moduleRegistry) {
73 this.moduleRegistry = moduleRegistry;
74 }
75
76 @Override
77 public void start() {
78 throw new IllegalStateException("not implemented yet");
79 }
80
81 protected RegistryMap<T> getRegistryMap() {
82 return registryMap;
83 }
84
85 @Override
86 public void register(DefinitionProvider<T> provider) {
87 getRegistryMap().put(onRegister(provider));
88 }
89
90 @Override
91 public Set<DefinitionMetadata> unregisterAndRegister(Collection<DefinitionMetadata> registeredIds, Collection<DefinitionProvider<T>> providers) {
92 List<DefinitionProvider<T>> wrappedProviders = providers.stream()
93 .map(this::onRegister)
94 .collect(toList());
95
96 for (DefinitionMetadata definitionMetadata : registeredIds) {
97 if (providers.stream().noneMatch(provider -> provider.getMetadata().equals(definitionMetadata))) {
98 for (DefinitionDecorator<T> definitionDecorator : definitionDecorators) {
99 if (definitionDecorator.appliesTo(getRegistryMap().get(definitionMetadata))) {
100 wrappedProviders.add(new DecoratedDefinitionProviderStub<>(this, definitionDecorator));
101 break;
102 }
103 }
104 }
105 }
106 return getRegistryMap().removeAndPutAll(registeredIds, wrappedProviders);
107 }
108
109 protected DefinitionProvider<T> onRegister(DefinitionProvider<T> provider) {
110 return provider;
111 }
112
113 @Override
114 public DefinitionProvider<T> getProvider(final DefinitionMetadata id) {
115 DefinitionProvider<T> provider = getRegistryMap().get(id);
116 if (provider == null) {
117 throw new NoSuchDefinitionException(getReferenceId(id));
118 }
119 provider = provider.isValid() ? getDecoratedDefinitionProvider(provider) : provider;
120 return validate(provider);
121 }
122
123 @Override
124 public DefinitionProvider<T> getProvider(final String referenceId) {
125 DefinitionProvider<T> provider = getRegistryMap().getByStringKey(referenceId);
126 if (provider == null) {
127 throw new NoSuchDefinitionException(referenceId);
128 }
129 provider = provider.isValid() ? getDecoratedDefinitionProvider(provider) : provider;
130 return validate(provider);
131 }
132
133 protected final DefinitionProvider<T> getDecoratedDefinitionProvider(final DefinitionProvider<T> provider) {
134
135 List<DefinitionDecorator<T>> decorators = definitionDecorators.stream()
136 .filter(appliesTo(provider))
137 .sorted(moduleDependencyBasedComparator(moduleRegistry))
138 .collect(toList());
139
140
141
142 DefinitionProvider<T> decoratedProvider = provider;
143 for (final DefinitionDecorator<T> definitionDecorator : decorators) {
144 final DefinitionMetadata definitionProviderMetadata = provider.getMetadata();
145 log.debug("Decorating [{}] definition with the reference id [{}] with [{}]", definitionProviderMetadata.getType().name(), definitionProviderMetadata.getReferenceId(), definitionDecorator.toString());
146 decoratedProvider = definitionDecorator.decorate(decoratedProvider);
147 }
148 return decoratedProvider;
149 }
150
151 @Override
152 public Collection<DefinitionProvider<T>> getAllProviders() {
153 return getAllMetadata().stream()
154 .map(this::getProvider)
155 .collect(toList());
156 }
157
158 @Override
159 public Collection<DefinitionMetadata> getAllMetadata() {
160 return getRegistryMap().keySet();
161 }
162
163 @Override
164 public Collection<T> getAllDefinitions() {
165 return getAllProviders().stream()
166 .filter(DefinitionProvider::isValid)
167 .map(DefinitionProvider::get)
168 .collect(toList());
169 }
170
171 @Override
172 @Deprecated
173 public DefinitionQuery<T> query() {
174 return DefinitionQuery.build(this);
175 }
176
177 @Override
178 public void addDecorator(DefinitionDecorator<T> definitionDecorator) {
179 if (definitionDecorator.metadata().getDecoratedDefinitionReference() != null && getAllProviders().stream().noneMatch(definitionDecorator::appliesTo)) {
180 register(new DecoratedDefinitionProviderStub<>(this, definitionDecorator));
181 }
182
183 final CachingDefinitionDecorator<T> cachingDecorator = new CachingDefinitionDecorator<>(definitionDecorator);
184
185
186 definitionDecorators.remove(cachingDecorator);
187
188
189 definitionDecorators.add(cachingDecorator);
190 }
191
192 @Override
193 public void removeDecorator(DefinitionDecorator<T> definitionDecorator) {
194
195 final DefinitionDecorator<T> toRemove = definitionDecorator instanceof CachingDefinitionDecorator ? definitionDecorator : new CachingDefinitionDecorator<>(definitionDecorator);
196 definitionDecorators.remove(toRemove);
197
198
199 final Optional<DefinitionProvider<T>> decoratedStub = getAllProviders().stream().filter(provider -> definitionDecorator.appliesTo(provider) && ConfigurationSourceTypeStub.stub == provider.getMetadata().getConfigurationSourceType()).findAny();
200 if (decoratedStub.isPresent() && definitionDecorators.stream().noneMatch(decorator -> decorator.appliesTo(decoratedStub.get()))) {
201 getRegistryMap().remove(decoratedStub.get().getMetadata());
202 }
203 }
204
205 @Override
206 public String getReferenceId(DefinitionReference definitionReference) {
207
208
209
210
211
212 return newMetadataBuilder().
213 relativeLocation(definitionReference.getRelativeLocation()).
214 name(definitionReference.getName()).
215 module(definitionReference.getModule()).
216 buildReferenceId();
217 }
218
219 Set<DefinitionDecorator<T>> getDefinitionDecorators() {
220 return definitionDecorators;
221 }
222
223 public void addValidator(DefinitionValidator<T> validator) {
224 validators.add(validator);
225 }
226
227 protected DefinitionProvider<T> validate(DefinitionProvider<T> provider) {
228 return new DefinitionProviderWrapper<T>(provider) {
229 @Override
230 public Collection<Problem> getProblems() {
231 final Collection<Problem> problems = new ArrayList<>(super.getProblems());
232 validators.forEach(validator -> problems.addAll(validator.validate(provider)));
233 return problems;
234 }
235 };
236 }
237 }