refactor to DFA

refactor to DFA
This commit is contained in:
coderfengyun 2014-04-15 10:03:40 +08:00
parent 161d0af167
commit 131812d917
3 changed files with 191 additions and 81 deletions

View File

@ -1,10 +1,9 @@
package org.bench4q.agent.scenario.dfa;
import java.util.LinkedList;
import java.util.List;
import org.bench4q.agent.scenario.dfa.ParamPart.ParamPartType;
import org.bench4q.agent.utils.ParameterParser;
import org.bench4q.agent.scenario.dfa.State.LiteralState;
public class DFA {
/**
@ -17,90 +16,22 @@ public class DFA {
*/
public static List<ParamPart> resolveMaltipleParamPart(
String paramOriginValue) {
List<ParamPart> result = new LinkedList<ParamPart>();
StringBuilder buf1 = new StringBuilder(), bufForVaribleOfContextCall = new StringBuilder();
int state = 0;
State state = State.getLiteralState();
try {
for (int i = 0, len = paramOriginValue.length(); i < len; i++) {
state = dfaInside(paramOriginValue, result, buf1,
bufForVaribleOfContextCall, state,
paramOriginValue.charAt(i));
for (char c : paramOriginValue.toCharArray()) {
state = state.digest(c);
}
if (state == 0 && buf1.length() > 0) {
result.add(new ParamPart(ParamPartType.STRING, buf1.toString(),
null, null));
if (state instanceof LiteralState
&& state.getBufferCommon().length() > 0) {
state.addResult(new ParamPart(ParamPartType.STRING, state
.getBufferCommon().toString(), null, null));
}
} catch (Exception e) {
result.clear();
result.add(new ParamPart(ParamPartType.STRING, paramOriginValue,
null, null));
state.clearResult();
state.addResult(new ParamPart(ParamPartType.STRING,
paramOriginValue, null, null));
}
return result;
return state.getResult();
}
private static int dfaInside(String paramOriginValue,
List<ParamPart> result, StringBuilder buf1, StringBuilder buf2,
int state, char c) {
switch (state) {
case 0: /* Literal string */
switch (c) {
case '$':
if (buf1.length() > 0) {
result.add(new ParamPart(ParamPartType.STRING, buf1
.toString(), null, null));
buf1.setLength(0);
}
return 2;
default:
buf1.append(c);
return state;
}
case 2: /* Context call */
switch (c) {
case '#':
result.add(new ParamPart(ParamPartType.SESSION_ID, null, null,
null));
return 0;
case '{':
return 3;
case '$': /* $$ is the escape sequence for $ */
buf1.append(c);
return 0;
default: /* Syntax error */
throw new RuntimeException("can't digest this tocken");
}
case 3: /* plugInId */
switch (c) {
case ':':
return 4;
case '{':
throw new RuntimeException("can't digest this tocken");
case '}': /* no ':' means system property */
result.add(new ParamPart(ParamPartType.PROPERTY, null, null,
ParameterParser.unescape(buf1.toString())));
buf1.setLength(0);
return 0;
default:
buf1.append(c);
return state;
}
case 4: /* Variable */
switch (c) {
case '}':
result.add(new ParamPart(ParamPartType.CONTEXT_CALL, null,
ParameterParser.unescape(buf1.toString()),
ParameterParser.unescape(buf2.toString())));
buf1.setLength(0);
buf2.setLength(0);
return 0;
case '{': /* Syntax error */
throw new RuntimeException("can't digest this tocken");
default:
buf2.append(c);
return state;
}
}
return state;
}
}

View File

@ -0,0 +1,158 @@
package org.bench4q.agent.scenario.dfa;
import java.util.ArrayList;
import java.util.List;
import org.bench4q.agent.scenario.dfa.ParamPart.ParamPartType;
import org.bench4q.agent.utils.ParameterParser;
public abstract class State {
private StringBuilder bufferCommon;
private StringBuilder bufferForContextVariable;
private List<ParamPart> result;
StringBuilder getBufferCommon() {
return bufferCommon;
}
private void setBufferCommon(StringBuilder bufferCommon) {
this.bufferCommon = bufferCommon;
}
StringBuilder getBufferForContextVariable() {
return bufferForContextVariable;
}
private void setBufferForContextVariable(
StringBuilder bufferForContextVariable) {
this.bufferForContextVariable = bufferForContextVariable;
}
public List<ParamPart> getResult() {
return result;
}
private void setResult(List<ParamPart> result) {
this.result = result;
}
public State() {
this.setBufferCommon(new StringBuilder());
this.setBufferForContextVariable(new StringBuilder());
this.setResult(new ArrayList<ParamPart>());
}
protected State convertTo(Class<? extends State> targetState) {
try {
State result = targetState.newInstance();
result.setBufferCommon(this.getBufferCommon());
result.setBufferForContextVariable(this
.getBufferForContextVariable());
result.setResult(this.getResult());
return result;
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public abstract State digest(char c);
public void addResult(ParamPart paramPart) {
this.getResult().add(paramPart);
}
public void clearResult() {
this.getResult().clear();
}
public static State getLiteralState() {
return new LiteralState();
}
public static class LiteralState extends State {
@Override
public State digest(char c) {
if (c == '$') {
if (this.getBufferCommon().length() > 0) {
this.getResult().add(
new ParamPart(ParamPartType.STRING, this
.getBufferCommon().toString(), null, null));
this.getBufferCommon().setLength(0);
}
return convertTo(ContextState.class);
}
this.getBufferCommon().append(c);
return this;
}
}
public static class ContextState extends State {
@Override
public State digest(char c) {
switch (c) {
case '#':
this.getResult().add(
new ParamPart(ParamPartType.SESSION_ID, null, null,
null));
return convertTo(LiteralState.class);
case '{':
return convertTo(PluginIdState.class);
case '$': /* $$ is the escape sequence for $ */
this.getBufferCommon().append(c);
return convertTo(LiteralState.class);
default: /* Syntax error */
throw new RuntimeException("can't digest this tocken");
}
}
}
public static class PluginIdState extends State {
@Override
public State digest(char c) {
switch (c) {
case ':':
return convertTo(VariableState.class);
case '{':
throw new RuntimeException("can't digest this tocken");
case '}': /* no ':' means system property */
this.getResult().add(
new ParamPart(ParamPartType.PROPERTY, null, null,
ParameterParser.unescape(this.getBufferCommon()
.toString())));
this.getBufferCommon().setLength(0);
return convertTo(LiteralState.class);
default:
this.getBufferCommon().append(c);
return this;
}
}
}
public static class VariableState extends State {
@Override
public State digest(char c) {
switch (c) {
case '}':
this.getResult().add(
new ParamPart(ParamPartType.CONTEXT_CALL, null,
ParameterParser.unescape(this.getBufferCommon()
.toString()), ParameterParser
.unescape(this
.getBufferForContextVariable()
.toString())));
this.getBufferCommon().setLength(0);
this.getBufferForContextVariable().setLength(0);
return convertTo(LiteralState.class);
case '{': /* Syntax error */
throw new RuntimeException("can't digest this tocken");
default:
this.getBufferForContextVariable().append(c);
return this;
}
}
}
}

View File

@ -15,6 +15,10 @@ public class Test_DFA {
private static final String TEST_CASE3 = "${csvProvider0:userName}$#okOrNot";
private static final String TEST_CASE4 = "${csvProvider0:userName}$#okOrNot${file.separator}";
private static final String TEST_CASE_NOTSUPPORT1 = "${{abc";
private static final String TEST_CASE_NOTSUPPORT2 = "${csvProvider0:adc{";
private static final String TEST_CASE_NOTSUPPORT3 = "$abc";
@Test
public void test_resolveMaltipleParamPart_WithOnePluginIdVariable() {
List<ParamPart> result = DFA.resolveMaltipleParamPart(TEST_CASE);
@ -91,4 +95,21 @@ public class Test_DFA {
assertEquals("file.separator", result.get(3)
.getVariableForContextCallAndProperty());
}
@Test
public void test_resolveMaltipleParamPart_WithTheNotSupportOnes() {
test_ForUnsupportOnes(TEST_CASE_NOTSUPPORT1);
test_ForUnsupportOnes(TEST_CASE_NOTSUPPORT2);
test_ForUnsupportOnes(TEST_CASE_NOTSUPPORT3);
}
private void test_ForUnsupportOnes(String testcaseUnsupport) {
List<ParamPart> result = DFA
.resolveMaltipleParamPart(testcaseUnsupport);
assertEquals(1, result.size());
assertEquals(ParamPartType.STRING, result.get(0).getType());
assertNull(result.get(0).getPluginIdForContextCallType());
assertNull(result.get(0).getVariableForContextCallAndProperty());
assertEquals(testcaseUnsupport, result.get(0).getContentForStringType());
}
}