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