/* * Copyright © 2017 John Wu * SPDX-License-Identifier: GPL-2.0-or-later */ package com.wireguard.android.util; import java.lang.ref.WeakReference; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; public class Topic { private static final int NON_INIT = 0; private static final int PENDING = 1; private static final int PUBLISHED = 2; private int state = NON_INIT; private List> subscribers; private Object[] results; public Topic() { subscribers = new SyncArrayList<>(); } public synchronized void subscribe(final Subscriber sub) { subscribers.add(new WeakReference<>(sub)); } public synchronized void unsubscribe() { subscribers = new SyncArrayList<>(); } public synchronized void unsubscribe(final Subscriber sub) { List> subs = subscribers; subscribers = new ArrayList<>(); for (final WeakReference subscriber : subs) { if (subscriber.get() != null && subscriber.get() != sub) subscribers.add(subscriber); } } public void reset() { state = NON_INIT; results = null; } public boolean isPublished() { return state == PUBLISHED; } public void publish() { publish(true); } public void publish(boolean record, Object... results) { if (record) state = PUBLISHED; this.results = results; // Snapshot List> subs = subscribers; for (final WeakReference subscriber : subs) { if (subscriber != null && subscriber.get() != null) subscriber.get().onTopicPublished(this); } } public Object[] getResults() { return results; } public boolean isPending() { return state == PENDING; } public void setPending() { state = PENDING; } public interface Subscriber { default void subscribeTopics() { for (final Topic topic : getSubscription()) { if (topic.isPublished()) { onTopicPublished(topic); } topic.subscribe(this); } } default void unsubscribeTopics() { for (final Topic event : getSubscription()) { event.unsubscribe(this); } } void onTopicPublished(Topic topic); Topic[] getSubscription(); } private static class SyncArrayList extends ArrayList { @Override public synchronized boolean add(final E e) { return super.add(e); } } }