Samples :: Scheduler

Simple Acceptor

Description

This sample acts as a simple acceptor for other scheduler samples.

“SimpleAcceptor” application must be started first.

Directory Contents

Item Description
conf/sample/SimpleAcceptor.properties engine and application configuration file
conf/logback.xml logger configuration file

Usage

  • Run the sample:
    • win: 1-SimpleAcceptor.bat
    • linux: 1-SimpleAcceptor.sh
  • Clean everything:
    • win: clean.bat
    • linux: clean.sh

Source Code

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import biz.onixs.fix.dictionary.Version;
import biz.onixs.fix.engine.Engine;
import biz.onixs.fix.engine.Session;
import biz.onixs.fix.scheduler.MultiDayLengthSchedule;
import biz.onixs.fix.scheduler.SequenceNumberResetPolicy;
import biz.onixs.fix.scheduler.SessionSchedule;
import biz.onixs.fix.scheduler.SessionScheduler;
import biz.onixs.fix.scheduler.SessionSchedulerException;
import biz.onixs.util.settings.PropertyBasedSettings;
import biz.onixs.util.settings.Settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
  
import java.time.DayOfWeek;
import java.time.LocalTime;
  
public class SimpleAcceptor {
    private static final Logger LOG = LoggerFactory.getLogger(SimpleAcceptor.class);
    private static final String SETTINGS_RESOURCE = "sample/SimpleAcceptor.properties";
    private final DemoSessionStateChangeListener stateChangeListener = new DemoSessionStateChangeListener();
  
    private void run() {
        SessionScheduler scheduler = null;
        try {
            LOG.info("Loading settings from: {}", SETTINGS_RESOURCE);
            final Settings settings = new PropertyBasedSettings(SETTINGS_RESOURCE);
            //
            LOG.info("Starting the Engine...");
            Engine.init(settings);
            //
            scheduler = createAndStartScheduler();
            final Session acceptor = createAcceptorSession(settings);
            //
            final SessionSchedule schedule = createSchedule();
            scheduler.registerAcceptor(acceptor, schedule);
            LOG.info("Acceptor session is registered in the scheduler.");
            //
            LOG.info("Waiting for connection...");
            stateChangeListener.waitEstablished();
            LOG.info("Connected");
            //
            LOG.info("Waiting for disconnection...");
            stateChangeListener.waitDisconnected();
            LOG.info("Disconnected");
            //
            scheduler.unregister(acceptor);
        } catch (final Exception e) {
            LOG.error(e.getMessage(), e);
        } finally {
            if (null != scheduler) {
                try {
                    scheduler.stop();
                } catch (final SessionSchedulerException e) {
                    LOG.error("Scheduler stop error", e);
                }
            }
            LOG.info("Stopping Engine...");
            if (Engine.isInited()) {
                Engine.getInstance().shutdown();
            }
        }
    }
  
    /**
     * Creates and configures the scheduler instance.
     */
    private SessionScheduler createAndStartScheduler() throws SessionSchedulerException {
        final SessionScheduler scheduler = new SessionScheduler();
        scheduler.getListenerManager().addErrorListener(new DemoErrorListener());
        scheduler.start();
        return scheduler;
    }
  
    /**
     * Creates and configures acceptor connection settings.
     */
    private Session createAcceptorSession(final Settings settings) {
        final Version fixVersion = Version.getById(settings.getString("FixVersion"));
        final Session session = new Session(settings.getString("SenderCompID"), settings.getString("TargetCompID"),
                fixVersion, false);
        session.addStateChangeListener(stateChangeListener);
        return session;
    }
  
    /**
     * Creates and configures session schedule. Details:
     * <ul>
     * <li>logon on Monday at 00:00:00</li>
     * <li>logout on Sunday at 23:59:55</li>
     * </ul>
     */
    private static SessionSchedule createSchedule() {
        final MultiDayLengthSchedule schedule = new MultiDayLengthSchedule();
        schedule.setLogonTime(LocalTime.of(0, 0, 0))
                .setLogoutTime(LocalTime.of(23, 59, 55))
                .setFirstDay(DayOfWeek.MONDAY)
                .setLastDay(DayOfWeek.SUNDAY)
                .setResetPolicy(SequenceNumberResetPolicy.DAILY);
        return schedule;
    }
  
    public static void main(final String[] args) {
        try {
            LOG.info("SimpleAcceptor");
            LOG.info("The application is starting...");
            final SimpleAcceptor acceptor = new SimpleAcceptor();
            acceptor.run();
        } catch (Throwable throwable) {
            LOG.error(throwable.getMessage(), throwable);
        } finally {
            LOG.info("The application is stopped.");
        }
    }
}

