
io.devbench.uibuilder.data.collectionds.CollectionDataSource Maven / Gradle / Ivy
/*
*
* Copyright © 2018 Webvalto Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.devbench.uibuilder.data.collectionds;
import io.devbench.uibuilder.core.utils.reflection.ClassMetadata;
import io.devbench.uibuilder.core.utils.reflection.PropertyMetadata;
import io.devbench.uibuilder.data.api.filter.FilterExpressionFactory;
import io.devbench.uibuilder.data.api.order.OrderExpressionFactory;
import io.devbench.uibuilder.data.api.order.SortOrder;
import io.devbench.uibuilder.data.collectionds.filter.CollectionFilterExpression;
import io.devbench.uibuilder.data.collectionds.filter.factories.CollectionFilterExpressionFactory;
import io.devbench.uibuilder.data.collectionds.interceptors.ItemDataSourceBindingContext;
import io.devbench.uibuilder.data.common.dataprovidersupport.KeyMapper;
import io.devbench.uibuilder.data.common.dataprovidersupport.OrmKeyMapper;
import io.devbench.uibuilder.data.common.dataprovidersupport.requestresponse.DataProviderRequest;
import io.devbench.uibuilder.data.common.datasource.CommonDataSource;
import io.devbench.uibuilder.data.common.datasource.PagingFetchRequest;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.annotation.Nonnull;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class CollectionDataSource extends CommonDataSource, ItemDataSourceBindingContext> {
@Getter
private final List keyPaths;
private final KeyMapper keyMapper;
private final CollectionFilterExpressionFactory filterExpressionFactory;
private final Collection items;
private Collection children;
private CollectionOrderExpression orderExpression;
private CollectionFilterExpression filterExpression;
public CollectionDataSource(ItemDataSourceBindingContext bindings, List keyPaths, Collection items) {
super(bindings);
this.keyPaths = Collections.unmodifiableList(keyPaths);
this.items = items;
this.keyMapper = initKeyMapper(this.keyPaths, items);
this.filterExpressionFactory = new CollectionFilterExpressionFactory<>();
String sortPath = bindings.getSortPath();
if (sortPath != null && !sortPath.trim().isEmpty()) {
orderExpression = getOrderExpressionFactory().create();
orderExpression.addOrder(new SortOrder(sortPath.trim(), bindings.getSortDirection()));
}
}
private KeyMapper initKeyMapper(List keyPaths, Collection items) {
if (keyPaths.isEmpty()) {
return new GeneratedIdBasedKeyMapper<>(items);
} else {
return new OrmKeyMapper<>(this, getMetadataProvider(), this.keyPaths);
}
}
public final Collection getItems() {
if (children != null) {
Collection children = this.children;
this.children = null;
return children;
} else {
return getRootItems();
}
}
protected Collection getRootItems() {
return this.items;
}
@Override
@SuppressWarnings("unchecked")
protected void handleHierarchicalRequest(DataProviderRequest request) {
if (isHierarchical()) {
Object o = getObjectFromRequest(request);
if (o != null) {
children = (Collection) getBindingContext().provideChildren(o);
} else {
children = null;
}
}
}
@Override
public boolean hasChildren(ClassMetadata element) {
return !getBindingContext().provideChildren(element.getInstance()).isEmpty();
}
@Override
public boolean isHierarchical() {
return getBindingContext().getHierarchyProvider() != null;
}
@Override
public final T findElementByKeyFilter(@Nonnull @NotNull CollectionFilterExpression keyFilter) {
return getItems()
.stream()
.filter(createPredicateIfNecessary(keyFilter))
.findFirst()
.orElse(null);
}
@Override
@SuppressWarnings("unchecked")
public final Class getElementType() {
if (getItems().isEmpty()) {
return (Class) Object.class;
} else {
return (Class) getItems().iterator().next().getClass();
}
}
@Override
public final FilterExpressionFactory> getFilterExpressionFactory() {
return filterExpressionFactory;
}
@Override
public final OrderExpressionFactory getOrderExpressionFactory() {
return CollectionOrderExpression::new;
}
@Override
public final void registerFilter(CollectionFilterExpression expression) {
this.filterExpression = expression;
}
@Override
public final void registerOrder(CollectionOrderExpression expression) {
this.orderExpression = expression;
}
@Override
public final long fetchSize(@Nullable PagingFetchRequest request) {
return getItems().stream().filter(createPredicateIfNecessary(this.filterExpression)).count();
}
@Override
public boolean hasChildren(CollectionFilterExpression request) {
return false;
}
@Override
public final List extends T> fetchData(@Nullable PagingFetchRequest request) {
List extends T> filteredOrderedItems = getFilteredOrderedItems();
if (isSourceOrdered() && isPagingFetchRequestPresent(request)) {
int offset = request.getPage() * request.getPageSize();
int end = offset + request.getPageSize();
if (end > filteredOrderedItems.size()) {
end = filteredOrderedItems.size();
}
return filteredOrderedItems.subList(offset, end);
}
return filteredOrderedItems;
}
private List extends T> getFilteredOrderedItems() {
Comparator comparator = createGenericComparator();
Predicate predicate = createPredicateIfNecessary(this.filterExpression);
Stream extends T> stream = getItems().stream().filter(predicate);
if (comparator != null) {
stream = stream.sorted(comparator);
}
return stream.collect(Collectors.toList());
}
@NotNull
private Predicate createPredicateIfNecessary(CollectionFilterExpression filterExpression) {
if (filterExpression != null) {
return filterExpression.toPredicate();
} else {
return t -> true;
}
}
@Nullable
private Comparator createGenericComparator() {
CollectionOrderExpression orderExpression = this.orderExpression;
if (orderExpression == null) {
return null;
} else {
Comparator retComparator = null;
for (SortOrder order : orderExpression.getOrders()) {
Comparator current = createComparatorBasedOnOrder(order);
if (retComparator == null) {
retComparator = current;
} else {
retComparator = retComparator.thenComparing(current);
}
}
return retComparator;
}
}
private Comparator createComparatorBasedOnOrder(SortOrder sortOrder) {
ClassMetadata classMetadata = ClassMetadata.ofClass(getElementType());
@SuppressWarnings({"unchecked"})
Comparator comparing = Comparator.comparing(item -> {
try {
String path = sortOrder.getPath();
@SuppressWarnings("OptionalGetWithoutIsPresent")
PropertyMetadata> propertyMetadata = classMetadata.withInstance(item).property(path).get();
return propertyMetadata.getInstance() == null ? null : (Comparable) propertyMetadata.getValue();
} catch (Exception e) {
throw new SortPathInvalidException(e);
}
}, Comparator.nullsLast(Comparable::compareTo));
if (SortOrder.Direction.ASCENDING == sortOrder.getDirection()) {
return comparing;
} else {
return comparing.reversed();
}
}
@Override
protected final KeyMapper createKeyMapper() {
return this.keyMapper;
}
@Override
public boolean isSourceOrdered() {
return getItems() instanceof List || orderExpression != null;
}
@Override
public Optional getIndexOfItem(T item) {
if (isSourceOrdered()) {
return Optional.of(getFilteredOrderedItems().indexOf(item));
}
return super.getIndexOfItem(item);
}
@Override
public Optional
© 2015 - 2025 Weber Informatics LLC | Privacy Policy