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