Advanced Customization > Business Logic Customization > Windchill ProjectLink Customization > Writing Custom Windchill ProjectLink Algorithms > Custom Handler Guidelines for Status and Deadline Calculation
  
Custom Handler Guidelines for Status and Deadline Calculation
* 
Custom handlers should only modify HealthStatus and Deadline and should not modify any other activity attribute.
Whenever possible, use multi-object APIs (APIs that take a collection as an argument rather than an individual object). This helps you avoid calling an API in a loop.
For example, to get all the running plans in the system, you should author the API as follows:
public WTCollection getActivePlans(){
QuerySpec qs = new QuerySpec();
int idxPlan = qs.appendClassList(Rootable.class, true);
SearchCondition scForActivePlans = new SearchCondition (
Plan.class,
Plan.PLANNABLE_STATE,
SearchCondition.EQUAL,
PlannableState.INPROCESS);
qs.appendWhere(scForActivePlans, new int[] { idxPlan });
PlanResultProcessor resultProcessor = new PlanResultProcessor();
PersistenceServerHelper.manager.query((StatementSpec) qs, resultProcessor);
WTHashSet plans = new WTHashSet(PersistenceHelper.manager.find(qs));
return plans;
}
Custom handlers should always refresh activity collections before performing any update operation on that object using the following API:
WTCollection summaryActivities = new WTArrayList(activitiesCollection);
leafActivities = CollectionsHelper.manager.refresh(leafActivities);
Custom handlers should always save activities after modification.
Preferably, you should use a multi-object API:
PersistenceHelper.manager.save(activities)
If only saving a single activity, use the following API:
PersistenceHelper.manager.save(leafAct)
To invoke custom algorithms from custom event listeners, call the following API from LeafActivityHealthStatusHandlerFactory:
void calculateDeadlineAndHealthStatus(WTCollection activities, Object event) throws WTException, WTPropertyVetoException
Avoiding Redundant Object Processing
Multiple events might get fired when a particular operation is performed. For example, if a user sets % Work Complete to 100 when completing the Track Work action on an activity in an automatic execution plan, the following events fire:
Plan Activity State Change
EPP Percent Change
EPP Finish Change
If only one custom algorithm is shared among all the events (for example, if the algorithm is not event-based), this will call the same custom algorithm on the same data three times.
To avoid repeatedly executing your algorithm, you can incorporate MethodContext and ProcessedEvent.
MethodContext provides operation-specific information about the events thrown and the objects for which they were thrown. This information is available in the following format:
HashMap(<Project Management Event Name>, <List of Objects>)
Whenever a single operation dispatches and listens to multiple events, HashMap updates after processing each event with an entry for the event and any objects processed.
You can then use the ProcessedEvent key to get the HashMap object from MethodContext:
HashMap(String, WTArrayList) objMap = MethodContext.get(“ProcessedEvent”);
Within this map, the event name for the ProjectManagementEvent is provided as the key, and the list of objects processed as part of that event is the value.
Your custom algorithm can iterate through the key set and find out the objects processed thus far.
For example, a collection of activities throws two events: EPP_PERCENT_CHANGE and EPP_FINISH_CHANGE:
1. The EPP_PERCENT_CHANGE event is thrown first.
2. Once it is processed, HashMap is updated as follows:
HashMap("ProcessedEvent", HashMap(EPP_PERCENT_CHANGE, <List of Objects>));
3. EPP_FINISH_CHANGE is thrown.
Now if your algorithm listens to the EPP_FINISH_CHANGE event, you can read the HashMap to check for a collection of objects that have already been processed by the EPP_PERCENT_CHANGE event. From there, you can determine if you want to process the same objects for EPP_FINISH_CHANGE. If not, you can skip this collection.