Program Schedule Sample

Description

The sample demonstrates how to configure session scheduler programatically.

This sample can be run together with the “SimpleAcceptor” app. The “SimpleAcceptor” must be started first.

Directory Contents

Item Description
conf/sample/ProgramScheduleSample.properties engine and application configuration file
conf/logback.xml logger configuration file

Usage

  • Run the sample:
    • win: 2-ProgramScheduleSample.bat
    • linux: 2-ProgramScheduleSample.sh
  • Clean everything:
    • win: clean.bat
    • linux: clean.sh

Source Code

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
import biz.onixs.fix.dictionary.Version;
import biz.onixs.fix.engine.Engine;
import biz.onixs.fix.engine.Session;
import biz.onixs.fix.scheduler.InitiatorConnection;
import biz.onixs.fix.scheduler.SequenceNumberResetPolicy;
import biz.onixs.fix.scheduler.SessionSchedule;
import biz.onixs.fix.scheduler.SessionScheduler;
import biz.onixs.fix.scheduler.SessionSchedulerException;
import biz.onixs.fix.scheduler.SingleDayLengthSchedule;
import biz.onixs.util.settings.PropertyBasedSettings;
import biz.onixs.util.settings.Settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
  
import java.net.InetSocketAddress;
import java.time.DayOfWeek;
import java.time.LocalTime;
  
public class ProgramScheduleSample {
    private static final Logger LOG = LoggerFactory.getLogger(ProgramScheduleSample.class);
    private final DemoSessionStateChangeListener stateChangeListener = new DemoSessionStateChangeListener();
  
    private void run() {
        Engine engine = null;
        SessionScheduler scheduler = null;
        try {
            final Settings appSettings = new PropertyBasedSettings("sample/ProgramScheduleSample.properties");
            //
            LOG.info("Starting Engine...");
            engine = Engine.init(appSettings);
            //
            LOG.info("---! Please make sure 'SimpleAcceptor' app is started !---");
            //
            scheduler = createAndStartScheduler();
            final Session initiator = createInitiatorSession(appSettings);
            //
            final SessionSchedule schedule = createSchedule();
            final InitiatorConnection connection = createInitiatorSettings(appSettings);
            scheduler.register(initiator, schedule, connection);
            LOG.info("Initiator session is registered in the scheduler.");
            //
            LOG.info("Waiting to connect...");
            stateChangeListener.waitEstablished();
            LOG.info("Connected.");
            //
            LOG.info("Waiting to disconnect...");
            stateChangeListener.waitDisconnected();
            LOG.info("Disconnected.");
            //
            scheduler.unregister(initiator);
        } catch (final Exception e) {
            LOG.error(e.getMessage(), e);
        } finally {
            if (null != scheduler) {
                try {
                    scheduler.stop();
                } catch (final SessionSchedulerException e) {
                    LOG.error("Scheduler stop error", e);
                }
            }
            LOG.info("Stopping Engine...");
            if (Engine.isInited()) {
                Engine.getInstance().shutdown();
            }
        }
    }
  
    /**
     * Creates and configures the FIX initiator session.
     */
    private Session createInitiatorSession(final Settings settings) {
        final Version fixVersion = Version.getById(settings.getString("FixVersion"));
        final String senderCompId = settings.getString("SenderCompID");
        final String targetCompId = settings.getString("TargetCompID");
        final Session session = new Session(senderCompId, targetCompId, fixVersion, false);
        session.addStateChangeListener(stateChangeListener);
        return session;
    }
  
    /**
     * Creates and configures the scheduler instance.
     */
    private static SessionScheduler createAndStartScheduler() throws SessionSchedulerException {
        final SessionScheduler scheduler = new SessionScheduler()
                .addLogoutNotification(1)
                .addLogoutNotification(2);
        scheduler.getListenerManager()
                .addErrorListener(new DemoErrorListener())
                .addLogoutNotificationListener(new DemoLogoutNotificationListener());
        scheduler.start();
        return scheduler;
    }
  
    /**
     * Creates and configures the initiator connection settings.
     */
    private static InitiatorConnection createInitiatorSettings(final Settings settings) {
        final InitiatorConnection connection = new InitiatorConnection();
        final String host = settings.getString("CounterpartyHost");
        final int port = settings.getInteger("CounterpartyPort");
        final InetSocketAddress address = InetSocketAddress.createUnresolved(host, port);
        connection.addAddress(address);
        return connection;
    }
  
    /**
     * Creates and configures the simple session schedule.
     * Features:
     * <ul>
     * <li>logon and logout every day from Monday till Sunday</li>
     * <li>logon time is set to 5 seconds from now</li>
     * <li>logout time is set to 10 seconds from now</li>
     * </ul>
     */
    private static SessionSchedule createSchedule() {
        final SingleDayLengthSchedule schedule = new SingleDayLengthSchedule();
        final LocalTime now = LocalTime.now();
        schedule.setLogonTime(now.plusSeconds(5))
                .setLogoutTime(now.plusSeconds(15))
                .setFirstDay(DayOfWeek.MONDAY)
                .setLastDay(DayOfWeek.SUNDAY)
                .setResetPolicy(SequenceNumberResetPolicy.DAILY);
        return schedule;
    }
  
    public static void main(final String[] args) {
        try {
            LOG.info("Program Schedule Sample");
            LOG.info("The application is starting...");
            final ProgramScheduleSample sample = new ProgramScheduleSample();
            sample.run();
        } catch (final Throwable throwable) {
            LOG.error(throwable.getMessage(), throwable);
        } finally {
            LOG.info("The application is stopped.");
        }
    }
}

Program Generic Schedule Sample

Description

This sample demonstrates how to create custom session schedule programatically.

“ProgramGenericScheduleSample” can be run together with the “SimpleAcceptor” app. The “SimpleAcceptor” must be started first.

Directory Contents

Item Description
conf/sample/ProgramGenericScheduleSample.properties engine and application configuration file
conf/logback.xml logger configuration file

Usage

  • Run the sample:
    • win: 2-ProgramGenericScheduleSample.bat
    • linux: 2-ProgramGenericScheduleSample.sh
  • Clean everything:
    • win: clean.bat
    • linux: clean.sh

Source Code

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
import biz.onixs.fix.dictionary.Version;
import biz.onixs.fix.engine.Engine;
import biz.onixs.fix.engine.Session;
import biz.onixs.fix.scheduler.GenericWeeklySchedule;
import biz.onixs.fix.scheduler.InitiatorConnection;
import biz.onixs.fix.scheduler.ScheduleValidationException;
import biz.onixs.fix.scheduler.SessionSchedule;
import biz.onixs.fix.scheduler.SessionScheduler;
import biz.onixs.fix.scheduler.SessionSchedulerException;
import biz.onixs.fix.scheduler.WeeklyInterval;
import biz.onixs.util.settings.PropertyBasedSettings;
import biz.onixs.util.settings.Settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
  
import java.net.InetSocketAddress;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalTime;
  
public class ProgramGenericScheduleSample {
    private static final Logger LOG = LoggerFactory.getLogger(ProgramGenericScheduleSample.class);
    private final DemoSessionStateChangeListener stateChangeListener = new DemoSessionStateChangeListener();
  
    private void run() {
        SessionScheduler scheduler = null;
        try {
            final Settings appSettings = new PropertyBasedSettings("sample/ProgramGenericScheduleSample.properties");
            //
            LOG.info("Starting Engine...");
            Engine.init(appSettings);
            //
            LOG.info("---! Please make sure 'SimpleAcceptor' app is started !---");
            //
            scheduler = createAndStartScheduler();
            final Session initiator = createInitiatorSession(appSettings);
            //
            final SessionSchedule schedule = createSchedule();
            //
            final InitiatorConnection connection = createInitiatorSettings(appSettings);
            scheduler.register(initiator, schedule, connection);
            LOG.info("Initiator session is registered in the scheduler.");
            //
            LOG.info("Waiting to connect...");
            stateChangeListener.waitEstablished();
            LOG.info("Connected.");
            //
            LOG.info("Waiting to disconnect...");
            stateChangeListener.waitDisconnected();
            LOG.info("Disconnected.");
            //
            scheduler.unregister(initiator);
        } catch (final Exception e) {
            LOG.error(e.getMessage(), e);
        } finally {
            if (null != scheduler) {
                try {
                    scheduler.stop();
                } catch (final SessionSchedulerException e) {
                    LOG.error("Scheduler stop error", e);
                }
            }
            LOG.info("Stopping Engine...");
            if (Engine.isInited()) {
                Engine.getInstance().shutdown();
            }
        }
    }
  
