001    /**
002     * Copyright (c) 2000-2010 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.GetterUtil;
021    import com.liferay.portal.kernel.util.IPDetector;
022    import com.liferay.portal.kernel.util.OSDetector;
023    import com.liferay.portal.kernel.util.SocketUtil;
024    import com.liferay.portal.kernel.util.StringBundler;
025    import com.liferay.portal.kernel.util.StringPool;
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                            _initialized = true;
080                    }
081    
082                    try {
083                            initChannels();
084                    }
085                    catch (Exception e) {
086                            if (_log.isErrorEnabled()) {
087                                    _log.error("Unable to initialize channels", e);
088                            }
089    
090                            throw new IllegalStateException(e);
091                    }
092            }
093    
094            public abstract void destroy();
095    
096            public boolean isEnabled() {
097                    return PropsValues.CLUSTER_LINK_ENABLED;
098            }
099    
100            protected JChannel createJChannel(
101                            String properties, Receiver receiver, String clusterName)
102                    throws ChannelException {
103    
104                    JChannel jChannel = new JChannel(properties);
105    
106                    jChannel.setReceiver(receiver);
107    
108                    jChannel.connect(clusterName);
109    
110                    if (_log.isInfoEnabled()) {
111                            _log.info(
112                                    "Create a new channel with properties " +
113                                            jChannel.getProperties());
114                    }
115    
116                    return jChannel;
117            }
118    
119            protected List<Address> getAddresses(JChannel channel) {
120                    View view = channel.getView();
121    
122                    Vector<org.jgroups.Address> jGroupsAddresses = view.getMembers();
123    
124                    if (jGroupsAddresses == null) {
125                            return Collections.EMPTY_LIST;
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 IOException {
139                    String autodetectAddress = PropsValues.CLUSTER_LINK_AUTODETECT_ADDRESS;
140    
141                    if (Validator.isNull(autodetectAddress)) {
142                            return;
143                    }
144    
145                    String host = autodetectAddress;
146                    int port = 80;
147    
148                    int index = autodetectAddress.indexOf(StringPool.COLON);
149    
150                    if (index != -1) {
151                            host = autodetectAddress.substring(0, index);
152                            port = GetterUtil.getInteger(
153                                    autodetectAddress.substring(index + 1), port);
154                    }
155    
156                    if (_log.isInfoEnabled()) {
157                            _log.info(
158                                    "Autodetecting JGroups outgoing IP address and interface for " +
159                                            host + ":" + port);
160                    }
161    
162                    SocketUtil.BindInfo bindInfo = SocketUtil.getBindInfo(host, port);
163    
164                    bindInetAddress = bindInfo.getInetAddress();
165                    NetworkInterface networkInterface = bindInfo.getNetworkInterface();
166    
167                    System.setProperty(
168                            "jgroups.bind_addr", bindInetAddress.getHostAddress());
169                    System.setProperty(
170                            "jgroups.bind_interface", networkInterface.getName());
171    
172                    if (_log.isInfoEnabled()) {
173                            _log.info(
174                                    "Setting JGroups outgoing IP address to " +
175                                            bindInetAddress.getHostAddress() + " and interface to " +
176                                                    networkInterface.getName());
177                    }
178            }
179    
180            protected abstract void initChannels() throws ChannelException;
181    
182            protected void initSystemProperties() {
183                    for (String systemProperty :
184                                    PropsValues.CLUSTER_LINK_CHANNEL_SYSTEM_PROPERTIES) {
185    
186                            int index = systemProperty.indexOf(StringPool.COLON);
187    
188                            if (index == -1) {
189                                    continue;
190                            }
191    
192                            String key = systemProperty.substring(0, index);
193                            String value = systemProperty.substring(index + 1);
194    
195                            System.setProperty(key, value);
196    
197                            if (_log.isDebugEnabled()) {
198                                    _log.debug(
199                                            "Setting system property {key=" + key + ", value=" + value +
200                                                    "}");
201                            }
202                    }
203            }
204    
205            private static Log _log = LogFactoryUtil.getLog(ClusterBase.class);
206    
207            private static boolean _initialized;
208    
209            protected InetAddress bindInetAddress;
210    
211    }