![JAR search and dependency download from the Maven repository](/logo.png)
io.datafx.provider.ListDataProvider Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of datasources Show documentation
Show all versions of datasources Show documentation
Visualizing Enterprise Data in JavaFX
/**
* Copyright (c) 2011, 2014, Jonathan Giles, Johan Vos, Hendrik Ebbers
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of DataFX, the website javafxdata.org, nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL DATAFX BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package io.datafx.provider;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.property.ListProperty;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleListProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.concurrent.Worker;
import javafx.concurrent.WorkerStateEvent;
import javafx.event.EventHandler;
import io.datafx.core.concurrent.ConcurrentUtils;
import io.datafx.core.concurrent.PublishingTask;
import io.datafx.io.DataReader;
import io.datafx.io.WritableDataReader;
import io.datafx.io.WriteBackHandler;
import io.datafx.io.WriteBackListProvider;
import io.datafx.io.WriteBackProvider;
import io.datafx.io.WriteTransient;
import java.lang.reflect.Field;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.Executor;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* The ListDataProvider is an implementation of {@link DataProvider} that allows
* the retrieval and parsing of a list of data entities.
* In case a single entity is expected to be retrieved, an {@link ObjectDataProvider}
* should be used. Instances of this class are typically used to populate ObservableList
* instances.
*
* This class requires a {@link io.datafx.io.DataReader} that either can be passed
* with the constructor or using the {@link #setDataReader(io.datafx.io.DataReader) }
* method.
*
* No external data will be retrieved until the {@link #retrieve()} method is called.
*
* Developers that prefer the builder approach can choose to use the
* {@link ListDataProviderBuilder} class to create an
* instance of ListDataProvider.
*
Example:
*
* JsonConverter jsonConverter = new JsonConverter("data", MyEntity.class);
* RestSourceBuilder restSourceBuilder = createRestSourceBuilder()
* .converter(jsonConverter)
* .path("part1").path("part2")
* RestSource restSource = restSourceBuilder.build();
* ListDataProvider<MyEntity> lodp = new ListDataProvider(restSource);
* lodp.setResultObservableList(model.allMyEntities());
*
*
* @param the type of data this ListDataProvider will deliver
*/
public class ListDataProvider implements DataProvider>,
WriteBackProvider, WriteBackListProvider {
private ListProperty listWrapper = new SimpleListProperty<>();
private ObservableList observableList;
private DataReader reader;
private Executor executor;
private WriteBackHandler writeBackHandler;
private WriteBackHandler entryAddedHandler;
public ListDataProvider() {
this (null, null, null);
}
public ListDataProvider(DataReader reader) {
this(reader, null, null);
}
/**
* Create a ListDataProvider with a given Executor and an existing
* ListProperty
*
* @param reader the DataReader that will obtain the real data
* @param executor an Executor that will make the (asynchronous) call.
* @param existingList the ListProperty that will be populated with the
* retrieved data. Note that in the past, we had to use a ListProperty
* rather than an ObservableList since we override the getData() method,
* which should return ObservableValue<T>
*/
public ListDataProvider(DataReader reader, Executor executor, ObservableList existingList) {
this.reader = reader;
this.executor = executor;
if (existingList != null) {
this.observableList = existingList;
} else {
this.observableList = FXCollections.observableArrayList();// = new SimpleListProperty(FXCollections.observableArrayList());
}
this.listWrapper.setValue(observableList);
}
/**
* This is a convenience method, allowing ObservableList instances (no
* ListProperties) to be synchronized with the result of the
* ListDataProvider.
*
* @param ol The ObservableList instance that should be synchronized with
* the data retrieved by this ListDataProvider. Note that this
* ObservableList will be cleared when calling this method -- as there is no
* data retrieved yet.
*/
public void setResultObservableList(final ObservableList ol) {
this.observableList = ol;
this.listWrapper.setValue(this.observableList);
}
public void setDataReader(DataReader reader) {
this.reader = reader;
}
public DataReader getDataReader() {
return reader;
}
@Override
public Worker> retrieve() {
final Service> retriever = createService(observableList);
return ConcurrentUtils.executeService(executor, retriever);
}
// private static Map addListeners = new HashMap();
final static Map addListeners = new HashMap();
final static List myListeners2 = new LinkedList();
protected Service> createService(final ObservableList value) {
return new Service>() {
@Override
protected Task> createTask() {
// We don't want to call writeback handlers while retrieving external data
ListChangeListener existingListener = null;
if (entryAddedHandler != null) {
synchronized (addListeners) {
Set> entrySet = addListeners.entrySet();
for (Entry entry : entrySet) {
if (entry.getKey().equals(value)) {
existingListener = entry.getValue();
}
}
if (existingListener != null) {
value.removeListener(existingListener);
}
}
}
final Task> task = createReceiverTask(value);
final ListChangeListener myListener = existingListener;
task.setOnSucceeded(new EventHandler() {
@Override
public void handle(WorkerStateEvent arg0) {
if (entryAddedHandler != null) {
if (myListener != null) {
value.addListener(myListener);
} else {
ListChangeListener localListener =
new ListChangeListener() {
@Override
public void onChanged(final ListChangeListener.Change extends T> change) {
while (change.next()) {
Service service = new Service() {
@Override
protected Task createTask() {
Task task = new Task() {
@Override
protected Object call() throws Exception {
List extends T> addedSubList = change.getAddedSubList();
for (T entry : addedSubList) {
WritableDataReader dataReader = entryAddedHandler.createDataSource(entry);
dataReader.writeBack();
}
return addedSubList;
}
};
return task;
}
};
if (executor != null) {
service.setExecutor(executor);
}
service.start();
}
}
};
synchronized (addListeners) {
addListeners.put(value, localListener);
value.addListener(localListener);
}
}
// );
}
}
});
return task;
}
};
}
protected PublishingTask createPublishingReceiverTask(ObservableList myResult) {
PublishingTask answer = new PublishingTask(myResult) {
@Override
protected void callTask() throws Exception {
while (getDataReader().next()) {
final T entry = getDataReader().get();
publish(entry);
if (writeBackHandler != null) {
checkProperties(entry);
}
}
}
};
return answer;
}
protected final Task> createReceiverTask(ObservableList myResult) {
PublishingTask task = createPublishingReceiverTask(myResult);
return task;
}
public Executor getExecutor() {
return executor;
}
/**
* returns the data obtained by this provider. This method has to return an
* ObservableValue, so it wraps the resulting ObservableList into a
* ListProperty
*
* @return the ListProperty containing the data.
*/
@Override
public ListProperty getData() {
return (ListProperty) listWrapper;
}
@Override
public void setAddEntryHandler(WriteBackHandler handler) {
this.entryAddedHandler = handler;
}
@Override
public void setWriteBackHandler(WriteBackHandler handler) {
this.writeBackHandler = handler;
}
private void checkProperties(final T target) {
Class c = target.getClass();
Field[] fields = c.getDeclaredFields();
for (final Field field : fields) {
Class clazz = field.getType();
// Only Observable fields without a WriteTransient annotation are considered
if ((Observable.class.isAssignableFrom(clazz)) && (field.getAnnotation(WriteTransient.class) == null)) {
try {
final Observable observable = AccessController.doPrivileged(new PrivilegedAction() {
@Override
public Observable run() {
try {
field.setAccessible(true);
Object f = field.get(target);
Observable answer = (Observable) f;
return answer;
} catch (IllegalArgumentException ex) {
Logger.getLogger(ObjectDataProvider.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(ObjectDataProvider.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
});
if (observable != null) {
observable.addListener(new InvalidationListener() {
@Override
public void invalidated(final Observable o) {
Service service = new Service() {
@Override
protected Task createTask() {
Task task = new Task() {
@Override
protected Object call() throws Exception {
WritableDataReader reader = writeBackHandler.createDataSource(target);
reader.writeBack();
return o;
}
};
return task;
}
};
if (executor != null) {
service.setExecutor(executor);
}
service.start();
}
});
}
} catch (IllegalArgumentException ex) {
Logger.getLogger(ObjectDataProvider.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
@Override
public void setResultProperty(Property> result) {
this.listWrapper = (ListProperty) result;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy