1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package io.wcm.handler.url.suffix;
21
22 import static io.wcm.handler.url.suffix.impl.UrlSuffixUtil.KEY_VALUE_DELIMITER;
23 import static io.wcm.handler.url.suffix.impl.UrlSuffixUtil.decodeKey;
24 import static io.wcm.handler.url.suffix.impl.UrlSuffixUtil.decodeResourcePathPart;
25 import static io.wcm.handler.url.suffix.impl.UrlSuffixUtil.decodeValue;
26 import static io.wcm.handler.url.suffix.impl.UrlSuffixUtil.splitSuffix;
27
28 import java.util.ArrayList;
29 import java.util.List;
30 import java.util.Objects;
31 import java.util.function.Predicate;
32 import java.util.stream.Collectors;
33
34 import org.apache.commons.lang3.StringUtils;
35 import org.apache.commons.lang3.math.NumberUtils;
36 import org.apache.sling.api.SlingHttpServletRequest;
37 import org.apache.sling.api.resource.Resource;
38 import org.jetbrains.annotations.NotNull;
39 import org.jetbrains.annotations.Nullable;
40 import org.osgi.annotation.versioning.ProviderType;
41
42 import com.day.cq.wcm.api.Page;
43 import com.day.cq.wcm.api.PageManager;
44
45 import io.wcm.sling.commons.adapter.AdaptTo;
46
47
48
49
50 @ProviderType
51 public final class SuffixParser {
52
53 private final SlingHttpServletRequest request;
54
55
56
57
58
59
60 public SuffixParser(@NotNull SlingHttpServletRequest request) {
61 this.request = request;
62 }
63
64
65
66
67
68
69
70
71
72 @SuppressWarnings("unchecked")
73 public <T> @Nullable T get(@NotNull String key, @NotNull Class<T> clazz) {
74 if (clazz == String.class) {
75 return (T)getString(key, (String)null);
76 }
77 if (clazz == Boolean.class) {
78 return (T)(Boolean)getBoolean(key, false);
79 }
80 if (clazz == Integer.class) {
81 return (T)(Integer)getInt(key, 0);
82 }
83 if (clazz == Long.class) {
84 return (T)(Long)getLong(key, 0L);
85 }
86 throw new IllegalArgumentException("Unsupported type: " + clazz.getName());
87 }
88
89
90
91
92
93
94
95
96
97 @SuppressWarnings("unchecked")
98 public <T> @Nullable T get(@NotNull String key, @Nullable T defaultValue) {
99 if (defaultValue instanceof String || defaultValue == null) {
100 return (T)getString(key, (String)defaultValue);
101 }
102 if (defaultValue instanceof Boolean) {
103 return (T)(Boolean)getBoolean(key, (Boolean)defaultValue);
104 }
105 if (defaultValue instanceof Integer) {
106 return (T)(Integer)getInt(key, (Integer)defaultValue);
107 }
108 if (defaultValue instanceof Long) {
109 return (T)(Long)getLong(key, (Long)defaultValue);
110 }
111 throw new IllegalArgumentException("Unsupported type: " + defaultValue.getClass().getName());
112 }
113
114 private String getString(String key, String defaultValue) {
115 String value = findSuffixPartByKey(key);
116 if (value == null) {
117 return defaultValue;
118 }
119 return value;
120 }
121
122 private boolean getBoolean(String key, boolean defaultValue) {
123 String value = findSuffixPartByKey(key);
124 if (value == null) {
125 return defaultValue;
126 }
127
128
129 if ("true".equals(value)) {
130 return true;
131 }
132 if ("false".equals(value)) {
133 return false;
134 }
135
136
137 return defaultValue;
138 }
139
140 private int getInt(String key, int defaultValue) {
141 String value = findSuffixPartByKey(key);
142 if (value == null) {
143 return defaultValue;
144 }
145 return NumberUtils.toInt(value, defaultValue);
146 }
147
148 private long getLong(String key, long defaultValue) {
149 String value = findSuffixPartByKey(key);
150 if (value == null) {
151 return defaultValue;
152 }
153 return NumberUtils.toLong(value, defaultValue);
154 }
155
156
157
158
159
160
161 private String findSuffixPartByKey(String key) {
162 for (String part : splitSuffix(request.getRequestPathInfo().getSuffix())) {
163 if (part.indexOf(KEY_VALUE_DELIMITER) >= 0) {
164 String partKey = decodeKey(part);
165 if (partKey.equals(key)) {
166 return decodeValue(part);
167 }
168 }
169 }
170 return null;
171 }
172
173
174
175
176
177
178 public @Nullable Resource getResource() {
179 return getResource((Predicate<Resource>)null, (Resource)null);
180 }
181
182
183
184
185
186
187 public @Nullable Resource getResource(@NotNull Resource baseResource) {
188 return getResource((Predicate<Resource>)null, baseResource);
189 }
190
191
192
193
194
195
196
197 public @Nullable Resource getResource(@NotNull Predicate<Resource> filter) {
198 return getResource(filter, (Resource)null);
199 }
200
201
202
203
204
205
206
207 public @Nullable Resource getResource(@Nullable Predicate<Resource> filter, @Nullable Resource baseResource) {
208 List<Resource> suffixResources = getResources(filter, baseResource);
209 if (suffixResources.isEmpty()) {
210 return null;
211 }
212 else {
213 return suffixResources.get(0);
214 }
215 }
216
217
218
219
220
221 public @NotNull List<Resource> getResources() {
222 return getResources((Predicate<Resource>)null, (Resource)null);
223 }
224
225
226
227
228
229
230 public @NotNull List<Resource> getResources(@NotNull Resource baseResource) {
231 return getResources((Predicate<Resource>)null, baseResource);
232 }
233
234
235
236
237
238
239 public @NotNull List<Resource> getResources(@NotNull Predicate<Resource> filter) {
240 return getResources(filter, (Resource)null);
241 }
242
243
244
245
246
247
248
249 @SuppressWarnings("java:S112")
250 public @NotNull List<Resource> getResources(@Nullable Predicate<Resource> filter, @Nullable Resource baseResource) {
251
252
253 Resource baseResourceToUse = baseResource;
254 if (baseResourceToUse == null) {
255 PageManager pageManager = request.getResourceResolver().adaptTo(PageManager.class);
256 if (pageManager == null) {
257 throw new RuntimeException("No page manager.");
258 }
259 Page currentPage = pageManager.getContainingPage(request.getResource());
260 if (currentPage != null) {
261 baseResourceToUse = currentPage.getContentResource();
262 }
263 else {
264 baseResourceToUse = request.getResource();
265 }
266 }
267 return getResourcesWithBaseResource(filter, baseResourceToUse);
268 }
269
270
271
272
273
274
275 public @Nullable Page getPage() {
276 return getPage((Predicate<Page>)null, (Page)null);
277 }
278
279
280
281
282
283
284 public @Nullable Page getPage(@NotNull Page basePage) {
285 return getPage((Predicate<Page>)null, basePage);
286 }
287
288
289
290
291
292
293
294 public @Nullable Page getPage(@NotNull Predicate<Page> filter) {
295 return getPage(filter, (Page)null);
296 }
297
298
299
300
301
302
303
304 public @Nullable Page getPage(@Nullable Predicate<Page> filter, @Nullable Page basePage) {
305 List<Page> suffixPages = getPages(filter, basePage);
306 if (suffixPages.isEmpty()) {
307 return null;
308 }
309 else {
310 return suffixPages.get(0);
311 }
312 }
313
314
315
316
317
318
319 public @NotNull List<Page> getPages() {
320 return getPages((Predicate<Page>)null, (Page)null);
321 }
322
323
324
325
326
327
328
329 public @NotNull List<Page> getPages(@NotNull Predicate<Page> filter) {
330 return getPages(filter, (Page)null);
331 }
332
333
334
335
336
337
338
339 @SuppressWarnings("null")
340 public @NotNull List<Page> getPages(@Nullable final Predicate<Page> filter, @Nullable final Page basePage) {
341 Resource baseResourceToUse = null;
342
343
344 if (basePage == null) {
345 PageManager pageManager = AdaptTo.notNull(request.getResourceResolver(), PageManager.class);
346 Page currentPage = pageManager.getContainingPage(request.getResource());
347 if (currentPage != null) {
348 baseResourceToUse = currentPage.adaptTo(Resource.class);
349 }
350 }
351 else {
352 baseResourceToUse = basePage.adaptTo(Resource.class);
353 }
354
355
356 Predicate<Resource> resourceFilter = resource -> {
357 Page page = resource.adaptTo(Page.class);
358 if (page == null) {
359 return false;
360 }
361 if (filter == null) {
362 return true;
363 }
364 return filter.test(page);
365 };
366 List<Resource> resources = getResourcesWithBaseResource(resourceFilter, baseResourceToUse);
367
368
369 return resources.stream()
370 .filter(Objects::nonNull)
371 .map(resource -> resource.adaptTo(Page.class))
372 .filter(Objects::nonNull)
373 .collect(Collectors.toList());
374 }
375
376 @SuppressWarnings("java:S135")
377 private @NotNull List<Resource> getResourcesWithBaseResource(@Nullable Predicate<Resource> filter, @Nullable Resource baseResource) {
378
379 String[] suffixParts = splitSuffix(request.getRequestPathInfo().getSuffix());
380
381
382 List<Resource> selectedResources = new ArrayList<>();
383 for (String path : suffixParts) {
384
385
386 if (StringUtils.contains(path, KEY_VALUE_DELIMITER)) {
387 continue;
388 }
389
390 String decodedPath = decodeResourcePathPart(path);
391
392
393 Resource resource = request.getResourceResolver().getResource(baseResource, decodedPath);
394 if (resource == null) {
395
396 continue;
397 }
398
399
400 if (filter == null || filter.test(resource)) {
401 selectedResources.add(resource);
402 }
403
404 }
405
406 return selectedResources;
407 }
408
409 }