You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by de...@apache.org on 2013/12/23 10:13:15 UTC
[21/22] CLOUDSTACK-5344: Update to allow rdp console to access
hyper-v vm virtual framebuffer.
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/common/SizeChangeListener.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/SizeChangeListener.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/SizeChangeListener.java
old mode 100644
new mode 100755
index d658d1b..0be8761
--- a/services/console-proxy-rdp/rdpconsole/src/main/java/common/SizeChangeListener.java
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/SizeChangeListener.java
@@ -18,5 +18,5 @@ package common;
public interface SizeChangeListener {
- public void sizeChanged(int width, int height);
+ public void sizeChanged(int width, int height);
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/common/adapter/AwtBellAdapter.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/adapter/AwtBellAdapter.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/adapter/AwtBellAdapter.java
new file mode 100755
index 0000000..7a1feb1
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/adapter/AwtBellAdapter.java
@@ -0,0 +1,76 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 common.adapter;
+
+import java.awt.Toolkit;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+import streamer.Element;
+import streamer.Link;
+import streamer.Pipeline;
+import streamer.PipelineImpl;
+import streamer.debug.FakeSource;
+
+public class AwtBellAdapter extends BaseElement {
+
+ public AwtBellAdapter(String id) {
+ super(id);
+ declarePads();
+ }
+
+ private void declarePads() {
+ inputPads.put(STDIN, null);
+ }
+
+ @Override
+ public void handleData(ByteBuffer buf, Link link) {
+ if (verbose)
+ System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+
+ if (buf == null)
+ return;
+
+ Toolkit.getDefaultToolkit().beep();
+ }
+
+ public String toString() {
+ return "Bell(" + id + ")";
+ }
+
+ /**
+ * Example.
+ */
+ public static void main(String args[]) {
+ System.setProperty("streamer.Element.debug", "true");
+
+ Element source = new FakeSource("source") {
+ {
+ this.incommingBufLength = 0;
+ this.delay = 1000;
+ this.numBuffers = 3;
+ }
+ };
+
+ Element sink = new AwtBellAdapter("sink");
+
+ Pipeline pipeline = new PipelineImpl("test");
+ pipeline.addAndLink(source, sink);
+ pipeline.runMainLoop("source", STDOUT, false, false);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/common/adapter/AwtCanvasAdapter.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/adapter/AwtCanvasAdapter.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/adapter/AwtCanvasAdapter.java
new file mode 100755
index 0000000..788d370
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/adapter/AwtCanvasAdapter.java
@@ -0,0 +1,171 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 common.adapter;
+
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.WritableRaster;
+
+import common.BitmapOrder;
+import common.BitmapRectangle;
+import common.BufferedImageCanvas;
+import common.CopyRectOrder;
+import common.OrderType;
+import common.ScreenDescription;
+
+import rdpclient.rdp.ServerBitmapUpdate;
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+import streamer.Element;
+import streamer.Link;
+import streamer.Order;
+import streamer.Pipeline;
+import streamer.PipelineImpl;
+
+public class AwtCanvasAdapter extends BaseElement {
+
+ protected ScreenDescription screen;
+
+ public AwtCanvasAdapter(String id, BufferedImageCanvas canvas, ScreenDescription screen) {
+ super(id);
+ this.canvas = canvas;
+ this.screen = screen;
+ }
+
+ protected BufferedImageCanvas canvas;
+
+ public String toString() {
+ return "AwtRdpAdapter(" + id + ")";
+ }
+
+ @Override
+ public void handleData(ByteBuffer buf, Link link) {
+ if (verbose)
+ System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+
+ Order order = (Order)buf.getOrder();
+ switch ((OrderType)order.type) {
+
+ case BITMAP_UPDATE:
+ handleBitmap((BitmapOrder)order, buf);
+ break;
+
+ case COPY_RECT:
+ handleCopyRect((CopyRectOrder)order, buf);
+ break;
+
+ default:
+ throw new RuntimeException("Order is not implemented: " + buf + ".");
+ // break;
+ }
+
+ buf.unref();
+ }
+
+ private void handleCopyRect(CopyRectOrder order, ByteBuffer buf) {
+ // TODO Auto-generated method stub
+ // Copy image
+ canvas.getOfflineGraphics().copyArea(order.srcX, order.srcY, order.width, order.height, order.x - order.srcX, order.y - order.srcY);
+
+ // Request update of repainted area
+ canvas.repaint(order.x, order.y, order.width, order.height);
+
+ }
+
+ private void handleBitmap(BitmapOrder order, ByteBuffer buf) {
+ // Draw rectangle on offline buffer
+ BufferedImage image = canvas.getOfflineImage();
+ Graphics2D g = (Graphics2D)image.getGraphics();
+
+ for (BitmapRectangle rectangle : order.rectangles) {
+ // *DEBUG*/System.out.println("["+this+"] DEBUG: Rectangle: " +
+ // rectangle.toString());
+
+ int x = rectangle.x;
+ int y = rectangle.y;
+ int width = rectangle.width;
+ int height = rectangle.height;
+ int bufferWidth = rectangle.bufferWidth;
+ int bufferHeight = rectangle.bufferHeight;
+
+ BufferedImage rectImage;
+ switch (rectangle.colorDepth) {
+ case 8: {
+ rectImage = new BufferedImage(bufferWidth, height, BufferedImage.TYPE_BYTE_INDEXED, screen.colorMap);
+ WritableRaster raster = rectImage.getRaster();
+ raster.setDataElements(0, 0, bufferWidth, bufferHeight, rectangle.bitmapDataStream.toByteArray());
+ break;
+ }
+ case 15: {
+ rectImage = new BufferedImage(bufferWidth, height, BufferedImage.TYPE_USHORT_555_RGB);
+ WritableRaster raster = rectImage.getRaster();
+ raster.setDataElements(0, 0, bufferWidth, bufferHeight, rectangle.bitmapDataStream.toShortArray());
+ break;
+ }
+ case 16: {
+ rectImage = new BufferedImage(bufferWidth, height, BufferedImage.TYPE_USHORT_565_RGB);
+ WritableRaster raster = rectImage.getRaster();
+ raster.setDataElements(0, 0, bufferWidth, bufferHeight, rectangle.bitmapDataStream.toShortArray());
+ break;
+ }
+ case 24:
+ case 32: {
+ rectImage = new BufferedImage(bufferWidth, height, BufferedImage.TYPE_INT_RGB);
+ WritableRaster raster = rectImage.getRaster();
+ raster.setDataElements(0, 0, bufferWidth, bufferHeight, rectangle.bitmapDataStream.toIntLEArray());
+ break;
+ }
+ default:
+ throw new RuntimeException("Unsupported color depth: " + rectangle.colorDepth + ".");
+ }
+
+ g.setClip(x, y, width, height);
+ g.drawImage(rectImage, x, y, null);
+
+ // Request update of repainted area
+ canvas.repaint(x, y, width, height);
+ }
+
+ }
+
+ /**
+ * Example.
+ */
+ public static void main(String args[]) {
+ // System.setProperty("streamer.Link.debug", "true");
+ // System.setProperty("streamer.Element.debug", "true");
+ // System.setProperty("streamer.Pipeline.debug", "true");
+ ByteBuffer packet = new ByteBuffer(new byte[] {0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x10, 0x00,
+ 0x01, 0x04, 0x0a, 0x00, 0x0c, (byte)0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
+
+ Pipeline pipeline = new PipelineImpl("test");
+
+ Element bitmap = new ServerBitmapUpdate("bitmap");
+
+ BufferedImageCanvas canvas = new BufferedImageCanvas(1024, 768);
+ Element adapter = new AwtCanvasAdapter("test", canvas, null) {
+ {
+ verbose = true;
+ }
+ };
+ pipeline.addAndLink(bitmap, adapter);
+
+ bitmap.handleData(packet, null);
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/common/adapter/AwtClipboardAdapter.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/adapter/AwtClipboardAdapter.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/adapter/AwtClipboardAdapter.java
new file mode 100755
index 0000000..ccdabf8
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/adapter/AwtClipboardAdapter.java
@@ -0,0 +1,56 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 common.adapter;
+
+import java.awt.Toolkit;
+import java.awt.datatransfer.StringSelection;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+import streamer.Link;
+
+public class AwtClipboardAdapter extends BaseElement {
+
+ public static final String CLIPBOARD_CONTENT = "content";
+
+ public AwtClipboardAdapter(String id) {
+ super(id);
+ declarePads();
+ }
+
+ private void declarePads() {
+ inputPads.put(STDIN, null);
+ }
+
+ @Override
+ public void handleData(ByteBuffer buf, Link link) {
+ if (verbose)
+ System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+
+ if (buf == null)
+ return;
+
+ String content = (String)buf.getMetadata(CLIPBOARD_CONTENT);
+ StringSelection contents = new StringSelection(content);
+ Toolkit.getDefaultToolkit().getSystemClipboard().setContents(contents, null);
+ }
+
+ public String toString() {
+ return "ClipboardAdapter(" + id + ")";
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/Any.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/Any.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/Any.java
new file mode 100755
index 0000000..dd73560
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/Any.java
@@ -0,0 +1,78 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 common.asn1;
+
+import streamer.ByteBuffer;
+
+/**
+ * Any type. Don't forget to set type.
+ */
+public class Any extends Tag {
+
+ /**
+ * Raw bytes of any value.
+ */
+ public ByteBuffer value;
+
+ public Any(String name) {
+ super(name);
+ }
+
+ @Override
+ public boolean isValueSet() {
+ return value != null;
+ }
+
+ @Override
+ public long calculateLengthOfValuePayload() {
+ return value.length;
+ }
+
+ @Override
+ public void writeTagValuePayload(ByteBuffer buf) {
+ buf.writeBytes(value);
+ }
+
+ @Override
+ public void readTagValue(ByteBuffer buf, BerType typeAndFlags) {
+ long length = buf.readBerLength();
+
+ value = buf.readBytes((int)length);
+ }
+
+ @Override
+ public Tag deepCopy(String suffix) {
+ return new Any(name + suffix).copyFrom(this);
+ }
+
+ @Override
+ public Tag copyFrom(Tag tag) {
+ super.copyFrom(tag);
+ this.tagType = tag.tagType;
+ this.value = new ByteBuffer(((Any)tag).value.toByteArray());
+ return this;
+ }
+
+ @Override
+ public boolean isTypeValid(BerType typeAndFlags, boolean explicit) {
+ if (explicit)
+ return typeAndFlags.tagClass == tagClass && typeAndFlags.constructed && typeAndFlags.typeOrTagNumber == tagNumber;
+ else
+ return true;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/Asn1Constants.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/Asn1Constants.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/Asn1Constants.java
new file mode 100755
index 0000000..6dacd60
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/Asn1Constants.java
@@ -0,0 +1,83 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 common.asn1;
+
+public interface Asn1Constants {
+
+ /**
+ * Universal class type.
+ */
+ public static final int UNIVERSAL_CLASS = 0x00;
+
+ /**
+ * Application class type.
+ */
+ public static final int APPLICATION_CLASS = 0x40;
+
+ public static final int CONTEXT_CLASS = 0x80;
+
+ public static final int PRIVATE_CLASS = 0xC0;
+
+ /**
+ * Constructed type.
+ */
+ public static final int CONSTRUCTED = 0x20;
+
+ /**
+ * Mask to extract class.
+ */
+ public static final int CLASS_MASK = 0xC0;
+
+ /**
+ * Mask to extract type.
+ */
+ public static final int TYPE_MASK = 0x1F;
+
+ public static final int EOF = 0x00;
+ public static final int BOOLEAN = 0x01;
+ /**
+ * Integer primitive.
+ */
+ public static final int INTEGER = 0x02;
+ public static final int BIT_STRING = 0x03;
+ /**
+ * Octet string primitive.
+ */
+ public static final int OCTET_STRING = 0x04;
+ public static final int NULL = 0x05;
+ public static final int OBJECT_ID = 0x06;
+ public static final int REAL = 0x09;
+ public static final int ENUMERATED = 0x0A;
+ /**
+ * Sequence primitive.
+ */
+ public static final int SEQUENCE = 0x10;
+ public static final int SET = 0x11;
+ public static final int NUMERIC_STRING = 0x12;
+ public static final int PRINTABLE_STRING = 0x13;
+ public static final int TELETEX_STRING = 0x14;
+ public static final int VIDEOTEXT_STRING = 0x15;
+ public static final int IA5_STRING = 0x16;
+ public static final int UTCTIME = 0x17;
+ public static final int GENERAL_TIME = 0x18;
+ public static final int GRAPHIC_STRING = 0x19;
+ public static final int VISIBLE_STRING = 0x1A;
+ public static final int GENERAL_STRING = 0x1B;
+
+ public static final int EXTENDED_TYPE = 0x1F;
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/Asn1Integer.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/Asn1Integer.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/Asn1Integer.java
new file mode 100755
index 0000000..fb8715f
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/Asn1Integer.java
@@ -0,0 +1,116 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 common.asn1;
+
+import streamer.ByteBuffer;
+
+/**
+ * Variable length integer.
+ */
+public class Asn1Integer extends Tag {
+
+ public Long value = null;
+
+ public Asn1Integer(String name) {
+ super(name);
+ this.tagType = INTEGER;
+ }
+
+ @Override
+ public void readTagValue(ByteBuffer buf, BerType typeAndFlags) {
+ // Type is already read by parent parser
+
+ long length = buf.readBerLength();
+ if (length > 8)
+ throw new RuntimeException("[" + this + "] ERROR: Integer value is too long: " + length + " bytes. Cannot handle integers more than 8 bytes long. Data: "
+ + buf + ".");
+
+ value = buf.readSignedVarInt((int)length);
+ }
+
+ @Override
+ public Tag deepCopy(String suffix) {
+ return new Asn1Integer(name + suffix).copyFrom(this);
+ }
+
+ @Override
+ public Tag copyFrom(Tag tag) {
+ super.copyFrom(tag);
+ this.value = ((Asn1Integer)tag).value;
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + "= " + value;
+ }
+
+ @Override
+ public long calculateLengthOfValuePayload() {
+ if (value <= 0xff)
+ return 1;
+ if (value <= 0xffFF)
+ return 2;
+ if (value <= 0xffFFff)
+ return 3;
+ if (value <= 0xffFFffFFL)
+ return 4;
+ if (value <= 0xffFFffFFffL)
+ return 5;
+ if (value <= 0xffFFffFFffFFL)
+ return 6;
+ if (value <= 0xffFFffFFffFFffL)
+ return 7;
+
+ return 8;
+ }
+
+ @Override
+ public void writeTagValuePayload(ByteBuffer buf) {
+ long value = this.value.longValue();
+
+ if (value < 0xff) {
+ buf.writeByte((int)value);
+ } else if (value <= 0xffFF) {
+ buf.writeShort((int)value);
+ } else if (value <= 0xffFFff) {
+ buf.writeByte((int)(value >> 16));
+ buf.writeShort((int)value);
+ } else if (value <= 0xffFFffFFL) {
+ buf.writeInt((int)value);
+ } else if (value <= 0xffFFffFFffL) {
+ buf.writeByte((int)(value >> 32));
+ buf.writeInt((int)value);
+ } else if (value <= 0xffFFffFFffFFL) {
+ buf.writeShort((int)(value >> 32));
+ buf.writeInt((int)value);
+ } else if (value <= 0xffFFffFFffFFffL) {
+ buf.writeByte((int)(value >> (32 + 16)));
+ buf.writeShort((int)(value >> 32));
+ buf.writeInt((int)value);
+ } else {
+ buf.writeInt((int)(value >> 32));
+ buf.writeInt((int)value);
+ }
+ }
+
+ @Override
+ public boolean isValueSet() {
+ return value != null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/BerType.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/BerType.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/BerType.java
new file mode 100755
index 0000000..8e53f24
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/BerType.java
@@ -0,0 +1,40 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 common.asn1;
+
+public class BerType {
+
+ public int tagClass;
+ public boolean constructed;
+ public int typeOrTagNumber;
+
+ public BerType() {
+ }
+
+ public BerType(int tagClass, boolean constructed, int typeOrTagNumber) {
+ this.tagClass = tagClass;
+ this.constructed = constructed;
+ this.typeOrTagNumber = typeOrTagNumber;
+ }
+
+ @Override
+ public String toString() {
+ return "BerType [tagClass=" + Tag.tagClassToString(tagClass) + ", constructed=" + constructed + ", type or tag number="
+ + Tag.tagTypeOrNumberToString(tagClass, typeOrTagNumber) + "]";
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/BitString.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/BitString.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/BitString.java
new file mode 100755
index 0000000..3aba5d4
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/BitString.java
@@ -0,0 +1,67 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 common.asn1;
+
+import streamer.ByteBuffer;
+
+public class BitString extends Tag {
+
+ /**
+ * Bit string value.
+ */
+ public ByteBuffer value;
+
+ public BitString(String name) {
+ super(name);
+ this.tagType = BIT_STRING;
+ }
+
+ @Override
+ public boolean isValueSet() {
+ return value != null;
+ }
+
+ @Override
+ public long calculateLengthOfValuePayload() {
+ return value.length;
+ }
+
+ @Override
+ public void writeTagValuePayload(ByteBuffer buf) {
+ buf.writeBytes(value);
+ }
+
+ @Override
+ public void readTagValue(ByteBuffer buf, BerType typeAndFlags) {
+ long length = buf.readBerLength();
+
+ value = buf.readBytes((int)length);
+ }
+
+ @Override
+ public Tag deepCopy(String suffix) {
+ return new BitString(name + suffix).copyFrom(this);
+ }
+
+ @Override
+ public Tag copyFrom(Tag tag) {
+ super.copyFrom(tag);
+ this.value = new ByteBuffer(((BitString)tag).value.toByteArray());
+ return this;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/ObjectID.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/ObjectID.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/ObjectID.java
new file mode 100755
index 0000000..47fdb42
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/ObjectID.java
@@ -0,0 +1,67 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 common.asn1;
+
+import streamer.ByteBuffer;
+
+public class ObjectID extends Tag {
+
+ /**
+ * Raw bytes of encoded OID.
+ */
+ public ByteBuffer value;
+
+ public ObjectID(String name) {
+ super(name);
+ this.tagType = OBJECT_ID;
+ }
+
+ @Override
+ public boolean isValueSet() {
+ return value != null;
+ }
+
+ @Override
+ public long calculateLengthOfValuePayload() {
+ return value.length;
+ }
+
+ @Override
+ public void writeTagValuePayload(ByteBuffer buf) {
+ buf.writeBytes(value);
+ }
+
+ @Override
+ public void readTagValue(ByteBuffer buf, BerType typeAndFlags) {
+ long length = buf.readBerLength();
+
+ value = buf.readBytes((int)length);
+ }
+
+ @Override
+ public Tag deepCopy(String suffix) {
+ return new ObjectID(name + suffix).copyFrom(this);
+ }
+
+ @Override
+ public Tag copyFrom(Tag tag) {
+ super.copyFrom(tag);
+ this.value = new ByteBuffer(((ObjectID)tag).value.toByteArray());
+ return this;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/OctetString.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/OctetString.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/OctetString.java
new file mode 100755
index 0000000..edad843
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/OctetString.java
@@ -0,0 +1,80 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 common.asn1;
+
+import streamer.ByteBuffer;
+
+public class OctetString extends Tag {
+
+ public ByteBuffer value = null;
+
+ public OctetString(String name) {
+ super(name);
+ this.tagType = OCTET_STRING;
+ }
+
+ @Override
+ public void readTagValue(ByteBuffer buf, BerType typeAndFlags) {
+ // Type is already read by parent parser
+
+ long length = buf.readBerLength();
+
+ if (length > buf.length)
+ throw new RuntimeException("BER octet string is too long: " + length + " bytes. Data: " + buf + ".");
+
+ value = buf.readBytes((int)length);
+ }
+
+ @Override
+ public Tag deepCopy(String suffix) {
+ return new OctetString(name + suffix).copyFrom(this);
+ }
+
+ @Override
+ public Tag copyFrom(Tag tag) {
+ super.copyFrom(tag);
+ this.value = ((OctetString)tag).value;
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + "= " + value;
+ }
+
+ @Override
+ public long calculateLengthOfValuePayload() {
+ if (value != null)
+ return value.length;
+ else
+ return 0;
+ }
+
+ @Override
+ public void writeTagValuePayload(ByteBuffer buf) {
+ if (value != null)
+ buf.writeBytes(value);
+ else
+ return;
+ }
+
+ @Override
+ public boolean isValueSet() {
+ return value != null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/Sequence.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/Sequence.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/Sequence.java
new file mode 100755
index 0000000..1676f69
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/Sequence.java
@@ -0,0 +1,143 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 common.asn1;
+
+import java.util.Arrays;
+
+import streamer.ByteBuffer;
+
+/**
+ * One or more elements of different types.
+ *
+ * Only prefixed tags are supported.
+ */
+public class Sequence extends Tag {
+
+ public Tag[] tags;
+
+ public Sequence(String name) {
+ super(name);
+ this.tagType = SEQUENCE;
+ // Sequence and SequenceOf are always encoded as constructed
+ this.constructed = true;
+ }
+
+ @Override
+ public long calculateLengthOfValuePayload() {
+ long sum = 0;
+
+ for (Tag tag : tags) {
+ long tagLength = tag.calculateFullLength();
+ sum += tagLength;
+ }
+
+ return sum;
+ }
+
+ @Override
+ public void writeTagValuePayload(ByteBuffer buf) {
+ // Write tags
+ for (Tag tag : tags) {
+ tag.writeTag(buf);
+ }
+ }
+
+ @Override
+ public void readTagValue(ByteBuffer buf, BerType typeAndFlags) {
+ // Type is already read by parent parser
+
+ long length = buf.readBerLength();
+ if (length > buf.remainderLength())
+ throw new RuntimeException("BER sequence is too long: " + length + " bytes, while buffer remainder length is " + buf.remainderLength() + ". Data: " + buf
+ + ".");
+
+ ByteBuffer value = buf.readBytes((int)length);
+ parseContent(value);
+
+ value.unref();
+ }
+
+ protected void parseContent(ByteBuffer buf) {
+ for (int i = 0; buf.remainderLength() > 0 && i < tags.length; i++) {
+ BerType typeAndFlags = readBerType(buf);
+
+ // If current tag does not match data in buffer
+ if (!tags[i].isTypeValid(typeAndFlags)) {
+
+ // If tag is required, then throw exception
+ if (!tags[i].optional) {
+ throw new RuntimeException("[" + this + "] ERROR: Required tag is missed: " + tags[i] + ". Unexected tag type: " + typeAndFlags + ". Data: " + buf
+ + ".");
+ } else {
+ // One or more tags are omitted, so skip them
+ for (; i < tags.length; i++) {
+ if (tags[i].isTypeValid(typeAndFlags)) {
+ break;
+ }
+ }
+
+ if (i >= tags.length || !tags[i].isTypeValid(typeAndFlags)) {
+ throw new RuntimeException("[" + this + "] ERROR: No more tags to read or skip, but some data still left in buffer. Unexected tag type: "
+ + typeAndFlags + ". Data: " + buf + ".");
+ }
+ }
+ }
+
+ tags[i].readTag(buf, typeAndFlags);
+ }
+
+ }
+
+ @Override
+ public boolean isTypeValid(BerType typeAndFlags, boolean explicit) {
+ if (explicit)
+ return typeAndFlags.tagClass == tagClass && typeAndFlags.constructed && typeAndFlags.typeOrTagNumber == tagNumber;
+ else
+ // Sequences are always encoded as "constructed" in BER.
+ return typeAndFlags.tagClass == UNIVERSAL_CLASS && typeAndFlags.constructed && typeAndFlags.typeOrTagNumber == SEQUENCE;
+ }
+
+ @Override
+ public Tag deepCopy(String suffix) {
+ return new Sequence(name + suffix).copyFrom(this);
+ }
+
+ @Override
+ public Tag copyFrom(Tag tag) {
+ super.copyFrom(tag);
+
+ if (this.tags.length != ((Sequence)tag).tags.length)
+ throw new RuntimeException("Incompatible sequences. This: " + this + ", another: " + tag + ".");
+
+ for (int i = 0; i < tags.length; i++) {
+ this.tags[i].copyFrom(((Sequence)tag).tags[i]);
+ }
+
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + "{" + Arrays.toString(tags) + " }";
+ }
+
+ @Override
+ public boolean isValueSet() {
+ return tags != null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/SequenceOf.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/SequenceOf.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/SequenceOf.java
new file mode 100755
index 0000000..aa4543c
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/SequenceOf.java
@@ -0,0 +1,81 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 common.asn1;
+
+import java.util.ArrayList;
+
+import streamer.ByteBuffer;
+
+/**
+ * Zero or more elements of same type (array).
+ */
+public class SequenceOf extends Sequence {
+
+ /**
+ * Type of this array.
+ */
+ public Tag type;
+
+ /* Values are stored in tags[] variable inherited from Sequence. */
+
+ public SequenceOf(String name) {
+ super(name);
+ }
+
+ protected void parseContent(ByteBuffer buf) {
+ ArrayList<Tag> tagList = new ArrayList<Tag>();
+
+ for (int index = 0; buf.remainderLength() > 0; index++) {
+ // End of array is marked with two zero bytes (0x00 0x00)
+ if (buf.peekUnsignedByte(0) == 0x00 && buf.peekUnsignedByte(1) == 0x00) {
+ break;
+ }
+
+ Tag tag = (Tag)type.deepCopy(index);
+
+ tag.readTag(buf);
+ tagList.add(tag);
+ }
+
+ tags = tagList.toArray(new Tag[tagList.size()]);
+ }
+
+ @Override
+ public Tag deepCopy(String suffix) {
+ return new SequenceOf(name + suffix).copyFrom(this);
+ }
+
+ @Override
+ public Tag copyFrom(Tag tag) {
+ super.copyFrom(tag);
+ // We can create shallow copy of type, because it will not be modified
+ this.type = ((SequenceOf)tag).type;
+
+ this.tags = new Tag[((Sequence)tag).tags.length];
+ for (int i = 0; i < tags.length; i++) {
+ this.tags[i] = ((Sequence)tag).tags[i].deepCopy("");
+ }
+
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + ": " + type;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/Tag.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/Tag.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/Tag.java
new file mode 100755
index 0000000..8fb8c82
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/asn1/Tag.java
@@ -0,0 +1,462 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 common.asn1;
+
+import streamer.ByteBuffer;
+
+public abstract class Tag implements Asn1Constants {
+
+ /**
+ * Name of this tag, for debugging purposes.
+ */
+ public String name = "";
+
+ /**
+ * Is this tag required or optional, for explicit tags only.
+ */
+ public boolean optional = false;
+
+ /**
+ * Tag primitive (e.g. implicit boolean), or constructed (e.g. sequence, or
+ * explicit boolean).
+ */
+ public boolean constructed = false;
+
+ /**
+ * Class of tag, when it is explicit.
+ */
+ public int tagClass = UNIVERSAL_CLASS;
+
+ /**
+ * Tag number (e.g. index in sequence), when tag is explicit.
+ */
+ public int tagNumber = -1;
+
+ /**
+ * Tag type (e.g. INDER), when tag is implicit.
+ */
+ public int tagType = -1;
+
+ /**
+ * If tag is explicit, then it is prefixed with tag number, so it can be
+ * optional or used in unordered set.
+ */
+ public boolean explicit = false;
+
+ public Tag(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Write tag value, with or without prefix.
+ */
+ public void writeTag(ByteBuffer buf) {
+
+ if (!isMustBeWritten())
+ return;
+
+ // Write prefix, when necessary
+ if (explicit) {
+
+ // Write tag prefix, always constructed
+ BerType berTagPrefix = new BerType(tagClass, true, tagNumber);
+ writeBerType(buf, berTagPrefix);
+
+ // Write tag prefix length
+ buf.writeBerLength(calculateLength());
+
+ // Write tag value
+ writeTagValue(buf);
+ } else {
+ // If implicit, just write tag value
+ writeTagValue(buf);
+ }
+ }
+
+ /**
+ * Must return true when value of this tag is set or tag is required, so it
+ * can be written, false otherwise.
+ */
+ public boolean isMustBeWritten() {
+ return !optional || isValueSet();
+ }
+
+ /**
+ * Must return true when value of this tag is set or tag is required, so it
+ * can be written, false otherwise.
+ */
+ public abstract boolean isValueSet();
+
+ /**
+ * Calculate full length of tag, including type (or prefix, when explicit).
+ */
+ public long calculateFullLength() {
+ if (!isMustBeWritten())
+ return 0;
+
+ // Length of value, including type
+ long length = calculateLength();
+
+ if (!explicit) {
+ // Length of tag type and it length
+ length += calculateLengthOfTagTypeOrTagNumber(tagType) + calculateLengthOfLength(length);
+ } else {
+ // Length of tag prefix and it length
+ length += calculateLengthOfTagTypeOrTagNumber(tagNumber) + calculateLengthOfLength(length);
+ }
+
+ return length;
+ }
+
+ /**
+ * Calculate length of tag, including type when explicit, but without length
+ * of prefix (or type, when implicit).
+ */
+ public long calculateLength() {
+ if (!isMustBeWritten())
+ return 0;
+
+ // Length of value
+ long length = calculateLengthOfValuePayload();
+
+ if (explicit) {
+ // Length of tag type and it length
+ length += calculateLengthOfTagTypeOrTagNumber(tagType) + calculateLengthOfLength(length);
+ }
+
+ return length;
+ }
+
+ /**
+ * Calculate length of BER length.
+ */
+ public int calculateLengthOfLength(long length) {
+ if (length < 0)
+ throw new RuntimeException("[" + this + "] ERROR: Length of tag cannot be less than zero: " + length + ".");
+
+ if (length <= 0x7f)
+ return 1;
+ if (length <= 0xff)
+ return 2;
+ if (length <= 0xffFF)
+ return 3;
+ if (length <= 0xffFFff)
+ return 4;
+ if (length <= 0xffFFffFFL)
+ return 5;
+ if (length <= 0xffFFffFFffL)
+ return 6;
+ if (length <= 0xffFFffFFffFFL)
+ return 7;
+ if (length <= 0xffFFffFFffFFffL)
+ return 8;
+
+ return 9;
+ }
+
+ /**
+ * Calculate length of type to tag number. Values less than 31 are encoded
+ * using lower 5 bits of first byte of tag. Values larger than 31 are
+ * indicated by lower 5 bits set to 1 (0x1F, 31), and next bytes are contain
+ * value in network order, where topmost bit of byte (0x80) indicates is value
+ * contains more bytes, i.e. last byte of sequence has this bit set to 0.
+ */
+ public int calculateLengthOfTagTypeOrTagNumber(int tagType) {
+ if (tagType >= EXTENDED_TYPE)
+ throw new RuntimeException("Multibyte tag types are not supported yet.");
+
+ return 1;
+ }
+
+ /**
+ * Calculate length of payload only, without tag prefix, tag type, and
+ * lengths.
+ *
+ * @return
+ */
+ public abstract long calculateLengthOfValuePayload();
+
+ /**
+ * Write tag value only, without prefix.
+ */
+ public void writeTagValue(ByteBuffer buf) {
+
+ // Write type
+ BerType valueType = new BerType(UNIVERSAL_CLASS, constructed, tagType);
+ writeBerType(buf, valueType);
+
+ // Write length
+ long lengthOfPayload = calculateLengthOfValuePayload();
+ buf.writeBerLength(lengthOfPayload);
+
+ // Store cursor to check is calculated length matches length of actual bytes
+ // written
+ int storedCursor = buf.cursor;
+
+ // Write value
+ writeTagValuePayload(buf);
+
+ // Check is calculated length matches length of actual bytes written, to catch errors early
+ int actualLength = buf.cursor - storedCursor;
+ if (actualLength != lengthOfPayload)
+ throw new RuntimeException("[" + this + "] ERROR: Unexpected length of data in buffer. Expected " + lengthOfPayload + " of bytes of payload, but "
+ + actualLength + " bytes are written instead. Data: " + buf + ".");
+ }
+
+ /**
+ * Write tag value only, without prefix, tag type, and length.
+ */
+ public abstract void writeTagValuePayload(ByteBuffer buf);
+
+ /**
+ * Read required tag, i.e. we are 100% sure that byte buffer will contain this
+ * tag, or exception will be thrown otherwise.
+ *
+ * @param buf
+ * buffer with tag data
+ */
+ public void readTag(ByteBuffer buf) {
+ BerType typeAndFlags = readBerType(buf);
+
+ // * DEBUG */System.out.println("Tag, read " + typeAndFlags);
+
+ if (!isTypeValid(typeAndFlags))
+ throw new RuntimeException("[" + this + "] Unexpected type: " + typeAndFlags + ".");
+
+ readTag(buf, typeAndFlags);
+ }
+
+ /**
+ * Read tag when it type is already read.
+ */
+ public void readTag(ByteBuffer buf, BerType typeAndFlags) {
+
+ if (explicit) {
+ long length = buf.readBerLength();
+
+ if (length > buf.length)
+ throw new RuntimeException("BER value is too long: " + length + " bytes. Data: " + buf + ".");
+
+ ByteBuffer value = buf.readBytes((int)length);
+
+ readTagValue(value);
+
+ value.unref();
+ } else {
+
+ readTagValue(buf, typeAndFlags);
+ }
+ }
+
+ /**
+ * Read tag value only, i.e. it prefix is already read.
+ */
+ public void readTagValue(ByteBuffer value) {
+ BerType typeAndFlags = readBerType(value);
+
+ // * DEBUG */System.out.println("Tag, read value " + typeAndFlags);
+
+ if (!isTypeValid(typeAndFlags, false))
+ throw new RuntimeException("[" + this + "] Unexpected type: " + typeAndFlags + ".");
+
+ readTagValue(value, typeAndFlags);
+ }
+
+ /**
+ * Check are tag type and flags valid for this tag.
+ */
+ public final boolean isTypeValid(BerType typeAndFlags) {
+ return isTypeValid(typeAndFlags, explicit);
+ }
+
+ /**
+ * Check are tag type and flags valid for this tag with or without tag prefix.
+ *
+ * @param explicit
+ * if true, then value is wrapped in tag prefix
+ */
+ public boolean isTypeValid(BerType typeAndFlags, boolean explicit) {
+ if (explicit)
+ return typeAndFlags.tagClass == tagClass && typeAndFlags.constructed && typeAndFlags.typeOrTagNumber == tagNumber;
+ else
+ return typeAndFlags.tagClass == UNIVERSAL_CLASS && !typeAndFlags.constructed && typeAndFlags.typeOrTagNumber == this.tagType;
+ }
+
+ @Override
+ public String toString() {
+ return " \nTag [name="
+ + name
+
+ + ((constructed) ? ", constructed=" + constructed : "")
+
+ + (", tagType=" + tagTypeOrNumberToString(UNIVERSAL_CLASS, tagType))
+
+ + ((explicit) ? ", explicit=" + explicit + ", optional=" + optional + ", tagClass=" + tagClassToString(tagClass) + ", tagNumber="
+ + tagTypeOrNumberToString(tagClass, tagNumber) : "") + "]";
+ }
+
+ public static final String tagTypeOrNumberToString(int tagClass, int tagTypeOrNumber) {
+ switch (tagClass) {
+ case UNIVERSAL_CLASS:
+ switch (tagTypeOrNumber) {
+ case EOF:
+ return "EOF";
+ case BOOLEAN:
+ return "BOOLEAN";
+ case INTEGER:
+ return "INTEGER";
+ case BIT_STRING:
+ return "BIT_STRING";
+ case OCTET_STRING:
+ return "OCTET_STRING";
+ case NULL:
+ return "NULL";
+ case OBJECT_ID:
+ return "OBJECT_ID";
+ case REAL:
+ return "REAL";
+ case ENUMERATED:
+ return "ENUMERATED";
+ case SEQUENCE:
+ return "SEQUENCE";
+ case SET:
+ return "SET";
+ case NUMERIC_STRING:
+ return "NUMERIC_STRING";
+ case PRINTABLE_STRING:
+ return "PRINTABLE_STRING";
+ case TELETEX_STRING:
+ return "TELETEX_STRING";
+ case VIDEOTEXT_STRING:
+ return "VIDEOTEXT_STRING";
+ case IA5_STRING:
+ return "IA5_STRING";
+ case UTCTIME:
+ return "UTCTIME";
+ case GENERAL_TIME:
+ return "GENERAL_TIME";
+ case GRAPHIC_STRING:
+ return "GRAPHIC_STRING";
+ case VISIBLE_STRING:
+ return "VISIBLE_STRING";
+ case GENERAL_STRING:
+ return "GENERAL_STRING";
+ case EXTENDED_TYPE:
+ return "EXTENDED_TYPE (multibyte)";
+ default:
+ return "UNKNOWN(" + tagTypeOrNumber + ")";
+
+ }
+
+ default:
+ return "[" + tagTypeOrNumber + "]";
+ }
+ }
+
+ public static final String tagClassToString(int tagClass) {
+ switch (tagClass) {
+ case UNIVERSAL_CLASS:
+ return "UNIVERSAL";
+ case CONTEXT_CLASS:
+ return "CONTEXT";
+ case APPLICATION_CLASS:
+ return "APPLICATION";
+ case PRIVATE_CLASS:
+ return "PRIVATE";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
+ /**
+ * Read BER tag type.
+ */
+ public BerType readBerType(ByteBuffer buf) {
+ int typeAndFlags = buf.readUnsignedByte();
+
+ int tagClass = typeAndFlags & CLASS_MASK;
+
+ boolean constructed = (typeAndFlags & CONSTRUCTED) != 0;
+
+ int type = typeAndFlags & TYPE_MASK;
+ if (type == EXTENDED_TYPE)
+ throw new RuntimeException("Extended tag types/numbers (31+) are not supported yet.");
+
+ return new BerType(tagClass, constructed, type);
+ }
+
+ /**
+ * Write BER tag type.
+ */
+ public void writeBerType(ByteBuffer buf, BerType berType) {
+
+ if (berType.typeOrTagNumber >= EXTENDED_TYPE || berType.typeOrTagNumber < 0)
+ throw new RuntimeException("Extended tag types/numbers (31+) are not supported yet: " + berType + ".");
+
+ if ((berType.tagClass & CLASS_MASK) != berType.tagClass)
+ throw new RuntimeException("Value of BER tag class is out of range: " + berType.tagClass + ". Expected values: " + UNIVERSAL_CLASS + ", " + CONTEXT_CLASS
+ + ", " + APPLICATION_CLASS + ", " + PRIVATE_CLASS + ".");
+
+ int typeAndFlags = berType.tagClass | ((berType.constructed) ? CONSTRUCTED : 0) | berType.typeOrTagNumber;
+
+ buf.writeByte(typeAndFlags);
+ }
+
+ /**
+ * Read tag value only, i.e. it prefix is already read, when value type is
+ * already read.
+ *
+ * @param buf
+ * buffer with tag data
+ */
+ public abstract void readTagValue(ByteBuffer buf, BerType typeAndFlags);
+
+ /**
+ * Create deep copy of this tag with given suffix appended to name.
+ *
+ * @param suffix
+ * suffix to add to tag name, or empty string
+ * @return deep copy of this tag
+ */
+ public abstract Tag deepCopy(String suffix);
+
+ /**
+ * Create deep copy of this tag for array or set.
+ *
+ * @param index
+ * index of element in array or set
+ * @return deep copy of this tag
+ */
+ public Tag deepCopy(int index) {
+ return deepCopy("[" + index + "]");
+ }
+
+ /**
+ * Copy tag values from an other tag, except name.
+ *
+ * @return this
+ */
+ public Tag copyFrom(Tag tag) {
+ this.constructed = tag.constructed;
+ this.explicit = tag.explicit;
+ this.optional = tag.optional;
+ this.tagClass = tag.tagClass;
+ this.tagNumber = tag.tagNumber;
+ return this;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/IncrementalOption.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/IncrementalOption.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/IncrementalOption.java
new file mode 100755
index 0000000..eb24d11
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/IncrementalOption.java
@@ -0,0 +1,28 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 common.opt;
+
+public class IncrementalOption extends Option {
+ int value = 0;
+
+ @Override
+ public int parse(int position, String[] args) {
+ value++;
+ return super.parse(position, args);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/IntOption.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/IntOption.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/IntOption.java
new file mode 100755
index 0000000..87e732a
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/IntOption.java
@@ -0,0 +1,41 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 common.opt;
+
+public class IntOption extends Option {
+ public int value = 0;
+
+ @Override
+ public int parse(int position, String[] args) {
+ if (position + 1 >= args.length)
+ throw new NoArgumentForOptionException("Cannot find required argument for option \"" + args[position] + "\".");
+
+ value = Integer.parseInt(args[position + 1]);
+ return super.parse(position, args) + 1;
+ }
+
+ @Override
+ public String help() {
+ StringBuilder help = new StringBuilder();
+ help.append(join("|", name, alias, aliases)).append(" VALUE\t").append(description);
+ if (required)
+ help.append(" Required.");
+ else if (value != 0)
+ help.append(" Default value is \"").append("" + value).append("\".");
+ return help.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/NoArgumentForOptionException.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/NoArgumentForOptionException.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/NoArgumentForOptionException.java
new file mode 100755
index 0000000..a074672
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/NoArgumentForOptionException.java
@@ -0,0 +1,26 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 common.opt;
+
+public class NoArgumentForOptionException extends RuntimeException {
+ public NoArgumentForOptionException(String message) {
+ super(message);
+ }
+
+ private static final long serialVersionUID = 1L;
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/Option.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/Option.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/Option.java
new file mode 100755
index 0000000..e038075
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/Option.java
@@ -0,0 +1,102 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 common.opt;
+
+public class Option {
+
+ public String name = "";
+ public String alias = null;
+ public String aliases[] = null;
+
+ public String description = "";
+ public boolean used = false;
+ public boolean required = false;
+
+ /**
+ * Parse option value, if any.
+ *
+ * @param position
+ * position of this option in list of arguments
+ * @param args
+ * command line arguments
+ * @return how many arguments are consumed, at least 1
+ */
+ public int parse(int position, String args[]) {
+ used = true;
+ return 1;
+ }
+
+ @Override
+ public String toString() {
+ return help();
+ }
+
+ /**
+ * Return help string for this option. Example:
+ *
+ * <pre>
+ * --foo|-f Foo option.
+ * </pre>
+ */
+ public String help() {
+ return join("|", name, alias, aliases) + "\t" + description + ((required) ? " Required." : "");
+ }
+
+ /**
+ * Return string like "--foo|-f|--another-foo-alias".
+ */
+ protected String join(String delim, String name, String alias, String aliases[]) {
+
+ // Option name is mandatory
+ StringBuilder sb = new StringBuilder(name.length());
+ sb.append(name);
+
+ // Alias is optional
+ if (alias != null && alias.length() > 0) {
+ sb.append(delim).append(alias);
+ }
+
+ // Other aliases are optional too
+ if (aliases != null) {
+ for (String s : aliases) {
+ if (s != null && s.length() > 0) {
+ sb.append(delim).append(s);
+ }
+ }
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Return description of options in format suitable for help and usage text.
+ *
+ * @param header
+ * header string to print before list of options
+ * @param options
+ * list of options to print
+ */
+ public static String toHelp(String header, Option[] options) {
+ StringBuffer sb = new StringBuffer();
+ sb.append(header).append(":\n");
+ for (Option option : options) {
+ sb.append(" ").append(option.help()).append('\n');
+ }
+ return sb.toString();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/OptionParser.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/OptionParser.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/OptionParser.java
new file mode 100755
index 0000000..5c45e9e
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/OptionParser.java
@@ -0,0 +1,147 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 common.opt;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Simple parser of GNU-like options.
+ */
+public class OptionParser {
+
+ public static Option helpOption() {
+ return new Option() {
+ {
+ name = "--help";
+ alias = "-h";
+ }
+ };
+ }
+
+ /**
+ * Parse options, capture values and return rest of arguments.
+ *
+ * @param args
+ * command line arguments to parse
+ * @param startFrom
+ * number of first argument to start parsing from
+ * @param options
+ * options to fill with values
+ * @return rest of command line after first non-option or "--" separator
+ */
+ public static String[] parseOptions(String args[], int startFrom, Option options[]) {
+ // Convert array of options into map, where key is option name or alias
+ Map<String, Option> optionMap = new HashMap<String, Option>(options.length);
+ for (Option option : options) {
+ optionMap.put(option.name, option);
+
+ if (option.alias != null)
+ optionMap.put(option.alias, option);
+
+ if (option.aliases != null) {
+ for (String alias : option.aliases)
+ optionMap.put(alias, option);
+ }
+ }
+
+ // Parse arguments
+ int position = startFrom;
+ while (position < args.length) {
+ // Double dash means end of options
+ String optionName = args[position];
+ if (optionName.equals("--")) {
+ position++;
+ break;
+ }
+
+ Option option = optionMap.get(optionName);
+
+ // If option is not found, then this is argument, unless is starts with
+ // dash
+ if (option == null)
+ if (!optionName.startsWith("-"))
+ break;
+ else
+ throw new UnknownOptionException("Option \"" + optionName
+ + "\" is unknown. If this is not an option, then use \"--\" to separate options and arguments. Known options: " + optionMap.keySet().toString());
+
+ position += option.parse(position, args);
+ }
+
+ // Check is required options are used on command line
+ for (Option option : options) {
+ if (option.required && !option.used)
+ throw new OptionRequiredException("Option \"" + option.name + "\" is required.");
+ }
+
+ // Return rest of arguments, which are left after options
+ return (position < args.length) ? Arrays.copyOfRange(args, position, args.length) : new String[] {};
+ }
+
+ /* Example. */
+ public static void main(String args[]) {
+ if (args.length == 0)
+ args = new String[] {"--help", "--foo", "fooval", "--bar", "123", "-v", "--verbose", "-v", "-a", "a1", "-aa", "a2", "-aaa", "a3", "rest", "of",
+ "arguments"};
+
+ StringOption foo = new StringOption() {
+ {
+ name = "--foo";
+ alias = "-f";
+ value = "fooDefault";
+ }
+ };
+
+ IntOption bar = new IntOption() {
+ {
+ name = "--bar";
+ alias = "-b";
+ value = 123;
+ }
+ };
+
+ IncrementalOption verbose = new IncrementalOption() {
+ {
+ name = "--verbose";
+ alias = "-v";
+ }
+ };
+
+ StringArrayOption array = new StringArrayOption() {
+ {
+ name = "--array";
+ alias = "-a";
+ aliases = new String[] {"-aa", "-aaa"};
+ }
+ };
+
+ String arguments[] = OptionParser.parseOptions(args, 0, new Option[] {helpOption(), foo, bar, verbose, array});
+
+ assertTrue(foo.value.equals("fooval"));
+ assertTrue(bar.value == 123);
+ assertTrue(verbose.value == 3);
+ assertTrue(Arrays.equals(array.value, new String[] {"a1", "a2", "a3"}));
+ assertTrue(Arrays.equals(arguments, new String[] {"rest", "of", "arguments"}));
+ }
+
+ public static void assertTrue(boolean result) {
+ if (!result)
+ throw new AssertionError();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/OptionRequiredException.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/OptionRequiredException.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/OptionRequiredException.java
new file mode 100755
index 0000000..b397627
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/OptionRequiredException.java
@@ -0,0 +1,26 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 common.opt;
+
+public class OptionRequiredException extends RuntimeException {
+ public OptionRequiredException(String message) {
+ super(message);
+ }
+
+ private static final long serialVersionUID = 1L;
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/StringArrayOption.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/StringArrayOption.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/StringArrayOption.java
new file mode 100755
index 0000000..b2f3c30
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/StringArrayOption.java
@@ -0,0 +1,38 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 common.opt;
+
+import java.util.Arrays;
+
+public class StringArrayOption extends Option {
+ public String value[] = null;
+
+ @Override
+ public int parse(int position, String[] args) {
+ if (position + 1 >= args.length)
+ throw new NoArgumentForOptionException("Cannot find required argument for option \"" + args[position] + "\".");
+
+ // Append value to end of array of values
+ if (value == null) {
+ value = new String[] {args[position + 1]};
+ } else {
+ value = Arrays.copyOf(value, value.length + 1);
+ value[value.length - 1] = args[position + 1];
+ }
+ return super.parse(position, args) + 1;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/StringEnumerationOption.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/StringEnumerationOption.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/StringEnumerationOption.java
new file mode 100755
index 0000000..f59952e
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/StringEnumerationOption.java
@@ -0,0 +1,72 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 common.opt;
+
+public class StringEnumerationOption extends Option {
+ public String value = "";
+ public String choices[] = new String[] {};
+
+ @Override
+ public int parse(int position, String[] args) {
+ if (position + 1 >= args.length)
+ throw new NoArgumentForOptionException("Cannot find required argument for option \"" + args[position] + "\".");
+
+ value = args[position + 1];
+
+ for (String s : choices) {
+ if (value.equals(s))
+ return super.parse(position, args) + 1;
+ }
+
+ throw new NoArgumentForOptionException("Unexpected argument for option \"" + args[position] + "\": \"" + value + "\". Expected argument: "
+ + join("|", choices) + ".");
+ }
+
+ @Override
+ public String help() {
+ StringBuilder help = new StringBuilder();
+ help.append(join("|", name, alias, aliases)).append(" ").append(join("|", choices)).append("\t").append(description);
+ if (required)
+ help.append(" Required.");
+ else if (value != null && value.length() > 0)
+ help.append(" Default value is \"").append(value).append("\".");
+ return help.toString();
+ }
+
+ /**
+ * Join strings in array into one large string.
+ */
+ protected String join(String delim, String values[]) {
+ StringBuilder sb = new StringBuilder();
+ if (values != null) {
+ boolean first = true;
+ for (String s : values) {
+ if (s != null && s.length() > 0) {
+ if (first)
+ first = false;
+ else
+ sb.append(delim);
+
+ sb.append(s);
+ }
+ }
+ }
+
+ return sb.toString();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/StringOption.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/StringOption.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/StringOption.java
new file mode 100755
index 0000000..ec9c82c
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/StringOption.java
@@ -0,0 +1,41 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 common.opt;
+
+public class StringOption extends Option {
+ public String value = "";
+
+ @Override
+ public int parse(int position, String[] args) {
+ if (position + 1 >= args.length)
+ throw new NoArgumentForOptionException("Cannot find required argument for option \"" + args[position] + "\".");
+
+ value = args[position + 1];
+ return super.parse(position, args) + 1;
+ }
+
+ @Override
+ public String help() {
+ StringBuilder help = new StringBuilder();
+ help.append(join("|", name, alias, aliases)).append(" VALUE\t").append(description);
+ if (required)
+ help.append(" Required.");
+ else if (value != null && value.length() > 0)
+ help.append(" Default value is \"").append(value).append("\".");
+ return help.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4f3611f9/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/UnknownOptionException.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/UnknownOptionException.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/UnknownOptionException.java
new file mode 100755
index 0000000..58cce73
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/opt/UnknownOptionException.java
@@ -0,0 +1,27 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 common.opt;
+
+public class UnknownOptionException extends RuntimeException {
+
+ public UnknownOptionException(String message) {
+ super(message);
+ }
+
+ private static final long serialVersionUID = 1L;
+
+}