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.resources.app.data;
35
36 import static info.magnolia.resources.app.workbench.tree.ResourcesTreePresenter.*;
37
38 import info.magnolia.jcr.RuntimeRepositoryException;
39 import info.magnolia.jcr.util.NodeTypes;
40 import info.magnolia.resourceloader.Resource;
41 import info.magnolia.resourceloader.ResourceOrigin;
42 import info.magnolia.resourceloader.layered.LayeredResource;
43 import info.magnolia.ui.datasource.optionlist.Option;
44 import info.magnolia.ui.filter.DataFilter;
45
46 import java.util.Arrays;
47 import java.util.List;
48 import java.util.stream.Stream;
49
50 import javax.inject.Inject;
51 import javax.jcr.Node;
52 import javax.jcr.RepositoryException;
53
54 import org.apache.commons.lang3.StringUtils;
55
56 import com.vaadin.data.provider.AbstractBackEndDataProvider;
57 import com.vaadin.data.provider.Query;
58
59
60
61
62 public class ResourceFilteringDataProvider extends AbstractBackEndDataProvider<Resource, DataFilter> implements ResourceHelper {
63
64 private final ResourceOrigin<?> resourceOrigin;
65
66 @Inject
67 public ResourceFilteringDataProvider(ResourceOrigin<?> resourceOrigin) {
68 this.resourceOrigin = resourceOrigin;
69 }
70
71 @Override
72 public Object getId(Resource item) {
73 return item.getPath();
74 }
75
76 @Override
77 protected Stream<Resource> fetchFromBackEnd(Query<Resource, DataFilter> query) {
78 return resourceOrigin.find("/", resource -> query.getFilter()
79 .map(dataFilter -> applyFilter(resource, dataFilter))
80 .orElse(true))
81 .skip(query.getOffset())
82 .limit(query.getLimit());
83 }
84
85 private boolean applyFilter(Resource resource, DataFilter filter) {
86 return filter.getPropertyFilters().entrySet().stream()
87 .filter(stringObjectEntry -> !"".equals(stringObjectEntry.getValue()))
88 .allMatch(stringObjectEntry -> filter(stringObjectEntry.getValue(), resource, stringObjectEntry.getKey()));
89 }
90
91 private boolean filter(Object filterValue, Resource resource, String propertyName) {
92 if (filterValue == null) {
93 return true;
94 } else if (COLUMN_ORIGIN.equals(propertyName)) {
95 return filterByOrigin((ResourceOrigin<?>) filterValue, resource);
96 } else if (COLUMN_TYPE.equals(propertyName)) {
97 return StringUtils.contains(TIKA.detect(resource.getName()), (String) filterValue);
98 } else if (COLUMN_NAME.equals(propertyName)) {
99 return resource.getName().contains((String) filterValue);
100 } else if (COLUMN_OVERRIDDEN.equals(propertyName)) {
101 return !((Boolean) filterValue) || (resource instanceof LayeredResource && ((LayeredResource) resource).getLayers().size() > 1);
102 } else if (COLUMN_STATUS.equals(propertyName)) {
103 int expectedStatus = Integer.parseInt(((Option) filterValue).getValue());
104 return getJcrNode(resource)
105 .map(this::getActivationStatus)
106 .map(integer -> integer == expectedStatus)
107 .orElse(false);
108 }
109 throw new IllegalArgumentException("Unsupported filter property: " + propertyName);
110 }
111
112 private boolean filterByOrigin(ResourceOrigin<?> filterValue, Resource resource) {
113 List<Resource> resources = resource instanceof LayeredResource ? ((LayeredResource) resource).getLayers() : Arrays.asList(resource);
114 return resources.stream()
115 .map(Resource::getOrigin)
116 .anyMatch(origin -> origin.getClass().equals(filterValue.getClass()));
117 }
118
119 private int getActivationStatus(Node node) {
120 try {
121 return NodeTypes.Activatable.getActivationStatus(node);
122 } catch (RepositoryException e) {
123 throw new RuntimeRepositoryException(e);
124 }
125 }
126
127 @Override
128 protected int sizeInBackEnd(Query<Resource, DataFilter> query) {
129 return (int) fetchFromBackEnd(query).count();
130 }
131 }
132