Package com.cloud.consoleproxy

Source Code of com.cloud.consoleproxy.ConsoleProxyClientBase

// 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 com.cloud.consoleproxy;

import java.awt.Image;
import java.awt.Rectangle;
import java.util.List;

import javassist.tools.web.Viewer;

import org.apache.log4j.Logger;

import com.cloud.consoleproxy.util.TileInfo;
import com.cloud.consoleproxy.util.TileTracker;
import com.cloud.consoleproxy.vnc.FrameBufferCanvas;

/**
*
* an instance of specialized console protocol implementation, such as VNC or RDP
*
* It mainly implements the features needed by front-end AJAX viewer
*
*/
public abstract class ConsoleProxyClientBase implements ConsoleProxyClient, ConsoleProxyClientListener {
    private static final Logger s_logger = Logger.getLogger(ConsoleProxyClientBase.class);
   
    private static int s_nextClientId = 0;
    protected int clientId = getNextClientId();
   
    protected long ajaxSessionId = 0;
   
    protected boolean dirtyFlag = false;
    protected Object tileDirtyEvent = new Object();
    protected TileTracker tracker;
    protected AjaxFIFOImageCache ajaxImageCache = new AjaxFIFOImageCache(2);

    protected ConsoleProxyClientParam clientParam;
    protected String clientToken;
   
    protected long createTime = System.currentTimeMillis();
    protected long lastFrontEndActivityTime = System.currentTimeMillis();

    protected boolean framebufferResized = false;
    protected int resizedFramebufferWidth;
    protected int resizedFramebufferHeight;

    public ConsoleProxyClientBase() {
        tracker = new TileTracker();
        tracker.initTracking(64, 64, 800, 600);
    }

    //
    // interface ConsoleProxyClient
    //
    @Override
    public int getClientId() {
        return clientId;
    }
   
    public abstract boolean isHostConnected();
    public abstract boolean isFrontEndAlive();

    @Override
    public long getAjaxSessionId() {
        return this.ajaxSessionId;
    }
   
    @Override
    public AjaxFIFOImageCache getAjaxImageCache() {
        return ajaxImageCache;
    }
   
    public Image getClientScaledImage(int width, int height) {
        FrameBufferCanvas canvas = getFrameBufferCavas();
        if(canvas != null)
            return canvas.getFrameBufferScaledImage(width, height);
       
        return null;
    }
   
    public abstract void sendClientRawKeyboardEvent(InputEventType event, int code, int modifiers);
    public abstract void sendClientMouseEvent(InputEventType event, int x, int y, int code, int modifiers);
   
    @Override
    public long getClientCreateTime() {
        return createTime;
    }
   
    @Override
    public long getClientLastFrontEndActivityTime() {
        return lastFrontEndActivityTime;
    }
   
    @Override
    public String getClientHostAddress() {
        return clientParam.getClientHostAddress();
    }
   
    @Override
    public int getClientHostPort() {
        return clientParam.getClientHostPort();
    }
   
    @Override
    public String getClientHostPassword() {
        return clientParam.getClientHostPassword();
    }
   
    @Override
    public String getClientTag() {
        if(clientParam.getClientTag() != null)
            return clientParam.getClientTag();
        return "";
    }

    @Override
    public abstract void initClient(ConsoleProxyClientParam param);
       
    @Override
    public abstract void closeClient();
   
    //
    // interface FrameBufferEventListener
    //
    @Override
    public void onFramebufferSizeChange(int w, int h) {
        tracker.resize(w, h);

        synchronized(this) {
            framebufferResized = true;
            resizedFramebufferWidth = w;
            resizedFramebufferHeight = h;
        }
       
        signalTileDirtyEvent();
    }

    @Override
    public void onFramebufferUpdate(int x, int y, int w, int h) {
        if(s_logger.isTraceEnabled())
            s_logger.trace("Frame buffer update {" + x + "," + y + "," + w + "," + h + "}");
        tracker.invalidate(new Rectangle(x, y, w, h));
       
        signalTileDirtyEvent();
    }
   
    //
    // AJAX Image manipulation
    //
    public byte[] getFrameBufferJpeg() {
        FrameBufferCanvas canvas = getFrameBufferCavas();
        if(canvas != null)
            return canvas.getFrameBufferJpeg();
       
        return null;
    }
   
    public byte[] getTilesMergedJpeg(List<TileInfo> tileList, int tileWidth, int tileHeight) {
        FrameBufferCanvas canvas = getFrameBufferCavas();
        if(canvas != null)
            return canvas.getTilesMergedJpeg(tileList, tileWidth, tileHeight);
        return null;
    }
   
