diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleInstruction.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleInstruction.java
index fcce42b2a..2d6c7a136 100644
--- a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleInstruction.java
+++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleInstruction.java
@@ -93,34 +93,6 @@ public class GuacamoleInstruction {
this.args = Collections.unmodifiableList(args);
}
- /**
- * Creates a new GuacamoleInstruction having the given opcode, list of
- * argument values, and underlying protocol representation. The list given
- * will be used to back the internal list of arguments and the list
- * returned by {@link #getArgs()}. The provided protocol representation
- * will be used to back the internal protocol representation and values
- * returned by {@link #toCharArray()} and {@link #toString()}.
- *
- * Neither the provided argument list nor the provided protocol
- * representation may be modified in any way after being provided to this
- * constructor. Doing otherwise will result in undefined behavior.
- *
- * @param opcode
- * The opcode of the instruction to create.
- *
- * @param args
- * The list of argument values to provide in the new instruction, if
- * any.
- *
- * @param raw
- * The underlying representation of this instruction as would be sent
- * over the network via the Guacamole protocol.
- */
- public GuacamoleInstruction(String opcode, List args, char[] raw) {
- this(opcode, args);
- this.rawChars = raw;
- }
-
/**
* Returns the opcode associated with this GuacamoleInstruction.
*
diff --git a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleParser.java b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleParser.java
index 378b471cc..dbbba2565 100644
--- a/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleParser.java
+++ b/guacamole-common/src/main/java/org/apache/guacamole/protocol/GuacamoleParser.java
@@ -21,6 +21,7 @@ package org.apache.guacamole.protocol;
import java.util.Arrays;
import java.util.Iterator;
+import java.util.List;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleServerException;
@@ -120,6 +121,62 @@ public class GuacamoleParser implements Iterator {
*/
private int rawInstructionOffset = 0;
+ /**
+ * GuacamoleInstruction that efficiently exposes the originally parsed
+ * character buffer for calls to {@link #toString()} and {@link #toCharArray()}
+ * rather than regenerate the buffer from scratch.
+ */
+ private static class ParsedGuacamoleInstruction extends GuacamoleInstruction {
+
+ /**
+ * The original data parsed to produce this GuacamoleInstruction.
+ */
+ private final char[] rawChars;
+
+ /**
+ * A String containing the original data parsed to produce this
+ * GuacamoleInstruction.
+ */
+ private String rawString = null;
+
+ /**
+ * Creates a new GuacamoleInstruction that efficiently exposes the
+ * originally parsed character buffer rather than regenerating that
+ * buffer from scratch for {@link #toString()} and {@link #toCharArray()}.
+ *
+ * @param opcode
+ * The opcode of the instruction to create.
+ *
+ * @param args
+ * The list of argument values to provide in the new instruction, if
+ * any.
+ *
+ * @param raw
+ * The underlying representation of this instruction as would be sent
+ * over the network via the Guacamole protocol.
+ */
+ public ParsedGuacamoleInstruction(String opcode, List args, char[] raw) {
+ super(opcode, args);
+ this.rawChars = raw;
+ }
+
+ @Override
+ public String toString() {
+
+ if (rawString == null)
+ rawString = new String(rawChars);
+
+ return rawString;
+
+ }
+
+ @Override
+ public char[] toCharArray() {
+ return rawChars;
+ }
+
+ }
+
/**
* Appends data from the given buffer to the current instruction.
*
@@ -167,7 +224,8 @@ public class GuacamoleParser implements Iterator {
// If the instruction is now complete, we're good to store the
// parsed instruction for future retrieval via next()
if (state == State.COMPLETE) {
- parsedInstruction = new GuacamoleInstruction(elements[0], Arrays.asList(elements).subList(1, elementCount),
+ parsedInstruction = new ParsedGuacamoleInstruction(elements[0],
+ Arrays.asList(elements).subList(1, elementCount),
Arrays.copyOf(rawInstruction, rawInstructionOffset));
rawInstructionOffset = 0;
}