Package org.restlet.ext.sdc.internal

Source Code of org.restlet.ext.sdc.internal.SdcServerConnection

/**
* Copyright 2005-2011 Noelios Technologies.
*
* The contents of this file are subject to the terms of one of the following
* open source licenses: LGPL 3.0 or LGPL 2.1 or CDDL 1.0 or EPL 1.0 (the
* "Licenses"). You can select the license that you prefer but you may not use
* this file except in compliance with one of these Licenses.
*
* You can obtain a copy of the LGPL 3.0 license at
* http://www.opensource.org/licenses/lgpl-3.0.html
*
* You can obtain a copy of the LGPL 2.1 license at
* http://www.opensource.org/licenses/lgpl-2.1.php
*
* You can obtain a copy of the CDDL 1.0 license at
* http://www.opensource.org/licenses/cddl1.php
*
* You can obtain a copy of the EPL 1.0 license at
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the Licenses for the specific language governing permissions and
* limitations under the Licenses.
*
* Alternatively, you can obtain a royalty free commercial license with less
* limitations, transferable or non-transferable, directly at
* http://www.noelios.com/products/restlet-engine
*
* Restlet is a registered trademark of Noelios Technologies.
*/

package org.restlet.ext.sdc.internal;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.net.ssl.SSLSocket;

import org.restlet.ext.sdc.SdcClientHelper;

import com.google.dataconnector.protocol.Dispatchable;
import com.google.dataconnector.protocol.FrameReceiver;
import com.google.dataconnector.protocol.FrameSender;
import com.google.dataconnector.protocol.FramingException;
import com.google.dataconnector.protocol.proto.SdcFrame;
import com.google.dataconnector.protocol.proto.SdcFrame.AuthorizationInfo;
import com.google.dataconnector.protocol.proto.SdcFrame.AuthorizationInfo.ResultCode;
import com.google.dataconnector.protocol.proto.SdcFrame.FetchReply;
import com.google.dataconnector.protocol.proto.SdcFrame.FrameInfo;
import com.google.dataconnector.protocol.proto.SdcFrame.FrameInfo.Type;
import com.google.dataconnector.protocol.proto.SdcFrame.HealthCheckInfo;
import com.google.dataconnector.protocol.proto.SdcFrame.HealthCheckInfo.Source;
import com.google.dataconnector.protocol.proto.SdcFrame.RegistrationRequestV4;
import com.google.dataconnector.protocol.proto.SdcFrame.RegistrationResponseV4;
import com.google.dataconnector.protocol.proto.SdcFrame.ServerSuppliedConf;
import com.google.dataconnector.util.ShutdownManager;
import com.google.protobuf.InvalidProtocolBufferException;

/**
* The SDC server connection established between this SDC client connector,
* acting as the tunnel server and a remote SDC agent.
*
* @author Jerome Louvel
*/
public class SdcServerConnection implements Dispatchable {

    /** The map of pending SDC/HTTP client calls, keyed by the unique call ID. */
    private final Map<String, SdcClientCall> calls;

    /** The receiver for SDC Frame protocol. */
    private final FrameReceiver frameReceiver;

    /** The sender for SDC Frame protocol. */
    private final FrameSender frameSender;

    /** The parent SDC client helper. */
    private final SdcClientHelper helper;

    /** The socket input stream. */
    private final InputStream inputStream;

    /** The authorization key composed of the email address and the password. */
    private volatile String key;

    /** The socket output stream. */
    private final OutputStream outputStream;

    /** The SSL connection socket. */
    private final SSLSocket socket;

    /**
     * Constructor.
     *
     * @param helper
     *            The parent SDC client helper.
     * @param socket
     *            The SSL connection socket.
     * @throws IOException
     */
    public SdcServerConnection(SdcClientHelper helper, SSLSocket socket)
            throws IOException {
        this.helper = helper;
        this.socket = socket;
        this.inputStream = socket.getInputStream();
        this.outputStream = socket.getOutputStream();
        this.frameReceiver = new FrameReceiver();
        this.frameReceiver.setInputStream(getInputStream());
        this.calls = new ConcurrentHashMap<String, SdcClientCall>();

        BlockingQueue<FrameInfo> sendQueue = new LinkedBlockingQueue<SdcFrame.FrameInfo>();
        ShutdownManager shutdownManager = new ShutdownManager();
        this.frameSender = new FrameSender(sendQueue, shutdownManager);
        this.frameSender.setOutputStream(getOutputStream());
    }

