001    /**
002     * Copyright (c) 2000-present 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.cluster;
016    
017    import com.liferay.portal.kernel.cluster.Address;
018    import com.liferay.portal.kernel.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.util.CharPool;
021    import com.liferay.portal.kernel.util.GetterUtil;
022    import com.liferay.portal.kernel.util.SocketUtil;
023    import com.liferay.portal.kernel.util.Validator;
024    import com.liferay.portal.util.PropsValues;
025    
026    import java.net.InetAddress;
027    import java.net.NetworkInterface;
028    
029    import java.util.ArrayList;
030    import java.util.Collections;
031    import java.util.List;
032    
033    import org.jgroups.JChannel;
034    import org.jgroups.Receiver;
035    import org.jgroups.View;
036    import org.jgroups.stack.Protocol;
037    import org.jgroups.stack.ProtocolStack;
038    
039    /**
040     * @author Shuyang Zhou
041     */
042    public abstract class ClusterBase {
043    
044            public void afterPropertiesSet() {
045                    if (!isEnabled()) {
046                            return;
047                    }
048    
049                    if (!_initialized) {
050                            initSystemProperties();
051    
052                            try {
053                                    initBindAddress();
054                            }
055                            catch (Exception e) {
056                                    if (_log.isWarnEnabled()) {
057                                            _log.warn("Failed to initialize outgoing IP address", e);
058                                    }
059                            }
060    
061                            _initialized = true;
062                    }
063    
064                    try {
065                            initChannels();
066                    }
067                    catch (Exception e) {
068                            if (_log.isErrorEnabled()) {
069                                    _log.error("Unable to initialize channels", e);
070                            }
071    
072                            throw new IllegalStateException(e);
073                    }
074            }
075    
076            public abstract void destroy();
077    
078            public boolean isEnabled() {
079                    return PropsValues.CLUSTER_LINK_ENABLED;
080            }
081    
082            protected JChannel createJChannel(
083                            String properties, Receiver receiver, String clusterName)
084                    throws Exception {
085    
086                    JChannel jChannel = new JChannel(properties);
087    
088                    jChannel.setReceiver(receiver);
089    
090                    jChannel.connect(clusterName);
091    
092                    if (_log.isInfoEnabled()) {
093                            _log.info(
094                                    "Create a new channel with properties " +
095                                            jChannel.getProperties());
096                    }
097    
098                    return jChannel;
099            }
100    
101            protected List<Address> getAddresses(JChannel channel) {
102                    BaseReceiver baseReceiver = (BaseReceiver)channel.getReceiver();
103    
104                    View view = baseReceiver.getView();
105    
106                    List<org.jgroups.Address> jGroupsAddresses = view.getMembers();
107    
108                    if (jGroupsAddresses == null) {
109                            return Collections.emptyList();
110                    }
111    
112                    List<Address> addresses = new ArrayList<Address>(
113                            jGroupsAddresses.size());
114    
115                    for (org.jgroups.Address jgroupsAddress : jGroupsAddresses) {
116                            addresses.add(new AddressImpl(jgroupsAddress));
117                    }
118    
119                    return addresses;
120            }
121    
122            protected InetAddress getBindInetAddress(JChannel jChannel) {
123                    ProtocolStack protocolStack = jChannel.getProtocolStack();
124    
125                    Protocol protocol = protocolStack.getBottomProtocol();
126    
127                    return (InetAddress)protocol.getValue("bind_addr");
128            }
129    
130            protected void initBindAddress() throws Exception {
131                    String autodetectAddress = PropsValues.CLUSTER_LINK_AUTODETECT_ADDRESS;
132    
133                    if (Validator.isNull(autodetectAddress)) {
134                            return;
135                    }
136    
137                    String host = autodetectAddress;
138                    int port = 80;
139    
140                    int index = autodetectAddress.indexOf(CharPool.COLON);
141    
142                    if (index != -1) {
143                            host = autodetectAddress.substring(0, index);
144                            port = GetterUtil.getInteger(
145                                    autodetectAddress.substring(index + 1), port);
146                    }
147    
148                    if (_log.isInfoEnabled()) {
149                            _log.info(
150                                    "Autodetecting JGroups outgoing IP address and interface for " +
151                                            host + ":" + port);
152                    }
153    
154                    SocketUtil.BindInfo bindInfo = SocketUtil.getBindInfo(host, port);
155    
156                    InetAddress inetAddress = bindInfo.getInetAddress();
157    
158                    NetworkInterface networkInterface = bindInfo.getNetworkInterface();
159    
160                    System.setProperty("jgroups.bind_addr", inetAddress.getHostAddress());
161                    System.setProperty(
162                            "jgroups.bind_interface", networkInterface.getName());
163    
164                    if (_log.isInfoEnabled()) {
165                            _log.info(
166                                    "Setting JGroups outgoing IP address to " +
167                                            inetAddress.getHostAddress() + " and interface to " +
168                                                    networkInterface.getName());
169                    }
170            }
171    
172            protected abstract void initChannels() throws Exception;
173    
174            protected void initSystemProperties() {
175                    for (String systemProperty :
176                                    PropsValues.CLUSTER_LINK_CHANNEL_SYSTEM_PROPERTIES) {
177    
178                            int index = systemProperty.indexOf(CharPool.COLON);
179    
180                            if (index == -1) {
181                                    continue;
182                            }
183    
184                            String key = systemProperty.substring(0, index);
185                            String value = systemProperty.substring(index + 1);
186    
187                            System.setProperty(key, value);
188    
189                            if (_log.isDebugEnabled()) {
190                                    _log.debug(
191                                            "Setting system property {key=" + key + ", value=" + value +
192                                                    "}");
193                            }
194                    }
195            }
196    
197            private static final Log _log = LogFactoryUtil.getLog(ClusterBase.class);
198    
199            private static boolean _initialized;
200    
201    }