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.rest.registry;
35
36 import static info.magnolia.rest.registry.EndpointDefinitionRegistryEventType.*;
37
38 import info.magnolia.config.registry.AbstractRegistry;
39 import info.magnolia.config.registry.DefinitionMetadata;
40 import info.magnolia.config.registry.DefinitionMetadataBuilder;
41 import info.magnolia.config.registry.DefinitionProvider;
42 import info.magnolia.config.registry.DefinitionProvider.Problem;
43 import info.magnolia.config.registry.DefinitionType;
44 import info.magnolia.config.registry.decoration.DefinitionDecorator;
45 import info.magnolia.event.EventBus;
46 import info.magnolia.event.SystemEventBus;
47 import info.magnolia.module.ModuleRegistry;
48 import info.magnolia.objectfactory.Components;
49 import info.magnolia.registry.RegistrationException;
50 import info.magnolia.rest.DynamicPath;
51 import info.magnolia.rest.EndpointDefinition;
52
53 import java.util.Collection;
54 import java.util.List;
55 import java.util.Optional;
56 import java.util.Set;
57
58 import javax.inject.Inject;
59 import javax.inject.Named;
60 import javax.inject.Singleton;
61
62 import org.slf4j.Logger;
63 import org.slf4j.LoggerFactory;
64
65
66
67
68 @Singleton
69 public class EndpointDefinitionRegistry extends AbstractRegistry<EndpointDefinition> {
70
71 private static final Logger log = LoggerFactory.getLogger(EndpointDefinitionRegistry.class);
72
73 static final DefinitionType TYPE = new DefinitionType() {
74 @Override
75 public String name() {
76 return "restEndpoint";
77 }
78
79 @Override
80 public Class baseClass() {
81 return EndpointDefinition.class;
82 }
83 };
84
85 private EventBus systemEventBus;
86
87 @Inject
88 public EndpointDefinitionRegistry(ModuleRegistry moduleRegistry, @Named(SystemEventBus.NAME) EventBus systemEventBus) {
89 super(moduleRegistry);
90 this.systemEventBus = systemEventBus;
91 }
92
93
94
95
96 @Deprecated
97 public EndpointDefinitionRegistry(@Named(SystemEventBus.NAME) EventBus systemEventBus) {
98 this(Components.getComponent(ModuleRegistry.class), systemEventBus);
99 }
100
101 @Override
102 public DefinitionType type() {
103 return TYPE;
104 }
105
106 @Override
107 public DefinitionMetadataBuilder newMetadataBuilder() {
108 return new RelativePathMetadataBuilder();
109 }
110
111 @Override
112 public void register(DefinitionProvider<EndpointDefinition> provider) {
113 DefinitionMetadata registeredMetadata = getRegistryMap().put(onRegister(provider));
114 if (registeredMetadata != null) {
115 DefinitionProvider<EndpointDefinition> decoratedProvider = getDecoratedDefinitionProvider(provider);
116 systemEventBus.fireEvent(new EndpointDefinitionRegistryEvent(REGISTERED, decoratedProvider));
117 }
118 }
119
120 @Override
121 protected DefinitionProvider<EndpointDefinition> onRegister(DefinitionProvider<EndpointDefinition> provider) {
122
123 DefinitionProvider<EndpointDefinition> definitionProvider = super.onRegister(provider);
124
125 try {
126 final EndpointDefinition endpointDefinition = provider.get();
127 DefinitionProvider<EndpointDefinition> conflictDefinition = getAllProviders().stream()
128 .filter(p -> !p.getMetadata().getReferenceId().equals(provider.getMetadata().getReferenceId()))
129 .filter(p -> endpointDefinition.getImplementationClass().getAnnotation(DynamicPath.class) == null)
130 .filter(p -> endpointDefinition.getImplementationClass().equals(p.get().getImplementationClass()))
131 .findFirst().orElse(null);
132
133 if (conflictDefinition != null) {
134 final String message = String.format("Endpoint definitions [%s:%s] and [%s:%s] both declare implementationClass [%s]. REST module V1 does not support endpoints with identical implementationClass.",
135 provider.getMetadata().getName(),
136 provider.getMetadata().getReferenceId(),
137 conflictDefinition.getMetadata().getName(),
138 conflictDefinition.getMetadata().getReferenceId(),
139 endpointDefinition.getImplementationClass());
140 Problem problem = Problem.major()
141 .withDetails(message)
142 .withTitle("Conflict endpoint definitions.")
143 .withType(Problem.DefaultTypes.SEMANTIC)
144 .withLocation(provider.getMetadata().getLocation())
145 .build();
146 provider.getProblems().add(problem);
147 }
148 } catch (Exception e) {
149 log.error("Error happens when checking endpoint duplications.", e);
150 }
151 return definitionProvider;
152 }
153
154 @Override
155 public Set<DefinitionMetadata> unregisterAndRegister(Collection<DefinitionMetadata> toRemoveIds, Collection<DefinitionProvider<EndpointDefinition>> definitionProviders) {
156 Set<DefinitionMetadata> registeredIds = super.unregisterAndRegister(toRemoveIds, definitionProviders);
157
158 toRemoveIds.stream()
159 .filter(metadata -> !registeredIds.contains(metadata))
160 .map(DefinitionMetadata::getReferenceId)
161 .forEach(referenceId -> systemEventBus.fireEvent(new EndpointDefinitionRegistryEvent(UNREGISTERED, referenceId)));
162
163 definitionProviders.stream()
164 .filter(provider -> toRemoveIds.contains(provider.getMetadata()))
165 .filter(provider -> registeredIds.contains(provider.getMetadata()))
166 .forEach(provider -> systemEventBus.fireEvent(new EndpointDefinitionRegistryEvent(REREGISTERED, provider)));
167
168 definitionProviders.stream()
169 .filter(provider -> !toRemoveIds.contains(provider.getMetadata()))
170 .filter(provider -> registeredIds.contains(provider.getMetadata()))
171 .forEach(provider -> systemEventBus.fireEvent(new EndpointDefinitionRegistryEvent(REGISTERED, provider)));
172
173 return registeredIds;
174 }
175
176 @Override
177 public void addDecorator(DefinitionDecorator<EndpointDefinition> decorator) {
178 super.addDecorator(decorator);
179 Optional<DefinitionProvider<EndpointDefinition>> targetProvider = getAllProviders().stream()
180 .filter(decorator::appliesTo)
181 .findFirst();
182 if (targetProvider.isPresent()) {
183 systemEventBus.fireEvent(new EndpointDefinitionRegistryEvent(REREGISTERED, targetProvider.get()));
184 } else {
185
186 super.removeDecorator(decorator);
187 }
188 }
189
190 @Override
191 public void removeDecorator(DefinitionDecorator<EndpointDefinition> decorator) {
192 Optional<DefinitionProvider<EndpointDefinition>> targetProvider = getAllProviders().stream()
193 .filter(decorator::appliesTo)
194 .findFirst();
195 super.removeDecorator(decorator);
196 targetProvider.ifPresent(provider -> systemEventBus.fireEvent(new EndpointDefinitionRegistryEvent(REREGISTERED, provider)));
197 }
198
199
200
201
202 @Deprecated
203 public EndpointDefinition getEndpointDefinition(String name) throws RegistrationException {
204 final EndpointDefinition endpointDefinition;
205 try {
206 endpointDefinition = getProvider(name).get();
207 } catch (NoSuchDefinitionException | InvalidDefinitionException e) {
208 throw new RegistrationException(e.getMessage(), e);
209 }
210 return endpointDefinition;
211 }
212
213
214
215
216 @Deprecated
217 public Set<String> unregisterAndRegister(Set<String> registeredNames, List<EndpointDefinitionProvider> providers) {
218 return null;
219 }
220
221
222
223
224 @Deprecated
225 public boolean isEndpointDefinitionRegistered(String name) {
226 try {
227 return getProvider(name).isValid();
228 } catch (NoSuchDefinitionException e) {
229 return false;
230 }
231 }
232
233
234
235
236 @Deprecated
237 public Collection<EndpointDefinition> getAllEndpointDefinitions() {
238 return getAllDefinitions();
239 }
240
241
242
243
244
245
246 public static class RelativePathMetadataBuilder extends DefinitionMetadataBuilder {
247 @Override
248 protected String buildReferenceId() {
249 return getRelativeLocation();
250 }
251 }
252 }