
net.sf.ehcache.distribution.jgroups.JGroupManager Maven / Gradle / Ivy
/**
* Copyright 2003-2009 Luck Consulting Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.ehcache.distribution.jgroups;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import net.sf.ehcache.Status;
import net.sf.ehcache.distribution.CacheManagerPeerProvider;
import net.sf.ehcache.distribution.CachePeer;
import org.jgroups.Address;
import org.jgroups.Channel;
import org.jgroups.blocks.NotificationBus;
import org.jgroups.stack.IpAddress;
import java.io.Serializable;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* The main Jgroup class for replication via JGroup. Starts up the Jgroup communication bus and listen for message in
* the bus. Because of Ehcache design we have to register this as a CachePeer. In reality this class listen for change
* on the bus and tells the cachemanager to update.
*
* @author Pierre Monestie ([email protected])
* @author Greg Luck
* @version $Id: JGroupManager.java 932 2009-04-13 20:18:40Z gregluck $
*/
public class JGroupManager implements NotificationBus.Consumer, CachePeer, CacheManagerPeerProvider {
private static final Logger LOG = Logger.getLogger(JGroupManager.class.getName());
private static final int CHUNK_SIZE = 100;
private NotificationBus notificationBus;
private CacheManager cacheManager;
/**
* Construct a new JGroupManager with a specific JGroups connection String
*
* @param cacheManager the cache manager
* @param connect the connection String
*/
public JGroupManager(CacheManager cacheManager, String connect) {
try {
this.cacheManager = cacheManager;
notificationBus = new NotificationBus("EH_CACHE", connect);
notificationBus.start();
notificationBus.getChannel().setOpt(Channel.LOCAL, Boolean.FALSE);
notificationBus.setConsumer(this);
LOG.info("JGroupManager started. address is " + this.notificationBus.getLocalAddress());
} catch (Exception e) {
LOG.log(Level.SEVERE, e.getMessage(), e);
}
}
/**
* {@inheritDoc}
*/
public Serializable getCache() {
return null;
}
private void handleJGroupNotification(JGroupSerializable e) {
Cache cache = cacheManager.getCache(e.getCacheName());
if (cache != null) {
if (e.getEvent() == JGroupEventMessage.REMOVE && cache.getQuiet(e.getKey()) != null) {
cache.remove(e.getKey(), true);
} else if (e.getEvent() == JGroupEventMessage.PUT) {
cache.put(new Element(e.getKey(), e.getValue()), true);
} else if (e.getEvent() == JGroupEventMessage.BOOTSTRAP_REPLY) {
LOG.fine("received bootstrap reply: cache=" + e.getCacheName() + ", key=" + e.getKey());
cache.put(new Element(e.getKey(), e.getValue()), true);
} else if (e.getEvent() == JGroupEventMessage.REMOVE_ALL) {
LOG.fine("remove all");
cache.removeAll(true);
} else if (e.getEvent() == JGroupEventMessage.ASK_FOR_BOOTSTRAP) {
sendBootstrapResponse(e, cache);
}
}
}
private void sendBootstrapResponse(JGroupSerializable e, Cache cache) {
IpAddress requestAddress = (IpAddress) e.getKey();
LOG.fine("received bootstrap request from " + requestAddress + ", cache=" + e.getCacheName());
List keys = cache.getKeys();
if (keys != null && keys.size() > 0) {
List messageList = new ArrayList();
for (Object key : keys) {
Element element = cache.get(key);
JGroupEventMessage jGroupEventMessage =
new JGroupEventMessage(JGroupEventMessage.BOOTSTRAP_REPLY,
(Serializable) key, element, cache, cache.getName());
messageList.add(jGroupEventMessage);
if (messageList.size() == CHUNK_SIZE) {
sendResponseChunk(cache, requestAddress, messageList);
messageList = new ArrayList();
}
}
//send remainders
if (messageList.size() > 0) {
sendResponseChunk(cache, requestAddress, messageList);
}
} else {
LOG.log(Level.FINE, "no keys to reply to " + requestAddress + " to boot cache " + cache.getName());
}
}
private void sendResponseChunk(Cache cache, IpAddress requestAddress, List events) {
LOG.fine("reply " + events.size() + " elements to " + requestAddress + " to boot cache " + cache.getName());
try {
send(requestAddress, events);
} catch (RemoteException e1) {
LOG.log(Level.SEVERE, "error repling to " + requestAddress, e1);
}
}
/**
* Handles notification: Looks at type of message and unwrap if the argument is a list
*/
public void handleNotification(Serializable arg0) {
if (arg0 instanceof JGroupSerializable) {
handleJGroupNotification((JGroupSerializable) arg0);
} else if (arg0 instanceof List) {
List l = (List) arg0;
for (int i = 0; i < l.size(); i++) {
Object obj = l.get(i);
if (obj instanceof JGroupSerializable) {
handleJGroupNotification((JGroupSerializable) obj);
}
}
}
}
/**
* {@inheritDoc}
*/
public void memberJoined(Address arg0) {
LOG.fine("joined:" + arg0);
}
/**
* {@inheritDoc}
*/
public void memberLeft(Address arg0) {
LOG.fine("left:" + arg0);
}
/**
* {@inheritDoc}
*/
public List getElements(List keys) throws RemoteException {
return null;
}
/**
* {@inheritDoc}
*/
public String getGuid() throws RemoteException {
return null;
}
/**
* {@inheritDoc}
*/
public List getKeys() throws RemoteException {
return null;
}
/**
* {@inheritDoc}
*/
public String getName() throws RemoteException {
return null;
}
/**
* {@inheritDoc}
*/
public Element getQuiet(Serializable key) throws RemoteException {
return null;
}
/**
* {@inheritDoc}
*/
public String getUrl() throws RemoteException {
return null;
}
/**
* {@inheritDoc}
*/
public String getUrlBase() throws RemoteException {
return null;
}
/**
* {@inheritDoc}
*/
public void put(Element element) throws IllegalArgumentException, IllegalStateException, RemoteException {
}
/**
* {@inheritDoc}
*/
public boolean remove(Serializable key) throws IllegalStateException, RemoteException {
return false;
}
/**
* {@inheritDoc}
*/
public void removeAll() throws RemoteException, IllegalStateException {
}
private JGroupSerializable wrapMessage(JGroupEventMessage msg) {
Serializable value = (msg.getElement() == null ? null : msg.getElement().getValue());
return new JGroupSerializable(msg.getEvent(), msg.getSerializableKey(), value, msg.getCacheName());
}
/**
* {@inheritDoc}
*/
public void send(List eventMessages) throws RemoteException {
send(null, eventMessages);
}
/**
* Sends a message to a single address
*/
public void send(Address address, List eventMessages) throws RemoteException {
if (eventMessages.size() == 1) {
notificationBus.sendNotification(wrapMessage((JGroupEventMessage) eventMessages.get(0)));
return;
}
ArrayList msg = new ArrayList();
for (Iterator iter = eventMessages.iterator(); iter.hasNext();) {
JGroupEventMessage m = (JGroupEventMessage) iter.next();
msg.add(wrapMessage(m));
}
try {
notificationBus.sendNotification(address, msg);
} catch (Throwable t) {
throw new RemoteException(t.getMessage());
}
}
/**
* @return the {@link Status} of the manager
*/
public Status getStatus() {
if (notificationBus == null) {
return Status.STATUS_UNINITIALISED;
}
if (notificationBus.getChannel() == null) {
return Status.STATUS_SHUTDOWN;
}
return Status.STATUS_ALIVE;
}
/**
* {@inheritDoc}
*/
public void dispose() throws CacheException {
if (notificationBus != null) {
try {
notificationBus.stop();
} catch (Exception e) {
LOG.log(Level.SEVERE, "Error occured while closing Manager:", e);
}
}
}
/**
* {@inheritDoc}
*/
public long getTimeForClusterToForm() {
return 0;
}
/**
* The replication scheme. Each peer provider has a scheme name, which can be used to specify the scheme for
* replication and bootstrap purposes. Each CacheReplicator
should lookup the provider for its scheme
* type during replication. Similarly a BootstrapCacheLoader
should also look up the provider for its
* scheme.
*
*
* @return the well-known scheme name, which is determined by the replication provider author.
* @since 1.6 introduced to permit multiple distribution schemes to be used in the same CacheManager
*/
public String getScheme() {
return "JGroups";
}
/**
* {@inheritDoc}
*/
public void init() {
}
/**
* {@inheritDoc}
* We act as our own peer in this implementation
*/
public List listRemoteCachePeers(Ehcache cache) throws CacheException {
ArrayList a = new ArrayList();
a.add(this);
return a;
}
/**
* {@inheritDoc}
*/
public void registerPeer(String rmiUrl) {
}
/**
* {@inheritDoc}
*/
public void unregisterPeer(String rmiUrl) {
}
/**
* @return
*/
public List getBusMembership() {
return notificationBus.getMembership();
}
/**
* @return
*/
public Address getBusLocalAddress() {
return notificationBus.getLocalAddress();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy