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/11/08 09:16:12 UTC

[9/9] git commit: updated refs/heads/master to a98c473

Remote Desktop Protocol(RDP) client that is suitable for including in the console VM.
The client renders RDP to a window created by Java. It is important for Hyper-V support,
because Hyper-V provides access to the consoles of VMs that it is running over RDP.


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/a98c473d
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/a98c473d
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/a98c473d

Branch: refs/heads/master
Commit: a98c473dca9ff2af1275f6c9afda773fc416a727
Parents: 57ba367
Author: Devdeep Singh <de...@gmail.com>
Authored: Fri Nov 8 13:16:44 2013 +0530
Committer: Devdeep Singh <de...@gmail.com>
Committed: Fri Nov 8 13:35:11 2013 +0530

----------------------------------------------------------------------
 .../console-proxy-rdp/rdpconsole/README.txt     |   50 +
 services/console-proxy-rdp/rdpconsole/pom.xml   |   49 +
 .../console-proxy-rdp/rdpconsole/rdp-config.bat |   42 +
 .../src/main/java/common/AwtBellAdapter.java    |   76 ++
 .../src/main/java/common/AwtCanvasAdapter.java  |  164 +++
 .../main/java/common/AwtClipboardAdapter.java   |   55 +
 .../src/main/java/common/AwtKeyEventSource.java |   53 +
 .../main/java/common/AwtMouseEventSource.java   |   71 ++
 .../src/main/java/common/BitmapOrder.java       |   48 +
 .../src/main/java/common/BitmapRectangle.java   |   74 ++
 .../main/java/common/BufferedImageCanvas.java   |   79 ++
 .../common/BufferedImageCopyRectAdapter.java    |  124 ++
 .../java/common/BufferedImagePixelsAdapter.java |  147 +++
 .../rdpconsole/src/main/java/common/Client.java |  137 +++
 .../src/main/java/common/CopyRectOrder.java     |   39 +
 .../src/main/java/common/KeyOrder.java          |   45 +
 .../src/main/java/common/MouseOrder.java        |   41 +
 .../src/main/java/common/OrderType.java         |   22 +
 .../src/main/java/common/ScreenDescription.java |  168 +++
 .../main/java/common/SizeChangeListener.java    |   22 +
 .../java/rdpclient/AwtRdpKeyboardAdapter.java   |  351 ++++++
 .../main/java/rdpclient/AwtRdpMouseAdapter.java |  180 +++
 .../java/rdpclient/ClientConfirmActivePDU.java  | 1132 ++++++++++++++++++
 .../main/java/rdpclient/ClientFastPathPDU.java  |   55 +
 .../src/main/java/rdpclient/ClientInfoPDU.java  |  456 +++++++
 .../rdpclient/ClientMCSAttachUserRequest.java   |  102 ++
 ...JoinRequest_ServerMCSChannelConfirmPDUs.java |  222 ++++
 .../java/rdpclient/ClientMCSConnectInitial.java |  669 +++++++++++
 .../rdpclient/ClientMCSErectDomainRequest.java  |  190 +++
 .../java/rdpclient/ClientPacketSniffer.java     |   50 +
 .../java/rdpclient/ClientSynchronizePDU.java    |  248 ++++
 .../src/main/java/rdpclient/ClientTpkt.java     |   54 +
 .../ClientX224ConnectionRequestPDU.java         |  156 +++
 .../main/java/rdpclient/ClientX224DataPdu.java  |   54 +
 .../src/main/java/rdpclient/HandshakeEnd.java   |   27 +
 .../src/main/java/rdpclient/MockServer.java     |  197 +++
 .../src/main/java/rdpclient/PacketSniffer.java  |   75 ++
 .../java/rdpclient/RLEBitmapDecompression.java  | 1014 ++++++++++++++++
 .../src/main/java/rdpclient/RdpClient.java      |  214 ++++
 .../src/main/java/rdpclient/RdpConstants.java   |   74 ++
 .../src/main/java/rdpclient/RdpState.java       |   33 +
 .../main/java/rdpclient/ServerBitmapUpdate.java |  201 ++++
 .../java/rdpclient/ServerChannel1003Router.java |  530 ++++++++
 .../rdpclient/ServerControlPDUCooperate.java    |  117 ++
 .../ServerControlPDUGrantedControl.java         |  114 ++
 .../java/rdpclient/ServerDemandActivePDU.java   |  661 ++++++++++
 .../src/main/java/rdpclient/ServerFastPath.java |  259 ++++
 .../ServerLicenseErrorPDUValidClient.java       |  121 ++
 .../ServerMCSAttachUserConfirmPDU.java          |  133 ++
 .../ServerMCSChannelJoinConfirmPDU.java         |   89 ++
 .../rdpclient/ServerMCSConnectResponse.java     |  283 +++++
 .../src/main/java/rdpclient/ServerMCSPDU.java   |  149 +++
 .../java/rdpclient/ServerPacketSniffer.java     |   52 +
 .../java/rdpclient/ServerPaletteUpdate.java     |   78 ++
 .../java/rdpclient/ServerSynchronizePDU.java    |  115 ++
 .../src/main/java/rdpclient/ServerTpkt.java     |   70 ++
 .../ServerX224ConnectionConfirmPDU.java         |  237 ++++
 .../main/java/rdpclient/ServerX224DataPdu.java  |   64 +
 .../rdpclient/TrustAllX509TrustManager.java     |   40 +
 .../main/java/rdpclient/UpgradeSocketToSSL.java |   44 +
 .../main/java/streamer/AssertingByteBuffer.java |  107 ++
 .../src/main/java/streamer/BaseElement.java     |  417 +++++++
 .../src/main/java/streamer/BufferPool.java      |   36 +
 .../src/main/java/streamer/ByteBuffer.java      |  826 +++++++++++++
 .../src/main/java/streamer/DataSink.java        |   24 +
 .../src/main/java/streamer/DataSource.java      |   60 +
 .../src/main/java/streamer/Direction.java       |   21 +
 .../src/main/java/streamer/Element.java         |  120 ++
 .../src/main/java/streamer/Event.java           |   33 +
 .../src/main/java/streamer/FakeSink.java        |   69 ++
 .../src/main/java/streamer/FakeSource.java      |  125 ++
 .../main/java/streamer/InputStreamSource.java   |  194 +++
 .../rdpconsole/src/main/java/streamer/Link.java |   66 +
 .../src/main/java/streamer/MockSink.java        |  111 ++
 .../src/main/java/streamer/MockSource.java      |   88 ++
 .../src/main/java/streamer/OneTimeSwitch.java   |  133 ++
 .../src/main/java/streamer/Order.java           |   23 +
 .../main/java/streamer/OutputStreamSink.java    |  153 +++
 .../src/main/java/streamer/Pipeline.java        |   91 ++
 .../src/main/java/streamer/PipelineImpl.java    |  309 +++++
 .../src/main/java/streamer/Queue.java           |  136 +++
 .../src/main/java/streamer/SocketWrapper.java   |  239 ++++
 .../src/main/java/streamer/SyncLink.java        |  402 +++++++
 .../vncclient/AwtKeyboardEventToVncAdapter.java |  369 ++++++
 .../vncclient/AwtMouseEventToVncAdapter.java    |   71 ++
 .../main/java/vncclient/EncodingsMessage.java   |   63 +
 .../vncclient/FrameBufferUpdateRequest.java     |  127 ++
 .../vncclient/RGB888LE32PixelFormatRequest.java |   90 ++
 .../src/main/java/vncclient/RfbConstants.java   |   85 ++
 .../src/main/java/vncclient/VncClient.java      |  107 ++
 .../src/main/java/vncclient/VncInitializer.java |  244 ++++
 .../main/java/vncclient/VncMessageHandler.java  |  419 +++++++
 .../java/vncclient/Vnc_3_3_Authentication.java  |  291 +++++
 .../src/main/java/vncclient/Vnc_3_3_Hello.java  |  115 ++
 .../rdpconsole/src/test/doc/README.txt          |   32 +
 .../rdpconsole/src/test/doc/dev-rdp-config.bat  |  126 ++
 .../rdpconsole/src/test/doc/rdp-key.pem         |   23 +
 .../src/test/java/rdpclient/MockServerTest.java |  189 +++
 98 files changed, 16550 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/README.txt
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/README.txt b/services/console-proxy-rdp/rdpconsole/README.txt
new file mode 100644
index 0000000..15029d4
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/README.txt
@@ -0,0 +1,50 @@
+// 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.
+This project contains code for basic VNC and RDP clients.
+
+VNC client can be invoked using following command:
+
+  mvn exec:java -Dexec.mainClass="common.Client" -Dexec.args="vnc 192.168.0.101 5901 password"
+
+where
+  * vnc - name of protcol;
+  * 192.168.0.101 - IP of VNC server;
+  * 5901 - port of VNC server screen (5900+display number);
+  * password - VNC server password.
+
+
+RDP client can be invoked using following command:
+
+  mvn exec:java -Dexec.mainClass="common.Client" -Dexec.args="rdp 192.168.0.101 3389 Administrator"
+
+where
+  * rdp - name of protcol;
+  * 192.168.0.101 - IP of RDP server;
+  * 3389 - port of RDP server;
+  * Administrator - user name for loging dialog.
+
+
+Limitations of VNC client:
+  * only basic functionality work.
+
+Limitations of RDP client:
+  * it uses SSL/TLS;
+  * NLA is not supported;
+  * only basic functionality work.
+
+
+To configure and start RDP service properly, run rdp-config.bat on server.

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/pom.xml
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/pom.xml b/services/console-proxy-rdp/rdpconsole/pom.xml
new file mode 100644
index 0000000..d1b4918
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/pom.xml
@@ -0,0 +1,49 @@
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>rdpclient</groupId>
+  <artifactId>rdpclient</artifactId>
+  <version>4.3.0-SNAPSHOT</version>
+  <packaging>jar</packaging>
+
+  <name>rdpclient</name>
+  <url>http://maven.apache.org</url>
+
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>3.8.1</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.tomcat.embed</groupId>
+      <artifactId>tomcat-embed-core</artifactId>
+      <version>7.0.30</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/rdp-config.bat
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/rdp-config.bat b/services/console-proxy-rdp/rdpconsole/rdp-config.bat
new file mode 100644
index 0000000..e951014
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/rdp-config.bat
@@ -0,0 +1,42 @@
+rem Licensed to the Apache Software Foundation (ASF) under one
+rem or more contributor license agreements.  See the NOTICE file
+rem distributed with this work for additional information
+rem regarding copyright ownership.  The ASF licenses this file
+rem to you under the Apache License, Version 2.0 (the
+rem "License"); you may not use this file except in compliance
+rem with the License.  You may obtain a copy of the License at
+rem 
+rem   http://www.apache.org/licenses/LICENSE-2.0
+rem 
+rem Unless required by applicable law or agreed to in writing,
+rem software distributed under the License is distributed on an
+rem "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+rem KIND, either express or implied.  See the License for the
+rem specific language governing permissions and limitations
+rem under the License.
+
+rem 
+rem Configure and start RDP service.
+rem 
+ 
+rem Turn off firewall
+
+netsh advfirewall firewall set rule group="Remote Desktop" new enable=yes
+
+rem Enable TS connections
+
+reg add "HKLM\System\CurrentControlSet\Control\Terminal Server" /v "AllowTSConnections" /t REG_DWORD /d 1 /f
+reg add "HKLM\System\CurrentControlSet\Control\Terminal Server" /v "fDenyTSConnections" /t REG_DWORD /d 0 /f
+
+rem Disable RDP NLA
+
+reg add "HKLM\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /v UserAuthentication /t REG_DWORD /d 0 /f
+
+rem Enable TS service
+
+sc config TermService start=auto
+
+rem Start TS service
+
+net start Termservice
+

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtBellAdapter.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtBellAdapter.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtBellAdapter.java
new file mode 100644
index 0000000..3318c09
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/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;
+
+import java.awt.Toolkit;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+import streamer.Element;
+import streamer.FakeSource;
+import streamer.Link;
+import streamer.Pipeline;
+import streamer.PipelineImpl;
+
+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/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtCanvasAdapter.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtCanvasAdapter.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtCanvasAdapter.java
new file mode 100644
index 0000000..12dd88b
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtCanvasAdapter.java
@@ -0,0 +1,164 @@
+// 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;
+
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.WritableRaster;
+
+import rdpclient.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/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtClipboardAdapter.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtClipboardAdapter.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtClipboardAdapter.java
new file mode 100644
index 0000000..aeed41c
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtClipboardAdapter.java
@@ -0,0 +1,55 @@
+// 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;
+
+import java.awt.Toolkit;
+import java.awt.datatransfer.StringSelection;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+import streamer.Link;
+import vncclient.VncMessageHandler;
+
+public class AwtClipboardAdapter extends BaseElement {
+
+  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(VncMessageHandler.CLIPBOARD_CONTENT);
+    StringSelection contents = new StringSelection(content);
+    Toolkit.getDefaultToolkit().getSystemClipboard().setContents(contents, null);
+  }
+
+  public String toString() {
+    return "Clipboard(" + id + ")";
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtKeyEventSource.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtKeyEventSource.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtKeyEventSource.java
new file mode 100644
index 0000000..a754796
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtKeyEventSource.java
@@ -0,0 +1,53 @@
+// 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;
+
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+
+public class AwtKeyEventSource extends BaseElement implements KeyListener {
+
+  public AwtKeyEventSource(String id) {
+    super(id);
+  }
+
+  @Override
+  public void keyTyped(KeyEvent e) {
+    // Nothing to do
+
+  }
+
+  @Override
+  public void keyPressed(KeyEvent e) {
+    sendEvent(e, true);
+  }
+
+  @Override
+  public void keyReleased(KeyEvent e) {
+    sendEvent(e, false);
+  }
+
+  private void sendEvent(KeyEvent e, boolean pressed) {
+    ByteBuffer buf=new ByteBuffer(new KeyOrder(e, pressed));
+
+    pushDataToAllOuts(buf);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtMouseEventSource.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtMouseEventSource.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtMouseEventSource.java
new file mode 100644
index 0000000..f3e58fc
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/AwtMouseEventSource.java
@@ -0,0 +1,71 @@
+// 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;
+
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+
+public class AwtMouseEventSource extends BaseElement implements MouseListener, MouseMotionListener {
+
+  public AwtMouseEventSource(String id) {
+    super(id);
+  }
+
+  @Override
+  public void mouseClicked(MouseEvent e) {
+    // Nothing to do
+  }
+
+  @Override
+  public void mousePressed(MouseEvent e) {
+    MouseOrder order = new MouseOrder(e);
+    order.pressed = true;
+    pushDataToAllOuts(new ByteBuffer(order));
+  }
+
+  @Override
+  public void mouseReleased(MouseEvent e) {
+    MouseOrder order = new MouseOrder(e);
+    order.released = true;
+    pushDataToAllOuts(new ByteBuffer(order));
+  }
+
+  @Override
+  public void mouseEntered(MouseEvent e) {
+    // Nothing to do
+  }
+
+  @Override
+  public void mouseExited(MouseEvent e) {
+    // Nothing to do
+  }
+
+  @Override
+  public void mouseDragged(MouseEvent e) {
+    pushDataToAllOuts(new ByteBuffer(new MouseOrder(e)));
+  }
+
+  @Override
+  public void mouseMoved(MouseEvent e) {
+    pushDataToAllOuts(new ByteBuffer(new MouseOrder(e)));
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/BitmapOrder.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/BitmapOrder.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/BitmapOrder.java
new file mode 100644
index 0000000..438755f
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/BitmapOrder.java
@@ -0,0 +1,48 @@
+// 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;
+
+import java.util.Arrays;
+
+
+import streamer.Order;
+
+/**
+ * Not an order, but derived from Order class for compatibility with orders.
+ * 
+ * @see http://msdn.microsoft.com/en-us/library/dd306368.aspx
+ */
+public class BitmapOrder extends Order {
+
+  public BitmapOrder() {
+    type = OrderType.BITMAP_UPDATE;
+  }
+
+  /**
+   * Structures, each of which contains a rectangular clipping taken from the
+   * server-side screen frame buffer.
+   */
+  public BitmapRectangle rectangles[];
+
+  @Override
+  public String toString() {
+    final int maxLen = 10;
+    return String.format("BitmapUpdateOrder [rectangles=%s]", rectangles != null ? Arrays.asList(rectangles).subList(0, Math.min(rectangles.length, maxLen))
+        : null);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/BitmapRectangle.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/BitmapRectangle.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/BitmapRectangle.java
new file mode 100644
index 0000000..f0c178e
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/BitmapRectangle.java
@@ -0,0 +1,74 @@
+// 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;
+
+import streamer.ByteBuffer;
+
+/**
+ * @see http://msdn.microsoft.com/en-us/library/cc240612.aspx
+ */
+public class BitmapRectangle {
+
+  /**
+   * Left bound of the rectangle.
+   */
+  public int x;
+
+  /**
+   * Top bound of the rectangle.
+   */
+  public int y;
+
+  /**
+   * Width of the rectangle.
+   */
+  public int width;
+
+  /**
+   * Height of the rectangle.
+   */
+  public int height;
+
+  /**
+   * Color depth of the rectangle data in bits-per-pixel.
+   */
+  public int colorDepth;
+
+  /**
+   * Variable-length array of bytes describing a raw uncompressed bitmap image.
+   */
+  public ByteBuffer bitmapDataStream;
+
+  /**
+   * Size of single horizontal scan line.
+   */
+  public int bufferWidth;
+
+  /**
+   * Number of horizontal scan lines in buffer.
+   */
+  public int bufferHeight;
+
+  @Override
+  public String toString() {
+    return String
+        .format(
+            "BitmapUpdateRectangle [x=%s, y=%s, width=%s, height=%s, bitsPerPixel=%s, bitmapDataStream=%s]",
+            x, y, width, height, colorDepth, bitmapDataStream);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/BufferedImageCanvas.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/BufferedImageCanvas.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/BufferedImageCanvas.java
new file mode 100644
index 0000000..6e7738f
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/BufferedImageCanvas.java
@@ -0,0 +1,79 @@
+// 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;
+
+import java.awt.Canvas;
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+
+/**
+ * A <code>BuffereImageCanvas</code> component represents frame buffer image on the
+ * screen. It also notifies its subscribers when screen is repainted.
+ */
+public class BufferedImageCanvas extends Canvas {
+  private static final long serialVersionUID = 1L;
+
+   // Offline screen buffer
+  private BufferedImage offlineImage;
+  
+  // Cached Graphics2D object for offline screen buffer
+  private Graphics2D graphics;
+
+  public BufferedImageCanvas(int width, int height) {
+    super();
+
+    setBackground(Color.black);
+    
+    setFocusable(true);
+
+    // Don't intercept TAB key
+    setFocusTraversalKeysEnabled(false);
+
+    setCanvasSize(width, height);
+  }
+
+  public void setCanvasSize(int width, int height) {
+    this.offlineImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+    graphics = offlineImage.createGraphics();
+
+    setSize(offlineImage.getWidth(), offlineImage.getHeight());
+  }
+
+  @Override
+  public void update(Graphics g) {
+    // Call paint() directly, without clearing screen first
+    paint(g);
+  }
+
+  @Override
+  public void paint(Graphics g) {
+    // Only part of image, requested with repaint(Rectangle), will be
+    // painted on screen.
+    g.drawImage(offlineImage, 0, 0, this);
+  }
+
+  public BufferedImage getOfflineImage() {
+    return offlineImage;
+  }
+
+  public Graphics2D getOfflineGraphics() {
+    return graphics;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/BufferedImageCopyRectAdapter.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/BufferedImageCopyRectAdapter.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/BufferedImageCopyRectAdapter.java
new file mode 100644
index 0000000..bbd5142
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/BufferedImageCopyRectAdapter.java
@@ -0,0 +1,124 @@
+// 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;
+
+import java.awt.image.DataBufferInt;
+import java.util.Arrays;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+import streamer.Element;
+import streamer.Link;
+
+public class BufferedImageCopyRectAdapter extends BaseElement {
+
+  public static final String SRC_X = "srcX";
+  public static final String SRC_Y = "srcY";
+  public static final String TARGET_X = "x";
+  public static final String TARGET_Y = "y";
+  public static final String WIDTH = "width";
+  public static final String HEIGHT = "height";
+
+  protected BufferedImageCanvas canvas;
+
+  public BufferedImageCopyRectAdapter(String id, BufferedImageCanvas canvas) {
+    super(id);
+    this.canvas = canvas;
+    declarePads();
+  }
+
+  private void declarePads() {
+    inputPads.put(STDIN, null);
+  }
+
+  public String toString() {
+    return "Renderer(" + id + ")";
+  }
+
+  @Override
+  public void handleData(ByteBuffer buf, Link link) {
+    if (buf == null)
+      return;
+    
+    if (verbose)
+      System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+
+    int x = (Integer) buf.getMetadata(TARGET_X);
+    int y = (Integer) buf.getMetadata(TARGET_Y);
+    int width = (Integer) buf.getMetadata(WIDTH);
+    int height = (Integer) buf.getMetadata(HEIGHT);
+    int srcX = (Integer) buf.getMetadata(SRC_X);
+    int srcY = (Integer) buf.getMetadata(SRC_Y);
+    buf.unref();
+
+    // Copy image
+    canvas.getOfflineGraphics().copyArea(srcX, srcY, width, height, x - srcX, y - srcY);
+
+    // Request update of repainted area
+    canvas.repaint(x, y, width, height);
+  }
+
+  public static void main(String args[]) {
+    System.setProperty("streamer.Element.debug", "true");
+
+    BufferedImageCanvas canvas = new BufferedImageCanvas(4, 4);
+
+    Element renderer = new BufferedImageCopyRectAdapter("renderer", canvas);
+
+    int[] pixelsBeforeCopy = new int[] {
+        // 0
+        1, 2, 3, 4,
+        // 1
+        5, 6, 7, 8,
+        // 2
+        9, 10, 11, 12,
+        // 3
+        13, 14, 15, 16 };
+    int[] pixelsAfterCopy = new int[] {
+        // 0
+        11, 12, 3, 4,
+        // 1
+        15, 16, 7, 8,
+        // 2
+        9, 10, 11, 12,
+        // 3
+        13, 14, 15, 16 };
+
+    
+    // Initalize image
+    int[] data = ((DataBufferInt) canvas.getOfflineImage().getRaster().getDataBuffer()).getData();
+    System.arraycopy(pixelsBeforeCopy, 0, data, 0, pixelsBeforeCopy.length);
+    
+    ByteBuffer buf = new ByteBuffer(new byte[0]);
+    buf.putMetadata(TARGET_X, 0);
+    buf.putMetadata(TARGET_Y, 0);
+    buf.putMetadata(WIDTH, 2);
+    buf.putMetadata(HEIGHT, 2);
+    buf.putMetadata(SRC_X, 2);
+    buf.putMetadata(SRC_Y, 2);
+
+    renderer.handleData(buf, null);
+
+    data = ((DataBufferInt) canvas.getOfflineImage().getRaster().getDataBuffer()).getData();
+    String actualData = Arrays.toString(data);
+    String expectedData = Arrays.toString(pixelsAfterCopy);
+    if (!actualData.equals(expectedData))
+      System.err.println("Actual image:   " + actualData + "\nExpected image: " + expectedData + ".");
+
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/BufferedImagePixelsAdapter.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/BufferedImagePixelsAdapter.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/BufferedImagePixelsAdapter.java
new file mode 100644
index 0000000..95e7738
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/BufferedImagePixelsAdapter.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;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferInt;
+import java.util.Arrays;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+import streamer.Element;
+import streamer.Link;
+
+public class BufferedImagePixelsAdapter extends BaseElement {
+
+  public static final String TARGET_X = "x";
+  public static final String TARGET_Y = "y";
+  public static final String WIDTH = "width";
+  public static final String HEIGHT = "height";
+  public static final String RGB888LE32 = "RGB888LE32";
+  public static final String PIXEL_FORMAT = "pixel_format";
+
+  protected BufferedImageCanvas canvas;
+
+  public BufferedImagePixelsAdapter(String id, BufferedImageCanvas canvas) {
+    super(id);
+    this.canvas = canvas;
+    declarePads();
+  }
+
+  private void declarePads() {
+    inputPads.put(STDIN, null);
+  }
+
+  public String toString() {
+    return "Renderer(" + id + ")";
+  }
+
+  @Override
+  public void handleData(ByteBuffer buf, Link link) {
+    if (verbose)
+      System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+
+    int x = (Integer) buf.getMetadata(TARGET_X);
+    int y = (Integer) buf.getMetadata(TARGET_Y);
+    int rectWidth = (Integer) buf.getMetadata(WIDTH);
+    int rectHeight = (Integer) buf.getMetadata(HEIGHT);
+    String format = (String) buf.getMetadata(PIXEL_FORMAT);
+
+    int bpp;
+    // Support RGB888/32 little endian only
+    if (format != null && RGB888LE32.equals(format)) {
+      bpp = 4;
+      // TODO: support more formats
+    } else
+      throw new RuntimeException("Unsupported format: " + format + ". Supported formats: " + RGB888LE32 + ".");
+
+    int dataLength = rectWidth * rectHeight * bpp;
+    if (!cap(buf, dataLength, dataLength, link, false))
+      return;
+
+    // Draw rectangle on offline buffer
+    BufferedImage image = canvas.getOfflineImage();
+
+    DataBuffer dataBuf = image.getRaster().getDataBuffer();
+
+    switch (dataBuf.getDataType()) {
+
+    case DataBuffer.TYPE_INT: {
+
+      // Convert array of bytes to array of int's
+      int[] intArray = buf.toIntLEArray();
+
+      // We chose RGB888 model, so Raster will use DataBufferInt type
+      DataBufferInt dataBuffer = (DataBufferInt) dataBuf;
+
+      int imageWidth = image.getWidth();
+      int imageHeight = image.getHeight();
+
+      // Paint rectangle directly on buffer, line by line
+      int[] imageBuffer = dataBuffer.getData();
+
+      for (int srcLine = 0, dstLine = y; srcLine < rectHeight && dstLine < imageHeight; srcLine++, dstLine++) {
+        try {
+          System.arraycopy(intArray, srcLine * rectWidth, imageBuffer, x + dstLine * imageWidth, rectWidth);
+        } catch (IndexOutOfBoundsException e) {
+        }
+      }
+      break;
+    }
+
+    default:
+      throw new RuntimeException("Unsupported data buffer in buffered image: expected data buffer of type int (DataBufferInt). Actual data buffer type: "
+          + dataBuf.getClass().getSimpleName());
+    }
+
+    // Request update of repainted area
+    canvas.repaint(x, y, rectWidth, rectHeight);
+
+    buf.unref();
+  }
+
+  public static void main(String args[]) {
+    System.setProperty("streamer.Element.debug", "true");
+
+    BufferedImageCanvas canvas = new BufferedImageCanvas(4, 4);
+
+    Element renderer = new BufferedImagePixelsAdapter("renderer", canvas);
+
+    byte[] pixels = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5,
+        6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
+
+    int[] pixelsLE = new int[] { 0x04030201, 0x08070605, 0x0c0b0a09, 0x100f0e0d, 0x04030201, 0x08070605, 0x0c0b0a09, 0x100f0e0d, 0x04030201, 0x08070605,
+        0x0c0b0a09, 0x100f0e0d, 0x04030201, 0x08070605, 0x0c0b0a09, 0x100f0e0d };
+
+    ByteBuffer buf = new ByteBuffer(pixels);
+    buf.putMetadata(TARGET_X, 0);
+    buf.putMetadata(TARGET_Y, 0);
+    buf.putMetadata(WIDTH, 4);
+    buf.putMetadata(HEIGHT, 4);
+    buf.putMetadata(PIXEL_FORMAT, RGB888LE32);
+
+    renderer.handleData(buf, null);
+
+    String actualData = Arrays.toString(((DataBufferInt) canvas.getOfflineImage().getRaster().getDataBuffer()).getData());
+    String expectedData = Arrays.toString(pixelsLE);
+    if (!actualData.equals(expectedData))
+      System.err.println("Actual image:   " + actualData + "\nExpected image: " + expectedData + ".");
+
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/Client.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/Client.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/Client.java
new file mode 100644
index 0000000..343fe0a
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/Client.java
@@ -0,0 +1,137 @@
+// 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;
+
+import java.awt.Frame;
+import java.awt.ScrollPane;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.net.InetSocketAddress;
+
+import rdpclient.RdpClient;
+import streamer.Element;
+import streamer.Pipeline;
+import streamer.PipelineImpl;
+import streamer.SocketWrapper;
+import vncclient.VncClient;
+
+public class Client {
+
+  private static Frame frame;
+  private static SocketWrapper socket;
+  private static ScrollPane scroller;
+  private static ScreenDescription screen;
+  private static BufferedImageCanvas canvas;
+
+  public static void main(String args[]) {
+    // System.setProperty("streamer.Link.debug", "true");
+    // System.setProperty("streamer.Element.debug", "true");
+    // System.setProperty("streamer.Pipeline.debug", "true");
+
+    try {
+      if (args.length < 4) {
+        System.out.println("Usage: \n  java common.Client vnc IP PORT PASSWORD\n  java common.Client rdp IP PORT username\n");
+        System.exit(0);
+      }
+
+      String connectionType = args[0];
+      String hostname = args[1];
+      int port = Integer.parseInt(args[2]);
+      String userNameOrPassword = args[3];
+
+      // Create address from arguments
+      InetSocketAddress address = new InetSocketAddress(hostname, port);
+
+      // Create socket wrapper
+      socket = new SocketWrapper("socket");
+
+      screen = new ScreenDescription();
+      canvas = new BufferedImageCanvas(1024, 768);
+      screen.addSizeChangeListener(new SizeChangeListener() {
+        @Override
+        public void sizeChanged(int width, int height) {
+          if (canvas != null) {
+            canvas.setCanvasSize(width, height);
+            if (scroller != null)
+              scroller.setSize(canvas.getWidth(), canvas.getHeight());
+          }
+        }
+      });
+
+      // Assemble pipeline
+      Element main;
+      if ("vnc".equals(connectionType)) {
+        main = new VncClient("client", userNameOrPassword, screen, canvas);
+      } else if ("rdp".equals(connectionType)) {
+        main = new RdpClient("client", userNameOrPassword, screen, canvas);
+      } else {
+        throw new RuntimeException("Unknown connection type. Expected value: \"vnc\" or \"rdp\", actual value: \"" + connectionType + "\".");
+      }
+
+      Pipeline pipeline = new PipelineImpl("Client");
+      pipeline.add(socket, main);
+      pipeline.link("socket", main.getId(), "socket");
+
+      pipeline.validate();
+      
+      frame = createVncClientMainWindow(canvas, "VNC", new WindowAdapter() {
+        public void windowClosing(WindowEvent evt) {
+          shutdown();
+        }
+      });
+
+      try {
+        // Connect socket to remote server and run main loop(s)
+        socket.connect(address);
+      } finally {
+        shutdown();
+      }
+
+    } catch (Exception e) {
+      e.printStackTrace(System.err);
+    }
+  }
+
+  protected static void shutdown() {
+    if (frame != null) {
+      frame.setVisible(false);
+      frame.dispose();
+    }
+    if (socket != null)
+      socket.shutdown();
+  }
+
+  protected static Frame createVncClientMainWindow(BufferedImageCanvas canvas, String title, WindowListener windowListener) {
+    // Create AWT windows
+    Frame frame = new Frame(title + " - RDP");
+
+    // Use scrolling pane to support screens, which are larger than ours
+    scroller = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED);
+    scroller.add(canvas);
+    scroller.setSize(canvas.getWidth(), canvas.getHeight());
+
+    frame.add(scroller);
+    frame.pack();
+    frame.setVisible(true);
+
+    frame.addWindowListener(windowListener);
+
+    return frame;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/CopyRectOrder.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/CopyRectOrder.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/CopyRectOrder.java
new file mode 100644
index 0000000..5f0c0f7
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/CopyRectOrder.java
@@ -0,0 +1,39 @@
+// 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;
+
+
+import streamer.Order;
+
+public class CopyRectOrder extends Order {
+  public int srcX;
+  public int srcY;
+  public int width;
+  public int height;
+  public int x;
+  public int y;
+
+  public CopyRectOrder() {
+    type = OrderType.COPY_RECT;
+  }
+
+  @Override
+  public String toString() {
+    return "CopyRectOrder [srcX=" + srcX + ", srcY=" + srcY + ", width=" + width + ", height=" + height + ", x=" + x + ", y=" + y + "]";
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/KeyOrder.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/KeyOrder.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/KeyOrder.java
new file mode 100644
index 0000000..726d8a0
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/KeyOrder.java
@@ -0,0 +1,45 @@
+// 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;
+
+import java.awt.event.KeyEvent;
+
+import streamer.Order;
+
+public class KeyOrder extends Order {
+  public KeyOrder() {
+    type = "key event";
+  }
+
+  public KeyOrder(KeyEvent event, boolean pressed) {
+    type = "key event";
+    
+    this.event = event;
+    this.pressed = pressed;
+  }
+
+  public KeyEvent event;
+  
+  public boolean pressed;
+
+  @Override
+  public String toString() {
+    return "KeyOrder [event=" + event + ", pressed=" + pressed + "]";
+  }
+  
+  
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/MouseOrder.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/MouseOrder.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/MouseOrder.java
new file mode 100644
index 0000000..d6670fa
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/MouseOrder.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;
+
+import java.awt.event.MouseEvent;
+
+import streamer.Order;
+
+public class MouseOrder extends Order {
+
+  public MouseOrder() {
+    type = "mouse order";
+  }
+
+  public MouseOrder(MouseEvent event) {
+    type = "mouse order";
+    this.event = event;
+  }
+
+  public MouseEvent event;
+  public boolean pressed;
+  public boolean released;
+  @Override
+  public String toString() {
+    return "MouseOrder [event=" + event + ", pressed=" + pressed + ", released=" + released + "]";
+  }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/OrderType.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/OrderType.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/OrderType.java
new file mode 100644
index 0000000..1e77ea9
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/OrderType.java
@@ -0,0 +1,22 @@
+// 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;
+
+public enum OrderType {
+  BITMAP_UPDATE, COPY_RECT,
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/common/ScreenDescription.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/common/ScreenDescription.java b/services/console-proxy-rdp/rdpconsole/src/main/java/common/ScreenDescription.java
new file mode 100644
index 0000000..a01f22e
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/ScreenDescription.java
@@ -0,0 +1,168 @@
+// 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;
+
+import java.awt.image.IndexColorModel;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * VncScreenDescription - contains information about remote VNC screen.
+ */
+public class ScreenDescription {
+  
+  protected Set<SizeChangeListener> sizeChangeListeners = new HashSet<SizeChangeListener>();
+
+  // Frame buffer size
+  protected int framebufferWidth = -1;
+  protected int framebufferHeight = -1;
+
+  // Desktop name
+  protected String desktopName = null;
+
+  // Bytes per pixel
+  protected int bytesPerPixel;
+  protected int colorDepth;
+  protected int bitsPerPixel;
+  protected int redShift;
+  protected int greenShift;
+  protected int blueShift;
+  protected int redMax;
+  protected int greenMax;
+  protected int blueMax;
+  protected boolean bigEndianFlag;
+  protected boolean trueColorFlag;
+
+  public IndexColorModel colorMap = null;
+
+  public ScreenDescription() {
+  }
+
+  /**
+   * Store information about server pixel format.
+   */
+  public void setPixelFormat(int bitsPerPixel, int depth, boolean bigEndianFlag, boolean trueColorFlag, int redMax, int greenMax, int blueMax, int redShift,
+      int greenShift, int blueShift) {
+
+    this.bytesPerPixel = (bitsPerPixel + 7) / 8;
+
+    this.bitsPerPixel = bitsPerPixel;
+    this.colorDepth = depth;
+    this.bigEndianFlag = bigEndianFlag;
+    this.trueColorFlag = trueColorFlag;
+
+    this.redMax = redMax;
+    this.greenMax = greenMax;
+    this.blueMax = blueMax;
+    this.redShift = redShift;
+    this.greenShift = greenShift;
+    this.blueShift = blueShift;
+  }
+
+  /**
+   * Store information about server pixel format.
+   */
+  public void setPixelFormatRGBTrueColor(int bitsPerPixel) {
+
+    switch(bitsPerPixel) {
+    case 8:
+      setPixelFormat(8, 8, false, false, -1, -1, -1, -1, -1, -1);
+      break;
+    case 15:
+      setPixelFormat(16, 15, false, true, 31, 31, 31, 0, 5, 10);
+      break;
+    case 16:
+      setPixelFormat(16, 16, false, true, 31, 63, 31, 0, 5, 11);
+      break;
+    case 24:
+      setPixelFormat(24, 24, false, true, 255, 255, 255, 0, 8, 16);
+      break;
+    case 32:
+      setPixelFormat(32, 24, false, true, 255, 255, 255, 0, 8, 16);
+      break;
+    default:
+      throw new RuntimeException("Unknown color depth.");
+    }
+
+  }
+
+  /**
+   * Store information about server screen size.
+   */
+  public void setFramebufferSize(int width, int height) {
+    if (height <= 0 || width <= 0)
+      throw new RuntimeException("Incorrect framebuffer size: " + width + "x" + height + ".");
+
+    this.framebufferWidth = width;
+    this.framebufferHeight = height;
+    
+    callSizeChangeListeners(width, height);
+  }
+
+  protected void callSizeChangeListeners(int width, int height) {
+    for(SizeChangeListener listener:sizeChangeListeners) {
+      listener.sizeChanged(width, height);
+    }
+  }
+
+  /**
+   * Store server desktop name.
+   */
+  public void setDesktopName(String desktopName) {
+    this.desktopName = desktopName;
+  }
+
+  // Getters for variables, as usual
+
+  public String getDesktopName() {
+    return desktopName;
+  }
+
+  public int getBytesPerPixel() {
+    return bytesPerPixel;
+  }
+
+  public int getFramebufferHeight() {
+    return framebufferHeight;
+  }
+
+  public int getFramebufferWidth() {
+    return framebufferWidth;
+  }
+
+  public boolean isRGB888_32_LE() {
+    return (colorDepth == 24 && bitsPerPixel == 32 && redShift == 0 && greenShift == 8 && blueShift == 16 && redMax == 255 && greenMax == 255 && blueMax == 255
+        && !bigEndianFlag && trueColorFlag);
+  }
+
+  @Override
+  public String toString() {
+    return "ScreenDescription [framebufferWidth=" + framebufferWidth + ", framebufferHeight=" + framebufferHeight + ", desktopName=" + desktopName
+        + ", bytesPerPixel=" + bytesPerPixel + ", depth=" + colorDepth + ", bitsPerPixel=" + bitsPerPixel + ", redShift=" + redShift + ", greenShift=" + greenShift
+        + ", blueShift=" + blueShift + ", redMax=" + redMax + ", greenMax=" + greenMax + ", blueMax=" + blueMax + ", bigEndianFlag=" + bigEndianFlag
+        + ", trueColorFlag=" + trueColorFlag + "]";
+  }
+
+  public void addSizeChangeListener(SizeChangeListener sizeChangeListener) {
+    sizeChangeListeners.add(sizeChangeListener);
+  }
+
+  public int getColorDeph() {
+    return colorDepth;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/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
new file mode 100644
index 0000000..d658d1b
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/common/SizeChangeListener.java
@@ -0,0 +1,22 @@
+// 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;
+
+public interface SizeChangeListener {
+
+  public void sizeChanged(int width, int height);
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/AwtRdpKeyboardAdapter.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/AwtRdpKeyboardAdapter.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/AwtRdpKeyboardAdapter.java
new file mode 100644
index 0000000..f19f09c
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/AwtRdpKeyboardAdapter.java
@@ -0,0 +1,351 @@
+// 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 rdpclient;
+
+import java.awt.event.KeyEvent;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+import streamer.Link;
+
+import common.KeyOrder;
+
+public class AwtRdpKeyboardAdapter extends BaseElement {
+
+  /**
+   * Absence of this flag indicates a key-down event, while its presence
+   * indicates a key-release event.
+   */
+  public static final int FASTPATH_INPUT_KBDFLAGS_RELEASE = 0x01;
+
+  /**
+   * Keystroke message contains an extended scancode. For enhanced 101-key and
+   * 102-key keyboards, extended keys include the right ALT and right CTRL keys
+   * on the main section of the keyboard; the INS, DEL, HOME, END, PAGE UP, PAGE
+   * DOWN and ARROW keys in the clusters to the left of the numeric keypad; and
+   * the Divide ("/") and ENTER keys in the numeric keypad.
+   */
+  public static final int FASTPATH_INPUT_KBDFLAGS_EXTENDED = 0x02;
+
+  public static final int FASTPATH_INPUT_EVENT_SCANCODE = 0;
+
+  public AwtRdpKeyboardAdapter(String id) {
+    super(id);
+  }
+
+  @Override
+  public void handleData(ByteBuffer buf, Link link) {
+    if (verbose)
+      System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+
+    KeyOrder order = (KeyOrder) buf.getOrder();
+    buf.unref();
+
+    ByteBuffer outBuf = new ByteBuffer(2, true);
+
+    int scanCode = map_en_us(order.event);
+
+    // eventHeader (1 byte): An 8-bit, unsigned integer. The format of this
+    // field is the same as the eventHeader byte field described in section
+    // 2.2.8.1.2.2. The eventCode bitfield (3 bits in size) MUST be set to
+    // FASTPATH_INPUT_EVENT_SCANCODE (0). The eventFlags bitfield (5 bits in
+    // size) contains flags describing the keyboard event.
+    outBuf.writeByte((scanCode >> 8) | (FASTPATH_INPUT_EVENT_SCANCODE << 5) | ((order.pressed) ? 0 : FASTPATH_INPUT_KBDFLAGS_RELEASE));
+
+    // keyCode (1 byte): An 8-bit, unsigned integer. The scancode of the key
+    // which triggered the event.
+    outBuf.writeByte(scanCode);
+
+    // Push buffer to one pad only, so it can be modified without copying of
+    // data
+    pushDataToPad(STDOUT, outBuf);
+  }
+
+  /**
+   * Return key scan code (in lower byte) and extended flags (in second byte).
+   */
+  private int map_en_us(KeyEvent event) {
+    // Also set extended key flag when necessary.
+    // For enhanced 101-key and 102-key keyboards, extended keys include the
+    // right ALT and right CTRL keys on the main section of the keyboard; the
+    // INS, DEL, HOME, END, PAGE UP, PAGE DOWN and ARROW keys in the clusters to
+    // the left of the numeric keypad; and the Divide ("/") and ENTER keys in
+    // the numeric keypad.
+
+    switch (event.getKeyCode()) {
+    // Functional keys
+    case KeyEvent.VK_ESCAPE:
+      return 1;
+    case KeyEvent.VK_F1:
+      return 59;
+    case KeyEvent.VK_F2:
+      return 60;
+    case KeyEvent.VK_F3:
+      return 61;
+    case KeyEvent.VK_F4:
+      return 62;
+    case KeyEvent.VK_F5:
+      return 63;
+    case KeyEvent.VK_F6:
+      return 64;
+    case KeyEvent.VK_F7:
+      return 65;
+    case KeyEvent.VK_F8:
+      return 66;
+    case KeyEvent.VK_F9:
+      return 67;
+    case KeyEvent.VK_F10:
+      return 68;
+    case KeyEvent.VK_F11:
+      return 87;
+    case KeyEvent.VK_F12:
+      return 88;
+
+      // Row #1
+    case KeyEvent.VK_BACK_QUOTE:
+      return 41;
+    case KeyEvent.VK_1:
+      return 2;
+    case KeyEvent.VK_2:
+      return 3;
+    case KeyEvent.VK_3:
+      return 4;
+    case KeyEvent.VK_4:
+      return 5;
+    case KeyEvent.VK_5:
+      return 6;
+    case KeyEvent.VK_6:
+      return 7;
+    case KeyEvent.VK_7:
+      return 8;
+    case KeyEvent.VK_8:
+      return 9;
+    case KeyEvent.VK_9:
+      return 10;
+    case KeyEvent.VK_0:
+      return 11;
+    case KeyEvent.VK_MINUS:
+      return 12;
+    case KeyEvent.VK_EQUALS:
+      return 13;
+    case KeyEvent.VK_BACK_SPACE:
+      return 14;
+
+      // Row #2
+    case KeyEvent.VK_TAB:
+      return 15;
+    case KeyEvent.VK_Q:
+      return 16;
+    case KeyEvent.VK_W:
+      return 17;
+    case KeyEvent.VK_E:
+      return 18;
+    case KeyEvent.VK_R:
+      return 19;
+    case KeyEvent.VK_T:
+      return 20;
+    case KeyEvent.VK_Y:
+      return 21;
+    case KeyEvent.VK_U:
+      return 22;
+    case KeyEvent.VK_I:
+      return 23;
+    case KeyEvent.VK_O:
+      return 24;
+    case KeyEvent.VK_P:
+      return 25;
+    case KeyEvent.VK_OPEN_BRACKET:
+      return 26;
+    case KeyEvent.VK_CLOSE_BRACKET:
+      return 27;
+    case KeyEvent.VK_ENTER:
+      switch (event.getKeyLocation()) {
+      default:
+      case KeyEvent.KEY_LOCATION_STANDARD:
+        return 28;
+      case KeyEvent.KEY_LOCATION_NUMPAD:
+        return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 28;
+      }
+
+      // Row #3
+    case KeyEvent.VK_CAPS_LOCK:
+      return 58;
+    case KeyEvent.VK_A:
+      return 30;
+    case KeyEvent.VK_S:
+      return 31;
+    case KeyEvent.VK_D:
+      return 32;
+    case KeyEvent.VK_F:
+      return 33;
+    case KeyEvent.VK_G:
+      return 34;
+    case KeyEvent.VK_H:
+      return 35;
+    case KeyEvent.VK_J:
+      return 36;
+    case KeyEvent.VK_K:
+      return 37;
+    case KeyEvent.VK_L:
+      return 38;
+    case KeyEvent.VK_SEMICOLON:
+      return 39;
+    case KeyEvent.VK_QUOTE:
+      return 40;
+
+      // Row #4
+    case KeyEvent.VK_SHIFT:
+      switch (event.getKeyLocation()) {
+      default:
+      case KeyEvent.KEY_LOCATION_LEFT:
+        return 42;
+      case KeyEvent.KEY_LOCATION_RIGHT:
+        return 54;
+      }
+    case KeyEvent.VK_BACK_SLASH:
+      return 43;
+    case KeyEvent.VK_Z:
+      return 44;
+    case KeyEvent.VK_X:
+      return 45;
+    case KeyEvent.VK_C:
+      return 46;
+    case KeyEvent.VK_V:
+      return 47;
+    case KeyEvent.VK_B:
+      return 48;
+    case KeyEvent.VK_N:
+      return 49;
+    case KeyEvent.VK_M:
+      return 50;
+    case KeyEvent.VK_COMMA:
+      return 51;
+    case KeyEvent.VK_PERIOD:
+      return 52;
+    case KeyEvent.VK_SLASH:
+      return 53;
+
+      //
+      // Bottom row
+    case KeyEvent.VK_CONTROL:
+      switch (event.getKeyLocation()) {
+      default:
+      case KeyEvent.KEY_LOCATION_LEFT:
+        return 29;
+      case KeyEvent.KEY_LOCATION_RIGHT:
+        return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 29;
+      }
+    case KeyEvent.VK_WINDOWS:
+      switch (event.getKeyLocation()) {
+      default:
+      case KeyEvent.KEY_LOCATION_LEFT:
+        return 91;
+      case KeyEvent.KEY_LOCATION_RIGHT:
+        return 92;
+      }
+    case KeyEvent.VK_ALT:
+      switch (event.getKeyLocation()) {
+      default:
+      case KeyEvent.KEY_LOCATION_LEFT:
+        return 56;
+      case KeyEvent.KEY_LOCATION_RIGHT:
+        return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 56;
+      }
+    case KeyEvent.VK_ALT_GRAPH:
+      return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 56;
+
+    case KeyEvent.VK_SPACE:
+      return 57;
+
+    case KeyEvent.VK_CONTEXT_MENU:
+      return 93;
+
+      //
+      // Special keys
+    case KeyEvent.VK_PRINTSCREEN:
+      return 55;
+    case KeyEvent.VK_SCROLL_LOCK:
+      return 70;
+    case KeyEvent.VK_PAUSE:
+      return 29;
+
+      // Text navigation keys
+    case KeyEvent.VK_INSERT:
+      return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 82;
+    case KeyEvent.VK_HOME:
+      return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 71;
+    case KeyEvent.VK_PAGE_UP:
+      return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 73;
+    case KeyEvent.VK_DELETE:
+      return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 83;
+    case KeyEvent.VK_END:
+      return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 79;
+    case KeyEvent.VK_PAGE_DOWN:
+      return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 81;
+
+      // Cursor keys
+    case KeyEvent.VK_UP:
+      return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 72;
+    case KeyEvent.VK_LEFT:
+      return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 75;
+    case KeyEvent.VK_DOWN:
+      return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 80;
+    case KeyEvent.VK_RIGHT:
+      return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 77;
+
+      // Keypad
+    case KeyEvent.VK_NUM_LOCK:
+      return 69;
+    case KeyEvent.VK_DIVIDE:
+      return (FASTPATH_INPUT_KBDFLAGS_EXTENDED << 8) | 53;
+    case KeyEvent.VK_MULTIPLY:
+      return 55;
+    case KeyEvent.VK_SUBTRACT:
+      return 74;
+    case KeyEvent.VK_ADD:
+      return 78;
+
+    case KeyEvent.VK_NUMPAD7:
+      return 71;
+    case KeyEvent.VK_NUMPAD8:
+      return 72;
+    case KeyEvent.VK_NUMPAD9:
+      return 73;
+    case KeyEvent.VK_NUMPAD4:
+      return 75;
+    case KeyEvent.VK_NUMPAD5:
+      return 76;
+    case KeyEvent.VK_NUMPAD6:
+      return 77;
+    case KeyEvent.VK_NUMPAD1:
+      return 79;
+    case KeyEvent.VK_NUMPAD2:
+      return 80;
+    case KeyEvent.VK_NUMPAD3:
+      return 81;
+    case KeyEvent.VK_NUMPAD0:
+      return 82;
+    case KeyEvent.VK_DECIMAL:
+      return 83;
+
+    default:
+      System.err.println("Key is not mapped: " + event + ".");
+      return 57; // Space
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a98c473d/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/AwtRdpMouseAdapter.java
----------------------------------------------------------------------
diff --git a/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/AwtRdpMouseAdapter.java b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/AwtRdpMouseAdapter.java
new file mode 100644
index 0000000..371bffc
--- /dev/null
+++ b/services/console-proxy-rdp/rdpconsole/src/main/java/rdpclient/AwtRdpMouseAdapter.java
@@ -0,0 +1,180 @@
+// 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 rdpclient;
+
+import java.awt.event.MouseEvent;
+
+import streamer.BaseElement;
+import streamer.ByteBuffer;
+import streamer.Link;
+
+import common.MouseOrder;
+
+/**
+ * @see http://msdn.microsoft.com/en-us/library/cc240594.aspx
+ */
+public class AwtRdpMouseAdapter extends BaseElement {
+  public static int FASTPATH_INPUT_EVENT_MOUSE = 0x01;
+
+  /**
+   * Event is a mouse wheel rotation. The only valid flags in a wheel rotation
+   * event are PTRFLAGS_WHEEL_NEGATIVE and the WheelRotationMask; all other
+   * pointer flags are ignored.
+   */
+  public static int PTRFLAGS_WHEEL = 0x0200;
+
+  /**
+   * Wheel rotation value (contained in the WheelRotationMask bit field) is
+   * negative and MUST be sign-extended before injection at the server.
+   */
+  public static int PTRFLAGS_WHEEL_NEGATIVE = 0x0100;
+
+  /**
+   * Bit field describing the number of rotation units the mouse wheel was
+   * rotated. The value is negative if the PTRFLAGS_WHEEL_NEGATIVE flag is set.
+   */
+  public static int WHEEL_ROTATION_MASK = 0x01FF;
+
+  /**
+   * Indicates that the mouse position MUST be updated to the location specified
+   * by the xPos and yPos fields.
+   */
+  public static int PTRFLAGS_MOVE = 0x0800;
+
+  /**
+   * Indicates that a click event has occurred at the position specified by the
+   * xPos and yPos fields. The button flags indicate which button has been
+   * clicked and at least one of these flags MUST be set.
+   */
+  public static int PTRFLAGS_DOWN = 0x8000;
+
+  /**
+   * Mouse button 1 (left button) was clicked or released. If the PTRFLAGS_DOWN
+   * flag is set, then the button was clicked, otherwise it was released.
+   */
+  public static int PTRFLAGS_BUTTON1 = 0x1000;
+
+  /**
+   * Mouse button 2 (right button) was clicked or released. If the PTRFLAGS_DOWN
+   * flag is set, then the button was clicked, otherwise it was released.
+   */
+  public static int PTRFLAGS_BUTTON2 = 0x2000;
+
+  /**
+   * Mouse button 3 (middle button or wheel) was clicked or released. If the
+   * PTRFLAGS_DOWN flag is set, then the button was clicked, otherwise it was
+   * released.
+   */
+  public static int PTRFLAGS_BUTTON3 = 0x4000;
+
+  public AwtRdpMouseAdapter(String id) {
+    super(id);
+  }
+
+  @Override
+  public void handleData(ByteBuffer buf, Link link) {
+    if (verbose)
+      System.out.println("[" + this + "] INFO: Data received: " + buf + ".");
+
+    // Get mouse event
+    MouseOrder order = (MouseOrder) buf.getOrder();
+
+    ByteBuffer outBuf = new ByteBuffer(7, true);
+
+    // eventHeader (1 byte): An 8-bit, unsigned integer. EventCode bitfield (top
+    // 3 bits) MUST be set to FASTPATH_INPUT_EVENT_MOUSE (1). The
+    // eventFlags bitfield (low 5 bits) MUST be zeroed out.
+    outBuf.writeByte(FASTPATH_INPUT_EVENT_MOUSE << 5);
+
+    // pointerFlags (2 bytes): A 16-bit, unsigned integer.
+    outBuf.writeShortLE(getPointerFlags(order));
+
+    // xPos (2 bytes): A 16-bit, unsigned integer. The x-coordinate of the
+    // pointer.
+    outBuf.writeShortLE(order.event.getX());
+
+    // yPos (2 bytes): A 16-bit, unsigned integer. The y-coordinate of the
+    // pointer.
+    outBuf.writeShortLE(order.event.getY());
+
+    // Push buffer to one pad only, so it can be modified without copying of
+    // data
+    pushDataToPad(STDOUT, outBuf);
+  }
+
+  // Remember mouse buttons
+  protected boolean button1, button2, button3;
+
+  protected int getPointerFlags(MouseOrder order) {
+    int flags = 0;
+
+    int modifiers = order.event.getModifiersEx();
+
+    if (order.pressed) {
+      // Mouse pressed
+      flags |= PTRFLAGS_DOWN;
+      
+      // Check, which one of buttons is released
+      boolean b1 = ((modifiers & MouseEvent.BUTTON1_DOWN_MASK) > 0) && !button1;
+      boolean b2 = ((modifiers & MouseEvent.BUTTON2_DOWN_MASK) > 0) && !button2;
+      boolean b3 = ((modifiers & MouseEvent.BUTTON3_DOWN_MASK) > 0) && !button3;
+
+      if (b1) {
+        flags |= PTRFLAGS_BUTTON1;
+        button1 = true;
+      }
+
+      if (b2) {
+        flags |= PTRFLAGS_BUTTON3;
+        button2 = true;
+      }
+
+      if (b3) {
+        flags |= PTRFLAGS_BUTTON2;
+        button3 = true;
+      }
+    } else if (order.released) {
+      // Mouse released
+      
+      // Check, which one of buttons is released
+      boolean b1 = !((modifiers & MouseEvent.BUTTON1_DOWN_MASK) > 0) && button1;
+      boolean b2 = !((modifiers & MouseEvent.BUTTON2_DOWN_MASK) > 0) && button2;
+      boolean b3 = !((modifiers & MouseEvent.BUTTON3_DOWN_MASK) > 0) && button3;
+
+      if (b1) {
+        flags |= PTRFLAGS_BUTTON1;
+        button1 = false;
+      }
+
+      if (b2) {
+        flags |= PTRFLAGS_BUTTON3;
+        button2 = false;
+      }
+
+      if (b3) {
+        flags |= PTRFLAGS_BUTTON2;
+        button3 = false;
+      }
+    } else {
+      // Mouse moved
+      flags |= PTRFLAGS_MOVE;
+    }
+
+    return flags;
+  }
+
+}