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