Data Management Capabilities > Managing Change > Change Management Administration > Change Association Rule Administration > Flexible Change Link Conversion > Convert Custom Links to Flexible Change Links
  
Convert Custom Links to Flexible Change Links
If you have custom change objects or links, you must follow additional steps to convert to flexible change objects:
Update change process links—Required only if you have custom change links that include additional attributes.
Create a converter delegate for each custom link type.
Create a converter rule file for each custom link type.
Create a custom readiness delegate—Required only if the provided readiness delegates do not satisfy your requirements.

Update Change Process Link
If a custom link has any additional attributes, it cannot be converted to a change process link.
You can accomplish this using the AddColumns utility. For more information, see Running the AddColumns Tool.
See the next section for an example of a custom link with an additional attribute.

Converter Delegate for Custom Link Type
This delegate allows you to update the change process link with any unique values from the custom legacy link. To register your new delegate, see Properties and Property Files.
Windchill provides the following link converter delegate registrations:
<!-- Delegates for converting legacy change link to flexible links. -->
<Service context="default" name="wt.change2.flexible.FlexibleChangeLinkConverterDelegate">
<Option selector="wt.change2.FormalizedBy" cardinality="singleton"
serviceClass="wt.change2.flexible.DefaultFlexibleChangeLinkConverterDelegate"
requestor="null"/>

