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 Content Engine uses a default constructor to create an event action handler object. Do not use a custom constructor.
- When an event action handler is started by a publish or republish operation,
a subscription is not involved in starting the handler. Therefore,
the subscription
Id
object that is passed to the handler is anull
value. A publish-invoked handler does not treat anull
subscription value as an error.
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.
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.
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.
- Custom events can be recorded to the Content Engine audit log. For more information, see Configuring a Class for Auditing.
- The state of a custom event can be set by a client application and then used in an event handler for conditional processing. For more information, see Setting Status for a Custom Event.
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.
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);
}
}
}
}