You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2006/07/31 21:29:08 UTC

svn commit: r427221 - in /incubator/cayenne/main/trunk/core/cayenne-jdk1.4-core/src: main/java/org/apache/cayenne/cache/OSQueryCache.java main/java/org/apache/cayenne/cache/OSQueryCacheFactory.java test/java/org/apache/cayenne/cache/OSQueryCacheTst.java

Author: aadamchik
Date: Mon Jul 31 12:29:07 2006
New Revision: 427221

URL: http://svn.apache.org/viewvc?rev=427221&view=rev
Log:
CAY-613 - support for per-query expiration policy

Added:
    incubator/cayenne/main/trunk/core/cayenne-jdk1.4-core/src/test/java/org/apache/cayenne/cache/OSQueryCacheTst.java
Modified:
    incubator/cayenne/main/trunk/core/cayenne-jdk1.4-core/src/main/java/org/apache/cayenne/cache/OSQueryCache.java
    incubator/cayenne/main/trunk/core/cayenne-jdk1.4-core/src/main/java/org/apache/cayenne/cache/OSQueryCacheFactory.java

Modified: incubator/cayenne/main/trunk/core/cayenne-jdk1.4-core/src/main/java/org/apache/cayenne/cache/OSQueryCache.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/core/cayenne-jdk1.4-core/src/main/java/org/apache/cayenne/cache/OSQueryCache.java?rev=427221&r1=427220&r2=427221&view=diff
==============================================================================
--- incubator/cayenne/main/trunk/core/cayenne-jdk1.4-core/src/main/java/org/apache/cayenne/cache/OSQueryCache.java (original)
+++ incubator/cayenne/main/trunk/core/cayenne-jdk1.4-core/src/main/java/org/apache/cayenne/cache/OSQueryCache.java Mon Jul 31 12:29:07 2006
@@ -18,11 +18,16 @@
  ****************************************************************/
 package org.apache.cayenne.cache;
 
+import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
+import java.util.Properties;
 
 import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.query.QueryMetadata;
 
+import com.opensymphony.oscache.base.CacheEntry;
 import com.opensymphony.oscache.base.NeedsRefreshException;
 import com.opensymphony.oscache.general.GeneralCacheAdministrator;
 
@@ -30,25 +35,129 @@
  * A {@link QueryCache} implementation based on OpenSymphony OSCache. Query cache
  * parameters are initialized from "/oscache.properties" file per <a
  * href="http://www.opensymphony.com/oscache/wiki/Configuration.html">OSCache</a>
