IBM FileNet P8, Version 5.2.1            

Working with Subscriptions

A Subscription object requires an EventAction object and a user-implemented event action handler that the EventAction object references. If the EventAction object and event action handler do not exist, you must first create them, and then associate them with the Subscription object, as shown in the following topics:

You can also retrieve Subscription objects, and set and retrieve properties and permissions for them. The following topics show how to code for common scenarios with retrieved subscriptions:

In addition to system events, you can subscribe custom events to a subscription. As shown in the following topics, a client application must manually raise a custom event to start an event action handler. Also, the client can set the status of a custom event to convey state to the event action handler:

When a subscription is started, its EventAction object, if it is configured to run asynchronously, is placed in a Content Engine queue as a pending action. You can monitor pending actions, and, if there are failed actions, you can fix them and relaunch them from the queue. See Retrieving Queue Items from an Object Store.

For an overview of subscriptions, see Subscriptions.

Creating an Event Action Handler

To create an event action handler, you must implement the onEvent method of the Java™ EventActionHandler interface or the RetrievalEventActionHandler interface. When you implement an event action handler, note the following information:

The following examples show Java and JavaScript implementations of a handler that screens new form documents. Forms of the FloodClaim class are filed to a special folder for users that belong to the NOL group. The handler is intended for a ClassSubscription object, in which the subscribed event is CreationEvent, and the target object is the FloodClaim class. When a user creates a new form and sets its class type to FloodClaim, the handler runs. The ObjectChangeEvent subobject is the CreationEvent object, and the event's source object is any form document of the FloodClaim class. For a code example of creating a class subscription applicable to this scenario, see Creating a Subscription Object.

Because the example handler changes the source object, the handler must be configured to run asynchronously. For more information, see Action Handlers. To view a sample source code EventActionHandler implementation that is packaged with the Content Engine, go to this Content Engine directory:
  • Windows: C:\Program Files\Filenet\Content Engine\samples
  • non-Windows: /opt/IBM/FileNet/ContentEngine/samples

Java Example

package sample.actionhandler;
import java.util.Iterator;
import com.filenet.api.engine.EventActionHandler;
import com.filenet.api.events.*;
import com.filenet.api.property.*;
import com.filenet.api.security.*;
import com.filenet.api.util.Id;
import com.filenet.api.exception.*;
import com.filenet.api.core.*;
import com.filenet.api.collection.GroupSet;
import com.filenet.api.constants.*;

public class FilterNewDocumentsEventHandler implements EventActionHandler
{
   public void onEvent(ObjectChangeEvent event, Id subId)
   {
      try
      {
         // As a best practice, fetch the persisted source object of the event, 
         // filtered on the two required properties, Owner and Name.
         ObjectStore os = event.getObjectStore();
         Id id = event.get_SourceObjectId();
         FilterElement fe = new FilterElement(null, null, null, "Owner Name", null);    
         PropertyFilter pf = new PropertyFilter();
         pf.addIncludeProperty(fe);
         Document doc = Factory.Document.fetchInstance(os, id, pf);

         User user = Factory.User.fetchInstance(os.getConnection(), doc.get_Owner(), null);
         GroupSet groups = user.get_MemberOfGroups();
         Iterator groupsIter = groups.iterator();
         while (groupsIter.hasNext())
         {
            Group group = (Group) groupsIter.next();
            if ( group.get_ShortName().equals("NOL") )
            {
               Folder folder=Factory.Folder.fetchInstance(os, "/Special Processing", null);
               // File form and save.
               DynamicReferentialContainmentRelationship drcr =
                   (DynamicReferentialContainmentRelationship)folder.file((IndependentlyPersistableObject)doc,
                  AutoUniqueName.AUTO_UNIQUE,
                  doc.getProperties().getStringValue("Name"),
                  DefineSecurityParentage.DO_NOT_DEFINE_SECURITY_PARENTAGE);
               drcr.save(RefreshMode.NO_REFRESH);
               break;
            }
         }
      }
      catch (Exception e)
      {
         throw new RuntimeException(e);
      }
   }
}
     

JavaScript Example

importPackage(java.lang);
importClass(java.util.Iterator);
importClass(Packages.com.filenet.api.engine.EventActionHandler);
importClass(Packages.com.filenet.api.collection.GroupSet);
importClass(Packages.com.filenet.api.util.Id);
importPackage(Packages.com.filenet.api.events);
importPackage(Packages.com.filenet.api.property);
importPackage(Packages.com.filenet.api.security);
importPackage(Packages.com.filenet.api.core);
importPackage(Packages.com.filenet.api.constants);

function onEvent(event, subId){
   try {
      // As a best practice, fetch the persisted source object of the event, 
      // filtered on the two required properties, Owner and Name.
      var os=event.getObjectStore();
      var id=event.get_SourceObjectId();
      var fe=new FilterElement(null,null,null,"Owner Name",null);
      var pf=new PropertyFilter();
      pf.addIncludeProperty(fe);
      var doc = Factory.Document.fetchInstance(os,id, pf);

      var user=Factory.User.fetchInstance(os.getConnection(), doc.get_Owner(),null);
      var groups=user.get_MemberOfGroups();
      var groupsIter=groups.iterator();
      while (groupsIter.hasNext())
      {
         var group = groupsIter.next();
         if( group.get_ShortName().equals("NOL") ) 
         {
            var folder = Factory.Folder.fetchInstance(os, "/Special Processing", null); 
           //File form and save.
           var drcr = 
              folder.file(doc, AutoUniqueName.AUTO_UNIQUE, 
              doc.getProperties().getStringValue("Name"),
              DefineSecurityParentage.DO_NOT_DEFINE_SECURITY_PARENTAGE);
           drcr.save(RefreshMode.NO_REFRESH);
           break;
        }
     }
   }
   catch ( e) {
      throw new RuntimeException(e);
   }
}

Creating an EventAction Object

An EventAction object identifies the event action handler to be started when a subscribed event is triggered. The following Java and C# code snippets show how to create an EventAction object and set the properties that associate it with an event action handler: ProgId and, conditionally, CodeModule. For a handler that is implemented with Java, you must set the ProgId property with the fully qualified name of the handler class. If, as shown in the examples, the event action handler is contained within a CodeModule stored in an object store, you must also get the CodeModule object, then assign it to the CodeModule property of the EventAction object. Note that you cannot set the CodeModule property to a reservation (in progress) version of CodeModule. For more information, see Creating a CodeModule Object.

Note: Do not set the CodeModule property if you set the application server's class path to the location of the event handler.

When an EventAction object is saved, it is stored in the Events/Event Action folder of a Content Engine object store.

Java Example

...
//Create event action.
EventAction eventAction = Factory.EventAction.createInstance(os, null);

// Set ProgId property with fully qualified name of handler class
eventAction.set_ProgId("sample.actionhandler.FilterNewDocumentsEventHandler");

//Get CodeModule object.
CodeModule cm = Factory.CodeModule.fetchInstance(os, new Id("{E6C739B5-0EEB-43E1-B1FB-D6BC74F80EAC}"), null); 

// Set CodeModule property if handler class is checked into object store.
eventAction.set_CodeModule(cm);

eventAction.set_DisplayName("FilterNewDocumentsEventAction");
eventAction.save(RefreshMode.REFRESH);

C# Example

...
// Create event action.
IEventAction eventAction = Factory.EventAction.CreateInstance(os, null);

// Set ProgId property with fully qualified name of handler class.
eventAction.ProgId = "sample.actionhandler.FilterNewDocumentsEventHandler";

// Get CodeModule object.
ICodeModule cm = Factory.CodeModule.FetchInstance(os, new Id("{E6C739B5-0EEB-43E1-B1FB-D6BC74F80EAC}"), null);

// Set CodeModule property.
eventAction.CodeModule = cm;

eventAction.DisplayName = "FilterNewDocumentsEventAction";
eventAction.Save(RefreshMode.REFRESH);

Creating a Subscription Object

After creating the event action handler and the EventAction object, you're ready to create a Subscription object and persist it to an object store. Although there are different subscription types, the process of creating a Subscription object is generally the same. You define the subscription type and set the following properties: the event action to execute, the target object of the subscription, and the subscribed events, which, when triggered on the target object, invoke the event action.

The following Java and C# examples show how to create a subscription of type ClassSubscription. A class subscription is launched when events are triggered on objects of a specified class. In this example, the subscription target is a subclass of the Document class, represented by the DocumentClassDefinition object, and the subscribed event is CreationEvent. Therefore, whenever an object of the Document subclass is created, the event action will execute. Note, however, that if there are children classes of the subclass, they are explicitly excluded from the subscription, as set in the IncludeSubclassesRequested property.

An event in a subscription is represented by a SubscribedEvent object. As shown in the examples, you set the object's EventClass property with an EventClassDefinition object, which identifies the event. You then add the SubscribedEvent object to a SubscribedEventList collection, and set the subscription's SubscribedEvents property to the collection.

When a subscription is saved, it is stored in the Events/Subscription folder of a Content Engine object store.

Java Example

// Create class subscription.
ClassSubscription subscription = Factory.ClassSubscription.createInstance(os, null);

// The target of the class subscription will be a Document subclass,
// identified by the ID object.
DocumentClassDefinition docCD=Factory.DocumentClassDefinition.getInstance(
   os, new Id("{B19C39FD-9E71-4E56-8D7E-9B036B3B903B}") );
subscription.set_SubscriptionTarget(docCD);

// Exclude subclasses of the target class.
subscription.set_IncludeSubclassesRequested(Boolean.FALSE); 

// Get EventAction object created in previous example, 
// and set subscription's EventAction property.
EventAction eventAction = Factory.EventAction.fetchInstance(os, 
   new Id("{F1C9ACE3-8454-4B2C-9AC4-30228FAA8113}"), null);
subscription.set_EventAction(eventAction);

// Specify one or more events that, when triggered, will invoke the subscription.
// Add the events to a list and set the subscription object.
Id subscribedEventId = GuidConstants.Class_CreationEvent;
EventClassDefinition evDef = Factory.EventClassDefinition.getInstance(os, subscribedEventId);
SubscribedEvent subEvent = Factory.SubscribedEvent.createInstance();
subEvent.set_EventClass(evDef);
SubscribedEventList subEventList = Factory.SubscribedEvent.createList();
subEventList.add(subEvent);
subscription.set_SubscribedEvents(subEventList);

// Specify that event handler run synchronously.
subscription.set_IsSynchronous(Boolean.TRUE);

subscription.set_DisplayName("FileDocumentSubscription");
subscription.save(RefreshMode.REFRESH);

C# Example

// Create class subscription.
IClassSubscription subscription = Factory.ClassSubscription.CreateInstance(os, null);

// The target of the class subscription will be the Document class,
// identified by the ID object.
IDocumentClassDefinition docCD = Factory.DocumentClassDefinition.GetInstance(
   os, new Id("{B19C39FD-9E71-4E56-8D7E-9B036B3B903B}") );
subscription.SubscriptionTarget = docCD;

// Exclude subclasses of the target class.
subscription.IncludeSubclassesRequested= false;

// Get EventAction object created in previous example,
// and set subscription's EventAction property.
IEventAction eventAction = Factory.EventAction.FetchInstance(
   os, new Id("{F1C9ACE3-8454-4B2C-9AC4-30228FAA8113}"), null);
subscription.EventAction = eventAction;

//Specify one or more events that, when triggered,
// will invoke the subscription.
// Add the events to a list and set the subscription object.
Id subscribedEventId = GuidConstants.Class_CreationEvent;
IEventClassDefinition evDef = Factory.EventClassDefinition.GetInstance(
   os, subscribedEventId);
ISubscribedEvent subEvent = Factory.SubscribedEvent.CreateInstance();
subEvent.EventClass = evDef;
ISubscribedEventList subEventList = Factory.SubscribedEvent.CreateList();
subEventList.Add(subEvent);
subscription.SubscribedEvents = subEventList;

// Specify that event handler run synchronously.
subscription.IsSynchronous = true;

subscription.DisplayName = "FileDocumentSubscription";
subscription.Save(RefreshMode.REFRESH);

Retrieving Subscriptions

You can retrieve a single Subscription object with a Factory method, and you can retrieve a collection of Subscription objects (SubscriptionSet) by getting the Subscriptions property on an EventAction or ObjectStore object. You can also return a SubscriptionSet with a WorkflowDefinition object's WorkflowSourceSubscriptions property.

