sending email for expired documents

I've followed this article in Nuxeo Blog for sending amail when some documents are expired, Here is what i've done

contract-scheduler-contrib.xml :

<?xml version="1.0"?>
 <component name="org.nuxeo.sample.scheduler.notifContract">
 <extension
 target="org.nuxeo.ecm.core.scheduler.SchedulerService"
 point="schedule">
 <schedule id="notifContractScehdulerId">
 <username>Administrator</username>
 <eventId>notifContract</eventId>
 <eventCategory>default</eventCategory>

 <cronExpression>0 * * * * ?</cronExpression>
 </schedule>
 </extension>

 </component>

contract-listener-contrib.xml

<?xml version="1.0"?>
 <component name="org.nuxeo.sample.listener.contrib.notifContract">
 <extension target="org.nuxeo.ecm.core.event.EventServiceComponent"
 point="listener">
 <listener name="notifContractListener" async="true" postCommit="false" priority="120"
 class="org.nuxeo.sample.restAPI.ContractNotifListener" >
 <event>notifContract</event>
 </listener>
 </extension>
 </component>

contract-notif-contrib.xml :

<?xml version="1.0"?>
<component
name="org.nuxeo.sample.contract.notifcontrib">

<extension
target="org.nuxeo.ecm.platform.ec.notification.service.NotificationService"
point="notifications">
<notification name="Contract Expired" channel="email" enabled="true" availableIn="Workspace"
autoSubscribed="false" template="contractExpired" subject="Contract expired" label="label.nuxeo.notifications.contractExpired">
<event name="contractExpired"/>

</notification>
</extension>

<extension
target="org.nuxeo.ecm.platform.ec.notification.service.NotificationService"
point="templates">
<template name="contractExpired" src="templates/contractExpired.ftl" />
</extension>

</component>

ContractNotifListener.java

package org.nuxeo.sample.restAPI;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import org.nuxeo.ecm.core.api.ClientException;
import org.nuxeo.ecm.core.api.CoreSession;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.DocumentModelList;
import org.nuxeo.ecm.core.event.Event;
import org.nuxeo.ecm.core.event.EventListener;
import org.nuxeo.ecm.core.event.EventService;
import org.nuxeo.ecm.core.event.impl.DocumentEventContext;
import org.nuxeo.runtime.api.Framework;

public class ContractNotifListener implements EventListener {

    private static final String QUERY_CONTRACTS = "Select * From Document WHERE ecm:isCheckedInVersion = 0 AND ecm:currentLifeCycleState != 'deleted' AND dc:expired = DATE '%s'";

    public void handleEvent(Event event) throws ClientException {
        CoreSession coreSession = event.getContext().getCoreSession();
        Calendar expirationDate = Calendar.getInstance();
        expirationDate.add(Calendar.DATE, 1);
        Date now = expirationDate.getTime();
        String date = new SimpleDateFormat("yyyy-MM-dd").format(now);
        String query = String.format(QUERY_CONTRACTS, date);
        DocumentModelList contracts = coreSession.query(query);

        EventService eventService;
        try {
        eventService = Framework.getService(EventService.class);
        for (DocumentModel contract : contracts) {
        DocumentEventContext ctx = new DocumentEventContext(
        coreSession, coreSession.getPrincipal(), contract);
        Event contractExpiredEvent = ctx.newEvent("contractExpired");
        eventService.fireEvent(contractExpiredEvent);
        }
        } catch (Exception e) {
        throw new RuntimeException("could not get the EventService", e);
        }
        }
        }

### MANIEST.MF

Manifest-Version: 1.0
Bundle-ManifestVersion: 1
Bundle-Name: Nuxeo Sample project
Bundle-SymbolicName: org.nuxeo.project.sample;singleton:=true
Bundle-Version: 1.0.0
Bundle-Vendor: Nuxeo
Provide-Package: org.nuxeo.project.sample
Require-Bundle: org.nuxeo.runtime,
 org.nuxeo.ecm.core.api,
 org.nuxeo.ecm.core,
 org.nuxeo.ecm.webapp.core
Nuxeo-Component: OSGI-INF/contract-scheduler-contrib.xml,
 OSGI-INF/contract-listener-contrib.xml,
 OSGI-INF/contract-notif-contrib.xml,
 OSGI-INF/core-types-contrib.xml,
 OSGI-INF/lifecycle-contrib.xml,
 OSGI-INF/ui-types-contrib.xml,
 OSGI-INF/login-contrib.xml,
 OSGI-INF/theme-contrib.xml,
 OSGI-INF/my-directories-contrib.xml,
 OSGI-INF/layouts-contrib.xml,
 OSGI-INF/actions-contrib.xml,
 OSGI-INF/contentviews-contrib.xml,
 OSGI-INF/versioningrules-contrib.xml,
 OSGI-INF/workflow-contrib.xml,
 OSGI-INF/directory-layout-contrib.xml

However, i can't get the email , the code is not executed and i have nothing in my log file, can you tell what i'm missing ? Any help would appreciated.

Update :

I've tried sending alert using documentCreated event that i send when clicking in a button, so i end up noticing that i have a problem with the Scheduler or with the new event 'contractExpired' . I want to mention that in those lines

Event contractExpiredEvent = ctx.newEvent("contractExpired");
eventService.fireEvent(event);

we should have eventService.fireEvent(contractExpiredEvent);

0 votes

0 answers

4147 views

ANSWER

Hi! Quick question: is you contractExpired event triggered at 5:20pm? You can set up a a listener to log its triggering. Even more easily if you use Nuxeo Studio.
12/11/2015

Hi Greg Drayon thank you for replying, actually i'm using Nuxeo IDE .
12/11/2015

OK, then you can add some logs at the beginning of your

org.nuxeo.sample.restAPI.ContractNotifListener.handleEvent(Event)

method, and activate the logs for the

org.nuxeo.ecm.core.scheduler

category in your log4j.xml file. Also, change your cron expression to something like

&quot;0 * * * * ?&quot;

so the event will be triggered every minute. Maybe you have already changed it, but if it is still at 5:20pm, it's going to be a long wait.

12/18/2015

Greg Drayon can you tell me how to add logs for org.nuxeo.ecm.core.scheduler ?
01/08/2016

To add logs, as I said, add the category in your log4j.xml, with a DEBUG level. Then, in your ContractNotifListener, you should add some logs lines. You will find an example here, lines 112-114:

if (log.isDebugEnabled()) {
        log.debug(&quot;Reconnecting CoreSession: &quot; + sessionId);
}
01/13/2016

Thank you Greg Drayon , can you explain to me why there are 'notifContract' and 'contractExpired' events in the article http://www.nuxeo.com/blog/qa-friday-upcoming-document-expiration-notification/
01/14/2016

  1. 'notifContract' is an event triggered by the scheduler, every day at 1 am.
  2. Then, the 'notifContract' event is caught by the listener named 'notifContractListener'.
  3. This listener is bound to the org.nuxeo.sample.ContractNotifListener class.
  4. In the 'ContractNotifListener' class (I think there is a mistake, it should be 'ContractNotifListener'), for every document brought up by the query, a 'contractExpired' event is triggered.
  5. The 'contractExpired' event is then caught by the notification named "Contract Expired".
01/14/2016

okay thank you Greg Drayon , though i don't know why it's not working , the notifContract event is not launched , the code in class 'ContractNotifListener' is not executed
01/14/2016

I would check the cron expression, but this is all I can think about. Maybe add a "year" value, such as "*"?
01/15/2016

Greg Drayon I'm using the one you provided `0 * * * * ?` but still not working
01/18/2016

I guess the component is defined in the MANIFEST.MF and has a unique component name, as well as the scheduler id?
01/19/2016

Greg Drayon yes i've added the components in MANIFEST.MF , please can you see my update i've added all the files i'm using
01/19/2016

Is there a reason why your listener does not implement EventListener? In the article you gave, it does.
01/19/2016

Greg Drayon I didn't update the java class, but in my current class it does. Can you tell me the difference between EventService and EventProducer ? i can't find in the documentation some information about EventService https://doc.nuxeo.com/display/NXDOC/Events+and+Listeners .
01/19/2016

You can see here that EventProducer is the parent interface of EventService. EventServiceImpl implements EventService, so it implements also EventProducer.
01/19/2016

Ok thank you Greg Drayon
01/19/2016

In "contract-listener-contrib.xml", the extension tag isn't closed in the code you give here.
01/19/2016

i've modified it but with no luck
01/19/2016

Are you sure the event is not fired? You may raise an Exception from your listener and see if it appears in the log file. If it does, the event is fired. If not, maybe check if you components are deployed, using the platform-explorer (if you have a Studio account). If it is, then either it comes from the cron expression, or I'm at loss for words…
01/19/2016

Greg Drayon can you give the proper code to raise an Exception from the listener in order to be sure i'm doing it right ? I'm not using Nuxeo Studio
01/19/2016

public class ContractNotifListener implements EventListener {

    public void handleEvent(Event event) throws ClientException {
        throw new ClientException(&quot;Exception! High-five!&quot;);
    }
01/19/2016

I changed the components order in MANIFEST.MF and the event fired ; now i'm getting

2016-01-19 11:50:00,038 ERROR [Quartz_Worker-1] [org.nuxeo.ecm.core.event.impl.EventServiceImpl] Exception during notifContractListener sync listener execution, continuing to run other listeners
java.lang.NullPointerException
    at org.nuxeo.sample.restAPI.ContractNotifListener.handleEvent(ContractNotifListener.java:28)
    at org.nuxeo.ecm.core.event.impl.EventServiceImpl.fireEvent(EventServiceImpl.java:191)
    at org.nuxeo.ecm.core.scheduler.EventJob.execute(EventJob.java:115)
    at org.nuxeo.ecm.core.scheduler.EventJob.execute(EventJob.java:60)
    at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:549)

Thank you for your help

01/19/2016

As the line 28 in ContractNotifListener.class is an empty line here, I guess the code isn't up to date.
01/19/2016

it's about this line DocumentModelList contracts = coreSession.query(query); coreSession is null
01/19/2016

Someone had the same issue here.
01/19/2016

i've tried this code ``` EventContext ctx = event.getContext();

    if (!(ctx instanceof DocumentEventContext)) {
        return;
    CoreSession session = ctx.getCoreSession();
but the condition ` if (!(ctx instanceof DocumentEventContext))` is true so the rest of code is not executed
01/20/2016

I don't know the ctx class, but you can still get a session using an unrestrictedSessionRunner. An example is in the page you followed. Maybe the example from the blog is not (anymore?) functional.
01/20/2016

It worked using

 RepositoryManager mgr = Framework.getService(RepositoryManager.class);
        Repository repository = mgr.getDefaultRepository();
        if (repository != null) {
                coreSession = repository.open();
01/20/2016