org.jwebsocket.plugins.flashbridge.FlashBridgePlugIn.java Source code

Java tutorial

Introduction

Here is the source code for org.jwebsocket.plugins.flashbridge.FlashBridgePlugIn.java

Source

//   ---------------------------------------------------------------------------
//   jWebSocket FlashBridge Plug-in (Community Edition, CE)
//   ---------------------------------------------------------------------------
//   Copyright 2010-2014 Innotrade GmbH (jWebSocket.org), Germany (NRW), Herzogenrath
//
//   Licensed 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 org.jwebsocket.plugins.flashbridge;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import java.util.Date;
import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.jwebsocket.api.PluginConfiguration;
import org.jwebsocket.api.WebSocketEngine;
import org.jwebsocket.config.JWebSocketCommonConstants;
import org.jwebsocket.config.JWebSocketConfig;
import org.jwebsocket.config.JWebSocketServerConstants;
import org.jwebsocket.logging.Logging;
import org.jwebsocket.plugins.TokenPlugIn;

/**
 * This plug-in processes the policy-file-request from the browser side flash
 * plug-in. This makes jWebSocket cross-browser-compatible.
 *
 * @author Alexander Schulze
 */
public class FlashBridgePlugIn extends TokenPlugIn {

    private static final Logger mLog = Logging.getLogger();
    private final static String VERSION = "1.0.0";
    private final static String VENDOR = JWebSocketCommonConstants.VENDOR_CE;
    private final static String LABEL = "jWebSocket FlashBridgePlugIn";
    private final static String COPYRIGHT = JWebSocketCommonConstants.COPYRIGHT_CE;
    private final static String LICENSE = JWebSocketCommonConstants.LICENSE_CE;
    private final static String DESCRIPTION = "jWebSocket FlashBridgePlugIn - Community Edition";
    /**
     *
     */
    public final static String NS_FLASH_BRIDGE = JWebSocketServerConstants.NS_BASE + ".plugins.flashbridge";

    private ServerSocket mServerSocket = null;
    private int mListenerPort = 843;
    private boolean mIsRunning = false;
    private int mEngineInstanceCount = 0;
    private BridgeProcess mBridgeProcess = null;
    private Thread mBridgeThread = null;
    private final static String PATH_TO_CROSSDOMAIN_XML = "crossdomain_xml";
    private final static String PORT_CONFIGURATION = "port";
    private static String mCrossDomainXML = "<cross-domain-policy>"
            + "<allow-access-from domain=\"*\" to-ports=\"*\" />" + "</cross-domain-policy>";

    /**
     *
     * @param aConfiguration
     */
    public FlashBridgePlugIn(PluginConfiguration aConfiguration) {
        super(aConfiguration);
        if (mLog.isDebugEnabled()) {
            mLog.debug("Instantiating FlashBridge plug-in...");
        }

        mGetSettings();
        // specify default name space for flash_bridge plug-in
        setNamespace(NS_FLASH_BRIDGE);
        try {
            mServerSocket = new ServerSocket(mListenerPort);

            mBridgeProcess = new BridgeProcess(this);
            mBridgeThread = new Thread(mBridgeProcess);
            mBridgeThread.start();
            if (mLog.isInfoEnabled()) {
                mLog.info("FlashBridge plug-in successfully instantiated and listening on port " + mListenerPort);
            }
        } catch (IOException lEx) {
            mLog.error("FlashBridge could not be started: " + lEx.getMessage());
        }
    }

    private void mGetSettings() {
        // load global settings, default to "true"
        String lPathToCrossDomainXML = getString(PATH_TO_CROSSDOMAIN_XML);
        if (lPathToCrossDomainXML != null) {
            try {
                if (mLog.isDebugEnabled()) {
                    mLog.debug("Trying to load " + lPathToCrossDomainXML + "...");
                }
                lPathToCrossDomainXML = JWebSocketConfig.expandEnvVarsAndProps(lPathToCrossDomainXML);
                if (mLog.isDebugEnabled()) {
                    mLog.debug("Trying to load expanded " + lPathToCrossDomainXML + "...");
                }
                URL lURL = JWebSocketConfig.getURLFromPath(lPathToCrossDomainXML);
                if (mLog.isDebugEnabled()) {
                    mLog.debug("Trying to load from URL " + lURL + "...");
                }
                File lFile = new File(lURL.getPath());
                mCrossDomainXML = FileUtils.readFileToString(lFile, "UTF-8");
                if (mLog.isInfoEnabled()) {
                    mLog.info("crossdomain config successfully loaded from " + lPathToCrossDomainXML + ".");
                }
            } catch (IOException lEx) {
                mLog.error(lEx.getClass().getSimpleName() + " reading crossdomain.xml: " + lEx.getMessage());
            }
        }
        String lPort = getString(PORT_CONFIGURATION);
        if (lPort != null) {
            try {
                // Checking if there is any port defined in the configuration
                Integer lInPort = Integer.parseInt(lPort.trim());
                if (lInPort > 0) {
                    mListenerPort = lInPort;
                }
            } catch (NumberFormatException e) {
                mLog.error("Port configuration error found while trying to parse " + lPort
                        + ". Please check your Flashbridge port configuration section");
            }
        }
    }

    /**
     * @return the mCrossDomainXML
     */
    public static String getCrossDomainXML() {
        return mCrossDomainXML;
    }

