<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>jcs-dev@jakarta.apache.org Archives</title>
<link rel="self" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/?format=atom"/>
<link href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/"/>
<id>http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/</id>
<updated>2009-12-05T19:27:07Z</updated>
<entry>
<title>svn commit: r887227 - /jakarta/jcs/trunk/src/java/org/apache/jcs/utils/access/JCSWorker.java</title>
<author><name>asmuts@apache.org</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200912.mbox/%3c20091204153025.3A2E623888FD@eris.apache.org%3e"/>
<id>urn:uuid:%3c20091204153025-3A2E623888FD@eris-apache-org%3e</id>
<updated>2009-12-04T15:30:25Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>
Author: asmuts
Date: Fri Dec  4 15:30:24 2009
New Revision: 887227

URL: http://svn.apache.org/viewvc?rev=887227&amp;view=rev
Log:
Fixing JCS-69 - https://issues.apache.org/jira/browse/JCS-69

Modified:
    jakarta/jcs/trunk/src/java/org/apache/jcs/utils/access/JCSWorker.java

Modified: jakarta/jcs/trunk/src/java/org/apache/jcs/utils/access/JCSWorker.java
URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/utils/access/JCSWorker.java?rev=887227&amp;r1=887226&amp;r2=887227&amp;view=diff
==============================================================================
--- jakarta/jcs/trunk/src/java/org/apache/jcs/utils/access/JCSWorker.java (original)
+++ jakarta/jcs/trunk/src/java/org/apache/jcs/utils/access/JCSWorker.java Fri Dec  4 15:30:24
2009
@@ -287,11 +287,11 @@
                 {
                     map.remove( getRegion() + aKey );
                 }
-                synchronized ( this )
+                synchronized ( aHelper )
                 {
                     aHelper.setFinished( true );
                     // Wake everyone waiting on us
-                    notifyAll();
+                    aHelper.notifyAll();
                 }
             }
         }



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



</pre>
</div>
</content>
</entry>
<entry>
<title>JCSWorker locks indefinitely - code fix provided.</title>
<author><name>Scott Archer &lt;scott.archer@gmail.com&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200912.mbox/%3c4858e4e30912040720g41e97e70jc683821d322604fe@mail.gmail.com%3e"/>
<id>urn:uuid:%3c4858e4e30912040720g41e97e70jc683821d322604fe@mail-gmail-com%3e</id>
<updated>2009-12-04T15:20:20Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>
Is there any chance we could get this code into the trunk?
We're running off our own build now, and it would be nice to keep in sync
with any changes going forward.

We've implemented this code change and the fix is working great.

Thanks,

Scott


https://issues.apache.org/jira/browse/JCS-69

When using the JCSWorker threads lock indefinitely.
I believe the synchronized block in the finally block is synchronizing on
and notifying the wrong object.

Once a thread locks it never unlocks.


Class: org.apache.jcs.utils.access.JCSWorker
Method: private Object run( Serializable aKey, String aGroup,
JCSWorkerHelper aHelper ) throws Exception

Bad Code (in finally block):
 synchronized ( this )
 {
     aHelper.setFinished( true );
     // Wake everyone waiting on us
     notifyAll();
 }

Suggested Fix:
 synchronized ( aHelper )
 {
     aHelper.setFinished( true );
     // Wake everyone waiting on aHelper
     aHelper.notifyAll();
 }


</pre>
</div>
</content>
</entry>
<entry>
<title>[jira] Created: (JCS-70) jcs-1.3.3.5-RC.jar compiled with JDK 1.4 and when we use the same in JDK 1.5.x environment the Garbage collection doesnt look good</title>
<author><name>&quot;Parthiban (JIRA)&quot; &lt;jira@apache.org&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200912.mbox/%3c722380308.1259801960845.JavaMail.jira@brutus%3e"/>
<id>urn:uuid:%3c722380308-1259801960845-JavaMail-jira@brutus%3e</id>
<updated>2009-12-03T00:59:20Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>
jcs-1.3.3.5-RC.jar compiled with JDK 1.4 and when we use the same in JDK 1.5.x environment
the Garbage collection doesnt look good
----------------------------------------------------------------------------------------------------------------------------------

                 Key: JCS-70
                 URL: https://issues.apache.org/jira/browse/JCS-70
             Project: JCS
          Issue Type: Bug
    Affects Versions: jcs-1.3
         Environment: Solaris 10, SUN web server 6.x
            Reporter: Parthiban
            Assignee: Aaron Smuts
             Fix For: jcs-1.3


  Currently we are using JCS 1.2.x older version of the JCS and trying to upgrade the version
but the latest version "jcs-1.3.3.5-RC" is compiled with JDK 1.4 and seems to be because of
the JDK 1.4 compilation the garbage collection doesnt look good so please help me to get the
"jcs-1.3.3.5-RC" version compiled with JDK 1.5.x.


The JCS jar downloaded path: 
http://svn.apache.org/repos/asf/jakarta/jcs/tempbuilds/

jcs-1.3.3.5-RC.jar
================
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.5.3 
Created-By: Apache Maven
Built-By: SG0894751
Package: org.apache.jcs
Build-Jdk: 1.4.2_18
Extension-Name: jcs
Specification-Title: Cache
Specification-Vendor: Apache Software Foundation
Implementation-Title: org.apache.jcs
Implementation-Vendor: Apache Software Foundation
Implementation-Version: 1.3.3.5-RC
X-Compile-Source-JDK: 1.4
X-Compile-Target-JDK: 1.4


this version "jcs-1.3.3.2-RC.jar" was compiled with the right JDK 1.5
================
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.5.3 
Created-By: Apache Maven
Built-By: SG0894751
Package: org.apache.jcs
Build-Jdk: 1.5.0_15
Extension-Name: jcs
Specification-Title: Cache
Specification-Vendor: Apache Software Foundation
Implementation-Title: org.apache.jcs
Implementation-Vendor: Apache Software Foundation
Implementation-Version: 1.3.3.2-RC
X-Compile-Source-JDK: 1.4
X-Compile-Target-JDK: 1.4


-- 
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-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jcs-dev-help@jakarta.apache.org



</pre>
</div>
</content>
</entry>
<entry>
<title>[NOTICE] Jakarta development mailing lists merging</title>
<author><name>Rahul Akolkar &lt;rahul.akolkar@gmail.com&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200911.mbox/%3cce1f2ea80911161711k5c3ee4aasc51a273fb60e4bd7@mail.gmail.com%3e"/>
<id>urn:uuid:%3cce1f2ea80911161711k5c3ee4aasc51a273fb60e4bd7@mail-gmail-com%3e</id>
<updated>2009-11-17T01:11:00Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>
The existing development mailing lists for Jakarta subprojects (BCEL,
BSF, Cactus, ECS, JCS, JMeter, ORO, Regexp and retired subproject
Slide) are merging.

Two new lists will be soon be created, one for development discussions
and another for notifications (such as SVN, Bugzilla, JIRA, Gump).
Subscribers to any of the existing development lists mentioned above
(also see CC header of this message) will be subscribed to the two new
lists automatically. The existing lists that appear in the CC header
of this message will subsequently be closed, with appropriate forwards
in place to point to the merged list.

The shared development discussions mailing list will use the
convention of identifying the subproject associated with the posting
in the email subject using square brackets. For example, a recent
email sent to the jmeter-dev list had the subject:

 Exposing run info with JMX

Once the shared mailing list is set up, the convention would be to use
the following email subject instead:

 [JMeter] Exposing run info with JMX

As a reminder, unsubscribing from a mailing list called
list@jakarta.apache.org can be done by sending an email to
list-unsubscribe@jakarta.apache.org (replace "list" with actual name
of the mailing list to unsubscribe from).

-Rahul

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



</pre>
</div>
</content>
</entry>
<entry>
<title>Regarding replication of cache - Please help ...i am in great need</title>
<author><name>Srikanth P &lt;aries.srikanth@gmail.com&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200911.mbox/%3cbedbebfb0911061053q56e36103hc7c65e6704cf8b70@mail.gmail.com%3e"/>
<id>urn:uuid:%3cbedbebfb0911061053q56e36103hc7c65e6704cf8b70@mail-gmail-com%3e</id>
<updated>2009-11-06T18:53:38Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>
Hi,

Pardon my ignorance. I am not very familiar caching mechanisms. Please go
through the following scenario and help me

*Scenario: *
*
*
There are two servers A and B (say). A has to fetch the data from database
and put it in its cache. This cache has to be replicated to server B. In
case of failure, B should take the responsibility of fetching the data from
database and putting in cache. When "A" comes up then again "A" should be
the master server and it should fetch the data from DB and put it in cache
and replicate the cache to B.


One more thing is, we are planning to expose the data in the cache as a
webservice. When the client access the webservice, then it should get the
cached data in the form of XML.


Please tell me how to implement the above scenario using *JCS* cache and
provide any useful url's that I can go through. Even if you have any POC's
please share.

What I want to know in particular is " how to replicate  cache over cluster
using JCS?"  and " What has to be done in case of master server failure?"

Thanks and Regards,
Sri Kanth


</pre>
</div>
</content>
</entry>
<entry>
<title>RE: [jira] Commented: (JCS-58) disc file cache</title>
<author><name>&quot;Tim Cronin&quot; &lt;Tim.Cronin@autonomy.com&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200910.mbox/%3c56A8F47A92B81F4C91648D4E38286A4804A9595F@exbehq01.Interwoven.com%3e"/>
<id>urn:uuid:%3c56A8F47A92B81F4C91648D4E38286A4804A9595F@exbehq01-Interwoven-com%3e</id>
<updated>2009-10-26T21:20:07Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>
&gt;It simply replaces all strange characters and spaces with underscores.


Why spaces if the os supports it or even strange chars if the os
supports non ascii encodings?

You can end up causing collisions with that type of replace.

-----Original Message-----
From: Aaron Smuts (JIRA) [mailto:jira@apache.org] 
Sent: Monday, October 26, 2009 3:53 PM
To: jcs-dev@jakarta.apache.org
Subject: [jira] Commented: (JCS-58) disc file cache


    [
https://issues.apache.org/jira/browse/JCS-58?page=com.atlassian.jira.plu
gin.system.issuetabpanels:comment-tabpanel&amp;focusedCommentId=12770189#act
ion_12770189 ] 

Aaron Smuts commented on JCS-58:
--------------------------------

Please send questions like this to the mailing list.  

Read the documentation.  This disk cache is like any other.  You
configure JCS to use it in the cache.ccf file just like any other disk
cache.  

If you want to create files outside of JCS, we'll have to expose a
utility for creating the names.  The algorithm is simply though.  It
simply replaces all strange characters and spaces with underscores.  

Please post to the user mailing list.

&gt; disc file cache
&gt; ---------------
&gt;
&gt;                 Key: JCS-58
&gt;                 URL: https://issues.apache.org/jira/browse/JCS-58
&gt;             Project: JCS
&gt;          Issue Type: New Feature
&gt;    Affects Versions: jcs-1.3
&gt;            Reporter: Tore Halset
&gt;            Assignee: Aaron Smuts
&gt;             Fix For: jcs-1.4-dev
&gt;
&gt;         Attachments: DiskFileCache.java, DiskFileCacheAttributes.java,
DiskFileCacheFactory.java
&gt;
&gt;
&gt; It would be nice to have a file based cache in jcs where each item is
stored as a single file and the filename is based on the key. This way,
several jvms can share the same cache and the cache can be rsynced
between nodes while running the application. 

-- 
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-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jcs-dev-help@jakarta.apache.org


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



</pre>
</div>
</content>
</entry>
<entry>
<title>[jira] Commented: (JCS-58) disc file cache</title>
<author><name>&quot;Aaron Smuts (JIRA)&quot; &lt;jira@apache.org&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200910.mbox/%3c464299960.1256590379456.JavaMail.jira@brutus%3e"/>
<id>urn:uuid:%3c464299960-1256590379456-JavaMail-jira@brutus%3e</id>
<updated>2009-10-26T20:52:59Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>

    [ https://issues.apache.org/jira/browse/JCS-58?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&amp;focusedCommentId=12770189#action_12770189
] 

Aaron Smuts commented on JCS-58:
--------------------------------

Please send questions like this to the mailing list.  

Read the documentation.  This disk cache is like any other.  You configure JCS to use it in
the cache.ccf file just like any other disk cache.  

If you want to create files outside of JCS, we'll have to expose a utility for creating the
names.  The algorithm is simply though.  It simply replaces all strange characters and spaces
with underscores.  

Please post to the user mailing list.

&gt; disc file cache
&gt; ---------------
&gt;
&gt;                 Key: JCS-58
&gt;                 URL: https://issues.apache.org/jira/browse/JCS-58
&gt;             Project: JCS
&gt;          Issue Type: New Feature
&gt;    Affects Versions: jcs-1.3
&gt;            Reporter: Tore Halset
&gt;            Assignee: Aaron Smuts
&gt;             Fix For: jcs-1.4-dev
&gt;
&gt;         Attachments: DiskFileCache.java, DiskFileCacheAttributes.java, DiskFileCacheFactory.java
&gt;
&gt;
&gt; It would be nice to have a file based cache in jcs where each item is stored as a single
file and the filename is based on the key. This way, several jvms can share the same cache
and the cache can be rsynced between nodes while running the application. 

-- 
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-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jcs-dev-help@jakarta.apache.org



</pre>
</div>
</content>
</entry>
<entry>
<title>[jira] Commented: (JCS-58) disc file cache</title>
<author><name>&quot;Chopin Hu (JIRA)&quot; &lt;jira@apache.org&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200910.mbox/%3c270528078.1256589182355.JavaMail.jira@brutus%3e"/>
<id>urn:uuid:%3c270528078-1256589182355-JavaMail-jira@brutus%3e</id>
<updated>2009-10-26T20:33:02Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>

    [ https://issues.apache.org/jira/browse/JCS-58?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&amp;focusedCommentId=12770179#action_12770179
] 

Chopin Hu commented on JCS-58:
------------------------------

Aaron,

I am still not getting it right. Seems that I put an ascii file into the file disk as a separate
file. But when it is an binary file. It does not work. Though I set the jvm to a bigger size
(1560MBs) to handle a 12 MBs binary file, it still fails. Do you have an sample code to show
how to make it work? If you need, I can send you a copy of the binary file I used for testing.

Thanks.

&gt; disc file cache
&gt; ---------------
&gt;
&gt;                 Key: JCS-58
&gt;                 URL: https://issues.apache.org/jira/browse/JCS-58
&gt;             Project: JCS
&gt;          Issue Type: New Feature
&gt;    Affects Versions: jcs-1.3
&gt;            Reporter: Tore Halset
&gt;            Assignee: Aaron Smuts
&gt;             Fix For: jcs-1.4-dev
&gt;
&gt;         Attachments: DiskFileCache.java, DiskFileCacheAttributes.java, DiskFileCacheFactory.java
&gt;
&gt;
&gt; It would be nice to have a file based cache in jcs where each item is stored as a single
file and the filename is based on the key. This way, several jvms can share the same cache
and the cache can be rsynced between nodes while running the application. 

-- 
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-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jcs-dev-help@jakarta.apache.org



</pre>
</div>
</content>
</entry>
<entry>
<title>[jira] Commented: (JCS-58) disc file cache</title>
<author><name>&quot;Chopin Hu (JIRA)&quot; &lt;jira@apache.org&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200910.mbox/%3c1291222024.1256589182200.JavaMail.jira@brutus%3e"/>
<id>urn:uuid:%3c1291222024-1256589182200-JavaMail-jira@brutus%3e</id>
<updated>2009-10-26T20:33:02Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>

    [ https://issues.apache.org/jira/browse/JCS-58?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&amp;focusedCommentId=12770178#action_12770178
] 

Chopin Hu commented on JCS-58:
------------------------------

Aaron,

I am still not getting it right.   Seems that I put an ascii file into the file disk as a
separate file.   But when it is an binary file.   It does not work.    Though I set the jvm
to a bigger size (1560MBs) to handle a 12 MBs binary file, it still fails.   Do you have an
sample code to show how to make it work?   If you need, I can send you a copy of the binary
file I used for testing.

Thanks.

&gt; disc file cache
&gt; ---------------
&gt;
&gt;                 Key: JCS-58
&gt;                 URL: https://issues.apache.org/jira/browse/JCS-58
&gt;             Project: JCS
&gt;          Issue Type: New Feature
&gt;    Affects Versions: jcs-1.3
&gt;            Reporter: Tore Halset
&gt;            Assignee: Aaron Smuts
&gt;             Fix For: jcs-1.4-dev
&gt;
&gt;         Attachments: DiskFileCache.java, DiskFileCacheAttributes.java, DiskFileCacheFactory.java
&gt;
&gt;
&gt; It would be nice to have a file based cache in jcs where each item is stored as a single
file and the filename is based on the key. This way, several jvms can share the same cache
and the cache can be rsynced between nodes while running the application. 

-- 
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-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jcs-dev-help@jakarta.apache.org



</pre>
</div>
</content>
</entry>
<entry>
<title>[jira] Commented: (JCS-58) disc file cache</title>
<author><name>&quot;Chopin Hu (JIRA)&quot; &lt;jira@apache.org&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200910.mbox/%3c1263621782.1256551439390.JavaMail.jira@brutus%3e"/>
<id>urn:uuid:%3c1263621782-1256551439390-JavaMail-jira@brutus%3e</id>
<updated>2009-10-26T10:03:59Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>

    [ https://issues.apache.org/jira/browse/JCS-58?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&amp;focusedCommentId=12769968#action_12769968
] 

Chopin Hu commented on JCS-58:
------------------------------

Figured out how to use it.   Thanks.

&gt; disc file cache
&gt; ---------------
&gt;
&gt;                 Key: JCS-58
&gt;                 URL: https://issues.apache.org/jira/browse/JCS-58
&gt;             Project: JCS
&gt;          Issue Type: New Feature
&gt;    Affects Versions: jcs-1.3
&gt;            Reporter: Tore Halset
&gt;            Assignee: Aaron Smuts
&gt;             Fix For: jcs-1.4-dev
&gt;
&gt;         Attachments: DiskFileCache.java, DiskFileCacheAttributes.java, DiskFileCacheFactory.java
&gt;
&gt;
&gt; It would be nice to have a file based cache in jcs where each item is stored as a single
file and the filename is based on the key. This way, several jvms can share the same cache
and the cache can be rsynced between nodes while running the application. 

-- 
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-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jcs-dev-help@jakarta.apache.org



</pre>
</div>
</content>
</entry>
<entry>
<title>[RESULT][VOTE] Merge dev lists</title>
<author><name>Rahul Akolkar &lt;rahul.akolkar@gmail.com&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200910.mbox/%3cce1f2ea80910240918w31cfc554rc333fcdf03c60420@mail.gmail.com%3e"/>
<id>urn:uuid:%3cce1f2ea80910240918w31cfc554rc333fcdf03c60420@mail-gmail-com%3e</id>
<updated>2009-10-24T16:18:07Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>
[Relaying result to all lists]

The vote to merge dev lists at Jakarta has passed with the following
binding votes cast:

5 +1s:
  Felipe Leme
  Daniel Savarese
  Vadim Gritsenko
  Rahul Akolkar
  Stephen Colebourne

2 +0s:
  Sebastian Bazley
  Rony Flatscher

2 -1s:
  Thomas Vandahl
  Torsten Curdt

I also count 4 non-binding +1s (Mark Murphy, Venkat Krishnamurthy,
Henri Yandell, Jörg Schaible) and 3 non-binding -1s (Hanson Char,
Giuseppe, Tim Cronin). Two non-binding +1s were cast by folks who
until recently were on the PMC (bayard, joehni) so perhaps not giving
their votes enough credit is getting too technical here.

We'll encourage simple conventions (as Commons was mentioned, for
example) to make filtering email, searching archives etc. as
convenient as we can on a shared list. Hope is that will alleviate to
some extent the primary concern of those who've voted against.

I will open an INFRA ticket for this merge in a week or so (after I
post another heads up note with more details, dev mailing list
conventions etc. to the lists).

Thanks to everyone who voted.

-Rahul



On Mon, Oct 19, 2009 at 4:02 PM, Rahul Akolkar &lt;rahul.akolkar@gmail.com&gt; wrote:
&gt; [Suggestion is to please reply to the general@jakarta list only]
&gt;
&gt; This is a vote to consolidate the development lists at Jakarta into
&gt; one development and one notifications list. For background including
&gt; timing, anticipated benefits and some discussion, see proposal [1]
&gt; thread.
&gt;
&gt; [ ] +1
&gt; [ ] -1
&gt;
&gt; While not required, it'd be nice if anyone voting against could
&gt; briefly state the reason(s). And you're ofcourse welcome to vote +/-0
&gt; if you really want.
&gt;
&gt; Vote will run atleast 72 hours and will close no sooner than Thursday 5 pm EST.
&gt;
&gt; TIA.
&gt; -Rahul
&gt;
&gt; [1] (long, possibly fragmented URL below)
&gt; http://mail-archives.apache.org/mod_mbox/jakarta-general/200910.mbox/%3cce1f2ea80910091443t5cad1db0na0663c416cb83a72@mail.gmail.com%3e
&gt;

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



</pre>
</div>
</content>
</entry>
<entry>
<title>[jira] Commented: (JCS-58) disc file cache</title>
<author><name>&quot;Chopin Hu (JIRA)&quot; &lt;jira@apache.org&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200910.mbox/%3c1265209454.1256323079488.JavaMail.jira@brutus%3e"/>
<id>urn:uuid:%3c1265209454-1256323079488-JavaMail-jira@brutus%3e</id>
<updated>2009-10-23T18:37:59Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>

    [ https://issues.apache.org/jira/browse/JCS-58?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&amp;focusedCommentId=12769351#action_12769351
] 

Chopin Hu commented on JCS-58:
------------------------------

Aaron,

Great.   I just got a chance to check out the release-1.3.3.5-RC, which looks the Disk File
Cache   

Now, my question is how to cache a file to the disk using a key as the file name.    Is this
a config issue?    If not, can you please provide a sample code showing how to use it?

Thank you so much.

&gt; disc file cache
&gt; ---------------
&gt;
&gt;                 Key: JCS-58
&gt;                 URL: https://issues.apache.org/jira/browse/JCS-58
&gt;             Project: JCS
&gt;          Issue Type: New Feature
&gt;    Affects Versions: jcs-1.3
&gt;            Reporter: Tore Halset
&gt;            Assignee: Aaron Smuts
&gt;             Fix For: jcs-1.4-dev
&gt;
&gt;         Attachments: DiskFileCache.java, DiskFileCacheAttributes.java, DiskFileCacheFactory.java
&gt;
&gt;
&gt; It would be nice to have a file based cache in jcs where each item is stored as a single
file and the filename is based on the key. This way, several jvms can share the same cache
and the cache can be rsynced between nodes while running the application. 

-- 
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-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jcs-dev-help@jakarta.apache.org



</pre>
</div>
</content>
</entry>
<entry>
<title>Re: [VOTE] Merge dev lists</title>
<author><name>Quasar &lt;quasaro@libero.it&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200910.mbox/%3c4ADDB328.7070602@libero.it%3e"/>
<id>urn:uuid:%3c4ADDB328-7070602@libero-it%3e</id>
<updated>2009-10-20T12:55:04Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>
-1

The reasons Rahul explained are certainly valid for developers 
subscribed to more than one dev list.
In my case, being subscribed to only JMeter dev list, I don't see 
advantages in having all prjs in the same list; on the contrary, I'll 
get more "useless" messages.

But of course this is only my opinion. Whatever decision will be taken, 
I'll be part of the dev list.

Giuseppe