One use case for retrieving all of the subscriptions in an object store is to find all of the subscriptions in which a particular object is the target of the subscriptions. The following Java and C# examples show how to retrieve a SubscriptionSet collection from an ObjectStore object, and iterate the collection in search of subscriptions where the target of the subscriptions is a particular Document object.

Java Example

// Get Document object to find subscriptions in which
// Document object is the target object of the subscriptions.
Document doc = Factory.Document.getInstance(
   os, "Document", new Id("{5B80C0B6-8EE3-430D-BE20-C461842326F8}"));

// Initialize ArrayList to hold subscriptions
// in which Document object is the target of the subscriptions.
ArrayList targetFound = new ArrayList();


// Get all subscriptions from object store.
SubscriptionSet subscriptions = os.get_Subscriptions();

// Iterate SubscriptionSet and look for subscription target 
// that matches specified Document object.
// For each match, add subscription to ArrayList object.
Iterator subcriptionsIter = subscriptions.iterator();
while (subcriptionsIter.hasNext())
{
   Subscription subscription = (Subscription) subcriptionsIter.next();
   Subscribable subObject = subscription.get_SubscriptionTarget();
   if (subObject.equals(doc))
   {
      targetFound.add(subscription);
   }
}

// Iterate ArrayList object and print out name of each subscription
// in which Document object is the target object of the subscription.
Iterator pi = targetFound.iterator();
while (pi.hasNext())
{
   Subscription subscription = (Subscription)pi.next();
   System.out.println(subscription.get_Name());
}

C# Example

// Get Document object to find subscriptions in which
// Document object is the target object of the subscriptions.
IDocument doc = Factory.Document.GetInstance
   (os, "Document", new Id("{5B80C0B6-8EE3-430D-BE20-C461842326F8}"));

// Initialize ArrayList to hold subscriptions
// in which Document object is the target of the subscriptions.
ArrayList targetFound = new ArrayList();

// Get all subscriptions from object store.
ISubscriptionSet subscriptions = os.Subscriptions;

// Iterate SubscriptionSet and look for subscription target
// that matches specified Document object.
// For each match, add subscription to ArrayList object.
foreach (ISubscription subscription in subscriptions)
{
   ISubscribable subObject = subscription.SubscriptionTarget;
   if (subObject.Equals(doc))
   {
      targetFound.Add(subscription);
   }
}

// Iterate ArrayList object and print out name of each subscription
// in which Document object is the target object of the subscription.
foreach (ISubscription subscription in targetFound)
{
   System.Console.WriteLine(subscription.Name);
}

For more information, see Retrieving Workflow Subscriptions.

Adding Subscribed Events to an Existing Subscription

A Subscription object's SubscribedEvents property contains a collection of the subscribed-to events for the subscription. The following Java and C# examples retrieve an existing subscription and print the display names of subscribed events that are currently assigned to the subscription. Then, two new events are added to the subscription: a system event and a custom event. If you add duplicated event types into the SubscribedEvents property, then the EVENT_DUPLICATE_LIST_SUBSCRIBED_EVENT exception is thrown. Adding event types that are already assigned to the subscription are ignored.

Java Example

// Set up property filter for fetching existing subscription.
FilterElement fe = new FilterElement(null, null, null,PropertyNames.SUBSCRIBED_EVENTS);
PropertyFilter pf = new PropertyFilter();
pf.addIncludeProperty(fe);
Subscription subscription = Factory.Subscription.fetchInstance(os, 
   new Id("{AB264E14-2D28-46F1-9215-783952A61897}"), pf);

// Retrieve and display names of subscription's existing subscribed events.
SubscribedEventList subEvents = subscription.get_SubscribedEvents();
Iterator subEventsIter = subEvents.iterator();
System.out.println("Subscribed events before additions:");
while (subEventsIter.hasNext())
{
   SubscribedEvent existingEvent = (SubscribedEvent) subEventsIter.next();
   System.out.println(existingEvent.get_EventClass().get_DisplayName());
}

// Create system subscribed event and add it to collection of subscribed events.
Id subscribedEventId = GuidConstants.Class_CancelCheckoutEvent;
EventClassDefinition evDef = Factory.EventClassDefinition.getInstance(
   os, subscribedEventId);
SubscribedEvent newEvent1 = Factory.SubscribedEvent.createInstance();
newEvent1.set_EventClass(evDef);
subEvents.add(newEvent1);

// Create custom subscribed event and add it to collection of subscribed events.
SubscribedEvent newEvent2 = Factory.SubscribedEvent.createInstance();
subscribedEventId = new Id("{9906D34A-DBE2-415E-B807-6B4CCA65B893}");
evDef = Factory.EventClassDefinition.getInstance(os, subscribedEventId);
newEvent2.set_EventClass(evDef);
subEvents.add(newEvent2);

// Add collection of new events to subscription, then save subscription.
subscription.set_SubscribedEvents(subEvents);
subscription.save(RefreshMode.REFRESH);

C# Example

// Set up property filter for fetching existing subscription.
FilterElement fe = new FilterElement(null, null, null, PropertyNames.SUBSCRIBED_EVENTS);
PropertyFilter pf = new PropertyFilter();
pf.AddIncludeProperty(fe);
ISubscription subscription = Factory.Subscription.FetchInstance(
   os, new Id("{AB264E14-2D28-46F1-9215-783952A61897}"), pf);

// Retrieve and display names of subscription's existing subscribed events.
ISubscribedEventList subEvents = subscription.SubscribedEvents;

System.Console.WriteLine("Subscribed events before additions:");
foreach (ISubscribedEvent existingEvent in subEvents)
{
   System.Console.WriteLine(existingEvent.EventClass.DisplayName);
}

// Create system subscribed event and add it to collection of subscribed events.
Id subscribedEventId = GuidConstants.Class_CancelCheckoutEvent;
IEventClassDefinition evDef = Factory.EventClassDefinition.GetInstance(
   os, subscribedEventId);
ISubscribedEvent newEvent1 = Factory.SubscribedEvent.CreateInstance();
newEvent1.EventClass = evDef;
subEvents.Add(newEvent1);

// Create custom subscribed event and add it to collection of subscribed events.
ISubscribedEvent newEvent2 = Factory.SubscribedEvent.CreateInstance();
subscribedEventId = new Id("{9906D34A-DBE2-415E-B807-6B4CCA65B893}");
evDef = Factory.EventClassDefinition.GetInstance(os, subscribedEventId);
newEvent2.EventClass = evDef;
subEvents.Add(newEvent2);

// Add collection of new events to subscription, then save subscription.
subscription.SubscribedEvents = subEvents;
subscription.Save(RefreshMode.REFRESH);

Creating and Raising a Custom Event

You can create a custom event and run it on a Subscribable object by calling the raiseEvent method on the object. Before you can raise a custom event, the event must exist in the object store. Also, a subscription must exist in which the subscription target is the Subscribable object on which the raiseEvent method is called, and in which the subscribed events include the custom event that is raised. When you raise the custom event, an instance of the RaiseEvent class is created, and the event action set in the subscription is run.

Note:

The following Java and C# examples create a custom event and raise it on a Subscribable object. An EventClassDefinition object is used to create and persist a subclass, MyCustomEvent, of the CustomEvent class. The EventClassDefinition object is added to an existing subscription. The newly created custom event is retrieved, as well as a Subscribable object and a Document object. The custom event is raised on the Document object, which is then saved to send the raiseEvent method to the server. (Because the event action does not change the Document object, NO_REFRESH is specified.)

Java Example

// Create new custom event and save it to object store.
EventClassDefinition custom = Factory.EventClassDefinition.getInstance(
   os, GuidConstants.Class_CustomEvent);
EventClassDefinition customSubclass =(EventClassDefinition) custom.createSubclass();
LocalizedString ls = Factory.LocalizedString.createInstance();
ls.set_LocalizedText("MyCustomEvent");
ls.set_LocaleName("en_US");
LocalizedStringList lsl = Factory.LocalizedString.createList();
lsl.add(ls);
customSubclass.set_DisplayNames(lsl);
customSubclass.save(RefreshMode.REFRESH);

// Get existing subscription to which you will add the new custom event.
FilterElement fe = new FilterElement(null, null, null,PropertyNames.SUBSCRIBED_EVENTS);
PropertyFilter pf = new PropertyFilter();
pf.addIncludeProperty(fe);
Subscription subscription = Factory.Subscription.fetchInstance(os, 
   new Id("{AB264E14-2D28-46F1-9215-783952A61897}"), pf);

// Retrieve list of subscription's existing subscribed events,
// then add new custom event to it.
SubscribedEventList subEvents = subscription.get_SubscribedEvents();
SubscribedEvent newEvent = Factory.SubscribedEvent.createInstance();
newEvent.set_EventClass(customSubclass);
subEvents.add(newEvent);

// Add collection of new events to subscription, then save subscription.
subscription.set_SubscribedEvents(subEvents);
subscription.save(RefreshMode.REFRESH);

// Get newly created custom event that will be raised.
CustomEvent custEvent = Factory.CustomEvent.getInstance(os, "MyCustomEvent", customSubclass.get_Id());

// Get Document object on which custom event will be raised.
Document doc=Factory.Document.getInstance (
   os, "Document", new Id("{50E32923-D1B7-40B5-A394-2F44CA955D2E}") );

// Raise event on Document object, then save it to invoke operation on server.
doc.raiseEvent(custEvent);

doc.save(RefreshMode.NO_REFRESH);

C# Example

// Create new custom event and save it to object store.
IEventClassDefinition custom = Factory.EventClassDefinition.GetInstance(
   os, GuidConstants.Class_CustomEvent);
IEventClassDefinition customSubclass = (IEventClassDefinition)custom.CreateSubclass();
ILocalizedString ls = Factory.LocalizedString.CreateInstance();
ls.LocalizedText = "MyCustomEvent";
ls.LocaleName = "en_US";
ILocalizedStringList lsl = Factory.LocalizedString.CreateList();
lsl.Add(ls);
customSubclass.DisplayNames = lsl;
customSubclass.Save(RefreshMode.REFRESH);

// Get existing subscription to which you will add the new custom event.
FilterElement fe = new FilterElement(null, null, null, PropertyNames.SUBSCRIBED_EVENTS);
PropertyFilter pf = new PropertyFilter();
pf.AddIncludeProperty(fe);
ISubscription subscription = Factory.Subscription.FetchInstance(os,
                 new Id("{AB264E14-2D28-46F1-9215-783952A61897}"), pf);

// Retrieve list of subscription's existing subscribed events,
// then add new custom event to it.
ISubscribedEventList subEvents = subscription.SubscribedEvents;
ISubscribedEvent newEvent = Factory.SubscribedEvent.CreateInstance();
newEvent.EventClass = customSubclass;
subEvents.Add(newEvent);

// Add collection of new events to subscription, then save subscription.
subscription.SubscribedEvents = subEvents;
subscription.Save(RefreshMode.REFRESH);

// Get newly created custom event that will be raised.
ICustomEvent custEvent = Factory.CustomEvent.CreateInstance(os, "MyCustomEvent", customSubclass.Id);

// Get Document object on which custom event will be raised.
IDocument doc = Factory.Document.FetchInstance (
   os, new Id("{50E32923-D1B7-40B5-A394-2F44CA955D2E}"), null);

// Raise event on Document object, then save it to invoke operation on server.
doc.RaiseEvent(custEvent);
doc.Save(RefreshMode.NO_REFRESH);

Setting Status for a Custom Event

You can set the EventStatus property of a CustomEvent object, allowing an event action handler implementation to apply conditional logic that is based on the value of the property. This scenario is shown in the following examples. The first example shows client application code that sets the EventStatus property. The second example shows server event handler code that retrieves and tests the value of the EventStatus property.

Client Application: Setting Status

As shown in the client-based Java and C# examples below, the setEventStatus method creates a CustomEvent object, sets the object's EventStatus property, and raises it on a Document object that is passed to the method. Because the EventStatus property can be set only on a created event, an instance of a custom event must be created and not retrieved.

Java Example

/* This method is invoked based on some user action on a document class.
 * The method creates a custom event and sets the event's EventStatus property based
 * on the group to which the user who invoked the action belongs.
 * The method then raises the custom event on the document passed to the method, which 
 * invokes an event handler, shown below.
 * To make this work, a class subscription exists that contains the document class, 
 * the custom event, and an event action representing the event handler.
 */

public void setEventStatus (Document doc, Connection ceConn)

   // Create an instance of existing custom event.
   CustomEvent custEvent = Factory.CustomEvent.createInstance(os, "MyCustomEvent");

   // Get user who invoked action on document class and the group to which the user belongs.
   User user = Factory.User.fetchCurrent(ceConn, null);
   GroupSet groups = user.get_MemberOfGroups();
   Iterator groupsIter = groups.iterator();

   // Iterate the groups, and set the event status of the custom event
   // based on whether the user is in the "Manager" group or the "Clerical" group.
   // (A user cannot belong to both groups.)
   while (groupsIter.hasNext())
   {
      Group group = (Group) groupsIter.next();
      if ( group.get_ShortName().equals("Manager") )
         custEvent.set_EventStatus(new Integer(50));
      else if ( group.get_ShortName().equals("Clerical") )
         custEvent.set_EventStatus(new Integer(51));
   }

   // Raise event on Document object, then save it to invoke operation on server.
   doc.raiseEvent(custEvent);
   doc.save(RefreshMode.NO_REFRESH);
}

C# Example

public void setEventStatus (IDocument doc, IConnection ceConn)
{

   // Create an instance of existing custom event.
   ICustomEvent custEvent = Factory.CustomEvent.CreateInstance(os, "MyCustomEvent");

   // Get user who invoked action on document class and the group to which the user belongs.
   IUser user = Factory.User.FetchCurrent(ceConn, null);
   IGroupSet groups = user.MemberOfGroups;

   // Iterate the groups, and set the event status of the custom event
   // based on whether the user is in the "Manager" group or the "Clerical" group.
   // (A user cannot belong to both groups.)
   foreach (IGroup group in groups)
   {
      if ( group.ShortName.Equals("Manager") )
         custEvent.EventStatus = 50;
      else if ( group.ShortName.Equals("Clerical") )
         custEvent.EventStatus = 51;
   }

   // Raise event on Document object, then save it to invoke operation on server.
   doc.RaiseEvent(custEvent);
   doc.Save(RefreshMode.NO_REFRESH);
}

Server Event Handler: Getting Status

The following code example demonstrates an EventActionHandler implementation that retrieves the value of the EventStatus property that is previously set in the client application code. The CheckStatusEventHandler class writes an entry to one of two available logs based on the value of the EventStatus property. Note that the EventActionHandler interface can be implemented only in Java.

Java Example

/* This event handler is invoked as a result of the above method.
 * A custom event is passed to it, and the event's EventStatus property
 * is checked to determine which log to write to.
 */

import com.filenet.api.engine.EventActionHandler;
import com.filenet.api.events.ObjectChangeEvent;
import com.filenet.api.util.Id;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

public class CheckStatusEventHandler implements EventActionHandler
{
   public void onEvent(ObjectChangeEvent event, Id subId)
   {
      // Initialize File objects for logs.
      File outputFile1 = new File("C:\\Program Files\\FileNet\\ContentEngine\\logs\\manager.txt");
      // non-Windows: File outputFile1 = new File("/opt/FileNet/ContentEngine/logs/manager.txt");
      File outputFile2 = new File("C:\\Program Files\\FileNet\\ContentEngine\\logs\\clerical.txt");
      // non-Windows: File outputFile2 = new File("/opt/FileNet/ContentEngine/logs/clerical.txt");
      FileWriter out;

      // Check status of custom event and write to applicable log.
      try
      {
         if ( event.get_EventStatus().equals(new Integer(50)) )
         {
            //Write to manager log.
            out = new FileWriter(outputFile1, true); // true = append
            out.write("Manager action taken at: " 
               + new java.util.Date() + "\r\n");
            out.close();
         }
         else if ( event.get_EventStatus().equals(new Integer(51)) ) 
         {
            //Write to clerical log.
            out = new FileWriter(outputFile2, true);
            out.write("Clerical action taken at: " 
               + new java.util.Date() + "\r\n");
            out.close();
         }
      }
      catch (IOException e) {
         ErrorRecord er[] = {new ErrorRecord (e)};
         throw new EngineRuntimeException(e, ExceptionCode.EVENT_HANDLER_THREW, er);
      }
   }
}

Retrieving Queue Items from an Object Store

When an event action configured to run asynchronously is started through a subscription, it is placed in a queue as a pending action that awaits execution. (Document classification actions, which run asynchronously, are placed in the same queue.) Represented as a QueueItem object, an action is removed from the queue if its associated event action handler runs successfully. If the action handler fails, execution is tried again as many times as are set in the QueueItem object's RetryCount property. The default value of the RetryCount property is six; therefore, up to seven execution attempts are made: the initial execution attempt and the six retries if execution repeatedly fails. If there is no successful retry, the QueueItem object remains inactive in the queue with its RetryCount property set to -1.

You can retrieve QueueItem objects that represent pending actions and failed actions. For a failed action, that is, one with a RetryCount property set to -1, you can delete it from the queue with the delete method. Alternatively, you can fix the event action handler and reset the object's RetryCount property, which reactivates the action in the queue.

Note: Although you can safely reset properties of a QueueItem object that has failed, it is recommended that you do not modify properties of a QueueItem object that is still waiting to be processed (pending action).

The easiest way to retrieve QueueItem objects in the queue is with Administration Console for Content Platform Engine, from which you can create SQL searches, or customize packaged search templates for managing entries in the queue. However, you can also retrieve QueueItem objects with the Content Java and .NET APIs.

The following Java and C# samples show how to reactivate inactive QueueItem objects in the queue. Using com.filenet.api.query classes, the examples pass a SQL statement that specifies the QueueItem database table to be searched. The examples iterate the search results, looking for queue items that are event actions, filtering out any potential document classification actions that might also be in the queue. The RetryCount property for inactive event actions is reset to six.

Java Example

...
   // Build the SQL select statement.
   String sqlStr = "Select * from QueueItem";
   SearchSQL sql = new SearchSQL(sqlStr);
   SearchScope ss = new com.filenet.api.query.SearchScope(os);

   // Get all items in the queue.
   QueueItemSet qiSet = (QueueItemSet)ss.fetchObjects(sql, new Integer(1), null, Boolean.TRUE);
   Iterator iter = qiSet.iterator();
   QueueItem qi;

   // Iterate queue items and reset RetryCount property for EventQueueItem objects.
   while (iter.hasNext())
   {
      qi = (QueueItem)iter.next();
      if (qi.get_ClassDescription().get_SymbolicName().equals(ClassNames.EVENT_QUEUE_ITEM))
      {
         System.out.println("Creator: " + qi.get_Creator() +
            "\nDate Created: " + qi.get_DateCreated().toString() +
            "\nRetry count is " + qi.get_RetryCount() );
            if (qi.get_RetryCount().equals(new Integer(-1)) )
            {
               qi.set_RetryCount(new Integer(6));
               qi.save(RefreshMode.REFRESH);
            }
      }
   }
}

C# Example

...
   // Build the SQL select statement.
   String sqlStr = "Select * from QueueItem";        
   SearchSQL sql = new SearchSQL(sqlStr);
   SearchScope ss = new FileNet.Api.Query.SearchScope(os);

   // Get all items in the queue.
   IQueueItemSet qiSet = (IQueueItemSet)ss.FetchObjects(sql, 1, null, true);

   // Iterate queue items and reset RetryCount property for IEventQueueItem objects.
   foreach (IQueueItem qi in qiSet)
   {
      if (qi.ClassDescription.SymbolicName.Equals(ClassNames.EVENT_QUEUE_ITEM))
      {
         System.Console.WriteLine("Creator: " + qi.Creator +
            "\nDate Created: " + qi.DateCreated +
            "\nRetry count is " + qi.RetryCount);
            if (qi.RetryCount == -1 )
            {
               qi.RetryCount = 6;
               qi.Save(RefreshMode.REFRESH);
            }
      }
   }
}
      


Last updated: October 2015
subscription_procedures.htm

© Copyright IBM Corporation 2015.