All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.openejb.client.SocketConnectionFactory Maven / Gradle / Ivy

The newest version!
/**
 * 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.openejb.client;

import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StreamCorruptedException;
import java.net.ConnectException;
import java.net.Socket;
import java.net.URI;
import java.util.Map;
import java.util.Stack;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class SocketConnectionFactory implements ConnectionFactory {

    private KeepAliveStyle keepAliveStyle = KeepAliveStyle.PING;

    private static Map connections = new ConcurrentHashMap();
    private int size = 5;
    private int timeout = 120;

    public SocketConnectionFactory() {
        Properties p = System.getProperties();

        size = getInt(p, "openejb.client.connectionpool.size", size);
        size = getInt(p, "openejb.client.connection.pool.size", size);
        timeout = getInt(p, "openejb.client.connectionpool.timeout", timeout);
        timeout = getInt(p, "openejb.client.connection.pool.timeout", timeout);
    }

    public static int getInt(Properties p, String property, int defaultValue){
        String value = p.getProperty(property);
        try {
            if (value != null) return Integer.parseInt(value);
            else return defaultValue;
        } catch (NumberFormatException e) {
            return defaultValue;
        }
    }

    public Connection getConnection(URI uri) throws java.io.IOException {

        Pool pool = getPool(uri);

        SocketConnection conn = pool.get();
        if (conn == null) {
            try {
                conn = new SocketConnection(uri, pool);
                conn.open(uri);
            } catch (IOException e) {
                pool.put(null);
                throw e;
            }
        }

        try {
            conn.lock.tryLock(60 * 5, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            Thread.interrupted();
            throw new IOException("Connection busy");
        }

        OutputStream ouputStream = conn.getOuputStream();
        if (conn.socket.isClosed()) {
            pool.put(null);
            return getConnection(uri);
        }

        try {
            ouputStream.write(getKeepAliveStyle().ordinal());

            switch (getKeepAliveStyle()) {
                case PING_PING: {
                    ouputStream.flush();
                    ouputStream.write(getKeepAliveStyle().ordinal());
                    ouputStream.flush();
                }
                break;
                case PING_PONG: {
                    ouputStream.flush();
                    conn.getInputStream().read();
                }
            }
        } catch (IOException e) {
            pool.put(null);
            throw e;
        }

        return conn;
    }

    private Pool getPool(URI uri) {
        Pool pool = connections.get(uri);
        if (pool == null) {
            pool = new Pool(size, timeout);
            connections.put(uri, pool);
        }
        return pool;
    }

    public KeepAliveStyle getKeepAliveStyle() {
        String property = System.getProperty("openejb.client.keepalive");
        if (property != null) {
            property = property.toUpperCase();
            return KeepAliveStyle.valueOf(property);
        }
        return keepAliveStyle;
    }

    class SocketConnection implements Connection {

        private Socket socket = null;
        private final URI uri;

        private boolean discarded;
        private final Pool pool;
        private final Lock lock = new ReentrantLock();
        private OutputStream out;
        private BufferedInputStream in;

        public SocketConnection(URI uri, Pool pool) {
            this.uri = uri;
            this.pool = pool;
        }

        protected void open(URI uri) throws IOException {

            /*-----------------------*/
            /* Open socket to server */
            /*-----------------------*/
            try {
                if (uri.getScheme().equalsIgnoreCase("ejbds")) {
                    SSLSocket sslSocket = (SSLSocket) SSLSocketFactory.getDefault().createSocket(uri.getHost(), uri.getPort());
                    // use an anonymous cipher suite so that a KeyManager or
                    // TrustManager is not needed
                    // NOTE: this assumes that the cipher suite is known. A check
                    // -should- be done first.
                    final String[] enabledCipherSuites = {"SSL_DH_anon_WITH_RC4_128_MD5"};
                    sslSocket.setEnabledCipherSuites(enabledCipherSuites);
                    socket = sslSocket;
                } else {
                    socket = new Socket(uri.getHost(), uri.getPort());
                }

                socket.setTcpNoDelay(true);
            } catch (ConnectException e) {
                throw new ConnectException("Cannot connect to server '" + uri.toString() + "'.  Check that the server is started and that the specified serverURL is correct.");

            } catch (IOException e) {
                throw new IOException("Cannot connect to server: '" + uri.toString() + "'.  Exception: " + e.getClass().getName() + " : " + e.getMessage());

            } catch (SecurityException e) {
                throw new IOException("Cannot access server: '" + uri.toString() + "' due to security restrictions in the current VM: " + e.getClass().getName() + " : " + e.getMessage());

            } catch (Throwable e) {
                throw new IOException("Cannot  connect to server: '" + uri.toString() + "' due to an unkown exception in the OpenEJB client: " + e.getClass().getName() + " : " + e.getMessage());
            }

        }

        public void discard() {
            pool.put(null);
            discarded = true;
            try {
                socket.close();
            } catch (IOException e) {
            }
            // don't bother unlocking it
            // it should never get used again
        }

        public URI getURI() {
            return uri;
        }

        public void close() throws IOException {
            if (discarded) return;

            pool.put(this);
            lock.unlock();
        }

        public InputStream getInputStream() throws IOException {
            /*----------------------------------*/
            /* Open input streams */
            /*----------------------------------*/
            try {
                if (in == null) {
                    in = new BufferedInputStream(socket.getInputStream());
                }

                return new Input(in);
            } catch (StreamCorruptedException e) {
                throw new IOException("Cannot open input stream to server, the stream has been corrupted: " + e.getClass().getName() + " : " + e.getMessage());

            } catch (IOException e) {
                throw new IOException("Cannot open input stream to server: " + e.getClass().getName() + " : " + e.getMessage());

            } catch (Throwable e) {
                throw new IOException("Cannot open output stream to server: " + e.getClass().getName() + " : " + e.getMessage());
            }
        }

        public OutputStream getOuputStream() throws IOException {
            /*----------------------------------*/
            /* Openning output streams */
            /*----------------------------------*/
            try {
                if (out == null) {
                    out = new BufferedOutputStream(socket.getOutputStream());
                }
                return new Output(out);
            } catch (IOException e) {
                throw new IOException("Cannot open output stream to server: " + e.getClass().getName() + " : " + e.getMessage());

            } catch (Throwable e) {
                throw new IOException("Cannot open output stream to server: " + e.getClass().getName() + " : " + e.getMessage());
            }
        }

    }

    public class Input extends java.io.FilterInputStream {

        public Input(InputStream in) {
            super(in);
        }

        public void close() throws IOException {
        }
    }

    public class Output extends java.io.FilterOutputStream {
        public Output(OutputStream out) {
            super(out);
        }

        public void close() throws IOException {
            flush();
        }
    }

    public static class Pool {
        private final Semaphore semaphore;
        private final Stack pool;
        private final long timeout;
        private final TimeUnit timeUnit;
        private final int size;

        public Pool(int size, long timeout) {
            this.size = size;
            this.semaphore = new Semaphore(size);
            this.pool = new Stack();
            this.timeout = timeout;
            this.timeUnit = TimeUnit.SECONDS;

            Object[] objects = new Object[size];
            for (int i = 0; i < objects.length; i++) {
                pool.push(null);
            }
        }

        public SocketConnection get() {
            try {
                if (semaphore.tryAcquire(timeout, timeUnit)) {
                    return pool.pop();
                }
            } catch (InterruptedException e) {
                Thread.interrupted();
            }

            throw new IllegalStateException("No connections available in pool (size " + size + ").  Waited for " + timeout + " seconds for a connection.");
        }

        public void put(SocketConnection connection) {
            pool.push(connection);
            semaphore.release();
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy