/**
* 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 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;
// Note: this is no longer injecting, just validating, as injection is now generalized
public class ValidateStreamsVisitor implements AstNode.Visitor<AstScriptNode, ValidateStreamsVisitor.State> {
public enum StreamState {
// @formatter:off
OPEN,
CLOSED,
// @formatter:on
}
public static final class State {
private StreamState readState;
private StreamState writeState;
public State() {
readState = StreamState.OPEN;
writeState = StreamState.OPEN;
}
}
@Override
public AstScriptNode visit(AstScriptNode script, State state) throws Exception {
for (AstStreamNode stream : script.getStreams()) {
stream.accept(this, state);
}
return null;
}
@Override
public AstScriptNode visit(AstPropertyNode propertyNode, State state) throws Exception {
return null;
}
@Override
public AstScriptNode visit(AstAcceptNode acceptNode, State state) throws Exception {
for (AstStreamableNode streamable : acceptNode.getStreamables()) {
streamable.accept(this, state);
}
for (AstAcceptableNode acceptable : acceptNode.getAcceptables()) {
state.readState = StreamState.OPEN;
state.writeState = StreamState.OPEN;
acceptable.accept(this, state);
}
return null;
}
@Override
public AstScriptNode visit(AstConnectNode connectNode, State state) throws Exception {
state.writeState = StreamState.OPEN;
state.readState = StreamState.OPEN;
for (AstStreamableNode streamable : connectNode.getStreamables()) {
streamable.accept(this, state);
}
return null;
}
@Override
public AstScriptNode visit(AstReadConfigNode node, State state) throws Exception {
switch (state.readState) {
case OPEN:
break;
default:
throw new IllegalStateException(String.format("Unexpected read config event (%s) while reading in state %s", node
.toString().trim(), state.readState));
}
return null;
}
@Override
public AstScriptNode visit(AstWriteConfigNode node, State state) throws Exception {
switch (state.writeState) {
case OPEN:
break;
default:
throw new IllegalStateException(String.format("Unexpected write config command (%s) while writing in state %s", node
.toString().trim(), state.writeState));
}
return null;
}
@Override
public AstScriptNode visit(AstReadClosedNode node, State state) throws Exception {
switch (state.readState) {
case OPEN:
state.readState = StreamState.CLOSED;
break;
default:
throw new IllegalStateException(unexpectedReadEvent(node, state));
}
return null;
}
@Override
public AstScriptNode visit(AstWriteCloseNode node, State state) throws Exception {
switch (state.writeState) {
case OPEN:
state.writeState = StreamState.CLOSED;
break;
default:
throw new IllegalStateException(unexpectedWriteEvent(node, state));
}
return null;
}
@Override
public AstScriptNode visit(AstAbortNode node, State state) throws Exception {
switch (state.writeState) {
case OPEN:
case CLOSED:
state.writeState = StreamState.CLOSED;
break;
default:
throw new IllegalStateException(unexpectedWriteEvent(node, state));
}
return null;
}
@Override
public AstScriptNode visit(AstAbortedNode node, State state) throws Exception {
switch (state.writeState) {
case OPEN:
state.writeState = StreamState.CLOSED;
break;
default:
throw new IllegalStateException(unexpectedWriteEvent(node, state));
}
return null;
}
@Override
public AstScriptNode visit(AstReadValueNode node, State state) throws Exception {
switch (state.readState) {
case OPEN:
break;
default:
throw new IllegalStateException(unexpectedReadEvent(node, state));
}
return null;
}
@Override
public AstScriptNode visit(AstWriteValueNode node, State state) throws Exception {
switch (state.writeState) {
case OPEN:
break;
default:
throw new IllegalStateException(unexpectedWriteEvent(node, state));
}
return null;
}
@Override
public AstScriptNode visit(AstWriteFlushNode node, State state) throws Exception {
switch (state.writeState) {
case OPEN:
break;
default:
throw new IllegalStateException(unexpectedWriteEvent(node, state));
}
return null;
}
@Override
public AstScriptNode visit(AstAcceptableNode acceptableNode, State state) throws Exception {
for (AstStreamableNode streamable : acceptableNode.getStreamables()) {
streamable.accept(this, state);
}
return null;
}
@Override
public AstScriptNode visit(AstDisconnectNode node, State state) throws Exception {
return null;
}
@Override
public AstScriptNode visit(AstUnbindNode node, State state) throws Exception {
return null;
}
@Override
public AstScriptNode visit(AstCloseNode node, State state) throws Exception {
return null;
}
@Override
public AstScriptNode visit(AstChildOpenedNode node, State state) throws Exception {
return null;
}
@Override
public AstScriptNode visit(AstChildClosedNode node, State state) throws Exception {
return null;
}
@Override
public AstScriptNode visit(AstOpenedNode node, State state) throws Exception {
return null;
}
@Override
public AstScriptNode visit(AstBoundNode node, State state) throws Exception {
return null;
}
@Override
public AstScriptNode visit(AstConnectedNode node, State state) throws Exception {
return null;
}
@Override
public AstScriptNode visit(AstDisconnectedNode node, State state) throws Exception {
return null;
}
@Override
public AstScriptNode visit(AstUnboundNode node, State state) throws Exception {
return null;
}
@Override
public AstScriptNode visit(AstClosedNode node, State state) throws Exception {
switch (state.readState) {
case OPEN:
state.readState = StreamState.CLOSED;
break;
case CLOSED:
break;
default:
throw new IllegalStateException(unexpectedReadEvent(node, state));
}
switch (state.writeState) {
case OPEN:
state.writeState = StreamState.CLOSED;
break;
case CLOSED:
break;
default:
throw new IllegalStateException(unexpectedWriteEvent(node, state));
}
return null;
}
@Override
public AstScriptNode visit(AstReadAwaitNode node, State state) throws Exception {
return null;
}
@Override
public AstScriptNode visit(AstWriteAwaitNode node, State state) throws Exception {
return null;
}
@Override
public AstScriptNode visit(AstReadNotifyNode node, State state) throws Exception {
return null;
}
@Override
public AstScriptNode visit(AstWriteNotifyNode node, State state) throws Exception {
return null;
}
@Override
public AstScriptNode visit(AstReadOptionNode node, State state) throws Exception {
return null;
}
@Override
public AstScriptNode visit(AstWriteOptionNode node, State state) throws Exception {
return null;
}
private String unexpectedReadEvent(AstNode node, State state) {
return String.format("Unexpected event (%s) while reading in state %s", node
.toString().trim(), state.readState);
}
private String unexpectedWriteEvent(AstNode node, State state) {
return String.format("Unexpected command (%s) while writing in state %s", node
.toString().trim(), state.writeState);
}
}