org.apache.manifoldcf.connectorcommon.common.InterruptibleSocketFactory.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.manifoldcf.connectorcommon.common.InterruptibleSocketFactory.java

Source

/* $Id$ */

/**
* 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 org.apache.manifoldcf.connectorcommon.common;

import java.io.*;
import java.net.*;

import org.apache.http.conn.ConnectTimeoutException;

/** SSL Socket factory which wraps another socket factory but allows timeout on socket
* creation.
*/
public class InterruptibleSocketFactory extends javax.net.ssl.SSLSocketFactory {
    protected final javax.net.ssl.SSLSocketFactory wrappedFactory;
    protected final long connectTimeoutMilliseconds;

    public InterruptibleSocketFactory(javax.net.ssl.SSLSocketFactory wrappedFactory,
            long connectTimeoutMilliseconds) {
        this.wrappedFactory = wrappedFactory;
        this.connectTimeoutMilliseconds = connectTimeoutMilliseconds;
    }

    @Override
    public Socket createSocket() throws IOException {
        // Socket isn't open
        return wrappedFactory.createSocket();
    }

    @Override
    public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
        return fireOffThread(InetAddress.getByName(host), port, null, -1);
    }

    @Override
    public Socket createSocket(InetAddress host, int port) throws IOException {
        return fireOffThread(host, port, null, -1);
    }

    @Override
    public Socket createSocket(String host, int port, InetAddress localHost, int localPort)
            throws IOException, UnknownHostException {
        return fireOffThread(InetAddress.getByName(host), port, localHost, localPort);
    }

    @Override
    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort)
            throws IOException {
        return fireOffThread(address, port, localAddress, localPort);
    }

    @Override
    public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
        // Socket's already open
        return wrappedFactory.createSocket(s, host, port, autoClose);
    }

    @Override
    public String[] getDefaultCipherSuites() {
        return wrappedFactory.getDefaultCipherSuites();
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return wrappedFactory.getSupportedCipherSuites();
    }

    protected Socket fireOffThread(InetAddress address, int port, InetAddress localHost, int localPort)
            throws IOException {
        SocketCreateThread thread = new SocketCreateThread(wrappedFactory, address, port, localHost, localPort);
        thread.start();
        try {
            // Wait for thread to complete for only a certain amount of time!
            thread.join(connectTimeoutMilliseconds);
            // If join() times out, then the thread is going to still be alive.
            if (thread.isAlive()) {
                // Kill the thread - not that this will necessarily work, but we need to try
                thread.interrupt();
                throw new ConnectTimeoutException("Secure connection timed out");
            }
            // The thread terminated.  Throw an error if there is one, otherwise return the result.
            Throwable t = thread.getException();
            if (t != null) {
                if (t instanceof java.net.SocketTimeoutException)
                    throw (java.net.SocketTimeoutException) t;
                else if (t instanceof ConnectTimeoutException)
                    throw (ConnectTimeoutException) t;
                else if (t instanceof InterruptedIOException)
                    throw (InterruptedIOException) t;
                else if (t instanceof IOException)
                    throw (IOException) t;
                else if (t instanceof Error)
                    throw (Error) t;
                else if (t instanceof RuntimeException)
                    throw (RuntimeException) t;
                throw new Error("Received an unexpected exception: " + t.getMessage(), t);
            }
            return thread.getResult();
        } catch (InterruptedException e) {
            throw new InterruptedIOException("Interrupted: " + e.getMessage());
        }

    }

    /** Create a secure socket in a thread, so that we can "give up" after a while if the socket fails to connect.
    */
    protected static class SocketCreateThread extends Thread {
        // Socket factory
        protected javax.net.ssl.SSLSocketFactory socketFactory;
        protected InetAddress host;
        protected int port;
        protected InetAddress clientHost;
        protected int clientPort;

        // The return socket
        protected Socket rval = null;
        // The return error
        protected Throwable throwable = null;

        /** Create the thread */
        public SocketCreateThread(javax.net.ssl.SSLSocketFactory socketFactory, InetAddress host, int port,
                InetAddress clientHost, int clientPort) {
            this.socketFactory = socketFactory;
            this.host = host;
            this.port = port;
            this.clientHost = clientHost;
            this.clientPort = clientPort;
            setDaemon(true);
        }

        public void run() {
            try {
                if (clientHost == null)
                    rval = socketFactory.createSocket(host, port);
                else
                    rval = socketFactory.createSocket(host, port, clientHost, clientPort);
            } catch (Throwable e) {
                throwable = e;
            }
        }

        public Throwable getException() {
            return throwable;
        }

        public Socket getResult() {
            return rval;
        }
    }

}