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(); }