I read a ton of literature about the Rx and, on the one hand, everything is clear, but on the other hand nothing is clear. I'm trying to do a simple filtration and storage of data from the server with this library, and it is not working as expected. I need to implement a simple channel list management:
1. Cache on disk and in memory
2. When user requested - return filtered channels
3. All Subscribers that was attached to this Observable must be notified if filtered cahnnels list was changed (call onNext() for all Subscribers)
I wrote the following:
ArrayList<Channel> channels = null;
ArrayList<Channel> filteredChannels = null;
Observable<ArrayList<Channel>> filteredObservable = Observable.create()
// here I need to check if cache is valid, if no - download from server
// then filter channels and return filteredChannels in onNext call
// all subscribers that called subscribe before and not called unsubscribe must be notified if filteredChannels changed
// how to implement this?
.subscribeOn(Schedulers.io());
public void setFilter(Filter filter) {
// update filteredChannels with the new filter and notify all Subscribers (call onNext()). How to implement this?
}
public Observable<ArrayList<Channel>> getFilteredChannels() {
return filteredObservable;
}
Do I correctly understood logic of the Rx pattern or not? Thanks in advance.
I would use .map()'s function to filter your list and then return your desired output. This would mean that your Observable would be emitting the filtered results.
Then you could commit the filtered list to your cache in your .subscribe() functions.
I found the solution for this task: I need to use flatMap and map and I tried to use BehaviourSubject to notify all subscribers for variable change, but this solution is not stable at all, because of error MissingBackpressureException, that's why I wrote next ObsevableValue class:
public class ObservableValue<T> {
private static final String TAG = ObservableValue.class.getSimpleName();
private ArrayList<Registration> subscriptions = new ArrayList<>();
private T value;
private int index;
private boolean firstNotify;
private ReentrantLock lock = new ReentrantLock();
public ObservableValue() {
firstNotify = false;
}
public ObservableValue(T defaultValue) {
value = defaultValue;
firstNotify = true;
}
#SuppressWarnings("unchecked")
public void setValue(T value) {
lock.lock();
this.value = value;
for (Registration listener: subscriptions) {
if (!listener.isFinished()) {
listener.getListener().valueChanged(value);
}
}
lock.unlock();
}
public T getValue() {
lock.lock();
T result = value;
lock.unlock();
return result;
}
public Registration subscribe(ValueChangeListener<T> listener) {
lock.lock();
Registration s = new Registration(this, index, listener);
index++;
subscriptions.add(s);
if (firstNotify||value!=null) {
listener.valueChanged(value);
}
lock.unlock();
return s;
}
protected void finish(int index) {
lock.lock();
for (int i=0;i<subscriptions.size();i++) {
Registration s = subscriptions.get(i);
if (s.getIndex()==index) {
subscriptions.remove(i);
break;
}
}
lock.unlock();
}
}
public abstract class ValueChangeListener<T> {
private Looper looper;
public ValueChangeListener() {}
public ValueChangeListener(Looper looper) {
this.looper = looper;
}
public void valueChanged(T data) {
if (looper!=null) {
Handler handler = new Handler(looper, msg -> {
onValueChanged(data);
return true;
});
handler.sendEmptyMessage(0);
} else {
onValueChanged(data);
}
}
public abstract void onValueChanged(T data);
}
public class Registration {
private ObservableValue observableValue;
private int index;
private ValueChangeListener listener;
private volatile boolean finished = false;
protected Registration(ObservableValue observableValue, int index, ValueChangeListener listener) {
this.observableValue = observableValue;
this.index = index;
this.listener = listener;
}
protected ValueChangeListener getListener() {
return listener;
}
protected int getIndex() {
return index;
}
public boolean isFinished() {
return finished;
}
public void finish() {
finished = true;
observableValue.finish(index);
}
}
Now it is working as expected. Like in Rx ObservableValue returns a Registration object that need to be finished() when it is not needed anymore.
Related
I am trying to create a TumblingWindow on a stream of continuous data and create aggregates within the window. But for some reason, the getResult() does not get called.
public class MyAggregator implements AggregateFunction<Event, MyMetrics, MyMetrics> {
#Override
public MyMetrics createAccumulator() {
return new MyMetrics(0L, 0L);
}
#Override
public MyMetrics add(Event value, MyMetrics accumulator) {
Instant previousValue = ...;
if (previousValue != null) {
Long myWay = ...;
accumulator.setMyWay(myWay);
}
return accumulator;
}
#Override
public MyMetrics getResult(MyMetrics accumulator) {
System.out.println("Inside getResult()");
return accumulator;
}
#Override
public MyMetrics merge(MyMetrics acc1, MyMetrics acc2) {
return new MyMetrics(
acc1.getMyWay() + acc2.getMyWay());
}
}
Note: event.getClientTime() returns an Instant object.
private WatermarkStrategy getWatermarkStrategy() {
return WatermarkStrategy
.<MyEvent>forBoundedOutOfOrderness(Duration.ofMinutes(10))
.withTimestampAssigner(
(event, timestamp) ->
event.getClientTime().toEpochMilli()
);
}
public static void main(String[] args) {
DataStream<MyEvent> watermarkedData = actuals
.assignTimestampsAndWatermarks(
getWatermarkStrategy()
).name("addWatermark");
final OutputTag<MyEvent> lateOutputTag = new OutputTag<MyEvent>("late-data"){};
SingleOutputStreamOperator<OutputModel> output_data = watermarkedData
.keyBy("input_key")
.window(TumblingEventTimeWindows.of(Time.hours(1)))
.sideOutputLateData(lateOutputTag)
.aggregate(
new MyAggregator(),
).name("AggregationRollUp");
output_data.addSink(new PrintSinkFunction<>());
}
Any pointers as to what I am missing here would be helpful.
First check the timing of the data to see if it meets the window trigger conditions
Second may be you can do a test by reducing the window size from 1h to 1min and reducing the watermark region from 10min to 30s
I want when ever we add element in queue , I should call a method to fetch as soon as element added in queue.
package com.java.listner;
import java.util.LinkedList;
import java.util.Queue;
public class QueueListner {
public static Queue<String> queue=new LinkedList<String>();
public boolean add(String e) {
itemAvailableInqueue();
return false;
}
public static void main(String[] args) {
queue.add("record1");
System.out.println(queue.poll());
}
public void itemAvailableInqueue() {
int size = queue.size();
for (int i = 1; i < size; i++) {
System.out.println(queue.poll());
}
}
}
To add a listener to a queue, you need to make it "listenable", the simplest way to do this is Decorator pattern. This pattern targets adding features in a class while keeping its base functionality.
In case of Queue, you just extend a AbstractQueue class, overriding its offer method. Other methods just delegate to a backing queue, since they don't need to notify listeners.
public class ListenableQueue<E> extends AbstractQueue<E> {
interface Listener<E> {
void onElementAdded(E element);
}
private final Queue<E> delegate; // backing queue
private final List<Listener<E>> listeners = new ArrayList<>();
public ListenableQueue(Queue<E> delegate) {
this.delegate = delegate;
}
public ListenableQueue<E> registerListener(Listener<E> listener) {
listeners.add(listener);
return this;
}
#Override
public boolean offer(E e) {
// here, we put an element in the backing queue,
// then notify listeners
if (delegate.offer(e)) {
listeners.forEach(listener -> listener.onElementAdded(e));
return true;
} else {
return false;
}
}
// following methods just delegate to backing instance
#Override public E poll() { return delegate.poll(); }
#Override public E peek() { return delegate.peek(); }
#Override public int size() { return delegate.size(); }
#Override public Iterator<E> iterator() { return delegate.iterator(); }
}
This ListenableQueue implements Queue interface thus has all Queue functionality considering properties of backing delegate queue (i.e. capacity constraints, blocking behavior, etc), so can be used like any other Queue.
Usage example:
// we create new `LinkedList` as a backing queue and decorate it
ListenableQueue<String> q = new ListenableQueue<>(new LinkedList<>());
// register a listener which polls a queue and prints an element
q.registerListener(e -> System.out.println(q.poll()));
// voila!
q.add("record1");
I have access to an ObservableList<T> that is updated(elements added, removed) from non-JavaFX thread, which I display in ListView<T>.
If the list is simply displayed in UI it throws java.lang.IllegalStateException: Not on FX application thread; so my solution was to create second list in UI thread and listen to changes and update the second list in UI thread:
ObservableList<Person> secondList = FXCollections.observableArrayList();
secondList.addAll(originalList);
originalList.addListener((ListChangeListener<? super Person>)change-> {
while(change.next()) {
if (change.wasRemoved()) {
Platform.runLater(() -> secondList.subList(change.getFrom(), change.getFrom() + change.getRemovedSize()).clear());
}
if (change.wasAdded()) {
Platform.runLater(() -> secondList.addAll(change.getFrom(), change.getAddedSubList()));
}
}
});
ListView<Person> listViewPerson = new ListView<>(secondList);
This I believe should work fine(if it has any problems, please point them out, I'm ignoring permutation for question's simplicity).
However, the problem arises when the list has an extractor:
ObservableList<Person> secondList = FXCollections.observableArrayList(person -> new Observable[]{person.adultProperty()});
The change to adult property happens on non-javafx thread and obviously that will either throw the same exception or will result in some undefined UI behavior.
I've thought of 2 solutions for this problem:
1) creating UI equivalent classes of original classes and update its' properties in UI thread:
public PersonUI(Person person) {
adult = new SimpleBooleanProperty(person.isAdult());
person.adultProperty().addListener((observableValue, oldValue, newValue) -> {
Platform.runLater(() -> this.adult.set(newValue));
});
}
and in UI display PersonUI instead of Person.
Don't think it's necessary, but here's full code of this solution: https://pastebin.com/FYXrre6U
2) Pollute back-end code with Platform.runLater()
Are there any other solutions? If there are any problems with my current solutions please point them out.
Option 3: implement a transformationList that propagates all changes onto the fx-thread. It's a bit of work front-up, but can be re-used.
An outline (not formally tested and incomplete!)
/**
* A 1:1 transform of the sourceList that guarantees to fire change notification
* on the fx-thread.
*
* #author Jeanette Winzenburg, Berlin
*/
public class FXThreadTransformationList<E> extends TransformationList<E, E> {
public FXThreadTransformationList(ObservableList<E> source) {
super(source);
}
#Override
protected void sourceChanged(Change<? extends E> c) {
beginChange();
while (c.next()) {
if (c.wasPermutated()) {
// tbd
} else if (c.wasUpdated()) {
update(c);
} else if (c.wasReplaced()) {
// tbd
} else {
addedOrRemoved(c);
}
}
// commit on fx-thread
endChangeOnFXThread();
}
public void endChangeOnFXThread() {
Platform.runLater(() -> endChange());
}
private void addedOrRemoved(Change<? extends E> c) {
if (c.wasRemoved()) {
nextRemove(c.getFrom(), c.getRemoved());
} else if (c.wasAdded()) {
nextAdd(c.getFrom(), c.getTo());
} else {
throw new IllegalStateException("expected either removed or added, but was:" + c);
}
}
private void update(Change<? extends E> c) {
for (int pos = c.getFrom(); pos < c.getTo(); pos++) {
nextUpdate(pos);
}
}
#Override
public int getViewIndex(int index) {
return index;
}
#Override
public int getSourceIndex(int index) {
return index;
}
#Override
public E get(int index) {
return getSource().get(index);
}
#Override
public int size() {
return getSource().size();
}
#SuppressWarnings("unused")
private static final Logger LOG = Logger
.getLogger(FXThreadTransformationList.class.getName());
}
I have a code which goes like this
List insert;
List update;
List delete
for(SomeObject someObj : someObjects){
if(isNew){
insert.add()
}
else if(isUpdate){
update.add();
}
if(isDelete){
delete.add()
}
}
//call update insert delete functions
The problem is this code is untestable because the update insert delete are all void methods.
My question is , should I consider iterating over the loop three times and then get the lists to test if the logic to filter each type of results is working? The cost is not that much since I am expecting <100 elements in the list.
You can check
(sum of lists sizes after) == (sum of lists sizes before) + someObjects.size();
The key here is to be able to control the dependencies and access the state that this method acts upon.
Here is an example that illustrates that:
interface SomeDao {
void add(SomeObject object);
void update(SomeObject object);
void delete(SomeObject object);
}
class SomeDaoStub implements SomeDao {
#Override public void add(SomeObject object) {}
#Override public void update(SomeObject object) {}
#Override public void delete(SomeObject object) {}
}
class SomeObject {
private final boolean isNew;
private final boolean isUpdated;
private final boolean isDeleted;
SomeObject(boolean isNew, boolean isUpdated, boolean isDeleted) {
this.isNew = isNew;
this.isUpdated = isUpdated;
this.isDeleted = isDeleted;
}
public boolean isNew() {
return isNew;
}
public boolean isUpdated() {
return isUpdated;
}
public boolean isDeleted() {
return isDeleted;
}
}
public void doSomethingComplicatedWithListsInAForLoop(Iterable<SomeObject> someObjects, SomeDao dao) {
for (SomeObject someObject : someObjects) {
if (someObject.isNew()) {
dao.add(someObject);
} else if (someObject.isUpdated()) {
dao.update(someObject);
} else if (someObject.isDeleted()) {
dao.delete(someObject);
}
}
}
#Test
public void itDeletesObjectsMarkedToBeDeleted() {
final List<SomeObject> actualDeletedObjects = new ArrayList<>();
List<SomeObject> expectedDeletedObjects = Arrays.asList(
new SomeObject(false, false, true),
new SomeObject(false, false, true),
new SomeObject(false, false, true)
);
SomeDao theDao = new SomeDaoStub() {
#Override
public void delete(SomeObject object) {
actualDeletedObjects.add(object);
}
};
doSomethingComplicatedWithListsInAForLoop(expectedDeletedObjects, theDao);
assertEquals(expectedDeletedObjects, actualDeletedObjects);
}
The only reason that I can figure out what doSomethingComplicatedWithListsInAForLoop manipulated is because I can control its dependencies, namely, in this example, SomeDao.
It is likely that you are finding difficulty testing your method because it makes calls to state which you cannot inject.
package design.pattern.behavioral;
import design.pattern.behavioral.ChainOfResponsibility.*;
public class ChainOfResponsibility {
public static class Chain {
private Request[] requests = null;
private Handler[] handlers = null;
public Chain(Handler[] handlers, Request[] requests){
this.handlers = handlers;
this.requests = requests;
}
public void start() {
for(Request r : requests)
for (Handler h : handlers)
if(h.handle(r)) break;
}
}
public static class Request {
private int value;
public Request setValue(int value){
this.value = value;
return this;
}
public int getValue() {
return value;
}
}
public static class Handler<T> {
private Command<T> command = null;
public Handler(Command<T> command) {
this.command = command;
}
public boolean handle(T request) {
return command.execute(request);
}
}
public static abstract class Command<T>{
public abstract Boolean execute(T request);
}
}
class TestChainOfResponsibility {
public static void main(String[] args) {
new TestChainOfResponsibility().test();
}
private void test() {
new Chain(new Handler[]{ // chain of responsibility
new Handler<Request>(
new Command<Request>(){ // command
public Boolean execute(Request condition) {
boolean result = condition.getValue() >= 600;
if (result) System.out.println("You are rich: " + condition.getValue() + " (id: " + condition.hashCode() + ")");
return result;
}
}
),
new Handler<Request>(
new Command<Request>(){
public Boolean execute(Request condition) {
boolean result = condition.getValue() >= 100;
if(result) System.out.println("You are poor: " + condition.getValue() + " (id: " + condition.hashCode() + ")");
return result;
}
}
),
},
new Request[]{
new Request().setValue(600), // chaining method
new Request().setValue(100),
}
).start();
}
}
I don't think there is a meaningful answer to such a general question. Design patterns don't exist in isolation and don't have a "perfect form": they live in a context.
A pattern is a solution to a problem in a context.
So without knowing the context of your solution, there is not much we can say about it. What is the concrete problem you are trying to resolve with it? What forces are in play? What are your constraints? Do you have any problems / issues with the current solution? If you give more details about these, maybe we can give a better answer.
Lambda isn't very descriptive (to most developers). Is it something you are pulling in from functional language theory?
I'd probably just get rid of the 'controlling' class, and wire the individual handlers up to each other directly - use more of an IoC approach, basically.
Example (in C#, forgive me) per request...
public interface IIntMessage
{
void HandleMesasge(int i);
}
public class EvenPrinter : IIntMessage
{
private IIntMessage m_next;
public EvenPrinter(IIntMessage next)
{
m_next = next;
}
public void HandleMesasge(int i)
{
if(i % 2 == 0)
{
System.Console.WriteLine("Even!");
}
else
{
m_next.HandleMesasge(i);
}
}
}
public class OddPrinter : IIntMessage
{
private IIntMessage m_next;
public OddPrinter(IIntMessage next)
{
m_next = next;
}
public void HandleMesasge(int i)
{
if(i%2 == 1)
{
System.Console.WriteLine("Odd!");
}
else
{
m_next.HandleMesasge(i);
}
}
}
Note that we get rid of the "controlling" class altogether, and simply allow the request handlers to directly chain to each other, without having to go through an intermediary.
Also, I could probably extract out a 'base' chain-of-command request handler, removing some of the duplicate code.