com.digitalpetri.enip.ChannelManager Maven / Gradle / Ivy
package com.digitalpetri.enip;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;
import com.digitalpetri.enip.commands.RegisterSession;
import com.digitalpetri.enip.commands.UnRegisterSession;
import io.netty.channel.Channel;
public class ChannelManager {
private final AtomicReference state = new AtomicReference<>(new Idle());
private final EtherNetIpClient client;
public ChannelManager(EtherNetIpClient client) {
this.client = client;
}
public CompletableFuture getChannel() {
State currentState = state.get();
if (currentState instanceof Idle) {
Connecting nextState = new Connecting();
if (state.compareAndSet(currentState, nextState)) {
CompletableFuture future = nextState.future;
future.whenComplete((ch, ex) -> {
if (ch != null) state.set(new Connected(future));
else state.set(new Idle());
});
return connect(future);
} else {
return getChannel();
}
} else if (currentState instanceof Connecting) {
return ((Connecting) currentState).future;
} else if (currentState instanceof Connected) {
return ((Connected) currentState).future;
} else {
throw new IllegalStateException(currentState.getClass().getSimpleName());
}
}
private CompletableFuture connect(CompletableFuture future) {
CompletableFuture bootstrap = EtherNetIpClient.bootstrap(client);
bootstrap.whenComplete((ch, ex) -> {
if (ch != null) {
ch.closeFuture().addListener(f -> state.set(new Idle()));
CompletableFuture registerFuture = new CompletableFuture<>();
registerFuture.whenComplete((r, ex2) -> {
if (r != null) future.complete(ch);
else future.completeExceptionally(ex2);
});
client.writeCommand(ch, new RegisterSession(), registerFuture);
} else {
future.completeExceptionally(ex);
}
});
return future;
}
public void disconnect() {
State currentState = state.get();
if (currentState instanceof Connecting) {
((Connecting) currentState).future.whenComplete((ch, ex) -> {
if (ch != null) ch.close();
});
} else if (currentState instanceof Connected) {
((Connected) currentState).future.whenComplete((ch, ex) -> {
CompletableFuture f = new CompletableFuture<>();
client.writeCommand(ch, new UnRegisterSession(), f);
f.whenComplete((ch2, ex2) -> ch.close());
});
}
}
public String getState() {
return state.get().getClass().getSimpleName();
}
private static abstract class State {
}
private static class Idle extends State {
}
private static class Connecting extends State {
private final CompletableFuture future = new CompletableFuture<>();
}
private static class Connected extends State {
private final CompletableFuture future;
private Connected(CompletableFuture future) {
this.future = future;
}
}
}