    @Override
    public String getVersion() {
        return VERSION;
    }

    @Override
    public String getLabel() {
        return LABEL;
    }

    @Override
    public String getDescription() {
        return DESCRIPTION;
    }

    @Override
    public String getVendor() {
        return VENDOR;
    }

    @Override
    public String getCopyright() {
        return COPYRIGHT;
    }

    @Override
    public String getLicense() {
        return LICENSE;
    }

    @Override
    public String getNamespace() {
        return NS_FLASH_BRIDGE;
    }

    private class BridgeProcess implements Runnable {

        private final FlashBridgePlugIn mPlugIn;

        /**
         * creates the server socket bridgeProcess for new incoming socket
         * connections.
         *
         * @param aPlugIn
         */
        public BridgeProcess(FlashBridgePlugIn aPlugIn) {
            mPlugIn = aPlugIn;
        }

        @Override
        public void run() {

            if (mLog.isDebugEnabled()) {
                mLog.debug("Starting FlashBridge process...");
            }
            mIsRunning = true;
            Thread.currentThread().setName("jWebSocket FlashBridge");
            while (mIsRunning) {
                try {
                    // accept is blocking so here is no need
                    // to put any sleeps into the loop
                    if (mLog.isDebugEnabled()) {
                        mLog.debug("Waiting on flash policy-file-request on port " + mServerSocket.getLocalPort()
                                + "...");
                    }
                    Socket lClientSocket = mServerSocket.accept();
                    if (mLog.isDebugEnabled()) {
                        mLog.debug("Client connected...");
                    }
                    try {
                        // clientSocket.setSoTimeout(TIMEOUT);
                        InputStream lIS = lClientSocket.getInputStream();
                        OutputStream lOS = lClientSocket.getOutputStream();
                        byte[] lBA = new byte[4096];
                        String lLine = "";
                        boolean lFoundPolicyFileRequest = false;
                        int lLen = 0;
                        while (lLen >= 0 && !lFoundPolicyFileRequest) {
                            lLen = lIS.read(lBA);
                            if (lLen > 0) {
                                lLine += new String(lBA, 0, lLen, "US-ASCII");
                            }
                            if (mLog.isDebugEnabled()) {
                                mLog.debug("Received " + lLine + "...");
                            }
                            lFoundPolicyFileRequest = lLine.contains("policy-file-request"); // "<policy-file-request/>"
                        }
                        if (lFoundPolicyFileRequest) {
                            if (mLog.isDebugEnabled()) {
                                mLog.debug("Answering on flash policy-file-request (" + lLine + ")...");
                                // mLog.debug("Answer: " + mCrossDomainXML);
                            }
                            lOS.write(getCrossDomainXML().getBytes("UTF-8"));
                            lOS.flush();
                        } else {
                            mLog.warn("Received invalid policy-file-request (" + lLine + ")...");
                        }
                    } catch (IOException lEx) {
                        mLog.error(lEx.getClass().getSimpleName() + ": " + lEx.getMessage());
                    }

                    lClientSocket.close();
                    if (mLog.isDebugEnabled()) {
                        mLog.debug("Client disconnected...");
                    }
                } catch (IOException lEx) {
                    if (mIsRunning) {
                        mIsRunning = false;
                        mLog.error(lEx.getClass().getSimpleName() + ": " + lEx.getMessage());
                    }
                    // otherwise closing the socket was intended, 
                    // no error in this case!
                }
            }
            if (mLog.isInfoEnabled()) {
                mLog.info("FlashBridge process stopped.");
            }
        }
    }

    @Override
    public void engineStarted(WebSocketEngine aEngine) {
        if (mLog.isDebugEnabled()) {
            mLog.debug("Engine '" + aEngine.getId() + "' started.");
        }
        // every time an engine starts increment counter
        mEngineInstanceCount++;
    }

    @Override
    public void engineStopped(WebSocketEngine aEngine) {
        if (mLog.isDebugEnabled()) {
            mLog.debug("Engine '" + aEngine.getId() + "' stopped.");
        }
        // every time an engine starts decrement counter
        mEngineInstanceCount--;
        // when last engine stopped also stop the FlashBridge
        if (mEngineInstanceCount <= 0) {
            super.engineStopped(aEngine);

            mIsRunning = false;
            long lStarted = new Date().getTime();

            try {
                // when done, close server socket
                // closing the server socket should lead to an exception
                // at accept in the bridgeProcess thread which terminates the
                // bridgeProcess
                if (mLog.isDebugEnabled()) {
                    mLog.debug("Closing FlashBridge server socket...");
                }
                mServerSocket.close();
                if (mLog.isDebugEnabled()) {
                    mLog.debug("Closed FlashBridge server socket.");
                }
            } catch (IOException ex) {
                mLog.error("(accept) " + ex.getClass().getSimpleName() + ": " + ex.getMessage());
            }

            try {
                mBridgeThread.join(10000);
            } catch (InterruptedException ex) {
                mLog.error(ex.getClass().getSimpleName() + ": " + ex.getMessage());
            }
            if (mLog.isDebugEnabled()) {
                long lDuration = new Date().getTime() - lStarted;
                if (mBridgeThread.isAlive()) {
                    mLog.warn("FlashBridge did not stopped after " + lDuration + "ms.");
                } else {
                    mLog.debug("FlashBridge stopped after " + lDuration + "ms.");
                }
            }
        }
    }
}