    /**
     * Connects this SDC tunnel with one remote SDC agent.
     *
     * @throws IOException
     */
    public void connect() throws IOException {
        try {
            // Initial handshakecom.google.dataconnector.util.ShutdownManager
            readHandshake();

            // Authorization step
            FrameInfo frameInfo = getFrameReceiver().readOneFrame();

            if (frameInfo.getType() == FrameInfo.Type.AUTHORIZATION) {
                AuthorizationInfo authorizationRequest = AuthorizationInfo
                        .parseFrom(frameInfo.getPayload());
                setKey(authorizationRequest.getEmail() + ":"
                        + authorizationRequest.getPassword());

                AuthorizationInfo authorizationResponse = AuthorizationInfo
                        .newBuilder().setResult(ResultCode.OK).build();

                getFrameSender().sendFrame(FrameInfo.Type.AUTHORIZATION,
                        authorizationResponse.toByteString());

                // Register frame dispatchers
                getFrameReceiver().registerDispatcher(Type.FETCH_REQUEST, this);
                getFrameReceiver().registerDispatcher(Type.REGISTRATION, this);
                getFrameReceiver().registerDispatcher(Type.HEALTH_CHECK, this);

                // Launch a thread to asynchronously receive incoming frames
                getHelper().getWorkerService().execute(new Runnable() {
                    public void run() {
                        try {
                            getFrameReceiver().startDispatching();
                        } catch (FramingException e) {
                            e.printStackTrace();
                        }
                    }
                });

                // Launch a thread to asynchronously send outgoing frames
                getHelper().getWorkerService().execute(new Runnable() {
                    public void run() {
                        getFrameSender().run();
                    }
                });
            } else {
                System.out
                        .println("Unable to authorize the connection. Wrong frame type received: "
                                + frameInfo);
            }
        } catch (FramingException e) {
            e.printStackTrace();
        }
    }

    /**
     * Asynchronously process the response frames received from the SDC agent.
     *
     * @param frameInfo
     *            The SDC frame to parse.
     */
    public void dispatch(FrameInfo frameInfo) throws FramingException {
        try {
            if (frameInfo.getType() == Type.FETCH_REQUEST) {
                FetchReply fetchReply = FetchReply.parseFrom(frameInfo
                        .getPayload());

                if (getLogger().isLoggable(Level.FINE)) {
                    getLogger().log(Level.FINE,
                            "SDC response received: " + fetchReply.toString());
                }

                // Lookup the associated SDC request
                SdcClientCall call = getCalls().get(fetchReply.getId());

                if (call != null) {
                    call.setFetchReply(fetchReply);

                    // Unblock the client thread
                    call.getLatch().countDown();
                } else if (getLogger().isLoggable(Level.WARNING)) {
                    getLogger()
                            .log(Level.WARNING,
                                    "Unable to find the SDC request associated to the received response");
                }
            } else if (frameInfo.getType() == FrameInfo.Type.REGISTRATION) {
                RegistrationRequestV4 registrationRequest = RegistrationRequestV4
                        .parseFrom(frameInfo.getPayload());

                if (getLogger().isLoggable(Level.FINE)) {
                    getLogger().log(
                            Level.FINE,
                            "SDC tunnel registration received: "
                                    + registrationRequest);
                }

                RegistrationResponseV4 registrationResponse = RegistrationResponseV4
                        .newBuilder()
                        .setResult(
                                com.google.dataconnector.protocol.proto.SdcFrame.RegistrationResponseV4.ResultCode.OK)
                        .setServerSuppliedConf(
                                ServerSuppliedConf.newBuilder()
                                        .setHealthCheckTimeout(5000)
                                        .setHealthCheckWakeUpInterval(5000)
                                        .build()).build();

                getFrameSender().sendFrame(FrameInfo.Type.REGISTRATION,
                        registrationResponse.toByteString());
            } else if (frameInfo.getType() == Type.HEALTH_CHECK) {
                HealthCheckInfo healthCheckResponse = HealthCheckInfo
                        .newBuilder()
                        .setSource(Source.SERVER)
                        .setTimeStamp(System.currentTimeMillis())
                        .setType(
                                com.google.dataconnector.protocol.proto.SdcFrame.HealthCheckInfo.Type.RESPONSE)
                        .build();

                if (getLogger().isLoggable(Level.FINE)) {
                    getLogger()
                            .log(Level.FINE,
                                    "SDC health check received: "
                                            + healthCheckResponse);
                }

                // Reply to the check
                getFrameSender().sendFrame(Type.HEALTH_CHECK,
                        healthCheckResponse.toByteString());
            } else if (getLogger().isLoggable(Level.FINE)) {
                getLogger().log(Level.FINE,
                        "Unexpected SDC frame received: " + frameInfo);
            }
        } catch (InvalidProtocolBufferException e) {
            getLogger().log(Level.WARNING, "Invalid SDC frame received", e);
        }
    }

