View Javadoc

1   /**
2    *  Copyright 2003-2007 Greg Luck
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  
17  package net.sf.ehcache.distribution;
18  
19  import net.sf.ehcache.Ehcache;
20  import net.sf.ehcache.Element;
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  
24  import java.io.Serializable;
25  import java.rmi.Remote;
26  import java.rmi.RemoteException;
27  import java.rmi.server.RMISocketFactory;
28  import java.rmi.server.UnicastRemoteObject;
29  import java.util.List;
30  import java.util.ArrayList;
31  
32  /**
33   * An RMI based implementation of <code>CachePeer</code>.
34   * <p/>
35   * This class features a customised RMIClientSocketFactory which enables socket timeouts to be configured.
36   *
37   * @author Greg Luck
38   * @version $Id: RMICachePeer.java 512 2007-07-10 09:18:45Z gregluck $
39   * @noinspection FieldCanBeLocal
40   */
41  public class RMICachePeer extends UnicastRemoteObject implements CachePeer, Remote {
42  
43      private static final Log LOG = LogFactory.getLog(RMICachePeer.class.getName());
44  
45      private final String hostname;
46      private final Integer port;
47      private final Ehcache cache;
48  
49      /**
50       * Construct a new remote peer.
51       *
52       * @param cache
53       * @param hostName
54       * @param port
55       * @param socketTimeoutMillis
56       * @throws RemoteException
57       */
58      public RMICachePeer(Ehcache cache, String hostName, Integer port, Integer socketTimeoutMillis)
59              throws RemoteException {
60          super(0, new ConfigurableRMIClientSocketFactory(socketTimeoutMillis),
61                  RMISocketFactory.getDefaultSocketFactory());
62  
63          this.hostname = hostName;
64          this.port = port;
65          this.cache = cache;
66      }
67  
68      /**
69       * {@inheritDoc}
70       * <p/>
71       * This implementation gives an URL which has meaning to the RMI remoting system.
72       *
73       * @return the URL, without the scheme, as a string e.g. //hostname:port/cacheName
74       */
75      public final String getUrl() {
76          return new StringBuffer()
77                  .append("//")
78                  .append(hostname)
79                  .append(":")
80                  .append(port)
81                  .append("/")
82                  .append(cache.getName())
83                  .toString();
84      }
85  
86      /**
87       * {@inheritDoc}
88       * <p/>
89       * This implementation gives an URL which has meaning to the RMI remoting system.
90       *
91       * @return the URL, without the scheme, as a string e.g. //hostname:port
92       */
93      public final String getUrlBase() {
94          return new StringBuffer()
95                  .append("//")
96                  .append(hostname)
97                  .append(":")
98                  .append(port)
99                  .toString();
100     }
101 
102     /**
103      * Returns a list of all elements in the cache, whether or not they are expired.
104      * <p/>
105      * The returned keys are unique and can be considered a set.
106      * <p/>
107      * The List returned is not live. It is a copy.
108      * <p/>
109      * The time taken is O(n). On a single cpu 1.8Ghz P4, approximately 8ms is required
110      * for each 1000 entries.
111      *
112      * @return a list of {@link Object} keys
113      */
114     public List getKeys() throws RemoteException {
115         return cache.getKeys();
116     }
117 
118     /**
119      * Gets an element from the cache, without updating Element statistics. Cache statistics are
120      * still updated.
121      *
122      * @param key a serializable value
123      * @return the element, or null, if it does not exist.
124      */
125     public Element getQuiet(Serializable key) throws RemoteException {
126         return cache.getQuiet(key);
127     }
128 
129     /**
130      * Gets a list of elements from the cache, for a list of keys, without updating Element statistics. Time to
131      * idle lifetimes are therefore not affected.
132      * <p/>
133      * Cache statistics are still updated.
134      * <p/>
135      * Callers should ideally first call this method with a small list of keys to gauge the size of a typical Element.
136      * Then a calculation can be made of the right number to request each time so as to optimise network performance and
137      * not cause an OutOfMemory error on this Cache.
138      *
139      * @param keys a list of serializable values which represent keys
140      * @return a list of Elements. If an element was not found or null, it will not be in the list.
141      */
142     public List getElements(List keys) throws RemoteException {
143         if (keys == null) {
144             return new ArrayList();
145         }
146         List elements = new ArrayList();
147         for (int i = 0; i < keys.size(); i++) {
148             Serializable key = (Serializable) keys.get(i);
149             Element element = cache.getQuiet(key);
150             if (element != null) {
151                 elements.add(element);
152             }
153         }
154         return elements;
155     }
156 
157 
158     /**
159      * Puts an Element into the underlying cache without notifying listeners or updating statistics.
160      *
161      * @param element
162      * @throws java.rmi.RemoteException
163      * @throws IllegalArgumentException
164      * @throws IllegalStateException
165      */
166     public void put(Element element) throws RemoteException, IllegalArgumentException, IllegalStateException {
167         cache.put(element, true);
168         if (LOG.isDebugEnabled()) {
169             LOG.debug("Remote put received. Element is: " + element);
170         }
171     }
172 
173 
174     /**
175      * Removes an Element from the underlying cache without notifying listeners or updating statistics.
176      *
177      * @param key
178      * @return true if the element was removed, false if it was not found in the cache
179      * @throws RemoteException
180      * @throws IllegalStateException
181      */
182     public final boolean remove(Serializable key) throws RemoteException, IllegalStateException {
183         if (LOG.isDebugEnabled()) {
184             LOG.debug("Remote remove received for key: " + key);
185         }
186         return cache.remove(key, true);
187     }
188 
189     /**
190      * Removes all cached items.
191      *
192      * @throws IllegalStateException if the cache is not {@link net.sf.ehcache.Status#STATUS_ALIVE}
193      */
194     public final void removeAll() throws RemoteException, IllegalStateException {
195         if (LOG.isDebugEnabled()) {
196             LOG.debug("Remote removeAll received");
197         }
198         cache.removeAll(true);
199     }
200 
201     /**
202      * Send the cache peer with an ordered list of {@link EventMessage}s
203      * <p/>
204      * This enables multiple messages to be delivered in one network invocation.
205      */
206     public final void send(List eventMessages) throws RemoteException {
207         for (int i = 0; i < eventMessages.size(); i++) {
208             EventMessage eventMessage = (EventMessage) eventMessages.get(i);
209             if (eventMessage.getEvent() == EventMessage.PUT) {
210                 put(eventMessage.getElement());
211             } else if (eventMessage.getEvent() == EventMessage.REMOVE) {
212                 remove(eventMessage.getSerializableKey());
213             } else if (eventMessage.getEvent() == EventMessage.REMOVE_ALL) {
214                 removeAll();
215             } else {
216                 LOG.error("Unknown event: " + eventMessage);
217             }
218         }
219     }
220 
221     /**
222      * Gets the cache name
223      */
224     public final String getName() throws RemoteException {
225         return cache.getName();
226     }
227 
228 
229     /**
230      * {@inheritDoc}
231      */
232     public final String getGuid() throws RemoteException {
233         return cache.getGuid();
234     }
235 
236     /**
237      * Gets the cache instance that this listener is bound to
238      */
239     final Ehcache getBoundCacheInstance() {
240         return cache;
241     }
242 
243     /**
244      * Returns a String that represents the value of this object.
245      */
246     public String toString() {
247         return getUrl();
248     }
249 
250 }