Wednesday, August 3, 2011

Using a Template in the Classpath for an Email on Alfresco 3.4

When trying to use a template on the classpath with the MailActionExecutor but without much success.  I was under the impression that all one had to do was provide the relative path to the ftl file via the PARAM_TEMPLATE parameter (can't remember what I read that made me think this... it also doesn't help that there is not a whole lot of Java examples/documentation other than the skimpy javadocs).  I tried this, and was met with the following exception:

org.springframework.mail.MailPreparationException: Could not prepare mail; nested exception is java.lang.ClassCastException: java.lang.String cannot be cast to org.alfresco.service.cmr.repository.NodeRef

A quick look at the source code revealed why:

...
// See if an email template has been specified
String text = null;
NodeRef templateRef = (NodeRef)ruleAction.getParameterValue(PARAM_TEMPLATE);
if (templateRef != null)
...

It doesn't even attempt to differentiate between a template in the repository vs one in the classpath.  It automatically assumes it is in the repo (hence the cast to a NodeRef before anything else is done).  To get around this, I had to manually process the template to generate the text to be used in the email.

To do this, a model needs to be generated for the template to use.  I used the code that generates the model in the MailActionExecutor.java minus a few objects I deemed unnecessary for my use case.  Then I passed in the path to the ftl and the model to the template service and it generated the output string.  I then set it to the PARAM_TEXT parameter for the email.

Here is the code:
private static final String EXPIRE_EMAIL_TEMPLATE = "alfresco/extension/burris/common/templates/expiration-email-template.ftl";
...
// Process the template - the mail action executor expects it to be in the repository which is why this has to be done
Map model = new HashMap( 8, 1.0f );
NodeRef person = personService.getPerson( authenticationService.getCurrentUserName() );
model.put( "person", new TemplateNode( person, serviceRegistry, null ) );
model.put( "document", new TemplateNode( nodeRef, serviceRegistry, null ) );
NodeRef parent = nodeService.getPrimaryParent( nodeRef ).getParentRef();
model.put( "space", new TemplateNode( parent, serviceRegistry, null ) );
model.put( "message", new I18NMessageMethod() );

String text = templateService.processTemplate( "freemarker", EXPIRE_EMAIL_TEMPLATE, model );

// Send email notice detailing the state change
Action emailAction = actionService.createAction( MailActionExecuter.NAME );

emailAction.setParameterValue( MailActionExecuter.PARAM_SUBJECT, subject.toString() );
emailAction.setParameterValue( MailActionExecuter.PARAM_TO_MANY, emailList );
emailAction.setParameterValue( MailActionExecuter.PARAM_TEXT, text );

if ( log.isDebugEnabled() ) log.debug( "Sending email..." );
actionService.executeAction( emailAction, nodeRef );
...

Monday, August 1, 2011

Send an Email to an Entire Alfresco Share Site

I had the need to send the users of an Alfresco Share site an email; however, doing so is not readily apparent.  It is pretty easy once you know the convention:

GROUP_site_siteId


This differs from the Alfresco Explorer groups which follow the pattern:

GROUP_groupId

Here is an example of what a site group identifier should look like if the site id is transportation:

GROUP_site_transportation

If you're working in the javascript world or just want to hardcode things together, you can construct the group identifier using the above as a template.  However, in the java world, Alfresco provides us with the SiteService. If you know the short name of your site, you can retrieve the string identifier for the site group. In my case, I retrieved the short name of the site from the nodeRef passed into a behavior.

Here is the code I used to do this:

// To
 SiteInfo siteInfo = siteService.getSite( nodeRef );
 String siteShortName = siteInfo.getShortName();
 String siteGroup = siteService.getSiteGroup( siteShortName );
   
 // Send email notice detailing the state change
 Action emailAction = actionService.createAction( MailActionExecuter.NAME );
 
 emailAction.setParameterValue( MailActionExecuter.PARAM_SUBJECT, subject );
 emailAction.setParameterValue( MailActionExecuter.PARAM_TO_MANY, siteGroup );
 emailAction.setParameterValue( MailActionExecuter.PARAM_TEXT, "Hello world." );
 
 actionService.executeAction( emailAction, nodeRef );