/* * JBoss, Home of Professional Open Source. * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. Some portions may be licensed * to Red Hat, Inc. under one or more contributor license agreements. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA. */ package org.teiid.net.socket; import java.io.DataOutputStream; import java.io.IOException; import java.io.InterruptedIOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.InetAddress; import java.net.Socket; import java.net.SocketAddress; import java.net.SocketTimeoutException; import java.security.GeneralSecurityException; import java.util.Properties; import java.util.concurrent.Future; import java.util.logging.Logger; import org.teiid.client.util.ResultsFuture; import org.teiid.core.util.AccessibleBufferedInputStream; import org.teiid.core.util.PropertiesUtils; import org.teiid.net.CommunicationException; import org.teiid.net.HostInfo; import org.teiid.net.socket.SocketUtil.SSLSocketFactory; import org.teiid.netty.handler.codec.serialization.ObjectDecoderInputStream; import org.teiid.netty.handler.codec.serialization.ObjectEncoderOutputStream; import org.teiid.runtime.client.Messages; public final class OioOjbectChannelFactory implements ObjectChannelFactory { public static ThreadLocal<Long> TIMEOUTS = new ThreadLocal<Long>(); private final static int STREAM_BUFFER_SIZE = 1<<15; private final static int DEFAULT_MAX_OBJECT_SIZE = 1 << 25; private static Logger log = Logger.getLogger("org.teiid.client.sockets"); //$NON-NLS-1$ final static class OioObjectChannel implements ObjectChannel { private final Socket socket; private ObjectOutputStream outputStream; private ObjectInputStream inputStream; private OioObjectChannel(Socket socket, int maxObjectSize) throws IOException { log.fine("creating new OioObjectChannel"); //$NON-NLS-1$ this.socket = socket; DataOutputStream out = new DataOutputStream(socket.getOutputStream()); outputStream = new ObjectEncoderOutputStream(out, STREAM_BUFFER_SIZE); final ClassLoader cl = this.getClass().getClassLoader(); inputStream = new ObjectDecoderInputStream(new AccessibleBufferedInputStream(socket.getInputStream(), STREAM_BUFFER_SIZE), cl, maxObjectSize); } @Override public void close() { log.finer("closing socket"); //$NON-NLS-1$ try { outputStream.flush(); } catch (IOException e) { // ignore } try { outputStream.close(); } catch (IOException e) { // ignore } try { inputStream.close(); } catch (IOException e) { // ignore } try { socket.close(); } catch (IOException e) { // ignore } } @Override public SocketAddress getRemoteAddress() { return socket.getRemoteSocketAddress(); } @Override public InetAddress getLocalAddress() { return socket.getLocalAddress(); } @Override public boolean isOpen() { return !socket.isClosed(); } @Override public Object read() throws IOException, ClassNotFoundException { log.finer("reading message from socket"); //$NON-NLS-1$ try { return inputStream.readObject(); } catch (SocketTimeoutException e) { Long timeout = TIMEOUTS.get(); if (timeout != null && timeout < System.currentTimeMillis()) { TIMEOUTS.set(null); throw new InterruptedIOException(Messages.gs(Messages.TEIID.TEIID20035)); } throw e; } catch (IOException e) { close(); throw e; } } @Override public synchronized Future<?> write(Object msg) { log.finer("writing message to socket"); //$NON-NLS-1$ ResultsFuture<Void> result = new ResultsFuture<Void>(); try { outputStream.writeObject(msg); outputStream.flush(); outputStream.reset(); result.getResultsReceiver().receiveResults(null); } catch (IOException e) { close(); result.getResultsReceiver().exceptionOccurred(e); } return result; } } private Properties props; private int receiveBufferSize = 0; private int sendBufferSize = 0; private boolean conserveBandwidth; private int soTimeout = 1000; private volatile SSLSocketFactory sslSocketFactory; private int maxObjectSize = DEFAULT_MAX_OBJECT_SIZE; public OioOjbectChannelFactory(Properties props) { this.props = props; PropertiesUtils.setBeanProperties(this, props, "org.teiid.sockets"); //$NON-NLS-1$ } @Override public ObjectChannel createObjectChannel(HostInfo info) throws IOException, CommunicationException { final Socket socket; if (info.isSsl()) { if (this.sslSocketFactory == null) { try { sslSocketFactory = SocketUtil.getSSLSocketFactory(props); } catch (GeneralSecurityException e) { throw new CommunicationException(e, e.getMessage()); } } socket = sslSocketFactory.getSocket(info.getHostName(), info.getPortNumber()); } else { socket = new Socket(info.getInetAddress(), info.getPortNumber()); } if (receiveBufferSize > 0) { socket.setReceiveBufferSize(receiveBufferSize); } if (sendBufferSize > 0) { socket.setSendBufferSize(sendBufferSize); } socket.setTcpNoDelay(!conserveBandwidth); // enable Nagle's algorithm to conserve bandwidth socket.setSoTimeout(soTimeout); return new OioObjectChannel(socket, maxObjectSize); } public int getSendBufferSize() { return sendBufferSize; } public void setSendBufferSize(int sendBufferSize) { this.sendBufferSize = sendBufferSize; } public int getReceiveBufferSize() { return receiveBufferSize; } public void setReceiveBufferSize(int receiveBufferSize) { this.receiveBufferSize = receiveBufferSize; } public boolean isConserveBandwidth() { return conserveBandwidth; } public void setConserveBandwidth(boolean conserveBandwidth) { this.conserveBandwidth = conserveBandwidth; } public void setSoTimeout(int soTimeout) { this.soTimeout = soTimeout; } public void setMaxObjectSize(int maxObjectSize) { this.maxObjectSize = maxObjectSize; } public int getSoTimeout() { return soTimeout; } }