Additional Windchill Capabilities > Service Information Management > Customizing Windchill Service Information Manager and Windchill Service Parts > Customizing Publishing > Advanced Customization of Publishing
  
Advanced Customization of Publishing
Extension Points for Publishing
There are several points during payload creation or processing where a customization can be implemented. You can also implement a post-conversion delegate as well.
Service Structure Traversal
This general use ServiceStructureTraversing delegate modifies the output service structures being serialized without affecting the input service structure. This delegate applies to traversal in general, including translation and publishing.
Registration
Register the ServiceStructureTraversing delegate by adding the following to a service.properties.xconf file:
<Service context="default" name="com.ptc.arbortext.windchill.siscore.
traversal.ServiceStructureTraversing">
<Option serviceClass="YourCustomTraversingClassName
requestor="wt.part.WTPart" selector="null"/>
</Service>
ServiceStructureTraversing Interface
package com.ptc.arbortext.windchill.siscore.traversal;

import java.util.List;

import wt.part.WTPart;
import wt.util.WTException;

/*
* Interface that allows customization of the nodes returned from
* StandardTraversalService.
* Children may be added, removed and reordered.
*/
public interface ServiceStructureTraversing {
boolean children(WTPart parent, List<pubNode> children)
throws WTException;
}
children() API Method
Returns true to use the modified value of the children parameter in the next stage of traversal.
This method is called before each node’s children are visited. The method supports:
Adding child nodes
Removing child nodes
Rearranging child nodes
Parameters:
parent
the service structure node which the traversal code is currently visiting
children
the child nodes of the parent parameter
Custom Content Ready Checker
The CustomContentReadyChecker delegate inspects each dynamic document (including member links of compound documents and graphics referenced from parts lists) during publishing and determines whether or not the content is ready for publishing. This delegate would be used to determine whether translations are ready, but it can also determine whether the document itself is ready.
The publishing rule parameter OnContentHolderLinkFailed defines how the publish request should be handled when a document or its translation is not ready.
Registration
Register the CustomContentReadyChecker delegate by adding the following to a service.properties.xconf file:
<Service name="com.ptc.arbortext.windchill.publisher.
CustomContentReadyChecker">
<Option serviceClass="CustomContentCheckerClassName"
requestor="null" selector="null"/>
</Service>
CustomContentReadyChecker Interface
package com.ptc.arbortext.windchill.publisher;

import wt.fc.Persistable;
import wt.util.WTException;

import com.ptc.arbortext.windchill.publisher.payload.PayloadContext;

public interface CustomContentReadyChecker {
boolean isTranslatedContentReady(
Persistable source,
Persistable trans,
PayloadContext context) throws WTException;
// if PTC_DD_TRANSLATE=="yes" && lang set
boolean isContentReady(
Persistable source,
PayloadContext context) throws WTException; // else this
}
isTranslatedContentReady() API Method
Returns true if the document is ready or false if it is not.
This method checks the state of the document and its translation to determine whether they are ready to be published.
Parameters:
source
the content of the document
trans
the translated content of the document
context
the payload context, which includes publication rule parameters and other publishing information
isContentReady() API Method
Returns true if the document is ready or false if it is not.
This method checks the state of the document to determine whether it is ready to be published.
Parameters:
source
the content of the document
context
the payload context, which includes publication rule parameters and other publishing information
Security Label Aggregator
The SecurityLabelAggregator delegate sets the security labels for a published representation based on the data and their security labels being published.
During the publishing process, Windchill Service Information Manager collects the security labels for each of the elements being collected for the payload and applies a security label attribute. You can define the security label hierarchy for the collection of elements using the SecurityLabelAggregator interface that aggregates security labels based on business logic.
The interface processes security labels for the following:
all WTParts in the structure
all linked WTDocument, EPMDocument, graphic, and parts list objects
all fragments linked from documents
all graphics linked from part lists and documents
all representations included in the payload
* 
Referenced objects are excluded unless their content is also included in the payload (not just their metadata).
Security Labels are not supported for bundle publishing.
Registration
Register the SecurityLabelAggregator delegate by adding the following to a service.properties.xconf file:
<Service name="com.ptc.arbortext.windchill.publisher.
SecurityLabelAggregator">
<Option serviceClass="CustomSecurityLabelAggregatorClassName"
requestor="null" selector="null"/>
</Service>
SecurityLabelAggregator Interface
package com.ptc.arbortext.windchill.publisher;

