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