mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
Scheduled Actions
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@2673 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
442
config/alfresco/extension/scheduled-action-services-context.xml
Normal file
442
config/alfresco/extension/scheduled-action-services-context.xml
Normal file
@@ -0,0 +1,442 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
|
||||||
|
|
||||||
|
<beans>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Define the model factory used to generate object models suitable for use with freemarker templates.
|
||||||
|
-->
|
||||||
|
<bean id="templateActionModelFactory" class="org.alfresco.repo.action.scheduled.FreeMarkerWithLuceneExtensionsModelFactory">
|
||||||
|
<property name="serviceRegistry">
|
||||||
|
<ref bean="ServiceRegistry"/>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
An example action template that defines an action to add the generalclassifiable aspect to all nodes that do not have
|
||||||
|
and add a category defined by path.
|
||||||
|
-->
|
||||||
|
<bean id="addClassifiableAspectAction" class="org.alfresco.repo.action.scheduled.SimpleTemplateActionDefinition">
|
||||||
|
<property name="actionName">
|
||||||
|
<value>add-features</value>
|
||||||
|
</property>
|
||||||
|
<property name="parameterTemplates">
|
||||||
|
<map>
|
||||||
|
<entry>
|
||||||
|
<key>
|
||||||
|
<value>aspect-name</value>
|
||||||
|
</key>
|
||||||
|
<value>{http://www.alfresco.org/model/content/1.0}generalclassifiable</value>
|
||||||
|
</entry>
|
||||||
|
|
||||||
|
<entry>
|
||||||
|
<key>
|
||||||
|
<value>{http://www.alfresco.org/model/content/1.0}categories</value>
|
||||||
|
</key>
|
||||||
|
<value>${selectSingleNode('workspace://SpacesStore', 'lucene', 'PATH:"/cm:generalclassifiable/cm:Languages/cm:English"' )}</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</property>
|
||||||
|
<property name="templateActionModelFactory">
|
||||||
|
<ref bean="templateActionModelFactory"/>
|
||||||
|
</property>
|
||||||
|
<property name="dictionaryService">
|
||||||
|
<ref bean="DictionaryService"/>
|
||||||
|
</property>
|
||||||
|
<property name="actionService">
|
||||||
|
<ref bean="ActionService"/>
|
||||||
|
</property>
|
||||||
|
<property name="templateService">
|
||||||
|
<ref bean="TemplateService"/>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
An example action template that removes an aspect from all those nodes that have the aspect.
|
||||||
|
-->
|
||||||
|
<bean id="removeClassifiableAspectAction" class="org.alfresco.repo.action.scheduled.SimpleTemplateActionDefinition">
|
||||||
|
<property name="actionName">
|
||||||
|
<value>remove-features</value>
|
||||||
|
</property>
|
||||||
|
<property name="parameterTemplates">
|
||||||
|
<map>
|
||||||
|
<entry>
|
||||||
|
<key>
|
||||||
|
<value>aspect-name</value>
|
||||||
|
</key>
|
||||||
|
<value>{http://www.alfresco.org/model/content/1.0}generalclassifiable</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</property>
|
||||||
|
<property name="templateActionModelFactory">
|
||||||
|
<ref bean="templateActionModelFactory"/>
|
||||||
|
</property>
|
||||||
|
<property name="dictionaryService">
|
||||||
|
<ref bean="DictionaryService"/>
|
||||||
|
</property>
|
||||||
|
<property name="actionService">
|
||||||
|
<ref bean="ActionService"/>
|
||||||
|
</property>
|
||||||
|
<property name="templateService">
|
||||||
|
<ref bean="TemplateService"/>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
An example that copies the tutorial node into the company home space
|
||||||
|
-->
|
||||||
|
<bean id="copyAction" class="org.alfresco.repo.action.scheduled.SimpleTemplateActionDefinition">
|
||||||
|
<property name="actionName">
|
||||||
|
<value>copy</value>
|
||||||
|
</property>
|
||||||
|
<property name="parameterTemplates">
|
||||||
|
<map>
|
||||||
|
<entry>
|
||||||
|
<key>
|
||||||
|
<value>destination-folder</value>
|
||||||
|
</key>
|
||||||
|
<value>${selectSingleNode('workspace://SpacesStore', 'lucene', 'PATH:"/app:company_home"' )}</value>
|
||||||
|
</entry>
|
||||||
|
<entry>
|
||||||
|
<key>
|
||||||
|
<value>assoc-type</value>
|
||||||
|
</key>
|
||||||
|
<value>${node.primaryParentAssoc.typeQName}</value>
|
||||||
|
</entry>
|
||||||
|
<entry>
|
||||||
|
<key>
|
||||||
|
<value>assoc-name</value>
|
||||||
|
</key>
|
||||||
|
<value>${node.primaryParentAssoc.QName}</value>
|
||||||
|
</entry>
|
||||||
|
<entry>
|
||||||
|
<key>
|
||||||
|
<value>deep-copy</value>
|
||||||
|
</key>
|
||||||
|
<value>false</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</property>
|
||||||
|
<property name="templateActionModelFactory">
|
||||||
|
<ref bean="templateActionModelFactory"/>
|
||||||
|
</property>
|
||||||
|
<property name="dictionaryService">
|
||||||
|
<ref bean="DictionaryService"/>
|
||||||
|
</property>
|
||||||
|
<property name="actionService">
|
||||||
|
<ref bean="ActionService"/>
|
||||||
|
</property>
|
||||||
|
<property name="templateService">
|
||||||
|
<ref bean="TemplateService"/>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
An example that sets the created date to now
|
||||||
|
-->
|
||||||
|
<bean id="setCreatedDateAction" class="org.alfresco.repo.action.scheduled.SimpleTemplateActionDefinition">
|
||||||
|
<property name="actionName">
|
||||||
|
<value>set-property-value</value>
|
||||||
|
</property>
|
||||||
|
<property name="parameterTemplates">
|
||||||
|
<map>
|
||||||
|
<entry>
|
||||||
|
<key>
|
||||||
|
<value>property</value>
|
||||||
|
</key>
|
||||||
|
<value>{http://www.alfresco.org/model/content/1.0}created</value>
|
||||||
|
</entry>
|
||||||
|
<entry>
|
||||||
|
<key>
|
||||||
|
<value>value</value>
|
||||||
|
</key>
|
||||||
|
<value>${today?string("yyyy-MM-dd'T'HH:mm:ss.sss'Z'")}</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</property>
|
||||||
|
<property name="templateActionModelFactory">
|
||||||
|
<ref bean="templateActionModelFactory"/>
|
||||||
|
</property>
|
||||||
|
<property name="dictionaryService">
|
||||||
|
<ref bean="DictionaryService"/>
|
||||||
|
</property>
|
||||||
|
<property name="actionService">
|
||||||
|
<ref bean="ActionService"/>
|
||||||
|
</property>
|
||||||
|
<property name="templateService">
|
||||||
|
<ref bean="TemplateService"/>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Compound action example ...
|
||||||
|
-->
|
||||||
|
|
||||||
|
<bean id="compositeAction" class="org.alfresco.repo.action.scheduled.CompositeTemplateActionDefinition">
|
||||||
|
<property name="actionService">
|
||||||
|
<ref bean="ActionService"/>
|
||||||
|
</property>
|
||||||
|
<property name="templateService">
|
||||||
|
<ref bean="TemplateService"/>
|
||||||
|
</property>
|
||||||
|
<property name="templateActionDefinitions">
|
||||||
|
<list>
|
||||||
|
<ref bean="copyAction"/>
|
||||||
|
<ref bean="setCreatedDateAction"/>
|
||||||
|
</list>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!-- ONE_TRANSACTION ISOLATED_TRANSACTIONS UNTIL_FIRST_FAILURE -->
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Define a job for adding the classified aspect to nodes.
|
||||||
|
-->
|
||||||
|
<bean id="addClassifiableAspectEveryTenMinutes" class="org.alfresco.repo.action.scheduled.CronScheduledQueryBasedTemplateActionDefinition">
|
||||||
|
<property name="transactionMode">
|
||||||
|
<value>UNTIL_FIRST_FAILURE</value>
|
||||||
|
</property>
|
||||||
|
<property name="compensatingActionMode">
|
||||||
|
<value>IGNORE</value>
|
||||||
|
</property>
|
||||||
|
<property name="searchService">
|
||||||
|
<ref bean="SearchService"/>
|
||||||
|
</property>
|
||||||
|
<property name="templateService">
|
||||||
|
<ref bean="TemplateService"/>
|
||||||
|
</property>
|
||||||
|
<property name="queryLanguage">
|
||||||
|
<value>lucene</value>
|
||||||
|
</property>
|
||||||
|
<property name="stores">
|
||||||
|
<list>
|
||||||
|
<value>workspace://SpacesStore</value>
|
||||||
|
</list>
|
||||||
|
</property>
|
||||||
|
<!-- Find all nodes that do not have the aspect -->
|
||||||
|
<property name="queryTemplate">
|
||||||
|
<value>PATH:"//\*" -ASPECT:"{http://www.alfresco.org/model/content/1.0}generalclassifiable"</value>
|
||||||
|
</property>
|
||||||
|
<property name="cronExpression">
|
||||||
|
<value>0 50 * * * ?</value>
|
||||||
|
</property>
|
||||||
|
<property name="jobName">
|
||||||
|
<value>jobA</value>
|
||||||
|
</property>
|
||||||
|
<property name="jobGroup">
|
||||||
|
<value>jobGroup</value>
|
||||||
|
</property>
|
||||||
|
<property name="triggerName">
|
||||||
|
<value>triggerA</value>
|
||||||
|
</property>
|
||||||
|
<property name="triggerGroup">
|
||||||
|
<value>triggerGroup</value>
|
||||||
|
</property>
|
||||||
|
<property name="scheduler">
|
||||||
|
<ref bean="schedulerFactory"/>
|
||||||
|
</property>
|
||||||
|
<property name="actionService">
|
||||||
|
<ref bean="ActionService"/>
|
||||||
|
</property>
|
||||||
|
<property name="templateActionModelFactory">
|
||||||
|
<ref bean="templateActionModelFactory"/>
|
||||||
|
</property>
|
||||||
|
<property name="templateActionDefinition">
|
||||||
|
<ref bean="addClassifiableAspectAction"/>
|
||||||
|
</property>
|
||||||
|
<property name="transactionService">
|
||||||
|
<ref bean="TransactionService"/>
|
||||||
|
</property>
|
||||||
|
<property name="runAsUser">
|
||||||
|
<value>System</value>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Define a job to remove an aspect.
|
||||||
|
-->
|
||||||
|
<bean id="removeClassifiableAspectEveryTenMinutes" class="org.alfresco.repo.action.scheduled.CronScheduledQueryBasedTemplateActionDefinition">
|
||||||
|
<property name="transactionMode">
|
||||||
|
<value>UNTIL_FIRST_FAILURE</value>
|
||||||
|
</property>
|
||||||
|
<property name="compensatingActionMode">
|
||||||
|
<value>IGNORE</value>
|
||||||
|
</property>
|
||||||
|
<property name="searchService">
|
||||||
|
<ref bean="SearchService"/>
|
||||||
|
</property>
|
||||||
|
<property name="templateService">
|
||||||
|
<ref bean="TemplateService"/>
|
||||||
|
</property>
|
||||||
|
<property name="queryLanguage">
|
||||||
|
<value>lucene</value>
|
||||||
|
</property>
|
||||||
|
<property name="stores">
|
||||||
|
<list>
|
||||||
|
<value>workspace://SpacesStore</value>
|
||||||
|
</list>
|
||||||
|
</property>
|
||||||
|
<property name="queryTemplate">
|
||||||
|
<value>ASPECT:"{http://www.alfresco.org/model/content/1.0}generalclassifiable"</value>
|
||||||
|
</property>
|
||||||
|
<property name="cronExpression">
|
||||||
|
<value>0 55 * * * ?</value>
|
||||||
|
</property>
|
||||||
|
<property name="jobName">
|
||||||
|
<value>jobB</value>
|
||||||
|
</property>
|
||||||
|
<property name="jobGroup">
|
||||||
|
<value>jobGroup</value>
|
||||||
|
</property>
|
||||||
|
<property name="triggerName">
|
||||||
|
<value>triggerB</value>
|
||||||
|
</property>
|
||||||
|
<property name="triggerGroup">
|
||||||
|
<value>triggerGroup</value>
|
||||||
|
</property>
|
||||||
|
<property name="scheduler">
|
||||||
|
<ref bean="schedulerFactory"/>
|
||||||
|
</property>
|
||||||
|
<property name="actionService">
|
||||||
|
<ref bean="ActionService"/>
|
||||||
|
</property>
|
||||||
|
<property name="templateActionModelFactory">
|
||||||
|
<ref bean="templateActionModelFactory"/>
|
||||||
|
</property>
|
||||||
|
<property name="templateActionDefinition">
|
||||||
|
<ref bean="removeClassifiableAspectAction"/>
|
||||||
|
</property>
|
||||||
|
<property name="transactionService">
|
||||||
|
<ref bean="TransactionService"/>
|
||||||
|
</property>
|
||||||
|
<property name="runAsUser">
|
||||||
|
<value>System</value>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Define a job to remove an aspect.
|
||||||
|
-->
|
||||||
|
<bean id="copyTutorialEveryTenMinutes" class="org.alfresco.repo.action.scheduled.CronScheduledQueryBasedTemplateActionDefinition">
|
||||||
|
<property name="transactionMode">
|
||||||
|
<value>UNTIL_FIRST_FAILURE</value>
|
||||||
|
</property>
|
||||||
|
<property name="compensatingActionMode">
|
||||||
|
<value>IGNORE</value>
|
||||||
|
</property>
|
||||||
|
<property name="searchService">
|
||||||
|
<ref bean="SearchService"/>
|
||||||
|
</property>
|
||||||
|
<property name="templateService">
|
||||||
|
<ref bean="TemplateService"/>
|
||||||
|
</property>
|
||||||
|
<property name="queryLanguage">
|
||||||
|
<value>lucene</value>
|
||||||
|
</property>
|
||||||
|
<property name="stores">
|
||||||
|
<list>
|
||||||
|
<value>workspace://SpacesStore</value>
|
||||||
|
</list>
|
||||||
|
</property>
|
||||||
|
<property name="queryTemplate">
|
||||||
|
<value>+PATH:"/app:company_home/*//*" +TEXT:"tutorial"</value>
|
||||||
|
</property>
|
||||||
|
<property name="cronExpression">
|
||||||
|
<value>0 40 * * * ?</value>
|
||||||
|
</property>
|
||||||
|
<property name="jobName">
|
||||||
|
<value>jobC</value>
|
||||||
|
</property>
|
||||||
|
<property name="jobGroup">
|
||||||
|
<value>jobGroup</value>
|
||||||
|
</property>
|
||||||
|
<property name="triggerName">
|
||||||
|
<value>triggerC</value>
|
||||||
|
</property>
|
||||||
|
<property name="triggerGroup">
|
||||||
|
<value>triggerGroup</value>
|
||||||
|
</property>
|
||||||
|
<property name="scheduler">
|
||||||
|
<ref bean="schedulerFactory"/>
|
||||||
|
</property>
|
||||||
|
<property name="actionService">
|
||||||
|
<ref bean="ActionService"/>
|
||||||
|
</property>
|
||||||
|
<property name="templateActionModelFactory">
|
||||||
|
<ref bean="templateActionModelFactory"/>
|
||||||
|
</property>
|
||||||
|
<property name="templateActionDefinition">
|
||||||
|
<ref bean="copyAction"/>
|
||||||
|
</property>
|
||||||
|
<property name="transactionService">
|
||||||
|
<ref bean="TransactionService"/>
|
||||||
|
</property>
|
||||||
|
<property name="runAsUser">
|
||||||
|
<value>System</value>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Find content created yesterday in the previous 10 years:-
|
||||||
|
set the created date to today and copy to the company home
|
||||||
|
-->
|
||||||
|
<bean id="makeStuffCreatedRecentlyCreatedNow" class="org.alfresco.repo.action.scheduled.CronScheduledQueryBasedTemplateActionDefinition">
|
||||||
|
<property name="transactionMode">
|
||||||
|
<value>UNTIL_FIRST_FAILURE</value>
|
||||||
|
</property>
|
||||||
|
<property name="compensatingActionMode">
|
||||||
|
<value>IGNORE</value>
|
||||||
|
</property>
|
||||||
|
<property name="searchService">
|
||||||
|
<ref bean="SearchService"/>
|
||||||
|
</property>
|
||||||
|
<property name="templateService">
|
||||||
|
<ref bean="TemplateService"/>
|
||||||
|
</property>
|
||||||
|
<property name="queryLanguage">
|
||||||
|
<value>lucene</value>
|
||||||
|
</property>
|
||||||
|
<property name="stores">
|
||||||
|
<list>
|
||||||
|
<value>workspace://SpacesStore</value>
|
||||||
|
</list>
|
||||||
|
</property>
|
||||||
|
<property name="queryTemplate">
|
||||||
|
<value>@cm\:created:${luceneDateRange(yesterday, "-P10Y")}</value>
|
||||||
|
</property>
|
||||||
|
<property name="cronExpression">
|
||||||
|
<value>0 0/1 * * * ?</value>
|
||||||
|
</property>
|
||||||
|
<property name="jobName">
|
||||||
|
<value>jobD</value>
|
||||||
|
</property>
|
||||||
|
<property name="jobGroup">
|
||||||
|
<value>jobGroup</value>
|
||||||
|
</property>
|
||||||
|
<property name="triggerName">
|
||||||
|
<value>triggerD</value>
|
||||||
|
</property>
|
||||||
|
<property name="triggerGroup">
|
||||||
|
<value>triggerGroup</value>
|
||||||
|
</property>
|
||||||
|
<property name="scheduler">
|
||||||
|
<ref bean="schedulerFactory"/>
|
||||||
|
</property>
|
||||||
|
<property name="actionService">
|
||||||
|
<ref bean="ActionService"/>
|
||||||
|
</property>
|
||||||
|
<property name="templateActionModelFactory">
|
||||||
|
<ref bean="templateActionModelFactory"/>
|
||||||
|
</property>
|
||||||
|
<property name="templateActionDefinition">
|
||||||
|
<ref bean="compositeAction"/>
|
||||||
|
</property>
|
||||||
|
<property name="transactionService">
|
||||||
|
<ref bean="TransactionService"/>
|
||||||
|
</property>
|
||||||
|
<property name="runAsUser">
|
||||||
|
<value>System</value>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
</beans>
|
@@ -0,0 +1,645 @@
|
|||||||
|
/*
|
||||||
|
* 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.action.scheduled;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||||
|
import org.alfresco.repo.transaction.TransactionUtil;
|
||||||
|
import org.alfresco.service.cmr.action.Action;
|
||||||
|
import org.alfresco.service.cmr.action.ActionService;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.transaction.TransactionService;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.quartz.Job;
|
||||||
|
import org.quartz.JobDataMap;
|
||||||
|
import org.quartz.JobDetail;
|
||||||
|
import org.quartz.JobExecutionContext;
|
||||||
|
import org.quartz.JobExecutionException;
|
||||||
|
import org.quartz.Scheduler;
|
||||||
|
import org.quartz.SchedulerException;
|
||||||
|
import org.quartz.Trigger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract action support.
|
||||||
|
*
|
||||||
|
* Each action applies to a set of nodes.
|
||||||
|
*
|
||||||
|
* These actions may be executed in one overall transaction or one individual transaction. If actions are in individual transactions an error may halt subsequent execution or
|
||||||
|
* processing can try and invoke the action for each node.
|
||||||
|
*
|
||||||
|
* @author Andy Hind
|
||||||
|
*/
|
||||||
|
public abstract class AbstractScheduledAction implements ScheduledActionDefinition
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Logging
|
||||||
|
*/
|
||||||
|
private static Log s_logger = LogFactory.getLog(AbstractScheduledAction.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum to define the transaction mode.
|
||||||
|
*
|
||||||
|
* @author Andy Hind
|
||||||
|
*/
|
||||||
|
public enum TransactionMode
|
||||||
|
{
|
||||||
|
ISOLATED_TRANSACTIONS, UNTIL_FIRST_FAILURE, ONE_TRANSACTION;
|
||||||
|
|
||||||
|
public static TransactionMode getTransactionMode(String transactionModeString)
|
||||||
|
{
|
||||||
|
TransactionMode transactionMode;
|
||||||
|
if (transactionModeString.equalsIgnoreCase("ISOLATED_TRANSACTIONS"))
|
||||||
|
{
|
||||||
|
transactionMode = TransactionMode.ISOLATED_TRANSACTIONS;
|
||||||
|
}
|
||||||
|
else if (transactionModeString.equalsIgnoreCase("UNTIL_FIRST_FAILURE"))
|
||||||
|
{
|
||||||
|
transactionMode = TransactionMode.UNTIL_FIRST_FAILURE;
|
||||||
|
}
|
||||||
|
else if (transactionModeString.equalsIgnoreCase("ONE_TRANSACTION"))
|
||||||
|
{
|
||||||
|
transactionMode = TransactionMode.ONE_TRANSACTION;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The default ....
|
||||||
|
transactionMode = TransactionMode.ISOLATED_TRANSACTIONS;
|
||||||
|
}
|
||||||
|
return transactionMode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum to define if compensating actions are run.
|
||||||
|
*
|
||||||
|
* @author Andy Hind
|
||||||
|
*/
|
||||||
|
public enum CompensatingActionMode
|
||||||
|
{
|
||||||
|
RUN_COMPENSATING_ACTIONS_ON_FAILURE, IGNORE;
|
||||||
|
|
||||||
|
public static CompensatingActionMode getCompensatingActionMode(String compensatingActionModeString)
|
||||||
|
{
|
||||||
|
CompensatingActionMode compensatingActionMode;
|
||||||
|
if (compensatingActionModeString.equalsIgnoreCase("RUN_COMPENSATING_ACTIONS_ON_FAILURE"))
|
||||||
|
{
|
||||||
|
compensatingActionMode = CompensatingActionMode.RUN_COMPENSATING_ACTIONS_ON_FAILURE;
|
||||||
|
}
|
||||||
|
else if (compensatingActionModeString.equalsIgnoreCase("IGNORE"))
|
||||||
|
{
|
||||||
|
compensatingActionMode = CompensatingActionMode.IGNORE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The default ....
|
||||||
|
compensatingActionMode = CompensatingActionMode.IGNORE;
|
||||||
|
}
|
||||||
|
return compensatingActionMode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Key used to pass the action in the quartz job definition
|
||||||
|
*/
|
||||||
|
private static final String ACTION_JOB_DATA_MAP_KEY = "Action";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The Action service.
|
||||||
|
*/
|
||||||
|
private ActionService actionService;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The user in whose name the action will run.
|
||||||
|
*/
|
||||||
|
private String runAsUser;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The template definition of the action.
|
||||||
|
*/
|
||||||
|
private TemplateActionDefinition templateActionDefinition;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The transaction mode in which all the nodes found by this sceduled action will be treated.
|
||||||
|
*/
|
||||||
|
private TransactionMode transactionMode = TransactionMode.ISOLATED_TRANSACTIONS;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Control if compensating actions will be used. The default is not to apply compensating actions.
|
||||||
|
*/
|
||||||
|
private CompensatingActionMode compensatingActionMode = CompensatingActionMode.IGNORE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The transaction service
|
||||||
|
*/
|
||||||
|
private TransactionService transactionService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple constructor
|
||||||
|
*/
|
||||||
|
public AbstractScheduledAction()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the user in whose name to run the action.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getRunAsUser()
|
||||||
|
{
|
||||||
|
return runAsUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the user in whose name to run the action.
|
||||||
|
*
|
||||||
|
* @param runAsUser
|
||||||
|
*/
|
||||||
|
public void setRunAsUser(String runAsUser)
|
||||||
|
{
|
||||||
|
this.runAsUser = runAsUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the template definition.
|
||||||
|
*/
|
||||||
|
public TemplateActionDefinition getTemplateActionDefinition()
|
||||||
|
{
|
||||||
|
return templateActionDefinition;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the action service - IOC.
|
||||||
|
*
|
||||||
|
* @param actionService
|
||||||
|
*/
|
||||||
|
public void setActionService(ActionService actionService)
|
||||||
|
{
|
||||||
|
this.actionService = actionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the actions service.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ActionService getActionService()
|
||||||
|
{
|
||||||
|
return actionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the behaviour for compensating actiions.
|
||||||
|
*
|
||||||
|
* @param compensatingActionModeString
|
||||||
|
*/
|
||||||
|
public void setCompensatingActionMode(String compensatingActionModeString)
|
||||||
|
{
|
||||||
|
this.compensatingActionMode = CompensatingActionMode.getCompensatingActionMode(compensatingActionModeString);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set transactional behaviour.
|
||||||
|
*
|
||||||
|
* @param transactionModeString
|
||||||
|
*/
|
||||||
|
public void setTransactionMode(String transactionModeString)
|
||||||
|
{
|
||||||
|
this.transactionMode = TransactionMode.getTransactionMode(transactionModeString);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the transaction service.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public TransactionService getTransactionService()
|
||||||
|
{
|
||||||
|
return transactionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the transactions service - IOC.
|
||||||
|
*
|
||||||
|
* @param transactionService
|
||||||
|
*/
|
||||||
|
public void setTransactionService(TransactionService transactionService)
|
||||||
|
{
|
||||||
|
this.transactionService = transactionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the template action that is used to generate the real action for each node.
|
||||||
|
*/
|
||||||
|
public void setTemplateActionDefinition(TemplateActionDefinition templateActionDefinition)
|
||||||
|
{
|
||||||
|
this.templateActionDefinition = templateActionDefinition;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the behaviour for compensating actions.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public CompensatingActionMode getCompensatingActionModeEnum()
|
||||||
|
{
|
||||||
|
return compensatingActionMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the transaction mode.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public TransactionMode getTransactionModeEnum()
|
||||||
|
{
|
||||||
|
return transactionMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void register(Scheduler scheduler) throws SchedulerException
|
||||||
|
{
|
||||||
|
JobDetail jobDetail = getJobDetail();
|
||||||
|
Trigger trigger = getTrigger();
|
||||||
|
|
||||||
|
if (s_logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
s_logger.debug(("Registering job: " + jobDetail));
|
||||||
|
s_logger.debug(("With trigger: " + trigger));
|
||||||
|
}
|
||||||
|
scheduler.scheduleJob(jobDetail, trigger);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the trigger definition for this job. Used to register with the injected scheduler.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public abstract Trigger getTrigger();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of nodes against which this action should run.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public abstract List<NodeRef> getNodes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the actual action for the given node from the action template.
|
||||||
|
*
|
||||||
|
* @param nodeRef
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public abstract Action getAction(NodeRef nodeRef);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the job detail.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private JobDetail getJobDetail()
|
||||||
|
{
|
||||||
|
JobDataMap jobDataMap = new JobDataMap();
|
||||||
|
jobDataMap.put(ACTION_JOB_DATA_MAP_KEY, this);
|
||||||
|
|
||||||
|
JobDetail jobDetail = new JobDetail();
|
||||||
|
jobDetail.setName(getJobName());
|
||||||
|
jobDetail.setGroup(getJobGroup());
|
||||||
|
jobDetail.setJobDataMap(jobDataMap);
|
||||||
|
jobDetail.setJobClass(JobDefinition.class);
|
||||||
|
return jobDetail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Job definition to run scheduled action
|
||||||
|
*
|
||||||
|
* @author Andy Hind
|
||||||
|
*/
|
||||||
|
public static class JobDefinition implements Job
|
||||||
|
{
|
||||||
|
|
||||||
|
public void execute(JobExecutionContext ctx) throws JobExecutionException
|
||||||
|
{
|
||||||
|
final AbstractScheduledAction abstractScheduledAction = (AbstractScheduledAction) ctx.getJobDetail()
|
||||||
|
.getJobDataMap().get(ACTION_JOB_DATA_MAP_KEY);
|
||||||
|
|
||||||
|
// Run as the required user
|
||||||
|
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>()
|
||||||
|
{
|
||||||
|
public Object doWork()
|
||||||
|
{
|
||||||
|
// Get the list of nodes
|
||||||
|
List<NodeRef> nodes = abstractScheduledAction.getNodes();
|
||||||
|
if (s_logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
s_logger.debug("Found " + nodes.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Individual transactions
|
||||||
|
if (abstractScheduledAction.getTransactionModeEnum() == TransactionMode.ONE_TRANSACTION)
|
||||||
|
{
|
||||||
|
if (s_logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
s_logger.debug("Executing in one transaction");
|
||||||
|
}
|
||||||
|
runTransactionalActions(nodes);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// Single global transaction
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
if (s_logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
s_logger.debug("Executing in individual transaction");
|
||||||
|
}
|
||||||
|
for (NodeRef nodeRef : nodes)
|
||||||
|
{
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
runTransactionalAction(nodeRef);
|
||||||
|
}
|
||||||
|
catch (Throwable t)
|
||||||
|
{
|
||||||
|
if (abstractScheduledAction.getTransactionModeEnum() == TransactionMode.ISOLATED_TRANSACTIONS)
|
||||||
|
{
|
||||||
|
s_logger
|
||||||
|
.error(
|
||||||
|
"Error in scheduled action executed in isolated transactions (other actions will continue",
|
||||||
|
t);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throwRuntimeException(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply the action to all nodes in one overall transaction
|
||||||
|
*
|
||||||
|
* @param nodes
|
||||||
|
*/
|
||||||
|
public void runTransactionalActions(final List<NodeRef> nodes)
|
||||||
|
{
|
||||||
|
boolean runCompensatingActions = abstractScheduledAction.getCompensatingActionModeEnum() == CompensatingActionMode.RUN_COMPENSATING_ACTIONS_ON_FAILURE;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
TransactionUtil.executeInUserTransaction(abstractScheduledAction.getTransactionService(),
|
||||||
|
new TransactionUtil.TransactionWork<Object>()
|
||||||
|
{
|
||||||
|
public Object doWork() throws Exception
|
||||||
|
{
|
||||||
|
// Build the full list of compensating actions
|
||||||
|
// If anything goes wrong we need to do all these instead
|
||||||
|
List<Pair<Action, NodeRef>> compensatingActions = new ArrayList<Pair<Action, NodeRef>>(
|
||||||
|
nodes.size());
|
||||||
|
|
||||||
|
for (NodeRef nodeRef : nodes)
|
||||||
|
{
|
||||||
|
Action action = abstractScheduledAction.getAction(nodeRef);
|
||||||
|
Action compensatingAction = action.getCompensatingAction();
|
||||||
|
if (compensatingAction != null)
|
||||||
|
{
|
||||||
|
compensatingActions.add(new Pair<Action, NodeRef>(compensatingAction,
|
||||||
|
nodeRef));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run all the actions
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
for (NodeRef nodeRef : nodes)
|
||||||
|
{
|
||||||
|
Action action = abstractScheduledAction.getAction(nodeRef);
|
||||||
|
abstractScheduledAction.getActionService().executeAction(action,
|
||||||
|
nodeRef);
|
||||||
|
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catch (Throwable t)
|
||||||
|
{
|
||||||
|
// Throw exception to trigger compensating actions
|
||||||
|
throw new CompensatingActionException("Requires compensating action", t,
|
||||||
|
compensatingActions);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Throwable t)
|
||||||
|
{
|
||||||
|
// Do compensation if required
|
||||||
|
doCompensation(runCompensatingActions, true, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run compensating actions.
|
||||||
|
*
|
||||||
|
* These are always in their own transaction. We try to run all compensating actions.
|
||||||
|
*
|
||||||
|
* @param runCompensatingActions
|
||||||
|
* @param rethrow
|
||||||
|
* @param t
|
||||||
|
*/
|
||||||
|
private void doCompensation(boolean runCompensatingActions, boolean rethrow, Throwable t)
|
||||||
|
{
|
||||||
|
// If the error triggers compensation, and they should be processed.
|
||||||
|
if (runCompensatingActions && (t instanceof CompensatingActionException))
|
||||||
|
{
|
||||||
|
CompensatingActionException cae = (CompensatingActionException) t.getCause();
|
||||||
|
for (Pair<Action, NodeRef> pair : cae.getCompensatingActions())
|
||||||
|
if ((pair != null) && (pair.getFirst() != null) && (pair.getSecond() != null))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
|
||||||
|
{
|
||||||
|
// try the compensating action in its own tx
|
||||||
|
runTransactionalCompensatingAction(pair);
|
||||||
|
}
|
||||||
|
catch (Throwable cat)
|
||||||
|
{
|
||||||
|
s_logger.error("Error executing compensating action", t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rethrow)
|
||||||
|
{
|
||||||
|
throwRuntimeException(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run a single transaction in its own tx
|
||||||
|
*
|
||||||
|
* @param nodeRef
|
||||||
|
*/
|
||||||
|
public void runTransactionalAction(final NodeRef nodeRef)
|
||||||
|
{
|
||||||
|
boolean runCompensatingActions = abstractScheduledAction.getCompensatingActionModeEnum() == CompensatingActionMode.RUN_COMPENSATING_ACTIONS_ON_FAILURE;
|
||||||
|
boolean rethrow = abstractScheduledAction.getTransactionModeEnum() != TransactionMode.ISOLATED_TRANSACTIONS;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
TransactionUtil.executeInUserTransaction(abstractScheduledAction.getTransactionService(),
|
||||||
|
new TransactionUtil.TransactionWork<Object>()
|
||||||
|
{
|
||||||
|
public Object doWork() throws Exception
|
||||||
|
{
|
||||||
|
// try action - failure triggers compensation
|
||||||
|
Action action = abstractScheduledAction.getAction(nodeRef);
|
||||||
|
Action compensatingAction = action.getCompensatingAction();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
abstractScheduledAction.getActionService().executeAction(action, nodeRef);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catch (Throwable t)
|
||||||
|
{
|
||||||
|
if (compensatingAction != null)
|
||||||
|
{
|
||||||
|
throw new CompensatingActionException(
|
||||||
|
"Requires compensating action",
|
||||||
|
t,
|
||||||
|
Collections
|
||||||
|
.<Pair<Action, NodeRef>> singletonList(new Pair<Action, NodeRef>(
|
||||||
|
action.getCompensatingAction(), nodeRef)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return throwRuntimeException(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Throwable t)
|
||||||
|
{
|
||||||
|
// Run compensating action if required
|
||||||
|
doCompensation(runCompensatingActions, rethrow, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manage running a compensating action and chaining all its compensating actions until done
|
||||||
|
*
|
||||||
|
* @param pair
|
||||||
|
*/
|
||||||
|
public void runTransactionalCompensatingAction(final Pair<Action, NodeRef> pair)
|
||||||
|
{
|
||||||
|
boolean runCompensatingActions = abstractScheduledAction.getCompensatingActionModeEnum() == CompensatingActionMode.RUN_COMPENSATING_ACTIONS_ON_FAILURE;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
TransactionUtil.executeInUserTransaction(abstractScheduledAction.getTransactionService(),
|
||||||
|
new TransactionUtil.TransactionWork<Object>()
|
||||||
|
{
|
||||||
|
public Object doWork() throws Exception
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
abstractScheduledAction.getActionService().executeAction(pair.getFirst(),
|
||||||
|
pair.getSecond());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catch (Throwable t)
|
||||||
|
{
|
||||||
|
List<Pair<Action, NodeRef>> compensatingActions = new ArrayList<Pair<Action, NodeRef>>(
|
||||||
|
1);
|
||||||
|
if (pair.getFirst().getCompensatingAction() != null)
|
||||||
|
{
|
||||||
|
compensatingActions.add(new Pair<Action, NodeRef>(pair.getFirst()
|
||||||
|
.getCompensatingAction(), pair.getSecond()));
|
||||||
|
}
|
||||||
|
throw new CompensatingActionException("Requires compensating action", t,
|
||||||
|
compensatingActions);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Throwable t)
|
||||||
|
{
|
||||||
|
// Run compensation
|
||||||
|
doCompensation(runCompensatingActions, true, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}, abstractScheduledAction.getRunAsUser());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple class to hold to related objects
|
||||||
|
*
|
||||||
|
* @author Andy Hind
|
||||||
|
*/
|
||||||
|
public static class Pair<FIRST, SECOND>
|
||||||
|
{
|
||||||
|
FIRST first;
|
||||||
|
|
||||||
|
SECOND second;
|
||||||
|
|
||||||
|
Pair(FIRST first, SECOND second)
|
||||||
|
{
|
||||||
|
this.first = first;
|
||||||
|
this.second = second;
|
||||||
|
}
|
||||||
|
|
||||||
|
FIRST getFirst()
|
||||||
|
{
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECOND getSecond()
|
||||||
|
{
|
||||||
|
return second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Support method to translate exceptions to runtime exceptions.
|
||||||
|
*
|
||||||
|
* @param t
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static Object throwRuntimeException(Throwable t)
|
||||||
|
{
|
||||||
|
if (t instanceof RuntimeException)
|
||||||
|
{
|
||||||
|
throw (RuntimeException) t;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new RuntimeException("Error during execution of transaction.", t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* 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.action.scheduled;
|
||||||
|
|
||||||
|
import org.alfresco.service.cmr.action.ActionService;
|
||||||
|
import org.alfresco.service.cmr.repository.TemplateService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common attributes for template action definitions.
|
||||||
|
*
|
||||||
|
* @author Andy Hind
|
||||||
|
*/
|
||||||
|
public abstract class AbstractTemplateActionDefinition implements TemplateActionDefinition
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The action service
|
||||||
|
*/
|
||||||
|
public ActionService actionService;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The template service
|
||||||
|
*/
|
||||||
|
public TemplateService templateService;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The compensating action
|
||||||
|
*/
|
||||||
|
protected TemplateActionDefinition compensatingTemplateActionDefinition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple construction
|
||||||
|
*/
|
||||||
|
public AbstractTemplateActionDefinition()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the action service.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ActionService getActionService()
|
||||||
|
{
|
||||||
|
return actionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the action service - IOC.
|
||||||
|
*
|
||||||
|
* @param actionService
|
||||||
|
*/
|
||||||
|
public void setActionService(ActionService actionService)
|
||||||
|
{
|
||||||
|
this.actionService = actionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the template service.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public TemplateService getTemplateService()
|
||||||
|
{
|
||||||
|
return templateService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the template service - IOC.
|
||||||
|
*
|
||||||
|
* @param templateService
|
||||||
|
*/
|
||||||
|
public void setTemplateService(TemplateService templateService)
|
||||||
|
{
|
||||||
|
this.templateService = templateService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the template to define the compensating action.
|
||||||
|
*
|
||||||
|
* @param compensatingTemplateActionDefinition
|
||||||
|
*/
|
||||||
|
public void setCompensatingTemplateCompositeActionDefinition(
|
||||||
|
TemplateActionDefinition compensatingTemplateActionDefinition)
|
||||||
|
{
|
||||||
|
this.compensatingTemplateActionDefinition = compensatingTemplateActionDefinition;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the template that defines the conpensating action.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public TemplateActionDefinition getCompensatingTemplateCompositeActionDefinition()
|
||||||
|
{
|
||||||
|
return compensatingTemplateActionDefinition;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* 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.action.scheduled;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.alfresco.error.AlfrescoRuntimeException;
|
||||||
|
import org.alfresco.repo.action.scheduled.AbstractScheduledAction.Pair;
|
||||||
|
import org.alfresco.service.cmr.action.Action;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error that triggers the execution of compensating actions.
|
||||||
|
*
|
||||||
|
* The required compensating actions are contained by the exception thrown.
|
||||||
|
*
|
||||||
|
* @author Andy Hind
|
||||||
|
*/
|
||||||
|
public class CompensatingActionException extends AlfrescoRuntimeException
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comment for <code>serialVersionUID</code>
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 2144573075007116603L;
|
||||||
|
|
||||||
|
List<Pair<Action, NodeRef>> compensatingActions;
|
||||||
|
|
||||||
|
public CompensatingActionException(String msgId)
|
||||||
|
{
|
||||||
|
super(msgId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompensatingActionException(String msgId, Throwable cause, List<Pair<Action, NodeRef>> compensatingActions)
|
||||||
|
{
|
||||||
|
super(msgId, cause);
|
||||||
|
this.compensatingActions = compensatingActions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Pair<Action, NodeRef>> getCompensatingActions()
|
||||||
|
{
|
||||||
|
return compensatingActions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompensatingActionException(String msgId, Object[] msgParams)
|
||||||
|
{
|
||||||
|
super(msgId, msgParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompensatingActionException(String msgId, Throwable cause)
|
||||||
|
{
|
||||||
|
super(msgId, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompensatingActionException(String msgId, Object[] msgParams, Throwable cause)
|
||||||
|
{
|
||||||
|
super(msgId, msgParams, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* 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.action.scheduled;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.alfresco.service.cmr.action.Action;
|
||||||
|
import org.alfresco.service.cmr.action.CompositeAction;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The template to define a composite action.
|
||||||
|
*
|
||||||
|
* @author Andy Hind
|
||||||
|
*/
|
||||||
|
public class CompositeTemplateActionDefinition extends AbstractTemplateActionDefinition
|
||||||
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The list of action templates that define this composite
|
||||||
|
*/
|
||||||
|
private List<TemplateActionDefinition> templateActionDefinitions;
|
||||||
|
|
||||||
|
public CompositeTemplateActionDefinition()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the action templates - IOC.
|
||||||
|
*
|
||||||
|
* @param templateActionDefinitions
|
||||||
|
*/
|
||||||
|
public void setTemplateActionDefinitions(List<TemplateActionDefinition> templateActionDefinitions)
|
||||||
|
{
|
||||||
|
this.templateActionDefinitions = templateActionDefinitions;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of template actions.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public List<TemplateActionDefinition> templateActionDefinitions()
|
||||||
|
{
|
||||||
|
return templateActionDefinitions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the composite action in the context of the given node.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public Action getAction(NodeRef nodeRef)
|
||||||
|
{
|
||||||
|
CompositeAction compositeAction = getActionService().createCompositeAction();
|
||||||
|
for(TemplateActionDefinition tad : templateActionDefinitions)
|
||||||
|
{
|
||||||
|
compositeAction.addAction(tad.getAction(nodeRef));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getCompensatingTemplateCompositeActionDefinition() != null)
|
||||||
|
{
|
||||||
|
compositeAction.setCompensatingAction(getCompensatingTemplateCompositeActionDefinition().getAction(nodeRef));
|
||||||
|
}
|
||||||
|
|
||||||
|
return compositeAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,309 @@
|
|||||||
|
/*
|
||||||
|
* 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.action.scheduled;
|
||||||
|
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.alfresco.service.cmr.action.Action;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.cmr.repository.StoreRef;
|
||||||
|
import org.alfresco.service.cmr.repository.TemplateService;
|
||||||
|
import org.alfresco.service.cmr.search.ResultSet;
|
||||||
|
import org.alfresco.service.cmr.search.ResultSetRow;
|
||||||
|
import org.alfresco.service.cmr.search.SearchParameters;
|
||||||
|
import org.alfresco.service.cmr.search.SearchService;
|
||||||
|
import org.quartz.CronTrigger;
|
||||||
|
import org.quartz.Scheduler;
|
||||||
|
import org.quartz.Trigger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A scheduled action for which the trigger is defined in the standard cron format and the nodes to which the
|
||||||
|
* action should be run is defined from the nodes selected by query.
|
||||||
|
*
|
||||||
|
* @author Andy Hind
|
||||||
|
*/
|
||||||
|
public class CronScheduledQueryBasedTemplateActionDefinition extends AbstractScheduledAction
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The search service.
|
||||||
|
*/
|
||||||
|
private SearchService searchService;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The template service.
|
||||||
|
*/
|
||||||
|
private TemplateService templateService;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The query language to use
|
||||||
|
*/
|
||||||
|
private String queryLanguage;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The stores against which the query should run
|
||||||
|
*/
|
||||||
|
private List<String> stores;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The template for the query
|
||||||
|
*/
|
||||||
|
private String queryTemplate;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The cron expression
|
||||||
|
*/
|
||||||
|
private String cronExpression;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The name of the job
|
||||||
|
*/
|
||||||
|
private String jobName;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The job group
|
||||||
|
*/
|
||||||
|
private String jobGroup;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The name of the trigger
|
||||||
|
*/
|
||||||
|
private String triggerName;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The name of the trigger group
|
||||||
|
*/
|
||||||
|
private String triggerGroup;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The scheduler
|
||||||
|
*/
|
||||||
|
private Scheduler scheduler;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The templateModelFactory
|
||||||
|
*
|
||||||
|
* This defines in which template language the query template is defined
|
||||||
|
*/
|
||||||
|
private TemplateActionModelFactory templateActionModelFactory;
|
||||||
|
|
||||||
|
public CronScheduledQueryBasedTemplateActionDefinition()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// IOC
|
||||||
|
//
|
||||||
|
|
||||||
|
public SearchService getSearchService()
|
||||||
|
{
|
||||||
|
return searchService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSearchService(SearchService searchService)
|
||||||
|
{
|
||||||
|
this.searchService = searchService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TemplateService getTemplateService()
|
||||||
|
{
|
||||||
|
return templateService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTemplateService(TemplateService templateService)
|
||||||
|
{
|
||||||
|
this.templateService = templateService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Scheduler getScheduler()
|
||||||
|
{
|
||||||
|
return scheduler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScheduler(Scheduler scheduler)
|
||||||
|
{
|
||||||
|
this.scheduler = scheduler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TemplateActionModelFactory getTemplateActionModelFactory()
|
||||||
|
{
|
||||||
|
return templateActionModelFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTemplateActionModelFactory(TemplateActionModelFactory templateActionModelFactory)
|
||||||
|
{
|
||||||
|
this.templateActionModelFactory = templateActionModelFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// End of IOC
|
||||||
|
//
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Trigger getTrigger()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return new CronTrigger(getTriggerName(), getTriggerGroup(), getCronExpression());
|
||||||
|
}
|
||||||
|
catch (ParseException e)
|
||||||
|
{
|
||||||
|
throw new InvalidCronExpression("Invalid chron expression: n" + getCronExpression());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<NodeRef> getNodes()
|
||||||
|
{
|
||||||
|
LinkedList<NodeRef> nodeRefs = new LinkedList<NodeRef>();
|
||||||
|
|
||||||
|
// Build the actual query string
|
||||||
|
String queryTemplate = getQueryTemplate();
|
||||||
|
String query = templateService.processTemplateString(getTemplateActionModelFactory().getTemplateEngine(),
|
||||||
|
queryTemplate, getTemplateActionModelFactory().getModel());
|
||||||
|
|
||||||
|
// Execute the query
|
||||||
|
SearchParameters sp = new SearchParameters();
|
||||||
|
sp.setLanguage(getQueryLanguage());
|
||||||
|
sp.setQuery(query);
|
||||||
|
for (String storeRef : getStores())
|
||||||
|
{
|
||||||
|
sp.addStore(new StoreRef(storeRef));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform the reults into a node list
|
||||||
|
ResultSet results = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
results = searchService.query(sp);
|
||||||
|
for (ResultSetRow row : results)
|
||||||
|
{
|
||||||
|
nodeRefs.add(row.getNodeRef());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (results != null)
|
||||||
|
{
|
||||||
|
results.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nodeRefs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Action getAction(NodeRef nodeRef)
|
||||||
|
{
|
||||||
|
// Use the template to build its action
|
||||||
|
return getTemplateActionDefinition().getAction(nodeRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// IOC/Getters/Setters for instance variables
|
||||||
|
//
|
||||||
|
|
||||||
|
public void setQueryLanguage(String queryLanguage)
|
||||||
|
{
|
||||||
|
this.queryLanguage = queryLanguage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getQueryLanguage()
|
||||||
|
{
|
||||||
|
return queryLanguage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStores(List<String> stores)
|
||||||
|
{
|
||||||
|
this.stores = stores;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getStores()
|
||||||
|
{
|
||||||
|
return stores;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setQueryTemplate(String queryTemplate)
|
||||||
|
{
|
||||||
|
this.queryTemplate = queryTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getQueryTemplate()
|
||||||
|
{
|
||||||
|
return queryTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCronExpression(String cronExpression)
|
||||||
|
{
|
||||||
|
this.cronExpression = cronExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCronExpression()
|
||||||
|
{
|
||||||
|
return cronExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJobName(String jobName)
|
||||||
|
{
|
||||||
|
this.jobName = jobName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJobName()
|
||||||
|
{
|
||||||
|
return jobName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJobGroup(String jobGroup)
|
||||||
|
{
|
||||||
|
this.jobGroup = jobGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJobGroup()
|
||||||
|
{
|
||||||
|
return jobGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTriggerName(String triggerName)
|
||||||
|
{
|
||||||
|
this.triggerName = triggerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTriggerName()
|
||||||
|
{
|
||||||
|
return triggerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTriggerGroup(String triggerGroup)
|
||||||
|
{
|
||||||
|
this.triggerGroup = triggerGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTriggerGroup()
|
||||||
|
{
|
||||||
|
return this.triggerGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register with the scheduler.
|
||||||
|
*/
|
||||||
|
public void afterPropertiesSet() throws Exception
|
||||||
|
{
|
||||||
|
register(getScheduler());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,150 @@
|
|||||||
|
/*
|
||||||
|
* 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.action.scheduled;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.GregorianCalendar;
|
||||||
|
|
||||||
|
import javax.transaction.UserTransaction;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||||
|
import org.alfresco.service.ServiceRegistry;
|
||||||
|
import org.alfresco.service.cmr.repository.datatype.Duration;
|
||||||
|
import org.alfresco.service.transaction.TransactionService;
|
||||||
|
import org.alfresco.util.ApplicationContextHelper;
|
||||||
|
import org.alfresco.util.ISO8601DateFormat;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that the correct date ranges are generated for lucene
|
||||||
|
*
|
||||||
|
* @author Andy Hind
|
||||||
|
*/
|
||||||
|
public class FreeMarkerModelLuceneFunctionTest extends TestCase
|
||||||
|
{
|
||||||
|
//private static SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sssZ");
|
||||||
|
private static SimpleDateFormat SDF2 = new SimpleDateFormat("yyyy-MM-dd");
|
||||||
|
|
||||||
|
private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
|
||||||
|
private AuthenticationComponent authenticationComponent;
|
||||||
|
private ServiceRegistry serviceRegistry;
|
||||||
|
private UserTransaction tx;
|
||||||
|
|
||||||
|
private Date today;
|
||||||
|
|
||||||
|
public FreeMarkerModelLuceneFunctionTest()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public FreeMarkerModelLuceneFunctionTest(String arg0)
|
||||||
|
{
|
||||||
|
super(arg0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUp() throws Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
authenticationComponent = (AuthenticationComponent) ctx.getBean("authenticationComponentImpl");
|
||||||
|
serviceRegistry = (ServiceRegistry) ctx.getBean("ServiceRegistry");
|
||||||
|
|
||||||
|
this.authenticationComponent.setSystemUserAsCurrentUser();
|
||||||
|
|
||||||
|
TransactionService transactionService = (TransactionService) ctx.getBean(ServiceRegistry.TRANSACTION_SERVICE
|
||||||
|
.getLocalName());
|
||||||
|
tx = transactionService.getUserTransaction();
|
||||||
|
tx.begin();
|
||||||
|
|
||||||
|
GregorianCalendar cal = new GregorianCalendar();
|
||||||
|
cal.set(Calendar.HOUR, 0);
|
||||||
|
cal.set(Calendar.MINUTE, 0);
|
||||||
|
cal.set(Calendar.SECOND, 0);
|
||||||
|
cal.set(Calendar.MILLISECOND, 0);
|
||||||
|
|
||||||
|
today = cal.getTime();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void tearDown() throws Exception
|
||||||
|
{
|
||||||
|
authenticationComponent.clearCurrentSecurityContext();
|
||||||
|
tx.rollback();
|
||||||
|
super.tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDate()
|
||||||
|
{
|
||||||
|
String template = "${date?date?string(\"yyyy-MM-dd\")}";
|
||||||
|
FreeMarkerWithLuceneExtensionsModelFactory mf = new FreeMarkerWithLuceneExtensionsModelFactory();
|
||||||
|
mf.setServiceRegistry(serviceRegistry);
|
||||||
|
String result = serviceRegistry.getTemplateService().processTemplateString("freemarker", template, mf.getModel());
|
||||||
|
assertEquals(result, SDF2.format(new Date()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testLuceneDateRangeFunction()
|
||||||
|
{
|
||||||
|
String template = "${luceneDateRange(\"2000-01-01T00:00:00.000Z\", \"P1D\")}";
|
||||||
|
FreeMarkerWithLuceneExtensionsModelFactory mf = new FreeMarkerWithLuceneExtensionsModelFactory();
|
||||||
|
mf.setServiceRegistry(serviceRegistry);
|
||||||
|
String result = serviceRegistry.getTemplateService().processTemplateString("freemarker", template, mf.getModel());
|
||||||
|
assertEquals(result, "[2000-01-01T00:00:00.000Z TO 2000-01-02T00:00:00.000Z]");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testLuceneDateRangeFunctionToAdte()
|
||||||
|
{
|
||||||
|
String template = "${luceneDateRange(\"2000-01-01T00:00:00.000Z\", \"2000-01-05T00:00:00.000Z\")}";
|
||||||
|
FreeMarkerWithLuceneExtensionsModelFactory mf = new FreeMarkerWithLuceneExtensionsModelFactory();
|
||||||
|
mf.setServiceRegistry(serviceRegistry);
|
||||||
|
String result = serviceRegistry.getTemplateService().processTemplateString("freemarker", template, mf.getModel());
|
||||||
|
assertEquals(result, "[2000-01-01T00:00:00.000Z TO 2000-01-05T00:00:00.000Z]");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testLuceneDateRangeFunctionTodayPlus4()
|
||||||
|
{
|
||||||
|
String template = "${luceneDateRange(today, \"P4D\")}";
|
||||||
|
FreeMarkerWithLuceneExtensionsModelFactory mf = new FreeMarkerWithLuceneExtensionsModelFactory();
|
||||||
|
mf.setServiceRegistry(serviceRegistry);
|
||||||
|
String result = serviceRegistry.getTemplateService().processTemplateString("freemarker", template, mf.getModel());
|
||||||
|
assertNotNull(result);
|
||||||
|
assertEquals(result, "["+ISO8601DateFormat.format(today) + " TO " + ISO8601DateFormat.format(Duration.add(today, new Duration("P4D"))) + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testLuceneDateRangeFunctionTodayMinus4()
|
||||||
|
{
|
||||||
|
String template = "${luceneDateRange(today, \"-P4D\")}";
|
||||||
|
FreeMarkerWithLuceneExtensionsModelFactory mf = new FreeMarkerWithLuceneExtensionsModelFactory();
|
||||||
|
mf.setServiceRegistry(serviceRegistry);
|
||||||
|
String result = serviceRegistry.getTemplateService().processTemplateString("freemarker", template, mf.getModel());
|
||||||
|
assertEquals(result, "["+ ISO8601DateFormat.format(Duration.add(today, new Duration("-P4D"))) + " TO " + ISO8601DateFormat.format(today) + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testLuceneDateRangeFunctionTodayToday()
|
||||||
|
{
|
||||||
|
String template = "${luceneDateRange(today, today)}";
|
||||||
|
FreeMarkerWithLuceneExtensionsModelFactory mf = new FreeMarkerWithLuceneExtensionsModelFactory();
|
||||||
|
mf.setServiceRegistry(serviceRegistry);
|
||||||
|
String result = serviceRegistry.getTemplateService().processTemplateString("freemarker", template, mf.getModel());
|
||||||
|
assertEquals(result, "["+ISO8601DateFormat.format(today) + " TO " + ISO8601DateFormat.format(today) + "]");
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,277 @@
|
|||||||
|
/*
|
||||||
|
* 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.action.scheduled;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.GregorianCalendar;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.alfresco.service.ServiceRegistry;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.cmr.repository.StoreRef;
|
||||||
|
import org.alfresco.service.cmr.repository.TemplateNode;
|
||||||
|
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||||
|
import org.alfresco.service.cmr.repository.datatype.Duration;
|
||||||
|
import org.alfresco.service.cmr.search.ResultSet;
|
||||||
|
import org.alfresco.service.cmr.search.SearchParameters;
|
||||||
|
import org.alfresco.util.ISO8601DateFormat;
|
||||||
|
|
||||||
|
import freemarker.template.TemplateDateModel;
|
||||||
|
import freemarker.template.TemplateMethodModelEx;
|
||||||
|
import freemarker.template.TemplateModelException;
|
||||||
|
import freemarker.template.TemplateScalarModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A factory implementation to build suitable models for the freemarker templating language.
|
||||||
|
*
|
||||||
|
* @author Andy Hind
|
||||||
|
*/
|
||||||
|
public class FreeMarkerWithLuceneExtensionsModelFactory implements TemplateActionModelFactory
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Service registry
|
||||||
|
*/
|
||||||
|
private ServiceRegistry serviceRegistry;
|
||||||
|
|
||||||
|
public FreeMarkerWithLuceneExtensionsModelFactory()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
// IOC
|
||||||
|
|
||||||
|
public void setServiceRegistry(ServiceRegistry serviceRegistry)
|
||||||
|
{
|
||||||
|
this.serviceRegistry = serviceRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the non-contextual model.
|
||||||
|
*
|
||||||
|
* This defines:
|
||||||
|
* <ol>
|
||||||
|
* <li>dates: date, today, yesterday, tomorrow
|
||||||
|
* <li>functions: luceneDateRange, selectSingleNode
|
||||||
|
* </ol>
|
||||||
|
*/
|
||||||
|
public Map<String, Object> getModel()
|
||||||
|
{
|
||||||
|
GregorianCalendar cal = new GregorianCalendar();
|
||||||
|
cal.set(Calendar.HOUR, 0);
|
||||||
|
cal.set(Calendar.MINUTE, 0);
|
||||||
|
cal.set(Calendar.SECOND, 0);
|
||||||
|
cal.set(Calendar.MILLISECOND, 0);
|
||||||
|
|
||||||
|
HashMap<String, Object> model = new HashMap<String, Object>();
|
||||||
|
|
||||||
|
model.put("date", new Date());
|
||||||
|
|
||||||
|
Date today = cal.getTime();
|
||||||
|
model.put("today", today);
|
||||||
|
|
||||||
|
model.put("yesterday", Duration.add(today, new Duration("-P1D")));
|
||||||
|
|
||||||
|
model.put("tomorrow", Duration.add(today, new Duration("P1D")));
|
||||||
|
|
||||||
|
model.put("luceneDateRange", new LuceneDateRangeFunction());
|
||||||
|
|
||||||
|
model.put("selectSingleNode", new QueryForSingleNodeFunction());
|
||||||
|
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a non-contextual nod model + the contextual node
|
||||||
|
*/
|
||||||
|
public Map<String, Object> getModel(NodeRef nodeRef)
|
||||||
|
{
|
||||||
|
Map<String, Object> model = getModel();
|
||||||
|
|
||||||
|
TemplateNode companyRootNode = new TemplateNode(nodeRef, serviceRegistry, null);
|
||||||
|
model.put("node", companyRootNode);
|
||||||
|
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to find a single node by query
|
||||||
|
*
|
||||||
|
* @author Andy Hind
|
||||||
|
*/
|
||||||
|
private class QueryForSingleNodeFunction implements TemplateMethodModelEx
|
||||||
|
{
|
||||||
|
public Object exec(List args) throws TemplateModelException
|
||||||
|
{
|
||||||
|
if (args.size() == 3)
|
||||||
|
{
|
||||||
|
Object arg0 = args.get(0);
|
||||||
|
Object arg1 = args.get(1);
|
||||||
|
Object arg2 = args.get(2);
|
||||||
|
StoreRef storeRef;
|
||||||
|
String language;
|
||||||
|
String query;
|
||||||
|
|
||||||
|
if (arg0 instanceof TemplateScalarModel)
|
||||||
|
{
|
||||||
|
storeRef = new StoreRef(((TemplateScalarModel) arg0).getAsString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new TemplateModelException("Invalid store string");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg1 instanceof TemplateScalarModel)
|
||||||
|
{
|
||||||
|
language = ((TemplateScalarModel) arg1).getAsString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new TemplateModelException("Invalid language string");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg2 instanceof TemplateScalarModel)
|
||||||
|
{
|
||||||
|
query = ((TemplateScalarModel) arg2).getAsString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new TemplateModelException("Invalid query string");
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchParameters sp = new SearchParameters();
|
||||||
|
sp.addStore(storeRef);
|
||||||
|
sp.setLanguage(language);
|
||||||
|
sp.setQuery(query);
|
||||||
|
|
||||||
|
ResultSet results = serviceRegistry.getSearchService().query(sp);
|
||||||
|
|
||||||
|
if (results.length() == 0)
|
||||||
|
{
|
||||||
|
throw new TemplateModelException("No nodes selected");
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (results.length() == 1)
|
||||||
|
{
|
||||||
|
return results.getNodeRef(0).toString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new TemplateModelException("More than one node selected");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new TemplateModelException("Incorrect arguments");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to generate the date range portion of a lucene query
|
||||||
|
*
|
||||||
|
* @author Andy Hind
|
||||||
|
*/
|
||||||
|
private static class LuceneDateRangeFunction implements TemplateMethodModelEx
|
||||||
|
{
|
||||||
|
|
||||||
|
public Object exec(List args) throws TemplateModelException
|
||||||
|
{
|
||||||
|
if (args.size() == 2)
|
||||||
|
{
|
||||||
|
|
||||||
|
Object arg0 = args.get(0);
|
||||||
|
Object arg1 = args.get(1);
|
||||||
|
|
||||||
|
Date startDate = null;
|
||||||
|
Date endDate = null;
|
||||||
|
|
||||||
|
if (arg0 instanceof TemplateDateModel)
|
||||||
|
{
|
||||||
|
startDate = (Date) ((TemplateDateModel) arg0).getAsDate();
|
||||||
|
}
|
||||||
|
else if (arg0 instanceof TemplateScalarModel)
|
||||||
|
{
|
||||||
|
String startDateString = ((TemplateScalarModel) arg0).getAsString();
|
||||||
|
startDate = ISO8601DateFormat.parse(startDateString);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new TemplateModelException("Invalid date entry");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg1 instanceof TemplateDateModel)
|
||||||
|
{
|
||||||
|
endDate = (Date) ((TemplateDateModel) arg0).getAsDate();
|
||||||
|
}
|
||||||
|
else if (arg1 instanceof TemplateScalarModel)
|
||||||
|
{
|
||||||
|
|
||||||
|
String valueString = ((TemplateScalarModel) arg1).getAsString();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Duration duration = new Duration(valueString);
|
||||||
|
endDate = Duration.add(startDate, duration);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
endDate = ISO8601DateFormat.parse(valueString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new TemplateModelException("Invalid date entry");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startDate.compareTo(endDate) > 0)
|
||||||
|
{
|
||||||
|
Date temp = startDate;
|
||||||
|
startDate = endDate;
|
||||||
|
endDate = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
builder.append("[");
|
||||||
|
builder.append(DefaultTypeConverter.INSTANCE.convert(String.class, startDate));
|
||||||
|
builder.append(" TO ");
|
||||||
|
builder.append(DefaultTypeConverter.INSTANCE.convert(String.class, endDate));
|
||||||
|
builder.append("]");
|
||||||
|
|
||||||
|
return builder.toString();
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new TemplateModelException("Invalid date entry");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the template engine for which this model applies.
|
||||||
|
* In this case, "freemarker".
|
||||||
|
*/
|
||||||
|
public String getTemplateEngine()
|
||||||
|
{
|
||||||
|
return "freemarker";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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.action.scheduled;
|
||||||
|
|
||||||
|
public class InvalidCronExpression extends ScheduledActionException
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comment for <code>serialVersionUID</code>
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = -6618964886875008727L;
|
||||||
|
|
||||||
|
public InvalidCronExpression(String msgId)
|
||||||
|
{
|
||||||
|
super(msgId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvalidCronExpression(String msgId, Object[] msgParams)
|
||||||
|
{
|
||||||
|
super(msgId, msgParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvalidCronExpression(String msgId, Throwable cause)
|
||||||
|
{
|
||||||
|
super(msgId, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvalidCronExpression(String msgId, Object[] msgParams, Throwable cause)
|
||||||
|
{
|
||||||
|
super(msgId, msgParams, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* 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.action.scheduled;
|
||||||
|
|
||||||
|
import org.quartz.Scheduler;
|
||||||
|
import org.quartz.SchedulerException;
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The information needed to schedule a job.
|
||||||
|
*
|
||||||
|
* The implementation is responsible for creating job details, triggers and registering with a scheduler.
|
||||||
|
*
|
||||||
|
* This is not used anywhere at the moment. When we have a service then scheduled actions will be registered with the service.
|
||||||
|
*
|
||||||
|
* @author Andy Hind
|
||||||
|
*/
|
||||||
|
public interface ScheduledActionDefinition extends InitializingBean
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Set the template action definition that is used to build the Action to execute.
|
||||||
|
*
|
||||||
|
* @param templateActionDefinition
|
||||||
|
*/
|
||||||
|
public void setTemplateActionDefinition(TemplateActionDefinition templateActionDefinition);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the template action definition that is used to build the Action to execute.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public TemplateActionDefinition getTemplateActionDefinition();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register with a scheduler. This should be called in the implementation afterPropertiesSet() method of InitializingBean
|
||||||
|
*
|
||||||
|
* @param scheduler
|
||||||
|
* @throws SchedulerException
|
||||||
|
*/
|
||||||
|
public void register(Scheduler scheduler) throws SchedulerException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the name of the job - used for job admin
|
||||||
|
*
|
||||||
|
* @param jobName
|
||||||
|
*/
|
||||||
|
public void setJobName(String jobName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the name of the job - used for job admin
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getJobName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the job group - used for job admin
|
||||||
|
*
|
||||||
|
* @param jobGroup
|
||||||
|
*/
|
||||||
|
public void setJobGroup(String jobGroup);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the job group - used for job admin
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getJobGroup();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the trigger name - used for job admin
|
||||||
|
*
|
||||||
|
* @param triggerName
|
||||||
|
*/
|
||||||
|
public void setTriggerName(String triggerName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the trigger name - used for job admin
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getTriggerName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the trigger group - used for job admin
|
||||||
|
*
|
||||||
|
* @param triggerGroup
|
||||||
|
*/
|
||||||
|
public void setTriggerGroup(String triggerGroup);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the trigger group - used for job admin
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getTriggerGroup();
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* 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.action.scheduled;
|
||||||
|
|
||||||
|
import org.alfresco.error.AlfrescoRuntimeException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base exception for sceduled actions.
|
||||||
|
*
|
||||||
|
* @author Andy Hind
|
||||||
|
*/
|
||||||
|
public class ScheduledActionException extends AlfrescoRuntimeException
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comment for <code>serialVersionUID</code>
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = -543079391770744598L;
|
||||||
|
|
||||||
|
public ScheduledActionException(String msgId)
|
||||||
|
{
|
||||||
|
super(msgId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScheduledActionException(String msgId, Object[] msgParams)
|
||||||
|
{
|
||||||
|
super(msgId, msgParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScheduledActionException(String msgId, Throwable cause)
|
||||||
|
{
|
||||||
|
super(msgId, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScheduledActionException(String msgId, Object[] msgParams, Throwable cause)
|
||||||
|
{
|
||||||
|
super(msgId, msgParams, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,224 @@
|
|||||||
|
/*
|
||||||
|
* 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.action.scheduled;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.alfresco.repo.action.executer.ActionExecuter;
|
||||||
|
import org.alfresco.service.cmr.action.Action;
|
||||||
|
import org.alfresco.service.cmr.action.ActionDefinition;
|
||||||
|
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||||
|
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeService;
|
||||||
|
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||||
|
import org.alfresco.service.namespace.QName;
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.ApplicationContextAware;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class defines the template used to build a single action.
|
||||||
|
*
|
||||||
|
* @author Andy Hind
|
||||||
|
*/
|
||||||
|
public class SimpleTemplateActionDefinition extends AbstractTemplateActionDefinition implements ApplicationContextAware
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The name of the action
|
||||||
|
*/
|
||||||
|
private String actionName;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The parameters used by the action
|
||||||
|
*/
|
||||||
|
private Map<String, String> parameterTemplates;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The model factory to build models appropriate to the template language used to define
|
||||||
|
* templated parameters.
|
||||||
|
*/
|
||||||
|
private TemplateActionModelFactory templateActionModelFactory;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The dictionary service.
|
||||||
|
*/
|
||||||
|
private DictionaryService dictionaryService;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The application context
|
||||||
|
* (Some actions are not publicly exposed via the action service.
|
||||||
|
* They can always be obtained via the appropriate action excecutor.)
|
||||||
|
*/
|
||||||
|
private ApplicationContext applicationContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple constructor.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public SimpleTemplateActionDefinition()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the template model factory.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public TemplateActionModelFactory getTemplateActionModelFactory()
|
||||||
|
{
|
||||||
|
return templateActionModelFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the template model factory IOC.
|
||||||
|
*
|
||||||
|
* @param templateActionModelFactory
|
||||||
|
*/
|
||||||
|
public void setTemplateActionModelFactory(TemplateActionModelFactory templateActionModelFactory)
|
||||||
|
{
|
||||||
|
this.templateActionModelFactory = templateActionModelFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the dictionary service.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public DictionaryService getDictionaryService()
|
||||||
|
{
|
||||||
|
return dictionaryService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the dictionary service - IOC.
|
||||||
|
*
|
||||||
|
* @param dictionaryService
|
||||||
|
*/
|
||||||
|
public void setDictionaryService(DictionaryService dictionaryService)
|
||||||
|
{
|
||||||
|
this.dictionaryService = dictionaryService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the name of the action.
|
||||||
|
*
|
||||||
|
* @param actionName
|
||||||
|
*/
|
||||||
|
public void setActionName(String actionName)
|
||||||
|
{
|
||||||
|
this.actionName = actionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the name of the action.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getActionName()
|
||||||
|
{
|
||||||
|
return actionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the map of parameters used by the template.
|
||||||
|
* These are processed via the template service to produce the actual poarameters.
|
||||||
|
*
|
||||||
|
* @param parameterTemplates
|
||||||
|
*/
|
||||||
|
public void setParameterTemplates(Map<String, String> parameterTemplates)
|
||||||
|
{
|
||||||
|
this.parameterTemplates = parameterTemplates;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the templates that define the parameters for the action.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Map<String, String> getParameterTemplates()
|
||||||
|
{
|
||||||
|
return parameterTemplates;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the action from the template using the context node.
|
||||||
|
*/
|
||||||
|
public Action getAction(NodeRef nodeRef)
|
||||||
|
{
|
||||||
|
// Get the action definition. We can not go to the service are some are not exposed.
|
||||||
|
// So we find them from the application context.
|
||||||
|
ActionExecuter actionExecutor = (ActionExecuter)applicationContext.getBean(getActionName());
|
||||||
|
ActionDefinition actionDefinition = actionExecutor.getActionDefinition();
|
||||||
|
|
||||||
|
|
||||||
|
// Build the base action
|
||||||
|
Action action = actionService.createAction(getActionName());
|
||||||
|
|
||||||
|
// Go through the template definitions and set the values.
|
||||||
|
for (String paramName : parameterTemplates.keySet())
|
||||||
|
{
|
||||||
|
// Transform the template
|
||||||
|
String template = parameterTemplates.get(paramName);
|
||||||
|
String stringValue = templateService.processTemplateString(getTemplateActionModelFactory()
|
||||||
|
.getTemplateEngine(), template, getTemplateActionModelFactory().getModel(nodeRef));
|
||||||
|
|
||||||
|
// Find the data type from the action defintion
|
||||||
|
DataTypeDefinition dataTypeDef;
|
||||||
|
if (actionDefinition.getParameterDefintion(paramName) != null)
|
||||||
|
{
|
||||||
|
dataTypeDef = dictionaryService
|
||||||
|
.getDataType(actionDefinition.getParameterDefintion(paramName).getType());
|
||||||
|
}
|
||||||
|
// Fall back to the DD using the property name of it is not defined
|
||||||
|
// This is sometimes used for setting a property to a value.
|
||||||
|
// There can be no definition for such an ad hoc property.
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dataTypeDef = dictionaryService.getProperty(QName.createQName(paramName)).getDataType();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the template result into the correct type and set the parameter
|
||||||
|
Object value = DefaultTypeConverter.INSTANCE.convert(dataTypeDef, stringValue);
|
||||||
|
if (value instanceof Serializable)
|
||||||
|
{
|
||||||
|
action.setParameterValue(paramName, (Serializable) value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is a compensating action then set it.
|
||||||
|
if (getCompensatingTemplateCompositeActionDefinition() != null)
|
||||||
|
{
|
||||||
|
action.setCompensatingAction(getCompensatingTemplateCompositeActionDefinition().getAction(nodeRef));
|
||||||
|
}
|
||||||
|
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ApplciationContextAware - get the application context.
|
||||||
|
*/
|
||||||
|
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
|
||||||
|
{
|
||||||
|
this.applicationContext = applicationContext;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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.action.scheduled;
|
||||||
|
|
||||||
|
import org.alfresco.service.cmr.action.Action;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A template action definition is used to generate an action from a template style
|
||||||
|
* definition.
|
||||||
|
*
|
||||||
|
* @author Andy Hind
|
||||||
|
*/
|
||||||
|
public interface TemplateActionDefinition
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Generate an action definition for the action defined by this template.
|
||||||
|
*
|
||||||
|
* @param nodeRef
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Action getAction(NodeRef nodeRef);
|
||||||
|
}
|
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* 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.action.scheduled;
|
||||||
|
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A factory that builds models to use with a particular template engine for use with scheduled actions built
|
||||||
|
* from action templates.
|
||||||
|
*
|
||||||
|
* @author Andy Hind
|
||||||
|
*/
|
||||||
|
public interface TemplateActionModelFactory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get the name of the template engine for which this factory applies
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getTemplateEngine();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a model with no default node context.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Object getModel();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a model with a default node context.
|
||||||
|
*
|
||||||
|
* @param nodeRef
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Object getModel(NodeRef nodeRef);
|
||||||
|
}
|
@@ -23,9 +23,11 @@ import org.alfresco.service.cmr.repository.ContentService;
|
|||||||
import org.alfresco.service.cmr.repository.NodeService;
|
import org.alfresco.service.cmr.repository.NodeService;
|
||||||
import org.alfresco.service.cmr.repository.TemplateException;
|
import org.alfresco.service.cmr.repository.TemplateException;
|
||||||
import org.alfresco.service.cmr.repository.TemplateProcessor;
|
import org.alfresco.service.cmr.repository.TemplateProcessor;
|
||||||
|
import org.alfresco.util.ISO9075;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import freemarker.cache.MruCacheStorage;
|
import freemarker.cache.MruCacheStorage;
|
||||||
|
import freemarker.cache.StringTemplateLoader;
|
||||||
import freemarker.template.Configuration;
|
import freemarker.template.Configuration;
|
||||||
import freemarker.template.Template;
|
import freemarker.template.Template;
|
||||||
import freemarker.template.TemplateExceptionHandler;
|
import freemarker.template.TemplateExceptionHandler;
|
||||||
@@ -98,6 +100,28 @@ public class FreeMarkerProcessor implements TemplateProcessor
|
|||||||
return this.config;
|
return this.config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Configuration getStringConfig(String path, String template)
|
||||||
|
{
|
||||||
|
|
||||||
|
Configuration config = new Configuration();
|
||||||
|
|
||||||
|
// setup template cache
|
||||||
|
config.setCacheStorage(new MruCacheStorage(20, 0));
|
||||||
|
|
||||||
|
// use our custom loader to find templates on the ClassPath
|
||||||
|
StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
|
||||||
|
stringTemplateLoader.putTemplate(path, template);
|
||||||
|
config.setTemplateLoader(stringTemplateLoader);
|
||||||
|
|
||||||
|
// use our custom object wrapper that can deal with QNameMap objects directly
|
||||||
|
config.setObjectWrapper(new QNameAwareObjectWrapper());
|
||||||
|
|
||||||
|
// rethrow any exception so we can deal with them
|
||||||
|
config.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see org.alfresco.service.cmr.repository.TemplateProcessor#process(java.lang.String, java.lang.Object, java.io.Writer)
|
* @see org.alfresco.service.cmr.repository.TemplateProcessor#process(java.lang.String, java.lang.Object, java.io.Writer)
|
||||||
*/
|
*/
|
||||||
@@ -144,4 +168,50 @@ public class FreeMarkerProcessor implements TemplateProcessor
|
|||||||
throw new TemplateException(MSG_ERROR_TEMPLATE_IO, new Object[] {template}, ioerr);
|
throw new TemplateException(MSG_ERROR_TEMPLATE_IO, new Object[] {template}, ioerr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final String PATH = "string://fixed";
|
||||||
|
|
||||||
|
public void processString(String template, Object model, Writer out)
|
||||||
|
{
|
||||||
|
if (template == null || template.length() == 0)
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("Template is mandatory.");
|
||||||
|
}
|
||||||
|
if (model == null)
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("Model is mandatory.");
|
||||||
|
}
|
||||||
|
if (out == null)
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("Output Writer is mandatory.");
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
logger.debug("Executing template: " + template + " on model: " + model);
|
||||||
|
|
||||||
|
Template t = getStringConfig(PATH, template).getTemplate(PATH);
|
||||||
|
if (t != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// perform the template processing against supplied data model
|
||||||
|
t.process(model, out);
|
||||||
|
}
|
||||||
|
catch (Throwable err)
|
||||||
|
{
|
||||||
|
throw new TemplateException(MSG_ERROR_TEMPLATE_FAIL, new Object[] {err.getMessage()}, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new TemplateException(MSG_ERROR_NO_TEMPLATE, new Object[] {template});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException ioerr)
|
||||||
|
{
|
||||||
|
throw new TemplateException(MSG_ERROR_TEMPLATE_IO, new Object[] {template}, ioerr);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -48,7 +48,7 @@ public class TemplateServiceImpl implements TemplateService, ApplicationContextA
|
|||||||
private Map<String, String> templateEngines;
|
private Map<String, String> templateEngines;
|
||||||
|
|
||||||
/** Threadlocal instance for template processor cache */
|
/** Threadlocal instance for template processor cache */
|
||||||
private static ThreadLocal<Map<String, TemplateProcessor>> processors = new ThreadLocal();
|
private static ThreadLocal<Map<String, TemplateProcessor>> processors = new ThreadLocal<Map<String, TemplateProcessor>>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the application context
|
* Set the application context
|
||||||
@@ -127,6 +127,36 @@ public class TemplateServiceImpl implements TemplateService, ApplicationContextA
|
|||||||
return out.toString();
|
return out.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void processTemplateString(String engine, String template, Object model, Writer out)
|
||||||
|
throws TemplateException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// execute template processor
|
||||||
|
TemplateProcessor processor = getTemplateProcessorImpl(engine);
|
||||||
|
processor.processString(template, model, out);
|
||||||
|
}
|
||||||
|
catch (TemplateException terr)
|
||||||
|
{
|
||||||
|
throw terr;
|
||||||
|
}
|
||||||
|
catch (Throwable err)
|
||||||
|
{
|
||||||
|
throw new TemplateException(err.getMessage(), err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String processTemplateString(String engine, String template, Object model)
|
||||||
|
throws TemplateException
|
||||||
|
{
|
||||||
|
Writer out = new StringWriter(1024);
|
||||||
|
processTemplateString(engine, template, model, out);
|
||||||
|
return out.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the TemplateProcessor implementation for the named template engine
|
* Return the TemplateProcessor implementation for the named template engine
|
||||||
*
|
*
|
||||||
|
@@ -92,6 +92,8 @@ public final class TemplateNode implements Serializable
|
|||||||
private TemplateImageResolver imageResolver = null;
|
private TemplateImageResolver imageResolver = null;
|
||||||
private TemplateNode parent = null;
|
private TemplateNode parent = null;
|
||||||
|
|
||||||
|
private ChildAssociationRef primaryParentAssoc;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
@@ -491,6 +493,19 @@ public final class TemplateNode implements Serializable
|
|||||||
return parent;
|
return parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return the primary parent association so we can get at the association QName and the association type QName.
|
||||||
|
*/
|
||||||
|
public ChildAssociationRef getPrimaryParentAssoc()
|
||||||
|
{
|
||||||
|
if (primaryParentAssoc == null)
|
||||||
|
{
|
||||||
|
primaryParentAssoc = this.services.getNodeService().getPrimaryParent(nodeRef);
|
||||||
|
}
|
||||||
|
return primaryParentAssoc;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the content String for this node from the default content property
|
* @return the content String for this node from the default content property
|
||||||
* (@see ContentModel.PROP_CONTENT)
|
* (@see ContentModel.PROP_CONTENT)
|
||||||
|
@@ -35,4 +35,13 @@ public interface TemplateProcessor
|
|||||||
* @param out Writer object to send output too
|
* @param out Writer object to send output too
|
||||||
*/
|
*/
|
||||||
public void process(String template, Object model, Writer out);
|
public void process(String template, Object model, Writer out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process a string template against the supplied data model and write to the out.
|
||||||
|
*
|
||||||
|
* @param template Template string
|
||||||
|
* @param model Object model to process template against
|
||||||
|
* @param out Writer object to send output too
|
||||||
|
*/
|
||||||
|
public void processString(String template, Object model, Writer out);
|
||||||
}
|
}
|
||||||
|
@@ -55,6 +55,34 @@ public interface TemplateService
|
|||||||
public void processTemplate(String engine, String template, Object model, Writer out)
|
public void processTemplate(String engine, String template, Object model, Writer out)
|
||||||
throws TemplateException;
|
throws TemplateException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process a given template, provided as a string, against the supplied data model and return the result as a String
|
||||||
|
*
|
||||||
|
* @param engine Name of the template engine to use
|
||||||
|
* @param template Template string
|
||||||
|
* @param model Object model to process template against
|
||||||
|
*
|
||||||
|
* @return output of the template process as a String
|
||||||
|
*
|
||||||
|
* @throws TemplateException
|
||||||
|
*/
|
||||||
|
public String processTemplateString(String engine, String template, Object model)
|
||||||
|
throws TemplateException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process a given template, provided as a string, against the supplied data model and report the
|
||||||
|
* result back in the provided writer.
|
||||||
|
*
|
||||||
|
* @param engine Name of the template engine to use
|
||||||
|
* @param template Template string
|
||||||
|
* @param model Object model to process template against
|
||||||
|
* @param out Writer object to send output too
|
||||||
|
*
|
||||||
|
* @throws TemplateException
|
||||||
|
*/
|
||||||
|
public void processTemplateString(String engine, String template, Object model, Writer out)
|
||||||
|
throws TemplateException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a TemplateProcessor instance for the specified engine name.
|
* Return a TemplateProcessor instance for the specified engine name.
|
||||||
* Note that the processor instance is NOT thread safe!
|
* Note that the processor instance is NOT thread safe!
|
||||||
|
Reference in New Issue
Block a user