    /**
     * Creates and configures the FIX initiator session.
     */
    private Session createInitiatorSession(final Settings settings) {
        final Version fixVersion = Version.getByNumber(settings.getString("FixVersion"));
        final String senderCompId = settings.getString("SenderCompID");
        final String targetCompId = settings.getString("TargetCompID");
        final Session session = new Session(senderCompId, targetCompId, fixVersion, false);
        session.addStateChangeListener(stateChangeListener);
        return session;
    }
  
    /**
     * Creates and configures the scheduler instance.
     */
    private static SessionScheduler createAndStartScheduler() throws SessionSchedulerException {
        final SessionScheduler scheduler = new SessionScheduler()
                .addLogoutNotification(1)
                .addLogoutNotification(2);
        scheduler.getListenerManager()
                .addErrorListener(new DemoErrorListener())
                .addLogoutNotificationListener(new DemoLogoutNotificationListener());
        scheduler.start();
        return scheduler;
    }
  
    /**
     * Creates and configures the initiator connection settings.
     */
    private static InitiatorConnection createInitiatorSettings(final Settings settings) {
        final InitiatorConnection connection = new InitiatorConnection();
        final String host = settings.getString("CounterpartyHost");
        final int port = settings.getInteger("CounterpartyPort");
        final InetSocketAddress address = InetSocketAddress.createUnresolved(host, port);
        connection.addAddress(address);
        return connection;
    }
  
    /**
     * Creates and configures generic weekly session schedule which can consist of several activity intervals.
     */
    private static SessionSchedule createSchedule() throws ScheduleValidationException {
        final GenericWeeklySchedule schedule = new GenericWeeklySchedule();
        //
        final LocalTime now = LocalTime.now();
        final DayOfWeek todayDayOfWeek = LocalDate.now().getDayOfWeek();
        //
        final WeeklyInterval interval = new WeeklyInterval()
                .setLogonDay(todayDayOfWeek)
                .setLogonTime(now.plusSeconds(5))
                .setLogoutDay(todayDayOfWeek)
                .setLogoutTime(now.plusSeconds(10))
                .setResetOnLogout(false);
        schedule.addInterval(interval);
        //
        return schedule;
    }
  
    public static void main(final String[] args) {
        try {
            LOG.info("ProgramGenericScheduleSample");
            LOG.info("The application is starting...");
            final ProgramGenericScheduleSample sample = new ProgramGenericScheduleSample();
            sample.run();
        } catch (final Throwable throwable) {
            LOG.error(throwable.getMessage(), throwable);
        } finally {
            LOG.info("The application is stopped.");
        }
    }
}

File Schedule Sample

Description

The sample demonstrates how to configure session scheduler using configuration file.

This sample can be run together with the “SimpleAcceptor” app. The “SimpleAcceptor” must be started first.

Directory Contents

Item Description
conf/sample/FileScheduleSample.properties engine and application configuration file
conf/sample/SchedulerSettings.xml scheduler configuration file
conf/logback.xml logger configuration file

Usage

  • Run the sample:
    • win: 2-FileScheduleSample.bat
    • linux: 2-FileScheduleSample.sh
  • Clean everything:
    • win: clean.bat
    • linux: clean.sh

Source Code

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import biz.onixs.fix.dictionary.Version;
import biz.onixs.fix.engine.Engine;
import biz.onixs.fix.engine.Session;
import biz.onixs.fix.scheduler.SchedulerSettings;
import biz.onixs.fix.scheduler.SchedulerSettingsLoader;
import biz.onixs.fix.scheduler.SchedulerSettingsLoaderException;
import biz.onixs.fix.scheduler.SessionScheduler;
import biz.onixs.fix.scheduler.SessionSchedulerException;
import biz.onixs.util.settings.PropertyBasedSettings;
import biz.onixs.util.settings.Settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
  
public class FileScheduleSample {
    private static final Logger LOG = LoggerFactory.getLogger(FileScheduleSample.class);
    private final DemoSessionStateChangeListener stateChangeListener = new DemoSessionStateChangeListener();
  
    private void run() {
        SessionScheduler scheduler = null;
        try {
            final Settings appSettings = new PropertyBasedSettings("sample/FileScheduleSample.properties");
            //
            LOG.info("Starting Engine...");
            Engine.init(appSettings);
            //
            LOG.info("---! Please make sure 'SimpleAcceptor' app is started !---");
            //
            scheduler = createAndStartScheduler();
            final SchedulerSettings schedulerSettings = loadSchedulerSettings("sample/SchedulerSettings.xml");
            final Session initiator = createInitiatorSession(appSettings);
            scheduler.register(initiator, schedulerSettings, "Schedule1", "Initiator1");
            LOG.info("Initiator session is registered in the scheduler.");
            //
            LOG.info("Waiting to connect...");
            stateChangeListener.waitEstablished();
            LOG.info("Connected.");
            //
            scheduler.unregister(initiator);
            //
            initiator.logout();
        } catch (final Exception e) {
            LOG.error(e.getMessage(), e);
        } finally {
            if (null != scheduler) {
                try {
                    scheduler.stop();
                } catch (final SessionSchedulerException e) {
                    LOG.error("Scheduler stop error", e);
                }
            }
            LOG.info("Stopping Engine...");
            if (Engine.isInited()) {
                Engine.getInstance().shutdown();
            }
        }
    }
  
    /**
     * Creates and configures the FIX initiator session.
     *
     * @return initiator session
     */
    private Session createInitiatorSession(final Settings settings) {
        final Version fixVersion = Version.getByNumber(settings.getString("FixVersion"));
        final String senderCompId = settings.getString("SenderCompID");
        final String targetCompId = settings.getString("TargetCompID");
        final Session session = new Session(senderCompId, targetCompId, fixVersion, false);
        session.addStateChangeListener(stateChangeListener);
        return session;
    }
  
    /**
     * Creates and configures the scheduler instance.
     *
     * @return scheduler
     */
    private static SessionScheduler createAndStartScheduler() throws SessionSchedulerException {
        final SessionScheduler scheduler = new SessionScheduler();
        scheduler.getListenerManager().addErrorListener(new DemoErrorListener());
        scheduler.start();
        return scheduler;
    }
  
    private static SchedulerSettings loadSchedulerSettings(final String resource)
            throws SchedulerSettingsLoaderException {
        final SchedulerSettingsLoader loader = new SchedulerSettingsLoader();
        return loader.load(resource);
    }
  
    public static void main(final String[] args) {
        try {
            LOG.info("File Schedule Sample");
            LOG.info("The application is starting...");
            final FileScheduleSample programScheduleSample = new FileScheduleSample();
            programScheduleSample.run();
        } catch (final Throwable throwable) {
            LOG.error(throwable.getMessage(), throwable);
        } finally {
            LOG.info("The application is stopped.");
        }
    }
}

Source Codes Used In Samples

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import biz.onixs.fix.scheduler.ErrorListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
  
public class DemoErrorListener implements ErrorListener {
    private static final Logger LOG = LoggerFactory.getLogger(DemoErrorListener.class);
  
    @Override
    public void onError(final ErrorArgs args) {
        LOG.error("onError(): {}", args);
    }
  
    /**
     * Logon error event callback.
     *
     * @param args event arguments
     */
    @Override
    public void onLogonError(final LogonErrorArgs args) {
        LOG.error("onLogonError(): {}", args);
    }
}
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import biz.onixs.fix.scheduler.LogoutNotification;
import biz.onixs.fix.scheduler.LogoutNotificationListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
  
/**
 * Demo logout notification listener implementation.
 */
public class DemoLogoutNotificationListener implements LogoutNotificationListener {
    private static final Logger LOG = LoggerFactory.getLogger(DemoLogoutNotificationListener.class);
  
    @Override
    public void onLogoutNotification(final LogoutNotification notification) {
        LOG.info("{}: logout notification: {} seconds left", notification.getSession(), notification.getInterval());
    }
}
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import biz.onixs.fix.engine.Session;
import biz.onixs.fix.engine.SessionState;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
  
import java.util.concurrent.Semaphore;
  
public class DemoSessionStateChangeListener implements Session.StateChangeListener {
    private static final Logger LOG = LoggerFactory.getLogger(DemoSessionStateChangeListener.class);
    private final Semaphore semaphoreIsEstablished = new Semaphore(0);
    private final Semaphore semaphoreIsDisconnected = new Semaphore(0);
  
    @Override
    public void onStateChange(final Object sender, final Session.StateChangeArgs args) {
        final SessionState prevState = args.getPrevState();
        final SessionState newState = args.getNewState();
        if ((prevState != SessionState.DISCONNECTED)
                && ((SessionState.DISCONNECTED == newState) || (SessionState.AWAIT_LOGON == newState))) {
            semaphoreIsDisconnected.release();
        } else if (SessionState.ESTABLISHED == newState) {
            semaphoreIsEstablished.release();
        }
    }
  
    public void waitEstablished() throws InterruptedException {
        semaphoreIsEstablished.acquire();
    }
  
    public void waitDisconnected() throws InterruptedException {
        semaphoreIsDisconnected.acquire();
    }
}