Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Transactional DataCommunicator and Grid for Flow
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;
import com.vaadin.data.provider.AbstractBackEndDataProvider;
import com.vaadin.data.provider.Query;
public class StreamDataProvider<T> extends AbstractBackEndDataProvider<T, Predicate<T>> {
private final Supplier<Stream<T>> streamSupplier;
public StreamDataProvider(Supplier<Stream<T>> streamSupplier) {
this.streamSupplier = streamSupplier;
}
@Override
protected Stream<T> fetchFromBackEnd(Query<T, Predicate<T>> query) {
Stream<T> stream = this.streamSupplier.get();
if (query.getFilter().isPresent()) {
stream = stream.filter(query.getFilter().get());
}
return stream.skip(query.getOffset()).limit(query.getLimit());
}
@Override
protected int sizeInBackEnd(Query<T, Predicate<T>> query) {
Stream<T> stream = this.streamSupplier.get();
if (query.getFilter().isPresent()) {
stream = stream.filter(query.getFilter().get());
}
long count = stream.skip(query.getOffset()).limit(query.getLimit()).count();
return Math.toIntExact(count);
}
}
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.support.TransactionTemplate;
import com.vaadin.data.provider.ArrayUpdater;
import com.vaadin.data.provider.DataCommunicator;
import com.vaadin.data.provider.DataGenerator;
import com.vaadin.flow.StateNode;
import com.vaadin.function.SerializableConsumer;
import elemental.json.JsonArray;
public class TransactionalDataCommunicator<T> extends DataCommunicator<T> {
private final TransactionTemplate transactionTemplate;
public TransactionalDataCommunicator(PlatformTransactionManager transactionManager, DataGenerator<T> dataGenerator,
ArrayUpdater arrayUpdater, SerializableConsumer<JsonArray> dataUpdater, StateNode stateNode) {
super(dataGenerator, arrayUpdater, dataUpdater, stateNode);
this.transactionTemplate = new TransactionTemplate(transactionManager);
this.transactionTemplate.setReadOnly(true);
}
@Override
protected Stream<T> fetchFromProvider(int offset, int limit) {
// Collecting the stream here since DataCommunicator::activate is
// private, therefore it cannot be made transacitonal
return this.transactionTemplate
.execute(status -> super.fetchFromProvider(offset, limit).collect(Collectors.toList()).stream());
}
@Override
protected int getDataProviderSize() {
return this.transactionTemplate.execute(status -> super.getDataProviderSize());
}
}
import java.lang.reflect.Field;
import java.util.Optional;
import org.springframework.transaction.PlatformTransactionManager;
import com.vaadin.data.provider.ArrayUpdater;
import com.vaadin.data.provider.DataCommunicator;
import com.vaadin.data.provider.DataGenerator;
import com.vaadin.ui.grid.Grid;
public class TransactionalGrid<T> extends Grid<T> {
private final DataCommunicator<T> transactionalDataCommunicator;
public TransactionalGrid(PlatformTransactionManager transactionManager) {
this.transactionalDataCommunicator = this.createDataCommunicator(transactionManager);
this.transactionalDataCommunicator.setRequestedRange(0, this.getPageSize());
}
@Override
public DataCommunicator<T> getDataCommunicator() {
// Needed because getDataCommunicator() is called by the super
// constructor, therefore at that moment the transactional one isn't
// built yet
return Optional.ofNullable(this.transactionalDataCommunicator).orElseGet(super::getDataCommunicator);
}
@SuppressWarnings("unchecked")
private DataCommunicator<T> createDataCommunicator(PlatformTransactionManager transactionManager) {
try {
Field dataGeneratorField = Grid.class.getDeclaredField("gridDataGenerator");
Field arrayUpdaterfield = Grid.class.getDeclaredField("arrayUpdater");
dataGeneratorField.setAccessible(true);
arrayUpdaterfield.setAccessible(true);
DataGenerator<T> dataGenerator = (DataGenerator<T>) dataGeneratorField.get(this);
ArrayUpdater arrayUpdater = (ArrayUpdater) arrayUpdaterfield.get(this);
return new TransactionalDataCommunicator<>(transactionManager, dataGenerator, arrayUpdater,
data -> this.getElement().callFunction("$connector.updateData", data), this.getElement().getNode());
} catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment