Scheduled Actions

From AlfrescoWiki

Jump to: navigation, search

Contents

[edit] Introduction to Scheduled Actions

A scheduled action is made up of three parts:

  • a cron expression;
  • a query template; and
  • an action template.


At the times specified by the cron expression, the query template is used to generate a query. Any supported query language can be used. The query is run to select a set of nodes. For each of the nodes in the set, the action template is converted into an action and then the action is applied to the node.


The use of templates allows the query to generate entries for dates and date ranges such as "today" and "the last four years". The use of templates for actions allows properties of each node found by the query to be used to parameterise the action instance. The parameters defined in the action template can be defined as freemarker templates. When the action is built from the action template its parameters are generated from the freemarker templates using a template model with the current node defined. So you can use properties of the node to set the properties on the action.


Currently definitions of scheduled actions are made in xml.


The action templates can be composite action templates or single actions.


Currently an action applies to a single node (it can not take the whole set of selected nodes)


The query can be something like:

  • has aspect;
  • does not have aspect;
  • was created in the last month;
  • is due in the next month;
  • is in category;

...


And the action any one of the built in:

  • AddFeaturesAction
  • CheckInAction
  • CheckOutAction
  • CompositeAction
  • ContentMetadata
  • CopyAction
  • CounterIncrementAction
  • CreateVersionAction
  • ExecuteAllRulesAction
  • ExporterAction
  • ImageTransformAction
  • ImporterAction
  • LinkCategoryAction
  • MailAction
  • MoveAction
  • RemoveFeaturesAction
  • RepositoryExporterAction
  • ScriptAction
  • SetPropertyValueAction
  • SimpleWorkflowAction
  • SpecialiseTypeAction
  • TransformAction


[edit] A simple Example

This example finds files without the general classifiable aspect and adds it with a default classification.


[edit] The Action definition

    <!-- An action that adds a classification to a node. -->
    <!-- It uses the AddFeatures action that adds an aspect and sets a property. --> 
    <bean id="addClassifiableAspectAction" class="org.alfresco.repo.action.scheduled.SimpleTemplateActionDefinition">
        <!-- The name of the action. -->
        <!-- In this case org.alfresco.repo.action.executer.AddFeaturesActionExecuter. -->
        <!-- This is actually set in the bean configuration for this action in action-services-context.xml. -->
        <!-- It is the bean name under which the action is registered in this file. --> 
        <property name="actionName">
            <value>add-features</value>
        </property>
        <!-- Define the properties required by the action. -->
        <property name="parameterTemplates">
            <map>
                <!-- There is no easy way to get properties that can be set at the moment -->
                <!-- You have to inspect the java code for the action implementation --> 

                <!-- Define the name of the aspact to add --> 
                <entry>
                    <key>
                        <!-- The name of the property -->
                        <!-- This defines the name of the aspect -->
                        <value>aspect-name</value>
                    </key>
                    <!-- The aspect required for normal classification -->
                    <value>{http://www.alfresco.org/model/content/1.0}generalclassifiable</value>
                </entry>
                
                <!-- Any other parameters are treated as property names to set -->        
                <entry>
                    <!-- The QName of property -->
                    <key>
                        <value>{http://www.alfresco.org/model/content/1.0}categories</value>
                    </key>
                    <!-- The property value -->
                    <!-- Here we make use of a freemarker template to get the node ref of a category -->
                    <!-- This is done ny invoking a lucene query -->
                    <value>${selectSingleNode('workspace://SpacesStore', 'lucene', 'PATH:"/cm:generalclassifiable/cm:Languages/cm:English"' )}</value>
                </entry>
            </map>
        </property>
        <!-- Required services and the freemarker template model -->
        <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>

[edit] The query and scheduler definition

    <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>
        <!-- Inject the scheduler - the trigger will be registered with this scheduler -->
        <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>

[edit] Available options for SimpleTemplateActionDefinition

actionName
the name of the action (the bean name for the implementation)
parameterTemplates
a map of names and valueTemplates
these are action specific
compensatingTemplateActionDefinition
an optional compensating action (simple or composite)

[edit] Available options for CompositeTemplateActionDefinition

compensatingTemplateActionDefinition
an optional compensating action template (simple or composite)
templateActionDefinitions
A list of other template definition beans (simple or composite)



Those properties not mentioned explicitly are required services and should be set as the above example.

[edit] Available properties for a CronScheduledQueryBasedTemplateActionDefinition bean

transactionMode
ISOLATED_TRANSACTIONS - for each node the action is run in an isolated transaction. Failures are logged.
UNTIL_FIRST_FAILURE - for each node the action is run in a isolated transacgtion. The first failure stops this.
ONE_TRANSACTION- the actions for all nodes are run in one transaction. One failure will roll back all;
compensatingActionMode
RUN_COMPENSATING_ACTIONS_ON_FAILURE
IGNORE
queryLanguage
The query language to use
stores
A list of stores to query (currently only one store is supported)
queryTemplate
The template string to build the query
cronExpression
The cron expression to define when the query runs
jobName
The name of the scheduled job
jobGroup
The group for the scheduled job
triggerName
The name for the trigger
triggerGroup
The group for the trigger
runAsUser
The user which who identity the action will run
templateActionDefinition
The bean that defines the action


Those properties not mentioned explicitly are required services and should be set as the above example.

[edit] Query Templates

The FreeMarker template is extended with some support to build lucene query strings. This is mostly around dates.


Template expression Meaning
${luceneDateRange(\"2000-01-01T00:00:00.000Z\", \"P1D\")} [2000-01-01T00:00:00.000Z TO 2000-01-05T00:00:00.000Z]
${luceneDateRange(today, \"P4D\")}" a range of the form [X TO Y] where X is today and Y is Today + 4 days
${luceneDateRange(today, \"-P4D\")} a range of the form [X TO Y] where X is today and Y is Today - 4 days
${luceneDateRange(today, today)} a range of the form [X TO Y] where X is today and Y is today


Date ranges are expressed as XML durations.


[edit] Examples

PATH:"//\*" -ASPECT:"{http://www.alfresco.org/model/content/1.0}generalclassifiable"

Find all nodes that do not have the general classifiable aspect


ASPECT:"{http://www.alfresco.org/model/content/1.0}generalclassifiable"

Find all nodes that do have the general classifiable aspect


+PATH:"/app:company_home/*//*" +TEXT:"tutorial"

Find all nodes under company home that also contain tutorial in the content.


@cm\:created:${luceneDateRange(yesterday, "-P10Y")}

Find all nodes created yesterday or in the 10 years before


[edit] Cron Explained

A cron expression is 6 or 7 text fields that are separated by whitespace.


Cron Fields
Field Name Position Mandatory Allowed Values Special Characters
Seconds 1 Yes 0-59 , - * /
Minutes 2 Yes 0-59 , - * /
Hours 3 Yes 1-23 , - * /
Day of Month 4 Yes 1-31 , - * ? / L W C
Month 5 Yes 1-12 or JAN-DEC , - * /
Day of Week 6 Yes 1-7 or SUN-SAT , - * ? / L C #
Year 7 No empty, 1970-2099 , - * /


[edit] Special characters

*
All values
This matches all available values for this field. In the second field, it means "every second"; in the minutes fields, "every minute"; in the hours field "every hour"; etc.
 ?
No specific value
A value can not be specified in both the day of the month and day of the week fields, one must contain ?.
This is used when specifying a day of the month or a day of the week. If you want the first day of the week but do not care on which day of the month this falls then you would have a 1 for the day of the week and ? for day of the month. Likewise, if you want the 5th day of the month and do not care about the day of the week, then you would have 5 in the day of the month and ? in the day of the week. If you have 1 for the day of the week and 5 for day of the month you would expect this to mean "it must be the first day of the week and the 5th day of the month": this is not supported.
-
This is used to sepecify a range
1-5 in day of the week field would mean "on days 1, 2, 3, 4 and 5". 0-11 in the hours field would mean "each hour in the morning".
,
A list of values
In the minutes field 0,15,30,45 would mean "when the minute is 0, 15, 30 OR 45". In the day field, MON,TUES would mean "on Mondays and Tuesdays"
/
After a value specifies increments
In the minutes field, 0/15 is equivalent to 0,15,30,45; */15 is equivalent to */15; and 10/15 is equivalent to 10,25,40,55. In the day of the month field 3/7 means "every seven days starting on the third of the month"; 3,10,17,24, ...
L
Last
Incompatible with lists and ranges (, and -), if used it will give confusing results.
The meaning depends on context. Used in the day of the month field, L alone means "the last day of the month" - day 31 for January, day 28 for February in non leap years, day 29 for Feb in leap years, day 31 for march, etc. Used in the day of the week field, L alone means the last day of the week, 7 or SAT. Used in the day of the week field an L after a numeric value, such as 6L means "the last Friday of the month".
W
The nearest week day
Incompatible with a list or range of days.
Only used in the day of the month to specify the nearest week day (Monday - Friday). 5W would mean "the week day nearest the 5th of the month". If the 5th falls on Mon-Friday it would execute as expected, if it falls on a Saturday then Friday will be used, if it falls on a Sunday then the following Monday will be used. The expression must refer to a day of the month and will not execute in the month before or after. For 1W with the first on a Saturday, then Monday the 3rd would be used. (TODO: Confirm the after behvaiour)
LW
The last week day of the month
#
The nth
Only used in the day of the month to specify the nth day of the week on the month. So, 2#1 means "the first Monday of the month", 6#3 means "the third Friday of the month" and 6#5 means "the fifth friday of the month". If there is no match for the month, say there is no 5th Friday, then nothing happens.
C
Meaningless in Alfrecso
It could mean "the first day on or after the given day included by some calendar". Support is not complete in the implementation and there is no way to define a calendar in the current configuration. If available it is not tested.


[edit] Examples

Expression Meaning Notes
0 0 12 * * ? At 12pm (noon) every day Note that the day of the month is specified as all (*) and the day of the week as unspecified (?).
0 0 12 * * ? * At 12pm (noon) every day  
0 0 12 ? * * At 12pm (noon) every day  
0 0 12 ? * * * At 12pm (noon) every day  
0 30 2 * * ? At 2:30 am every day  
0 30 2 * * ? 2006 At 2:30 am every day during 2006  
0 10 * * * ? Every hour at ten past the hour  
0 * 8 * * ? Every minute from 8.00am until 8.59 every day  
0 0,30 8-18 * * ? Every half hour from 8.00am until 18.00  
0 0/15 * * * ? Every 15 minutes at 0, 15, 30, 45 minutes past the hour  
0 0 2,14 ? * FRI At 2.00am and 2pm every Friday  
0 0 4 LW 3,6,9,12 ? At 4.00am on the last week day of each quarter  
0 0 2 * * 6#1 At 2.00am on the first friday of every month  


[edit] Tips

  • Using cron expression in the first hour after midnight can lead to unexpected results when daylight savings are applied and removed. Triggers can fire twice or may be skipped if the time moves backwards or forwards respectively.
  • The names of days and months are case insensitive. You can use MON, Mon or mon.


[edit] Script Action Example

    <!--
    Execute the script /Company Home/Record Management/testscript.js
    -->
    <bean id="runScriptAction" class="org.alfresco.repo.action.scheduled.SimpleTemplateActionDefinition">
        <property name="actionName">
            <value>script</value>
        </property>
        <property name="parameterTemplates">
            <map>
                <entry>
                    <key>
                        <value>script-ref</value>
                    </key>
                    <value>${selectSingleNode('workspace://SpacesStore', 'lucene', 'PATH:"/app:company_home/cm:Record_x0020_Management/cm:testscript.js"' )}</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>
    
    <!--
   Run the script every minute - select the single node company home that is not used ...
    -->
    <bean id="runScript" 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"</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="runScriptAction"/> <!-- This is name of the action (bean) that gets run -->
        </property>
        <property name="transactionService">
            <ref bean="TransactionService"/>
        </property>
        <property name="runAsUser">
            <value>System</value>
        </property>
    </bean>

[edit] More Examples

More examples can be found in config\alfresco\extension\scheduled-action-services-context.xml.sample.