net.sf.ehcache.distribution.RMICachePeer Maven / Gradle / Ivy
Show all versions of ehcache-core Show documentation
/**
* Copyright Terracotta, Inc.
*
* 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;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import java.io.Serializable;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.List;
import net.sf.ehcache.distribution.RmiEventMessage.RmiEventType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* An RMI based implementation of CachePeer
.
*
* This class features a customised RMIClientSocketFactory which enables socket timeouts to be configured.
*
* @author Greg Luck
* @version $Id: RMICachePeer.java 10789 2018-04-26 02:08:13Z adahanne $
*/
public class RMICachePeer extends UnicastRemoteObject implements CachePeer, Remote {
private static final Logger LOG = LoggerFactory.getLogger(RMICachePeer.class.getName());
private final String hostname;
private final Integer rmiRegistryPort;
private Integer remoteObjectPort;
private final Ehcache cache;
/**
* Construct a new remote peer.
*
* @param cache The cache attached to the peer
* @param hostName The host name the peer is running on.
* @param rmiRegistryPort The port number on which the RMI Registry listens. Should be an unused port in
* the range 1025 - 65536
* @param remoteObjectPort the port number on which the remote objects bound in the registry receive calls.
* This defaults to a free port if not specified.
* Should be an unused port in the range 1025 - 65536
* @param socketTimeoutMillis
* @throws RemoteException
*/
public RMICachePeer(Ehcache cache, String hostName, Integer rmiRegistryPort, Integer remoteObjectPort,
Integer socketTimeoutMillis)
throws RemoteException {
super(remoteObjectPort.intValue(), new ConfigurableRMIClientSocketFactory(socketTimeoutMillis),
ConfigurableRMIClientSocketFactory.getConfiguredRMISocketFactory());
this.remoteObjectPort = remoteObjectPort;
this.hostname = hostName;
this.rmiRegistryPort = rmiRegistryPort;
this.cache = cache;
}
/**
* {@inheritDoc}
*
* This implementation gives an URL which has meaning to the RMI remoting system.
*
* @return the URL, without the scheme, as a string e.g. //hostname:port/cacheName
*/
public final String getUrl() {
return new StringBuilder()
.append("//")
.append(hostname.contains(":") ? ("[" + hostname + "]") : hostname)
.append(":")
.append(rmiRegistryPort)
.append("/")
.append(cache.getName())
.toString();
}
/**
* {@inheritDoc}
*
* This implementation gives an URL which has meaning to the RMI remoting system.
*
* @return the URL, without the scheme, as a string e.g. //hostname:port
*/
public final String getUrlBase() {
return new StringBuilder()
.append("//")
.append(hostname.contains(":") ? ("[" + hostname + "]") : hostname)
.append(":")
.append(rmiRegistryPort)
.toString();
}
/**
* Returns a list of all elements in the cache, whether or not they are expired.
*
* The returned keys are unique and can be considered a set.
*
* The List returned is not live. It is a copy.
*
* The time taken is O(n). On a single cpu 1.8Ghz P4, approximately 8ms is required
* for each 1000 entries.
*
* @return a list of {@link Object} keys
*/
public List getKeys() throws RemoteException {
List keys = cache.getKeys();
if (keys instanceof Serializable) {
return keys;
}
return new ArrayList(keys);
}
/**
* Gets an element from the cache, without updating Element statistics. Cache statistics are
* still updated.
*
* @param key a serializable value
* @return the element, or null, if it does not exist.
*/
public Element getQuiet(Serializable key) throws RemoteException {
return cache.getQuiet(key);
}
/**
* Gets a list of elements from the cache, for a list of keys, without updating Element statistics. Time to
* idle lifetimes are therefore not affected.
*
* Cache statistics are still updated.
*
* Callers should ideally first call this method with a small list of keys to gauge the size of a typical Element.
* Then a calculation can be made of the right number to request each time so as to optimise network performance and
* not cause an OutOfMemory error on this Cache.
*
* @param keys a list of serializable values which represent keys
* @return a list of Elements. If an element was not found or null, it will not be in the list.
*/
public List getElements(List keys) throws RemoteException {
if (keys == null) {
return new ArrayList();
}
List elements = new ArrayList();
for (int i = 0; i < keys.size(); i++) {
Serializable key = (Serializable) keys.get(i);
Element element = cache.getQuiet(key);
if (element != null) {
elements.add(element);
}
}
return elements;
}
/**
* Puts an Element into the underlying cache without notifying listeners or updating statistics.
*
* @param element
* @throws java.rmi.RemoteException
* @throws IllegalArgumentException
* @throws IllegalStateException
*/
public void put(Element element) throws RemoteException, IllegalArgumentException, IllegalStateException {
cache.put(element, true);
if (LOG.isDebugEnabled()) {
LOG.debug("RMICachePeer for cache " + cache.getName() + ": remote put received. Element is: " + element);
}
}
/**
* Removes an Element from the underlying cache without notifying listeners or updating statistics.
*
* @param key
* @return true if the element was removed, false if it was not found in the cache
* @throws RemoteException
* @throws IllegalStateException
*/
public boolean remove(Serializable key) throws RemoteException, IllegalStateException {
if (LOG.isDebugEnabled()) {
LOG.debug("RMICachePeer for cache " + cache.getName() + ": remote remove received for key: " + key);
}
return cache.remove(key, true);
}
/**
* Removes all cached items.
*
* @throws IllegalStateException if the cache is not {@link net.sf.ehcache.Status#STATUS_ALIVE}
*/
public void removeAll() throws RemoteException, IllegalStateException {
if (LOG.isDebugEnabled()) {
LOG.debug("RMICachePeer for cache " + cache.getName() + ": remote removeAll received");
}
cache.removeAll(true);
}
/**
* Send the cache peer with an ordered list of {@link EventMessage}s
*
* This enables multiple messages to be delivered in one network invocation.
*/
public void send(List eventMessages) throws RemoteException {
for (int i = 0; i < eventMessages.size(); i++) {
RmiEventMessage eventMessage = (RmiEventMessage) eventMessages.get(i);
if (eventMessage.getType() == RmiEventType.PUT) {
put(eventMessage.getElement());
} else if (eventMessage.getType() == RmiEventType.REMOVE) {
remove(eventMessage.getSerializableKey());
} else if (eventMessage.getType() == RmiEventType.REMOVE_ALL) {
removeAll();
} else {
LOG.error("Unknown event: " + eventMessage);
}
}
}
/**
* Gets the cache name
*/
public final String getName() throws RemoteException {
return cache.getName();
}
/**
* {@inheritDoc}
*/
public final String getGuid() throws RemoteException {
return cache.getGuid();
}
/**
* Gets the cache instance that this listener is bound to
*/
final Ehcache getBoundCacheInstance() {
return cache;
}
/**
* Returns a String that represents the value of this object.
*/
public String toString() {
StringBuilder buffer = new StringBuilder("URL: ");
buffer.append(getUrl());
buffer.append(" Remote Object Port: ");
buffer.append(remoteObjectPort);
return buffer.toString();
}
}