    private String prepareAjaxImage(List<TileInfo> tiles, boolean init) {
        byte[] imgBits;
        if(init)
            imgBits = getFrameBufferJpeg();
        else
            imgBits = getTilesMergedJpeg(tiles, tracker.getTileWidth(), tracker.getTileHeight());
       
        if(imgBits == null) {
            s_logger.warn("Unable to generate jpeg image");
        } else {
            if(s_logger.isTraceEnabled())
                s_logger.trace("Generated jpeg image size: " + imgBits.length);
        }
       
        int key = ajaxImageCache.putImage(imgBits);
        StringBuffer sb = new StringBuffer();
        sb.append("/ajaximg?token=").append(clientToken);
        sb.append("&key=").append(key);
        sb.append("&ts=").append(System.currentTimeMillis());
       
        return sb.toString();
    }
   
    private String prepareAjaxSession(boolean init) {
        if(init) {
            synchronized(this) {
                ajaxSessionId++;
            }
        }

        StringBuffer sb = new StringBuffer();
        sb.append("/ajax?token=").append(clientToken).append("&sess=").append(ajaxSessionId);
        return sb.toString();
    }

    @Override
    public String onAjaxClientKickoff() {
        return "onKickoff();";
    }
   
    private boolean waitForViewerReady() {
        long startTick = System.currentTimeMillis();
        while(System.currentTimeMillis() - startTick < 5000) {
            if(getFrameBufferCavas() != null)
                return true;
           
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
            }
        }
        return false;
    }
   
    private String onAjaxClientConnectFailed() {
        return "<html><head></head><body><div id=\"main_panel\" tabindex=\"1\"><p>" +
            "Unable to start console session as connection is refused by the machine you are accessing" +
            "</p></div></body></html>";
    }

    @Override
    public String onAjaxClientStart(String title, List<String> languages, String guest) {
        updateFrontEndActivityTime();
       
        if(!waitForViewerReady())
            return onAjaxClientConnectFailed();
       
        synchronized(this) {
            ajaxSessionId++;
            framebufferResized = false;
        }
       
        int tileWidth = tracker.getTileWidth();
        int tileHeight = tracker.getTileHeight();
        int width = tracker.getTrackWidth();
        int height = tracker.getTrackHeight();
       
        if(s_logger.isTraceEnabled())
            s_logger.trace("Ajax client start, frame buffer w: " + width + ", " + height);

/*       
        int retry = 0;
        tracker.initCoverageTest();
        while(!tracker.hasFullCoverage() && retry < 10) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
            retry++;
        }
*/
       
        List<TileInfo> tiles = tracker.scan(true);
        String imgUrl = prepareAjaxImage(tiles, true);
        String updateUrl = prepareAjaxSession(true);
       
        StringBuffer sbTileSequence = new StringBuffer();
        int i = 0;
        for(TileInfo tile : tiles) {
            sbTileSequence.append("[").append(tile.getRow()).append(",").append(tile.getCol()).append("]");
            if(i < tiles.size() - 1)
                sbTileSequence.append(",");
           
            i++;
        }

        return getAjaxViewerPageContent(sbTileSequence.toString(), imgUrl,
            updateUrl, width, height, tileWidth, tileHeight, title,
            ConsoleProxy.keyboardType == ConsoleProxy.KEYBOARD_RAW,
            languages, guest, this.clientParam.getLocale());
    }
   
    private String getAjaxViewerPageContent(String tileSequence, String imgUrl, String updateUrl, int width,
        int height, int tileWidth, int tileHeight, String title, boolean rawKeyboard, List<String> languages, String guest, String locale) {

        StringBuffer sbLanguages = new StringBuffer("");
        if(languages != null) {
            for(String lang : languages) {
                if(sbLanguages.length() > 0) {
                    sbLanguages.append(",");
                }
                sbLanguages.append(lang);
            }
        }
       
        String[] content = new String[] {
            "<html>",
            "<head>",
            "<script type=\"text/javascript\" language=\"javascript\" src=\"/resource/js/jquery.js\"></script>",
            "<script type=\"text/javascript\" language=\"javascript\" src=\"/resource/js/cloud.logger.js\"></script>",
            "<script type=\"text/javascript\" language=\"javascript\" src=\"/resource/js/ajaxkeys.js\"></script>",
            "<script type=\"text/javascript\" language=\"javascript\" src=\"/resource/js/ajaxviewer.js\"></script>",
            "<script type=\"text/javascript\" language=\"javascript\" src=\"/resource/js/handler.js\"></script>",
            "<link rel=\"stylesheet\" type=\"text/css\" href=\"/resource/css/ajaxviewer.css\"></link>",
            "<link rel=\"stylesheet\" type=\"text/css\" href=\"/resource/css/logger.css\"></link>",
            "<title>" + title + "</title>",
            "</head>",
            "<body>",
            "<div id=\"toolbar\">",
            "<ul>",
                "<li>",
                    "<a href=\"#\" cmd=\"sendCtrlAltDel\">",
                        "<span><img align=\"left\" src=\"/resource/images/cad.gif\" alt=\"Ctrl-Alt-Del\" />Ctrl-Alt-Del</span>",
                    "</a>",
                "</li>",
                "<li>",
                    "<a href=\"#\" cmd=\"sendCtrlEsc\">",
                        "<span><img align=\"left\" src=\"/resource/images/winlog.png\" alt=\"Ctrl-Esc\" style=\"width:16px;height:16px\"/>Ctrl-Esc</span>",
                    "</a>",
                "</li>",
               
                "<li class=\"pulldown\">",
                    "<a href=\"#\">",
                        "<span><img align=\"left\" src=\"/resource/images/winlog.png\" alt=\"Keyboard\" style=\"width:16px;height:16px\"/>Keyboard</span>",
                    "</a>",
                    "<ul>",
                        "<li><a href=\"#\" cmd=\"keyboard_us\"><span>Standard (US) keyboard</span></a></li>",
                        "<li><a href=\"#\" cmd=\"keyboard_uk\"><span>UK keyboard</span></a></li>",
                        "<li><a href=\"#\" cmd=\"keyboard_jp\"><span>Japanese keyboard</span></a></li>",
                    "</ul>",
                "</li>",
            "</ul>",
            "<span id=\"light\" class=\"dark\" cmd=\"toggle_logwin\"></span>",
            "</div>",
            "<div id=\"main_panel\" tabindex=\"1\"></div>",
            "<script language=\"javascript\">",
            "var acceptLanguages = '" + sbLanguages.toString() + "';",
            "var tileMap = [ " + tileSequence + " ];",
            "var ajaxViewer = new AjaxViewer('main_panel', '" + imgUrl + "', '" + updateUrl + "', '" + locale + "', tileMap, ",
                String.valueOf(width) + ", " + String.valueOf(height) + ", " + String.valueOf(tileWidth) + ", " + String.valueOf(tileHeight) + ");",

            "$(function() {",
                "ajaxViewer.start();",
            "});",

            "</script>",
            "</body>",
            "</html>"  
        };
       
        StringBuffer sb = new StringBuffer();
        for(int i = 0; i < content.length; i++)
            sb.append(content[i]);
       
        return sb.toString();
    }
   
    public String onAjaxClientDisconnected() {
        return "onDisconnect();";
    }

    @Override
    public String onAjaxClientUpdate() {
        updateFrontEndActivityTime();
        if(!waitForViewerReady())
            return onAjaxClientDisconnected();
       
        synchronized(tileDirtyEvent) {
            if(!dirtyFlag) {
                try {
                    tileDirtyEvent.wait(3000);
                } catch(InterruptedException e) {
                }
            }
        }
       
        boolean doResize = false;
        synchronized(this) {
            if(framebufferResized) {
                framebufferResized = false;
                doResize = true;
            }
        }
       
        List<TileInfo> tiles;
       
        if(doResize)
            tiles = tracker.scan(true);
        else
            tiles = tracker.scan(false);
        dirtyFlag = false;
       
        String imgUrl = prepareAjaxImage(tiles, false);
        StringBuffer sbTileSequence = new StringBuffer();
        int i = 0;
        for(TileInfo tile : tiles) {
            sbTileSequence.append("[").append(tile.getRow()).append(",").append(tile.getCol()).append("]");
            if(i < tiles.size() - 1)
                sbTileSequence.append(",");
           
            i++;
        }

        return getAjaxViewerUpdatePageContent(sbTileSequence.toString(), imgUrl, doResize,
            resizedFramebufferWidth, resizedFramebufferHeight,
            tracker.getTileWidth(), tracker.getTileHeight());
    }
   
    private String getAjaxViewerUpdatePageContent(String tileSequence, String imgUrl, boolean resized, int width,
        int height, int tileWidth, int tileHeight) {
       
        String[] content = new String[] {
            "tileMap = [ " + tileSequence + " ];",
            resized ? "ajaxViewer.resize('main_panel', " + width + ", " + height + " , " + tileWidth + ", " + tileHeight + ");" : "",
            "ajaxViewer.refresh('" + imgUrl + "', tileMap, false);"
        };
       
        StringBuffer sb = new StringBuffer();
        for(int i = 0; i < content.length; i++)
            sb.append(content[i]);
       
        return sb.toString();
    }
   
    //
    // Helpers
    //
    private synchronized static int getNextClientId() {
        return ++s_nextClientId;
    }
   
    private void signalTileDirtyEvent() {
        synchronized(tileDirtyEvent) {
            dirtyFlag = true;
            tileDirtyEvent.notifyAll();
        }
    }
   
    public void updateFrontEndActivityTime() {
        lastFrontEndActivityTime = System.currentTimeMillis();
    }

    protected abstract FrameBufferCanvas getFrameBufferCavas();

    public ConsoleProxyClientParam getClientParam() {
        return clientParam;
    }

    public void setClientParam(ConsoleProxyClientParam clientParam) {
        this.clientParam = clientParam;
        ConsoleProxyPasswordBasedEncryptor encryptor = new ConsoleProxyPasswordBasedEncryptor(ConsoleProxy.getEncryptorPassword());
        this.clientToken = encryptor.encryptObject(ConsoleProxyClientParam.class, clientParam);
    }
}
TOP

Related Classes of com.cloud.consoleproxy.ConsoleProxyClientBase

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.