/** * Copyright 2007-2015, Kaazing Corporation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.kaazing.k3po.driver.internal.behavior.visitor; import java.util.List; import org.kaazing.k3po.driver.internal.behavior.visitor.InjectEventsVisitor.State; import org.kaazing.k3po.lang.internal.ast.AstAbortNode; import org.kaazing.k3po.lang.internal.ast.AstAbortedNode; import org.kaazing.k3po.lang.internal.ast.AstAcceptNode; import org.kaazing.k3po.lang.internal.ast.AstAcceptableNode; import org.kaazing.k3po.lang.internal.ast.AstBoundNode; import org.kaazing.k3po.lang.internal.ast.AstChildClosedNode; import org.kaazing.k3po.lang.internal.ast.AstChildOpenedNode; import org.kaazing.k3po.lang.internal.ast.AstCloseNode; import org.kaazing.k3po.lang.internal.ast.AstClosedNode; import org.kaazing.k3po.lang.internal.ast.AstConnectNode; import org.kaazing.k3po.lang.internal.ast.AstConnectedNode; import org.kaazing.k3po.lang.internal.ast.AstDisconnectNode; import org.kaazing.k3po.lang.internal.ast.AstDisconnectedNode; import org.kaazing.k3po.lang.internal.ast.AstNode; import org.kaazing.k3po.lang.internal.ast.AstOpenedNode; import org.kaazing.k3po.lang.internal.ast.AstPropertyNode; import org.kaazing.k3po.lang.internal.ast.AstReadAwaitNode; import org.kaazing.k3po.lang.internal.ast.AstReadClosedNode; import org.kaazing.k3po.lang.internal.ast.AstReadConfigNode; import org.kaazing.k3po.lang.internal.ast.AstReadNotifyNode; import org.kaazing.k3po.lang.internal.ast.AstReadOptionNode; import org.kaazing.k3po.lang.internal.ast.AstReadValueNode; import org.kaazing.k3po.lang.internal.ast.AstScriptNode; import org.kaazing.k3po.lang.internal.ast.AstStreamNode; import org.kaazing.k3po.lang.internal.ast.AstStreamableNode; import org.kaazing.k3po.lang.internal.ast.AstUnbindNode; import org.kaazing.k3po.lang.internal.ast.AstUnboundNode; import org.kaazing.k3po.lang.internal.ast.AstWriteAwaitNode; import org.kaazing.k3po.lang.internal.ast.AstWriteCloseNode; import org.kaazing.k3po.lang.internal.ast.AstWriteConfigNode; import org.kaazing.k3po.lang.internal.ast.AstWriteFlushNode; import org.kaazing.k3po.lang.internal.ast.AstWriteNotifyNode; import org.kaazing.k3po.lang.internal.ast.AstWriteOptionNode; import org.kaazing.k3po.lang.internal.ast.AstWriteValueNode; public class InjectEventsVisitor implements AstNode.Visitor<AstScriptNode, State> { public enum ConnectivityState { NONE, OPENED, BOUND, CONNECTED, DISCONNECTED, UNBOUND, CLOSED } public static final class State { private List<AstStreamNode> streams; private List<AstStreamableNode> streamables; private ConnectivityState connectivityState; } @Override public AstScriptNode visit(AstScriptNode script, State state) throws Exception { AstScriptNode newScript = new AstScriptNode(); newScript.setRegionInfo(script.getRegionInfo()); newScript.getProperties().addAll(script.getProperties()); state.streams = newScript.getStreams(); for (AstStreamNode stream : script.getStreams()) { stream.accept(this, state); } return newScript; } @Override public AstScriptNode visit(AstPropertyNode propertyNode, State state) throws Exception { return null; } @Override public AstScriptNode visit(AstAcceptNode acceptNode, State state) throws Exception { state.connectivityState = ConnectivityState.NONE; AstAcceptNode newAcceptNode = new AstAcceptNode(acceptNode); state.streamables = newAcceptNode.getStreamables(); for (AstStreamableNode streamable : acceptNode.getStreamables()) { streamable.accept(this, state); } for (AstAcceptableNode acceptable : acceptNode.getAcceptables()) { acceptable.accept(this, state); } state.streams.add(newAcceptNode); return null; } @Override public AstScriptNode visit(AstAcceptableNode acceptableNode, State state) throws Exception { state.connectivityState = ConnectivityState.NONE; AstAcceptableNode newAcceptableNode = new AstAcceptableNode(); newAcceptableNode.setRegionInfo(acceptableNode.getRegionInfo()); newAcceptableNode.setAcceptName(acceptableNode.getAcceptName()); state.streamables = newAcceptableNode.getStreamables(); for (AstStreamableNode streamable : acceptableNode.getStreamables()) { streamable.accept(this, state); } state.streams.add(newAcceptableNode); return null; } @Override public AstScriptNode visit(AstConnectNode connectNode, State state) throws Exception { state.connectivityState = ConnectivityState.NONE; AstConnectNode newConnectNode = new AstConnectNode(connectNode); state.streamables = newConnectNode.getStreamables(); for (AstStreamableNode streamable : connectNode.getStreamables()) { streamable.accept(this, state); } state.streams.add(newConnectNode); return null; } @Override public AstScriptNode visit(AstReadAwaitNode node, State state) throws Exception { state.streamables.add(node); return null; } @Override public AstScriptNode visit(AstWriteAwaitNode node, State state) throws Exception { state.streamables.add(node); return null; } @Override public AstScriptNode visit(AstReadNotifyNode node, State state) throws Exception { state.streamables.add(node); return null; } @Override public AstScriptNode visit(AstWriteNotifyNode node, State state) throws Exception { state.streamables.add(node); return null; } @Override public AstScriptNode visit(AstWriteValueNode node, State state) throws Exception { switch (state.connectivityState) { case CONNECTED: state.streamables.add(node); break; default: throw new IllegalStateException("Unexpected write before connected"); } return null; } @Override public AstScriptNode visit(AstDisconnectNode node, State state) throws Exception { switch (state.connectivityState) { case CONNECTED: state.streamables.add(node); break; default: throw new IllegalStateException("Unexpected disconnect before connected"); } return null; } @Override public AstScriptNode visit(AstUnbindNode node, State state) throws Exception { switch (state.connectivityState) { case DISCONNECTED: state.streamables.add(node); break; default: throw new IllegalStateException("Unexpected unbind before disconnected"); } return null; } @Override public AstScriptNode visit(AstCloseNode node, State state) throws Exception { switch (state.connectivityState) { case CONNECTED: state.streamables.add(node); break; default: throw new IllegalStateException("Unexpected close before connected"); } return null; } @Override public AstScriptNode visit(AstAbortNode node, State state) throws Exception { switch (state.connectivityState) { case CONNECTED: state.streamables.add(node); break; default: throw new IllegalStateException("Unexpected abort before connected"); } return null; } @Override public AstScriptNode visit(AstChildOpenedNode childOpenedNode, State state) throws Exception { state.streamables.add(childOpenedNode); return null; } @Override public AstScriptNode visit(AstChildClosedNode childClosedNode, State state) throws Exception { state.streamables.add(childClosedNode); return null; } @Override public AstScriptNode visit(AstOpenedNode openedNode, State state) throws Exception { switch (state.connectivityState) { case NONE: state.connectivityState = ConnectivityState.OPENED; state.streamables.add(openedNode); break; default: throw new IllegalStateException("Unexpected event: opened"); } return null; } @Override public AstScriptNode visit(AstBoundNode boundNode, State state) throws Exception { switch (state.connectivityState) { case NONE: AstOpenedNode openedNode = new AstOpenedNode(); openedNode.setRegionInfo(boundNode.getRegionInfo()); openedNode.accept(this, state); break; default: break; } // The above switch might have changed the connectivity state, so // we switch on it again switch (state.connectivityState) { case OPENED: state.streamables.add(boundNode); state.connectivityState = ConnectivityState.BOUND; break; default: throw new IllegalStateException("Unexpected event: bound"); } return null; } @Override public AstScriptNode visit(AstConnectedNode connectedNode, State state) throws Exception { switch (state.connectivityState) { case NONE: case OPENED: AstBoundNode boundNode = new AstBoundNode(); boundNode.setRegionInfo(connectedNode.getRegionInfo()); boundNode.accept(this, state); break; default: break; } // The above switch might have changed the connectivity state, so // we switch on it again switch (state.connectivityState) { case BOUND: state.streamables.add(connectedNode); state.connectivityState = ConnectivityState.CONNECTED; break; default: throw new IllegalStateException("Unexpected event: connected"); } return null; } @Override public AstScriptNode visit(AstReadValueNode node, State state) throws Exception { switch (state.connectivityState) { case CONNECTED: state.streamables.add(node); break; default: throw new IllegalStateException("Unexpected read before connected"); } return null; } @Override public AstScriptNode visit(AstDisconnectedNode disconnectedNode, State state) throws Exception { switch (state.connectivityState) { case CONNECTED: state.streamables.add(disconnectedNode); state.connectivityState = ConnectivityState.DISCONNECTED; break; default: throw new IllegalStateException("Unexpected event: disconnected"); } return null; } @Override public AstScriptNode visit(AstUnboundNode unboundNode, State state) throws Exception { switch (state.connectivityState) { case CONNECTED: AstDisconnectedNode disconnectedNode = new AstDisconnectedNode(); disconnectedNode.setRegionInfo(unboundNode.getRegionInfo()); disconnectedNode.accept(this, state); break; default: break; } switch (state.connectivityState) { case DISCONNECTED: state.streamables.add(unboundNode); state.connectivityState = ConnectivityState.UNBOUND; break; default: throw new IllegalStateException("Unexpected event: unbound"); } return null; } @Override public AstScriptNode visit(AstClosedNode closedNode, State state) throws Exception { switch (state.connectivityState) { case CONNECTED: case DISCONNECTED: AstUnboundNode unboundNode = new AstUnboundNode(); unboundNode.setRegionInfo(closedNode.getRegionInfo()); unboundNode.accept(this, state); break; default: break; } switch (state.connectivityState) { case UNBOUND: state.streamables.add(closedNode); state.connectivityState = ConnectivityState.CLOSED; break; default: throw new IllegalStateException("Unexpected event: closed"); } return null; } @Override public AstScriptNode visit(AstAbortedNode node, State state) throws Exception { switch (state.connectivityState) { case CONNECTED: state.streamables.add(node); break; default: throw new IllegalStateException("Unexpected aborted before connected"); } return null; } @Override public AstScriptNode visit(AstReadConfigNode node, State state) throws Exception { switch (state.connectivityState) { case CONNECTED: break; default: throw new IllegalStateException(String.format("Unexpected \"%s\" before connected", node)); } state.streamables.add(node); return null; } @Override public AstScriptNode visit(AstWriteConfigNode node, State state) throws Exception { switch (state.connectivityState) { case CONNECTED: break; default: throw new IllegalStateException(String.format("Unexpected \"%s\" before connected", node)); } state.streamables.add(node); return null; } @Override public AstScriptNode visit(AstReadClosedNode node, State state) throws Exception { switch (state.connectivityState) { case CONNECTED: break; default: throw new IllegalStateException(String.format("Unexpected \"%s\" before connected", node)); } state.streamables.add(node); return null; } @Override public AstScriptNode visit(AstWriteCloseNode node, State state) throws Exception { switch (state.connectivityState) { case CONNECTED: break; default: throw new IllegalStateException(String.format("Unexpected \"%s\" before connected", node)); } state.streamables.add(node); return null; } @Override public AstScriptNode visit(AstWriteFlushNode node, State state) throws Exception { switch (state.connectivityState) { case CONNECTED: break; default: throw new IllegalStateException(String.format("Unexpected \"%s\" before connected", node)); } state.streamables.add(node); return null; } @Override public AstScriptNode visit(AstReadOptionNode node, State state) throws Exception { state.streamables.add(node); return null; } @Override public AstScriptNode visit(AstWriteOptionNode node, State state) throws Exception { state.streamables.add(node); return null; } }