<Option selector="wt.change2.AddressedBy2" cardinality="singleton"
serviceClass="wt.change2.flexible.DefaultFlexibleChangeLinkConverterDelegate"
requestor="null"/>
</Service>
In the following example, there is an additional attribute on the custom legacy link that must be added to the change process link. This example assumes you have already run the AddColumns utility.
The delegate retrieves the attribute from the custom legacy link and adds it to the change process link:
package com.myCompany;
public class CustomLinkConverterDelegate extends FlexibleChangeLinkConverterDelegate {

@Override
public void postStoreUpdate(WTValuedMap legacyToFlexibleLinkMap) throws WTException {
Locale locale = SessionHelper.getLocale();

//Go through individual legacy links
for(Object obj: legacyToFlexibleLinkMap.entrySet()){
WTValuedEntry entry = (WTValuedEntry) obj;
ObjectReference legacyLinkRef = (ObjectReference) entry.getKey();
ObjectReference changeProcessRef = (ObjectReference) entry.getValue();

//Get value of custom attribute
CustomFormalizedBy formalizedBy = (CustomFormalizedBy) legacyLinkRef.getObject();
String customLinkValue = formalizedBy.getValue().toString();

//Set value of attribute on Change Process Link
ChangeProcessLink changeProcessLink = (ChangeProcessLink) changeProcessRef.getObject();
PersistableAdapter perAdapter = new PersistableAdapter(changeProcessLink,null,locale,new UpdateOperationIdentifier());
perAdapter.load("CustomLinkValue");
perAdapter.set("CustomLinkValue",customLinkValue);
perAdapter.apply();
try {
changeProcessLink.getPersistInfo().setVerified(true);
} catch (WTPropertyVetoException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
PersistenceHelper.manager.modify(changeProcessLink);
}
}
}
The CustomLinkConverterDelegate class would be registered as follows:
<Service context="default" name="wt.change2.flexible.FlexibleChangeLinkConverterDelegate">
<Option selector="wt.change2.FormalizedBy" cardinality="singleton"
serviceClass="com.myCompany.CustomLinkConverterDelegate"
requestor="null"/>
</Service>

Custom Link Type Converter Rule Files
Custom link converter rule files must be created for each custom link in the system.
For example, a link converter rule file for com.myCompany.CustomFormalizedBy would be located and named as follows:
<Windchill>/codebase/wt/change2/flexible/LinkConverterRule.com.myCompany.CustomFormalizedBy.csv
For more information, see Configure Link Converter Rules.

Custom Readiness Delegate
The readiness delegate determines whether a change object is ready for conversion based on your requirements.
Windchill provides the following default delegates:
WorkflowReadinessDelegate
ResolutionDateReadinessDelegate
TerminalStateReadinessDelegate
AdministrativeLockReadinessDelegate
* 
The TerminalStateReadinessDelegate is not registered out-of-the-box. For more information, see Administration of Terminal States for Change Management Objects.
The default readiness delegates determine whether a change object is ready for conversion. If the object passes one evaluation, then the object is considered ready for conversion regardless of whether it fails another readiness delegate.
To change this behavior for a change object type, call the following API on the ReadinessInfo object: setShouldContinueProcessing() If this API is set to false, the utility stops checking other delegates if an object is marked as not ready for conversion.
Windchill provides the following services for configuring the readiness delegates:
wt.change2.flexible.FlexibleChangeItemReadinessDelegate.convertLinks
wt.change2.flexible.FlexibleChangeItemReadinessDelegate.convertReplicatedLinks
Each delegate must be registered with a unique selector integer value greater than zero. When two or more readiness delegates are registered, they are used in order of increasing selector value.
The wt.change2.flexible.FlexibleChangeItemReadinessDelegate.convertLinks service calls the AdministrativeLockReadinessDelegate first to check if the change object is administratively locked. If locked, the delegate returns a ReadinessInfo object containing the following values:
isReady flag set to false
shouldContinueProcessing flag set to false
The processing of the current administratively locked object is stopped from further readiness checks.
If the object is not locked, ResolutionDateReadinessDelegate is called to determine whether the change object is ready for conversion. If it is not ready, the WorkflowReadinessDelegate is called.
The wt.change2.flexible.FlexibleChangeItemReadinessDelegate.convertReplicatedLinks service does not call the AdministrativeLockReadinessDelegate.
The following example provides the configuration for out-of-the-box readiness delegates:
<!-- Delegates for computing readiness state for converting legacy change items.
The selector attribute must be unique and must be an integer because the delegates
are called in a particular order which is based on the selector value. -->
<Service context="default" name="wt.change2.flexible.FlexibleChangeItemReadinessDelegate.convertLinks">
<Option serviceClass="wt.change2.flexible.AdministrativeLockReadinessDelegate"
selector="10"
requestor="wt.change2.FlexibleChangeItem"
cardinality="singleton"/>
<Option serviceClass="wt.change2.flexible.ResolutionDateReadinessDelegate"
selector="20"
requestor="wt.change2.FlexibleChangeItem"
cardinality="singleton"/>
<Option serviceClass="wt.change2.flexible.WorkflowReadinessDelegate"
selector="30"
requestor="wt.change2.FlexibleChangeItem"
cardinality="singleton"/>
</Service>

<Service context="default" name="wt.change2.flexible.FlexibleChangeItemReadinessDelegate.convertReplicatedLinks">
<Option serviceClass="wt.change2.flexible.ResolutionDateReadinessDelegate"
selector="10"
requestor="wt.change2.FlexibleChangeItem"
cardinality="singleton"/>
<Option serviceClass="wt.change2.flexible.WorkflowReadinessDelegate"
selector="20"
requestor="wt.change2.FlexibleChangeItem"
cardinality="singleton"/>
</Service>
To register your new delegate, see Properties and Property Files.
The following example delegate demonstrates two actions:
Checks whether the change object is in the Implementation state.
Disregards any other delegates if the object is in the wrong state.
package com.myCompany;
public class CustomReadinessDelegate extends FlexibleChangeItemReadinessDelegate {

protected static final String CUSTOM_RESOURCE = CustomConverterResource.class.getName();
private static final Logger logger = Logger.getLogger(CustomReadinessDelegate.class.getName());

@Override
public WTKeyedMap determineReadiness(WTCollection changeItems) throws WTException {
WTKeyedMap changeItemToReadinessMap = new WTKeyedHashMap();
Map<FlexibleChangeItem, Boolean> shouldContinueMap = new HashMap<FlexibleChangeItem, Boolean>();

for (Object object : changeItems) {
ObjectReference changeItemRef = (ObjectReference) object;
ChangeRequest2Custom changeItem = (ChangeRequest2Custom) changeItemRef.getObject();
ReadinessInfo readinessInfo = null;
WTMessage reasonMsg;
boolean isReady = true;
boolean shouldContinue = true;
if (((VersionableChangeItem) changeItem).getState().getState() != State.toState("IMPLEMENTATION")) {
reasonMsg = new WTMessage(CUSTOM_RESOURCE, CustomConverterResource.INCORRECT_STATE,
new Object[] { FlexibleChangeConverterHelper.getDisplayIdentity(changeItem) });
isReady = false;
shouldContinue = false;
} else {
reasonMsg = new WTMessage(CUSTOM_RESOURCE, CustomConverterResource.CORRECT_STATE,
new Object[] { FlexibleChangeConverterHelper.getDisplayIdentity(changeItem) });
}
readinessInfo = new ReadinessInfo(isReady, changeItemRef, reasonMsg);
readinessInfo.setShouldContinueProcessing(shouldContinue);
changeItemToReadinessMap.put(changeItem, readinessInfo);
}
return changeItemToReadinessMap;
}
}
To execute CustomReadinessDelegate before the out-of-the-box delegates, register it with a lower selector value:
<Service context="default" name="wt.change2.flexible.FlexibleChangeItemReadinessDelegate">
<Option serviceClass=" com.myCompany.CustomReadinessDelegate"
selector="5"
requestor="wt.change2.FlexibleChangeItem"
cardinality="singleton"/>
</Service>