IBM FileNet P8, Version 5.2            

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 already 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, as well as 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 invoke 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 invoked, 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 implementing an event action handler, note the following:

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 belonging 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 executes. 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. See Restrictions and Best Practices for additional implementation information. To view a sample source code EventActionHandler implementation 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 launched 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 Java-implemented handler, 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 saved, an EventAction object 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 saved, a subscription 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);
}

See Retrieving Workflow Subscriptions for more information.

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 currently assigned to the subscription. Then two new events are added to the subscription: a system event and a custom event. Note if you add duplicated event types into the SubscribedEvents property, then the EVENT_DUPLICATE_LIST_SUBSCRIBED_EVENT exception will be thrown. Adding event types that are already assigned to the subscription will be 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 invoke 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 will be called, and in which the subscribed events include the custom event that will be raised. When you raise the custom event, an instance of the RaiseEvent class is created, and the event action set in the subscription is invoked.

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, 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 passed to the method. Note that an instance of a custom event must be created and not retrieved because the EventStatus property can only be set on a created event.

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

Below is an EventActionHandler implementation that retrieves the value of the EventStatus property set in the client application code above. 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 only be implemented 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 invoked through a subscription, it is placed in a queue as a pending action awaiting 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 executes successfully. If the action handler fails, execution will be retried as many times as set in the QueueItem's RetryCount property. The default value of the RetryCount property is six; therefore, up to seven execution attempts will be made, the initial execution attempt and the six retries should execution repeatedly fail. 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 representing 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, you should 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 specifying 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);
            }
      }
   }
}
      


Feedback

Last updated: October 2013
subscription_procedures.htm

© Copyright IBM Corporation 2014.
This information center is powered by Eclipse technology. (http://www.eclipse.org)