import java.util.Map;

import wt.access.SecurityLabeled;
import wt.util.WTException;

public interface SecurityLabelAggregator {
/**
*
* @param mergeTo is the output. Initially it has other labels
* @param finalTarget is the object in which the final result is saved
* @param mergeFrom is a collection of labels that will be merged to
* mergeTo.
* @param mergeFromObject is the object where mergeFrom is retrieved.
* If mergeFromObject is a representation, its target object
* is used.
* @param options are the parameters that can be used to control the
* merging.
* @throws WTException, when thrown, the current publish job fails.
*/
public void aggregate(Map<String, String> mergeTo,
SecurityLabeled finalTarget, Map<String, String> mergeFrom,
SecurityLabeled mergeFromObject, Map<String, String> options)
throws WTException;
/**
*
* The method tests if the security labels need the PE alternate
* transaction archive.
* If there is a label called ITAR, an implementation could return true.
* PE would put the publish job's transaction archive in the alternate
* archive.
* @param securityLabels are the aggregated security labels
* @param options parameters
* @return true if secure and false if public
*/
public boolean isSecured(Map<String, String> securityLabels,
Map<String, String> options) throws WTException;
}
aggregate() API Method
Returns void.
This method sets the final security label of the target representation based on the security labels of all the data collected in a payload.
Parameters:
mergeTo
a collection of security labels for the finalTarget. When the method is called, this variable might already contain some security labels.
finalTarget
the object in which the final security labels are stored.
mergeFrom
a collection of security labels for the mergeFromObejct. These security labels will help determine how the final security labels are set.
mergeFromObject
an object which contains some security labels
options
a map of the publishing rule parameters and their values
isSecured() API Method
Returns true or false.
The method checks the aggregated final security labels and determines whether to secure the published representation. If isSecured() returns true, the published representation will need be placed in a secured folder. The secure transaction archive must be configured on the Arbortext Publishing Engine.
Parameters
securityLabels
the final security labels to apply for security
options
a map of the publishing rule parameters and their values
Element Filter
The ElementFilter delegate allows the user to exclude information elements from service structure payloads. For example, this delegate can exclude the information elements with certain security labels from payloads.
A content object (such as an EPMDocument) or a parts list should be filtered if any of their children are filtered, or there is a risk of errors from publishing an incomplete document or parts list.
Registration
Register the ElementFilter delegate by adding the following to a service.properties.xconf file:
<Service name="com.ptc.arbortext.windchill.publisher.payload.ElementFilter">
<Option serviceClass="CustomElementFilterClassName"
requestor="null" selector="null"/>
</Service>
ElementFilter Interface
package com.ptc.arbortext.windchill.publisher.payload;

import wt.fc.Persistable;
import wt.fc.collections.WTList;
import wt.util.WTException;

