001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.nio.intraband.welder.socket;
016    
017    import com.liferay.portal.kernel.nio.intraband.Intraband;
018    import com.liferay.portal.kernel.nio.intraband.RegistrationReference;
019    import com.liferay.portal.kernel.nio.intraband.welder.BaseWelder;
020    import com.liferay.portal.kernel.util.GetterUtil;
021    import com.liferay.portal.kernel.util.InetAddressUtil;
022    import com.liferay.portal.kernel.util.PropsKeys;
023    import com.liferay.portal.kernel.util.PropsUtil;
024    import com.liferay.portal.kernel.util.SocketUtil;
025    import com.liferay.portal.kernel.util.SocketUtil.ServerSocketConfigurator;
026    
027    import java.io.IOException;
028    
029    import java.net.InetSocketAddress;
030    import java.net.ServerSocket;
031    import java.net.Socket;
032    import java.net.SocketException;
033    
034    import java.nio.channels.ServerSocketChannel;
035    import java.nio.channels.SocketChannel;
036    
037    /**
038     * @author Shuyang Zhou
039     */
040    public class SocketWelder extends BaseWelder {
041    
042            public SocketWelder() throws IOException {
043    
044                    // Assignments have to stay in the constructor because we need to
045                    // differentiate between a constructor created object and a
046                    // deserialization created object. Only the constructor created object
047                    // needs to assign values. The deserialization created object gets its
048                    // values from the original object.
049    
050                    bufferSize = Configuration.bufferSize;
051                    keepAlive = Configuration.keepAlive;
052                    reuseAddress = Configuration.reuseAddress;
053                    soLinger = Configuration.soLinger;
054                    soTimeout = Configuration.soTimeout;
055                    tcpNoDelay = Configuration.tcpNoDelay;
056    
057                    serverSocketChannel = SocketUtil.createServerSocketChannel(
058                            InetAddressUtil.getLoopbackInetAddress(),
059                            Configuration.serverStartPort,
060                            new SocketWelderServerSocketConfigurator());
061    
062                    ServerSocket serverSocket = serverSocketChannel.socket();
063    
064                    serverPort = serverSocket.getLocalPort();
065            }
066    
067            @Override
068            protected void doDestroy() throws IOException {
069                    socketChannel.close();
070            }
071    
072            @Override
073            protected RegistrationReference weldClient(Intraband intraband)
074                    throws IOException {
075    
076                    socketChannel = SocketChannel.open();
077    
078                    _configureSocket(socketChannel.socket());
079    
080                    socketChannel.connect(
081                            new InetSocketAddress(
082                                    InetAddressUtil.getLoopbackInetAddress(), serverPort));
083    
084                    return intraband.registerChannel(socketChannel);
085            }
086    
087            @Override
088            protected RegistrationReference weldServer(Intraband intraband)
089                    throws IOException {
090    
091                    socketChannel = serverSocketChannel.accept();
092    
093                    serverSocketChannel.close();
094    
095                    _configureSocket(socketChannel.socket());
096    
097                    return intraband.registerChannel(socketChannel);
098            }
099    
100            protected final int bufferSize;
101            protected final boolean keepAlive;
102            protected final boolean reuseAddress;
103            protected final int serverPort;
104            protected final transient ServerSocketChannel serverSocketChannel;
105            protected transient SocketChannel socketChannel;
106            protected final int soLinger;
107            protected final int soTimeout;
108            protected final boolean tcpNoDelay;
109    
110            protected static class Configuration {
111    
112                    protected static final int bufferSize = GetterUtil.getInteger(
113                            PropsUtil.get(PropsKeys.INTRABAND_WELDER_SOCKET_BUFFER_SIZE));
114    
115                    protected static final boolean keepAlive = GetterUtil.getBoolean(
116                            PropsUtil.get(PropsKeys.INTRABAND_WELDER_SOCKET_KEEP_ALIVE));
117    
118                    protected static final boolean reuseAddress = GetterUtil.getBoolean(
119                            PropsUtil.get(PropsKeys.INTRABAND_WELDER_SOCKET_REUSE_ADDRESS));
120    
121                    protected static final int serverStartPort = GetterUtil.getInteger(
122                            PropsUtil.get(PropsKeys.INTRABAND_WELDER_SOCKET_SERVER_START_PORT));
123    
124                    protected static final int soLinger = GetterUtil.getInteger(
125                            PropsUtil.get(PropsKeys.INTRABAND_WELDER_SOCKET_SO_LINGER));
126    
127                    protected static final int soTimeout = GetterUtil.getInteger(
128                            PropsUtil.get(PropsKeys.INTRABAND_WELDER_SOCKET_SO_TIMEOUT));
129    
130                    protected static final boolean tcpNoDelay = GetterUtil.getBoolean(
131                            PropsUtil.get(PropsKeys.INTRABAND_WELDER_SOCKET_TCP_NO_DELAY));
132    
133            }
134    
135            protected class SocketWelderServerSocketConfigurator
136                    implements ServerSocketConfigurator {
137    
138                    @Override
139                    public void configure(ServerSocket serverSocket)
140                            throws SocketException {
141    
142                            serverSocket.setReceiveBufferSize(bufferSize);
143                            serverSocket.setReuseAddress(reuseAddress);
144                            serverSocket.setSoTimeout(soTimeout);
145                    }
146    
147            }
148    
149            private void _configureSocket(Socket socket) throws SocketException {
150                    socket.setKeepAlive(keepAlive);
151                    socket.setReceiveBufferSize(bufferSize);
152                    socket.setReuseAddress(reuseAddress);
153                    socket.setSendBufferSize(bufferSize);
154    
155                    if (soLinger <= 0) {
156                            socket.setSoLinger(false, soLinger);
157                    }
158                    else {
159                            socket.setSoLinger(true, soLinger);
160                    }
161    
162                    socket.setSoTimeout(soTimeout);
163                    socket.setTcpNoDelay(tcpNoDelay);
164            }
165    
166    }