Any reason that the RemoteCacheServer class is not exposed in the
Javadocs?

http://jakarta.apache.org/jcs/apidocs/org/apache/jcs/auxiliary/remote/se
rver/RemoteCacheServerFactory.html


-----Original Message-----
From: Aaron Smuts (JIRA) [mailto:j...@apache.org] 
Sent: Monday, August 31, 2009 8:29 AM
To: jcs-dev@jakarta.apache.org
Subject: [jira] Commented: (JCS-68) Admin.jsp on remote cache server
does not broadcast removes - patch


    [
https://issues.apache.org/jira/browse/JCS-68?page=com.atlassian.jira.plu
gin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12749487#act
ion_12749487 ] 

Aaron Smuts commented on JCS-68:
--------------------------------

Thanks, this is a good idea.  Why are you calling the remove method via
reflection?  That's too fragile.  Especially without any unit tests.  I
need unit tests for all changes.  

> Admin.jsp on remote cache server does not broadcast removes - patch
> -------------------------------------------------------------------
>
>                 Key: JCS-68
>                 URL: https://issues.apache.org/jira/browse/JCS-68
>             Project: JCS
>          Issue Type: Bug
>          Components: RMI Remote Cache
>    Affects Versions: jcs-1.3, jcs-1.4-dev
>         Environment: All
>            Reporter: Niall Gallagher
>            Assignee: Aaron Smuts
>            Priority: Minor
>   Original Estimate: 0.5h
>  Remaining Estimate: 0.5h
>
> We'd like to contribute some patches to fix an issue with the
JCSAdmin.jsp when it's used on a JCS remote cache server.
> We use this JSP on our remote cache server. This allows us to browse
the objects stored in our distributed cache (i.e. uploaded by the client
servers), and allows us to remove arbitrary objects from the distributed
cache by clicking 'remove' next to the key of the relevant object
displayed on the JSP.
> The issue is: when we use the unmodified version of the code to remove
an object, the object is successfully removed from the JCS remote
server, but the 'remove' event for that object is not broadcast to all
client machines. Client machines which start up after we remove the
object get 'null' when they try to retrieve the object (the desired
behaviour). However client machines which were already running and using
this object continue to see the object in their view of the cache.
> This problem occurs because the JCSAdminBean (used by this JSP) calls
the wrong API in JCS to remove objects from the cache when it's running
on the remote cache server. It calls the CompositeCache API, which is
intended for use client-side only.
> Our patches update JCSAdminBean to call this same API when its running
on a client machine, BUT if it's running on a machine on which the JCS
remote server is enabled, it calls the RemoteCacheServer API instead.
> The fix involves replacing 3 methods in
org.apache.jcs.admin.JCSAdminBean as follows:
>     /**
>      * Clears all regions in the cache.
>      * <p/>
>      * If this class is running within a remote cache server, clears
all regions via the <code>RemoteCacheServer</code>
>      * API, so that removes will be broadcast to client machines.
Otherwise clears all regions in the cache directly via
>      * the usual cache API.
>      */
>     public void clearAllRegions() throws IOException {
>         if (RemoteCacheServerFactory.getRemoteCacheServer() == null) {
>             // Not running in a remote cache server.
>             // Remove objects from the cache directly, as no need to
broadcast removes to client machines...
>             String[] names = cacheHub.getCacheNames();
>             for (int i = 0; i < names.length; i++) {
>                 cacheHub.getCache(names[i]).removeAll();
>             }
>         }
>         else {
>             // Running in a remote cache server.
>             // Remove objects via the RemoteCacheServer API, so that
removes will be broadcast to client machines...
>             try {
>                 String[] cacheNames =
CompositeCacheManager.getInstance().getCacheNames();
>                 // Call remoteCacheServer.removeAll(String) for each
cacheName...
>                 // Note: We must do this using reflection to bypass
its package-private access...
>                 Object remoteCacheServerObject =
RemoteCacheServerFactory.getRemoteCacheServer();
>                 Method removeAllMethod =
remoteCacheServerObject.getClass().getMethod("removeAll", new
Class[]{String.class});
>                 boolean previouslyAccessibility =
removeAllMethod.isAccessible();
>                 removeAllMethod.setAccessible(true);
>                 for (int i = 0; i < cacheNames.length; i++) {
>                     String cacheName = cacheNames[i];
>                     removeAllMethod.invoke(remoteCacheServerObject,
new Object[]{cacheName});
>                 }
>
removeAllMethod.setAccessible(previouslyAccessibility);
>             }
>             catch (Exception e) {
>                 throw new IllegalStateException("Failed to remove all
elements from all cache regions: " + e, e);
>             }
>         }
>     }
>     /**
>      * Clears a particular cache region.
>      * <p/>
>      * If this class is running within a remote cache server, clears
the region via the <code>RemoteCacheServer</code>
>      * API, so that removes will be broadcast to client machines.
Otherwise clears the region directly via the usual
>      * cache API.
>      */
>     public void clearRegion(String cacheName) throws IOException {
>         if (cacheName == null) {
>             throw new IllegalArgumentException("The cache name
specified was null.");
>         }
>         if (RemoteCacheServerFactory.getRemoteCacheServer() == null) {
>             // Not running in a remote cache server.
>             // Remove objects from the cache directly, as no need to
broadcast removes to client machines...
>             cacheHub.getCache(cacheName).removeAll();
>         }
>         else {
>             // Running in a remote cache server.
>             // Remove objects via the RemoteCacheServer API, so that
removes will be broadcast to client machines...
>             try {
>                 // Call remoteCacheServer.removeAll(String)...
>                 // Note: We must do this using reflection to bypass
its package-private access...
>                 Object remoteCacheServerObject =
RemoteCacheServerFactory.getRemoteCacheServer();
>                 Method removeAllMethod =
remoteCacheServerObject.getClass().getMethod("removeAll", new
Class[]{String.class});
>                 boolean previouslyAccessibility =
removeAllMethod.isAccessible();
>                 removeAllMethod.setAccessible(true);
>                 removeAllMethod.invoke(remoteCacheServerObject, new
Object[]{cacheName});
>
removeAllMethod.setAccessible(previouslyAccessibility);
>             }
>             catch (Exception e) {
>                 throw new IllegalStateException("Failed to remove all
elements from cache region [" + cacheName + "]: " + e, e);
>             }
>         }
>     }
>     /**
>      * Removes a particular item from a particular region.
>      * <p/>
>      * If this class is running within a remote cache server, removes
the item via the <code>RemoteCacheServer</code>
>      * API, so that removes will be broadcast to client machines.
Otherwise clears the region directly via the usual
>      * cache API.
>      *
>      * @param cacheName
>      * @param key
>      *
>      * @throws IOException
>      */
>     public void removeItem(String cacheName, String key) throws
IOException {
>         if (cacheName == null) {
>             throw new IllegalArgumentException("The cache name
specified was null.");
>         }
>         if (key == null) {
>             throw new IllegalArgumentException("The key specified was
null.");
>         }
>         if (RemoteCacheServerFactory.getRemoteCacheServer() == null) {
>             // Not running in a remote cache server.
>             // Remove objects from the cache directly, as no need to
broadcast removes to client machines...
>             cacheHub.getCache(cacheName).remove(key);
>         }
>         else {
>             // Running in a remote cache server.
>             // Remove objects via the RemoteCacheServer API, so that
removes will be broadcast to client machines...
>             try {
>                 Object keyToRemove = null;
>                 CompositeCache cache =
CompositeCacheManager.getInstance().getCache(cacheName);
>                 // A String key was supplied, but to remove elements
via the RemoteCacheServer API, we need the
>                 // actual key object as stored in the cache (i.e. a
Serializable object). To find the key in this form,
>                 // we iterate through all keys stored in the memory
cache until we find one whose toString matches
>                 // the string supplied...
>                 Object[] allKeysInCache =
cache.getMemoryCache().getKeyArray();
>                 for (int i = 0; i < allKeysInCache.length; i++) {
>                     Object keyInCache = allKeysInCache[i];
>                     if (keyInCache.toString().equals(key)) {
>                         if (keyToRemove == null) {
>                             keyToRemove = keyInCache;
>                         }
>                         else {
>                             // A key matching the one specified was
already found...
>                             throw new
IllegalStateException("Unexpectedly found duplicate keys in the cache
region matching the key specified.");
>                         }
>                     }
>                 }
>                 if (keyToRemove == null) {
>                     throw new IllegalStateException("No match for this
key could be found in the set of keys retrieved from the memory
cache.");
>                 }
>                 if (!(keyToRemove instanceof Serializable)) {
>                     throw new IllegalStateException("Found key [" +
keyToRemove + ", " + keyToRemove.getClass() + "] in cache matching key
specified, however key found in cache is unexpectedly not
serializable.");
>                 }
>                 // At this point, we have retrieved the matching
Serializable key.
>                 // Call remoteCacheServer.remove(String,
Serializable)...
>                 // Note: We must fo this using reflection to bypass
its package-private access...
>                 Object remoteCacheServerObject =
RemoteCacheServerFactory.getRemoteCacheServer();
>                 Method removeMethod =
remoteCacheServerObject.getClass().getMethod("remove", new
Class[]{String.class, Serializable.class});
>                 boolean previouslyAccessibility =
removeMethod.isAccessible();
>                 removeMethod.setAccessible(true);
>                 removeMethod.invoke(remoteCacheServerObject, new
Object[]{cacheName, keyToRemove});
>                 removeMethod.setAccessible(previouslyAccessibility);
>             }
>             catch (Exception e) {
>                 throw new IllegalStateException("Failed to remove
element with key [" + key + ", " + key.getClass() + "] from cache region
[" + cacheName + "]: " + e, e);
>             }
>         }
>     }

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


---------------------------------------------------------------------
To unsubscribe, e-mail: jcs-dev-unsubscr...@jakarta.apache.org
For additional commands, e-mail: jcs-dev-h...@jakarta.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: jcs-dev-unsubscr...@jakarta.apache.org
For additional commands, e-mail: jcs-dev-h...@jakarta.apache.org

Reply via email to