001package jmri.jmrit.logixng.actions;
002
003import java.util.*;
004
005import jmri.InstanceManager;
006import jmri.JmriException;
007import jmri.jmrit.logixng.*;
008import jmri.jmrit.logixng.expressions.AbstractDigitalExpression;
009
010/**
011 * Executes actions in a sequence.
012 *
013 * @author Daniel Bergqvist Copyright 2020
014 */
015public class Sequence extends AbstractDigitalAction
016        implements FemaleSocketListener {
017
018    private static class State {
019        private int _currentStep = -1;
020        private boolean _isRunning = false;
021    }
022
023    public static final int EXPRESSION_START = 0;
024    public static final int EXPRESSION_STOP = 1;
025    public static final int EXPRESSION_RESET = 2;
026    public static final int NUM_STATIC_EXPRESSIONS = 3;
027
028    private String _startExpressionSocketSystemName;
029    private String _stopExpressionSocketSystemName;
030    private String _resetExpressionSocketSystemName;
031    private final FemaleDigitalExpressionSocket _startExpressionSocket;
032    private final FemaleDigitalExpressionSocket _stopExpressionSocket;
033    private final FemaleDigitalExpressionSocket _resetExpressionSocket;
034    private final List<ExpressionEntry> _expressionEntries = new ArrayList<>();
035    private final List<ActionEntry> _actionEntries = new ArrayList<>();
036    private boolean _startImmediately = false;
037    private boolean _runContinuously = false;
038    private boolean disableCheckForUnconnectedSocket = false;
039    private final Map<ConditionalNG, State> _stateMap = new HashMap<>();
040
041    public Sequence(String sys, String user) {
042        super(sys, user);
043        _startExpressionSocket = InstanceManager.getDefault(DigitalExpressionManager.class)
044                .createFemaleSocket(this, this, Bundle.getMessage("SequenceSocketStart"));
045        _stopExpressionSocket = InstanceManager.getDefault(DigitalExpressionManager.class)
046                .createFemaleSocket(this, this, Bundle.getMessage("SequenceSocketStop"));
047        _resetExpressionSocket = InstanceManager.getDefault(DigitalExpressionManager.class)
048                .createFemaleSocket(this, this, Bundle.getMessage("SequenceSocketReset"));
049        _actionEntries
050                .add(new ActionEntry(InstanceManager.getDefault(DigitalActionManager.class)
051                        .createFemaleSocket(this, this, getNewActionSocketName())));
052        _expressionEntries
053                .add(new ExpressionEntry(InstanceManager.getDefault(DigitalExpressionManager.class)
054                        .createFemaleSocket(this, this, getNewExpressionSocketName())));
055    }
056
057    public Sequence(String sys, String user,
058            List<Map.Entry<String, String>> expressionSystemNames,
059            List<Map.Entry<String, String>> actionSystemNames)
060            throws BadUserNameException, BadSystemNameException {
061        super(sys, user);
062        _startExpressionSocket = InstanceManager.getDefault(DigitalExpressionManager.class)
063                .createFemaleSocket(this, this, Bundle.getMessage("SequenceSocketStart"));
064        _stopExpressionSocket = InstanceManager.getDefault(DigitalExpressionManager.class)
065                .createFemaleSocket(this, this, Bundle.getMessage("SequenceSocketStop"));
066        _resetExpressionSocket = InstanceManager.getDefault(DigitalExpressionManager.class)
067                .createFemaleSocket(this, this, Bundle.getMessage("SequenceSocketReset"));
068        setExpressionSystemNames(expressionSystemNames);
069        setActionSystemNames(actionSystemNames);
070    }
071
072    public String getNewActionSocketName() {
073        String[] names = new String[getChildCount()];
074        for (int i=0; i < getChildCount(); i++) {
075            names[i] = getChild(i).getName();
076        }
077        return getNewSocketName(names);
078    }
079
080    public String getNewExpressionSocketName() {
081        String[] names = new String[getChildCount()];
082        for (int i=0; i < getChildCount(); i++) {
083            names[i] = getChild(i).getName();
084        }
085        return AbstractDigitalExpression.getNewSocketName(names);
086    }
087
088    @Override
089    public Base getDeepCopy(Map<String, String> systemNames, Map<String, String> userNames) throws JmriException {
090        DigitalActionManager manager = InstanceManager.getDefault(DigitalActionManager.class);
091        String sysName = systemNames.get(getSystemName());
092        String userName = userNames.get(getSystemName());
093        if (sysName == null) sysName = manager.getAutoSystemName();
094        Sequence copy = new Sequence(sysName, userName);
095        copy.setComment(getComment());
096        copy.setStartImmediately(_startImmediately);
097        copy.setRunContinuously(_runContinuously);
098
099        // Ensure the copy has as many childs as myself
100        while (copy.getChildCount() < this.getChildCount()) {
101            copy.doSocketOperation(copy.getChildCount()-1, FemaleSocketOperation.InsertAfter);
102        }
103
104        return manager.registerAction(copy).deepCopyChildren(this, systemNames, userNames);
105    }
106
107    private void setExpressionSystemNames(List<Map.Entry<String, String>> systemNames) {
108        if (!_expressionEntries.isEmpty()) {
109            throw new RuntimeException("expression system names cannot be set more than once");
110        }
111
112        for (Map.Entry<String, String> entry : systemNames) {
113            FemaleDigitalExpressionSocket socket =
114                    InstanceManager.getDefault(DigitalExpressionManager.class)
115                            .createFemaleSocket(this, this, entry.getKey());
116
117            _expressionEntries.add(new ExpressionEntry(socket, entry.getValue()));
118        }
119    }
120
121    private void setActionSystemNames(List<Map.Entry<String, String>> systemNames) {
122        if (!_actionEntries.isEmpty()) {
123            throw new RuntimeException("action system names cannot be set more than once");
124        }
125
126        for (Map.Entry<String, String> entry : systemNames) {
127            FemaleDigitalActionSocket socket =
128                    InstanceManager.getDefault(DigitalActionManager.class)
129                            .createFemaleSocket(this, this, entry.getKey());
130
131            _actionEntries.add(new ActionEntry(socket, entry.getValue()));
132        }
133    }
134
135    /** {@inheritDoc} */
136    @Override
137    public Category getCategory() {
138        return Category.FLOW_CONTROL;
139    }
140
141    /** {@inheritDoc} */
142    @Override
143    public void execute() throws JmriException {
144        State state = _stateMap.computeIfAbsent(getConditionalNG(), o -> new State());
145        if (_startImmediately) state._isRunning = true;
146
147        // We want to limit the number of loops in case all expressions return
148        // True so we don't get caught in an endless loop
149        for (int count=0; count < _actionEntries.size(); count++) {
150            if (_stopExpressionSocket.isConnected()
151                    && _stopExpressionSocket.evaluate()) {
152                state._isRunning = false;
153//                System.out.format("Stop: _currentStep: %d%n", _currentStep);
154                return;
155            }
156
157            if (_startExpressionSocket.isConnected()
158                    && _startExpressionSocket.evaluate()) {
159                state._isRunning = true;
160//                System.out.format("Start: _currentStep: %d%n", _currentStep);
161            }
162
163            if (_resetExpressionSocket.isConnected()
164                    && _resetExpressionSocket.evaluate()) {
165                state._currentStep = -1;
166//                System.out.format("Reset: _currentStep: %d%n", _currentStep);
167            }
168
169            if (!state._isRunning) return;
170
171            if (state._currentStep == -1) {
172                state._currentStep = 0;
173//                System.out.format("_currentStep: %d, size: %d%n", _currentStep, _actionEntries.size());
174                FemaleDigitalActionSocket socket =
175                        _actionEntries.get(state._currentStep)._socket;
176                if (socket.isConnected()) socket.execute();
177            }
178
179            FemaleDigitalExpressionSocket exprSocket =
180                    _expressionEntries.get(state._currentStep)._socket;
181            if (exprSocket.isConnected()) {
182                if (exprSocket.evaluate()) {
183                    state._currentStep++;
184//                    System.out.format("_currentStep: %d, size: %d%n", _currentStep, _actionEntries.size());
185                    if (state._currentStep >= _actionEntries.size()) {
186                        state._currentStep = 0;
187//                        System.out.format("_currentStep set to 0: %d%n", _currentStep);
188                    }
189
190                    FemaleDigitalActionSocket actionSocket =
191                            _actionEntries.get(state._currentStep)._socket;
192                    if (actionSocket.isConnected()) actionSocket.execute();
193
194                    if (!_runContinuously && state._currentStep == _actionEntries.size() - 1) {
195                        // Sequence is done, stop and reset the sequence so that it can be started again later
196                        state._isRunning = false;
197                        state._currentStep = -1;
198                    }
199                } else {
200                    // Break the outer for loop
201                    return;
202                }
203            }
204        }
205    }
206
207    /**
208     * Get if to start immediately
209     * @return true if to start immediately
210     */
211    public boolean getStartImmediately() {
212        return _startImmediately;
213    }
214
215    /**
216     * Set if to start immediately
217     * @param startImmediately true if to start immediately
218     */
219    public void setStartImmediately(boolean startImmediately) {
220        _startImmediately = startImmediately;
221        if (_startImmediately) {
222            _stateMap.forEach((conditionalNG, state) -> { state._isRunning = true; });
223        }
224    }
225
226    /**
227     * Get if run continuously
228     * @return true if run continuously
229     */
230    public boolean getRunContinuously() {
231        return _runContinuously;
232    }
233
234    /**
235     * Set if run continuously
236     * @param runContinuously true if run continuously
237     */
238    public void setRunContinuously(boolean runContinuously) {
239        _runContinuously = runContinuously;
240    }
241
242    @Override
243    public FemaleSocket getChild(int index) throws IllegalArgumentException, UnsupportedOperationException {
244        if (index == EXPRESSION_START) return _startExpressionSocket;
245        if (index == EXPRESSION_STOP) return _stopExpressionSocket;
246        if (index == EXPRESSION_RESET) return _resetExpressionSocket;
247
248        index -= NUM_STATIC_EXPRESSIONS;
249        if ((index % 2) == 0) return _actionEntries.get(index >> 1)._socket;
250        else return _expressionEntries.get(index >> 1)._socket;
251    }
252
253    @Override
254    public int getChildCount() {
255        return NUM_STATIC_EXPRESSIONS + _expressionEntries.size() + _actionEntries.size();
256    }
257
258    /** {@inheritDoc} */
259    @Override
260    public boolean isSocketOperationAllowed(int index, FemaleSocketOperation oper) {
261        index -= NUM_STATIC_EXPRESSIONS;
262
263        // Num children except the static expressions
264        int numChilds = getChildCount() - NUM_STATIC_EXPRESSIONS;
265
266        switch (oper) {
267            case Remove:
268                // Possible if not the three static sockets,
269                // the socket is not connected and the next socket is not connected
270                return (index >= 0)
271                        && (index+1 < numChilds)
272                        && !getChild(index+NUM_STATIC_EXPRESSIONS).isConnected()
273                        && !getChild(index+NUM_STATIC_EXPRESSIONS+1).isConnected();
274            case InsertBefore:
275                // Possible if not the first three static sockets
276                return index >= 0;
277            case InsertAfter:
278                // Possible if not the static sockets, except the last one
279                return index >= -1;
280            case MoveUp:
281                // Possible, except for the the three static sockets, the first two sockets after that, and the last socket
282                return (index >= 2) && (index < numChilds-1);
283            case MoveDown:
284                // Possible if not the static sockets and if not the last three sockets
285                return (index >= 0) && (index < numChilds-3);
286            default:
287                throw new UnsupportedOperationException("Oper is unknown" + oper.name());
288        }
289    }
290
291    private void insertNewSocket(int index) {
292        int actionIndex = index >> 1;
293        int expressionIndex = index >> 1;
294
295        // Does index points to an expression socket instead of an action socket?
296        if ((index % 2) != 0) {
297            expressionIndex = index >> 1;
298            actionIndex = (index >> 1) + 1;
299        }
300
301        FemaleDigitalActionSocket actionSocket =
302                InstanceManager.getDefault(DigitalActionManager.class)
303                        .createFemaleSocket(this, this, getNewActionSocketName());
304        _actionEntries.add(actionIndex, new ActionEntry(actionSocket));
305
306        FemaleDigitalExpressionSocket exprSocket =
307                InstanceManager.getDefault(DigitalExpressionManager.class)
308                        .createFemaleSocket(this, this, getNewExpressionSocketName());
309        _expressionEntries.add(expressionIndex, new ExpressionEntry(exprSocket));
310
311        List<FemaleSocket> addList = new ArrayList<>();
312        addList.add(actionSocket);
313        addList.add(exprSocket);
314        firePropertyChange(Base.PROPERTY_CHILD_COUNT, null, addList);
315    }
316
317    private void removeSocket(int index) {
318        int actionIndex = index >> 1;
319        int expressionIndex = index >> 1;
320
321        // Does index points to an expression socket instead of an action socket?
322        if ((index % 2) != 0) {
323            actionIndex = (index >> 1) + 1;
324        }
325
326        List<FemaleSocket> removeList = new ArrayList<>();
327        removeList.add(_actionEntries.remove(actionIndex)._socket);
328        removeList.add(_expressionEntries.remove(expressionIndex)._socket);
329        firePropertyChange(Base.PROPERTY_CHILD_COUNT, removeList, null);
330    }
331
332    private void moveSocketDown(int index) {
333        int actionIndex = index >> 1;
334        int expressionIndex = index >> 1;
335
336        // Does index points to an expression socket instead of an action socket?
337        if ((index % 2) != 0) {
338            actionIndex = (index >> 1) + 1;
339        }
340
341        ActionEntry actionTemp = _actionEntries.get(actionIndex);
342        _actionEntries.set(actionIndex, _actionEntries.get(actionIndex+1));
343        _actionEntries.set(actionIndex+1, actionTemp);
344
345        ExpressionEntry exprTemp = _expressionEntries.get(expressionIndex);
346        _expressionEntries.set(expressionIndex, _expressionEntries.get(expressionIndex+1));
347        _expressionEntries.set(expressionIndex+1, exprTemp);
348
349        List<FemaleSocket> list = new ArrayList<>();
350        list.add(_actionEntries.get(actionIndex)._socket);
351        list.add(_actionEntries.get(actionIndex+1)._socket);
352        list.add(_expressionEntries.get(expressionIndex)._socket);
353        list.add(_expressionEntries.get(expressionIndex+1)._socket);
354        firePropertyChange(Base.PROPERTY_CHILD_REORDER, null, list);
355    }
356
357    /** {@inheritDoc} */
358    @Override
359    public void doSocketOperation(int index, FemaleSocketOperation oper) {
360        index -= NUM_STATIC_EXPRESSIONS;
361
362        switch (oper) {
363            case Remove:
364                if (index+NUM_STATIC_EXPRESSIONS+1 >= getChildCount()) throw new UnsupportedOperationException("Cannot remove only the last socket");
365                if (getChild(index+NUM_STATIC_EXPRESSIONS).isConnected()) throw new UnsupportedOperationException("Socket is connected");
366                if (getChild(index+NUM_STATIC_EXPRESSIONS+1).isConnected()) throw new UnsupportedOperationException("Socket below is connected");
367                removeSocket(index);
368                break;
369            case InsertBefore:
370                insertNewSocket(index);
371                break;
372            case InsertAfter:
373                insertNewSocket(index+1);
374                break;
375            case MoveUp:
376                if (index < 0) throw new UnsupportedOperationException("cannot move up static sockets");
377                if (index <= 1) throw new UnsupportedOperationException("cannot move up first two children");
378                moveSocketDown(index-2);
379                break;
380            case MoveDown:
381                if (index+2 >= getChildCount()) throw new UnsupportedOperationException("cannot move down last two children");
382                moveSocketDown(index);
383                break;
384            default:
385                throw new UnsupportedOperationException("Oper is unknown" + oper.name());
386        }
387    }
388
389    @Override
390    public void connected(FemaleSocket socket) {
391        if (disableCheckForUnconnectedSocket) return;
392
393        if (socket == _startExpressionSocket) {
394            _startExpressionSocketSystemName = socket.getConnectedSocket().getSystemName();
395        } else if (socket == _stopExpressionSocket) {
396            _stopExpressionSocketSystemName = socket.getConnectedSocket().getSystemName();
397        } else if (socket == _resetExpressionSocket) {
398            _resetExpressionSocketSystemName = socket.getConnectedSocket().getSystemName();
399        } else {
400            for (ExpressionEntry entry : _expressionEntries) {
401                if (socket == entry._socket) {
402                    entry._socketSystemName =
403                            socket.getConnectedSocket().getSystemName();
404                }
405            }
406            for (ActionEntry entry : _actionEntries) {
407                if (socket == entry._socket) {
408                    entry._socketSystemName =
409                            socket.getConnectedSocket().getSystemName();
410                }
411            }
412        }
413    }
414
415    @Override
416    public void disconnected(FemaleSocket socket) {
417        if (socket == _startExpressionSocket) {
418            _startExpressionSocketSystemName = null;
419        } else if (socket == _stopExpressionSocket) {
420            _stopExpressionSocketSystemName = null;
421        } else if (socket == _resetExpressionSocket) {
422            _resetExpressionSocketSystemName = null;
423        } else {
424            for (ExpressionEntry entry : _expressionEntries) {
425                if (socket == entry._socket) {
426                    entry._socketSystemName = null;
427                }
428            }
429            for (ActionEntry entry : _actionEntries) {
430                if (socket == entry._socket) {
431                    entry._socketSystemName = null;
432                }
433            }
434        }
435    }
436
437    @Override
438    public String getShortDescription(Locale locale) {
439        return Bundle.getMessage(locale, "Sequence_Short");
440    }
441
442    @Override
443    public String getLongDescription(Locale locale) {
444        return Bundle.getMessage(locale, "Sequence_Long");
445    }
446
447    public FemaleDigitalExpressionSocket getStartExpressionSocket() {
448        return _startExpressionSocket;
449    }
450
451    public String getStartExpressionSocketSystemName() {
452        return _startExpressionSocketSystemName;
453    }
454
455    public void setStartExpressionSocketSystemName(String systemName) {
456        _startExpressionSocketSystemName = systemName;
457    }
458
459    public FemaleDigitalExpressionSocket getStopExpressionSocket() {
460        return _stopExpressionSocket;
461    }
462
463    public String getStopExpressionSocketSystemName() {
464        return _stopExpressionSocketSystemName;
465    }
466
467    public void setStopExpressionSocketSystemName(String systemName) {
468        _stopExpressionSocketSystemName = systemName;
469    }
470
471    public FemaleDigitalExpressionSocket getResetExpressionSocket() {
472        return _resetExpressionSocket;
473    }
474
475    public String getResetExpressionSocketSystemName() {
476        return _resetExpressionSocketSystemName;
477    }
478
479    public void setResetExpressionSocketSystemName(String systemName) {
480        _resetExpressionSocketSystemName = systemName;
481    }
482
483    public int getNumExpressions() {
484        return _expressionEntries.size();
485    }
486
487    public FemaleDigitalExpressionSocket getExpressionSocket(int socket) {
488        return _expressionEntries.get(socket)._socket;
489    }
490
491    public String getExpressionSocketSystemName(int socket) {
492        return _expressionEntries.get(socket)._socketSystemName;
493    }
494
495    public void setExpressionSocketSystemName(int socket, String systemName) {
496        _expressionEntries.get(socket)._socketSystemName = systemName;
497    }
498
499    public int getNumActions() {
500        return _actionEntries.size();
501    }
502
503    public FemaleDigitalActionSocket getActionSocket(int socket) {
504        return _actionEntries.get(socket)._socket;
505    }
506
507    public String getActionSocketSystemName(int socket) {
508        return _actionEntries.get(socket)._socketSystemName;
509    }
510
511    public void setActionSocketSystemName(int socket, String systemName) {
512        _actionEntries.get(socket)._socketSystemName = systemName;
513    }
514
515    /** {@inheritDoc} */
516    @Override
517    public void setup() {
518        // We don't want to check for unconnected sockets while setup sockets
519        disableCheckForUnconnectedSocket = true;
520
521        try {
522            if ( !_startExpressionSocket.isConnected()
523                    || !_startExpressionSocket.getConnectedSocket().getSystemName()
524                            .equals(_startExpressionSocketSystemName)) {
525
526                String socketSystemName = _startExpressionSocketSystemName;
527                _startExpressionSocket.disconnect();
528                if (socketSystemName != null) {
529                    MaleSocket maleSocket =
530                            InstanceManager.getDefault(DigitalExpressionManager.class)
531                                    .getBySystemName(socketSystemName);
532                    if (maleSocket != null) {
533                        _startExpressionSocket.connect(maleSocket);
534                        maleSocket.setup();
535                    } else {
536                        log.error("cannot load digital expression {}", socketSystemName);
537                    }
538                }
539            } else {
540                _startExpressionSocket.getConnectedSocket().setup();
541            }
542
543            if ( !_stopExpressionSocket.isConnected()
544                    || !_stopExpressionSocket.getConnectedSocket().getSystemName()
545                            .equals(_stopExpressionSocketSystemName)) {
546
547                String socketSystemName = _stopExpressionSocketSystemName;
548                _stopExpressionSocket.disconnect();
549                if (socketSystemName != null) {
550                    MaleSocket maleSocket =
551                            InstanceManager.getDefault(DigitalExpressionManager.class)
552                                    .getBySystemName(socketSystemName);
553                    _stopExpressionSocket.disconnect();
554                    if (maleSocket != null) {
555                        _stopExpressionSocket.connect(maleSocket);
556                        maleSocket.setup();
557                    } else {
558                        log.error("cannot load digital expression {}", socketSystemName);
559                    }
560                }
561            } else {
562                _stopExpressionSocket.getConnectedSocket().setup();
563            }
564
565            if ( !_resetExpressionSocket.isConnected()
566                    || !_resetExpressionSocket.getConnectedSocket().getSystemName()
567                            .equals(_resetExpressionSocketSystemName)) {
568
569                String socketSystemName = _resetExpressionSocketSystemName;
570                _resetExpressionSocket.disconnect();
571                if (socketSystemName != null) {
572                    MaleSocket maleSocket =
573                            InstanceManager.getDefault(DigitalExpressionManager.class)
574                                    .getBySystemName(socketSystemName);
575                    _resetExpressionSocket.disconnect();
576                    if (maleSocket != null) {
577                        _resetExpressionSocket.connect(maleSocket);
578                        maleSocket.setup();
579                    } else {
580                        log.error("cannot load digital expression {}", socketSystemName);
581                    }
582                }
583            } else {
584                _resetExpressionSocket.getConnectedSocket().setup();
585            }
586
587            for (ExpressionEntry ee : _expressionEntries) {
588                if ( !ee._socket.isConnected()
589                        || !ee._socket.getConnectedSocket().getSystemName()
590                                .equals(ee._socketSystemName)) {
591
592                    String socketSystemName = ee._socketSystemName;
593                    ee._socket.disconnect();
594                    if (socketSystemName != null) {
595                        MaleSocket maleSocket =
596                                InstanceManager.getDefault(DigitalExpressionManager.class)
597                                        .getBySystemName(socketSystemName);
598                        ee._socket.disconnect();
599                        if (maleSocket != null) {
600                            ee._socket.connect(maleSocket);
601                            maleSocket.setup();
602                        } else {
603                            log.error("cannot load digital expression {}", socketSystemName);
604                        }
605                    }
606                } else {
607                    ee._socket.getConnectedSocket().setup();
608                }
609            }
610
611            for (ActionEntry ae : _actionEntries) {
612                if ( !ae._socket.isConnected()
613                        || !ae._socket.getConnectedSocket().getSystemName()
614                                .equals(ae._socketSystemName)) {
615
616                    String socketSystemName = ae._socketSystemName;
617                    ae._socket.disconnect();
618                    if (socketSystemName != null) {
619                        MaleSocket maleSocket =
620                                InstanceManager.getDefault(DigitalActionManager.class)
621                                        .getBySystemName(socketSystemName);
622                        ae._socket.disconnect();
623                        if (maleSocket != null) {
624                            ae._socket.connect(maleSocket);
625                            maleSocket.setup();
626                        } else {
627                            log.error("cannot load digital action {}", socketSystemName);
628                        }
629                    }
630                } else {
631                    ae._socket.getConnectedSocket().setup();
632                }
633            }
634        } catch (SocketAlreadyConnectedException ex) {
635            // This shouldn't happen and is a runtime error if it does.
636            throw new RuntimeException("socket is already connected");
637        }
638
639        disableCheckForUnconnectedSocket = false;
640    }
641
642    /** {@inheritDoc} */
643    @Override
644    public void registerListenersForThisClass() {
645        if (!_listenersAreRegistered) {
646            _listenersAreRegistered = true;
647        }
648    }
649
650    /** {@inheritDoc} */
651    @Override
652    public void unregisterListenersForThisClass() {
653        _listenersAreRegistered = false;
654    }
655
656    /** {@inheritDoc} */
657    @Override
658    public void disposeMe() {
659    }
660
661
662    private static class ExpressionEntry {
663        private String _socketSystemName;
664        private final FemaleDigitalExpressionSocket _socket;
665
666        private ExpressionEntry(FemaleDigitalExpressionSocket socket, String socketSystemName) {
667            _socketSystemName = socketSystemName;
668            _socket = socket;
669        }
670
671        private ExpressionEntry(FemaleDigitalExpressionSocket socket) {
672            this._socket = socket;
673        }
674
675    }
676
677    private static class ActionEntry {
678        private String _socketSystemName;
679        private final FemaleDigitalActionSocket _socket;
680
681        private ActionEntry(FemaleDigitalActionSocket socket, String socketSystemName) {
682            _socketSystemName = socketSystemName;
683            _socket = socket;
684        }
685
686        private ActionEntry(FemaleDigitalActionSocket socket) {
687            this._socket = socket;
688        }
689
690    }
691
692
693    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(Sequence.class);
694
695}