1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package io.wcm.wcm.ui.granite.pathfield.impl;
21
22 import java.io.IOException;
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.Collections;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.regex.Pattern;
29
30 import javax.jcr.Node;
31 import javax.jcr.RepositoryException;
32 import javax.servlet.Servlet;
33 import javax.servlet.ServletException;
34
35 import org.apache.commons.collections4.IteratorUtils;
36 import org.apache.commons.collections4.Predicate;
37 import org.apache.commons.collections4.PredicateUtils;
38 import org.apache.commons.collections4.Transformer;
39 import org.apache.commons.collections4.iterators.FilterIterator;
40 import org.apache.commons.collections4.iterators.TransformIterator;
41 import org.apache.sling.api.SlingHttpServletRequest;
42 import org.apache.sling.api.SlingHttpServletResponse;
43 import org.apache.sling.api.resource.Resource;
44 import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
45 import org.apache.sling.servlets.annotations.SlingServletResourceTypes;
46 import org.jetbrains.annotations.NotNull;
47 import org.osgi.framework.BundleContext;
48 import org.osgi.service.component.annotations.Activate;
49 import org.osgi.service.component.annotations.Component;
50 import org.osgi.service.component.annotations.Reference;
51
52 import com.adobe.granite.ui.components.Config;
53 import com.adobe.granite.ui.components.ExpressionHelper;
54 import com.adobe.granite.ui.components.ExpressionResolver;
55 import com.adobe.granite.ui.components.PagingIterator;
56 import com.adobe.granite.ui.components.ds.AbstractDataSource;
57 import com.adobe.granite.ui.components.ds.DataSource;
58 import com.adobe.granite.ui.components.ds.EmptyDataSource;
59
60 import io.wcm.wcm.ui.granite.pathfield.impl.predicate.HideInternalContentPathsPredicate;
61 import io.wcm.wcm.ui.granite.pathfield.impl.util.PredicatedResourceWrapper;
62 import io.wcm.wcm.ui.granite.util.impl.PredicateProviderUtils;
63
64
65
66
67 @Component(service = Servlet.class)
68 @SlingServletResourceTypes(
69 resourceTypes = PathFieldChildrenDatasourceServlet.RESOURCE_TYPE)
70 public class PathFieldChildrenDatasourceServlet extends SlingSafeMethodsServlet {
71
72 private static final long serialVersionUID = 1L;
73
74 static final String RESOURCE_TYPE = "wcm-io/wcm/ui/granite/components/form/pathfield/datasources/children";
75
76 private BundleContext bundleContext;
77 @Reference
78 private ExpressionResolver expressionResolver;
79
80 @Activate
81 private void activate(BundleContext bc) {
82 this.bundleContext = bc;
83 }
84
85 @Override
86 @SuppressWarnings("null")
87 protected void doGet(@NotNull SlingHttpServletRequest request, @NotNull SlingHttpServletResponse response)
88 throws ServletException, IOException {
89
90 final ExpressionHelper ex = new ExpressionHelper(expressionResolver, request);
91 final Config cfg = new Config(request.getResource().getChild(Config.DATASOURCE));
92
93 final String query = ex.getString(cfg.get("query", String.class));
94
95 final String parentPath;
96 final String searchName;
97
98 if (query != null) {
99 final String rootPath = ex.getString(cfg.get("rootPath", "/"));
100
101 final int slashIndex = query.lastIndexOf('/');
102 if (slashIndex < 0) {
103 parentPath = rootPath;
104 searchName = query.toLowerCase();
105 }
106 else if (!query.startsWith(rootPath)) {
107 parentPath = rootPath;
108 searchName = null;
109 }
110 else if (slashIndex == query.length() - 1) {
111 parentPath = query;
112 searchName = null;
113 }
114 else {
115 parentPath = query.substring(0, slashIndex + 1);
116 searchName = query.substring(slashIndex + 1).toLowerCase();
117 }
118 }
119 else {
120 parentPath = ex.getString(cfg.get("path", String.class));
121 searchName = null;
122 }
123
124 final Resource parent = request.getResourceResolver().getResource(parentPath);
125
126 final DataSource ds;
127 if (parent == null) {
128 ds = EmptyDataSource.instance();
129 }
130 else {
131 final Integer offset = ex.get(cfg.get("offset", String.class), Integer.class);
132 final Integer limit = ex.get(cfg.get("limit", String.class), Integer.class);
133 final String itemResourceType = cfg.get("itemResourceType", String.class);
134 final String[] filter = new String[] {
135 ex.get(cfg.get("filter", "hierarchyNotFile"), String.class)
136 };
137
138 final Collection<Predicate<Resource>> predicates = new ArrayList<>();
139 predicates.add(new HideInternalContentPathsPredicate());
140 predicates.addAll(PredicateProviderUtils.toPredicates(filter, bundleContext));
141
142 if (searchName != null) {
143 final Pattern searchNamePattern = Pattern.compile(Pattern.quote(searchName), Pattern.CASE_INSENSITIVE);
144 predicates.add(resource -> searchNamePattern.matcher(resource.getName()).lookingAt());
145 }
146
147 final Predicate<Resource> predicate = PredicateUtils.allPredicate(predicates);
148 final Transformer<Resource, Resource> transformer = createTransformer(itemResourceType, predicate);
149
150 DataSource datasource = new AbstractDataSource() {
151
152 @Override
153 public Iterator<Resource> iterator() {
154 List<Resource> list = IteratorUtils.toList(new FilterIterator<>(parent.listChildren(), predicate));
155
156
157 if (!isOrderableChildNodes(parent)) {
158 Collections.sort(list, (Resource r1, Resource r2) -> r1.getName().compareTo(r2.getName()));
159 }
160
161 return new TransformIterator<>(new PagingIterator<>(list.iterator(), offset, limit), transformer);
162 }
163 };
164
165 ds = datasource;
166 }
167
168 request.setAttribute(DataSource.class.getName(), ds);
169 }
170
171 private static Transformer<Resource, Resource> createTransformer(final String itemResourceType, final Predicate<Resource> predicate) {
172 return r -> new PredicatedResourceWrapper(r, predicate) {
173
174 @Override
175 public @NotNull String getResourceType() {
176 if (itemResourceType == null) {
177 return super.getResourceType();
178 }
179 return itemResourceType;
180 }
181 };
182 }
183
184 private static boolean isOrderableChildNodes(Resource resource) {
185 Node node = resource.adaptTo(Node.class);
186 if (node != null) {
187 try {
188 return node.getPrimaryNodeType().hasOrderableChildNodes();
189 }
190 catch (RepositoryException ex) {
191 return false;
192 }
193 }
194 return false;
195 }
196
197 }