    /**
     * Returns the map of pending SDC/HTTP client calls, keyed by the unique
     * call ID.
     *
     * @return The map of pending SDC/HTTP client calls, keyed by the unique
     *         call ID.
     */
    public Map<String, SdcClientCall> getCalls() {
        return calls;
    }

    /**
     * Returns the receiver for SDC Frame protocol.
     *
     * @return The receiver for SDC Frame protocol.
     */
    public FrameReceiver getFrameReceiver() {
        return frameReceiver;
    }

    /**
     * Returns the sender for SDC Frame protocol.
     *
     * @return The sender for SDC Frame protocol.
     */
    public FrameSender getFrameSender() {
        return frameSender;
    }

    /**
     * Returns the parent SDC client helper.
     *
     * @return The parent SDC client helper.
     */
    public SdcClientHelper getHelper() {
        return helper;
    }

    /**
     * Returns the socket input stream.
     *
     * @return The socket input stream.
     */
    public InputStream getInputStream() {
        return inputStream;
    }

    /**
     * Returns the authorization key composed of the email address and the
     * password separated by a colon character.
     *
     * @return The authorization key.
     */
    public String getKey() {
        return key;
    }

    /**
     * Returns the current logger.
     *
     * @return The current logger.
     */
    public Logger getLogger() {
        return getHelper().getLogger();
    }

    /**
     * Returns the socket output stream.
     *
     * @return The socket output stream.
     */
    public OutputStream getOutputStream() {
        return outputStream;
    }

    /**
     * Returns the SSL connection socket.
     *
     * @return The SSL connection socket.
     */
    public SSLSocket getSocket() {
        return socket;
    }

    /**
     * Reads the SDC initial handshake message from the socket input stream.
     *
     * @return The SDC initial handshake message from the socket input stream.
     * @throws IOException
     */
    protected boolean readHandshake() throws IOException {
        boolean result = true;
        byte[] hsm = ("v5.0 "
                + FrameReceiver.class.getPackage().getImplementationVersion() + "\n")
                .getBytes();
        int c;

        for (int i = 0; result && (i < hsm.length); i++) {
            c = getInputStream().read();
            result = (c == hsm[i]);
        }

        return result;
    }

    /**
     * Effectively send the requests using the SDC frame protocol. It also
     * stores the call in the map to be later be able to associate it with its
     * response.
     *
     * @param call
     *            The SDC client call to be sent.
     */
    public void sendRequest(SdcClientCall call) {
        getCalls().put(call.getFetchRequest().getId(), call);
        getFrameSender().sendFrame(FrameInfo.Type.FETCH_REQUEST,
                call.getFetchRequest().toByteString());

    }

    /**
     * Sets the authorization key composed of the email address and the password
     * separated by a colon character.
     *
     * @param key
     *            The authorization key.
     */
    public void setKey(String key) {
        this.key = key;
    }

}
TOP

Related Classes of org.restlet.ext.sdc.internal.SdcServerConnection

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.