/**
* An interface that is used to filter information elements based on
* customized criteria. Only one instance is used for the whole payload.
*
*/
public interface ElementFilter {
/**
*
* @param context
* @param curElement it could be WTPart, PartList
* @param associated a list of Persistable objects. If the current
* element is a structured document, such as dynamic document,
* only its root dynamic document is included.
* Depending on business logic, users may need to check the children.
* @return true means we don't include the Element. Otherwise,
* include the element. If the element is not included and the
* publishing stops, an exception is expected.
* @throws WTException
*/
public boolean filter(PayloadContext context, Persistable curElement,
WTList associated) throws WTException;
}
filter() API Method
Returns true to exclude curElement from the payload. Returns false to include curElement.
This method checks each information element in the service structure to determine if it should be filtered.
Parameters:
context
the payload context, which includes publication rule parameters and other information.
curElement
a service structure node, a parts list, or a parts list illustration that might be added to the payload.
associated
a collection of persistable objects that is associated with curElement. For example, if the curElement is an information structure node which points to a dynamic document, the associated parameter contains the dynamic document.
Custom Metadata Source Provider
The CustomMetaDataSourceProvider delegate allows the user to supply additional metadata sources for any parts list item or any node in a service structure. The additional metadata sources are appended to existing metadata sources and then serialized to XML files. Ordinarily, metadata sources are collected from each structure node and each parts list item based on the settings in the publishable_attset.xml file. For more information, see Configuring Attributes.
Registration
Register the CustomMetaDataSourceProvider delegate by adding the following to a service.properties.xconf file:
<Service name="com.ptc.arbortext.windchill.siscore.operation.
CustomMetaDataSourceProvider">
<Option serviceClass="CustomMetaDataSourceProviderClassName"
requestor="null" selector="wt.part.WTPart|com.ptc.sis.Base|
com.ptc.sis.BaseDiv "/>
</Service>
CustomMetaDataSourceProvider Interface
package com.ptc.arbortext.windchill.siscore.operation;

import java.util.List;

import wt.fc.ObjectToObjectLink;
import wt.fc.Persistable;
import wt.util.WTException;

public interface CustomMetaDataSourceProvider {
List<SISMetaDataSource> getCustomDataSources(Persistable targetNode,
ObjectToObjectLink linkToNode,
Persistable rootNode,
SISOperationServerContext hookContext) throws WTException;
}
getCustomDataSources() API method
Returns a collection of custom metadata sources that will be appended to the existing metadata sources and serialized to the target node.
This method collects additional metadata for specified sources.
Parameters:
targetNode
the value can be any of the following:
the node being visited in the information structure or publication structure at the time that the method is called
the wt.part.WTPart linked from a parts list when a Parts List object is serialized
a content object being added to the payload, such as a dynamic document, when that object's metadata is needed in the manifest
linkToNode
the link to the targetNode from the parent node at the time the method is called. This may be null for the root node or for nodes added to the tree by the ServiceStructureTraversing delegate. In a partslist item, this is the PartListItem linked to the wt.part.WTPart. For content objects, it may be a specialized link, such as an EPMDescribedByLink.
rootNode
the root of the service structure or a Parts List object.
hookContext
a SISOperationServerContext context which provides information about the type of operation being performed and the filters applied to the structure.
Providing Custom Metadata Translations
If you are working with translated custom metadata, use the addTranslation() method from the PropertyValue class of RawMetaDataSource. For example:
RawMetaDataSource.Property p = new RawMetaDataSource.
Property("token2", "property_type", null, authorLang);
p.setLocalizable(true);
RawMetaDataSource.PropertyValue v = new RawMetaDataSource.
PropertyValue("value12", "value_token", "value_key");
v.addTranslation("fr", "value12_fr");
v.addTranslation("de", "value12_de");
p.addValue(v);
properties.add(p);
data.setProperties(properties);
Metadata results for French (bundle default):
<Metadata source="RawSoftType">
<Property name="token2">
<Value xml:lang="en" transidref="...">value12</Value>
<Value xml:lang="en" transidref="...">value12_2</Value>
</Property>
</Metadata>
Metadata results in translation.xml (PDF default):
<Target xml:lang="fr">
...
<Value transid="07ecb4cfd68fab55">value12_fr</Value>
<Value transid="07ecb4cfd68fse54">value12_2_fr</Value>
...
</Target>
The delegate can set Localizable to “true”, meaning property values have a translation that can appear in bundle. The addTranslation() method can supply custom translations for a particular language. Delegates can have multiple translations for one PropertyValue, When the bundle is published for a specific language, the appropriate translation (if supplied) will appear in the bundle.
If a property is marked localizable but the delegate does not provide a translation for the publishing target language, the publishing job will fail (if the CompleteTranslationCheck publishing rule is set to “true”).
Comparing Custom Metadata for Aggregated Timestamps
In custom metadata, details of aggregated timestamp are provided through the SIM.lastUpdated attribute for partlist and the SIM.lastUpdatedMetadata attribute for EPM Documents. Use the getTimeStamp() method from the AttributeMetaDataSource class in RawMetadasource in the CustomMetaDataSourceProvider delegate.
Publishing will include the value returned by getTimeStamp() for the root content that is, Dynamic Documents under the content holder, and PartList and ignore the rest of the content. For example, if child Dynamic Document’s custom data contains the timestamp too, publishing will not include this piece of information in its parent’s calculated timestamp.
The timestamp is returned through RawMetadasource and is defined in the AttributeMetaDataSource class.
public class AttributeMetaDataSource implements SISMetaDataSource {
private WTReference targetRef;
protected List<Property> properties;
protected List<Object> incrementalList;
protected long timeStamp;
Manifest Custom Metadata Source Provider
The ManifestCustomMetaDataSourceProvider delegate adds and removes metadata sources for content as well as adds new attributes to existing metadata in the manifest.xml file in the payload. The additional metadata sources are appended to existing metadata sources and then serialized to XML files. A typical existing metadata source would be service effectivity. When serializing service structure content (such as dynamic documents, parts lists) for the payload, metadata sources are collected based on the settings in the manifest_attset.xml. For more information, see Configuring Attributes.
Registration
Register the ManifestCustomMetaDataSourceProvider delegate by adding the following to a service.properties.xconf file:
<Service name="com.ptc.arbortext.windchill.siscore.operation.
ManifestCustomMetaDataSourceProvider">
<Option cardinality="singleton" serviceClass=
"ManifestCustomMetaDataSourceProviderClassName"
requestor="null" />
</Service>
The selector attribute specifies the context. The class is registered as a singleton. Be sure the object can be reused in multiple threads simultaneously.
ManifestCustomMetaDataSourceProvider Interface
package com.ptc.arbortext.windchill.siscore.operation;

import java.util.List;
import java.util.Map;

import wt.fc.WTReference;
import wt.fc.collections.WTKeyedMap;
import wt.util.WTException;

public interface ManifestCustomMetaDataSourceProvider {
/**
*
* @param currentData
* @param hookContext
* @return
* @throws WTException
*/
Map<WTReference, List<SISMetaDataSource>> getCustomDataSources
(WTKeyedMap currentData,SISOperationServerContext hookContext)
throws WTException;
}
getCustomDataSources() API Method
Returns a map of targeted references and their custom metadata information.
Parameters:
currentData
The value is a map of targeted references and their children.
hookContext
a SISOperationServerContext context which provides information about the type of operation being performed and the filters applied to the structure.
Example of Adding Metadata
Initialize an OperationMetaDataSource object.
OperationMetaDataSource om = new OperationMetaDataSource
(OperationMetaDataSource.E_Operation.Add);
WTArrayList list = new WTArrayList();
list.add(PersistableObject);
om.setTargets(list);
Return the OperationMetaDataSource object.
Map<WTReference, List<SISMetaDataSource>> ret = new HashMap
<WTReference, List<SISMetaDataSource>>
List<SISMetaDataSource> src = new ArrayList<SISMetaDataSource>()
src.add(om);
ret.put(targetRef, src);
Example of Removing Metadata
Initialize an OperationMetaDataSource object.
OperationMetaDataSource om = new OperationMetaDataSource
(OperationMetaDataSource.E_Operation.Remove);
WTArrayList list = new WTArrayList();
list.add(PersistableObject);
om.setTargets(list);
Return the OperationMetaDataSource object.
Map<WTReference, List<SISMetaDataSource>>
ret = new HashMap<WTReference,
List<SISMetaDataSource>>List<SISMetaDataSource> src = new
ArrayList<SISMetaDataSource>();
src.add(om);
ret.put(targetRef, src);
Example of Adding an Attribute to Existing Metadata
Initialize an AttributeMetaDataSource object.
AttributeMetaDataSource am = new AttributeMetaDataSource(ref);
List<RawMetaDataSource.Property> properties = new ArrayList
<RawMetaDataSource.Property>();
RawMetaDataSource.Property p = new RawMetaDataSource.Property
("NewCustomAttributeId", null);
RawMetaDataSource.PropertyValue v = new RawMetaDataSource.PropertyValue
(ref.toString(), null, null);
p.addValue(v);
properties.add(p);
am.setProperties(properties);
Return the AttributeMetaDataSource object.
Map<WTReference, List<SISMetaDataSource>>
ret = new HashMap<WTReference,
List<SISMetaDataSource>>List<SISMetaDataSource> src = new
ArrayList<SISMetaDataSource>();
src.add(am);
ret.put(targetRef, src);
Providing Custom Metadata Translations
If you are working with translated custom metadata, use the addTranslation() method from the PropertyValue class of RawMetaDataSource. For example:
RawMetaDataSource.Property p = new RawMetaDataSource.
Property("token2", "property_type", null, authorLang);
p.setLocalizable(true);
RawMetaDataSource.PropertyValue v = new RawMetaDataSource.
PropertyValue("value12", "value_token", "value_key");
v.addTranslation("fr", "value12_fr");
v.addTranslation("de", "value12_de");
p.addValue(v);
properties.add(p);
data.setProperties(properties);
Metadata results for French (bundle default):
<Metadata source="RawSoftType">
<Property name="token2">
<Value xml:lang="en" transidref="...">value12</Value>
<Value xml:lang="en" transidref="...">value12_2</Value>
</Property>
</Metadata>
Metadata results in translation.xml (PDF default):
<Target xml:lang="fr">
...
<Value transid="07ecb4cfd68fab55">value12_fr</Value>
<Value transid="07ecb4cfd68fse54">value12_2_fr</Value>
...
</Target>
The delegate can set Localizable to “true”, meaning property values have a translation that can appear in bundle. The addTranslation() method can supply custom translations for a particular language. Delegates can have multiple translations for one PropertyValue, When the bundle is published for a specific language, the appropriate translation (if supplied) will appear in the bundle.
If a property is marked localizable but the delegate does not provide a translation for the publishing target language, the publishing job will fail (if the CompleteTranslationCheck publishing rule is set to “true”).
Comparing Manifest Custom Metadata for Aggregated Timestamps
In custom metadata, details of aggregated timestamp are provided through the SIM.lastUpdated attribute for partlist and the SIM.lastUpdatedMetadata attribute for EPM Documents. Use the getTimeStamp() method from the AttributeMetaDataSource class in RawMetadasource in the ManifestCustomMetadataSourceProvider delegate.
Publishing will include the value returned by getTimeStamp() for the root content that is, Dynamic Documents under the content holder, and PartList and ignore the rest of the content. For example, if child Dynamic Document’s custom data contains the timestamp too, publishing will not include this piece of information in its parent’s calculated timestamp.
public class AttributeMetaDataSource implements SISMetaDataSource {
private WTReference targetRef;
protected List<Property> properties;
protected List<Object> incrementalList;
protected long timeStamp;
* 
Metadata returned from this hook is not monitored for incremental publishing.
Custom Translation Hook
The CustomTranslationHook can retrieve translated values for Windchill attributes during publishing. A null return value means that a translation is not available. The published output will be included in translation.xml. The specified attributes need to be included in the localizable_attset.xml configuration file to be included in the payload.
Registration
Register your custom translation hook delegate by adding an entry like the following to the sis.service.properties.xconf file:
<Service name="com.ptc.arbortext.windchill.siscore.CustomTranslationHook">
<Option serviceClass="YourCustomTranslationHookClassName"
requestor="null" selector="null"/>
</Service>
CustomTranslationHook Interface
package com.ptc.arbortext.windchill.siscore.translation;
import wt.util.WTException;
public abstract class CustomTranslationHook {
/**
*
* @param softtype Windchill soft type name
* @param attributeName Windchill soft attribute name
* @param sourceLanguage source or authored language of attributeValue
* @param attributeValue attributeValue to fetch translation for
* @param targetLanguage target language of translation to fetch
* @throws WTException
*/
public abstract String translateAttribute(String softtype,
String attributeName, String sourceLanguage,
String attributeValue, String targetLanguage)
throws WTException;

}
translateAttribute() API Method
This method specifies the attribute for which you want to retrieve a translated attribute value.
The returned value is a translated string for the specified attribute if a translation exists. If the method returns null or throws an exception, a translation is not available and the source attribute string will be used.
Parameters:
softtype
the Windchill subtype of the service structure
attributeName
the Windchill subtype attribute name
sourceLanguage
the source or authored language of the attributeValue
attributeValue
the attribute value for which a translation should be retrieved
targetLanguage
the target language for which a translation should be retrieved
Custom Folder in Payload
The CustomArtifactProvider delegate provides a hook to include custom artifacts to the payload bundle.
Registration
Register the CustomArtifactProvider delegate by adding an entry like the following to the sis.service.properties.xconf file:
<Service name="com.ptc.arbortext.windchill.publisher.payload.CustomArtifactProvider">
<Option serviceClass="YourCustomArtifactProviderImplementation"
requestor="null" selector="null"/>
</Service>
CustomArtifactProvider Interface
package com.ptc.arbortext.windchill.publisher.payload;
import com.ptc.wvs.common.util.VSResult;
import wt.util.WTException;
public interface CustomArtifactProvider {
/**
* This method is passed the path for a newly created empty temporary
* directory as well as the payload context object.
* @param tempDirPath : empty temporary directory
* @param context : payload context object
* @return VSResult.SUCCESSFUL or VSRESULT.FAIL
* @throws WTException
*/
public VSResult initiateCustomFolder(String tempDir, PayloadContext context) throws WTException;
/**
* If the method returns VSResult.SUCCESSFUL, then the contents of the directory
* will be copied to the custom folder in the payload.
Otherwise if the method returns VSRESULT.FAIL, the temporary directory
will be permanently deleted with including its content in the payload.
* @return VSResult.SUCCESSFUL or VSRESULT.FAIL
* @throws WTException
*/
public VSResult publishCustomFolder() throws WTException;
/**
* cleanUp is called regardless what happens to publish
* to clean up resources in customization.
*/
public void cleanUp();
initiateCustomFolder() API Method
This method is passed the path for a newly created empty temporary directory as well as the payload context object. If it returns VSResult.FAIL, the publish job stops and returns error.
Parameters:
tempDir
empty temporary directory
context
payload context object
Returns VSResult.SUCCESSFUL or VSRESULT.FAIL
publishCustomFolder() API Method
This method modifies the contents of the temporary directory. For example, zipping some artifacts.
Returns VSResult.SUCCESSFUL or VSRESULT.FAIL. If the method returns VSResult.SUCCESSFUL, the contents of the directory are copied to the custom folder in the payload. If the method returns VSRESULT.FAIL, the temporary directory is permanently deleted with its contents in the payload.
Method to Encode Directory and File Names
The encodePayloadFileName utility uses a percent style encoding to encode special characters that may be present in the filename of a directory or artifacts in the payload or publishing bundle. The utility replaces special characters and non-alphanumeric characters contained in filenames with an underscore (_) character followed by the hex (#) values of the characters that are being replaced.
Following characters will not be escaped during encoding:
A-Z (Uppercase Latin characters)
a-z (Lowercase Latin characters)
0–9 (Arabic numerals)
. (period)
~ (Tilde)
Method signature for the utility:
public static String encodePayloadFileName(String fname)
Fully qualified method signature for the utility:
com.ptc.arbortext.windchill.publisher.payload.util.FileNameUtil.encodePayloadFileName(String fname)
Where, fname is the filename.
Publish Inactive Product Hierarchy Nodes
The CustomPHHook detects Product Hierarchy nodes outside of the Product Hierarchy tree and publishes them as inactive nodes. If the node is a part of tree, it is marked as inactive. If it is not, it is inserted as a child of root PH and it is marked as inactive.
Registration
Register your custom product hierarchy hook delegate by adding an entry like the following to the ssis.service.properties.xconf file:
<Service name="com.ptc.arbortext.windchill.publisher.payload.CustomPHHook">
<Option cardinality="singleton" serviceClass="YourCustomPHHook"
requestor="null" selector="null"/>
</Service>
CustomPHHook Interface
package com.ptc.arbortext.windchill.publisher.extract;
import com.ptc.arbortext.windchill.publisher.payload.PayloadContext;

import wt.fc.collections.WTCollection;
import wt.filter.NavigationCriteria;
import wt.part.WTPart;
import wt.util.WTException;
Public abstract class CustomPHHook {
public abstract WTCollection getInactivePHNodes(WTPart rootPH, NavigationCriteria phNC, PayloadContext payloadContext);
}
getInactivePHNodes() API Method
Returns a collection of WTParts that are inactive nodes in a Product Hierarchy. If the method returns a node that is not a part of the Product Hierarchy or the object is not a WTPart, an exception is thrown. If the method returns a node or part that is outside of the Product Hierarchy tree, the node is added as a new Product Hierarchy information element in the structure.
Parameters:
rootPH
root of Product Hierarchy Structure
phNC
Product Hierarchy navigation criteria
payloadContext
Context
Post-Convert Delegate
The PostConvertDelegate allows the user to post-process a returned response from Arbortext Publishing Engine after a publishing job. The response includes information in the composerlog.xml file that has errors or warnings. This information should either trigger a workflow action or email notification. The delegate will be called whether the publishing job passes or fails.
If PostConvertDelegate throws an exception, the exception will be noted in the WVS log, but that exception will not change the status of the publishing job.
Registration
Register your custom post-convert delegate by adding the WVS PostConvertDelegate publishing parameter to a publishing rule and specifying the class name of your custom delegate, for example:

<worker name="com.ptc.arbortext.wvs/PostConvertDelegate">
com.ptc.arbortext.windchill.publisher.CustomPostConvertDelegate</worker>
PostConvertDelegate Interface
package com.ptc.arbortext.windchill.publisher;

import java.io.InputStream;
import java.util.Map;

import com.ptc.wvs.common.util.VSResult;
import com.ptc.wvs.server.publish.PublishParams;

import wt.fc.collections.WTCollection;
import wt.representation.Representable;
import wt.representation.Representation;
import wt.util.WTException;

/**
* The abstract class is designed to invoke after the response is returned
* from PE whether the publish job fails or succeeds.
*/
public abstract class PostConvertDelegate {
/**
* The method is invoked after getting response from PE.
* Its result is displayed in the WVS monitor.
* Any exception it throws is logged in method server log,
* but doesn't affect existing publish process;
*
* @param representable is the target object
* @param targetRep is the targeted representation in the targeted object.
* It is not null only for republishing or incremental publishing.
* @param parameters are publishing parameters for this publishing job.
* @param responseStreams is the map that includes all the file names
* and file output streams
* @param publishedList is the list of content included in the payload.
* If it is null, audit is disabled.
* @return is the messages sent to WVS job monitor */
public abstract VSResult execute(Representable representable,
Representation targetRep,
PublishParams parameters,
Map<String, InputStream> responseStreams,
WTCollection publishedList) throws WTException;
}
execute() API Method
The returned value is displayed in the WVS job monitor.
This method is invoked just after the publishing job response is returned from Arbortext Publishing Engine.
Parameters:
representable
the target object that has been published
targetRep
the targeted representation in the targeted object. This parameter is for republishing and incremental publishing only. When it is not null, it contains the old representation of the target object. All other cases are null.
parameters
the publish rule parameters that were used for this publishing job
responseStreams
a map that includes all the file names and file output streams for the response
publishedList
a collection of the contents included in the payload. It can be null if audit is disabled.