From 9323a8cd7a9707c8bad0c7011c6e3cfc486a7c70 Mon Sep 17 00:00:00 2001 From: Kevin Roast Date: Fri, 9 Mar 2007 12:30:34 +0000 Subject: [PATCH] Template extension spring configuration support - similar pattern to existing script bean extension support - new root model helper objects and custom methods can be added via spring configuration Cleanup of script extension spring support Fix to thread safety of configured script extension beans that use the Scopable interface git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5369 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- config/alfresco/script-services-context.xml | 14 +-- config/alfresco/template-services-context.xml | 55 ++++++++++++ .../java/org/alfresco/repo/jscript/AVM.java | 20 +---- .../org/alfresco/repo/jscript/Actions.java | 16 +--- .../BaseScopableScriptImplementation.java | 49 ++++++++++ .../alfresco/repo/jscript/Classification.java | 16 +--- .../repo/jscript/CrossRepositoryCopy.java | 15 +--- .../java/org/alfresco/repo/jscript/Node.java | 10 ++- .../org/alfresco/repo/jscript/People.java | 18 +--- .../repo/jscript/RhinoScriptService.java | 2 +- .../org/alfresco/repo/jscript/Scopeable.java | 2 +- .../alfresco/repo/jscript/ScriptUtils.java | 16 +--- .../org/alfresco/repo/jscript/Search.java | 16 +--- .../BaseTemplateExtensionImplementation.java | 89 +++++++++++++++++++ .../repo/template/Classification.java | 24 +++-- .../repo/template/DateCompareMethod.java | 2 +- .../repo/template/DateIncrementMethod.java | 4 +- .../repo/template/FreeMarkerProcessor.java | 22 ++--- .../repo/template/HasAspectMethod.java | 7 +- .../repo/template/I18NMessageMethod.java | 4 +- .../org/alfresco/repo/template/Session.java | 16 ++-- .../repo/template/TemplateServiceImpl.java | 26 ++++++ .../TemplateExtensionImplementation.java | 54 +++++++++++ .../cmr/repository/TemplateService.java | 17 ++++ 24 files changed, 363 insertions(+), 151 deletions(-) create mode 100644 source/java/org/alfresco/repo/jscript/BaseScopableScriptImplementation.java create mode 100644 source/java/org/alfresco/repo/template/BaseTemplateExtensionImplementation.java create mode 100644 source/java/org/alfresco/service/cmr/repository/TemplateExtensionImplementation.java diff --git a/config/alfresco/script-services-context.xml b/config/alfresco/script-services-context.xml index 6466d0ef6d..1818644106 100644 --- a/config/alfresco/script-services-context.xml +++ b/config/alfresco/script-services-context.xml @@ -9,6 +9,8 @@ + @@ -28,7 +30,7 @@ - + @@ -37,7 +39,7 @@ - + @@ -49,7 +51,7 @@ ${spaces.store} - + @@ -61,7 +63,7 @@ ${spaces.store} - + @@ -73,7 +75,7 @@ - + @@ -82,7 +84,7 @@ - + diff --git a/config/alfresco/template-services-context.xml b/config/alfresco/template-services-context.xml index b74598ebff..41e3171f13 100644 --- a/config/alfresco/template-services-context.xml +++ b/config/alfresco/template-services-context.xml @@ -2,6 +2,7 @@ + @@ -34,4 +35,58 @@ --> + + + + + + + + + + + session + + + + + + + + + classification + + + ${spaces.store} + + + + + + + + + hasAspect + + + + + + message + + + + + + dateCompare + + + + + + incrementDate + + + diff --git a/source/java/org/alfresco/repo/jscript/AVM.java b/source/java/org/alfresco/repo/jscript/AVM.java index 5f2be688e3..6a7879bdd7 100644 --- a/source/java/org/alfresco/repo/jscript/AVM.java +++ b/source/java/org/alfresco/repo/jscript/AVM.java @@ -26,23 +26,19 @@ package org.alfresco.repo.jscript; import org.alfresco.config.JNDIConstants; import org.alfresco.repo.avm.AVMNodeConverter; -import org.alfresco.service.cmr.avm.AVMNodeDescriptor; import org.alfresco.service.ServiceRegistry; -import org.mozilla.javascript.Scriptable; +import org.alfresco.service.cmr.avm.AVMNodeDescriptor; /** * Helper to access AVM nodes from a script context. * * @author Kevin Roast */ -public final class AVM extends BaseScriptImplementation implements Scopeable +public final class AVM extends BaseScopableScriptImplementation { /** Repository Service Registry */ private ServiceRegistry services; - /** Root scope for this object */ - private Scriptable scope; - /** * Set the service registry * @@ -53,14 +49,6 @@ public final class AVM extends BaseScriptImplementation implements Scopeable this.services = serviceRegistry; } - /** - * @see org.alfresco.repo.jscript.Scopeable#setScope(org.mozilla.javascript.Scriptable) - */ - public void setScope(Scriptable scope) - { - this.scope = scope; - } - /** * Return an AVM Node representing the public store root folder. * @@ -77,7 +65,7 @@ public final class AVM extends BaseScriptImplementation implements Scopeable AVMNodeDescriptor nodeDesc = this.services.getAVMService().lookup(-1, rootPath); if (nodeDesc != null) { - rootNode = new AVMNode(AVMNodeConverter.ToNodeRef(-1, rootPath), this.services, this.scope); + rootNode = new AVMNode(AVMNodeConverter.ToNodeRef(-1, rootPath), this.services, getScope()); } } return rootNode; @@ -98,7 +86,7 @@ public final class AVM extends BaseScriptImplementation implements Scopeable AVMNodeDescriptor nodeDesc = this.services.getAVMService().lookup(-1, path); if (nodeDesc != null) { - node = new AVMNode(AVMNodeConverter.ToNodeRef(-1, path), this.services, this.scope); + node = new AVMNode(AVMNodeConverter.ToNodeRef(-1, path), this.services, getScope()); } } return node; diff --git a/source/java/org/alfresco/repo/jscript/Actions.java b/source/java/org/alfresco/repo/jscript/Actions.java index 26599e3042..9e7f6bb87e 100644 --- a/source/java/org/alfresco/repo/jscript/Actions.java +++ b/source/java/org/alfresco/repo/jscript/Actions.java @@ -30,21 +30,17 @@ import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.action.Action; import org.alfresco.service.cmr.action.ActionDefinition; import org.alfresco.service.cmr.action.ActionService; -import org.mozilla.javascript.Scriptable; /** * Scripted Action service for describing and executing actions against Nodes. * * @author davidc */ -public final class Actions extends BaseScriptImplementation implements Scopeable +public final class Actions extends BaseScopableScriptImplementation { /** Repository Service Registry */ private ServiceRegistry services; - /** Root scope for this object */ - private Scriptable scope; - /** * Set the service registry * @@ -54,14 +50,6 @@ public final class Actions extends BaseScriptImplementation implements Scopeable { this.services = serviceRegistry; } - - /** - * @see org.alfresco.repo.jscript.Scopeable#setScope(org.mozilla.javascript.Scriptable) - */ - public void setScope(Scriptable scope) - { - this.scope = scope; - } /** * Gets the list of registered action names @@ -102,7 +90,7 @@ public final class Actions extends BaseScriptImplementation implements Scopeable { Action action = actionService.createAction(actionName); scriptAction = new ScriptAction(this.services, action, actionDef); - scriptAction.setScope(scope); + scriptAction.setScope(getScope()); } return scriptAction; } diff --git a/source/java/org/alfresco/repo/jscript/BaseScopableScriptImplementation.java b/source/java/org/alfresco/repo/jscript/BaseScopableScriptImplementation.java new file mode 100644 index 0000000000..e61fedf813 --- /dev/null +++ b/source/java/org/alfresco/repo/jscript/BaseScopableScriptImplementation.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * 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.alfresco.repo.jscript; + +import org.mozilla.javascript.Scriptable; + +/** + * Abstract base class for a script implementation that requires a script execution scope. + * + * The scope is local to the currently executing script and therefore a ThreadLocal is required. + * + * @author Kevin Roast + */ +public class BaseScopableScriptImplementation extends BaseScriptImplementation implements Scopeable +{ + private static ThreadLocal scope = new ThreadLocal(); + + /** + * Set the Scriptable global scope + * + * @param script relative global scope + */ + public void setScope(Scriptable scope) + { + this.scope.set(scope); + } + + /** + * @return script global scope + */ + public Scriptable getScope() + { + return this.scope.get(); + } +} diff --git a/source/java/org/alfresco/repo/jscript/Classification.java b/source/java/org/alfresco/repo/jscript/Classification.java index 5821ccc48e..5b98d09ec9 100644 --- a/source/java/org/alfresco/repo/jscript/Classification.java +++ b/source/java/org/alfresco/repo/jscript/Classification.java @@ -31,18 +31,14 @@ import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.search.CategoryService; import org.alfresco.service.namespace.QName; -import org.mozilla.javascript.Scriptable; /** * Support class for finding categories, finding root nodes for categories and creating root categories. * * @author Andy Hind */ -public final class Classification extends BaseScriptImplementation implements Scopeable +public final class Classification extends BaseScopableScriptImplementation { - @SuppressWarnings("unused") - private Scriptable scope; - private ServiceRegistry services; private StoreRef storeRef; @@ -67,14 +63,6 @@ public final class Classification extends BaseScriptImplementation implements S this.services = services; } - /** - * @see org.alfresco.repo.jscript.Scopeable#setScope(org.mozilla.javascript.Scriptable) - */ - public void setScope(Scriptable scope) - { - this.scope = scope; - } - /** * Find all the category nodes in a given classification. * @@ -137,7 +125,7 @@ public final class Classification extends BaseScriptImplementation implements S int i = 0; for (ChildAssociationRef car : cars) { - categoryNodes[i++] = new CategoryNode(car.getChildRef(), this.services, this.scope); + categoryNodes[i++] = new CategoryNode(car.getChildRef(), this.services, getScope()); } return categoryNodes; } diff --git a/source/java/org/alfresco/repo/jscript/CrossRepositoryCopy.java b/source/java/org/alfresco/repo/jscript/CrossRepositoryCopy.java index 1141e10948..4fcbec1ca1 100644 --- a/source/java/org/alfresco/repo/jscript/CrossRepositoryCopy.java +++ b/source/java/org/alfresco/repo/jscript/CrossRepositoryCopy.java @@ -37,24 +37,13 @@ import org.mozilla.javascript.Scriptable; * * @author Kevin Roast */ -public final class CrossRepositoryCopy extends BaseScriptImplementation implements Scopeable +public final class CrossRepositoryCopy extends BaseScopableScriptImplementation { public final static String BEAN_NAME = "crossCopyScript"; /** Service registry */ private ServiceRegistry services; - /** Root scope for this object */ - private Scriptable scope; - - /** - * @see org.alfresco.repo.jscript.Scopeable#setScope(org.mozilla.javascript.Scriptable) - */ - public void setScope(Scriptable scope) - { - this.scope = scope; - } - /** * Set the service registry * @@ -98,7 +87,7 @@ public final class CrossRepositoryCopy extends BaseScriptImplementation implemen AVMNodeDescriptor node = this.services.getAVMService().lookup(-1, destPath); if (node != null) { - result = ((AVMNode)dest).newInstance(destPath, -1, this.services, this.scope); + result = ((AVMNode)dest).newInstance(destPath, -1, this.services, getScope()); } } else if (dest.getNodeRef().getStoreRef().getProtocol().equals(StoreRef.PROTOCOL_WORKSPACE)) diff --git a/source/java/org/alfresco/repo/jscript/Node.java b/source/java/org/alfresco/repo/jscript/Node.java index 1d4030e8f3..025d89c520 100644 --- a/source/java/org/alfresco/repo/jscript/Node.java +++ b/source/java/org/alfresco/repo/jscript/Node.java @@ -1550,9 +1550,13 @@ public class Node implements Serializable, Scopeable private String processTemplate(String template, NodeRef templateRef, ScriptableObject args) { // build default model for the template processing - Map model = FreeMarkerProcessor.buildDefaultModel(services, ((Node) ((Wrapper) scope.get( - "person", scope)).unwrap()).getNodeRef(), ((Node) ((Wrapper) scope.get("companyhome", scope)).unwrap()) - .getNodeRef(), ((Node) ((Wrapper) scope.get("userhome", scope)).unwrap()).getNodeRef(), templateRef, null); + Map model = FreeMarkerProcessor.buildDefaultModel( + services, + ((Node)((Wrapper)scope.get("person", scope)).unwrap()).getNodeRef(), + ((Node)((Wrapper)scope.get("companyhome", scope)).unwrap()).getNodeRef(), + ((Node)((Wrapper)scope.get("userhome", scope)).unwrap()).getNodeRef(), + templateRef, + null); // add the current node as either the document/space as appropriate if (this.getIsDocument()) diff --git a/source/java/org/alfresco/repo/jscript/People.java b/source/java/org/alfresco/repo/jscript/People.java index 71110615e9..6d359cbddc 100644 --- a/source/java/org/alfresco/repo/jscript/People.java +++ b/source/java/org/alfresco/repo/jscript/People.java @@ -33,22 +33,18 @@ import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.cmr.security.AuthorityType; import org.alfresco.service.cmr.security.PersonService; -import org.mozilla.javascript.Scriptable; /** * Scripted People service for describing and executing actions against People & Groups. * * @author davidc */ -public final class People extends BaseScriptImplementation implements Scopeable +public final class People extends BaseScopableScriptImplementation { /** Repository Service Registry */ private ServiceRegistry services; private AuthorityDAO authorityDAO; - /** Root scope for this object */ - private Scriptable scope; - /** * Set the service registry * @@ -69,14 +65,6 @@ public final class People extends BaseScriptImplementation implements Scopeable this.authorityDAO = authorityDAO; } - /** - * @see org.alfresco.repo.jscript.Scopeable#setScope(org.mozilla.javascript.Scriptable) - */ - public void setScope(Scriptable scope) - { - this.scope = scope; - } - /** * Gets the Person given the username * @@ -90,7 +78,7 @@ public final class People extends BaseScriptImplementation implements Scopeable if (personService.personExists(username)) { NodeRef personRef = personService.getPerson(username); - person = new Node(personRef, services, scope); + person = new Node(personRef, services, getScope()); } return person; } @@ -107,7 +95,7 @@ public final class People extends BaseScriptImplementation implements Scopeable NodeRef groupRef = authorityDAO.getAuthorityNodeRefOrNull(groupName); if (groupRef != null) { - group = new Node(groupRef, services, scope); + group = new Node(groupRef, services, getScope()); } return group; } diff --git a/source/java/org/alfresco/repo/jscript/RhinoScriptService.java b/source/java/org/alfresco/repo/jscript/RhinoScriptService.java index 74982a29b4..4d948272c3 100644 --- a/source/java/org/alfresco/repo/jscript/RhinoScriptService.java +++ b/source/java/org/alfresco/repo/jscript/RhinoScriptService.java @@ -69,7 +69,7 @@ public class RhinoScriptService implements ScriptService private ServiceRegistry services; /** List of global scripts */ - private List globalScripts = new ArrayList(5); + private List globalScripts = new ArrayList(); /** * Set the Service Registry diff --git a/source/java/org/alfresco/repo/jscript/Scopeable.java b/source/java/org/alfresco/repo/jscript/Scopeable.java index 88c8d70ee7..1c1a93773f 100644 --- a/source/java/org/alfresco/repo/jscript/Scopeable.java +++ b/source/java/org/alfresco/repo/jscript/Scopeable.java @@ -39,7 +39,7 @@ public interface Scopeable /** * Set the Scriptable global scope * - * @param scope global scope + * @param script relative global scope */ void setScope(Scriptable scope); } diff --git a/source/java/org/alfresco/repo/jscript/ScriptUtils.java b/source/java/org/alfresco/repo/jscript/ScriptUtils.java index b2e790ac80..b486f34bc6 100644 --- a/source/java/org/alfresco/repo/jscript/ScriptUtils.java +++ b/source/java/org/alfresco/repo/jscript/ScriptUtils.java @@ -26,29 +26,17 @@ package org.alfresco.repo.jscript; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.repository.NodeRef; -import org.mozilla.javascript.Scriptable; /** * Place for general and miscellenous utility functions not already found in generic JavaScript. * * @author Kevin Roast */ -public final class ScriptUtils extends BaseScriptImplementation implements Scopeable +public final class ScriptUtils extends BaseScopableScriptImplementation { - /** Root scope for this object */ - private Scriptable scope; - /** Services */ private ServiceRegistry services; - /** - * @see org.alfresco.repo.jscript.Scopeable#setScope(org.mozilla.javascript.Scriptable) - */ - public void setScope(Scriptable scope) - { - this.scope = scope; - } - /** * Sets the service registry * @@ -86,6 +74,6 @@ public final class ScriptUtils extends BaseScriptImplementation implements Scope public Node getNodeFromString(String nodeRefString) { NodeRef nodeRef = new NodeRef(nodeRefString); - return (Node)new ValueConverter().convertValueForScript(this.services, this.scope, null, nodeRef); + return (Node)new ValueConverter().convertValueForScript(this.services, getScope(), null, nodeRef); } } diff --git a/source/java/org/alfresco/repo/jscript/Search.java b/source/java/org/alfresco/repo/jscript/Search.java index ff7a61cace..6c030dc9ce 100644 --- a/source/java/org/alfresco/repo/jscript/Search.java +++ b/source/java/org/alfresco/repo/jscript/Search.java @@ -40,7 +40,6 @@ import org.alfresco.service.cmr.search.SearchService; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; -import org.mozilla.javascript.Scriptable; /** * Search component for use by the ScriptService. @@ -55,7 +54,7 @@ import org.mozilla.javascript.Scriptable; * * @author Kevin Roast */ -public final class Search extends BaseScriptImplementation implements Scopeable +public final class Search extends BaseScopableScriptImplementation { /** Service registry */ private ServiceRegistry services; @@ -63,9 +62,6 @@ public final class Search extends BaseScriptImplementation implements Scopeable /** Default store reference */ private StoreRef storeRef; - /** Root scope for this object */ - private Scriptable scope; - /** * Set the default store reference * @@ -86,14 +82,6 @@ public final class Search extends BaseScriptImplementation implements Scopeable this.services = services; } - /** - * @see org.alfresco.repo.jscript.Scopeable#setScope(org.mozilla.javascript.Scriptable) - */ - public void setScope(Scriptable scope) - { - this.scope = scope; - } - /** * Find a single Node by the Node reference * @@ -251,7 +239,7 @@ public final class Search extends BaseScriptImplementation implements Scopeable for (ResultSetRow row: results) { NodeRef nodeRef = row.getNodeRef(); - set.add(new Node(nodeRef, services, this.scope)); + set.add(new Node(nodeRef, services, getScope())); } } } diff --git a/source/java/org/alfresco/repo/template/BaseTemplateExtensionImplementation.java b/source/java/org/alfresco/repo/template/BaseTemplateExtensionImplementation.java new file mode 100644 index 0000000000..4161d46055 --- /dev/null +++ b/source/java/org/alfresco/repo/template/BaseTemplateExtensionImplementation.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * 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.alfresco.repo.template; + +import org.alfresco.service.cmr.repository.TemplateExtensionImplementation; +import org.alfresco.service.cmr.repository.TemplateImageResolver; +import org.alfresco.service.cmr.repository.TemplateService; + +/** + * Abstract base class for a template extension implementation + * + * @author Kevin Roast + */ +public abstract class BaseTemplateExtensionImplementation implements TemplateExtensionImplementation +{ + /** The template service instance */ + private TemplateService templateService; + + /** The name of the template extension */ + private String extensionName; + + /** The TemplateImageResolver for the current template execution thread */ + private ThreadLocal resolver = new ThreadLocal(); + + + /** + * @param templateService The TemplateService to set. + */ + public void setTemplateService(TemplateService templateService) + { + this.templateService = templateService; + } + + /** + * @see org.alfresco.service.cmr.repository.TemplateExtensionImplementation#setTemplateImageResolver(org.alfresco.service.cmr.repository.TemplateImageResolver) + */ + public void setTemplateImageResolver(TemplateImageResolver resolver) + { + this.resolver.set(resolver); + } + + /** + * @see org.alfresco.service.cmr.repository.TemplateExtensionImplementation#getTemplateImageResolver() + */ + public TemplateImageResolver getTemplateImageResolver() + { + return this.resolver.get(); + } + + /** + * Registers this template extension with the Template Service + */ + public void register() + { + this.templateService.registerExtension(this); + } + + /** + * Returns the name of the template extension + * + * @return the name of the template extension + */ + public String getExtensionName() + { + return extensionName; + } + + /** + * @param extensionName The template extension name. + */ + public void setExtensionName(String extensionName) + { + this.extensionName = extensionName; + } +} diff --git a/source/java/org/alfresco/repo/template/Classification.java b/source/java/org/alfresco/repo/template/Classification.java index 7a16b46eec..555527cdfc 100644 --- a/source/java/org/alfresco/repo/template/Classification.java +++ b/source/java/org/alfresco/repo/template/Classification.java @@ -32,8 +32,6 @@ import org.alfresco.repo.jscript.CategoryTemplateNode; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.StoreRef; -import org.alfresco.service.cmr.repository.TemplateImageResolver; -import org.alfresco.service.cmr.repository.TemplateNode; import org.alfresco.service.cmr.search.CategoryService; import org.alfresco.service.namespace.QName; @@ -42,19 +40,29 @@ import org.alfresco.service.namespace.QName; * * @author Andy Hind */ -public final class Classification +public class Classification extends BaseTemplateExtensionImplementation { private ServiceRegistry services; - private TemplateImageResolver imageResolver; private StoreRef storeRef; - public Classification(StoreRef storeRef, ServiceRegistry services, TemplateImageResolver imageResolver) + /** + * Sets the service registry + * + * @param services the service registry + */ + public void setServiceRegistry(ServiceRegistry services) { - this.storeRef = storeRef; this.services = services; - this.imageResolver = imageResolver; } + /** + * @param storeUrl The store ref url to set. + */ + public void setStoreUrl(String storeUrl) + { + this.storeRef = new StoreRef(storeUrl); + } + /** * Find all the category nodes in a given classification. * @@ -110,7 +118,7 @@ public final class Classification ArrayList categoryNodes = new ArrayList(cars.size()); for (ChildAssociationRef car : cars) { - categoryNodes.add(new CategoryTemplateNode(car.getChildRef(), this.services, this.imageResolver)); + categoryNodes.add(new CategoryTemplateNode(car.getChildRef(), this.services, getTemplateImageResolver())); } return categoryNodes; } diff --git a/source/java/org/alfresco/repo/template/DateCompareMethod.java b/source/java/org/alfresco/repo/template/DateCompareMethod.java index 991a0dd467..0f97f55025 100644 --- a/source/java/org/alfresco/repo/template/DateCompareMethod.java +++ b/source/java/org/alfresco/repo/template/DateCompareMethod.java @@ -43,7 +43,7 @@ import freemarker.template.TemplateNumberModel; * dateCompare(dateA, dateB) - 1 if dateA if greater than dateB * dateCompare(dateA, dateB, millis) - 1 if dateA is greater than dateB by at least millis, else 0 */ -public final class DateCompareMethod implements TemplateMethodModelEx +public class DateCompareMethod extends BaseTemplateExtensionImplementation implements TemplateMethodModelEx { /** * @see freemarker.template.TemplateMethodModel#exec(java.util.List) diff --git a/source/java/org/alfresco/repo/template/DateIncrementMethod.java b/source/java/org/alfresco/repo/template/DateIncrementMethod.java index c7ec804ec3..75f3c5ebd0 100644 --- a/source/java/org/alfresco/repo/template/DateIncrementMethod.java +++ b/source/java/org/alfresco/repo/template/DateIncrementMethod.java @@ -34,10 +34,8 @@ import freemarker.template.TemplateNumberModel; /** * @author Roy Wetherall - * - */ -public final class DateIncrementMethod implements TemplateMethodModelEx +public class DateIncrementMethod extends BaseTemplateExtensionImplementation implements TemplateMethodModelEx { /** * @see freemarker.template.TemplateMethodModel#exec(java.util.List) diff --git a/source/java/org/alfresco/repo/template/FreeMarkerProcessor.java b/source/java/org/alfresco/repo/template/FreeMarkerProcessor.java index f626753ff0..6f6d5924ca 100644 --- a/source/java/org/alfresco/repo/template/FreeMarkerProcessor.java +++ b/source/java/org/alfresco/repo/template/FreeMarkerProcessor.java @@ -35,6 +35,7 @@ import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.TemplateException; +import org.alfresco.service.cmr.repository.TemplateExtensionImplementation; import org.alfresco.service.cmr.repository.TemplateImageResolver; import org.alfresco.service.cmr.repository.TemplateNode; import org.alfresco.service.cmr.repository.TemplateProcessor; @@ -100,7 +101,7 @@ public class FreeMarkerProcessor implements TemplateProcessor { this.contentService = contentService; } - + /** * Set the default template encoding * @@ -338,18 +339,13 @@ public class FreeMarkerProcessor implements TemplateProcessor // current date/time is useful to have and isn't supplied by FreeMarker by default model.put("date", new Date()); - // Session support - model.put("session", new Session(services, imageResolver)); - - // Classification support - - model.put("classification", new Classification(companyHome.getStoreRef(), services, imageResolver)); - - // add custom method objects - model.put("hasAspect", new HasAspectMethod()); - model.put("message", new I18NMessageMethod()); - model.put("dateCompare", new DateCompareMethod()); - model.put("incrementDate", new DateIncrementMethod()); + // add the template extensions to the model + // the extensions include custom root helper objects and custom template method objects + for (TemplateExtensionImplementation ext : services.getTemplateService().getExtensions()) + { + ext.setTemplateImageResolver(imageResolver); + model.put(ext.getExtensionName(), ext); + } return model; } diff --git a/source/java/org/alfresco/repo/template/HasAspectMethod.java b/source/java/org/alfresco/repo/template/HasAspectMethod.java index caa8d4e865..5a3c167b08 100644 --- a/source/java/org/alfresco/repo/template/HasAspectMethod.java +++ b/source/java/org/alfresco/repo/template/HasAspectMethod.java @@ -24,14 +24,11 @@ */ package org.alfresco.repo.template; -import java.util.ArrayList; import java.util.List; import org.alfresco.service.cmr.repository.TemplateNode; -import org.alfresco.service.namespace.QName; import freemarker.ext.beans.BeanModel; -import freemarker.ext.beans.StringModel; import freemarker.template.TemplateMethodModelEx; import freemarker.template.TemplateModelException; import freemarker.template.TemplateScalarModel; @@ -44,9 +41,9 @@ import freemarker.template.TemplateScalarModel; * Method returns whether a TemplateNode has a particular aspect applied to it. The aspect * name can be either the fully qualified QName or the short prefixed name string. *

- * Usage: hasAspect(TemplateNode node, String aspect) + * Usage: hasAspect(TemplateNode node, String aspect) - 1 on true, 0 on false */ -public final class HasAspectMethod implements TemplateMethodModelEx +public class HasAspectMethod extends BaseTemplateExtensionImplementation implements TemplateMethodModelEx { /** * @see freemarker.template.TemplateMethodModel#exec(java.util.List) diff --git a/source/java/org/alfresco/repo/template/I18NMessageMethod.java b/source/java/org/alfresco/repo/template/I18NMessageMethod.java index b8db182c47..693560a6d5 100644 --- a/source/java/org/alfresco/repo/template/I18NMessageMethod.java +++ b/source/java/org/alfresco/repo/template/I18NMessageMethod.java @@ -37,11 +37,11 @@ import freemarker.template.TemplateScalarModel; * * Custom FreeMarker Template language method. *

- * Method an I18N message resolved for the current locale and specified message ID. + * Returns an I18N message resolved for the current locale and specified message ID. *

* Usage: message(String id) */ -public final class I18NMessageMethod implements TemplateMethodModelEx +public class I18NMessageMethod extends BaseTemplateExtensionImplementation implements TemplateMethodModelEx { /** * @see freemarker.template.TemplateMethodModel#exec(java.util.List) diff --git a/source/java/org/alfresco/repo/template/Session.java b/source/java/org/alfresco/repo/template/Session.java index aa1064b805..9855f8802a 100644 --- a/source/java/org/alfresco/repo/template/Session.java +++ b/source/java/org/alfresco/repo/template/Session.java @@ -32,20 +32,20 @@ import org.alfresco.service.cmr.repository.TemplateImageResolver; * * @author Andy Hind */ -public class Session +public class Session extends BaseTemplateExtensionImplementation { - private ServiceRegistry services; - @SuppressWarnings("unused") - private TemplateImageResolver imageResolver; - - public Session(ServiceRegistry services, TemplateImageResolver imageResolver) + /** + * Sets the service registry + * + * @param services the service registry + */ + public void setServiceRegistry(ServiceRegistry services) { this.services = services; - this.imageResolver = imageResolver; } - + /** * Get the current authentication ticket. * diff --git a/source/java/org/alfresco/repo/template/TemplateServiceImpl.java b/source/java/org/alfresco/repo/template/TemplateServiceImpl.java index d8c54bf90e..66cff32385 100644 --- a/source/java/org/alfresco/repo/template/TemplateServiceImpl.java +++ b/source/java/org/alfresco/repo/template/TemplateServiceImpl.java @@ -26,11 +26,15 @@ package org.alfresco.repo.template; import java.io.StringWriter; import java.io.Writer; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.service.cmr.repository.ScriptImplementation; import org.alfresco.service.cmr.repository.TemplateException; +import org.alfresco.service.cmr.repository.TemplateExtensionImplementation; import org.alfresco.service.cmr.repository.TemplateProcessor; import org.alfresco.service.cmr.repository.TemplateService; import org.apache.commons.logging.Log; @@ -40,6 +44,8 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; /** + * Implementation of the TemplateService using Spring configured template engines. + * * @author Kevin Roast */ public class TemplateServiceImpl implements TemplateService, ApplicationContextAware @@ -58,6 +64,10 @@ public class TemplateServiceImpl implements TemplateService, ApplicationContextA /** Threadlocal instance for template processor cache */ private static ThreadLocal> processors = new ThreadLocal>(); + /** List of global template extensions */ + private List globalExtensions = new ArrayList(); + + /** * Set the application context * @@ -68,6 +78,22 @@ public class TemplateServiceImpl implements TemplateService, ApplicationContextA this.applicationContext = applicationContext; } + /** + * @see org.alfresco.service.cmr.repository.TemplateService#registerExtension(org.alfresco.service.cmr.repository.TemplateExtensionImplementation) + */ + public void registerExtension(TemplateExtensionImplementation extension) + { + this.globalExtensions.add(extension); + } + + /** + * @see org.alfresco.service.cmr.repository.TemplateService#getExtensions() + */ + public List getExtensions() + { + return this.globalExtensions; + } + /** * @param defaultTemplateEngine The default Template Engine name to set. */ diff --git a/source/java/org/alfresco/service/cmr/repository/TemplateExtensionImplementation.java b/source/java/org/alfresco/service/cmr/repository/TemplateExtensionImplementation.java new file mode 100644 index 0000000000..92d368172d --- /dev/null +++ b/source/java/org/alfresco/service/cmr/repository/TemplateExtensionImplementation.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.service.cmr.repository; + +/** + * Interface to represent a server side template extension implementation + * + * @author Kevin Roast + */ +public interface TemplateExtensionImplementation +{ + /** + * Returns the name of the template extension + * + * @return the name of the template extension + */ + String getExtensionName(); + + /** + * Set the template image resolver for this extension + * + * @param resolver TemplateImageResolver + */ + void setTemplateImageResolver(TemplateImageResolver resolver); + + /** + * Get the template image resolver for this extension + * + * @return TemplateImageResolver + */ + TemplateImageResolver getTemplateImageResolver(); +} diff --git a/source/java/org/alfresco/service/cmr/repository/TemplateService.java b/source/java/org/alfresco/service/cmr/repository/TemplateService.java index 8ed95a55bd..5bb2b72b06 100644 --- a/source/java/org/alfresco/service/cmr/repository/TemplateService.java +++ b/source/java/org/alfresco/service/cmr/repository/TemplateService.java @@ -25,6 +25,7 @@ package org.alfresco.service.cmr.repository; import java.io.Writer; +import java.util.List; import org.alfresco.service.Auditable; import org.alfresco.service.PublicService; @@ -111,4 +112,20 @@ public interface TemplateService */ @Auditable(warn = true, parameters = {"engine"}) public TemplateProcessor getTemplateProcessor(String engine); + + /** + * Registers a template extension implementation with the Template service + * + * @param extension the template extension implementation + */ + @Auditable(parameters = {"extension"}) + public void registerExtension(TemplateExtensionImplementation extension); + + /** + * Returns a list of the Template Extension objects configured for this service + * + * @return list of the Template Extension objects configured for this service + */ + @Auditable(warn = true, recordReturnedObject = false) + public List getExtensions(); }