Initial commit

This commit is contained in:
Tony Garnock-Jones 2020-12-04 19:57:47 +01:00
commit 956a509418
19 changed files with 809 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
out/

3
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

6
.idea/misc.xml Normal file
View File

@ -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>

9
.idea/modules.xml Normal file
View File

@ -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>

124
.idea/uiDesigner.xml Normal file
View File

@ -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>

6
.idea/vcs.xml Normal file
View File

@ -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>

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -0,0 +1,7 @@
package org.syndicate_lang.actors;
public class InternalError extends RuntimeException {
public InternalError(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -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);
}
}

View File

@ -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());
}
}
}

View File

@ -0,0 +1,7 @@
package org.syndicate_lang.actors;
public class ProxyFailure extends RuntimeException {
public ProxyFailure(Throwable t) {
super(t);
}
}

View File

@ -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 + ")";
}
}

11
src/main/main.iml Normal file
View File

@ -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>

View File

@ -0,0 +1,6 @@
package org.syndicate_lang.actors.example.example1;
public interface IValueHolder<T> {
public T get();
public void set(T newValue);
}

View File

@ -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);
}
}

View File

@ -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;
}
}

13
src/test/test.iml Normal file
View File

@ -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>