Rahul Akolkar wrote:
&gt; [Suggestion is to please reply to the general@jakarta list only]
&gt;
&gt; This is a vote to consolidate the development lists at Jakarta into
&gt; one development and one notifications list. For background including
&gt; timing, anticipated benefits and some discussion, see proposal [1]
&gt; thread.
&gt;
&gt; [ ] +1
&gt; [ ] -1
&gt;
&gt; While not required, it'd be nice if anyone voting against could
&gt; briefly state the reason(s). And you're ofcourse welcome to vote +/-0
&gt; if you really want.
&gt;
&gt; Vote will run atleast 72 hours and will close no sooner than Thursday 5 pm EST.
&gt;
&gt; TIA.
&gt; -Rahul
&gt;
&gt; [1] (long, possibly fragmented URL below)
&gt; http://mail-archives.apache.org/mod_mbox/jakarta-general/200910.mbox/%3cce1f2ea80910091443t5cad1db0na0663c416cb83a72@mail.gmail.com%3e
&gt;
&gt; ---------------------------------------------------------------------
&gt; To unsubscribe, e-mail: jmeter-dev-unsubscribe@jakarta.apache.org
&gt; For additional commands, e-mail: jmeter-dev-help@jakarta.apache.org
&gt;
&gt; .
&gt;
&gt;   


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



</pre>
</div>
</content>
</entry>
<entry>
<title>Re: [VOTE] Merge dev lists</title>
<author><name>Hanson Char &lt;hanson.char@gmail.com&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200910.mbox/%3cca53c8f80910200027t6615efcfl1872ed1d14b3e657@mail.gmail.com%3e"/>
<id>urn:uuid:%3cca53c8f80910200027t6615efcfl1872ed1d14b3e657@mail-gmail-com%3e</id>
<updated>2009-10-20T07:27:16Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>
-1

Too much noise to signal ratio - not everyone is interested in every Jakarta
projects.  Notification list consolidation seems fine, but probably not dev.

On Mon, Oct 19, 2009 at 1:02 PM, Rahul Akolkar &lt;rahul.akolkar@gmail.com&gt;wrote:

&gt; [Suggestion is to please reply to the general@jakarta list only]
&gt;
&gt; This is a vote to consolidate the development lists at Jakarta into
&gt; one development and one notifications list. For background including
&gt; timing, anticipated benefits and some discussion, see proposal [1]
&gt; thread.
&gt;
&gt; [ ] +1
&gt; [ ] -1
&gt;
&gt; While not required, it'd be nice if anyone voting against could
&gt; briefly state the reason(s). And you're ofcourse welcome to vote +/-0
&gt; if you really want.
&gt;
&gt; Vote will run atleast 72 hours and will close no sooner than Thursday 5 pm
&gt; EST.
&gt;
&gt; TIA.
&gt; -Rahul
&gt;
&gt; [1] (long, possibly fragmented URL below)
&gt;
&gt; http://mail-archives.apache.org/mod_mbox/jakarta-general/200910.mbox/%3cce1f2ea80910091443t5cad1db0na0663c416cb83a72@mail.gmail.com%3e
&gt;
&gt; ---------------------------------------------------------------------
&gt; To unsubscribe, e-mail: jcs-dev-unsubscribe@jakarta.apache.org
&gt; For additional commands, e-mail: jcs-dev-help@jakarta.apache.org
&gt;
&gt;


</pre>
</div>
</content>
</entry>
<entry>
<title>[VOTE] Merge dev lists</title>
<author><name>Rahul Akolkar &lt;rahul.akolkar@gmail.com&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200910.mbox/%3cce1f2ea80910191302w30811450rdd7cbf66f9a1bb92@mail.gmail.com%3e"/>
<id>urn:uuid:%3cce1f2ea80910191302w30811450rdd7cbf66f9a1bb92@mail-gmail-com%3e</id>
<updated>2009-10-19T20:02:15Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>
[Suggestion is to please reply to the general@jakarta list only]

This is a vote to consolidate the development lists at Jakarta into
one development and one notifications list. For background including
timing, anticipated benefits and some discussion, see proposal [1]
thread.

[ ] +1
[ ] -1

While not required, it'd be nice if anyone voting against could
briefly state the reason(s). And you're ofcourse welcome to vote +/-0
if you really want.

Vote will run atleast 72 hours and will close no sooner than Thursday 5 pm EST.

TIA.
-Rahul

[1] (long, possibly fragmented URL below)
http://mail-archives.apache.org/mod_mbox/jakarta-general/200910.mbox/%3cce1f2ea80910091443t5cad1db0na0663c416cb83a72@mail.gmail.com%3e

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



</pre>
</div>
</content>
</entry>
<entry>
<title>[jira] Updated: (JCS-69) Synchronization Problem in JCSWorker</title>
<author><name>&quot;Scott Archer (JIRA)&quot; &lt;jira@apache.org&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200910.mbox/%3c170722070.1255637251513.JavaMail.jira@brutus%3e"/>
<id>urn:uuid:%3c170722070-1255637251513-JavaMail-jira@brutus%3e</id>
<updated>2009-10-15T20:07:31Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>

     [ https://issues.apache.org/jira/browse/JCS-69?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]

Scott Archer updated JCS-69:
----------------------------

    Attachment: cache.ccf
                JCSTest.java

This class reproduces the problem.

&gt; Synchronization Problem in JCSWorker
&gt; ------------------------------------
&gt;
&gt;                 Key: JCS-69
&gt;                 URL: https://issues.apache.org/jira/browse/JCS-69
&gt;             Project: JCS
&gt;          Issue Type: Bug
&gt;    Affects Versions: jcs-1.3, jcs-1.4-dev
&gt;         Environment: Linux 2.6.28-15-generic #52-Ubuntu SMP Wed Sep 9 10:48:52 UTC 2009
x86_64 GNU/Linux
&gt; java version "1.6.0_16"
&gt; Java(TM) SE Runtime Environment (build 1.6.0_16-b01)
&gt; Java HotSpot(TM) 64-Bit Server VM (build 14.2-b01, mixed mode)
&gt;            Reporter: Scott Archer
&gt;            Assignee: Aaron Smuts
&gt;         Attachments: cache.ccf, JCSTest.java
&gt;
&gt;
&gt; When using the JCSWorker threads lock indefinitely.
&gt; I believe the synchronized block in the finally block is synchronizing on and notifying
the wrong object.
&gt; Once a thread locks it never unlocks.
&gt; Class: org.apache.jcs.utils.access.JCSWorker
&gt; Method: private Object run( Serializable aKey, String aGroup, JCSWorkerHelper aHelper
) throws Exception
&gt; Bad Code (in finally block):
&gt;  synchronized ( this )
&gt;  {
&gt;      aHelper.setFinished( true );
&gt;      // Wake everyone waiting on us
&gt;      notifyAll();
&gt;  }
&gt; Suggested Fix:
&gt;  synchronized ( aHelper )
&gt;  {
&gt;      aHelper.setFinished( true );
&gt;      // Wake everyone waiting on aHelper
&gt;      aHelper.notifyAll();
&gt;  }

-- 
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-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jcs-dev-help@jakarta.apache.org



</pre>
</div>
</content>
</entry>
<entry>
<title>[jira] Updated: (JCS-69) Synchronization Problem in JCSWorker</title>
<author><name>&quot;Scott Archer (JIRA)&quot; &lt;jira@apache.org&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200910.mbox/%3c1943902282.1255635211426.JavaMail.jira@brutus%3e"/>
<id>urn:uuid:%3c1943902282-1255635211426-JavaMail-jira@brutus%3e</id>
<updated>2009-10-15T19:33:31Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>

     [ https://issues.apache.org/jira/browse/JCS-69?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]

Scott Archer updated JCS-69:
----------------------------

    Description: 
When using the JCSWorker threads lock indefinitely.
I believe the synchronized block in the finally block is synchronizing on and notifying the
wrong object.

Once a thread locks it never unlocks.


Class: org.apache.jcs.utils.access.JCSWorker
Method: private Object run( Serializable aKey, String aGroup, JCSWorkerHelper aHelper ) throws
Exception

Bad Code (in finally block):
 synchronized ( this )
 {
     aHelper.setFinished( true );
     // Wake everyone waiting on us
     notifyAll();
 }

Suggested Fix:
 synchronized ( aHelper )
 {
     aHelper.setFinished( true );
     // Wake everyone waiting on aHelper
     aHelper.notifyAll();
 }


  was:
When using the JCSWorker threads lock indefinitely.
I believe the synchronized block in the finally block is synchronizing on the wrong object.

Once a thread locks it never unlocks.


Class: org.apache.jcs.utils.access.JCSWorker
Method: private Object run( Serializable aKey, String aGroup, JCSWorkerHelper aHelper ) throws
Exception

Bad Code (in finally block):
 synchronized ( this )
 {
     aHelper.setFinished( true );
     // Wake everyone waiting on us
     notifyAll();
 }

Suggested Fix:
 synchronized ( aHelper )
 {
     aHelper.setFinished( true );
     // Wake everyone waiting on aHelper
     aHelper.notifyAll();
 }



&gt; Synchronization Problem in JCSWorker
&gt; ------------------------------------
&gt;
&gt;                 Key: JCS-69
&gt;                 URL: https://issues.apache.org/jira/browse/JCS-69
&gt;             Project: JCS
&gt;          Issue Type: Bug
&gt;    Affects Versions: jcs-1.3, jcs-1.4-dev
&gt;         Environment: Linux 2.6.28-15-generic #52-Ubuntu SMP Wed Sep 9 10:48:52 UTC 2009
x86_64 GNU/Linux
&gt; java version "1.6.0_16"
&gt; Java(TM) SE Runtime Environment (build 1.6.0_16-b01)
&gt; Java HotSpot(TM) 64-Bit Server VM (build 14.2-b01, mixed mode)
&gt;            Reporter: Scott Archer
&gt;            Assignee: Aaron Smuts
&gt;
&gt; When using the JCSWorker threads lock indefinitely.
&gt; I believe the synchronized block in the finally block is synchronizing on and notifying
the wrong object.
&gt; Once a thread locks it never unlocks.
&gt; Class: org.apache.jcs.utils.access.JCSWorker
&gt; Method: private Object run( Serializable aKey, String aGroup, JCSWorkerHelper aHelper
) throws Exception
&gt; Bad Code (in finally block):
&gt;  synchronized ( this )
&gt;  {
&gt;      aHelper.setFinished( true );
&gt;      // Wake everyone waiting on us
&gt;      notifyAll();
&gt;  }
&gt; Suggested Fix:
&gt;  synchronized ( aHelper )
&gt;  {
&gt;      aHelper.setFinished( true );
&gt;      // Wake everyone waiting on aHelper
&gt;      aHelper.notifyAll();
&gt;  }

-- 
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-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jcs-dev-help@jakarta.apache.org



</pre>
</div>
</content>
</entry>
<entry>
<title>[jira] Created: (JCS-69) Synchronization Problem in JCSWorker</title>
<author><name>&quot;Scott Archer (JIRA)&quot; &lt;jira@apache.org&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200910.mbox/%3c2077477338.1255633771899.JavaMail.jira@brutus%3e"/>
<id>urn:uuid:%3c2077477338-1255633771899-JavaMail-jira@brutus%3e</id>
<updated>2009-10-15T19:09:31Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>
Synchronization Problem in JCSWorker
------------------------------------

                 Key: JCS-69
                 URL: https://issues.apache.org/jira/browse/JCS-69
             Project: JCS
          Issue Type: Bug
    Affects Versions: jcs-1.3, jcs-1.4-dev
         Environment: Linux 2.6.28-15-generic #52-Ubuntu SMP Wed Sep 9 10:48:52 UTC 2009 x86_64
GNU/Linux
java version "1.6.0_16"
Java(TM) SE Runtime Environment (build 1.6.0_16-b01)
Java HotSpot(TM) 64-Bit Server VM (build 14.2-b01, mixed mode)

            Reporter: Scott Archer
            Assignee: Aaron Smuts


When using the JCSWorker threads lock indefinitely.
I believe the synchronized block in the finally block is synchronizing on the wrong object.

Once a thread locks it never unlocks.


Class: org.apache.jcs.utils.access.JCSWorker
Method: private Object run( Serializable aKey, String aGroup, JCSWorkerHelper aHelper ) throws
Exception

Bad Code (in finally block):
 synchronized ( this )
 {
     aHelper.setFinished( true );
     // Wake everyone waiting on us
     notifyAll();
 }

Suggested Fix:
 synchronized ( aHelper )
 {
     aHelper.setFinished( true );
     // Wake everyone waiting on aHelper
     aHelper.notifyAll();
 }


-- 
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-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jcs-dev-help@jakarta.apache.org



</pre>
</div>
</content>
</entry>
<entry>
<title>[jira] Commented: (JCS-58) disc file cache</title>
<author><name>&quot;Aaron Smuts (JIRA)&quot; &lt;jira@apache.org&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200910.mbox/%3c30350512.1255551151449.JavaMail.jira@brutus%3e"/>
<id>urn:uuid:%3c30350512-1255551151449-JavaMail-jira@brutus%3e</id>
<updated>2009-10-14T20:12:31Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>

    [ https://issues.apache.org/jira/browse/JCS-58?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&amp;focusedCommentId=12765724#action_12765724
] 

Aaron Smuts commented on JCS-58:
--------------------------------

Use the latest temp build.  It's production ready.  I'm using it in prod.  You don't need
a formal release build.  1.3 is way out of date.  We'll issue a new release in a couple of
months, but there is no need to wait.

&gt; disc file cache
&gt; ---------------
&gt;
&gt;                 Key: JCS-58
&gt;                 URL: https://issues.apache.org/jira/browse/JCS-58
&gt;             Project: JCS
&gt;          Issue Type: New Feature
&gt;    Affects Versions: jcs-1.3
&gt;            Reporter: Tore Halset
&gt;            Assignee: Aaron Smuts
&gt;             Fix For: jcs-1.4-dev
&gt;
&gt;         Attachments: DiskFileCache.java, DiskFileCacheAttributes.java, DiskFileCacheFactory.java
&gt;
&gt;
&gt; It would be nice to have a file based cache in jcs where each item is stored as a single
file and the filename is based on the key. This way, several jvms can share the same cache
and the cache can be rsynced between nodes while running the application. 

-- 
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-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jcs-dev-help@jakarta.apache.org



</pre>
</div>
</content>
</entry>
<entry>
<title>[PROPOSAL] One development list</title>
<author><name>Rahul Akolkar &lt;rahul.akolkar@gmail.com&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200910.mbox/%3cce1f2ea80910091443t5cad1db0na0663c416cb83a72@mail.gmail.com%3e"/>
<id>urn:uuid:%3cce1f2ea80910091443t5cad1db0na0663c416cb83a72@mail-gmail-com%3e</id>
<updated>2009-10-09T21:43:43Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>
[Out of necessity, this is heavily cross-posted. Suggestion is to send
any replies to the general@jakarta list only to keep any discussion in
one place.]

We currently have 8 active development lists at Jakarta, each devoted
to a subproject. I've been subscribed to all for a while and based on
my observations and the overall benefits of doing so, I think its time
to consolidate them into a single development list at Jakarta.

Motivations (not in any order):
 * Flattens and simplifies oversight - Not much else to be said on that.
 * Communication - Subprojects can often have various touch points.
So, Rony's surprise today at the BSF taglib being retired is one
example. Lets have all dev discussions on one list.
 * Cross-pollination - Most subprojects are at the point where it
certainly wouldn't hurt to have the active folks from all of Jakarta
around for dev discussions, votes etc.
 * Manageable overhead - More on this later, but we have a number of
usual suspects showing up on many of the dev lists, they'd barely
notice a difference. Others can manage, IMO/hopefully.

Operationally:
 * The combined list traffic will obviously be more than any one of
the separate lists. However, development tends to be in spurts on
these lists and the probabilistic chances of more than a couple of
subproject spurts happening at the same time seems quite low. Overall,
combined traffic is not at all overpowering IMO.
 * The proposal will include closing current dev lists and adding all
subscribers to the one new dev list. We'll post a heads up on these
lists before that. Throw in site-cvs@ as well for good measure.
 * We could repurpose general@ as the one dev list, but OTOH, seems
worthwhile to maintain the dev / general separation.
 * No changes proposed to the user lists.

Thoughts?

Lets say a little over a week (10 days, which should give us two
weekends) for initial feedback and opinions please.

-Rahul

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



</pre>
</div>
</content>
</entry>
<entry>
<title>[jira] Commented: (JCS-58) disc file cache</title>
<author><name>&quot;Chopin Hu (JIRA)&quot; &lt;jira@apache.org&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200910.mbox/%3c542241048.1255100191400.JavaMail.jira@brutus%3e"/>
<id>urn:uuid:%3c542241048-1255100191400-JavaMail-jira@brutus%3e</id>
<updated>2009-10-09T14:56:31Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>

    [ https://issues.apache.org/jira/browse/JCS-58?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&amp;focusedCommentId=12764043#action_12764043
] 

Chopin Hu commented on JCS-58:
------------------------------

That is exactly what I am looking for.   But is the release 1.4 available yet?   I don't care
to use JDK 1.5+.   that's not an issue to me and to my project.

Currently, I am evaluating JCS 1.3.   If I can put this feature (one key, and use the key
as a filename for cache) into function with the version 1.3, it is great.   If not, then where
to find the version JCS 1.4?

By the way, the files I am going to cache are binary data.   I hope it will work out.

Thanks a lot.

&gt; disc file cache
&gt; ---------------
&gt;
&gt;                 Key: JCS-58
&gt;                 URL: https://issues.apache.org/jira/browse/JCS-58
&gt;             Project: JCS
&gt;          Issue Type: New Feature
&gt;    Affects Versions: jcs-1.3
&gt;            Reporter: Tore Halset
&gt;            Assignee: Aaron Smuts
&gt;             Fix For: jcs-1.4-dev
&gt;
&gt;         Attachments: DiskFileCache.java, DiskFileCacheAttributes.java, DiskFileCacheFactory.java
&gt;
&gt;
&gt; It would be nice to have a file based cache in jcs where each item is stored as a single
file and the filename is based on the key. This way, several jvms can share the same cache
and the cache can be rsynced between nodes while running the application. 

-- 
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-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jcs-dev-help@jakarta.apache.org



</pre>
</div>
</content>
</entry>
<entry>
<title>[jira] Updated: (JCS-48) JDBC Disk Auxiliary Cache Configuration -&gt; support JNDI datasource in Appservers</title>
<author><name>&quot;Vishal Sinha (JIRA)&quot; &lt;jira@apache.org&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200909.mbox/%3c524329136.1253132637525.JavaMail.jira@brutus%3e"/>
<id>urn:uuid:%3c524329136-1253132637525-JavaMail-jira@brutus%3e</id>
<updated>2009-09-16T20:23:57Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>

     [ https://issues.apache.org/jira/browse/JCS-48?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]

Vishal Sinha updated JCS-48:
----------------------------

    Attachment: JCSDataSourceHelper.java
                JDBCDiskCache.java

I have added one class JCSDataSourceHelper and modified the existing class JDBCDiskCache.
I have tried to keep it as low risk, and jcs code will behave as it used to do if we revert
back to old configuration in cache.ccf. 

For the datasource to work, the only change required in cache.ccf is: 
jcs.auxiliary.JDBC.attributes.url=jdbc/jcsDataSource
that is, specify datasource jndi instead of DB url 

But I do have the dependency in the code that datasource jndi name should start with "jdbc/"
just to identify thats its datasource jndi name and not the DB url.

Regards
Vishal Sinha


&gt; JDBC Disk Auxiliary Cache Configuration -&gt; support JNDI datasource in Appservers
&gt; --------------------------------------------------------------------------------
&gt;
&gt;                 Key: JCS-48
&gt;                 URL: https://issues.apache.org/jira/browse/JCS-48
&gt;             Project: JCS
&gt;          Issue Type: Improvement
&gt;          Components: JDBC Disk Cache
&gt;    Affects Versions: jcs-1.4-dev
&gt;            Reporter: hanasaki jiji
&gt;            Assignee: Aaron Smuts
&gt;            Priority: Minor
&gt;         Attachments: JCSDataSourceHelper.java, JDBCDiskCache.java
&gt;
&gt;
&gt; JDBC Disk Auxiliary Cache Configuration -&gt; support JNDI datasource in Appservers
&gt; http://jakarta.apache.org/jcs/JDBCDiskCacheProperties.html
&gt; Allow property "url" to be used (or add URI) so that tomcat and other appservers providing
JNDI datasources can be used to specific the table and id/pass and connection information.
 In this case several other properties would be ignored: tableName, userName, password.

-- 
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-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jcs-dev-help@jakarta.apache.org



</pre>
</div>
</content>
</entry>
<entry>
<title>Re: JCS remote cache client shutdown behaviour</title>
<author><name>Niall Gallagher &lt;niall@switchfire.com&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200909.mbox/%3c1252511266.16914.181.camel@niall-dell%3e"/>
<id>urn:uuid:%3c1252511266-16914-181-camel@niall-dell%3e</id>
<updated>2009-09-09T15:47:46Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>
Hi Aaron,

Good to know, thanks for the info.

Never mind- since this is the designed behaviour (which works in normal
network environments) then this isn't really a problem with JCS, the
root problem is our insane network architecture. I was just hoping there
might be some trivial tweak we could make in JCS to work around our
network issue. Anyway we will be migrating to a new data centre soon,
and in the meantime we'll be careful.

Thanks,
Niall

-----Original Message-----
From: Aaron Smuts &lt;asmuts@yahoo.com&gt;
Reply-to: "JCS Developers List" &lt;jcs-dev@jakarta.apache.org&gt;
To: JCS Developers List &lt;jcs-dev@jakarta.apache.org&gt;
Subject: Re: JCS remote cache client shutdown behaviour
Date: Wed, 9 Sep 2009 07:30:15 -0700 (PDT)


I don't think that shutdown will properly kill the event queues on the server side.  The server
will queue and retry 10 times before killing the queue and marking it non functional.  If
you have a large number of items and lots of clients that keep going down, then you could
see a memory spike.  

We should look into the client shutdown process.  

Aaron

--- On Mon, 9/7/09, Niall Gallagher &lt;niall@switchfire.com&gt; wrote:

&gt; From: Niall Gallagher &lt;niall@switchfire.com&gt;
&gt; Subject: JCS remote cache client shutdown behaviour
&gt; To: "JCS Developers List" &lt;jcs-dev@jakarta.apache.org&gt;
&gt; Date: Monday, September 7, 2009, 7:50 AM
&gt; Hi,
&gt; 
&gt; I'm wondering if anyone can explain the sequence of steps
&gt; the JCS client
&gt; code is supposed to follow when
&gt; CompositeCacheManager.shutDown() is
&gt; called client-side? We are intermittently seeing high
&gt; memory usage in
&gt; our JCS remote server, which appears to be caused by large
&gt; backlogs of
&gt; event objects queued for delivery to client machines which
&gt; have been
&gt; shut down, even though we are shutting down our client
&gt; machines
&gt; gracefully using the method above. This is certainly
&gt; aggravated by our
&gt; network's architecture, but I'm not sure if the root cause
&gt; might be a
&gt; bug in JCS or I'm not understanding what should happen
&gt; properly.
&gt; 
&gt; When we call CompositeCacheManager.shutDown() on a client
&gt; machine, from
&gt; our client-side logs it appears that the dispose() method
&gt; in this object
&gt; is getting called correctly for each cache region:
&gt; http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/RemoteCacheListener.java?view=markup
&gt; 
&gt; However that method appears to just unexport the RMI
&gt; RemoteCacheListener
&gt; object for each region client-side; basically terminating
&gt; the
&gt; client-side end of the event delivery connection. Before
&gt; disconnecting
&gt; though, shouldn't this method notify the server that the
&gt; client is about
&gt; to disconnect?
&gt; 
&gt; Subsequently we often see errors like this in the remote
&gt; server log:
&gt; 
&gt; 
&gt; 07-Sep 13:52:13,347 INFO  [jcs.engine.CacheEventQueue]
&gt; Error while running event from Queue: RemoveEvent for [GAN:
&gt; groupId=[groupId=&lt;region name&gt;, defaultGroup],
&gt; attrName=&lt;cache key&gt;]. Retrying...
&gt; 07-Sep 13:52:13,747 WARN  [jcs.engine.CacheEventQueue]
&gt; java.rmi.ConnectException: Connection refused to host:
&gt; &lt;client machine ip address&gt;; nested exception is:
&gt;         java.net.ConnectException:
&gt; Connection refused
&gt; 07-Sep 13:52:13,748 WARN  [jcs.engine.CacheEventQueue]
&gt; Error while running event from Queue: RemoveEvent for [GAN:
&gt; groupId=[groupId=&lt;region name&gt;, defaultGroup],
&gt; attrName=&lt;cache key&gt;]. Dropping Event and marking
&gt; Event Queue as non-functional.
&gt; 
&gt; 
&gt; ...this implies the remote server continues to try to
&gt; deliver events to
&gt; the JCS client which disconnected, as if the client didn't
&gt; de-register
&gt; itself before disconnecting.
&gt; 
&gt; Perhaps I've missed something in the code.
&gt; 
&gt; I see that the RemoteCacheServer API (to which clients
&gt; connect) does in
&gt; fact have a server-side dispose() method which (on initial
&gt; investigation) would "de-register" the client from the
&gt; server's list of
&gt; event listeners. Could it be that JCS clients are simply
&gt; not calling
&gt; this method?..
&gt; http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/server/RemoteCacheServer.java?view=markup
&gt; 
&gt; 
&gt; This issue is a problem for us depending on which network
&gt; subnet the
&gt; client machine is in. Basically our network is divided into
&gt; 2 subnets,
&gt; with a fairly rubbish (or overly-strict) router/firewall
&gt; between the two
&gt; subnets. This router does not relay networking errors (ICMP
&gt; error
&gt; messages) between the two subnets. When a machine in one
&gt; subnet goes
&gt; offline and a machine in the other subnet tries to connect
&gt; to it, our
&gt; router does not notify the source machine that the target
&gt; machine is
&gt; offline, and so the source machine waits indefinitely (i.e.
&gt; with a
&gt; socket in the open wait state) for a response from the
&gt; target machine.
&gt; On the other hand when both machines are in the same
&gt; subnet, the source
&gt; machine gets a "host not reachable" exception immediately
&gt; when a target
&gt; machine is offline.
&gt; 
&gt; Anyway... the problem is when we shut down a client machine
&gt; in a
&gt; different subnet, the JCS remote server builds up a large
&gt; backlog of
&gt; cache event objects, presumably trying to connect to a
&gt; disconnected
&gt; client, and eventually runs out of memory. We determine
&gt; this using the
&gt; JDK's jmap command - we find a large number of PutEvent and
&gt; RemoveEvent
&gt; objects in the remote server's memory. We don't have the
&gt; issue when both
&gt; machines are in the same subnet, but I wonder if that's
&gt; because JCS
&gt; remote server is relying on the networking errors, and is
&gt; de-registering
&gt; clients automatically after a certain number of failed
&gt; attempts to
&gt; connect to the client. i.e. perhaps clients are not
&gt; de-registering
&gt; themselves gracefully from the remote server in the first
&gt; place.
&gt; 
&gt; Does anyone have any experience with this- anyone regularly
&gt; see "Error
&gt; while running event from Queue" in the remote server logs?
&gt; I realise our
&gt; network setup is partly to blame here, but perhaps the root
&gt; cause is
&gt; that client's are not de-registering properly.
&gt; 
&gt; Many thanks in advance,
&gt; 
&gt; Niall
&gt; 

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




</pre>
</div>
</content>
</entry>
<entry>
<title>Re: Any operation in JCS cache similar to ConcurrentHashMap.putIfAbsent() ?</title>
<author><name>Aaron Smuts &lt;asmuts@yahoo.com&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200909.mbox/%3c333687.96413.qm@web38708.mail.mud.yahoo.com%3e"/>
<id>urn:uuid:%3c333687-96413-qm@web38708-mail-mud-yahoo-com%3e</id>
<updated>2009-09-09T14:31:22Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>
Nope.  There is a putSafe method, but it won't do what you want.

Are you worried about redundant puts?  

--- On Tue, 9/8/09, Marvin-Chin-Pang.Leung@ubs.com &lt;Marvin-Chin-Pang.Leung@ubs.com&gt;
wrote:

&gt; From: Marvin-Chin-Pang.Leung@ubs.com &lt;Marvin-Chin-Pang.Leung@ubs.com&gt;
&gt; Subject: Any operation in JCS cache similar to ConcurrentHashMap.putIfAbsent() ?
&gt; To: jcs-dev@jakarta.apache.org
&gt; Date: Tuesday, September 8, 2009, 8:30 PM
&gt; 
&gt; 
&gt; 
&gt;  
&gt;  
&gt; Any operation in JCS cache similar to
&gt; ConcurrentHashMap.putIfAbsent() ?
&gt; 
&gt;  
&gt; 
&gt; 
&gt; Hi JCS Dev, 
&gt; 
&gt; 
&gt;   I am trying to use
&gt; JCS cache in concurrent environment. Wonder if there any
&gt; function in JCS cache similar to that of putIfAbsent() in
&gt; ConcurrentHashMap? 
&gt; 
&gt; Rdgs,
&gt; 
&gt; 
&gt; Marvin
&gt; 
&gt; 
&gt;  
&gt; 
&gt; -----Inline Attachment Follows-----
&gt; 
&gt; Visit our website at http://www.ubs.com
&gt; 
&gt; This message contains confidential information and is
&gt; intended only 
&gt; for the individual named.  If you are not the named
&gt; addressee you 
&gt; should not disseminate, distribute or copy this
&gt; e-mail.  Please 
&gt; notify the sender immediately by e-mail if you have
&gt; received this 
&gt; e-mail by mistake and delete this e-mail from your system.
&gt;     
&gt; E-mails are not encrypted and cannot be guaranteed to be
&gt; secure or 
&gt; error-free as information could be intercepted, corrupted,
&gt; lost, 
&gt; destroyed, arrive late or incomplete, or contain
&gt; viruses.  The sender 
&gt; therefore does not accept liability for any errors or
&gt; omissions in the 
&gt; contents of this message which arise as a result of e-mail
&gt; transmission.  
&gt; If verification is required please request a hard-copy
&gt; version.  This 
&gt; message is provided for informational purposes and should
&gt; not be 
&gt; construed as a solicitation or offer to buy or sell any
&gt; securities 
&gt; or related financial instruments.
&gt; 
&gt;  
&gt; UBS reserves the right to retain all messages. Messages are
&gt; protected
&gt; and accessed only in legally justified cases.
&gt; 
&gt; ---------------------------------------------------------------------
&gt; To unsubscribe, e-mail: jcs-dev-unsubscribe@jakarta.apache.org
&gt; For additional commands, e-mail: jcs-dev-help@jakarta.apache.org

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



</pre>
</div>
</content>
</entry>
<entry>
<title>Re: JCS remote cache client shutdown behaviour</title>
<author><name>Aaron Smuts &lt;asmuts@yahoo.com&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200909.mbox/%3c777173.83400.qm@web38706.mail.mud.yahoo.com%3e"/>
<id>urn:uuid:%3c777173-83400-qm@web38706-mail-mud-yahoo-com%3e</id>
<updated>2009-09-09T14:30:15Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>
I don't think that shutdown will properly kill the event queues on the server side.  The server
will queue and retry 10 times before killing the queue and marking it non functional.  If
you have a large number of items and lots of clients that keep going down, then you could
see a memory spike.  

We should look into the client shutdown process.  

Aaron

--- On Mon, 9/7/09, Niall Gallagher &lt;niall@switchfire.com&gt; wrote:

&gt; From: Niall Gallagher &lt;niall@switchfire.com&gt;
&gt; Subject: JCS remote cache client shutdown behaviour
&gt; To: "JCS Developers List" &lt;jcs-dev@jakarta.apache.org&gt;
&gt; Date: Monday, September 7, 2009, 7:50 AM
&gt; Hi,
&gt; 
&gt; I'm wondering if anyone can explain the sequence of steps
&gt; the JCS client
&gt; code is supposed to follow when
&gt; CompositeCacheManager.shutDown() is
&gt; called client-side? We are intermittently seeing high
&gt; memory usage in
&gt; our JCS remote server, which appears to be caused by large
&gt; backlogs of
&gt; event objects queued for delivery to client machines which
&gt; have been
&gt; shut down, even though we are shutting down our client
&gt; machines
&gt; gracefully using the method above. This is certainly
&gt; aggravated by our
&gt; network's architecture, but I'm not sure if the root cause
&gt; might be a
&gt; bug in JCS or I'm not understanding what should happen
&gt; properly.
&gt; 
&gt; When we call CompositeCacheManager.shutDown() on a client
&gt; machine, from
&gt; our client-side logs it appears that the dispose() method
&gt; in this object
&gt; is getting called correctly for each cache region:
&gt; http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/RemoteCacheListener.java?view=markup
&gt; 
&gt; However that method appears to just unexport the RMI
&gt; RemoteCacheListener
&gt; object for each region client-side; basically terminating
&gt; the
&gt; client-side end of the event delivery connection. Before
&gt; disconnecting
&gt; though, shouldn't this method notify the server that the
&gt; client is about
&gt; to disconnect?
&gt; 
&gt; Subsequently we often see errors like this in the remote
&gt; server log:
&gt; 
&gt; 
&gt; 07-Sep 13:52:13,347 INFO  [jcs.engine.CacheEventQueue]
&gt; Error while running event from Queue: RemoveEvent for [GAN:
&gt; groupId=[groupId=&lt;region name&gt;, defaultGroup],
&gt; attrName=&lt;cache key&gt;]. Retrying...
&gt; 07-Sep 13:52:13,747 WARN  [jcs.engine.CacheEventQueue]
&gt; java.rmi.ConnectException: Connection refused to host:
&gt; &lt;client machine ip address&gt;; nested exception is:
&gt;         java.net.ConnectException:
&gt; Connection refused
&gt; 07-Sep 13:52:13,748 WARN  [jcs.engine.CacheEventQueue]
&gt; Error while running event from Queue: RemoveEvent for [GAN:
&gt; groupId=[groupId=&lt;region name&gt;, defaultGroup],
&gt; attrName=&lt;cache key&gt;]. Dropping Event and marking
&gt; Event Queue as non-functional.
&gt; 
&gt; 
&gt; ...this implies the remote server continues to try to
&gt; deliver events to
&gt; the JCS client which disconnected, as if the client didn't
&gt; de-register
&gt; itself before disconnecting.
&gt; 
&gt; Perhaps I've missed something in the code.
&gt; 
&gt; I see that the RemoteCacheServer API (to which clients
&gt; connect) does in
&gt; fact have a server-side dispose() method which (on initial
&gt; investigation) would "de-register" the client from the
&gt; server's list of
&gt; event listeners. Could it be that JCS clients are simply
&gt; not calling
&gt; this method?..
&gt; http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/server/RemoteCacheServer.java?view=markup
&gt; 
&gt; 
&gt; This issue is a problem for us depending on which network
&gt; subnet the
&gt; client machine is in. Basically our network is divided into
&gt; 2 subnets,
&gt; with a fairly rubbish (or overly-strict) router/firewall
&gt; between the two
&gt; subnets. This router does not relay networking errors (ICMP
&gt; error
&gt; messages) between the two subnets. When a machine in one
&gt; subnet goes
&gt; offline and a machine in the other subnet tries to connect
&gt; to it, our
&gt; router does not notify the source machine that the target
&gt; machine is
&gt; offline, and so the source machine waits indefinitely (i.e.
&gt; with a
&gt; socket in the open wait state) for a response from the
&gt; target machine.
&gt; On the other hand when both machines are in the same
&gt; subnet, the source
&gt; machine gets a "host not reachable" exception immediately
&gt; when a target
&gt; machine is offline.
&gt; 
&gt; Anyway... the problem is when we shut down a client machine
&gt; in a
&gt; different subnet, the JCS remote server builds up a large
&gt; backlog of
&gt; cache event objects, presumably trying to connect to a
&gt; disconnected
&gt; client, and eventually runs out of memory. We determine
&gt; this using the
&gt; JDK's jmap command - we find a large number of PutEvent and
&gt; RemoveEvent
&gt; objects in the remote server's memory. We don't have the
&gt; issue when both
&gt; machines are in the same subnet, but I wonder if that's
&gt; because JCS
&gt; remote server is relying on the networking errors, and is
&gt; de-registering
&gt; clients automatically after a certain number of failed
&gt; attempts to
&gt; connect to the client. i.e. perhaps clients are not
&gt; de-registering
&gt; themselves gracefully from the remote server in the first
&gt; place.
&gt; 
&gt; Does anyone have any experience with this- anyone regularly
&gt; see "Error
&gt; while running event from Queue" in the remote server logs?
&gt; I realise our
&gt; network setup is partly to blame here, but perhaps the root
&gt; cause is
&gt; that client's are not de-registering properly.
&gt; 
&gt; Many thanks in advance,
&gt; 
&gt; Niall
&gt; 

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



</pre>
</div>
</content>
</entry>
<entry>
<title>Any operation in JCS cache similar to ConcurrentHashMap.putIfAbsent() ?</title>
<author><name>&lt;Marvin-Chin-Pang.Leung@ubs.com&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200909.mbox/%3c337A0A67307F4F4A86416CA7162FF94F87BF4D@NHKGC101PEX1.ubsw.net%3e"/>
<id>urn:uuid:%3c337A0A67307F4F4A86416CA7162FF94F87BF4D@NHKGC101PEX1-ubsw-net%3e</id>
<updated>2009-09-09T03:30:38Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>
Hi JCS Dev, 

  I am trying to use JCS cache in concurrent environment. Wonder if
there any function in JCS cache similar to that of putIfAbsent() in
ConcurrentHashMap? 

Rdgs,
Marvin


</pre>
</div>
</content>
</entry>
<entry>
<title>JCS remote cache client shutdown behaviour</title>
<author><name>Niall Gallagher &lt;niall@switchfire.com&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200909.mbox/%3c1252335019.21970.108.camel@niall-dell%3e"/>
<id>urn:uuid:%3c1252335019-21970-108-camel@niall-dell%3e</id>
<updated>2009-09-07T14:50:19Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>
Hi,

I'm wondering if anyone can explain the sequence of steps the JCS client
code is supposed to follow when CompositeCacheManager.shutDown() is
called client-side? We are intermittently seeing high memory usage in
our JCS remote server, which appears to be caused by large backlogs of
event objects queued for delivery to client machines which have been
shut down, even though we are shutting down our client machines
gracefully using the method above. This is certainly aggravated by our
network's architecture, but I'm not sure if the root cause might be a
bug in JCS or I'm not understanding what should happen properly.

When we call CompositeCacheManager.shutDown() on a client machine, from
our client-side logs it appears that the dispose() method in this object
is getting called correctly for each cache region:
http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/RemoteCacheListener.java?view=markup

However that method appears to just unexport the RMI RemoteCacheListener
object for each region client-side; basically terminating the
client-side end of the event delivery connection. Before disconnecting
though, shouldn't this method notify the server that the client is about
to disconnect?

Subsequently we often see errors like this in the remote server log:


07-Sep 13:52:13,347 INFO  [jcs.engine.CacheEventQueue] Error while running event from Queue:
RemoveEvent for [GAN: groupId=[groupId=&lt;region name&gt;, defaultGroup], attrName=&lt;cache
key&gt;]. Retrying...
07-Sep 13:52:13,747 WARN  [jcs.engine.CacheEventQueue] java.rmi.ConnectException: Connection
refused to host: &lt;client machine ip address&gt;; nested exception is:
        java.net.ConnectException: Connection refused
07-Sep 13:52:13,748 WARN  [jcs.engine.CacheEventQueue] Error while running event from Queue:
RemoveEvent for [GAN: groupId=[groupId=&lt;region name&gt;, defaultGroup], attrName=&lt;cache
key&gt;]. Dropping Event and marking Event Queue as non-functional.


...this implies the remote server continues to try to deliver events to
the JCS client which disconnected, as if the client didn't de-register
itself before disconnecting.

Perhaps I've missed something in the code.

I see that the RemoteCacheServer API (to which clients connect) does in
fact have a server-side dispose() method which (on initial
investigation) would "de-register" the client from the server's list of
event listeners. Could it be that JCS clients are simply not calling
this method?..
http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/server/RemoteCacheServer.java?view=markup


This issue is a problem for us depending on which network subnet the
client machine is in. Basically our network is divided into 2 subnets,
with a fairly rubbish (or overly-strict) router/firewall between the two
subnets. This router does not relay networking errors (ICMP error
messages) between the two subnets. When a machine in one subnet goes
offline and a machine in the other subnet tries to connect to it, our
router does not notify the source machine that the target machine is
offline, and so the source machine waits indefinitely (i.e. with a
socket in the open wait state) for a response from the target machine.
On the other hand when both machines are in the same subnet, the source
machine gets a "host not reachable" exception immediately when a target
machine is offline.

Anyway... the problem is when we shut down a client machine in a
different subnet, the JCS remote server builds up a large backlog of
cache event objects, presumably trying to connect to a disconnected
client, and eventually runs out of memory. We determine this using the
JDK's jmap command - we find a large number of PutEvent and RemoveEvent
objects in the remote server's memory. We don't have the issue when both
machines are in the same subnet, but I wonder if that's because JCS
remote server is relying on the networking errors, and is de-registering
clients automatically after a certain number of failed attempts to
connect to the client. i.e. perhaps clients are not de-registering
themselves gracefully from the remote server in the first place.

Does anyone have any experience with this- anyone regularly see "Error
while running event from Queue" in the remote server logs? I realise our
network setup is partly to blame here, but perhaps the root cause is
that client's are not de-registering properly.

Many thanks in advance,

Niall


</pre>
</div>
</content>
</entry>
<entry>
<title>[jira] Commented: (JCS-68) Admin.jsp on remote cache server does not broadcast removes - patch</title>
<author><name>&quot;Aaron Smuts (JIRA)&quot; &lt;jira@apache.org&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200909.mbox/%3c698060432.1251915032735.JavaMail.jira@brutus%3e"/>
<id>urn:uuid:%3c698060432-1251915032735-JavaMail-jira@brutus%3e</id>
<updated>2009-09-02T18:10:32Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>

    [ https://issues.apache.org/jira/browse/JCS-68?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&amp;focusedCommentId=12750574#action_12750574
] 

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

Yes.  We can restrict the constructor (if needed) and not the class.

&gt; Admin.jsp on remote cache server does not broadcast removes - patch
&gt; -------------------------------------------------------------------
&gt;
&gt;                 Key: JCS-68
&gt;                 URL: https://issues.apache.org/jira/browse/JCS-68
&gt;             Project: JCS
&gt;          Issue Type: Bug
&gt;          Components: RMI Remote Cache
&gt;    Affects Versions: jcs-1.3, jcs-1.4-dev
&gt;         Environment: All
&gt;            Reporter: Niall Gallagher
&gt;            Assignee: Aaron Smuts
&gt;            Priority: Minor
&gt;   Original Estimate: 0.5h
&gt;  Remaining Estimate: 0.5h
&gt;
&gt; 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.
&gt; 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.
&gt; 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.
&gt; 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.
&gt; 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.
&gt; The fix involves replacing 3 methods in org.apache.jcs.admin.JCSAdminBean as follows:
&gt;     /**
&gt;      * Clears all regions in the cache.
&gt;      * &lt;p/&gt;
&gt;      * If this class is running within a remote cache server, clears all regions via
the &lt;code&gt;RemoteCacheServer&lt;/code&gt;
&gt;      * API, so that removes will be broadcast to client machines. Otherwise clears all
regions in the cache directly via
&gt;      * the usual cache API.
&gt;      */
&gt;     public void clearAllRegions() throws IOException {
&gt;         if (RemoteCacheServerFactory.getRemoteCacheServer() == null) {
&gt;             // Not running in a remote cache server.
&gt;             // Remove objects from the cache directly, as no need to broadcast removes
to client machines...
&gt;             String[] names = cacheHub.getCacheNames();
&gt;             for (int i = 0; i &lt; names.length; i++) {
&gt;                 cacheHub.getCache(names[i]).removeAll();
&gt;             }
&gt;         }
&gt;         else {
&gt;             // Running in a remote cache server.
&gt;             // Remove objects via the RemoteCacheServer API, so that removes will be
broadcast to client machines...
&gt;             try {
&gt;                 String[] cacheNames = CompositeCacheManager.getInstance().getCacheNames();
&gt;                 // Call remoteCacheServer.removeAll(String) for each cacheName...
&gt;                 // Note: We must do this using reflection to bypass its package-private
access...
&gt;                 Object remoteCacheServerObject = RemoteCacheServerFactory.getRemoteCacheServer();
&gt;                 Method removeAllMethod = remoteCacheServerObject.getClass().getMethod("removeAll",
new Class[]{String.class});
&gt;                 boolean previouslyAccessibility = removeAllMethod.isAccessible();
&gt;                 removeAllMethod.setAccessible(true);
&gt;                 for (int i = 0; i &lt; cacheNames.length; i++) {
&gt;                     String cacheName = cacheNames[i];
&gt;                     removeAllMethod.invoke(remoteCacheServerObject, new Object[]{cacheName});
&gt;                 }
&gt;                 removeAllMethod.setAccessible(previouslyAccessibility);
&gt;             }
&gt;             catch (Exception e) {
&gt;                 throw new IllegalStateException("Failed to remove all elements from all
cache regions: " + e, e);
&gt;             }
&gt;         }
&gt;     }
&gt;     /**
&gt;      * Clears a particular cache region.
&gt;      * &lt;p/&gt;
&gt;      * If this class is running within a remote cache server, clears the region via the
&lt;code&gt;RemoteCacheServer&lt;/code&gt;
&gt;      * API, so that removes will be broadcast to client machines. Otherwise clears the
region directly via the usual
&gt;      * cache API.
&gt;      */
&gt;     public void clearRegion(String cacheName) throws IOException {
&gt;         if (cacheName == null) {
&gt;             throw new IllegalArgumentException("The cache name specified was null.");
&gt;         }
&gt;         if (RemoteCacheServerFactory.getRemoteCacheServer() == null) {
&gt;             // Not running in a remote cache server.
&gt;             // Remove objects from the cache directly, as no need to broadcast removes
to client machines...
&gt;             cacheHub.getCache(cacheName).removeAll();
&gt;         }
&gt;         else {
&gt;             // Running in a remote cache server.
&gt;             // Remove objects via the RemoteCacheServer API, so that removes will be
broadcast to client machines...
&gt;             try {
&gt;                 // Call remoteCacheServer.removeAll(String)...
&gt;                 // Note: We must do this using reflection to bypass its package-private
access...
&gt;                 Object remoteCacheServerObject = RemoteCacheServerFactory.getRemoteCacheServer();
&gt;                 Method removeAllMethod = remoteCacheServerObject.getClass().getMethod("removeAll",
new Class[]{String.class});
&gt;                 boolean previouslyAccessibility = removeAllMethod.isAccessible();
&gt;                 removeAllMethod.setAccessible(true);
&gt;                 removeAllMethod.invoke(remoteCacheServerObject, new Object[]{cacheName});
&gt;                 removeAllMethod.setAccessible(previouslyAccessibility);
&gt;             }
&gt;             catch (Exception e) {
&gt;                 throw new IllegalStateException("Failed to remove all elements from cache
region [" + cacheName + "]: " + e, e);
&gt;             }
&gt;         }
&gt;     }
&gt;     /**
&gt;      * Removes a particular item from a particular region.
&gt;      * &lt;p/&gt;
&gt;      * If this class is running within a remote cache server, removes the item via the
&lt;code&gt;RemoteCacheServer&lt;/code&gt;
&gt;      * API, so that removes will be broadcast to client machines. Otherwise clears the
region directly via the usual
&gt;      * cache API.
&gt;      *
&gt;      * @param cacheName
&gt;      * @param key
&gt;      *
&gt;      * @throws IOException
&gt;      */
&gt;     public void removeItem(String cacheName, String key) throws IOException {
&gt;         if (cacheName == null) {
&gt;             throw new IllegalArgumentException("The cache name specified was null.");
&gt;         }
&gt;         if (key == null) {
&gt;             throw new IllegalArgumentException("The key specified was null.");
&gt;         }
&gt;         if (RemoteCacheServerFactory.getRemoteCacheServer() == null) {
&gt;             // Not running in a remote cache server.
&gt;             // Remove objects from the cache directly, as no need to broadcast removes
to client machines...
&gt;             cacheHub.getCache(cacheName).remove(key);
&gt;         }
&gt;         else {
&gt;             // Running in a remote cache server.
&gt;             // Remove objects via the RemoteCacheServer API, so that removes will be
broadcast to client machines...
&gt;             try {
&gt;                 Object keyToRemove = null;
&gt;                 CompositeCache cache = CompositeCacheManager.getInstance().getCache(cacheName);
&gt;                 // A String key was supplied, but to remove elements via the RemoteCacheServer
API, we need the
&gt;                 // actual key object as stored in the cache (i.e. a Serializable object).
To find the key in this form,
&gt;                 // we iterate through all keys stored in the memory cache until we find
one whose toString matches
&gt;                 // the string supplied...
&gt;                 Object[] allKeysInCache = cache.getMemoryCache().getKeyArray();
&gt;                 for (int i = 0; i &lt; allKeysInCache.length; i++) {
&gt;                     Object keyInCache = allKeysInCache[i];
&gt;                     if (keyInCache.toString().equals(key)) {
&gt;                         if (keyToRemove == null) {
&gt;                             keyToRemove = keyInCache;
&gt;                         }
&gt;                         else {
&gt;                             // A key matching the one specified was already found...
&gt;                             throw new IllegalStateException("Unexpectedly found duplicate
keys in the cache region matching the key specified.");
&gt;                         }
&gt;                     }
&gt;                 }
&gt;                 if (keyToRemove == null) {
&gt;                     throw new IllegalStateException("No match for this key could be found
in the set of keys retrieved from the memory cache.");
&gt;                 }
&gt;                 if (!(keyToRemove instanceof Serializable)) {
&gt;                     throw new IllegalStateException("Found key [" + keyToRemove + ",
" + keyToRemove.getClass() + "] in cache matching key specified, however key found in cache
is unexpectedly not serializable.");
&gt;                 }
&gt;                 // At this point, we have retrieved the matching Serializable key.
&gt;                 // Call remoteCacheServer.remove(String, Serializable)...
&gt;                 // Note: We must fo this using reflection to bypass its package-private
access...
&gt;                 Object remoteCacheServerObject = RemoteCacheServerFactory.getRemoteCacheServer();
&gt;                 Method removeMethod = remoteCacheServerObject.getClass().getMethod("remove",
new Class[]{String.class, Serializable.class});
&gt;                 boolean previouslyAccessibility = removeMethod.isAccessible();
&gt;                 removeMethod.setAccessible(true);
&gt;                 removeMethod.invoke(remoteCacheServerObject, new Object[]{cacheName,
keyToRemove});
&gt;                 removeMethod.setAccessible(previouslyAccessibility);
&gt;             }
&gt;             catch (Exception e) {
&gt;                 throw new IllegalStateException("Failed to remove element with key ["
+ key + ", " + key.getClass() + "] from cache region [" + cacheName + "]: " + e, e);
&gt;             }
&gt;         }
&gt;     }

-- 
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-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jcs-dev-help@jakarta.apache.org



</pre>
</div>
</content>
</entry>
<entry>
<title>[jira] Commented: (JCS-68) Admin.jsp on remote cache server does not broadcast removes - patch</title>
<author><name>&quot;Niall Gallagher (JIRA)&quot; &lt;jira@apache.org&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200909.mbox/%3c1561506124.1251808233015.JavaMail.jira@brutus%3e"/>
<id>urn:uuid:%3c1561506124-1251808233015-JavaMail-jira@brutus%3e</id>
<updated>2009-09-01T12:30:33Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>

    [ https://issues.apache.org/jira/browse/JCS-68?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&amp;focusedCommentId=12749878#action_12749878
] 

Niall Gallagher commented on JCS-68:
------------------------------------

We had to use reflection because the RemoteCacheServer class is package-private, the reflection
bypasses the access restriction. Re: Tim's question on the mailing list- I'm not sure but
this might also be why RemoteCacheServer is missing from the JavaDocs.

Can we make the RemoteCacheServer API public? This would allow us to call it without reflection.
In fact without reflection these patches would be fairly simple indeed.

Here's the relevant class in trunk..

http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/auxiliary/remote/server/RemoteCacheServer.java?revision=727172

It looks like the required 'removeXXX' methods are already public. It's just the class that's
not public. So we just need to add the keyword 'public' to the class declaration. Can we do
this?


&gt; Admin.jsp on remote cache server does not broadcast removes - patch
&gt; -------------------------------------------------------------------
&gt;
&gt;                 Key: JCS-68
&gt;                 URL: https://issues.apache.org/jira/browse/JCS-68
&gt;             Project: JCS
&gt;          Issue Type: Bug
&gt;          Components: RMI Remote Cache
&gt;    Affects Versions: jcs-1.3, jcs-1.4-dev
&gt;         Environment: All
&gt;            Reporter: Niall Gallagher
&gt;            Assignee: Aaron Smuts
&gt;            Priority: Minor
&gt;   Original Estimate: 0.5h
&gt;  Remaining Estimate: 0.5h
&gt;
&gt; 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.
&gt; 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.
&gt; 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.
&gt; 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.
&gt; 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.
&gt; The fix involves replacing 3 methods in org.apache.jcs.admin.JCSAdminBean as follows:
&gt;     /**
&gt;      * Clears all regions in the cache.
&gt;      * &lt;p/&gt;
&gt;      * If this class is running within a remote cache server, clears all regions via
the &lt;code&gt;RemoteCacheServer&lt;/code&gt;
&gt;      * API, so that removes will be broadcast to client machines. Otherwise clears all
regions in the cache directly via
&gt;      * the usual cache API.
&gt;      */
&gt;     public void clearAllRegions() throws IOException {
&gt;         if (RemoteCacheServerFactory.getRemoteCacheServer() == null) {
&gt;             // Not running in a remote cache server.
&gt;             // Remove objects from the cache directly, as no need to broadcast removes
to client machines...
&gt;             String[] names = cacheHub.getCacheNames();
&gt;             for (int i = 0; i &lt; names.length; i++) {
&gt;                 cacheHub.getCache(names[i]).removeAll();
&gt;             }
&gt;         }
&gt;         else {
&gt;             // Running in a remote cache server.
&gt;             // Remove objects via the RemoteCacheServer API, so that removes will be
broadcast to client machines...
&gt;             try {
&gt;                 String[] cacheNames = CompositeCacheManager.getInstance().getCacheNames();
&gt;                 // Call remoteCacheServer.removeAll(String) for each cacheName...
&gt;                 // Note: We must do this using reflection to bypass its package-private
access...
&gt;                 Object remoteCacheServerObject = RemoteCacheServerFactory.getRemoteCacheServer();
&gt;                 Method removeAllMethod = remoteCacheServerObject.getClass().getMethod("removeAll",
new Class[]{String.class});
&gt;                 boolean previouslyAccessibility = removeAllMethod.isAccessible();
&gt;                 removeAllMethod.setAccessible(true);
&gt;                 for (int i = 0; i &lt; cacheNames.length; i++) {
&gt;                     String cacheName = cacheNames[i];
&gt;                     removeAllMethod.invoke(remoteCacheServerObject, new Object[]{cacheName});
&gt;                 }
&gt;                 removeAllMethod.setAccessible(previouslyAccessibility);
&gt;             }
&gt;             catch (Exception e) {
&gt;                 throw new IllegalStateException("Failed to remove all elements from all
cache regions: " + e, e);
&gt;             }
&gt;         }
&gt;     }
&gt;     /**
&gt;      * Clears a particular cache region.
&gt;      * &lt;p/&gt;
&gt;      * If this class is running within a remote cache server, clears the region via the
&lt;code&gt;RemoteCacheServer&lt;/code&gt;
&gt;      * API, so that removes will be broadcast to client machines. Otherwise clears the
region directly via the usual
&gt;      * cache API.
&gt;      */
&gt;     public void clearRegion(String cacheName) throws IOException {
&gt;         if (cacheName == null) {
&gt;             throw new IllegalArgumentException("The cache name specified was null.");
&gt;         }
&gt;         if (RemoteCacheServerFactory.getRemoteCacheServer() == null) {
&gt;             // Not running in a remote cache server.
&gt;             // Remove objects from the cache directly, as no need to broadcast removes
to client machines...
&gt;             cacheHub.getCache(cacheName).removeAll();
&gt;         }
&gt;         else {
&gt;             // Running in a remote cache server.
&gt;             // Remove objects via the RemoteCacheServer API, so that removes will be
broadcast to client machines...
&gt;             try {
&gt;                 // Call remoteCacheServer.removeAll(String)...
&gt;                 // Note: We must do this using reflection to bypass its package-private
access...
&gt;                 Object remoteCacheServerObject = RemoteCacheServerFactory.getRemoteCacheServer();
&gt;                 Method removeAllMethod = remoteCacheServerObject.getClass().getMethod("removeAll",
new Class[]{String.class});
&gt;                 boolean previouslyAccessibility = removeAllMethod.isAccessible();
&gt;                 removeAllMethod.setAccessible(true);
&gt;                 removeAllMethod.invoke(remoteCacheServerObject, new Object[]{cacheName});
&gt;                 removeAllMethod.setAccessible(previouslyAccessibility);
&gt;             }
&gt;             catch (Exception e) {
&gt;                 throw new IllegalStateException("Failed to remove all elements from cache
region [" + cacheName + "]: " + e, e);
&gt;             }
&gt;         }
&gt;     }
&gt;     /**
&gt;      * Removes a particular item from a particular region.
&gt;      * &lt;p/&gt;
&gt;      * If this class is running within a remote cache server, removes the item via the
&lt;code&gt;RemoteCacheServer&lt;/code&gt;
&gt;      * API, so that removes will be broadcast to client machines. Otherwise clears the
region directly via the usual
&gt;      * cache API.
&gt;      *
&gt;      * @param cacheName
&gt;      * @param key
&gt;      *
&gt;      * @throws IOException
&gt;      */
&gt;     public void removeItem(String cacheName, String key) throws IOException {
&gt;         if (cacheName == null) {
&gt;             throw new IllegalArgumentException("The cache name specified was null.");
&gt;         }
&gt;         if (key == null) {
&gt;             throw new IllegalArgumentException("The key specified was null.");
&gt;         }
&gt;         if (RemoteCacheServerFactory.getRemoteCacheServer() == null) {
&gt;             // Not running in a remote cache server.
&gt;             // Remove objects from the cache directly, as no need to broadcast removes
to client machines...
&gt;             cacheHub.getCache(cacheName).remove(key);
&gt;         }
&gt;         else {
&gt;             // Running in a remote cache server.
&gt;             // Remove objects via the RemoteCacheServer API, so that removes will be
broadcast to client machines...
&gt;             try {
&gt;                 Object keyToRemove = null;
&gt;                 CompositeCache cache = CompositeCacheManager.getInstance().getCache(cacheName);
&gt;                 // A String key was supplied, but to remove elements via the RemoteCacheServer
API, we need the
&gt;                 // actual key object as stored in the cache (i.e. a Serializable object).
To find the key in this form,
&gt;                 // we iterate through all keys stored in the memory cache until we find
one whose toString matches
&gt;                 // the string supplied...
&gt;                 Object[] allKeysInCache = cache.getMemoryCache().getKeyArray();
&gt;                 for (int i = 0; i &lt; allKeysInCache.length; i++) {
&gt;                     Object keyInCache = allKeysInCache[i];
&gt;                     if (keyInCache.toString().equals(key)) {
&gt;                         if (keyToRemove == null) {
&gt;                             keyToRemove = keyInCache;
&gt;                         }
&gt;                         else {
&gt;                             // A key matching the one specified was already found...
&gt;                             throw new IllegalStateException("Unexpectedly found duplicate
keys in the cache region matching the key specified.");
&gt;                         }
&gt;                     }
&gt;                 }
&gt;                 if (keyToRemove == null) {
&gt;                     throw new IllegalStateException("No match for this key could be found
in the set of keys retrieved from the memory cache.");
&gt;                 }
&gt;                 if (!(keyToRemove instanceof Serializable)) {
&gt;                     throw new IllegalStateException("Found key [" + keyToRemove + ",
" + keyToRemove.getClass() + "] in cache matching key specified, however key found in cache
is unexpectedly not serializable.");
&gt;                 }
&gt;                 // At this point, we have retrieved the matching Serializable key.
&gt;                 // Call remoteCacheServer.remove(String, Serializable)...
&gt;                 // Note: We must fo this using reflection to bypass its package-private
access...
&gt;                 Object remoteCacheServerObject = RemoteCacheServerFactory.getRemoteCacheServer();
&gt;                 Method removeMethod = remoteCacheServerObject.getClass().getMethod("remove",
new Class[]{String.class, Serializable.class});
&gt;                 boolean previouslyAccessibility = removeMethod.isAccessible();
&gt;                 removeMethod.setAccessible(true);
&gt;                 removeMethod.invoke(remoteCacheServerObject, new Object[]{cacheName,
keyToRemove});
&gt;                 removeMethod.setAccessible(previouslyAccessibility);
&gt;             }
&gt;             catch (Exception e) {
&gt;                 throw new IllegalStateException("Failed to remove element with key ["
+ key + ", " + key.getClass() + "] from cache region [" + cacheName + "]: " + e, e);
&gt;             }
&gt;         }
&gt;     }

-- 
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-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jcs-dev-help@jakarta.apache.org



</pre>
</div>
</content>
</entry>
<entry>
<title>RE: [jira] Commented: (JCS-68) Admin.jsp on remote cache server does not broadcast removes - patch</title>
<author><name>Aaron Smuts &lt;asmuts@yahoo.com&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200908.mbox/%3c115216.42454.qm@web38707.mail.mud.yahoo.com%3e"/>
<id>urn:uuid:%3c115216-42454-qm@web38707-mail-mud-yahoo-com%3e</id>
<updated>2009-08-31T17:58:03Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>
I have no idea.  Strange.  

But to make a patch, you have to checkout the code.  . . . 

--- On Mon, 8/31/09, Tim Cronin &lt;Tim.Cronin@autonomy.com&gt; wrote:

&gt; From: Tim Cronin &lt;Tim.Cronin@autonomy.com&gt;
&gt; Subject: RE: [jira] Commented: (JCS-68) Admin.jsp on remote cache server does not broadcast
removes - patch
&gt; To: "JCS Developers List" &lt;jcs-dev@jakarta.apache.org&gt;
&gt; Date: Monday, August 31, 2009, 8:22 AM
&gt; Any reason that the RemoteCacheServer
&gt; class is not exposed in the
&gt; Javadocs?
&gt; 
&gt; http://jakarta.apache.org/jcs/apidocs/org/apache/jcs/auxiliary/remote/se
&gt; rver/RemoteCacheServerFactory.html
&gt; 
&gt; 
&gt; -----Original Message-----
&gt; From: Aaron Smuts (JIRA) [mailto:jira@apache.org] 
&gt; Sent: Monday, August 31, 2009 8:29 AM
&gt; To: jcs-dev@jakarta.apache.org
&gt; Subject: [jira] Commented: (JCS-68) Admin.jsp on remote
&gt; cache server
&gt; does not broadcast removes - patch
&gt; 
&gt; 
&gt;     [
&gt; https://issues.apache.org/jira/browse/JCS-68?page=com.atlassian.jira.plu
&gt; gin.system.issuetabpanels:comment-tabpanel&amp;focusedCommentId=12749487#act
&gt; ion_12749487 ] 
&gt; 
&gt; Aaron Smuts commented on JCS-68:
&gt; --------------------------------
&gt; 
&gt; Thanks, this is a good idea.  Why are you calling the
&gt; remove method via
&gt; reflection?  That's too fragile.  Especially
&gt; without any unit tests.  I
&gt; need unit tests for all changes.  
&gt; 
&gt; &gt; Admin.jsp on remote cache server does not broadcast
&gt; removes - patch
&gt; &gt;
&gt; -------------------------------------------------------------------
&gt; &gt;
&gt; &gt;             
&gt;    Key: JCS-68
&gt; &gt;             
&gt;    URL: https://issues.apache.org/jira/browse/JCS-68
&gt; &gt;         
&gt;    Project: JCS
&gt; &gt;          Issue Type: Bug
&gt; &gt;          Components: RMI
&gt; Remote Cache
&gt; &gt;    Affects Versions: jcs-1.3, jcs-1.4-dev
&gt; &gt;         Environment:
&gt; All
&gt; &gt;            Reporter:
&gt; Niall Gallagher
&gt; &gt;            Assignee:
&gt; Aaron Smuts
&gt; &gt;            Priority:
&gt; Minor
&gt; &gt;   Original Estimate: 0.5h
&gt; &gt;  Remaining Estimate: 0.5h
&gt; &gt;
&gt; &gt; We'd like to contribute some patches to fix an issue
&gt; with the
&gt; JCSAdmin.jsp when it's used on a JCS remote cache server.
&gt; &gt; We use this JSP on our remote cache server. This
&gt; allows us to browse
&gt; the objects stored in our distributed cache (i.e. uploaded
&gt; by the client
&gt; servers), and allows us to remove arbitrary objects from
&gt; the distributed
&gt; cache by clicking 'remove' next to the key of the relevant
&gt; object
&gt; displayed on the JSP.
&gt; &gt; The issue is: when we use the unmodified version of
&gt; the code to remove
&gt; an object, the object is successfully removed from the JCS
&gt; remote
&gt; server, but the 'remove' event for that object is not
&gt; broadcast to all
&gt; client machines. Client machines which start up after we
&gt; remove the
&gt; object get 'null' when they try to retrieve the object (the
&gt; desired
&gt; behaviour). However client machines which were already
&gt; running and using
&gt; this object continue to see the object in their view of the
&gt; cache.
&gt; &gt; This problem occurs because the JCSAdminBean (used by
&gt; this JSP) calls
&gt; the wrong API in JCS to remove objects from the cache when
&gt; it's running
&gt; on the remote cache server. It calls the CompositeCache
&gt; API, which is
&gt; intended for use client-side only.
&gt; &gt; Our patches update JCSAdminBean to call this same API
&gt; when its running
&gt; on a client machine, BUT if it's running on a machine on
&gt; which the JCS
&gt; remote server is enabled, it calls the RemoteCacheServer
&gt; API instead.
&gt; &gt; The fix involves replacing 3 methods in
&gt; org.apache.jcs.admin.JCSAdminBean as follows:
&gt; &gt;     /**
&gt; &gt;      * Clears all regions in the
&gt; cache.
&gt; &gt;      * &lt;p/&gt;
&gt; &gt;      * If this class is running within
&gt; a remote cache server, clears
&gt; all regions via the
&gt; &lt;code&gt;RemoteCacheServer&lt;/code&gt;
&gt; &gt;      * API, so that removes will be
&gt; broadcast to client machines.
&gt; Otherwise clears all regions in the cache directly via
&gt; &gt;      * the usual cache API.
&gt; &gt;      */
&gt; &gt;     public void clearAllRegions()
&gt; throws IOException {
&gt; &gt;         if
&gt; (RemoteCacheServerFactory.getRemoteCacheServer() == null) {
&gt; &gt;             //
&gt; Not running in a remote cache server.
&gt; &gt;             //
&gt; Remove objects from the cache directly, as no need to
&gt; broadcast removes to client machines...
&gt; &gt;         
&gt;    String[] names =
&gt; cacheHub.getCacheNames();
&gt; &gt;         
&gt;    for (int i = 0; i &lt; names.length; i++)
&gt; {
&gt; &gt;             
&gt;    cacheHub.getCache(names[i]).removeAll();
&gt; &gt;             }
&gt; &gt;         }
&gt; &gt;         else {
&gt; &gt;             //
&gt; Running in a remote cache server.
&gt; &gt;             //
&gt; Remove objects via the RemoteCacheServer API, so that
&gt; removes will be broadcast to client machines...
&gt; &gt;         
&gt;    try {
&gt; &gt;             
&gt;    String[] cacheNames =
&gt; CompositeCacheManager.getInstance().getCacheNames();
&gt; &gt;             
&gt;    // Call
&gt; remoteCacheServer.removeAll(String) for each
&gt; cacheName...
&gt; &gt;             
&gt;    // Note: We must do this using reflection
&gt; to bypass
&gt; its package-private access...
&gt; &gt;             
&gt;    Object remoteCacheServerObject =
&gt; RemoteCacheServerFactory.getRemoteCacheServer();
&gt; &gt;             
&gt;    Method removeAllMethod =
&gt; remoteCacheServerObject.getClass().getMethod("removeAll",
&gt; new
&gt; Class[]{String.class});
&gt; &gt;             
&gt;    boolean previouslyAccessibility =
&gt; removeAllMethod.isAccessible();
&gt; &gt;             
&gt;    removeAllMethod.setAccessible(true);
&gt; &gt;             
&gt;    for (int i = 0; i &lt; cacheNames.length;
&gt; i++) {
&gt; &gt;               
&gt;      String cacheName = cacheNames[i];
&gt; &gt;               
&gt;  
&gt;    removeAllMethod.invoke(remoteCacheServerObject,
&gt; new Object[]{cacheName});
&gt; &gt;             
&gt;    }
&gt; &gt;
&gt; removeAllMethod.setAccessible(previouslyAccessibility);
&gt; &gt;             }
&gt; &gt;         
&gt;    catch (Exception e) {
&gt; &gt;             
&gt;    throw new IllegalStateException("Failed to
&gt; remove all
&gt; elements from all cache regions: " + e, e);
&gt; &gt;             }
&gt; &gt;         }
&gt; &gt;     }
&gt; &gt;     /**
&gt; &gt;      * Clears a particular cache
&gt; region.
&gt; &gt;      * &lt;p/&gt;
&gt; &gt;      * If this class is running within
&gt; a remote cache server, clears
&gt; the region via the
&gt; &lt;code&gt;RemoteCacheServer&lt;/code&gt;
&gt; &gt;      * API, so that removes will be
&gt; broadcast to client machines.
&gt; Otherwise clears the region directly via the usual
&gt; &gt;      * cache API.
&gt; &gt;      */
&gt; &gt;     public void clearRegion(String
&gt; cacheName) throws IOException {
&gt; &gt;         if (cacheName ==
&gt; null) {
&gt; &gt;         
&gt;    throw new IllegalArgumentException("The
&gt; cache name
&gt; specified was null.");
&gt; &gt;         }
&gt; &gt;         if
&gt; (RemoteCacheServerFactory.getRemoteCacheServer() == null) {
&gt; &gt;             //
&gt; Not running in a remote cache server.
&gt; &gt;             //
&gt; Remove objects from the cache directly, as no need to
&gt; broadcast removes to client machines...
&gt; &gt;         
&gt;    cacheHub.getCache(cacheName).removeAll();
&gt; &gt;         }
&gt; &gt;         else {
&gt; &gt;             //
&gt; Running in a remote cache server.
&gt; &gt;             //
&gt; Remove objects via the RemoteCacheServer API, so that
&gt; removes will be broadcast to client machines...
&gt; &gt;         
&gt;    try {
&gt; &gt;             
&gt;    // Call
&gt; remoteCacheServer.removeAll(String)...
&gt; &gt;             
&gt;    // Note: We must do this using reflection
&gt; to bypass
&gt; its package-private access...
&gt; &gt;             
&gt;    Object remoteCacheServerObject =
&gt; RemoteCacheServerFactory.getRemoteCacheServer();
&gt; &gt;             
&gt;    Method removeAllMethod =
&gt; remoteCacheServerObject.getClass().getMethod("removeAll",
&gt; new
&gt; Class[]{String.class});
&gt; &gt;             
&gt;    boolean previouslyAccessibility =
&gt; removeAllMethod.isAccessible();
&gt; &gt;             
&gt;    removeAllMethod.setAccessible(true);
&gt; &gt;             
&gt;    removeAllMethod.invoke(remoteCacheServerObject,
&gt; new
&gt; Object[]{cacheName});
&gt; &gt;
&gt; removeAllMethod.setAccessible(previouslyAccessibility);
&gt; &gt;             }
&gt; &gt;         
&gt;    catch (Exception e) {
&gt; &gt;             
&gt;    throw new IllegalStateException("Failed to
&gt; remove all
&gt; elements from cache region [" + cacheName + "]: " + e, e);
&gt; &gt;             }
&gt; &gt;         }
&gt; &gt;     }
&gt; &gt;     /**
&gt; &gt;      * Removes a particular item from a
&gt; particular region.
&gt; &gt;      * &lt;p/&gt;
&gt; &gt;      * If this class is running within
&gt; a remote cache server, removes
&gt; the item via the
&gt; &lt;code&gt;RemoteCacheServer&lt;/code&gt;
&gt; &gt;      * API, so that removes will be
&gt; broadcast to client machines.
&gt; Otherwise clears the region directly via the usual
&gt; &gt;      * cache API.
&gt; &gt;      *
&gt; &gt;      * @param cacheName
&gt; &gt;      * @param key
&gt; &gt;      *
&gt; &gt;      * @throws IOException
&gt; &gt;      */
&gt; &gt;     public void removeItem(String
&gt; cacheName, String key) throws
&gt; IOException {
&gt; &gt;         if (cacheName ==
&gt; null) {
&gt; &gt;         
&gt;    throw new IllegalArgumentException("The
&gt; cache name
&gt; specified was null.");
&gt; &gt;         }
&gt; &gt;         if (key == null)
&gt; {
&gt; &gt;         
&gt;    throw new IllegalArgumentException("The
&gt; key specified was
&gt; null.");
&gt; &gt;         }
&gt; &gt;         if
&gt; (RemoteCacheServerFactory.getRemoteCacheServer() == null) {
&gt; &gt;             //
&gt; Not running in a remote cache server.
&gt; &gt;             //
&gt; Remove objects from the cache directly, as no need to
&gt; broadcast removes to client machines...
&gt; &gt;         
&gt;    cacheHub.getCache(cacheName).remove(key);
&gt; &gt;         }
&gt; &gt;         else {
&gt; &gt;             //
&gt; Running in a remote cache server.
&gt; &gt;             //
&gt; Remove objects via the RemoteCacheServer API, so that
&gt; removes will be broadcast to client machines...
&gt; &gt;         
&gt;    try {
&gt; &gt;             
&gt;    Object keyToRemove = null;
&gt; &gt;             
&gt;    CompositeCache cache =
&gt; CompositeCacheManager.getInstance().getCache(cacheName);
&gt; &gt;             
&gt;    // A String key was supplied, but to
&gt; remove elements
&gt; via the RemoteCacheServer API, we need the
&gt; &gt;             
&gt;    // actual key object as stored in the
&gt; cache (i.e. a
&gt; Serializable object). To find the key in this form,
&gt; &gt;             
&gt;    // we iterate through all keys stored in
&gt; the memory
&gt; cache until we find one whose toString matches
&gt; &gt;             
&gt;    // the string supplied...
&gt; &gt;             
&gt;    Object[] allKeysInCache =
&gt; cache.getMemoryCache().getKeyArray();
&gt; &gt;             
&gt;    for (int i = 0; i &lt;
&gt; allKeysInCache.length; i++) {
&gt; &gt;               
&gt;      Object keyInCache =
&gt; allKeysInCache[i];
&gt; &gt;               
&gt;      if
&gt; (keyInCache.toString().equals(key)) {
&gt; &gt;               
&gt;          if (keyToRemove ==
&gt; null) {
&gt; &gt;               
&gt;          
&gt;    keyToRemove = keyInCache;
&gt; &gt;               
&gt;          }
&gt; &gt;               
&gt;          else {
&gt; &gt;               
&gt;              // A
&gt; key matching the one specified was
&gt; already found...
&gt; &gt;               
&gt;              throw
&gt; new
&gt; IllegalStateException("Unexpectedly found duplicate keys in
&gt; the cache
&gt; region matching the key specified.");
&gt; &gt;               
&gt;          }
&gt; &gt;               
&gt;      }
&gt; &gt;             
&gt;    }
&gt; &gt;             
&gt;    if (keyToRemove == null) {
&gt; &gt;               
&gt;      throw new IllegalStateException("No
&gt; match for this
&gt; key could be found in the set of keys retrieved from the
&gt; memory
&gt; cache.");
&gt; &gt;             
&gt;    }
&gt; &gt;             
&gt;    if (!(keyToRemove instanceof
&gt; Serializable)) {
&gt; &gt;               
&gt;      throw new
&gt; IllegalStateException("Found key [" +
&gt; keyToRemove + ", " + keyToRemove.getClass() + "] in cache
&gt; matching key
&gt; specified, however key found in cache is unexpectedly not
&gt; serializable.");
&gt; &gt;             
&gt;    }
&gt; &gt;             
&gt;    // At this point, we have retrieved the
&gt; matching
&gt; Serializable key.
&gt; &gt;             
&gt;    // Call remoteCacheServer.remove(String,
&gt; Serializable)...
&gt; &gt;             
&gt;    // Note: We must fo this using reflection
&gt; to bypass
&gt; its package-private access...
&gt; &gt;             
&gt;    Object remoteCacheServerObject =
&gt; RemoteCacheServerFactory.getRemoteCacheServer();
&gt; &gt;             
&gt;    Method removeMethod =
&gt; remoteCacheServerObject.getClass().getMethod("remove", new
&gt; Class[]{String.class, Serializable.class});
&gt; &gt;             
&gt;    boolean previouslyAccessibility =
&gt; removeMethod.isAccessible();
&gt; &gt;             
&gt;    removeMethod.setAccessible(true);
&gt; &gt;             
&gt;    removeMethod.invoke(remoteCacheServerObject,
&gt; new
&gt; Object[]{cacheName, keyToRemove});
&gt; &gt;             
&gt;    removeMethod.setAccessible(previouslyAccessibility);
&gt; &gt;             }
&gt; &gt;         
&gt;    catch (Exception e) {
&gt; &gt;             
&gt;    throw new IllegalStateException("Failed to
&gt; remove
&gt; element with key [" + key + ", " + key.getClass() + "] from
&gt; cache region
&gt; [" + cacheName + "]: " + e, e);
&gt; &gt;             }
&gt; &gt;         }
&gt; &gt;     }
&gt; 
&gt; -- 
&gt; This message is automatically generated by JIRA.
&gt; -
&gt; You can reply to this email to add a comment to the issue
&gt; online.
&gt; 
&gt; 
&gt; ---------------------------------------------------------------------
&gt; To unsubscribe, e-mail: jcs-dev-unsubscribe@jakarta.apache.org
&gt; For additional commands, e-mail: jcs-dev-help@jakarta.apache.org
&gt; 
&gt; 
&gt; ---------------------------------------------------------------------
&gt; To unsubscribe, e-mail: jcs-dev-unsubscribe@jakarta.apache.org
&gt; For additional commands, e-mail: jcs-dev-help@jakarta.apache.org
&gt; 
&gt; 

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



</pre>
</div>
</content>
</entry>
<entry>
<title>RE: [jira] Commented: (JCS-68) Admin.jsp on remote cache server does not broadcast removes - patch</title>
<author><name>&quot;Tim Cronin&quot; &lt;Tim.Cronin@autonomy.com&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200908.mbox/%3c56A8F47A92B81F4C91648D4E38286A48047B7CF1@exbehq01.Interwoven.com%3e"/>
<id>urn:uuid:%3c56A8F47A92B81F4C91648D4E38286A48047B7CF1@exbehq01-Interwoven-com%3e</id>
<updated>2009-08-31T15:22:05Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>
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:jira@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&amp;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.  

&gt; Admin.jsp on remote cache server does not broadcast removes - patch
&gt; -------------------------------------------------------------------
&gt;
&gt;                 Key: JCS-68
&gt;                 URL: https://issues.apache.org/jira/browse/JCS-68
&gt;             Project: JCS
&gt;          Issue Type: Bug
&gt;          Components: RMI Remote Cache
&gt;    Affects Versions: jcs-1.3, jcs-1.4-dev
&gt;         Environment: All
&gt;            Reporter: Niall Gallagher
&gt;            Assignee: Aaron Smuts
&gt;            Priority: Minor
&gt;   Original Estimate: 0.5h
&gt;  Remaining Estimate: 0.5h
&gt;
&gt; 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.
&gt; 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.
&gt; 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.
&gt; 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.
&gt; 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.
&gt; The fix involves replacing 3 methods in
org.apache.jcs.admin.JCSAdminBean as follows:
&gt;     /**
&gt;      * Clears all regions in the cache.
&gt;      * &lt;p/&gt;
&gt;      * If this class is running within a remote cache server, clears
all regions via the &lt;code&gt;RemoteCacheServer&lt;/code&gt;
&gt;      * API, so that removes will be broadcast to client machines.
Otherwise clears all regions in the cache directly via
&gt;      * the usual cache API.
&gt;      */
&gt;     public void clearAllRegions() throws IOException {
&gt;         if (RemoteCacheServerFactory.getRemoteCacheServer() == null) {
&gt;             // Not running in a remote cache server.
&gt;             // Remove objects from the cache directly, as no need to
broadcast removes to client machines...
&gt;             String[] names = cacheHub.getCacheNames();
&gt;             for (int i = 0; i &lt; names.length; i++) {
&gt;                 cacheHub.getCache(names[i]).removeAll();
&gt;             }
&gt;         }
&gt;         else {
&gt;             // Running in a remote cache server.
&gt;             // Remove objects via the RemoteCacheServer API, so that
removes will be broadcast to client machines...
&gt;             try {
&gt;                 String[] cacheNames =
CompositeCacheManager.getInstance().getCacheNames();
&gt;                 // Call remoteCacheServer.removeAll(String) for each
cacheName...
&gt;                 // Note: We must do this using reflection to bypass
its package-private access...
&gt;                 Object remoteCacheServerObject =
RemoteCacheServerFactory.getRemoteCacheServer();
&gt;                 Method removeAllMethod =
remoteCacheServerObject.getClass().getMethod("removeAll", new
Class[]{String.class});
&gt;                 boolean previouslyAccessibility =
removeAllMethod.isAccessible();
&gt;                 removeAllMethod.setAccessible(true);
&gt;                 for (int i = 0; i &lt; cacheNames.length; i++) {
&gt;                     String cacheName = cacheNames[i];
&gt;                     removeAllMethod.invoke(remoteCacheServerObject,
new Object[]{cacheName});
&gt;                 }
&gt;
removeAllMethod.setAccessible(previouslyAccessibility);
&gt;             }
&gt;             catch (Exception e) {
&gt;                 throw new IllegalStateException("Failed to remove all
elements from all cache regions: " + e, e);
&gt;             }
&gt;         }
&gt;     }
&gt;     /**
&gt;      * Clears a particular cache region.
&gt;      * &lt;p/&gt;
&gt;      * If this class is running within a remote cache server, clears
the region via the &lt;code&gt;RemoteCacheServer&lt;/code&gt;
&gt;      * API, so that removes will be broadcast to client machines.
Otherwise clears the region directly via the usual
&gt;      * cache API.
&gt;      */
&gt;     public void clearRegion(String cacheName) throws IOException {
&gt;         if (cacheName == null) {
&gt;             throw new IllegalArgumentException("The cache name
specified was null.");
&gt;         }
&gt;         if (RemoteCacheServerFactory.getRemoteCacheServer() == null) {
&gt;             // Not running in a remote cache server.
&gt;             // Remove objects from the cache directly, as no need to
broadcast removes to client machines...
&gt;             cacheHub.getCache(cacheName).removeAll();
&gt;         }
&gt;         else {
&gt;             // Running in a remote cache server.
&gt;             // Remove objects via the RemoteCacheServer API, so that
removes will be broadcast to client machines...
&gt;             try {
&gt;                 // Call remoteCacheServer.removeAll(String)...
&gt;                 // Note: We must do this using reflection to bypass
its package-private access...
&gt;                 Object remoteCacheServerObject =
RemoteCacheServerFactory.getRemoteCacheServer();
&gt;                 Method removeAllMethod =
remoteCacheServerObject.getClass().getMethod("removeAll", new
Class[]{String.class});
&gt;                 boolean previouslyAccessibility =
removeAllMethod.isAccessible();
&gt;                 removeAllMethod.setAccessible(true);
&gt;                 removeAllMethod.invoke(remoteCacheServerObject, new
Object[]{cacheName});
&gt;
removeAllMethod.setAccessible(previouslyAccessibility);
&gt;             }
&gt;             catch (Exception e) {
&gt;                 throw new IllegalStateException("Failed to remove all
elements from cache region [" + cacheName + "]: " + e, e);
&gt;             }
&gt;         }
&gt;     }
&gt;     /**
&gt;      * Removes a particular item from a particular region.
&gt;      * &lt;p/&gt;
&gt;      * If this class is running within a remote cache server, removes
the item via the &lt;code&gt;RemoteCacheServer&lt;/code&gt;
&gt;      * API, so that removes will be broadcast to client machines.
Otherwise clears the region directly via the usual
&gt;      * cache API.
&gt;      *
&gt;      * @param cacheName
&gt;      * @param key
&gt;      *
&gt;      * @throws IOException
&gt;      */
&gt;     public void removeItem(String cacheName, String key) throws
IOException {
&gt;         if (cacheName == null) {
&gt;             throw new IllegalArgumentException("The cache name
specified was null.");
&gt;         }
&gt;         if (key == null) {
&gt;             throw new IllegalArgumentException("The key specified was
null.");
&gt;         }
&gt;         if (RemoteCacheServerFactory.getRemoteCacheServer() == null) {
&gt;             // Not running in a remote cache server.
&gt;             // Remove objects from the cache directly, as no need to
broadcast removes to client machines...
&gt;             cacheHub.getCache(cacheName).remove(key);
&gt;         }
&gt;         else {
&gt;             // Running in a remote cache server.
&gt;             // Remove objects via the RemoteCacheServer API, so that
removes will be broadcast to client machines...
&gt;             try {
&gt;                 Object keyToRemove = null;
&gt;                 CompositeCache cache =
CompositeCacheManager.getInstance().getCache(cacheName);
&gt;                 // A String key was supplied, but to remove elements
via the RemoteCacheServer API, we need the
&gt;                 // actual key object as stored in the cache (i.e. a
Serializable object). To find the key in this form,
&gt;                 // we iterate through all keys stored in the memory
cache until we find one whose toString matches
&gt;                 // the string supplied...
&gt;                 Object[] allKeysInCache =
cache.getMemoryCache().getKeyArray();
&gt;                 for (int i = 0; i &lt; allKeysInCache.length; i++) {
&gt;                     Object keyInCache = allKeysInCache[i];
&gt;                     if (keyInCache.toString().equals(key)) {
&gt;                         if (keyToRemove == null) {
&gt;                             keyToRemove = keyInCache;
&gt;                         }
&gt;                         else {
&gt;                             // A key matching the one specified was
already found...
&gt;                             throw new
IllegalStateException("Unexpectedly found duplicate keys in the cache
region matching the key specified.");
&gt;                         }
&gt;                     }
&gt;                 }
&gt;                 if (keyToRemove == null) {
&gt;                     throw new IllegalStateException("No match for this
key could be found in the set of keys retrieved from the memory
cache.");
&gt;                 }
&gt;                 if (!(keyToRemove instanceof Serializable)) {
&gt;                     throw new IllegalStateException("Found key [" +
keyToRemove + ", " + keyToRemove.getClass() + "] in cache matching key
specified, however key found in cache is unexpectedly not
serializable.");
&gt;                 }
&gt;                 // At this point, we have retrieved the matching
Serializable key.
&gt;                 // Call remoteCacheServer.remove(String,
Serializable)...
&gt;                 // Note: We must fo this using reflection to bypass
its package-private access...
&gt;                 Object remoteCacheServerObject =
RemoteCacheServerFactory.getRemoteCacheServer();
&gt;                 Method removeMethod =
remoteCacheServerObject.getClass().getMethod("remove", new
Class[]{String.class, Serializable.class});
&gt;                 boolean previouslyAccessibility =
removeMethod.isAccessible();
&gt;                 removeMethod.setAccessible(true);
&gt;                 removeMethod.invoke(remoteCacheServerObject, new
Object[]{cacheName, keyToRemove});
&gt;                 removeMethod.setAccessible(previouslyAccessibility);
&gt;             }
&gt;             catch (Exception e) {
&gt;                 throw new IllegalStateException("Failed to remove
element with key [" + key + ", " + key.getClass() + "] from cache region
[" + cacheName + "]: " + e, e);
&gt;             }
&gt;         }
&gt;     }

-- 
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-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jcs-dev-help@jakarta.apache.org


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



</pre>
</div>
</content>
</entry>
<entry>
<title>[jira] Commented: (JCS-68) Admin.jsp on remote cache server does not broadcast removes - patch</title>
<author><name>&quot;Aaron Smuts (JIRA)&quot; &lt;jira@apache.org&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200908.mbox/%3c110147091.1251725312710.JavaMail.jira@brutus%3e"/>
<id>urn:uuid:%3c110147091-1251725312710-JavaMail-jira@brutus%3e</id>
<updated>2009-08-31T13:28:32Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>

    [ https://issues.apache.org/jira/browse/JCS-68?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&amp;focusedCommentId=12749487#action_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.  

&gt; Admin.jsp on remote cache server does not broadcast removes - patch
&gt; -------------------------------------------------------------------
&gt;
&gt;                 Key: JCS-68
&gt;                 URL: https://issues.apache.org/jira/browse/JCS-68
&gt;             Project: JCS
&gt;          Issue Type: Bug
&gt;          Components: RMI Remote Cache
&gt;    Affects Versions: jcs-1.3, jcs-1.4-dev
&gt;         Environment: All
&gt;            Reporter: Niall Gallagher
&gt;            Assignee: Aaron Smuts
&gt;            Priority: Minor
&gt;   Original Estimate: 0.5h
&gt;  Remaining Estimate: 0.5h
&gt;
&gt; 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.
&gt; 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.
&gt; 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.
&gt; 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.
&gt; 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.
&gt; The fix involves replacing 3 methods in org.apache.jcs.admin.JCSAdminBean as follows:
&gt;     /**
&gt;      * Clears all regions in the cache.
&gt;      * &lt;p/&gt;
&gt;      * If this class is running within a remote cache server, clears all regions via
the &lt;code&gt;RemoteCacheServer&lt;/code&gt;
&gt;      * API, so that removes will be broadcast to client machines. Otherwise clears all
regions in the cache directly via
&gt;      * the usual cache API.
&gt;      */
&gt;     public void clearAllRegions() throws IOException {
&gt;         if (RemoteCacheServerFactory.getRemoteCacheServer() == null) {
&gt;             // Not running in a remote cache server.
&gt;             // Remove objects from the cache directly, as no need to broadcast removes
to client machines...
&gt;             String[] names = cacheHub.getCacheNames();
&gt;             for (int i = 0; i &lt; names.length; i++) {
&gt;                 cacheHub.getCache(names[i]).removeAll();
&gt;             }
&gt;         }
&gt;         else {
&gt;             // Running in a remote cache server.
&gt;             // Remove objects via the RemoteCacheServer API, so that removes will be
broadcast to client machines...
&gt;             try {
&gt;                 String[] cacheNames = CompositeCacheManager.getInstance().getCacheNames();
&gt;                 // Call remoteCacheServer.removeAll(String) for each cacheName...
&gt;                 // Note: We must do this using reflection to bypass its package-private
access...
&gt;                 Object remoteCacheServerObject = RemoteCacheServerFactory.getRemoteCacheServer();
&gt;                 Method removeAllMethod = remoteCacheServerObject.getClass().getMethod("removeAll",
new Class[]{String.class});
&gt;                 boolean previouslyAccessibility = removeAllMethod.isAccessible();
&gt;                 removeAllMethod.setAccessible(true);
&gt;                 for (int i = 0; i &lt; cacheNames.length; i++) {
&gt;                     String cacheName = cacheNames[i];
&gt;                     removeAllMethod.invoke(remoteCacheServerObject, new Object[]{cacheName});
&gt;                 }
&gt;                 removeAllMethod.setAccessible(previouslyAccessibility);
&gt;             }
&gt;             catch (Exception e) {
&gt;                 throw new IllegalStateException("Failed to remove all elements from all
cache regions: " + e, e);
&gt;             }
&gt;         }
&gt;     }
&gt;     /**
&gt;      * Clears a particular cache region.
&gt;      * &lt;p/&gt;
&gt;      * If this class is running within a remote cache server, clears the region via the
&lt;code&gt;RemoteCacheServer&lt;/code&gt;
&gt;      * API, so that removes will be broadcast to client machines. Otherwise clears the
region directly via the usual
&gt;      * cache API.
&gt;      */
&gt;     public void clearRegion(String cacheName) throws IOException {
&gt;         if (cacheName == null) {
&gt;             throw new IllegalArgumentException("The cache name specified was null.");
&gt;         }
&gt;         if (RemoteCacheServerFactory.getRemoteCacheServer() == null) {
&gt;             // Not running in a remote cache server.
&gt;             // Remove objects from the cache directly, as no need to broadcast removes
to client machines...
&gt;             cacheHub.getCache(cacheName).removeAll();
&gt;         }
&gt;         else {
&gt;             // Running in a remote cache server.
&gt;             // Remove objects via the RemoteCacheServer API, so that removes will be
broadcast to client machines...
&gt;             try {
&gt;                 // Call remoteCacheServer.removeAll(String)...
&gt;                 // Note: We must do this using reflection to bypass its package-private
access...
&gt;                 Object remoteCacheServerObject = RemoteCacheServerFactory.getRemoteCacheServer();
&gt;                 Method removeAllMethod = remoteCacheServerObject.getClass().getMethod("removeAll",
new Class[]{String.class});
&gt;                 boolean previouslyAccessibility = removeAllMethod.isAccessible();
&gt;                 removeAllMethod.setAccessible(true);
&gt;                 removeAllMethod.invoke(remoteCacheServerObject, new Object[]{cacheName});
&gt;                 removeAllMethod.setAccessible(previouslyAccessibility);
&gt;             }
&gt;             catch (Exception e) {
&gt;                 throw new IllegalStateException("Failed to remove all elements from cache
region [" + cacheName + "]: " + e, e);
&gt;             }
&gt;         }
&gt;     }
&gt;     /**
&gt;      * Removes a particular item from a particular region.
&gt;      * &lt;p/&gt;
&gt;      * If this class is running within a remote cache server, removes the item via the
&lt;code&gt;RemoteCacheServer&lt;/code&gt;
&gt;      * API, so that removes will be broadcast to client machines. Otherwise clears the
region directly via the usual
&gt;      * cache API.
&gt;      *
&gt;      * @param cacheName
&gt;      * @param key
&gt;      *
&gt;      * @throws IOException
&gt;      */
&gt;     public void removeItem(String cacheName, String key) throws IOException {
&gt;         if (cacheName == null) {
&gt;             throw new IllegalArgumentException("The cache name specified was null.");
&gt;         }
&gt;         if (key == null) {
&gt;             throw new IllegalArgumentException("The key specified was null.");
&gt;         }
&gt;         if (RemoteCacheServerFactory.getRemoteCacheServer() == null) {
&gt;             // Not running in a remote cache server.
&gt;             // Remove objects from the cache directly, as no need to broadcast removes
to client machines...
&gt;             cacheHub.getCache(cacheName).remove(key);
&gt;         }
&gt;         else {
&gt;             // Running in a remote cache server.
&gt;             // Remove objects via the RemoteCacheServer API, so that removes will be
broadcast to client machines...
&gt;             try {
&gt;                 Object keyToRemove = null;
&gt;                 CompositeCache cache = CompositeCacheManager.getInstance().getCache(cacheName);
&gt;                 // A String key was supplied, but to remove elements via the RemoteCacheServer
API, we need the
&gt;                 // actual key object as stored in the cache (i.e. a Serializable object).
To find the key in this form,
&gt;                 // we iterate through all keys stored in the memory cache until we find
one whose toString matches
&gt;                 // the string supplied...
&gt;                 Object[] allKeysInCache = cache.getMemoryCache().getKeyArray();
&gt;                 for (int i = 0; i &lt; allKeysInCache.length; i++) {
&gt;                     Object keyInCache = allKeysInCache[i];
&gt;                     if (keyInCache.toString().equals(key)) {
&gt;                         if (keyToRemove == null) {
&gt;                             keyToRemove = keyInCache;
&gt;                         }
&gt;                         else {
&gt;                             // A key matching the one specified was already found...
&gt;                             throw new IllegalStateException("Unexpectedly found duplicate
keys in the cache region matching the key specified.");
&gt;                         }
&gt;                     }
&gt;                 }
&gt;                 if (keyToRemove == null) {
&gt;                     throw new IllegalStateException("No match for this key could be found
in the set of keys retrieved from the memory cache.");
&gt;                 }
&gt;                 if (!(keyToRemove instanceof Serializable)) {
&gt;                     throw new IllegalStateException("Found key [" + keyToRemove + ",
" + keyToRemove.getClass() + "] in cache matching key specified, however key found in cache
is unexpectedly not serializable.");
&gt;                 }
&gt;                 // At this point, we have retrieved the matching Serializable key.
&gt;                 // Call remoteCacheServer.remove(String, Serializable)...
&gt;                 // Note: We must fo this using reflection to bypass its package-private
access...
&gt;                 Object remoteCacheServerObject = RemoteCacheServerFactory.getRemoteCacheServer();
&gt;                 Method removeMethod = remoteCacheServerObject.getClass().getMethod("remove",
new Class[]{String.class, Serializable.class});
&gt;                 boolean previouslyAccessibility = removeMethod.isAccessible();
&gt;                 removeMethod.setAccessible(true);
&gt;                 removeMethod.invoke(remoteCacheServerObject, new Object[]{cacheName,
keyToRemove});
&gt;                 removeMethod.setAccessible(previouslyAccessibility);
&gt;             }
&gt;             catch (Exception e) {
&gt;                 throw new IllegalStateException("Failed to remove element with key ["
+ key + ", " + key.getClass() + "] from cache region [" + cacheName + "]: " + e, e);
&gt;             }
&gt;         }
&gt;     }

-- 
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-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jcs-dev-help@jakarta.apache.org



</pre>
</div>
</content>
</entry>
<entry>
<title>[jira] Updated: (JCS-68) Admin.jsp on remote cache server does not broadcast removes - patch</title>
<author><name>&quot;Niall Gallagher (JIRA)&quot; &lt;jira@apache.org&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200908.mbox/%3c1058429328.1251480392774.JavaMail.jira@brutus%3e"/>
<id>urn:uuid:%3c1058429328-1251480392774-JavaMail-jira@brutus%3e</id>
<updated>2009-08-28T17:26:32Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>

     [ https://issues.apache.org/jira/browse/JCS-68?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]

Niall Gallagher updated JCS-68:
-------------------------------

    Description: 
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.
     * &lt;p/&gt;
     * If this class is running within a remote cache server, clears all regions via the &lt;code&gt;RemoteCacheServer&lt;/code&gt;
     * 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 &lt; 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 &lt; 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.
     * &lt;p/&gt;
     * If this class is running within a remote cache server, clears the region via the &lt;code&gt;RemoteCacheServer&lt;/code&gt;
     * 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.
     * &lt;p/&gt;
     * If this class is running within a remote cache server, removes the item via the &lt;code&gt;RemoteCacheServer&lt;/code&gt;
     * 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 &lt; 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);
            }
        }
    }



  was:
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 a 3 methods in org.apache.jcs.admin.JCSAdminBean with as follows:

    /**
     * Clears all regions in the cache.
     * &lt;p/&gt;
     * If this class is running within a remote cache server, clears all regions via the &lt;code&gt;RemoteCacheServer&lt;/code&gt;
     * 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 &lt; 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 &lt; 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.
     * &lt;p/&gt;
     * If this class is running within a remote cache server, clears the region via the &lt;code&gt;RemoteCacheServer&lt;/code&gt;
     * 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.
     * &lt;p/&gt;
     * If this class is running within a remote cache server, removes the item via the &lt;code&gt;RemoteCacheServer&lt;/code&gt;
     * 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 &lt; 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);
            }
        }
    }




&gt; Admin.jsp on remote cache server does not broadcast removes - patch
&gt; -------------------------------------------------------------------
&gt;
&gt;                 Key: JCS-68
&gt;                 URL: https://issues.apache.org/jira/browse/JCS-68
&gt;             Project: JCS
&gt;          Issue Type: Bug
&gt;          Components: RMI Remote Cache
&gt;    Affects Versions: jcs-1.3, jcs-1.4-dev
&gt;         Environment: All
&gt;            Reporter: Niall Gallagher
&gt;            Assignee: Aaron Smuts
&gt;            Priority: Minor
&gt;   Original Estimate: 0.5h
&gt;  Remaining Estimate: 0.5h
&gt;
&gt; 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.
&gt; 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.
&gt; 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.
&gt; 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.
&gt; 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.
&gt; The fix involves replacing 3 methods in org.apache.jcs.admin.JCSAdminBean as follows:
&gt;     /**
&gt;      * Clears all regions in the cache.
&gt;      * &lt;p/&gt;
&gt;      * If this class is running within a remote cache server, clears all regions via
the &lt;code&gt;RemoteCacheServer&lt;/code&gt;
&gt;      * API, so that removes will be broadcast to client machines. Otherwise clears all
regions in the cache directly via
&gt;      * the usual cache API.
&gt;      */
&gt;     public void clearAllRegions() throws IOException {
&gt;         if (RemoteCacheServerFactory.getRemoteCacheServer() == null) {
&gt;             // Not running in a remote cache server.
&gt;             // Remove objects from the cache directly, as no need to broadcast removes
to client machines...
&gt;             String[] names = cacheHub.getCacheNames();
&gt;             for (int i = 0; i &lt; names.length; i++) {
&gt;                 cacheHub.getCache(names[i]).removeAll();
&gt;             }
&gt;         }
&gt;         else {
&gt;             // Running in a remote cache server.
&gt;             // Remove objects via the RemoteCacheServer API, so that removes will be
broadcast to client machines...
&gt;             try {
&gt;                 String[] cacheNames = CompositeCacheManager.getInstance().getCacheNames();
&gt;                 // Call remoteCacheServer.removeAll(String) for each cacheName...
&gt;                 // Note: We must do this using reflection to bypass its package-private
access...
&gt;                 Object remoteCacheServerObject = RemoteCacheServerFactory.getRemoteCacheServer();
&gt;                 Method removeAllMethod = remoteCacheServerObject.getClass().getMethod("removeAll",
new Class[]{String.class});
&gt;                 boolean previouslyAccessibility = removeAllMethod.isAccessible();
&gt;                 removeAllMethod.setAccessible(true);
&gt;                 for (int i = 0; i &lt; cacheNames.length; i++) {
&gt;                     String cacheName = cacheNames[i];
&gt;                     removeAllMethod.invoke(remoteCacheServerObject, new Object[]{cacheName});
&gt;                 }
&gt;                 removeAllMethod.setAccessible(previouslyAccessibility);
&gt;             }
&gt;             catch (Exception e) {
&gt;                 throw new IllegalStateException("Failed to remove all elements from all
cache regions: " + e, e);
&gt;             }
&gt;         }
&gt;     }
&gt;     /**
&gt;      * Clears a particular cache region.
&gt;      * &lt;p/&gt;
&gt;      * If this class is running within a remote cache server, clears the region via the
&lt;code&gt;RemoteCacheServer&lt;/code&gt;
&gt;      * API, so that removes will be broadcast to client machines. Otherwise clears the
region directly via the usual
&gt;      * cache API.
&gt;      */
&gt;     public void clearRegion(String cacheName) throws IOException {
&gt;         if (cacheName == null) {
&gt;             throw new IllegalArgumentException("The cache name specified was null.");
&gt;         }
&gt;         if (RemoteCacheServerFactory.getRemoteCacheServer() == null) {
&gt;             // Not running in a remote cache server.
&gt;             // Remove objects from the cache directly, as no need to broadcast removes
to client machines...
&gt;             cacheHub.getCache(cacheName).removeAll();
&gt;         }
&gt;         else {
&gt;             // Running in a remote cache server.
&gt;             // Remove objects via the RemoteCacheServer API, so that removes will be
broadcast to client machines...
&gt;             try {
&gt;                 // Call remoteCacheServer.removeAll(String)...
&gt;                 // Note: We must do this using reflection to bypass its package-private
access...
&gt;                 Object remoteCacheServerObject = RemoteCacheServerFactory.getRemoteCacheServer();
&gt;                 Method removeAllMethod = remoteCacheServerObject.getClass().getMethod("removeAll",
new Class[]{String.class});
&gt;                 boolean previouslyAccessibility = removeAllMethod.isAccessible();
&gt;                 removeAllMethod.setAccessible(true);
&gt;                 removeAllMethod.invoke(remoteCacheServerObject, new Object[]{cacheName});
&gt;                 removeAllMethod.setAccessible(previouslyAccessibility);
&gt;             }
&gt;             catch (Exception e) {
&gt;                 throw new IllegalStateException("Failed to remove all elements from cache
region [" + cacheName + "]: " + e, e);
&gt;             }
&gt;         }
&gt;     }
&gt;     /**
&gt;      * Removes a particular item from a particular region.
&gt;      * &lt;p/&gt;
&gt;      * If this class is running within a remote cache server, removes the item via the
&lt;code&gt;RemoteCacheServer&lt;/code&gt;
&gt;      * API, so that removes will be broadcast to client machines. Otherwise clears the
region directly via the usual
&gt;      * cache API.
&gt;      *
&gt;      * @param cacheName
&gt;      * @param key
&gt;      *
&gt;      * @throws IOException
&gt;      */
&gt;     public void removeItem(String cacheName, String key) throws IOException {
&gt;         if (cacheName == null) {
&gt;             throw new IllegalArgumentException("The cache name specified was null.");
&gt;         }
&gt;         if (key == null) {
&gt;             throw new IllegalArgumentException("The key specified was null.");
&gt;         }
&gt;         if (RemoteCacheServerFactory.getRemoteCacheServer() == null) {
&gt;             // Not running in a remote cache server.
&gt;             // Remove objects from the cache directly, as no need to broadcast removes
to client machines...
&gt;             cacheHub.getCache(cacheName).remove(key);
&gt;         }
&gt;         else {
&gt;             // Running in a remote cache server.
&gt;             // Remove objects via the RemoteCacheServer API, so that removes will be
broadcast to client machines...
&gt;             try {
&gt;                 Object keyToRemove = null;
&gt;                 CompositeCache cache = CompositeCacheManager.getInstance().getCache(cacheName);
&gt;                 // A String key was supplied, but to remove elements via the RemoteCacheServer
API, we need the
&gt;                 // actual key object as stored in the cache (i.e. a Serializable object).
To find the key in this form,
&gt;                 // we iterate through all keys stored in the memory cache until we find
one whose toString matches
&gt;                 // the string supplied...
&gt;                 Object[] allKeysInCache = cache.getMemoryCache().getKeyArray();
&gt;                 for (int i = 0; i &lt; allKeysInCache.length; i++) {
&gt;                     Object keyInCache = allKeysInCache[i];
&gt;                     if (keyInCache.toString().equals(key)) {
&gt;                         if (keyToRemove == null) {
&gt;                             keyToRemove = keyInCache;
&gt;                         }
&gt;                         else {
&gt;                             // A key matching the one specified was already found...
&gt;                             throw new IllegalStateException("Unexpectedly found duplicate
keys in the cache region matching the key specified.");
&gt;                         }
&gt;                     }
&gt;                 }
&gt;                 if (keyToRemove == null) {
&gt;                     throw new IllegalStateException("No match for this key could be found
in the set of keys retrieved from the memory cache.");
&gt;                 }
&gt;                 if (!(keyToRemove instanceof Serializable)) {
&gt;                     throw new IllegalStateException("Found key [" + keyToRemove + ",
" + keyToRemove.getClass() + "] in cache matching key specified, however key found in cache
is unexpectedly not serializable.");
&gt;                 }
&gt;                 // At this point, we have retrieved the matching Serializable key.
&gt;                 // Call remoteCacheServer.remove(String, Serializable)...
&gt;                 // Note: We must fo this using reflection to bypass its package-private
access...
&gt;                 Object remoteCacheServerObject = RemoteCacheServerFactory.getRemoteCacheServer();
&gt;                 Method removeMethod = remoteCacheServerObject.getClass().getMethod("remove",
new Class[]{String.class, Serializable.class});
&gt;                 boolean previouslyAccessibility = removeMethod.isAccessible();
&gt;                 removeMethod.setAccessible(true);
&gt;                 removeMethod.invoke(remoteCacheServerObject, new Object[]{cacheName,
keyToRemove});
&gt;                 removeMethod.setAccessible(previouslyAccessibility);
&gt;             }
&gt;             catch (Exception e) {
&gt;                 throw new IllegalStateException("Failed to remove element with key ["
+ key + ", " + key.getClass() + "] from cache region [" + cacheName + "]: " + e, e);
&gt;             }
&gt;         }
&gt;     }

-- 
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-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jcs-dev-help@jakarta.apache.org



</pre>
</div>
</content>
</entry>
<entry>
<title>[jira] Commented: (JCS-68) Admin.jsp on remote cache server does not broadcast removes - patch</title>
<author><name>&quot;Niall Gallagher (JIRA)&quot; &lt;jira@apache.org&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200908.mbox/%3c545402384.1251479792708.JavaMail.jira@brutus%3e"/>
<id>urn:uuid:%3c545402384-1251479792708-JavaMail-jira@brutus%3e</id>
<updated>2009-08-28T17:16:32Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>

    [ https://issues.apache.org/jira/browse/JCS-68?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&amp;focusedCommentId=12748906#action_12748906
] 

Niall Gallagher commented on JCS-68:
------------------------------------

FYI we updated the getByteCount method in JCSAdminBean too. This is not strictly necessary
to fix the issue above, it's fixes a display issue only. The unmodified code wasn't accounting
for objects which were already serialized (which is always the case on the remote cache server).
This version accounts for objects which are already serialized...

    /**
     * Tries to estimate how much data is in a region. This is expensive. If there are any
non serializable objects in
     * the region or an error occurs, suppresses exceptions and returns 0.
     * &lt;p/&gt;
     *
     * @return int The size of the region in bytes.
     */
    public int getByteCount(CompositeCache cache) throws Exception {
        if (cache == null) {
            throw new IllegalArgumentException("The cache object specified was null.");
        }
        long size = 0;
        try {
            MemoryCache memCache = cache.getMemoryCache();

            Iterator iter = memCache.getIterator();
            while (iter.hasNext()) {

                Map.Entry nextMapEntry = (Map.Entry) iter.next();
                ICacheElement ice = (ICacheElement) nextMapEntry.getValue();

                if (ice instanceof CacheElementSerialized) {
                    size = size + ((CacheElementSerialized) ice).getSerializedValue().length;
                }
                else {
                    Serializable element = ice.getVal();

                    //CountingOnlyOutputStream: Keeps track of the number of bytes written
to it, but doesn't write them anywhere.
                    CountingOnlyOutputStream counter = new CountingOnlyOutputStream();
                    try {
                        ObjectOutputStream out = new ObjectOutputStream(counter);
                        out.writeObject(element);
                    }
                    catch (IOException e) {
                        throw new RuntimeException("IOException while trying to measure the
size of the cached element", e);
                    }
                    // 4 bytes lost for the serialization header
                    size = size + counter.getCount() - 4;
                }
            }
            if (size &gt; Integer.MAX_VALUE) {
                throw new IllegalStateException("The size of cache " + cache.getCacheName()
+ " (" + size + " bytes) is too large to be represented as an integer.");
            }
        }
        catch (Exception e) {
//            throw new RuntimeException("Failed to calculate the size of cache region ["
+ cache.getCacheName() + "]:" + e, e);
            return 0;
        }
        return (int) size;
    }


&gt; Admin.jsp on remote cache server does not broadcast removes - patch
&gt; -------------------------------------------------------------------
&gt;
&gt;                 Key: JCS-68
&gt;                 URL: https://issues.apache.org/jira/browse/JCS-68
&gt;             Project: JCS
&gt;          Issue Type: Bug
&gt;          Components: RMI Remote Cache
&gt;    Affects Versions: jcs-1.3, jcs-1.4-dev
&gt;         Environment: All
&gt;            Reporter: Niall Gallagher
&gt;            Assignee: Aaron Smuts
&gt;            Priority: Minor
&gt;   Original Estimate: 0.5h
&gt;  Remaining Estimate: 0.5h
&gt;
&gt; 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.
&gt; 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.
&gt; 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.
&gt; 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.
&gt; 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.
&gt; The fix involves replacing a 3 methods in org.apache.jcs.admin.JCSAdminBean with as follows:
&gt;     /**
&gt;      * Clears all regions in the cache.
&gt;      * &lt;p/&gt;
&gt;      * If this class is running within a remote cache server, clears all regions via
the &lt;code&gt;RemoteCacheServer&lt;/code&gt;
&gt;      * API, so that removes will be broadcast to client machines. Otherwise clears all
regions in the cache directly via
&gt;      * the usual cache API.
&gt;      */
&gt;     public void clearAllRegions() throws IOException {
&gt;         if (RemoteCacheServerFactory.getRemoteCacheServer() == null) {
&gt;             // Not running in a remote cache server.
&gt;             // Remove objects from the cache directly, as no need to broadcast removes
to client machines...
&gt;             String[] names = cacheHub.getCacheNames();
&gt;             for (int i = 0; i &lt; names.length; i++) {
&gt;                 cacheHub.getCache(names[i]).removeAll();
&gt;             }
&gt;         }
&gt;         else {
&gt;             // Running in a remote cache server.
&gt;             // Remove objects via the RemoteCacheServer API, so that removes will be
broadcast to client machines...
&gt;             try {
&gt;                 String[] cacheNames = CompositeCacheManager.getInstance().getCacheNames();
&gt;                 // Call remoteCacheServer.removeAll(String) for each cacheName...
&gt;                 // Note: We must do this using reflection to bypass its package-private
access...
&gt;                 Object remoteCacheServerObject = RemoteCacheServerFactory.getRemoteCacheServer();
&gt;                 Method removeAllMethod = remoteCacheServerObject.getClass().getMethod("removeAll",
new Class[]{String.class});
&gt;                 boolean previouslyAccessibility = removeAllMethod.isAccessible();
&gt;                 removeAllMethod.setAccessible(true);
&gt;                 for (int i = 0; i &lt; cacheNames.length; i++) {
&gt;                     String cacheName = cacheNames[i];
&gt;                     removeAllMethod.invoke(remoteCacheServerObject, new Object[]{cacheName});
&gt;                 }
&gt;                 removeAllMethod.setAccessible(previouslyAccessibility);
&gt;             }
&gt;             catch (Exception e) {
&gt;                 throw new IllegalStateException("Failed to remove all elements from all
cache regions: " + e, e);
&gt;             }
&gt;         }
&gt;     }
&gt;     /**
&gt;      * Clears a particular cache region.
&gt;      * &lt;p/&gt;
&gt;      * If this class is running within a remote cache server, clears the region via the
&lt;code&gt;RemoteCacheServer&lt;/code&gt;
&gt;      * API, so that removes will be broadcast to client machines. Otherwise clears the
region directly via the usual
&gt;      * cache API.
&gt;      */
&gt;     public void clearRegion(String cacheName) throws IOException {
&gt;         if (cacheName == null) {
&gt;             throw new IllegalArgumentException("The cache name specified was null.");
&gt;         }
&gt;         if (RemoteCacheServerFactory.getRemoteCacheServer() == null) {
&gt;             // Not running in a remote cache server.
&gt;             // Remove objects from the cache directly, as no need to broadcast removes
to client machines...
&gt;             cacheHub.getCache(cacheName).removeAll();
&gt;         }
&gt;         else {
&gt;             // Running in a remote cache server.
&gt;             // Remove objects via the RemoteCacheServer API, so that removes will be
broadcast to client machines...
&gt;             try {
&gt;                 // Call remoteCacheServer.removeAll(String)...
&gt;                 // Note: We must do this using reflection to bypass its package-private
access...
&gt;                 Object remoteCacheServerObject = RemoteCacheServerFactory.getRemoteCacheServer();
&gt;                 Method removeAllMethod = remoteCacheServerObject.getClass().getMethod("removeAll",
new Class[]{String.class});
&gt;                 boolean previouslyAccessibility = removeAllMethod.isAccessible();
&gt;                 removeAllMethod.setAccessible(true);
&gt;                 removeAllMethod.invoke(remoteCacheServerObject, new Object[]{cacheName});
&gt;                 removeAllMethod.setAccessible(previouslyAccessibility);
&gt;             }
&gt;             catch (Exception e) {
&gt;                 throw new IllegalStateException("Failed to remove all elements from cache
region [" + cacheName + "]: " + e, e);
&gt;             }
&gt;         }
&gt;     }
&gt;     /**
&gt;      * Removes a particular item from a particular region.
&gt;      * &lt;p/&gt;
&gt;      * If this class is running within a remote cache server, removes the item via the
&lt;code&gt;RemoteCacheServer&lt;/code&gt;
&gt;      * API, so that removes will be broadcast to client machines. Otherwise clears the
region directly via the usual
&gt;      * cache API.
&gt;      *
&gt;      * @param cacheName
&gt;      * @param key
&gt;      *
&gt;      * @throws IOException
&gt;      */
&gt;     public void removeItem(String cacheName, String key) throws IOException {
&gt;         if (cacheName == null) {
&gt;             throw new IllegalArgumentException("The cache name specified was null.");
&gt;         }
&gt;         if (key == null) {
&gt;             throw new IllegalArgumentException("The key specified was null.");
&gt;         }
&gt;         if (RemoteCacheServerFactory.getRemoteCacheServer() == null) {
&gt;             // Not running in a remote cache server.
&gt;             // Remove objects from the cache directly, as no need to broadcast removes
to client machines...
&gt;             cacheHub.getCache(cacheName).remove(key);
&gt;         }
&gt;         else {
&gt;             // Running in a remote cache server.
&gt;             // Remove objects via the RemoteCacheServer API, so that removes will be
broadcast to client machines...
&gt;             try {
&gt;                 Object keyToRemove = null;
&gt;                 CompositeCache cache = CompositeCacheManager.getInstance().getCache(cacheName);
&gt;                 // A String key was supplied, but to remove elements via the RemoteCacheServer
API, we need the
&gt;                 // actual key object as stored in the cache (i.e. a Serializable object).
To find the key in this form,
&gt;                 // we iterate through all keys stored in the memory cache until we find
one whose toString matches
&gt;                 // the string supplied...
&gt;                 Object[] allKeysInCache = cache.getMemoryCache().getKeyArray();
&gt;                 for (int i = 0; i &lt; allKeysInCache.length; i++) {
&gt;                     Object keyInCache = allKeysInCache[i];
&gt;                     if (keyInCache.toString().equals(key)) {
&gt;                         if (keyToRemove == null) {
&gt;                             keyToRemove = keyInCache;
&gt;                         }
&gt;                         else {
&gt;                             // A key matching the one specified was already found...
&gt;                             throw new IllegalStateException("Unexpectedly found duplicate
keys in the cache region matching the key specified.");
&gt;                         }
&gt;                     }
&gt;                 }
&gt;                 if (keyToRemove == null) {
&gt;                     throw new IllegalStateException("No match for this key could be found
in the set of keys retrieved from the memory cache.");
&gt;                 }
&gt;                 if (!(keyToRemove instanceof Serializable)) {
&gt;                     throw new IllegalStateException("Found key [" + keyToRemove + ",
" + keyToRemove.getClass() + "] in cache matching key specified, however key found in cache
is unexpectedly not serializable.");
&gt;                 }
&gt;                 // At this point, we have retrieved the matching Serializable key.
&gt;                 // Call remoteCacheServer.remove(String, Serializable)...
&gt;                 // Note: We must fo this using reflection to bypass its package-private
access...
&gt;                 Object remoteCacheServerObject = RemoteCacheServerFactory.getRemoteCacheServer();
&gt;                 Method removeMethod = remoteCacheServerObject.getClass().getMethod("remove",
new Class[]{String.class, Serializable.class});
&gt;                 boolean previouslyAccessibility = removeMethod.isAccessible();
&gt;                 removeMethod.setAccessible(true);
&gt;                 removeMethod.invoke(remoteCacheServerObject, new Object[]{cacheName,
keyToRemove});
&gt;                 removeMethod.setAccessible(previouslyAccessibility);
&gt;             }
&gt;             catch (Exception e) {
&gt;                 throw new IllegalStateException("Failed to remove element with key ["
+ key + ", " + key.getClass() + "] from cache region [" + cacheName + "]: " + e, e);
&gt;             }
&gt;         }
&gt;     }

-- 
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-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jcs-dev-help@jakarta.apache.org



</pre>
</div>
</content>
</entry>
<entry>
<title>[jira] Created: (JCS-68) Admin.jsp on remote cache server does not broadcast removes - patch</title>
<author><name>&quot;Niall Gallagher (JIRA)&quot; &lt;jira@apache.org&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200908.mbox/%3c1354234808.1251479312789.JavaMail.jira@brutus%3e"/>
<id>urn:uuid:%3c1354234808-1251479312789-JavaMail-jira@brutus%3e</id>
<updated>2009-08-28T17:08:32Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>
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


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 a 3 methods in org.apache.jcs.admin.JCSAdminBean with as follows:

    /**
     * Clears all regions in the cache.
     * &lt;p/&gt;
     * If this class is running within a remote cache server, clears all regions via the &lt;code&gt;RemoteCacheServer&lt;/code&gt;
     * 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 &lt; 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 &lt; 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.
     * &lt;p/&gt;
     * If this class is running within a remote cache server, clears the region via the &lt;code&gt;RemoteCacheServer&lt;/code&gt;
     * 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.
     * &lt;p/&gt;
     * If this class is running within a remote cache server, removes the item via the &lt;code&gt;RemoteCacheServer&lt;/code&gt;
     * 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 &lt; 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-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jcs-dev-help@jakarta.apache.org



</pre>
</div>
</content>
</entry>
<entry>
<title>Re: [ERROR] JDBCDiskCache - java.io.StreamCorruptedException: invalid stream header</title>
<author><name>Vishal Sinha &lt;vishal_sinha21@yahoo.com&gt;</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200908.mbox/%3c25156423.post@talk.nabble.com%3e"/>
<id>urn:uuid:%3c25156423-post@talk-nabble-com%3e</id>
<updated>2009-08-26T20:00:50Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>

I faced the same problem and finally it was resolved by changing the oracle
driver. I replaced mine with a newer version and it worked! I was not able
to find out what exactly changed in the newer version that made it work, I
suspect it might be the jdk version difference or may be the default charset
for these drivers has changed, not sure what but I am really curious to find
it out.

Here are version details of these drivers (jars attached):

Working:

Manifest-Version: 1.0
Specification-Title:    Oracle JDBC driver classes for use with JDK14
Sealed: false
Created-By: 1.4.2_08 (Sun Microsystems Inc.)
Implementation-Title:   ojdbc14.jar
Specification-Vendor:   Oracle Corporation
Specification-Version:  Oracle JDBC Driver version - "10.2.0.3.0"
Implementation-Version: Oracle JDBC Driver version - "10.2.0.3.0"
Implementation-Vendor:  Oracle Corporation
Implementation-Time:    Fri Sep 29 09:43:24 2006

Name: oracle/sql/converter/
Sealed: false

Name: oracle/sql/
Sealed: false

Name: oracle/sql/converter_xcharset/
Sealed: false

 
Not Working:

Manifest-Version: 1.0
Implementation-Version: "Oracle JDBC Driver version - 10.1.0.2.0"
Specification-Title:    "Oracle JDBC driver classes for use with JDK1.
 4"
Specification-Version:  "Oracle JDBC Driver version - 10.1.0.2.0"
Implementation-Title:   "ojdbc14.jar"
Created-By: 1.2.2 (Sun Microsystems Inc.)
Implementation-Time:    "Wed Jan 21 00:48:12 2004"
Implementation-Vendor:  "Oracle Corporation"
Specification-Vendor:   "Oracle Corporation" 

Regards
Vishal Sinha

-- 
View this message in context: http://www.nabble.com/-ERROR--JDBCDiskCache---java.io.StreamCorruptedException%3A-invalid-stream-header-tp11169850p25156423.html
Sent from the JCS - Dev mailing list archive at Nabble.com.


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



</pre>
</div>
</content>
</entry>
<entry>
<title>svn commit: r803719 - in /jakarta/jcs/trunk/src/java/org/apache/jcs: access/ access/behavior/ access/exception/ engine/match/ utils/props/</title>
<author><name>asmuts@apache.org</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200908.mbox/%3c20090812214145.2167523888BB@eris.apache.org%3e"/>
<id>urn:uuid:%3c20090812214145-2167523888BB@eris-apache-org%3e</id>
<updated>2009-08-12T21:41:44Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>
Author: asmuts
Date: Wed Aug 12 21:41:44 2009
New Revision: 803719

URL: http://svn.apache.org/viewvc?rev=803719&amp;view=rev
Log:
Added a rough sketch of a partitioned cache access.  I changed the get multiple to return
a Map and not a HashMap.  Unfortunately, this may break some client.  I hate to do this, but
it's a trivial fix.

Added:
    jakarta/jcs/trunk/src/java/org/apache/jcs/access/PartitionedCacheAccess.java
    jakarta/jcs/trunk/src/java/org/apache/jcs/access/exception/ConfigurationException.java
    jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/AbstractPropertyContainer.java
    jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/PropertiesFactory.java
    jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/PropertiesFactoryFileImpl.java
Modified:
    jakarta/jcs/trunk/src/java/org/apache/jcs/access/CacheAccess.java
    jakarta/jcs/trunk/src/java/org/apache/jcs/access/behavior/ICacheAccess.java
    jakarta/jcs/trunk/src/java/org/apache/jcs/access/exception/CacheException.java
    jakarta/jcs/trunk/src/java/org/apache/jcs/engine/match/KeyMatcherPatternImpl.java

Modified: jakarta/jcs/trunk/src/java/org/apache/jcs/access/CacheAccess.java
URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/access/CacheAccess.java?rev=803719&amp;r1=803718&amp;r2=803719&amp;view=diff
==============================================================================
--- jakarta/jcs/trunk/src/java/org/apache/jcs/access/CacheAccess.java (original)
+++ jakarta/jcs/trunk/src/java/org/apache/jcs/access/CacheAccess.java Wed Aug 12 21:41:44
2009
@@ -200,7 +200,7 @@
      * @param pattern - a key pattern for the objects stored
      * @return A map of key to values.  These are stripped from the wrapper.
      */
-    public HashMap getMatching( String pattern )
+    public Map getMatching( String pattern )
     {
         HashMap unwrappedResults = new HashMap();
         

Added: jakarta/jcs/trunk/src/java/org/apache/jcs/access/PartitionedCacheAccess.java
URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/access/PartitionedCacheAccess.java?rev=803719&amp;view=auto
==============================================================================
--- jakarta/jcs/trunk/src/java/org/apache/jcs/access/PartitionedCacheAccess.java (added)
+++ jakarta/jcs/trunk/src/java/org/apache/jcs/access/PartitionedCacheAccess.java Wed Aug 12
21:41:44 2009
@@ -0,0 +1,737 @@
+package org.apache.jcs.access;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.jcs.JCS;
+import org.apache.jcs.access.behavior.ICacheAccess;
+import org.apache.jcs.access.exception.CacheException;
+import org.apache.jcs.access.exception.ConfigurationException;
+import org.apache.jcs.engine.behavior.ICacheElement;
+import org.apache.jcs.engine.behavior.ICompositeCacheAttributes;
+import org.apache.jcs.engine.behavior.IElementAttributes;
+import org.apache.jcs.utils.props.AbstractPropertyContainer;
+
+/**
+ * TODO:  Add new methods that will allow you to provide a partition indicator for all major
calls.  Add an interface as well.
+ * &lt;p&gt;
+ * This handles dividing puts and gets.
+ * &lt;p&gt;
+ * There are two required properties.
+ * &lt;p&gt;
+ * &lt;ol&gt;
+ * &lt;li&gt;.numberOfPartitions&lt;/li&gt;
+ * &lt;li&gt;.partitionRegionNamePrefix&lt;/li&gt;
+ * &lt;/ol&gt;
+ * System properties will override values in the properties file.
+ * &lt;p&gt;
+ * We use a JCS region name for each partition that looks like this: partitionRegionNamePrefix
+ "_"
+ * + patitionNuber. The number is ) indexed based.
+ * &lt;p&gt;
+ * @author Aaron Smuts
+ */
+public class PartitionedCacheAccess
+    extends AbstractPropertyContainer
+    implements ICacheAccess
+{
+    /** the logger. */
+    private static final Log log = LogFactory.getLog( PartitionedCacheAccess.class );
+
+    /** The number of partitions. */
+    private int numberOfPartitions = 1;
+
+    /**
+     * We use a JCS region name for each partition that looks like this: partitionRegionNamePrefix
+
+     * "_" + partitionNumber
+     */
+    private String partitionRegionNamePrefix;
+
+    /** An array of partitions built during initialization. */
+    private ICacheAccess[] partitions;
+
+    /** Is the class initialized. */
+    private boolean initialized = false;
+
+    /** Sets default properties heading and group. */
+    public PartitionedCacheAccess()
+    {
+        setPropertiesHeading( "PartitionedCacheAccess" );
+        setPropertiesGroup( "cache" );
+    }
+
+    /**
+     * Puts the value into the appropriate cache partition.
+     * &lt;p&gt;
+     * @param key key
+     * @param object object
+     * @throws CacheException on configuration problem
+     */
+    public void put( Object key, Object object )
+        throws CacheException
+    {
+        if ( key == null || object == null )
+        {
+            log.warn( "Bad input key [" + key + "].  Cannot put null into the cache." );
+            return;
+        }
+        ensureInit();
+
+        int partition = getPartitionNumberForKey( key );
+        try
+        {
+            partitions[partition].put( key, object );
+        }
+        catch ( CacheException e )
+        {
+            log.error( "Problem putting value for key [" + key + "] in cache [" + partitions[partition]
+ "]" );
+            throw ( e );
+        }
+    }
+
+    /**
+     * Puts in cache if an item does not exist with the name in that region.
+     * &lt;p&gt;
+     * @param key
+     * @param object
+     * @throws CacheException
+     */
+    public void putSafe( Object key, Object object )
+        throws CacheException
+    {
+        if ( key == null || object == null )
+        {
+            log.warn( "Bad input key [" + key + "].  Cannot putSafe null into the cache."
);
+        }
+        ensureInit();
+
+        int partition = getPartitionNumberForKey( key );
+        partitions[partition].putSafe( key, object );
+    }
+
+    /**
+     * Puts the value into the appropriate cache partition.
+     * &lt;p&gt;
+     * @param key key
+     * @param object object
+     * @param attr
+     * @throws CacheException on configuration problem
+     */
+    public void put( Object key, Object object, IElementAttributes attr )
+        throws CacheException
+    {
+        if ( key == null || object == null )
+        {
+            log.warn( "Bad input key [" + key + "].  Cannot put null into the cache." );
+            return;
+        }
+        ensureInit();
+
+        int partition = getPartitionNumberForKey( key );
+        try
+        {
+            partitions[partition].put( key, object, attr );
+        }
+        catch ( CacheException e )
+        {
+            log.error( "Problem putting value for key [" + key + "] in cache [" + partitions[partition]
+ "]" );
+            throw ( e );
+        }
+    }
+
+    /**
+     * Gets the object for the key from the desired partition.
+     * &lt;p&gt;
+     * @param key key
+     * @return result, null if not found.
+     */
+    public Object get( Object key )
+    {
+        if ( key == null )
+        {
+            log.warn( "Bad input key [" + key + "]." );
+            return null;
+        }
+        try
+        {
+            ensureInit();
+        }
+        catch ( ConfigurationException e )
+        {
+            // TODO add exception to interface method.
+            log.error( "Couldn't configure partioned access.", e );
+            return null;
+        }
+
+        int partition = getPartitionNumberForKey( key );
+
+        return partitions[partition].get( key );
+    }
+
+    /**
+     * Gets the ICacheElement (the wrapped object) for the key from the desired partition.
+     * &lt;p&gt;
+     * @param key key
+     * @return result, null if not found.
+     */
+    public ICacheElement getCacheElement( Object key )
+    {
+        if ( key == null )
+        {
+            log.warn( "Bad input key [" + key + "]." );
+            return null;
+        }
+        try
+        {
+            ensureInit();
+        }
+        catch ( ConfigurationException e )
+        {
+            // TODO add exception to interface method.
+            log.error( "Couldn't configure partioned access.", e );
+            return null;
+        }
+
+        int partition = getPartitionNumberForKey( key );
+
+        return partitions[partition].getCacheElement( key );
+    }
+
+    /**
+     * This is a getMultiple. We try to group the keys so that we make as few calls as needed.
+     * &lt;p&gt;
+     * @param names
+     * @return Map of keys to ICacheElement
+     */
+    public Map getCacheElements( Set names )
+    {
+        if ( names == null )
+        {
+            log.warn( "Bad input names cannot be null." );
+            return Collections.EMPTY_MAP;
+        }
+
+        Set[] dividedNames = new Set[this.getNumberOfPartitions()];
+
+        Iterator it = names.iterator();
+        while ( it.hasNext() )
+        {
+            Object key = it.next();
+            int partition = getPartitionNumberForKey( key );
+            if ( dividedNames[partition] == null )
+            {
+                dividedNames[partition] = new HashSet();
+            }
+            dividedNames[partition].add( key );
+        }
+
+        Map result = new HashMap();
+        for ( int i = 0; i &lt; partitions.length; i++ )
+        {
+            if ( dividedNames[i] != null &amp;&amp; !dividedNames[i].isEmpty() )
+            {
+                result.putAll( partitions[i].getCacheElements( dividedNames[i] ) );
+            }
+        }
+        return result;
+    }
+
+    /**
+     * This is tricky. Do we need to get from all the partitions?
+     * &lt;p&gt;
+     * If this interface took an object, we could use the hashcode to determine the partition.
Then
+     * we could user the toString for the pattern.
+     * &lt;p&gt;
+     * @param pattern
+     * @return HashMap key to value
+     */
+    public Map getMatching( String pattern )
+    {
+        if ( pattern == null )
+        {
+            log.warn( "Bad input keypattern [" + pattern + "]." );
+            return null;
+        }
+        try
+        {
+            ensureInit();
+        }
+        catch ( ConfigurationException e )
+        {
+            // TODO add exception to interface method.
+            log.error( "Couldn't configure partioned access.", e );
+            return null;
+        }
+
+        Map result = new HashMap();
+        for ( int i = 0; i &lt; partitions.length; i++ )
+        {
+            result.putAll( partitions[i].getMatching( pattern ) );
+        }
+        return result;
+    }
+    
+    /**
+     * This is tricky. Do we need to get from all the partitions?
+     * &lt;p&gt;
+     * @param pattern
+     * @return HashMap key to ICacheElement
+     */
+    public Map getMatchingCacheElements( String pattern )
+    {
+        if ( pattern == null )
+        {
+            log.warn( "Bad input keypattern [" + pattern + "]." );
+            return null;
+        }
+        try
+        {
+            ensureInit();
+        }
+        catch ( ConfigurationException e )
+        {
+            // TODO add exception to interface method.
+            log.error( "Couldn't configure partioned access.", e );
+            return null;
+        }
+
+        Map result = new HashMap();
+        for ( int i = 0; i &lt; partitions.length; i++ )
+        {
+            result.putAll( partitions[i].getMatchingCacheElements( pattern ) );
+        }
+        return result;
+    }
+
+    /**
+     * Calls remove on all partitions. This gets translated into a removeAll call.
+     * &lt;p&gt;
+     * @throws CacheException
+     */
+    public void remove()
+        throws CacheException
+    {
+        ensureInit();
+
+        for ( int i = 0; i &lt; partitions.length; i++ )
+        {
+            partitions[i].remove();
+        }
+    }
+
+    /**
+     * Removes the item from the appropriate partition.
+     * &lt;p&gt;
+     * @param key
+     * @throws CacheException
+     */
+    public void remove( Object key )
+        throws CacheException
+    {
+        if ( key == null )
+        {
+            log.warn( "Bad input key [" + key + "].  Cannot remove null from the cache."
);
+            return;
+        }
+        ensureInit();
+
+        int partition = getPartitionNumberForKey( key );
+        try
+        {
+            partitions[partition].remove( key );
+        }
+        catch ( CacheException e )
+        {
+            log.error( "Problem removing value for key [" + key + "] in cache [" + partitions[partition]
+ "]" );
+            throw ( e );
+        }
+    }
+
+    /**
+     * Calls free on each partition.
+     * &lt;p&gt;
+     * @param numberToFree
+     * @return number removed
+     * @throws CacheException
+     */
+    public int freeMemoryElements( int numberToFree )
+        throws CacheException
+    {
+        ensureInit();
+
+        int count = 0;
+        for ( int i = 0; i &lt; partitions.length; i++ )
+        {
+            count += partitions[i].freeMemoryElements( numberToFree );
+        }
+        return count;
+    }
+
+    /**
+     * @return ICompositeCacheAttributes from the first partition.
+     */
+    public ICompositeCacheAttributes getCacheAttributes()
+    {
+        try
+        {
+            ensureInit();
+        }
+        catch ( ConfigurationException e )
+        {
+            // TODO add exception to interface method.
+            log.error( "Couldn't configure partioned access.", e );
+            return null;
+        }
+
+        if ( partitions.length == 0 )
+        {
+            return null;
+        }
+
+        return partitions[0].getCacheAttributes();
+    }
+
+    /**
+     * @return IElementAttributes from the first partition.
+     * @throws CacheException
+     */
+    public IElementAttributes getElementAttributes()
+        throws CacheException
+    {
+        ensureInit();
+
+        if ( partitions.length == 0 )
+        {
+            return null;
+        }
+
+        return partitions[0].getElementAttributes();
+    }
+
+    /**
+     * This is no more efficient than simply getting the cache element.
+     * &lt;p&gt;
+     * @param key
+     * @return IElementAttributes
+     * @throws CacheException
+     */
+    public IElementAttributes getElementAttributes( Object key )
+        throws CacheException
+    {
+        if ( key == null )
+        {
+            log.warn( "Bad input key [" + key + "].  Cannot getElementAttributes for null
from the cache." );
+            return null;
+        }
+        ensureInit();
+
+        int partition = getPartitionNumberForKey( key );
+
+        return partitions[partition].getElementAttributes( key );
+    }
+
+    /**
+     * Resets the default element attributes on all partitions. This does not change items
that are
+     * already in the cache.
+     * &lt;p&gt;
+     * @param attributes
+     * @throws CacheException
+     */
+    public void resetElementAttributes( IElementAttributes attributes )
+        throws CacheException
+    {
+        ensureInit();
+
+        for ( int i = 0; i &lt; partitions.length; i++ )
+        {
+            partitions[i].resetElementAttributes( attributes );
+        }
+    }
+
+    /**
+     * Resets the attributes for this item. This has the same effect as an update, in most
cases.
+     * None of the auxiliaries are optimized to do this more efficiently than a simply update.
+     * &lt;p&gt;
+     * @param key
+     * @param attributes
+     * @throws CacheException
+     */
+    public void resetElementAttributes( Object key, IElementAttributes attributes )
+        throws CacheException
+    {
+        if ( key == null )
+        {
+            log.warn( "Bad input key [" + key + "].  Cannot resetElementAttributes for null."
);
+            return;
+        }
+        ensureInit();
+
+        int partition = getPartitionNumberForKey( key );
+
+        partitions[partition].resetElementAttributes( key, attributes );
+    }
+
+    /**
+     * Sets the attributes on all the partitions.
+     * &lt;p&gt;
+     * @param cattr
+     */
+    public void setCacheAttributes( ICompositeCacheAttributes cattr )
+    {
+        try
+        {
+            ensureInit();
+        }
+        catch ( ConfigurationException e )
+        {
+            // TODO add exception to interface method.
+            log.error( "Couldn't configure partioned access.", e );
+            return;
+        }
+
+        for ( int i = 0; i &lt; partitions.length; i++ )
+        {
+            partitions[i].setCacheAttributes( cattr );
+        }
+    }
+
+    /**
+     * This expects a numeric key. If the key cannot be converted into a number, we wil return
0.
+     * TODO we could md5 it or get the hashcode.
+     * &lt;p&gt;
+     * We determine the partition by taking the mod of the number of partions.
+     * &lt;p&gt;
+     * @param key key
+     * @return the partition number.
+     */
+    protected int getPartitionNumberForKey( Object key )
+    {
+        if ( key == null )
+        {
+            return 0;
+        }
+
+        long keyNum = getNumericValueForKey( key );
+
+        int partition = (int) ( keyNum % getNumberOfPartitions() );
+
+        if ( log.isDebugEnabled() )
+        {
+            log.debug( "Using partition [" + partition + "] for key [" + key + "]" );
+        }
+
+        return partition;
+    }
+
+    /**
+     * This can be overridden for special purposes.
+     * &lt;p&gt;
+     * @param key key
+     * @return long
+     */
+    public long getNumericValueForKey( Object key )
+    {
+        String keyString = key.toString();
+        long keyNum = -1;
+        try
+        {
+            keyNum = Long.parseLong( keyString );
+        }
+        catch ( NumberFormatException e )
+        {
+            // THIS IS UGLY, but I can't think of a better failsafe right now.
+            keyNum = key.hashCode();
+            log.warn( "Counldn't convert [" + key + "] into a number.  Will use hashcode
[" + keyNum + "]" );
+        }
+        return keyNum;
+    }
+
+    /**
+     * Initialize if we haven't already.
+     * &lt;p&gt;
+     * @throws ConfigurationException on configuration problem
+     */
+    protected synchronized void ensureInit()
+        throws ConfigurationException
+    {
+        if ( !initialized )
+        {
+            initialize();
+        }
+    }
+
+    /**
+     * Use the partion prefix and the number of partions to get JCS regions.
+     * &lt;p&gt;
+     * @throws ConfigurationException on configuration problem
+     */
+    protected synchronized void initialize()
+        throws ConfigurationException
+    {
+        ensureProperties();
+
+        ICacheAccess[] tempPartitions = new ICacheAccess[this.getNumberOfPartitions()];
+        for ( int i = 0; i &lt; this.getNumberOfPartitions(); i++ )
+        {
+            String regionName = this.getPartitionRegionNamePrefix() + "_" + i;
+            try
+            {
+                tempPartitions[i] = CacheAccess.getAccess( regionName );
+            }
+            catch ( CacheException e )
+            {
+                log.error( "Problem getting cache for region [" + regionName + "]" );
+            }
+        }
+        partitions = tempPartitions;
+        initialized = true;
+    }
+
+    /**
+     * Loads in the needed configuration settings. System properties are checked first. A
system
+     * property will override local property value.
+     * &lt;p&gt;
+     * Loads the following JCS Cache specific properties:
+     * &lt;ul&gt;
+     * &lt;li&gt;heading.numberOfPartitions&lt;/li&gt;
+     * &lt;li&gt;heading.partitionRegionNamePrefix&lt;/li&gt;
+     * &lt;/ul&gt;
+     * @throws ConfigurationException on configuration problem
+     */
+    protected void handleProperties()
+        throws ConfigurationException
+    {
+        // Number of Partitions.
+        String numberOfPartitionsPropertyName = this.getPropertiesHeading() + ".numberOfPartitions";
+        String numberOfPartitionsPropertyValue = getPropertyForName( numberOfPartitionsPropertyName,
true );
+        try
+        {
+            this.setNumberOfPartitions( Integer.parseInt( numberOfPartitionsPropertyValue
) );
+        }
+        catch ( NumberFormatException e )
+        {
+            String message = "Could not convert [" + numberOfPartitionsPropertyValue + "]
into a number for ["
+                + numberOfPartitionsPropertyName + "]";
+            log.error( message );
+            throw new ConfigurationException( message );
+        }
+
+        // Partition Name Prefix.
+        String prefixPropertyName = this.getPropertiesHeading() + ".partitionRegionNamePrefix";
+        String prefix = getPropertyForName( prefixPropertyName, true );
+        this.setPartitionRegionNamePrefix( prefix );
+    }
+
+    /**
+     * Checks the system properties before the properties.
+     * &lt;p&gt;
+     * @param propertyName name
+     * @param required is it required?
+     * @return the property value if one is found
+     * @throws ConfigurationException thrown if it is required and not found.
+     */
+    protected String getPropertyForName( String propertyName, boolean required )
+        throws ConfigurationException
+    {
+        String propertyValue = null;
+        propertyValue = System.getProperty( propertyName );
+        if ( propertyValue != null )
+        {
+            if ( log.isInfoEnabled() )
+            {
+                log.info( "Found system property override: Name [" + propertyName + "] Value
[" + propertyValue + "]" );
+            }
+        }
+        else
+        {
+            propertyValue = this.getProperties().getProperty( propertyName );
+            if ( required &amp;&amp; propertyValue == null )
+            {
+                String message = "Could not find required property [" + propertyName + "]
in propertiesGroup ["
+                    + this.getPropertiesGroup() + "]";
+                log.error( message );
+                throw new ConfigurationException( message );
+            }
+            else
+            {
+                if ( log.isInfoEnabled() )
+                {
+                    log.info( "Name [" + propertyName + "] Value [" + propertyValue + "]"
);
+                }
+            }
+        }
+        return propertyValue;
+    }
+
+    /**
+     * @param numberOfPartitions The numberOfPartitions to set.
+     */
+    protected void setNumberOfPartitions( int numberOfPartitions )
+    {
+        this.numberOfPartitions = numberOfPartitions;
+    }
+
+    /**
+     * @return Returns the numberOfPartitions.
+     */
+    protected int getNumberOfPartitions()
+    {
+        return numberOfPartitions;
+    }
+
+    /**
+     * @param partitionRegionNamePrefix The partitionRegionNamePrefix to set.
+     */
+    protected void setPartitionRegionNamePrefix( String partitionRegionNamePrefix )
+    {
+        this.partitionRegionNamePrefix = partitionRegionNamePrefix;
+    }
+
+    /**
+     * @return Returns the partitionRegionNamePrefix.
+     */
+    protected String getPartitionRegionNamePrefix()
+    {
+        return partitionRegionNamePrefix;
+    }
+
+    /**
+     * @param partitions The partitions to set.
+     */
+    protected void setPartitions( JCS[] partitions )
+    {
+        this.partitions = partitions;
+    }
+
+    /**
+     * @return Returns the partitions.
+     */
+    protected ICacheAccess[] getPartitions()
+    {
+        return partitions;
+    }
+}

Modified: jakarta/jcs/trunk/src/java/org/apache/jcs/access/behavior/ICacheAccess.java
URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/access/behavior/ICacheAccess.java?rev=803719&amp;r1=803718&amp;r2=803719&amp;view=diff
==============================================================================
--- jakarta/jcs/trunk/src/java/org/apache/jcs/access/behavior/ICacheAccess.java (original)
+++ jakarta/jcs/trunk/src/java/org/apache/jcs/access/behavior/ICacheAccess.java Wed Aug 12
21:41:44 2009
@@ -19,7 +19,6 @@
  * under the License.
  */
 
-import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
 
@@ -45,10 +44,10 @@
      * Retrieve matching objects from the cache region this instance provides access to.
      * &lt;p&gt;
      * @param pattern - a key pattern for the objects stored
-     * @return A map of key to values.  These are stripped from the wrapper.
+     * @return A map of key to values. These are stripped from the wrapper.
      */
-    HashMap getMatching( String pattern );
-    
+    Map getMatching( String pattern );
+
     /**
      * Puts in cache if an item does not exist with the name in that region.
      * &lt;p&gt;
@@ -112,7 +111,8 @@
      * The last access time in the ElementAttributes should be current.
      * &lt;p&gt;
      * @param names set of Object cache keys
-     * @return a map of Object key to ICacheElement element, or empty map if none of the
keys are present
+     * @return a map of Object key to ICacheElement element, or empty map if none of the
keys are
+     *         present
      */
     Map getCacheElements( Set names );
 
@@ -131,19 +131,10 @@
      * The last access time in the ElementAttributes should be current.
      * &lt;p&gt;
      * @param pattern key search patern
-     * @return a map of Object key to ICacheElement element, or empty map if no keys match
the pattern
+     * @return a map of Object key to ICacheElement element, or empty map if no keys match
the
+     *         pattern
      */
     Map getMatchingCacheElements( String pattern );
-    
-    /**
-     * Removes an item or all items. Should be called remove.
-     * &lt;p&gt;
-     * @throws CacheException
-     * @deprecated
-     * @see #remove()
-     */
-    void destroy()
-        throws CacheException;
 
     /**
      * Old remove all method.
@@ -153,17 +144,6 @@
         throws CacheException;
 
     /**
-     * The older removeall method.
-     * &lt;p&gt;
-     * @param name
-     * @throws CacheException
-     * @deprecated
-     * @see #remove(Object)
-     */
-    void destroy( Object name )
-        throws CacheException;
-
-    /**
      * Remove an object for this key if one exists, else do nothing.
      * &lt;p&gt;
      * @param name
@@ -173,14 +153,13 @@
         throws CacheException;
 
     /**
-     * ResetAttributes allows for some of the attributes of a region to be reset
-     * in particular expiration time attriubtes, time to live, default time to
-     * live and idle time, and event handlers. The cacheloader object and
-     * attributes set as flags can't be reset with resetAttributes, the object
-     * must be destroyed and redefined to cache those parameters. Changing
-     * default settings on groups and regions will not affect existing objects.
-     * Only object loaded after the reset will use the new defaults. If no name
-     * argument is provided, the reset is applied to the region.
+     * ResetAttributes allows for some of the attributes of a region to be reset in particular
+     * expiration time attriubtes, time to live, default time to live and idle time, and
event
+     * handlers. The cacheloader object and attributes set as flags can't be reset with
+     * resetAttributes, the object must be destroyed and redefined to cache those parameters.
+     * Changing default settings on groups and regions will not affect existing objects.
Only object
+     * loaded after the reset will use the new defaults. If no name argument is provided,
the reset
+     * is applied to the region.
      * &lt;p&gt;
      * @param attributes
      * @throws CacheException
@@ -199,10 +178,10 @@
         throws CacheException;
 
     /**
-     * GetElementAttributes will return an attribute object describing the
-     * current attributes associated with the object name. If no name parameter
-     * is available, the attributes for the region will be returned. The name
-     * object must override the Object.equals and Object.hashCode methods.
+     * GetElementAttributes will return an attribute object describing the current attributes
+     * associated with the object name. If no name parameter is available, the attributes
for the
+     * region will be returned. The name object must override the Object.equals and Object.hashCode
+     * methods.
      * &lt;p&gt;
      * @return The elementAttributes value
      * @throws CacheException
@@ -230,20 +209,18 @@
     /**
      * Sets the ICompositeCacheAttributes of the cache region
      * &lt;p&gt;
-     * @param cattr
-     *            The new ICompositeCacheAttribute value
+     * @param cattr The new ICompositeCacheAttribute value
      */
     public void setCacheAttributes( ICompositeCacheAttributes cattr );
 
     /**
-     * This instructs the memory cache to remove the &lt;i&gt;numberToFree&lt;/i&gt;
-     * according to its eviction policy. For example, the LRUMemoryCache will
-     * remove the &lt;i&gt;numberToFree&lt;/i&gt; least recently used items. These will be
-     * spooled to disk if a disk auxiliary is available.
+     * This instructs the memory cache to remove the &lt;i&gt;numberToFree&lt;/i&gt; according
to its eviction
+     * policy. For example, the LRUMemoryCache will remove the &lt;i&gt;numberToFree&lt;/i&gt;
least recently
+     * used items. These will be spooled to disk if a disk auxiliary is available.
      * &lt;p&gt;
      * @param numberToFree
-     * @return the number that were removed. if you ask to free 5, but there are
-     *         only 3, you will get 3.
+     * @return the number that were removed. if you ask to free 5, but there are only 3,
you will
+     *         get 3.
      * @throws CacheException
      */
     public int freeMemoryElements( int numberToFree )

Modified: jakarta/jcs/trunk/src/java/org/apache/jcs/access/exception/CacheException.java
URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/access/exception/CacheException.java?rev=803719&amp;r1=803718&amp;r2=803719&amp;view=diff
==============================================================================
--- jakarta/jcs/trunk/src/java/org/apache/jcs/access/exception/CacheException.java (original)
+++ jakarta/jcs/trunk/src/java/org/apache/jcs/access/exception/CacheException.java Wed Aug
12 21:41:44 2009
@@ -57,5 +57,4 @@
     {
         super( message );
     }
-
 }

Added: jakarta/jcs/trunk/src/java/org/apache/jcs/access/exception/ConfigurationException.java
URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/access/exception/ConfigurationException.java?rev=803719&amp;view=auto
==============================================================================
--- jakarta/jcs/trunk/src/java/org/apache/jcs/access/exception/ConfigurationException.java
(added)
+++ jakarta/jcs/trunk/src/java/org/apache/jcs/access/exception/ConfigurationException.java
Wed Aug 12 21:41:44 2009
@@ -0,0 +1,25 @@
+package org.apache.jcs.access.exception;
+
+/** Thrown if there is some severe configuration problem that makes the cache nonfunctional.
*/
+public class ConfigurationException
+    extends CacheException
+{
+    /** Don't change. */
+    private static final long serialVersionUID = 6881044536186097055L;
+
+    /** Constructor for the ConfigurationException object */
+    public ConfigurationException()
+    {
+        super();
+    }
+
+    /**
+     * Constructor for the ConfigurationException object.
+     * &lt;p&gt;
+     * @param message
+     */
+    public ConfigurationException( String message )
+    {
+        super( message );
+    }
+}

Modified: jakarta/jcs/trunk/src/java/org/apache/jcs/engine/match/KeyMatcherPatternImpl.java
URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/engine/match/KeyMatcherPatternImpl.java?rev=803719&amp;r1=803718&amp;r2=803719&amp;view=diff
==============================================================================
--- jakarta/jcs/trunk/src/java/org/apache/jcs/engine/match/KeyMatcherPatternImpl.java (original)
+++ jakarta/jcs/trunk/src/java/org/apache/jcs/engine/match/KeyMatcherPatternImpl.java Wed
Aug 12 21:41:44 2009
@@ -28,6 +28,7 @@
         for ( int i = 0; i &lt; keyArray.length; i++ )
         {
             Object key = keyArray[i];
+            // TODO we might want to match on the toString.
             if ( key instanceof String )
             {
                 Matcher matcher = compiledPattern.matcher( (String) key );

Added: jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/AbstractPropertyContainer.java
URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/AbstractPropertyContainer.java?rev=803719&amp;view=auto
==============================================================================
--- jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/AbstractPropertyContainer.java (added)
+++ jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/AbstractPropertyContainer.java Wed
Aug 12 21:41:44 2009
@@ -0,0 +1,190 @@
+package org.apache.jcs.utils.props;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import java.util.Properties;
+
+import org.apache.jcs.access.exception.ConfigurationException;
+
+/**
+ * Provides a mechanism to load properties into objects.
+ * &lt;p&gt;
+ * Functions that depend on properties should call ensureProperties() before it uses any
properties.
+ */
+public abstract class AbstractPropertyContainer
+{
+    /** File, db, etc */
+    private static final PropertiesFactory DEFAULT_PROPERTIES_FACTORY = new PropertiesFactoryFileImpl();
+
+    /**
+     * A property group is a subsection of properties. It's sent to the properties factory
to
+     * specify which group of properties to pull back. This will probably mean different
things to
+     * different property factories. For PropertiesFactoryFileImpl, the propertiesGroup maps
to a
+     * filename.
+     */
+    private String propertiesGroup;
+
+    /**
+     * The property heading is used to specify a starting point in the properties object.
This is
+     * used so that settings can be relative to this propertiesHeading, as opposed to being
+     * statically coded. There's no enforcement of this, but users are encouraged to call
+     * getProperties().get( getPropertiesHeading() + ".foo" );
+     */
+    private String propertiesHeading;
+
+    /** The factory to use. */
+    private PropertiesFactory propertiesFactory;
+
+    /** The loaded properties. */
+    private Properties properties;
+
+    /**
+     * Makes sure an AbstractPropertyClass has all the properties it needs.
+     * &lt;p&gt;
+     * Synchronized mutators so multiple threads cannot cause problems. We wouldn't want
the
+     * properties heading to get changed as we were processing the properties.
+     * &lt;p&gt;
+     * @throws ConfigurationException on configuration failure
+     */
+    public synchronized void ensureProperties()
+        throws ConfigurationException
+    {
+        if ( getProperties() == null )
+        {
+            initializeProperties();
+        }
+    }
+
+    /**
+     * Loads the properties and then calls handleProperties. Typically, you don't need to
call this.
+     * This is primarily intended for reinitialization.
+     * &lt;p&gt;
+     * If the properties object is null, when you call ensureProperties initialize will be
called.
+     * &lt;p&gt;
+     * @throws ConfigurationException on configuration failure
+     */
+    public synchronized void initializeProperties()
+        throws ConfigurationException
+    {
+        loadProperties();
+
+        handleProperties();
+    }
+
+    /**
+     * This loads the properties regardless of whether or not they have already been loaded.
+     * &lt;p&gt;
+     * @throws ConfigurationException on configuration failure
+     */
+    private void loadProperties()
+        throws ConfigurationException
+    {
+        if ( getPropertiesGroup() == null )
+        {
+            throw new ConfigurationException( "Properties group is null and it shouldn't
be" );
+        }
+
+        if ( getPropertiesHeading() == null )
+        {
+            throw new ConfigurationException( "Properties heading is null and it shouldn't
be" );
+        }
+
+        if ( getPropertiesFactory() == null )
+        {
+            setProperties( DEFAULT_PROPERTIES_FACTORY.getProperties( getPropertiesGroup()
) );
+        }
+        else
+        {
+            setProperties( getPropertiesFactory().getProperties( getPropertiesGroup() ) );
+        }
+    }
+
+    /**
+     * Sets fields for properties, and verifies that all necessary properties are there.
+     * &lt;p&gt;
+     * @throws ConfigurationException on configuration failure
+     */
+    protected abstract void handleProperties()
+        throws ConfigurationException;
+
+    /**
+     * @return Returns the properties.
+     */
+    public Properties getProperties()
+    {
+        return properties;
+    }
+
+    /**
+     * @param properties The properties to set.
+     */
+    public synchronized void setProperties( Properties properties )
+    {
+        this.properties = properties;
+    }
+
+    /**
+     * @return Returns the propertiesHeading.
+     */
+    public String getPropertiesHeading()
+    {
+        return propertiesHeading;
+    }
+
+    /**
+     * @param propertiesHeading The propertiesHeading to set.
+     */
+    public synchronized void setPropertiesHeading( String propertiesHeading )
+    {
+        this.propertiesHeading = propertiesHeading;
+    }
+
+    /**
+     * @return Returns the propertiesFactory.
+     */
+    public PropertiesFactory getPropertiesFactory()
+    {
+        return propertiesFactory;
+    }
+
+    /**
+     * @param propertiesFactory The propertiesFactory to set.
+     */
+    public void setPropertiesFactory( PropertiesFactory propertiesFactory )
+    {
+        this.propertiesFactory = propertiesFactory;
+    }
+
+    /**
+     * @return Returns the propertiesGroup.
+     */
+    public String getPropertiesGroup()
+    {
+        return propertiesGroup;
+    }
+
+    /**
+     * @param propertiesGroup The propertiesGroup to set.
+     */
+    public void setPropertiesGroup( String propertiesGroup )
+    {
+        this.propertiesGroup = propertiesGroup;
+    }
+}

Added: jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/PropertiesFactory.java
URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/PropertiesFactory.java?rev=803719&amp;view=auto
==============================================================================
--- jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/PropertiesFactory.java (added)
+++ jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/PropertiesFactory.java Wed Aug 12
21:41:44 2009
@@ -0,0 +1,36 @@
+package org.apache.jcs.utils.props;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import java.util.Properties;
+
+/**
+ * Retrieves properties from a configurable source.
+ */
+public interface PropertiesFactory
+{
+    /**
+     * Fetches a set of properties for the specified group.
+     * &lt;p&gt;
+     * @param groupName the group to pull properties from.
+     * @return a properties object.
+     */
+    Properties getProperties( String groupName );
+}

Added: jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/PropertiesFactoryFileImpl.java
URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/PropertiesFactoryFileImpl.java?rev=803719&amp;view=auto
==============================================================================
--- jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/PropertiesFactoryFileImpl.java (added)
+++ jakarta/jcs/trunk/src/java/org/apache/jcs/utils/props/PropertiesFactoryFileImpl.java Wed
Aug 12 21:41:44 2009
@@ -0,0 +1,39 @@
+package org.apache.jcs.utils.props;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import java.util.Properties;
+
+/**
+ * Goes to the file system to load a properties file.
+ */
+public class PropertiesFactoryFileImpl
+    implements PropertiesFactory
+{
+    /**
+     * Loads the properties using the property loader.
+     * @param groupName property group name
+     * @return Properties
+     */
+    public Properties getProperties( String groupName )
+    {
+        return PropertyLoader.loadProperties( groupName );
+    }
+}



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



</pre>
</div>
</content>
</entry>
<entry>
<title>svn commit: r803539 - /jakarta/jcs/tempbuilds/jcs-1.3.3.5-RC.jar</title>
<author><name>asmuts@apache.org</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200908.mbox/%3c20090812143919.C20492388852@eris.apache.org%3e"/>
<id>urn:uuid:%3c20090812143919-C20492388852@eris-apache-org%3e</id>
<updated>2009-08-12T14:39:19Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>
Author: asmuts
Date: Wed Aug 12 14:39:19 2009
New Revision: 803539

URL: http://svn.apache.org/viewvc?rev=803539&amp;view=rev
Log:
Fixed bug (JCS-67) in the indexed disk cache. Partial key removal was adding duplicates in
the	recycle bin. This lead to the multiple keys pointing to the same spot on disk.

Added:
    jakarta/jcs/tempbuilds/jcs-1.3.3.5-RC.jar   (with props)

Added: jakarta/jcs/tempbuilds/jcs-1.3.3.5-RC.jar
URL: http://svn.apache.org/viewvc/jakarta/jcs/tempbuilds/jcs-1.3.3.5-RC.jar?rev=803539&amp;view=auto
==============================================================================
Binary file - no diff available.

Propchange: jakarta/jcs/tempbuilds/jcs-1.3.3.5-RC.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream



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



</pre>
</div>
</content>
</entry>
<entry>
<title>svn commit: r803538 - /jakarta/jcs/tags/JCS_1_3_3_5/</title>
<author><name>asmuts@apache.org</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200908.mbox/%3c20090812143758.DA4452388852@eris.apache.org%3e"/>
<id>urn:uuid:%3c20090812143758-DA4452388852@eris-apache-org%3e</id>
<updated>2009-08-12T14:37:58Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>
Author: asmuts
Date: Wed Aug 12 14:37:58 2009
New Revision: 803538

URL: http://svn.apache.org/viewvc?rev=803538&amp;view=rev
Log:
Fixed indexed disk cache problem where the partial key removal would add dupes to the recylebin.

Added:
    jakarta/jcs/tags/JCS_1_3_3_5/
      - copied from r803537, jakarta/jcs/trunk/


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



</pre>
</div>
</content>
</entry>
<entry>
<title>svn commit: r803536 - in /jakarta/jcs/trunk: pom.xml project.xml</title>
<author><name>asmuts@apache.org</name></author>
<link rel="alternate" href="http://mail-archives.apache.org/mod_mbox/jakarta-jcs-dev/200908.mbox/%3c20090812143705.2C37B23888D7@eris.apache.org%3e"/>
<id>urn:uuid:%3c20090812143705-2C37B23888D7@eris-apache-org%3e</id>
<updated>2009-08-12T14:37:05Z</updated>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<pre>
Author: asmuts
Date: Wed Aug 12 14:37:04 2009
New Revision: 803536

URL: http://svn.apache.org/viewvc?rev=803536&amp;view=rev
Log:
Increasing version for tag and tempbuild.

Modified:
    jakarta/jcs/trunk/pom.xml
    jakarta/jcs/trunk/project.xml

Modified: jakarta/jcs/trunk/pom.xml
URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/pom.xml?rev=803536&amp;r1=803535&amp;r2=803536&amp;view=diff
==============================================================================
--- jakarta/jcs/trunk/pom.xml (original)
+++ jakarta/jcs/trunk/pom.xml Wed Aug 12 14:37:04 2009
@@ -36,7 +36,7 @@
   &lt;groupId&gt;org.apache.jcs&lt;/groupId&gt;
   &lt;artifactId&gt;jcs&lt;/artifactId&gt;
   &lt;packaging&gt;pom&lt;/packaging&gt;
-  &lt;version&gt;1.3.3.4-RC&lt;/version&gt;
+  &lt;version&gt;1.3.3.5-RC&lt;/version&gt;
   &lt;name&gt;Jakarta JCS&lt;/name&gt;
   &lt;url&gt;http://jakarta.apache.org/jcs/&lt;/url&gt;
   &lt;inceptionYear&gt;2002&lt;/inceptionYear&gt;

Modified: jakarta/jcs/trunk/project.xml
URL: http://svn.apache.org/viewvc/jakarta/jcs/trunk/project.xml?rev=803536&amp;r1=803535&amp;r2=803536&amp;view=diff
==============================================================================
--- jakarta/jcs/trunk/project.xml (original)
+++ jakarta/jcs/trunk/project.xml Wed Aug 12 14:37:04 2009
@@ -17,7 +17,7 @@
 	&lt;pomVersion&gt;3&lt;/pomVersion&gt;
 	&lt;name&gt;JCS&lt;/name&gt;
 	&lt;id&gt;jcs&lt;/id&gt;
-	&lt;currentVersion&gt;1.3.3.4-RC&lt;/currentVersion&gt;
+	&lt;currentVersion&gt;1.3.3.5-RC&lt;/currentVersion&gt;
 	&lt;organization&gt;
 		&lt;name&gt;Apache Software Foundation&lt;/name&gt;
 		&lt;url&gt;http://jakarta.apache.org/&lt;/url&gt;



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



</pre>
</div>
</content>
</entry>
</feed>