- * documentation.
+ * documentation. In addition to the standard OSCache parameters, Cayenne provdier allows
+ * to setup global and per-query cache expiration parameters. A sample oscache.properties
+ * may look like this:
+ * 
+ * <pre>
+ *   # OSCache configuration file
+ *  
+ *   # OSCache standard configuration per
+ *   #     http://www.opensymphony.com/oscache/wiki/Configuration.html
+ *   # ---------------------------------------------------------------
+ *  
+ *   #cache.memory=true
+ *   cache.capacity=5000
+ *   cache.algorithm=com.opensymphony.oscache.base.algorithm.LRUCache
+ *  
+ *  
+ *   # Cayenne specific properties
+ *   # ---------------------------------------------------------------
+ *  
+ *   # Default refresh period in seconds:
+ *   cayenne.default.refresh = 60
+ *  
+ *   # Default expiry specified as cron expressions per
+ *   #    http://www.opensymphony.com/oscache/wiki/Cron%20Expressions.html
+ *   # expire entries every hour on the 10's minute
+ *   cayenne.default.cron = 10 * * * *
+ *  
+ *   # Same parameters can be overriden per query
+ *   cayenne.query.xyz.refresh = 120
+ *   cayenne.query.xyz.cron = 10 1 * * *
+ * </pre>
  * 
  * @since 3.0
  * @author Andrus Adamchik
  */
 public class OSQueryCache implements QueryCache {
 
+    public static final int DEFAULT_REFRESH_PERIOD = CacheEntry.INDEFINITE_EXPIRY;
+
+    static String DEFAULT_REFRESH_KEY = "cayenne.default.refresh";
+    static String DEFAULT_CRON_KEY = "cayenne.default.cron";
+
+    static String QUERY_PREFIX = "cayenne.query.";
+    static String REFRESH_SUFFIX = ".refresh";
+    static String CRON_SUFFIX = ".cron";
+
     protected GeneralCacheAdministrator cache;
-    protected int refreshPeriod;
-    protected String cronExpression;
 
-    public OSQueryCache(int refreshPeriod, String cronExpression) {
-        this(new GeneralCacheAdministrator(), refreshPeriod, cronExpression);
+    RefreshSpecification defaultRefreshSpecification;
+    Map refreshSpecifications;
+
+    public OSQueryCache() {
+        OSCacheAdministrator admin = new OSCacheAdministrator();
+        init(admin, admin.getProperties());
+    }
+
+    public OSQueryCache(Properties properties) {
+        init(new GeneralCacheAdministrator(), properties);
     }
 
-    OSQueryCache(GeneralCacheAdministrator cache, int refreshPeriod, String cronExpression) {
+    OSQueryCache(GeneralCacheAdministrator cache, Properties properties) {
+        init(cache, properties);
+    }
+
+    void init(GeneralCacheAdministrator cache, Properties properties) {
+
         this.cache = cache;
-        this.refreshPeriod = refreshPeriod;
-        this.cronExpression = cronExpression;
+        this.defaultRefreshSpecification = new RefreshSpecification();
+
+        // load defaults and per-query settings
+        if (properties != null) {
+            Iterator it = properties.entrySet().iterator();
+            while (it.hasNext()) {
+
+                Map.Entry entry = (Map.Entry) it.next();
+
+                if (entry.getKey() == null || entry.getValue() == null) {
+                    continue;
+                }
+
+                String key = entry.getKey().toString();
+                if (key.startsWith(QUERY_PREFIX)) {
+
+                    if (key.endsWith(REFRESH_SUFFIX)) {
+                        String name = key.substring(QUERY_PREFIX.length(), key.length()
+                                - REFRESH_SUFFIX.length());
+
+                        nonNullSpec(name).setRefreshPeriod(entry.getValue());
+                    }
+                    else if (key.endsWith(CRON_SUFFIX)) {
+                        String name = key.substring(QUERY_PREFIX.length(), key.length()
+                                - CRON_SUFFIX.length());
+
+                        nonNullSpec(name).cronExpression = entry.getValue().toString();
+                    }
+
+                }
+                else if (key.equals(DEFAULT_REFRESH_KEY)) {
+                    defaultRefreshSpecification.setRefreshPeriod(entry.getValue());
+                }
+                else if (key.equals(DEFAULT_CRON_KEY)) {
+                    defaultRefreshSpecification.cronExpression = entry
+                            .getValue()
+                            .toString();
+                }
+            }
+        }
+
+    }
+
+    private RefreshSpecification nonNullSpec(String name) {
+        if (refreshSpecifications == null) {
+            refreshSpecifications = new HashMap();
+        }
+
+        RefreshSpecification spec = (RefreshSpecification) refreshSpecifications
+                .get(name);
+        if (spec == null) {
+            spec = new RefreshSpecification();
+            refreshSpecifications.put(name, spec);
+        }
+
+        return spec;
     }
 
     public List get(QueryMetadata metadata) {
@@ -57,8 +166,21 @@
             return null;
         }
 
+        RefreshSpecification refresh = null;
+
+        if (refreshSpecifications != null) {
+            refresh = (RefreshSpecification) refreshSpecifications.get(key);
+        }
+
+        if (refresh == null) {
+            refresh = defaultRefreshSpecification;
+        }
+
         try {
-            return (List) cache.getFromCache(key, refreshPeriod, cronExpression);
+            return (List) cache.getFromCache(
+                    key,
+                    refresh.refreshPeriod,
+                    refresh.cronExpression);
         }
         catch (NeedsRefreshException e) {
             cache.cancelUpdate(key);
@@ -99,4 +221,43 @@
     public int size() {
         return cache.getCache().getSize();
     }
+
+    final static class RefreshSpecification {
+
+        int refreshPeriod;
+        String cronExpression;
+
+        RefreshSpecification() {
+            this.refreshPeriod = DEFAULT_REFRESH_PERIOD;
+        }
+
+        RefreshSpecification(int refrehsPeriod, String cronExpression) {
+            this.refreshPeriod = refrehsPeriod;
+            this.cronExpression = cronExpression;
+        }
+
+        void setRefreshPeriod(Object value) {
+            try {
+                refreshPeriod = Integer.parseInt(value.toString());
+            }
+            catch (NumberFormatException e) {
+                // ignore...
+            }
+        }
+    }
+
+    final class OSCacheAdministrator extends GeneralCacheAdministrator {
+
+        OSCacheAdministrator() {
+        }
+
+        OSCacheAdministrator(Properties properties) {
+            super(properties);
+        }
+
+        Properties getProperties() {
+            return super.config.getProperties();
+        }
+    }
+
 }

Modified: incubator/cayenne/main/trunk/core/cayenne-jdk1.4-core/src/main/java/org/apache/cayenne/cache/OSQueryCacheFactory.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/core/cayenne-jdk1.4-core/src/main/java/org/apache/cayenne/cache/OSQueryCacheFactory.java?rev=427221&r1=427220&r2=427221&view=diff
==============================================================================
--- incubator/cayenne/main/trunk/core/cayenne-jdk1.4-core/src/main/java/org/apache/cayenne/cache/OSQueryCacheFactory.java (original)
+++ incubator/cayenne/main/trunk/core/cayenne-jdk1.4-core/src/main/java/org/apache/cayenne/cache/OSQueryCacheFactory.java Mon Jul 31 12:29:07 2006
@@ -18,69 +18,22 @@
  ****************************************************************/
 package org.apache.cayenne.cache;
 
-import java.util.Collections;
 import java.util.Map;
 
-import com.opensymphony.oscache.base.CacheEntry;
-import com.opensymphony.oscache.general.GeneralCacheAdministrator;
-
 /**
- * A factory for the OSCache factory. A few extra properties in addition to what OSCache
- * supports can be read from "/oscache.properties" file. Those are
- * {@link OSQueryCacheFactory#OSCACHE_CRON_EXPRESSION_PROPERTY} and
- * {@link OSQueryCacheFactory#OSCACHE_REFRESH_PERIOD_PROPERTY}.
+ * A factory for the OSCache factory. "/oscache.properties" file is read to load the
+ * standard OSCache properties and also extra properties
  * 
  * @since 3.0
  * @author Andrus Adamchik
  */
 public class OSQueryCacheFactory implements QueryCacheFactory {
 
-    public static final String OSCACHE_REFRESH_PERIOD_PROPERTY = "cayenne.OSQueryCacheFactory.refresh";
-    public static final String OSCACHE_CRON_EXPRESSION_PROPERTY = "cayenne.OSQueryCacheFactory.cron";
-
-    protected OSQueryCache createCache(
-            GeneralCacheAdministrator cache,
-            int refreshPeriod,
-            String cronExpression) {
-        return new OSQueryCache(cache, refreshPeriod, cronExpression);
-    }
-
+    /**
+     * Creates QueryCache, ignoring provided properties, and reading data from
+     * "oscache.properties" file instead.
+     */
     public QueryCache getQueryCache(Map properties) {
-
-        int refreshPeriod = CacheEntry.INDEFINITE_EXPIRY;
-        String cronExpression = null;
-
-        // this code loads oscache.properties. Use it as a failover for Cayenne-specific
-        // properties.
-        GeneralCacheAdministrator cache = new GeneralCacheAdministrator();
-
-        if (properties == null) {
-            properties = Collections.EMPTY_MAP;
-        }
-
-        Object refreshPeriodProperty = properties.get(OSCACHE_REFRESH_PERIOD_PROPERTY);
-        if (refreshPeriodProperty == null) {
-            refreshPeriodProperty = cache.getProperty(OSCACHE_REFRESH_PERIOD_PROPERTY);
-        }
-
-        if (refreshPeriodProperty != null) {
-            try {
-                refreshPeriod = Integer.parseInt(refreshPeriodProperty.toString());
-            }
-            catch (NumberFormatException e) {
-                // ignore
-            }
-        }
-
-        Object cronExpressionProperty = properties.get(OSCACHE_CRON_EXPRESSION_PROPERTY);
-        if (cronExpressionProperty == null) {
-            cronExpressionProperty = cache.getProperty(OSCACHE_CRON_EXPRESSION_PROPERTY);
-        }
-
-        if (cronExpressionProperty != null) {
-            cronExpression = cronExpressionProperty.toString();
-        }
-
-        return createCache(cache, refreshPeriod, cronExpression);
+        return new OSQueryCache();
     }
 }

Added: incubator/cayenne/main/trunk/core/cayenne-jdk1.4-core/src/test/java/org/apache/cayenne/cache/OSQueryCacheTst.java
URL: http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/core/cayenne-jdk1.4-core/src/test/java/org/apache/cayenne/cache/OSQueryCacheTst.java?rev=427221&view=auto
==============================================================================
--- incubator/cayenne/main/trunk/core/cayenne-jdk1.4-core/src/test/java/org/apache/cayenne/cache/OSQueryCacheTst.java (added)
+++ incubator/cayenne/main/trunk/core/cayenne-jdk1.4-core/src/test/java/org/apache/cayenne/cache/OSQueryCacheTst.java Mon Jul 31 12:29:07 2006
@@ -0,0 +1,82 @@
+/*****************************************************************
+ *   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.
+ ****************************************************************/
+package org.apache.cayenne.cache;
+
+import java.util.Properties;
+
+import org.apache.cayenne.cache.OSQueryCache.RefreshSpecification;
+
+import junit.framework.TestCase;
+
+import com.opensymphony.oscache.base.CacheEntry;
+
+public class OSQueryCacheTst extends TestCase {
+
+    public void testDefaults() {
+        OSQueryCache cache = new OSQueryCache();
+
+        assertNull(cache.refreshSpecifications);
+        assertNull(cache.defaultRefreshSpecification.cronExpression);
+        assertEquals(
+                CacheEntry.INDEFINITE_EXPIRY,
+                cache.defaultRefreshSpecification.refreshPeriod);
+    }
+
+    public void testDefaultOverrides() {
+
+        Properties props = new Properties();
+        props.put(OSQueryCache.DEFAULT_REFRESH_KEY, "15");
+        props.put(OSQueryCache.DEFAULT_CRON_KEY, "9 * * * * *");
+        OSQueryCache cache = new OSQueryCache(props);
+
+        assertNull(cache.refreshSpecifications);
+        assertEquals("9 * * * * *", cache.defaultRefreshSpecification.cronExpression);
+        assertEquals(15, cache.defaultRefreshSpecification.refreshPeriod);
+    }
+
+    public void testQueryOverrides() {
+
+        Properties props = new Properties();
+        props.put(OSQueryCache.QUERY_PREFIX + "ABC" + OSQueryCache.REFRESH_SUFFIX, "25");
+        props.put(
+                OSQueryCache.QUERY_PREFIX + "ABC" + OSQueryCache.CRON_SUFFIX,
+                "12 * * * * *");
+        props.put(OSQueryCache.QUERY_PREFIX + "XYZ" + OSQueryCache.REFRESH_SUFFIX, "35");
+        props.put(
+                OSQueryCache.QUERY_PREFIX + "XYZ" + OSQueryCache.CRON_SUFFIX,
+                "24 * * * * *");
+
+        OSQueryCache cache = new OSQueryCache(props);
+
+        assertNotNull(cache.refreshSpecifications);
+        assertEquals(2, cache.refreshSpecifications.size());
+
+        RefreshSpecification abc = (RefreshSpecification) cache.refreshSpecifications
+                .get("ABC");
+        assertNotNull(abc);
+        assertEquals("12 * * * * *", abc.cronExpression);
+        assertEquals(25, abc.refreshPeriod);
+
+        RefreshSpecification xyz = (RefreshSpecification) cache.refreshSpecifications
+                .get("XYZ");
+        assertNotNull(xyz);
+        assertEquals("24 * * * * *", xyz.cronExpression);
+        assertEquals(35, xyz.refreshPeriod);
+    }
+}