Customizing Hook to Generate or Regenerate New Service Structure
Background
When generating or regenerating a service structure from a template structure, the OOTB business logic determines which nodes in the template structure should be removed, reused, or copied to the resulting service structure.
The OOTB business logic to determine the removal, reuse, or copy of nodes is as follows:
• The node has been removed from the template structure.
• The node has been filtered out of the template structure.
• The node is an empty group or section and the Include Empty Nodes preference is set to false.
• The parts list in the template structure is empty or would be empty after applying the filter. This would also cause its parent to be removed if it has no other siblings.
• The parts list in the template structure is generic and has no true parts matching the filter. This would also cause its parent to be removed if it has no other siblings.
• Reuse—The following types of nodes are reused from the template structure and new copies are not made in the resulting service structure:
◦ Information Elements
◦ Content Holders
◦ Generic Information Elements
• Copy—The following types of nodes are copied from the template structure and are inserted as new objects into the resulting service structure:
◦ Information Groups
◦ Publication Sections
◦ Nested Information Structures
◦ Nested Publication Structures
◦ Dynamic Documents—When a dynamic document is copied, only the document itself is copied and any linked dynamic documents are reused.
◦ Textual Information Elements
◦ Graphical Information Elements
Objective
Override the OOTB business logic and add custom algorithm rules to decide whether nodes should be removed, reused, or copied.
Solution
A customization hook has been created to allow you to create your own business logic to decide which nodes should be removed, reused, or copied when generating or regenerating a service structure. By default this follows the OOTB logic. This service can be extended by a custom implementation to override the OOTB business logic. The default interface and the public API for the service are described below.
Interface
The NodeResolutionService interface allows the comparison of nodes so as to determine which nodes should be removed, reused, or copied. You can customize the StandardNodeResolutionService service by extending it and hooking the custom implementation of the service in the wt.properties file using the xconfmanager utility.
There are two methods that can be overridden to allow the custom logic implementations, one method for generation and another for regeneration of service structures. The methods are as follows:
• resolveNodeForGeneration
/**
* This method is called when processing nodes during structure generation to determine which child nodes should be copied, reused or omitted from the generated structure.
*
*@param sourceNode the child node which should be resolved
* @return A map of the nodes stored against the relevant resolution key (COPY, REUSE, REMOVE, UNRESOLVED)
*/
Map<NavigationUnit, ResolutionKey> resolveNodeForGeneration(NavigationUnit sourceNode)
• resolveNodeForRegeneration
/**
* This method is called when processing nodes during structure generation to determine which child nodes should be copied, reused or omitted from the generated structure. It is expected that this method will call the service helper methods to retrieve the child nodes for testing against custom logic
*
* @param isNew true if the node is a new source node being added to the structure
* @param sourceNodes the child nodes which should be resolved in the source structure
* @return A map of the nodes stored against the relevant resolution key (COPY, REUSE, REMOVE, UNRESOLVED)
*/
Map<NavigationUnit, ResolutionKey> resolveNodeForRegeneration(boolean isNew, NavigationUnit sourceNode)
Each node in the source structure will be passed to the method through a NavigationUnit, which contains the node itself, its parent and the UsageLink in between.
ResolutionKey is an enumeration that identifies the resolutions for objects returned from the service. The valid keys for ResolutionKey are as follows:
• REMOVE — List of nodes from the target structure that will be removed from the newly generated or regenerated service structure.
• REUSE — List or range of new nodes that are required to be reused in the target structure such as new Information elements. In case of structure regeneration, this key lists only new nodes or elements that were not previously generated since those will be reused by default, unless they are identified for remove or copy.
• COPY — List or range of nodes from the source structure that require new copies to be created for them in the target structure.
• UNRESOLVED — The node has not been resolved by the customizing hook logic and is to be returned to the system to be resolved by the OOTB logic.
Registry
1. Use the xconfmanager utility to edit site.xconf.
2. Add the following property:
Property name=" wt.services.service.10399"
overridable="true"
targetFile="codebase/wt.properties"
value="com.ptc.arbortext.windchill.siscore.services.NodeResolutionService/<fully qualified custom class"/>
where, <fully qualified custom class> is the full qualified package address, that is, com.ptc.arbortext.sis.MyServiceImplementation.
3. Save the file.
4. Propagate your changes using the xconfmanager utility. From the <Windchill>\bin directory, enter the following command:
xconfmanager -pF
5. Restart the method server.
Helper Methods
Some protected helper methods are provided which can be used to retrieve related nodes and help resolve nodes. These helper methods can be called from the resolveNodeForGeneration and resolveNodeForRegeneration methods by passing their parameters to the helper methods. You can access these helper methods in the new class using the super key word.
These helper methods return arrays of navigation units representing the relationship between the parent and child of a given node in the template structure. A navigation unit contains a parent, the child, and the links between them.
• getChildren
/**
* Retrieves an Array of Navigation units representing the relationship between the parent and child nodes
*
* @param parent the node to find the children for.
* @return the NavigationUnits containing the children.
*/
protected NavigationUnit [] getChildren(Persistable parent, boolean sourceNodes);
• getParents
/**
* Retrieves an Array of Navigation units for the nodes parent/s
*
* @param child the child node to find the parents of.
* @return the NavigationUnits containing the parents.
*/
protected NavigationUnit [] getParents(Persistable child, boolean sourceNodes);
/**
• findPreviousGeneratedTargetNode
* Attempts to retrieve a previously generated element and its parent for the given source node, N.B for IEs
* this will be a navigation unit containing itself since it would have been reused on any previous generation.
*
* @param sourceUnit The source element to find the target node for.
* @return The target navigation unit containing the previously generated element (or itself if an IE) as the end node
*/
protected NavigationUnit findPreviousGeneratedTargetNode(NavigationUnit sourceUnit) {
• getGeneratedPartList
/**
* Checks if the PartList param was resolved by the partlist service i.e. has changes and/or contains parts
*
* @param pList The part list to locate the generated part list for.
* @return a generated partlist, the same partlist (if reused) or null if the partlist was not resolved (is empty/filtered)
*/
protected PartList getGeneratedPartList(PartList pList)
• External helper method: SisCoreHelper.getContentFromHolders(holders);
getContentFromHolders
/**
* A multi object api version of getContentFromHolder to reduce number of jdbc calls.
*
* @param holders
* A WTCollection of content holders.
* @return
*/ A WTKeyedMap of content holders to a WTCollection of content.
public static WTKeyedMap getContentFromHolders(WTCollection holders);