Update of 
/var/cvs/applications/vpro-wizards/src/org/mmbase/applications/vprowizards/spring/cache
In directory 
james.mmbase.org:/tmp/cvs-serv1128/applications/vpro-wizards/src/org/mmbase/applications/vprowizards/spring/cache

Modified Files:
        OSCacheWrapper.java BasicCacheHandlerInterceptor.java 
        CacheHandlerInterceptor.java TokenizerCacheNameResolver.java 
        FlushNameTemplateBean.java 
Log Message:
quite some refactoring and testing done


See also: 
http://cvs.mmbase.org/viewcvs/applications/vpro-wizards/src/org/mmbase/applications/vprowizards/spring/cache


Index: OSCacheWrapper.java
===================================================================
RCS file: 
/var/cvs/applications/vpro-wizards/src/org/mmbase/applications/vprowizards/spring/cache/OSCacheWrapper.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- OSCacheWrapper.java 12 Nov 2008 14:52:56 -0000      1.1
+++ OSCacheWrapper.java 28 Nov 2008 20:20:48 -0000      1.2
@@ -9,8 +9,6 @@
 */ 
 package org.mmbase.applications.vprowizards.spring.cache;
 
-import javax.servlet.http.HttpServletRequest;
-
 import org.mmbase.module.core.MMBaseContext;
 
 import com.opensymphony.oscache.base.Cache;


Index: BasicCacheHandlerInterceptor.java
===================================================================
RCS file: 
/var/cvs/applications/vpro-wizards/src/org/mmbase/applications/vprowizards/spring/cache/BasicCacheHandlerInterceptor.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- BasicCacheHandlerInterceptor.java   12 Nov 2008 14:52:56 -0000      1.1
+++ BasicCacheHandlerInterceptor.java   28 Nov 2008 20:20:48 -0000      1.2
@@ -22,9 +22,18 @@
 import org.springframework.web.servlet.ModelAndView;
 
 /**
- *This is a cache handler interceptor that implements support for all types of 
cacheflush hints.
- *
+ * <pre>
+ *This is a cache handler intercepter that implements support for all types of 
cache flush hints.
+ *It works as following:
+ *- It creates a [EMAIL PROTECTED] Handling} instance for each type of cache 
flush hint.
+ *- It uses a class instance factory of type [EMAIL PROTECTED] 
CacheNameResolver} to generate a resolver instance.
+ *  The resolver is used to  transform the value of the 'flush name' parameter 
into a list of
+ *  flush names for a specific type of cache flush hint.
+ *- Any number of [EMAIL PROTECTED] Modifier}s can be registered to post 
process the resolved cache names. They are
+ *  applied in the order they are registered.
+ *- A [EMAIL PROTECTED] CacheWrapper} is used to handle the actual cache 
flushing
  *
+ *</pre>
  * @author ebunders
  *
  */


Index: CacheHandlerInterceptor.java
===================================================================
RCS file: 
/var/cvs/applications/vpro-wizards/src/org/mmbase/applications/vprowizards/spring/cache/CacheHandlerInterceptor.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- CacheHandlerInterceptor.java        12 Nov 2008 14:52:56 -0000      1.1
+++ CacheHandlerInterceptor.java        28 Nov 2008 20:20:48 -0000      1.2
@@ -20,10 +20,6 @@
 import org.springframework.web.servlet.ModelAndView;
 
 /**
- * Deze class is de basis voor verschillende CachFlushHandler implementaties.
- * Je kunt je eigen implementatie maken door deze class te extenden, en in de 
constructor Handling instanties
- * aan te maken voor de verschillende cache flush hints [EMAIL PROTECTED] 
CacheFlushHint}.
- * Je kunt eenvoudig Handling instanties maken door de methode handle() 
anoniem te overschijven.
  * @author ebunders
  *
  */


