/** * 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 static org.kaazing.k3po.lang.internal.ast.util.AstUtil.equivalent; import java.util.HashMap; import java.util.List; import java.util.Map; import org.kaazing.k3po.driver.internal.behavior.visitor.AssociateStreamsVisitor.State; import org.kaazing.k3po.lang.internal.RegionInfo; 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.AstRegionException; 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 AssociateStreamsVisitor implements AstNode.Visitor<AstScriptNode, State> { public enum ReadWriteState { NONE, READ, WRITE } public static final class State { private List<AstStreamNode> streams; private List<AstStreamableNode> streamables; private Map<String, AstAcceptNode> accepts = new HashMap<>(); private String implicitAcceptName; private int implicitAcceptCount; } @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); } // remove all associated streams from the main script // But this appears to be a NOOP. Acceptables are not added as streams! for (AstAcceptNode accept : state.accepts.values()) { newScript.getStreams().removeAll(accept.getAcceptables()); } return newScript; } @Override public AstScriptNode visit(AstPropertyNode propertyNode, State state) throws Exception { return null; } @Override public AstScriptNode visit(AstAcceptNode acceptNode, State state) throws Exception { AstAcceptNode newAcceptNode = new AstAcceptNode(acceptNode); String acceptName = acceptNode.getAcceptName(); String newAcceptName = acceptName != null ? acceptName : String.format("~accept~%d", ++state.implicitAcceptCount); state.accepts.put(newAcceptName, newAcceptNode); state.implicitAcceptName = newAcceptName; state.streamables = newAcceptNode.getStreamables(); for (AstStreamableNode streamable : acceptNode.getStreamables()) { streamable.accept(this, state); } for (AstAcceptableNode acceptable : acceptNode.getAcceptables()) { assert equivalent(acceptName, acceptable.getAcceptName()); acceptable.accept(this, state); } state.streams.add(newAcceptNode); return null; } @Override public AstScriptNode visit(AstAcceptableNode acceptableNode, State state) throws Exception { AstAcceptableNode newAcceptableNode = new AstAcceptableNode(); newAcceptableNode.setRegionInfo(acceptableNode.getRegionInfo()); String acceptName = acceptableNode.getAcceptName(); if (acceptName == null) { acceptName = state.implicitAcceptName; } AstAcceptNode acceptNode = state.accepts.get(acceptName); if (acceptNode == null) { RegionInfo regionInfo = acceptableNode.getRegionInfo(); throw new AstRegionException("Accept not found for accepted").initRegionInfo(regionInfo); } state.streamables = newAcceptableNode.getStreamables(); for (AstStreamableNode streamable : acceptableNode.getStreamables()) { streamable.accept(this, state); } // associate accepted stream to corresponding accept acceptNode.getAcceptables().add(newAcceptableNode); return null; } @Override public AstScriptNode visit(AstConnectNode connectNode, State state) throws Exception { 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 { state.streamables.add(node); return null; } @Override public AstScriptNode visit(AstDisconnectNode node, State state) throws Exception { state.streamables.add(node); return null; } @Override public AstScriptNode visit(AstUnbindNode node, State state) throws Exception { state.streamables.add(node); return null; } @Override public AstScriptNode visit(AstCloseNode node, State state) throws Exception { state.streamables.add(node); return null; } @Override public AstScriptNode visit(AstAbortNode node, State state) throws Exception { state.streamables.add(node); 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(AstAbortedNode node, State state) throws Exception { state.streamables.add(node); return null; } @Override public AstScriptNode visit(AstOpenedNode openedNode, State state) throws Exception { state.streamables.add(openedNode); return null; } @Override public AstScriptNode visit(AstBoundNode boundNode, State state) throws Exception { state.streamables.add(boundNode); return null; } @Override public AstScriptNode visit(AstConnectedNode connectedNode, State state) throws Exception { state.streamables.add(connectedNode); return null; } @Override public AstScriptNode visit(AstReadValueNode node, State state) throws Exception { state.streamables.add(node); return null; } @Override public AstScriptNode visit(AstDisconnectedNode disconnectedNode, State state) throws Exception { state.streamables.add(disconnectedNode); return null; } @Override public AstScriptNode visit(AstUnboundNode unboundNode, State state) throws Exception { state.streamables.add(unboundNode); return null; } @Override public AstScriptNode visit(AstClosedNode closedNode, State state) throws Exception { state.streamables.add(closedNode); return null; } @Override public AstScriptNode visit(AstReadConfigNode node, State state) throws Exception { state.streamables.add(node); return null; } @Override public AstScriptNode visit(AstWriteConfigNode node, State state) throws Exception { state.streamables.add(node); return null; } @Override public AstScriptNode visit(AstReadClosedNode node, State state) throws Exception { state.streamables.add(node); return null; } @Override public AstScriptNode visit(AstWriteCloseNode node, State state) throws Exception { state.streamables.add(node); return null; } @Override public AstScriptNode visit(AstWriteFlushNode node, State state) throws Exception { 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; } }