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.cache.ehcache;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    
020    import java.rmi.RemoteException;
021    
022    import java.util.ArrayList;
023    import java.util.List;
024    import java.util.Random;
025    
026    import net.sf.ehcache.Ehcache;
027    import net.sf.ehcache.distribution.RemoteCacheException;
028    import net.sf.ehcache.distribution.jgroups.JGroupEventMessage;
029    import net.sf.ehcache.distribution.jgroups.JGroupManager;
030    
031    import org.jgroups.Address;
032    
033    /**
034     * <p>
035     * See http://issues.liferay.com/browse/LPS-11061.
036     * </p>
037     *
038     * @author Shuyang Zhou
039     */
040    public class JGroupsBootstrapCacheLoader
041            extends net.sf.ehcache.distribution.jgroups.JGroupsBootstrapCacheLoader {
042    
043            public JGroupsBootstrapCacheLoader(
044                    boolean asynchronous, int maximumChunkSize) {
045    
046                    super(asynchronous, maximumChunkSize);
047            }
048    
049            public Object clone() {
050                    return new JGroupsBootstrapCacheLoader(
051                            asynchronous, maximumChunkSizeBytes);
052            }
053    
054            public void doLoad(Ehcache cache) throws RemoteCacheException {
055                    List<JGroupManager> cachePeers = acquireCachePeers(cache);
056    
057                    if ((cachePeers == null) || cachePeers.isEmpty()) {
058                            if (_log.isInfoEnabled()) {
059                                    _log.info(
060                                            "Empty list of cache peers for cache " + cache.getName() +
061                                                    ". No cache peer to bootstrap from.");
062                            }
063    
064                            return;
065                    }
066    
067                    JGroupManager jGroupManager = cachePeers.get(0);
068    
069                    Address localAddress = jGroupManager.getBusLocalAddress();
070    
071                    if (_log.isInfoEnabled()) {
072                            _log.info(
073                                    "(" + cache.getName() + ") local address: " + localAddress);
074                    }
075    
076                    List<Address> addresses = _buildCachePeerAddressList(
077                            cache, jGroupManager, localAddress);
078    
079                    if ((addresses == null) || addresses.isEmpty()) {
080                            if (_log.isInfoEnabled()) {
081                                    _log.info(
082                                            "This is the first node to start. No cache bootstrap for " +
083                                                    cache.getName() + ".");
084                            }
085    
086                            return;
087                    }
088    
089                    Address address = null;
090                    Random random = new Random();
091    
092                    while (!addresses.isEmpty() &&
093                               ((address == null) || (cache.getSize() == 0))) {
094    
095                            int randomPeerNumber = random.nextInt(addresses.size());
096    
097                            address = addresses.get(randomPeerNumber);
098    
099                            addresses.remove(randomPeerNumber);
100    
101                            JGroupEventMessage event = new JGroupEventMessage(
102                                    JGroupEventMessage.ASK_FOR_BOOTSTRAP,
103                                    localAddress, null, cache, cache.getName());
104    
105                            if (_log.isInfoEnabled()) {
106                                    _log.info(
107                                            "Contact " + address + " to boot cache " + cache.getName());
108                            }
109    
110                            List<JGroupEventMessage> events =
111                                    new ArrayList<JGroupEventMessage>();
112    
113                            events.add(event);
114    
115                            try {
116                                    jGroupManager.send(address, events);
117    
118                                    try {
119                                            Thread.sleep(3000);
120                                    }
121                                    catch (InterruptedException ie) {
122                                            _log.error(ie, ie);
123                                    }
124                            }
125                            catch (RemoteException re) {
126                                    _log.error(re, re);
127                            }
128                    }
129    
130                    if (cache.getSize() == 0) {
131                            if (_log.isInfoEnabled()) {
132                                    _log.info(
133                                            "Cache failed to bootstrap from its peers " +
134                                                    cache.getName());
135                            }
136                    }
137                    else {
138                            if (_log.isInfoEnabled()) {
139                                    _log.info(
140                                            "Bootstrap for cache " + cache.getName() + " has loaded " +
141                                                    cache.getSize() + " elements");
142                            }
143                    }
144            }
145    
146            private List<Address> _buildCachePeerAddressList(
147                    Ehcache cache, JGroupManager jGroupManager, Address localAddress) {
148    
149                    List<Address> addresses = new ArrayList<Address>();
150    
151                    List<Address> members = jGroupManager.getBusMembership();
152    
153                    for (int i = 0; i < members.size(); i++) {
154                            Address member = members.get(i);
155    
156                            if (_log.isInfoEnabled()) {
157                                    _log.info(
158                                            "(" + cache.getName() + ") member " + i + ": " + member +
159                                                    (member.equals(localAddress) ? " ***" : ""));
160                            }
161    
162                            if (!member.equals(localAddress)) {
163                                    addresses.add(member);
164                            }
165                    }
166    
167                    return addresses;
168            }
169    
170            private static Log _log = LogFactoryUtil.getLog(
171                    JGroupsBootstrapCacheLoader.class);
172    
173    }