Index: TokenizerCacheNameResolver.java
===================================================================
RCS file: 
/var/cvs/applications/vpro-wizards/src/org/mmbase/applications/vprowizards/spring/cache/TokenizerCacheNameResolver.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- TokenizerCacheNameResolver.java     12 Nov 2008 14:52:56 -0000      1.1
+++ TokenizerCacheNameResolver.java     28 Nov 2008 20:20:48 -0000      1.2
@@ -21,18 +21,21 @@
 import org.mmbase.util.logging.Logging;
 
 /**
- * This class helps you to handle strings that are formatted in a certain way. 
The idea is that you have a comma
- * separated list of values attached to a namespace, like 
'namespace:value1,value2,value3'.<br>
- * the input string can contain more that one of these constructs for 
different namespaces, separated by a 
- * space. When using this class you have to give an input string, and then you 
can get values for different namespaces.
- * The input string will be parsed once.
+ * <pre>
  * 
+ * This class has a no-arg constructor so you can use it as a bean.
+ * It is reusable, but not thread safe.
+ * To see what kind of formats it can tokenize: [EMAIL PROTECTED] 
TokenizerCacheNameResolverTest}.
+ * The purpose of this class is to tokenize a cashflush command, where values 
can be grouped
+ * in names paces. Each name space could relate to a kind of cache flush hint 
[EMAIL PROTECTED] CacheFlushHint}.
+ * There is also support for templates. See: [EMAIL PROTECTED] 
FlushNameTemplateBean}
+ * </pre> 
  * @author ebunders
- * 
  */
 public class TokenizerCacheNameResolver implements CacheNameResolver {
 
     
+    
     private Map<String, List<String>> namesForNamespace = null;
     private List<String> globalValues;
     private String input = null;
@@ -45,17 +48,11 @@
     private static Logger log = 
Logging.getLoggerInstance(TokenizerCacheNameResolver.class);
 
 
-    /* (non-Javadoc)
-     * @see 
org.mmbase.applications.vprowizard.spring.cache.CacheNameResolver#getNamesForNamespace(java.lang.String)
-     */
     public List<String> getNames(String nameSpace) {
         if(StringUtils.isEmpty(nameSpace)) {
             throw new IllegalStateException("attribute namespace is empty");
         }
-        
-        if (namesForNamespace == null) {
-            tokenize();
-        }
+        tokenizeIfNecessary();
         List<String> result = new ArrayList<String>();
         if(namesForNamespace.get(nameSpace) != null){
             result.addAll(namesForNamespace.get(nameSpace));
@@ -64,9 +61,12 @@
         return result;
     }
     
-    /* (non-Javadoc)
-     * @see 
org.mmbase.applications.vprowizard.spring.cache.CacheNameResolver#setInput(java.lang.String)
-     */
+    private void tokenizeIfNecessary() {
+        if (namesForNamespace == null) {
+            tokenize();
+        }
+    }
+    
     public void setInput(String input) {
         reset();
         this.input = input;


Index: FlushNameTemplateBean.java
===================================================================
RCS file: 
/var/cvs/applications/vpro-wizards/src/org/mmbase/applications/vprowizards/spring/cache/FlushNameTemplateBean.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- FlushNameTemplateBean.java  12 Nov 2008 14:52:56 -0000      1.1
+++ FlushNameTemplateBean.java  28 Nov 2008 20:20:48 -0000      1.2
@@ -6,7 +6,7 @@
 The license (Mozilla version 1.0) can be read at the MMBase site.
 See http://www.MMBase.org/license
 
-*/ 
+ */
 package org.mmbase.applications.vprowizards.spring.cache;
 
 import java.util.StringTokenizer;
@@ -19,20 +19,33 @@
 import org.mmbase.util.logging.Logging;
 
 /**
- * This bean is used in the templates of the vpro-wizards. it is used to add 
node numbers to templates of flushnames. It
- * also has a method for cleaning the templates out of the flushnames. this is 
used by
- * [EMAIL PROTECTED] TokenizerCacheNameResolver}. For this reason it 
implements the Modifier interface.<br>
- * So, what are templates?<br>
- * Templates are a way to create dynamic cacheGroup names, where the dynamic 
bit is dependend on the node you are
- * currently editing, and are used by the list tag. You can use a flushname 
like, 'locations_[location]', where the
- * 'location' between brackets is the builder name. Inside the list tag the 
[buildername] part is then changed into [buildername:nodenumber]
- * where nodenumber is the number of each row (where the nodetype of the list 
matches the nodetype set in this bean).
- * This way the flushname parameter wil be differen for each row in the 
list.<br>
- * There is one variety, that you can use if you want to create a dynamic 
cache flush name for the parent node of the nodes in a certain list.
- * To do this you create a template like [thistype,role,parenttype]. Then the 
number of the first node found with this path (where thistype matches the
- * type set in this bean) will be inserted in the template.<br>
- * So why insert and not replace (the filtering out of the template is done 
just before using the flush names?<br>
  * 
+ * <pre>
+ * This bean is used in the templates of the vpro-wizards. it is used to add 
node numbers to templates inside flush names.
+ * It also has a method for cleaning the templates out of the flush names. For 
this reason it implements the Modifier 
+ * interface.
+ * 
+ * As arguments it takes a template string, a 
+ * 
+ * So, what are templates?
+ * 
+ * Templates are a way to create dynamic cacheGroup names, where the dynamic 
bit is dependent on the node you are
+ * currently editing, and are used by the list tag. 
+ * You can use a flush name like, 'locations_[location]', where the 'location' 
between brackets is the builder name.
+ *  
+ * Inside the list tag the [builder name] part is then changed into 
[buildername:nodenumber] where node number is the 
+ * number of each row (where the node type of the list matches the node type 
set in this bean). 
+ * This way the flush name parameter will be different for each row in the 
list.
+ * 
+ * There is one variety, that you can use if you want to create a dynamic 
cache flush name for the parent node of the
+ * nodes in a certain list. To do this you create a template like 
[this_type.relation_role.child_type]. Then the number of the
+ * first node found with this path (where this_type matches the type set in 
this bean) will be inserted in the template.
+ * 
+ * The original template is not replaced with the node number, but the node 
number is appended to the template. This is
+ * done because the template is handed to a (hierarchy of) jsp page(s), and is 
reused. with each reuse the previous node
+ * numbers are stripped out of the template.
+ * 
+ * </pre>
  * 
  * TODO:/to test the 'extended' template (where the parent node is found we 
need either a cloud or a cloud mock object
  * 
@@ -40,166 +53,222 @@
  * 
  */
 public class FlushNameTemplateBean implements Modifier {
+    private static final String TEMPLATE_REGEXP = 
"^.*\\[[a-zA-Z0-9\\.:]+\\].*$";
+
     private String template;
 
-    private String type;
+    private String nodeType;
 
-    private String nodenr;
+    private String nodeNumber;
 
     private Cloud cloud;
 
     private static final Logger log = 
Logging.getLoggerInstance(FlushNameTemplateBean.class);
 
-    /**
-     * this method processes the template and appends the nodenumber to all 
matching placeholders in the templates it
-     * also removes preveously added nodenumbers. (templates can be reused)
-     * 
-     * @return
-     */
-    public String getProcessedTemplate() {
-        if(StringUtils.isEmpty(template)) {
+    public void setCloud(Cloud cloud) {
+        this.cloud = cloud;
+    }
+
+
+    public void setNodeType(String type) {
+        this.nodeType = type;
+    }
+
+
+    public void setTemplate(String template) {
+        this.template = template;
+    }
+
+
+    public void setNodeNumber(String nodenr) {
+        this.nodeNumber = nodenr;
+    }
+
+
+    public String processAndGetTemplate() {
+        if (StringUtils.isEmpty(template)) {
             throw new IllegalStateException("template not set");
         }
         
-        if(StringUtils.isEmpty(nodenr)) {
+        if (StringUtils.isEmpty(nodeNumber)) {
             throw new IllegalStateException("nodenr not set");
         }
-        if(StringUtils.isEmpty(type)) {
+        if (StringUtils.isEmpty(nodeType)) {
             throw new IllegalStateException("type   not set");
         }
-        int from = 0;
-        while 
(template.substring(from).matches("^.*\\[[a-zA-Z0-9\\.:]+\\].*$")) {
-            // \\[[a-zA-Z0-9]+\\]
-            log.debug("evaluating: " + template.substring(from) + ", from: " + 
from);
-            int begin = template.indexOf("[", from);
-            int end = template.indexOf("]", from);
-            String t = template.substring(begin + 1, end);
-            log.debug("begin: " + begin + ", end: " + end + ", template: " + 
t);
-
-            // maybe this template was used before, in that case we have to 
clean the old value out of it
-            if (t.indexOf(":") > -1) {
-                t = t.substring(0, t.indexOf(":"));
-                log.debug("template reuse. after cleaning: " + t);
-            }
-
-            // is the template a path?
-            String thistype = null, relation = null, destination = null;
-            boolean isQuery = false;
-            if (t.indexOf(".") > -1) {
-                StringTokenizer st = new StringTokenizer(t, ".");
-                thistype = st.nextToken();
-                relation = st.nextToken();
-                destination = st.nextToken();
-                isQuery = true;
-            } else {
-                thistype = t;
+        
+        if (cloud == null) {
+            throw new IllegalStateException("cloud not set");
             }
 
-            // if the template matches the given type, add the node number
-            if (thistype.equals(type)) {
+        //we create a processor that will first strip the old node numbers, 
and then insert new ones.
+        processTemplate(new SubTemplateProcessor() {
+            @Override
+            void process() {
+                // Perhaps the template has been used before, and 'old' node 
numbers are present
+                // if this is so, they must be removed.
+                _subTemplate = stripNodenumberFromSubtemplate(_subTemplate);
 
-                // we copy the nodenumber field becouse if there are more 
templates then one we need the original again.
-                String copyNodeNumber = nodenr;
-                if (isQuery) {
-                    Node node = cloud.getNode(nodenr);
-                    NodeList nl = node.getRelatedNodes(destination, relation, 
"both");
-                    if (nl.size() > 0) {
-                        copyNodeNumber = "" + nl.getNode(0).getNumber();
-                    } else {
-                        log.error("could not find 'parent' node with path " + 
t + " and root node " + copyNodeNumber);
-                        copyNodeNumber = "!notfound!";
-                    }
-                }
-                template = template.substring(0, begin + 1) + t + ":" + 
copyNodeNumber + template.substring(end);
-                // adjust the end index
-                end = template.indexOf("]", from);
+
+                String templateNodeType = deriveTemplateType(_subTemplate);
+                if (nodeType.equals(templateNodeType)) {
+                    _subTemplate = appendNodenumberToTemplate(_subTemplate);
             }
-            from = end + 1;
+                
+                //even if the node type did not match, perhaps the template 
was cleaned from previous uses.
+                //reinsert it anyway.
+                reinsertSubTemplateIntoTemplate(_subTemplate, _begin, _end);
         }
+        });
         return template;
     }
 
+    
     /**
-     * This method is from the Modifier interface, and allows this class to 
-     * play as a Modifier instance.
+     * This method is from the Modifier interface, and allows this class to 
play as a Modifier instance.
      */
     public String modify(String input) {
-        try {
-            return stripTemplates(input);
-        } catch (Exception e) {
-            e.printStackTrace();
+            setTemplate(input);
+            processTemplate(new SubTemplateProcessor(){
+                @Override
+                void process() {
+                    _subTemplate = 
stripNodenumberFromSubtemplate(_subTemplate);
+                    reinsertSubTemplateIntoTemplate(_subTemplate, _begin, 
_end);
+                }});
+        return template;
+    }
+
+    private void processTemplate(SubTemplateProcessor processor) {
+        int offset = 0;
+        while (offset < template.length()  && 
template.substring(offset).matches(TEMPLATE_REGEXP) ) {
+            log.debug("evaluating: " + template.substring(offset) + ", from: " 
+ offset);
+            int begin = template.indexOf("[", offset) + 1;
+            int end = template.indexOf("]", offset);
+
+            String subTemplate = template.substring(begin, end);
+            log.debug("begin: " + begin + ", end: " + end + ", template: " + 
subTemplate);
+
+            processor.setSubTemplate(subTemplate);
+            processor.setBegin(begin);
+            processor.setEnd(end);
+            processor.process();
+            offset = offset + begin + processor.getSubTemplate().length() + 1;
         }
-        // TODO: What to do when an exception occurs?
-        return input;
     }
 
-    /**
-     * this method strips the templates away from the flushnames and just 
leaves the nodenumbers. This should yield the
-     * actual flushnames.
-     * 
-     * @param flushname
-     * @return
-     * @throws Exception
-     *             when there is a problem with parsing the template
-     */
-    public static String stripTemplates(String flushname) throws Exception {
-        log.debug("before. template: " + flushname);
-        // decode the templates out of the flushname
-        int from = 0;
-        while 
(flushname.substring(from).matches("^.*\\[[a-zA-Z0-9\\.]+:[a-zA-Z0-9]+\\].*$")) 
{
-            log.debug("evaluating: " + flushname.substring(from) + ", from: " 
+ from);
-            int begin = flushname.indexOf("[", from);
-            int end = flushname.indexOf("]", from);
-            String t = flushname.substring(begin + 1, end);
-            log.debug("begin: " + begin + ", end: " + end + ", flushname: " + 
t);
-
-            if (t.indexOf(":") == -1) {
-                // when this happens there is a template in the flushname that 
has not been suffixed
-                // with an actual nodenumber. this is an application error!
-                throw new Exception("flushname '" + flushname
-                        + "' illegal. some temlates have not been suffixed 
with ':<nodenr>'");
+    
+    
+    private void reinsertSubTemplateIntoTemplate(String subTemplate, int 
begin, int end){
+        String subTemplatePrefix = template.substring(0, begin);
+        String subTemplateSuffix = template.substring(end);
+        template = subTemplatePrefix + subTemplate + subTemplateSuffix;
             }
-            String nodenr = t.substring(t.indexOf(":") + 1);
 
-            flushname = flushname.substring(0, begin) + nodenr + 
flushname.substring(end + 1);
-            from = begin + 1;
+    private String stripNodenumberFromSubtemplate(String subTemplate) {
+        //pattern: aaa:89 or aaa.aaa.aaa:00
+        if (subTemplate.matches("(\\w+:\\d+)|((\\w+)(\\.\\w+){2}:\\d+)")) {
+            subTemplate = subTemplate.substring(0, subTemplate.indexOf(":"));
+            log.debug("template reuse. after cleaning: " + subTemplate);
         }
-        log.debug("after. tempate: " + flushname);
-        return flushname;
+        return subTemplate;
     }
 
-    public void setCloud(Cloud cloud) {
-        this.cloud = cloud;
+    private boolean subtemplateIsQuery(String subTemplate) {
+        return subTemplate.split("\\.").length == 3;
     }
 
-    /**
-     * @param type
-     *            the nodetype to add the nodenumber to.
-     */
-    public void setType(String type) {
-        this.type = type;
+    private String resolveNodeNumber(String subTemplate) {
+        if (subtemplateIsQuery(subTemplate)) {
+            return resolveNodeNumberForQuery(subTemplate);
+        } else {
+            return nodeNumber;
+        }
     }
 
-    /**
-     * 
-     * @param template
-     *            flushname with placeholders to be replaced
-     */
-    public void setTemplate(String template) {
-        this.template = template;
+    private String appendNodenumberToTemplate(String subTemplate) {
+        return subTemplate + ":" + resolveNodeNumber(subTemplate);
     }
 
-    /**
-     * @param nodenr
-     *            the number of the node appended to the tempate for matches 
with 'type'
-     */
-    public void setNodenr(String nodenr) {
-        this.nodenr = nodenr;
+    private String resolveNodeNumberForQuery(String subTemplate) {
+        QueryTemplate queryTemplate = parseQueryTemplate(subTemplate);
+        Node node = cloud.getNode(nodeNumber);
+        NodeList nl = node.getRelatedNodes(queryTemplate.getDestinationType(), 
queryTemplate.getRelationRole(), "both");
+        if (nl.size() > 0) {
+            return "" + nl.getNode(0).getNumber();
+        } else {
+            log.error("could not find 'parent' node with path " + subTemplate 
+ " and root node " + nodeNumber);
+            return "!notfound!";
+        }
+    }
+
+    private String deriveTemplateType(String subTemplate) {
+        if (subtemplateIsQuery(subTemplate)) {
+            return parseQueryTemplate(subTemplate).getSourceType();
+        } else {
+            return subTemplate;
+        }
+    }
+
+    private QueryTemplate parseQueryTemplate(String subTemplate) {
+        String[] q = subTemplate.split("\\.");
+        if (q.length == 3) {
+            return new QueryTemplate(q[0], q[1], q[2]);
+        } else {
+            throw new IllegalStateException(String.format(
+                    "template '%s' is not a query template, can not create 
QueryTemplate instance", subTemplate));
+        }
     }
 
     public Modifier copy() {
-        //as a Modifier this thing is completely stateless, so just return
-        //this instance
+        // as a Modifier this thing is completely stateless, so just return
+        // this instance
         return this;
     }
+
+    private static class QueryTemplate {
+        private String sourceType, relationRole, destinationType;
+
+        public QueryTemplate(String sourceType, String relationRole, String 
destinationType) {
+            this.sourceType = sourceType;
+            this.relationRole = relationRole;
+            this.destinationType = destinationType;
+        }
+
+        public String getSourceType() {
+            return sourceType;
+        }
+
+        public String getRelationRole() {
+            return relationRole;
+        }
+
+        public String getDestinationType() {
+            return destinationType;
+        }
+    }
+
+    private abstract class SubTemplateProcessor {
+        protected int _begin;
+        protected int _end;
+        protected String _subTemplate;
+
+        abstract void process();
+
+        public void setSubTemplate(String subTemplate) {
+            this._subTemplate = subTemplate;
+        }
+        
+        public String getSubTemplate(){
+            return _subTemplate;
+        }
+
+        public void setBegin(int begin) {
+            this._begin = begin;
+        }
+
+        public void setEnd(int end) {
+            this._end = end;
+        }
+
+    }
 }
_______________________________________________
Cvs mailing list
[email protected]
http://lists.mmbase.org/mailman/listinfo/cvs

Reply via email to