Initial commit
This commit is contained in:
commit
956a509418
|
@ -0,0 +1 @@
|
|||
out/
|
|
@ -0,0 +1,3 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="11" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/src/main/main.iml" filepath="$PROJECT_DIR$/src/main/main.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/src/test/test.iml" filepath="$PROJECT_DIR$/src/test/test.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
|
@ -0,0 +1,124 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Palette2">
|
||||
<group name="Swing">
|
||||
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
|
||||
</item>
|
||||
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
|
||||
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
|
||||
<initial-values>
|
||||
<property name="text" value="Button" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="RadioButton" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="CheckBox" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="Label" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
|
||||
<preferred-size width="-1" height="20" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
|
||||
</item>
|
||||
</group>
|
||||
</component>
|
||||
</project>
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
|
@ -0,0 +1,178 @@
|
|||
package org.syndicate_lang.actors;
|
||||
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* I represent the shared execution concepts for a collection of objects; I am roughly analogous to the E concept of a Vat.
|
||||
*/
|
||||
public class Actor implements Executor {
|
||||
private final static ThreadLocal<Actor> _currentActor = new ThreadLocal<>();
|
||||
private final static AtomicLong _count = new AtomicLong(0);
|
||||
protected final static ScheduledExecutorService _executor = Executors.newScheduledThreadPool(4);
|
||||
|
||||
private final String _name;
|
||||
private final Logger _logger;
|
||||
|
||||
private boolean _alive = true;
|
||||
private Throwable _exitReason = null;
|
||||
private boolean _isCounted = true;
|
||||
|
||||
public static Actor current() {
|
||||
return _currentActor.get();
|
||||
}
|
||||
|
||||
public static Logger log() {
|
||||
return current().getLogger();
|
||||
}
|
||||
|
||||
public static<T> Remote<T> ref(T o) {
|
||||
return current().proxyFor(o);
|
||||
}
|
||||
|
||||
public Actor() {
|
||||
this("" + System.currentTimeMillis());
|
||||
}
|
||||
|
||||
public Actor(String debugName) {
|
||||
this._name = debugName;
|
||||
this._logger = Logger.getLogger(Actor.class.getCanonicalName() + "(" + this._name + ")");
|
||||
_count.incrementAndGet();
|
||||
}
|
||||
|
||||
public static<T> Remote<T> forObject(T o) {
|
||||
return new Actor().proxyFor(o);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return _name;
|
||||
}
|
||||
|
||||
public Throwable getExitReason() {
|
||||
return _exitReason;
|
||||
}
|
||||
|
||||
public Logger getLogger() {
|
||||
return _logger;
|
||||
}
|
||||
|
||||
public synchronized boolean isDaemon() {
|
||||
return _alive && !_isCounted;
|
||||
}
|
||||
|
||||
public synchronized Actor daemonize() {
|
||||
this._releaseCount();
|
||||
return this;
|
||||
}
|
||||
|
||||
private void _releaseCount() {
|
||||
if (_isCounted) {
|
||||
_isCounted = false;
|
||||
synchronized (_count) {
|
||||
if (_count.decrementAndGet() == 0) {
|
||||
_count.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return super.toString() + "(" + this._name + ")";
|
||||
}
|
||||
|
||||
public<T> Remote<T> proxyFor(T o) {
|
||||
return new Remote<T>(this, o);
|
||||
}
|
||||
|
||||
private void _perform(Runnable work, Runnable ifNotAlive) {
|
||||
synchronized (this) {
|
||||
_currentActor.set(this);
|
||||
try {
|
||||
if (!_alive) {
|
||||
if (ifNotAlive != null) ifNotAlive.run();
|
||||
} else {
|
||||
try {
|
||||
work.run();
|
||||
} catch (Throwable exn) {
|
||||
this._stop(false, exn);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
_currentActor.set(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Promise<?> stop() {
|
||||
return stop(null);
|
||||
}
|
||||
|
||||
public Promise<?> stop(Throwable reason) {
|
||||
if (current() == this) {
|
||||
this._stop(true, reason);
|
||||
return Promise.resolved();
|
||||
} else {
|
||||
Promise<?> p = new Promise<>();
|
||||
this.execute(() -> {
|
||||
this._stop(true, reason);
|
||||
p.resolve();
|
||||
}, p::resolve);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void _stop(boolean normally, Throwable reason) {
|
||||
if (_alive) {
|
||||
_alive = false;
|
||||
_exitReason = reason;
|
||||
if (normally) {
|
||||
getLogger().log(Level.INFO, "Actor stopped", reason);
|
||||
} else {
|
||||
getLogger().log(Level.SEVERE, "Actor terminated with error", reason);
|
||||
}
|
||||
_releaseCount();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Runnable work) {
|
||||
this.execute(work, null);
|
||||
}
|
||||
|
||||
public void execute(Runnable work, Runnable ifNotAlive) {
|
||||
this.later(0, work, ifNotAlive);
|
||||
}
|
||||
|
||||
public void later(long delayMilliseconds, Runnable work) {
|
||||
this.later(delayMilliseconds, work, null);
|
||||
}
|
||||
|
||||
public void later(long delayMilliseconds, Runnable work, Runnable ifNotAlive) {
|
||||
_executor.schedule(() -> this._perform(work, ifNotAlive), delayMilliseconds, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public PeriodicTimer every(long periodMilliseconds, Runnable f) {
|
||||
return every(0, periodMilliseconds, f);
|
||||
}
|
||||
|
||||
public PeriodicTimer every(long initialDelayMilliseconds, long periodMilliseconds, Runnable f) {
|
||||
return new PeriodicTimer(
|
||||
_executor.scheduleAtFixedRate(
|
||||
() -> this._perform(f, null),
|
||||
initialDelayMilliseconds,
|
||||
periodMilliseconds,
|
||||
TimeUnit.MILLISECONDS));
|
||||
}
|
||||
|
||||
public static boolean awaitAll() throws InterruptedException {
|
||||
while (_count.get() > 0) {
|
||||
synchronized (_count) {
|
||||
_count.wait(1000);
|
||||
}
|
||||
}
|
||||
_executor.shutdown();
|
||||
return _executor.awaitTermination(5, TimeUnit.MINUTES);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.syndicate_lang.actors;
|
||||
|
||||
public class ActorTerminated extends Exception {
|
||||
private Actor _actor;
|
||||
|
||||
public ActorTerminated(Actor actor) {
|
||||
super("Actor terminated: " + actor, actor.getExitReason());
|
||||
this._actor = actor;
|
||||
}
|
||||
|
||||
public Actor getActor() {
|
||||
return _actor;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package org.syndicate_lang.actors;
|
||||
|
||||
public class BrokenPromise extends RuntimeException {
|
||||
private Promise<?> _promise;
|
||||
|
||||
public BrokenPromise(Promise<?> promise) {
|
||||
super(promise.getReason());
|
||||
this._promise = promise;
|
||||
}
|
||||
|
||||
public Promise<?> getPromise() {
|
||||
return _promise;
|
||||
}
|
||||
|
||||
public Throwable getReason() {
|
||||
return _promise.getReason();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package org.syndicate_lang.actors;
|
||||
|
||||
public class InternalError extends RuntimeException {
|
||||
public InternalError(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package org.syndicate_lang.actors;
|
||||
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
|
||||
public class PeriodicTimer {
|
||||
private ScheduledFuture<?> _future;
|
||||
|
||||
protected PeriodicTimer(ScheduledFuture<?> future) {
|
||||
this._future = future;
|
||||
}
|
||||
|
||||
public boolean isCancelled() {
|
||||
return _future.isCancelled();
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
_future.cancel(false);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,240 @@
|
|||
package org.syndicate_lang.actors;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class Promise<T> implements Future<T> {
|
||||
public static enum State {
|
||||
PENDING,
|
||||
FULFILLED,
|
||||
REJECTED
|
||||
};
|
||||
|
||||
private volatile State _state = State.PENDING;
|
||||
private T _value = null;
|
||||
private Throwable _reason = null;
|
||||
private List<Consumer<T>> _resolvers = null;
|
||||
private List<Consumer<Throwable>> _rejecters = null;
|
||||
|
||||
public Promise() {}
|
||||
|
||||
public static<T> Promise<T> resolved() {
|
||||
return resolved(null);
|
||||
}
|
||||
|
||||
public static<T> Promise<T> resolved(T v) {
|
||||
var p = new Promise<T>();
|
||||
p.resolveWith(v);
|
||||
return p;
|
||||
}
|
||||
|
||||
public static<T> Promise<T> rejected(Throwable e) {
|
||||
var p = new Promise<T>();
|
||||
p.rejectWith(e);
|
||||
return p;
|
||||
}
|
||||
|
||||
public State getState() {
|
||||
return _state;
|
||||
}
|
||||
|
||||
public boolean isPending() {
|
||||
return _state == State.PENDING;
|
||||
}
|
||||
|
||||
public boolean isFulfilled() {
|
||||
return _state == State.FULFILLED;
|
||||
}
|
||||
|
||||
public boolean isRejected() {
|
||||
return _state == State.REJECTED;
|
||||
}
|
||||
|
||||
public T getValue() {
|
||||
return _value;
|
||||
}
|
||||
|
||||
public Throwable getReason() {
|
||||
return _reason;
|
||||
}
|
||||
|
||||
public void resolve() {
|
||||
this.resolveWith(null);
|
||||
}
|
||||
|
||||
public synchronized void resolveWith(T t) {
|
||||
if (this.isPending()) {
|
||||
this._value = t;
|
||||
this._state = State.FULFILLED;
|
||||
var worklist = _resolvers;
|
||||
_resolvers = null;
|
||||
_rejecters = null;
|
||||
if (worklist != null) {
|
||||
for (var callback : worklist) {
|
||||
callback.accept(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void chain(Promise<T> t) {
|
||||
if (this == t) {
|
||||
throw new IllegalArgumentException("cannot chain promise immediately to itself");
|
||||
}
|
||||
t.whenFulfilled((v) -> this.resolveWith(v));
|
||||
t.whenRejected((e) -> this.rejectWith(e));
|
||||
}
|
||||
|
||||
public void rejectWith(Throwable e) {
|
||||
if (this.isPending()) {
|
||||
this._reason = e;
|
||||
this._state = State.REJECTED;
|
||||
var worklist = _rejecters;
|
||||
_resolvers = null;
|
||||
_rejecters = null;
|
||||
if (worklist != null) {
|
||||
for (var callback : worklist) {
|
||||
callback.accept(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public<R> Promise<R> andThen(Function<T, R> ok) {
|
||||
return this.andThen(ok, null);
|
||||
}
|
||||
|
||||
public synchronized<R> Promise<R> andThen(final Function<T, R> ok, final Function<Throwable, R> fail) {
|
||||
Actor a0 = Actor.current();
|
||||
final Actor a = a0 != null ? a0 : new Actor();
|
||||
|
||||
Promise<R> p = new Promise<>();
|
||||
this.whenFulfilled((t) -> a.execute(() -> {
|
||||
try {
|
||||
p.resolveWith(ok.apply(t));
|
||||
} catch (Throwable e) {
|
||||
p.rejectWith(e);
|
||||
}
|
||||
}, () -> p.rejectWith(new ActorTerminated(a))));
|
||||
this.whenRejected((e) -> a.execute(() -> {
|
||||
try {
|
||||
if (fail == null) {
|
||||
p.rejectWith(e);
|
||||
} else {
|
||||
p.resolveWith(fail.apply(e));
|
||||
}
|
||||
} catch (Throwable e2) {
|
||||
p.rejectWith(e2);
|
||||
}
|
||||
}, () -> p.rejectWith(new ActorTerminated(a))));
|
||||
return p;
|
||||
}
|
||||
|
||||
private static<T> T unexpectedTimeout(TimeoutException e) {
|
||||
throw new InternalError("await() without delay signalled TimeoutException", e);
|
||||
}
|
||||
|
||||
public T await() {
|
||||
try {
|
||||
return this.await(-1);
|
||||
} catch (TimeoutException e) {
|
||||
return unexpectedTimeout(e);
|
||||
}
|
||||
}
|
||||
|
||||
public T await(long delayMilliseconds) throws TimeoutException {
|
||||
try {
|
||||
return _await(delayMilliseconds, TimeUnit.MILLISECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
this.rejectWith(e);
|
||||
throw new BrokenPromise(this);
|
||||
}
|
||||
}
|
||||
|
||||
public T _await(long delay, TimeUnit unit) throws TimeoutException, InterruptedException {
|
||||
Semaphore s = new Semaphore(0);
|
||||
this.whenFulfilled((_t) -> s.release());
|
||||
this.whenRejected((_e) -> s.release());
|
||||
if (delay == -1) {
|
||||
s.acquire();
|
||||
} else {
|
||||
if (!s.tryAcquire(delay, unit)) {
|
||||
throw new TimeoutException();
|
||||
}
|
||||
}
|
||||
if (this.isFulfilled()) {
|
||||
return this._value;
|
||||
} else {
|
||||
throw new BrokenPromise(this);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void whenFulfilled(Consumer<T> callback) {
|
||||
switch (this._state) {
|
||||
case PENDING:
|
||||
if (_resolvers == null) _resolvers = new ArrayList<>();
|
||||
_resolvers.add(callback);
|
||||
break;
|
||||
case FULFILLED:
|
||||
callback.accept(this._value);
|
||||
break;
|
||||
case REJECTED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void whenRejected(Consumer<Throwable> callback) {
|
||||
switch (this._state) {
|
||||
case PENDING:
|
||||
if (_rejecters == null) _rejecters = new ArrayList<>();
|
||||
_rejecters.add(callback);
|
||||
break;
|
||||
case FULFILLED:
|
||||
break;
|
||||
case REJECTED:
|
||||
callback.accept(this._reason);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation of Future<T>
|
||||
|
||||
@Override
|
||||
public boolean cancel(boolean b) {
|
||||
rejectWith(new CancellationException());
|
||||
return isRejected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return isRejected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
return !isPending();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() throws InterruptedException, ExecutionException {
|
||||
try {
|
||||
return _await(-1, TimeUnit.MILLISECONDS);
|
||||
} catch (TimeoutException e) {
|
||||
return unexpectedTimeout(e);
|
||||
} catch (BrokenPromise e) {
|
||||
throw new ExecutionException(e.getReason());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get(long l, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException {
|
||||
try {
|
||||
return _await(l, timeUnit);
|
||||
} catch (BrokenPromise e) {
|
||||
throw new ExecutionException(e.getReason());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package org.syndicate_lang.actors;
|
||||
|
||||
public class ProxyFailure extends RuntimeException {
|
||||
public ProxyFailure(Throwable t) {
|
||||
super(t);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package org.syndicate_lang.actors;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class Remote<T> implements InvocationHandler {
|
||||
private final Actor _actor;
|
||||
private final T _target;
|
||||
|
||||
public Remote(Actor actor, T target) {
|
||||
this._actor = actor;
|
||||
this._target = target;
|
||||
}
|
||||
|
||||
public Actor getActor() {
|
||||
return _actor;
|
||||
}
|
||||
|
||||
public void async(Consumer<T> f) {
|
||||
this.async(0, f);
|
||||
}
|
||||
|
||||
public void async(long delayMilliseconds, Consumer<T> f) {
|
||||
this._actor.later(delayMilliseconds, () -> f.accept(this._target));
|
||||
}
|
||||
|
||||
public Promise<Object> syncVoid(Consumer<T> f) {
|
||||
return this.syncVoid(0, f);
|
||||
}
|
||||
|
||||
public Promise<Object> syncVoid(long delayMilliseconds, Consumer<T> f) {
|
||||
return this.sync(delayMilliseconds, (t) -> {
|
||||
f.accept(t);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
public<R> Promise<R> sync(Function<T, R> f) {
|
||||
return this.sync(0, f);
|
||||
}
|
||||
|
||||
public<R> Promise<R> sync(long delayMilliseconds, Function<T, R> f) {
|
||||
Promise<R> p = new Promise<>();
|
||||
this._actor.later(
|
||||
delayMilliseconds,
|
||||
() -> p.resolveWith(f.apply(this._target)),
|
||||
() -> p.rejectWith(this._actor.getExitReason()));
|
||||
return p;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public<I> I proxy(Class<I> c) {
|
||||
if (!c.isInstance(this._target)) {
|
||||
throw new IllegalArgumentException("target is not an instance of " + c);
|
||||
}
|
||||
return (I) Proxy.newProxyInstance(c.getClassLoader(), new Class[] { c }, this);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static<I, T extends I> Remote<T> from(I proxy) {
|
||||
return (Remote<T>) Proxy.getInvocationHandler(proxy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
return this.sync((v) -> {
|
||||
try {
|
||||
return method.invoke(v, args);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new ProxyFailure(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new ProxyFailure(e.getCause());
|
||||
}
|
||||
}).await();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + "(" + this._actor.getName() + "::" + this._target + ")";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/java" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
|
@ -0,0 +1,6 @@
|
|||
package org.syndicate_lang.actors.example.example1;
|
||||
|
||||
public interface IValueHolder<T> {
|
||||
public T get();
|
||||
public void set(T newValue);
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package org.syndicate_lang.actors.example.example1;
|
||||
|
||||
import org.syndicate_lang.actors.Actor;
|
||||
import org.syndicate_lang.actors.PeriodicTimer;
|
||||
import org.syndicate_lang.actors.Remote;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
final var vh = Actor.forObject(new ValueHolder<>("There"));
|
||||
vh.getActor().daemonize();
|
||||
final var m = Actor.forObject(new Main());
|
||||
m.async(10, (m_) -> m_.run(vh));
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
IValueHolder<String> vv = vh.proxy(IValueHolder.class);
|
||||
|
||||
System.out.println("Value: " + vv.get());
|
||||
vv.set("Second");
|
||||
System.out.println("Value: " + vv.get());
|
||||
System.out.println("Underlying: " + Remote.from(vv));
|
||||
|
||||
Actor.awaitAll();
|
||||
System.out.println("Overall main returning");
|
||||
}
|
||||
|
||||
private int greetingCounter = 0;
|
||||
|
||||
public void run(Remote<ValueHolder<String>> vh) {
|
||||
this.greet((String) vh.proxy(IValueHolder.class).get());
|
||||
vh.syncVoid((v) -> v.set("World"));
|
||||
AtomicReference<PeriodicTimer> timer = new AtomicReference<>();
|
||||
timer.set(Actor.current().every(1000, () -> {
|
||||
if (greetingCounter >= 3) Actor.current().stop();
|
||||
this.greet(vh.sync((v) -> v.get()).await());
|
||||
}));
|
||||
}
|
||||
|
||||
public void greet(String who) {
|
||||
Actor.log().info((greetingCounter++) + ": Hi " + who);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package org.syndicate_lang.actors.example.example1;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public class ValueHolder<T> implements IValueHolder<T> {
|
||||
private T value;
|
||||
|
||||
public ValueHolder(T initialValue) {
|
||||
this.value = initialValue;
|
||||
}
|
||||
|
||||
public T get() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public void set(T newValue) {
|
||||
this.value = newValue;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/java" isTestSource="true" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module" module-name="main" />
|
||||
<orderEntry type="module" module-name="main" />
|
||||
</component>
|
||||
</module>
|
Loading…
Reference in New Issue