Advanced Customization > Business Logic Customization > Customizing Windchill Visualization Services > Custom Publishing
  
Custom Publishing
Objective
You want to initiate publishing from another product area or from custom code. You may also want to define alternative inputs to the creation of a representation such as naming, descriptions, or configuration specifications to an OOTB publishing mechanism (i.e. check-in driven and scheduled publishing).
Background
Out-of-the-box Windchill Visualization Services can create representations three ways. They are by manual creation from the Windchill UI, the check-in of a Representable (an object that can have Representations; i.e. EPMDocument, WTPart, WTDocument), and by a schedule job. This document will help explain how to initiate publishing in other ways such as custom code for workflows, from a custom UI, etc.
This topic also explains how to customize the creation of representations from such existing mechanisms like the check-in of a Representable or by a schedule job. Unlike manual creation, there is no out-of-the-box way to specify special configuration specifications for publishing, or provide business specific information you may want to capture in the name or description of the Representation.
Scope/Applicability/Assumptions
Custom publishing should be used when there is a requirement to initiate publishing in Windchill from a non-standard way (something other than check-in, manual or schedule), or if you need to modify the input information for a Representation. Publishing can only be performed on wt.representation.Representable objects (i.e. EPMDocuments, WTPart, WTDocuments; including soft and hard typed children).
Intended Outcome
Using the information in this topic will allow end users to perform publishing in a manner in-line with their business requirement whenever the out-of-the-box publishing mechanisms are not sufficient.
Solution
Customize publishing by implementing public WVS APIs in custom code and making WVS aware of this custom code via appropriate WVS property changes.
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following:
Java Development
Standard WVS publishing setup and configuration
WVS concepts such as Representable and Representation
Basic understanding of publishable business objects such as EPMDocuments, WTParts and WTDocuments and their relationships/structure
The use of configuration specifications (ConfigSpecs)
* 
The use of configuration specifications (ConfigSpecs) Additional Resources includes references to many or all of these subjects.
Solution Elements
Element
Type
Description
Publisher.class
Class file
Contains api for doPublish needed for invoking publishing from code.
Runtime Location: <Windchill>\codebase\com\ptc \wvs\common\ui
PublisherAction. class
Class file
Used to create the optional actionString to be passed to the doPublish method in Publisher. See JavaDoc for details.
Runtime Location: <Windchill>\codebase\com\ptc \wvs\common\ui
VisualizationHelper.class
Class file
Contains helper api’s such as findRepresentable and getRepresentation often needed in custom code.
Runtime Location: <Windchill>\ codebase\com\ptc \wvs\common\ui
ScheduleJobs.class
Class file
Contains getCurrentContainer method needed when writing custom schedule jobs.
Runtime Location: <Windchill>\codebase\com\ptc \wvs\server\schedule
wvs.properties
Properties file
Contains specific properties used with the Windchill Visualization Service.
Runtime Location: <Windchill>\codebase
Procedure – Invoking Publishing from Custom Code/Workflow
This section details how to use the following supported APIs and classes:
doPublish from Publisher class – see Simple Publish
PublisherAction class for advanced use of doPublish – see Advanced Publish
To invoke publishing from custom code or from an Expression Robot in a Workflow the key method to understand and use is the supported doPublish method in the com.ptc.wvs.common.ui.Publisher class.
public boolean doPublish (boolean viewableLink,
boolean forceRepublish,
String objectReference,
ConfigSpec configSpec,
ConfigSpec partConfigSpec,
boolean defaultRep,
String repName,
String repDescription,
int structureType,
String actionString,
int jobSource)
For more details on this method and it’s parameters, see the JavaDoc in <Windchill>\codebase\wt\clients\library\api\index.html.
Simple Publish
You have an EPMDocument instance with publishable data and you want to create a default Representation.
String objRef =
ObjectReference.newObjectReference(myepmdoc).toString();
Publisher pub = new Publisher();
boolean result = pub.doPublish(false, true, objRef,
(ConfigSpec)null,
(ConfigSpec)null, true, null, null,
Publisher.EPM, null, 0);
This simple example will simply add a publish job to the publishing queue for myepmdoc. The resulting default representation named “default” will be published using the As-Stored or Latest ConfigSpec as defined in wvs.properties (publish.configspec.default.useasstoredifavailable). Since the forceRepublish parameter was true, an existing representation with the same name would be replaced.
If you wanted to programmatically provide a name for the representation, or insert useful business information into the description modify the parameters. For example:
Publisher pub = new Publisher();
boolean result = pub.doPublish(false, true, objRef,
(ConfigSpec)null,
(ConfigSpec)null, true, “MyRep”,
(ConfigSpec)null, true, “MyRep”,
“My Description”, Publisher.EPM, null,
0);
The only difference between this and the previous example is that the resulting default representation will have the name “MyRep” and have the description “My Description”.
If you wish to retrieve a reference to an existing Representation, set the viewableLink parameter to true and the forceRepublish parameter to false. If there is an existing Representation with the repName you provided associated to the Representable, you can call getViewableObjRef() following a call to doPublish. This will provide a String object reference if the Representation was found. Otherwise null will be returned.
String repObjRef = null;
Publisher pub = new Publisher();
if (pub.doPublish(true, false, objRef, (ConfigSpec)null,
(ConfigSpec)null,
true, “MyRep”, “My Description”, Publisher.EPM,
null, 0)) {
repObjRef = pub.getViewableObjRef();
}
In addition to getting the object reference of an existing Representation, you can also get an HTML fragment to use for launching Creo View to view the representation by using the getViewableLink() api following a call to doPublish. Again, viewableLink must be true, forceRepublish must be false, and a Representation with the name passed in for repName must exist on the Representable supplied by the objRef parameter.
String repLink = null;
Publisher pub = new Publisher();
if (pub.doPublish(true, false, objRef, (ConfigSpec)null,
(ConfigSpec)null,
true, “MyRep”, “My Description”, Publisher.EPM,
null, 0)) {
repLink = pub.getViewableLink();
}
Advanced Publish
You have an EPMDocument instance with publishable data and you want to create a default Representation with your own configuration specification and have the publish job processed on the high priority publishing queue.
The more advanced features of publishing require using the use of the PublisherAction class. See the JavaDoc for full details; a couple examples are shown below.
String objRef =
ObjectReference.newObjectReference(myepmdoc).toString();
PublisherAction pa = new
PublisherAction(PublisherAction.QUEUEPRIORITY, “H”);
ConfigSpec configSpec = <MyHelper.getBaselineConfigSpec()>;
Publisher pub = new Publisher();
boolean result = pub.doPublish(true, true, objRef, configSpec,
null, true,
null, null, Publisher.EPM,
pa.toString(), 0);
You have a WTDocument with several pieces of content. For example, doc1.doc, doc2.doc and doc3.doc are all content of your WTDocument and you only wish to publish doc3.doc (by default all docs would be published).
String objRef = ObjectReference.newObjectRefer-
ence(mydoc).toString();
PublisherAction pa =
new PublisherAction(PublisherAction.DOCUMENTFILE, “doc3.doc”);
Publisher pub = new Publisher();
boolean result = pub.doPublish(true, true, objRef, (Config-
Spec)null,
(ConfigSpec)null, null, null,
Publisher.NONE, pa.toString(), 0);
* 
For WTDocuments, a ConfigSpec is not used and the structureType is Publisher.NONE.
This sort of processing could be useful if you established a business practice of naming certain content files in a particular way if you wanted them to be published.
Procedure – Getting Representables and Representations
This section details how to use the following supported APIs and classes:
findReprentable from VisualizationHelper class – see findRepresentable
getRepresentation and getRepresentations from VisualizationHelper class – see getRepresentable.
The association of Representables to Representations is one to many. The key concept when finding these relationships is to understand that when you have an EPMDocument (i.e. Representable) its Representations aren’t necessarily directly associated. In the case where an EPMDocument has an actively associated WTPart (i.e. option of creating associated parts in the workgroup manager was used when checking-in the EPMDocument), the Representations are linked to the WTPart. In all other cases the Representations are directly associated with the Representable (i.e. non-actively associated EPMDocuments, DynamicDocuments, WTParts, WTDocuments and MPMLink Representables).
findRepresentable
To simplify the concept discussed above, there is a method called findRepresentable in com.ptc.wvs.common.ui.VisualizationHelper. This method allows you to pass in a Representable and always get back the right Representable in the case where actively associated parts are involved. In the case where there are no actively associated parts, it simply returns the object you passed in. The method signature is shown below:public Representable findRepresentable(Persistable d)
public Representable findRepresentable(Persistable d)
If you have custom code that is dealing with Representables, it is a good practice to use this method so you can be sure to have the right Representable that is associated to the Representations. Also, note that if you pass in a Persistable that is not a Representable, the method will return null. You must have an instance of VisualizationHelper to use this method. For example:
VisualizationHelper vizHelper = new VisualizationHelper();
Representable repable = vizHelper.findRepresentable(d);
getRepresentation
In the com.ptc.wvs.common.ui.VisualizationHelper there are also some convenience methods for getting Representations from a Representable.
public Representation getRepresentation(Persistable d)
As noted previously, the relationship of Representables to Representations is one to many. However, one of the Representations may be noted as the “default” Representation. There will be 0 or 1 defaults. The above method will return the default Representation if one exists. Otherwise, null will be returned.public Representation getRepresentation(Persistable d, String repName)
public Representation getRepresentation (Persistable d,
String repName)
The method above will return the Representation associated to the Persistable with the name passed in to the repName argument. If there are no Representations or one can’t be found with the supplied name, null will be returned.
public QueryResult getRepresentations(Persistable d)
This method will return all of the Representations associated to the Persistable passed in. If there are no Representations, null will be returned.
All three methods in this subsection require that you have an instance of VisualizationHelper:
VisualizationHelper vizHelper = new VisualizationHelper();
Representation rep = vizHelper.getRepresentation(d);
* 
All three of the above methods make use of the findRepresentable method, so you do not need to worry about actively associated parts when calling it. Additionally, if the Persistable passed in is not a Representable, null will be returned.
Procedure – Creating Custom Schedule Jobs
This section details how to use the following supported APIs and classes:
Creating a custom schedule job step-by-step and using supported api getCurrentContainer from ScheduleJobs class – see Custom Schedule Job Fundamentals.
Incorporating the use of doPublish from the Publisher class in your custom schedule job – see An Advanced Technique for Custom Schedule Jobs.
Custom Schedule Job Fundamentals
In addition to the out-of-the-box Schedule Jobs, you can also create your own custom jobs. To do this, start by creating or adding to a custom class in the Windchill codebase; for example ext.wvs.CustomJobs. In this class create a method with the following signature:
public static WTList <nameOfMethod>() or public static QuerySpec <nameOfMethod>() or public static QueryResult <nameOfMethod>()
You can use whatever method name you want, but it is important that the method be public, static, return a WTList and accept no arguments.
Then add the following to your wvs.properties.xconf file (edit as needed):
<Property default="MyCustomJob" name="myJob.description"/>
<Property default="ext.wvs.CustomJobs" name=" myJob.class"/>
<Property default="myCustomJob" name=" myJob.method"/>
<Property default="true" name=" myJob.enableOnContainers"/>
<Property default="myJob" name="schedulejobs<N>"/>
Line 1 (<Property default="MyCustomJob" name="myJob.description"/>) is what you see in the Scheduler UI to identify your custom job.
Line 2 (<Property default="ext.wvs.CustomJobs" name=" myJob.class"/>) is the fully qualified class where your custom method resides.
Line 3 (<Property default="myCustomJob" name=" myJob.method"/>) is the name of your custom method.
Line 4 (<Property default="true" name=" myJob.enableOnContainers"/>) defines whether or not the job code will have access to the container that the schedule job was initiated from. For example, the out-of-the-box schedule jobs only handle objects found in the container the schedule job was initiated from (i.e. Project, Product, Library, or Organization) because this value is set to true. If the value is set to false it would be the same as executing the job from the context of the Exchange container, no matter what container the schedule job was initiated from.
Line 5 (<Property default="myJob" name="schedulejobs<N>”/>) is to display your custom job in the Publish Scheduler Administrator. In the name string you must replace the <N> with the integer that follows that last schedulejobsN that is already defined.
Below is an example of a publish job:
public static WTlist myCustomJob() {
WTList wtl = new WTArrayList();
try {
QuerySpec qs = new QuerySpec(WTDocument.class);
WTContainerRef cr = ScheduleJobs.getCurrentContainer();
if (cr != null) {
ContainerSpec cs = new ContainerSpec();
cs.addSearchContainer(cr);
qs.setAdvancedQueryEnabled(true);
qs.appendWhere(
WTContainerHelper.getWhereContainerIn(cs, ,new Class[] {WTDocument.class}),
new int[]{0});
}
if (cr != null) qs.appendAnd();
qs.appendWhere(new SearchCondition(WTDocument.class,
Iterated.LATEST_ITERATION,
SearchCondition.IS_TRUE),
new int[]{0});

Representable doc = null;
int offset = 0;
BasicPageableQuerySpec bpqs = new BasicPageableQuerySpec();
bpqs.setPrimaryStatement(qs);
bpqs.setOffset(offset);
bpqs.setRange(1000);
PagingQueryResult qr =
(PagingQueryResult)PersistenceHelper.manager.find(bpqs);
long sessionId = qr.getSessionId();
int total = qr.getTotalSize();

while (true) {
while (qr.hasMoreElements()) {
doc = (Representable)((Object[])qr.nextElement())[0];
wtl.add(doc);
}

offset += qr.size();
if (offset >= total) break;

PageableQuerySpec pqs = new PagingSessionSpec(sessionId);
pqs.setOffset(offset);
pqs.setRange(1000);
qr = (PagingQueryResult)PersistenceHelper.manager.find(pqs);
}
if (sessionId > 0) PagingSessionHelper.closePagingSession(sessionId);
} catch(Exception e) {e.printStackTrace(); wtl = new WTArrayList ();}

return wtl;
}
* 
This example contains the use of a BasicPageableQuerySpec and PagingSessions to avoid out of memory errors. See JavaDoc in the wt.query and wt.fc packages for details.
This example would effectively ask for all latest iterations of any WTDocuments found in the current container to be published.
In line six of the example the following method is used from com.ptc.wvs.server.schedule.ScheduleJobs:
public static WTContainerRef getCurrentContainer()
The result of this method will be null if the schedule job was initiated from the Exchange container (Site) or if the enableOnContainers value is false in the job definition (see line four of properties shown prior to the example above). If the value of enableOnContainers is true, then a WTContainerRef of the container the schedule job was initiated from will be returned. In the example code, this is used to filter the scope of the query to the Organization or the Product/Project/Library container the schedule job was initiated from.
* 
You can have multiple custom schedule jobs. Just use another method name in the same class, or use a new class altogether. For example:
public static WTList anotherCustomJob();
Then add the following to your wvs.properties.xconf file (edit as needed):
<Property default="AnotherCustomJob"
name="anotherJob.description"/>
<Property default="ext.wvs.CustomJobs" name=" anotherJob.class"/>
<Property default="anotherCustomJob" name=" anotherJob.method"/>
<Property default="true" name=" anotherJob.enableOnContainers"/>
<Property default="anotherJob" name="schedulejobs<N>"/>
An Advanced Technique for Custom Schedule Jobs
Using the technique in the Custom Schedule Job Fundamentals does not allow you to provide input to creating the Publish Job and specify the name of the Representation, description of the Representation, etc. Combining the concepts in the Procedure — Invoking Publishing from Custom Code Workflow with the Custom Schedule Job Fundamentals can open up a lot of flexibility for schedule jobs.
The technique simply requires you to insert the use of the doPublish method from the Publisher class into your myCustomJob method. Since myCustomJob must return a QueryResult, simply return an empty QueryResult as the doPublish method will now cause Publish Jobs to be queued up for execution.
public static WTList myCustomJob() {
WTList wt = new WTArrayList();

try {
QuerySpec qs = new QuerySpec(WTDocument.class);
WTContainerRef cr = ScheduleJobs.getCurrentContainer();
if (cr != null) {
ContainerSpec cs = new ContainerSpec();
cs.addSearchContainer(cr);
qs.setAdvancedQueryEnabled(true);
qs.appendWhere(
WTContainerHelper.getWhereContainerIn(cs, WTDocument.class),
new int[]{0});
}
if (cr != null) qs.appendAnd();
qs.appendWhere(new SearchCondition(WTDocument.class,
Iterated.LATEST_ITERATION,
SearchCondition.IS_TRUE),
new int[]{0});

Representable doc = null;
String objRef;
int offset = 0;
BasicPageableQuerySpec bpqs = new BasicPageableQuerySpec();
bpqs.setPrimaryStatement(qs);
bpqs.setOffset(offset);
bpqs.setRange(1000);
PagingQueryResult qr =
(PagingQueryResult)PersistenceHelper.manager.find(bpqs);
long sessionId = qr.getSessionId();
int total = qr.getTotalSize();

while (true) {
while (qr.hasMoreElements()) {
doc = (Representable)((Object[])qr.nextElement())[0];
objRef =
ObjectReference.newObjectReference(doc).toString();
Publisher pub = new Publisher();
pub.doPublish(false, true, objRef, (ConfigSpec)null,
(ConfigSpec)null, true, "My Rep",
"My Description", Publisher.NONE, null, 0)
;
}

offset += qr.size();
if (offset >= total) break;

PageableQuerySpec pqs = new PagingSessionSpec(sessionId);
pqs.setOffset(offset);
pqs.setRange(1000);
qr =
(PagingQueryResult)PersistenceHelper.manager.find(pqs);
}
if (sessionId > 0)
PagingSessionHelper.closePagingSession(sessionId);
} catch(Exception e) {e.printStackTrace();}

return new wtl;
}
This is the same example used in Custom Schedule Job Fundamentals , but notice the use of the doPublish method shown in bold. This custom job will now create Representations with the name “My Rep” and a description of “My Description”. Also, note that the returned WTList from the method is empty.
Refer to Procedure — Invoking Publishing from Custom Code Workflow for see other useful ways to use the doPublish method.
Procedure – Customizing Check-in Based Publishing
This section details how to use the following property-driven custom hooks:
publish.service.filterepmdocumentpublishmethod – see Filter Publishing for EPMDocument Check-in.
publish.service.filterdocumentpublishmethod – see Filter Publishing for WTDocument Check-in or Upload.
Incorporating the use of doPublish from the Publisher class in your custom hook code – see An Advanced Technique for Custom Check-in Based Publishing.
Filter Publishing for EPMDocument Check-in
Once publishing is configured for an Authoring Application (i.e. Creo Parametric) publishing will occur out-out-of-the box for all EPMDocuments of that Authoring Application that are checked-in. Sometimes there are business reasons for filtering out some EPMDocuments from publishing based on some criteria. For example a certain lifecycle state, EPMDocumentType, EPMDocSubType, etc. Windchill Visualization Services has a code hook available where you can plug in code to filter on such criteria.
In a custom class you can define a method with the following signature:
public static Boolean epmFilterMethod(EPMDocument epmdoc)
You can use whatever name you want in place of epmFilterMethod. Make sure the class that contains your custom method is accessible in the Windchill codebase (i.e. ext.wvs.MyFilterMethods).
The next step is to add the class and method to wvs.properties.xconf. The following property is empty out-of-the-box. Update it to include your class and filter method in the format “class/method”.
<Property default="ext.wvs.MyFilterMethods/epmFilterMethod"
name="publish.service.filterepmdocumentpublishmethod"/>
Once you make the change use the xconfmanager to propagate the changes to wvs.properties.
Every time a check-in occurs where publishing of an EPMDocument would normally occur, this method will now be invoked. If the method returns Boolean.TRUE publishing will be attempted for the specific EPMDocument. If the method returns Boolean.FALSE, publishing will not be attempted.
The following is a simple example of how to filter out a specific EPMDocumentType:
public static Boolean epmFilterMethod(EPMDocument epmdoc) {
if (epmdoc.getDocType().equals(

EPMDocumentType.toEPMDocumentType("MANIKIN_POSTURE"))) {
return Boolean.FALSE;
}
return Boolean.TRUE;
}
This is another example where you can filter out the publishing of EPMDocuments that are in the LifeCycle state of InWork.
public static Boolean epmFilterMethod(EPMDocument epmdoc) {
if (epmdoc.getLifeCycleState() != State.INWORK) {
return Boolean.TRUE;
}
return Boolean.FALSE;
}
Filter Publishing for WTDocument Check-in or Upload
Very similar to filtering publishing for EPMDocuments, there is a means for filtering for WTDocument publishing as well. For example, you may want to filter based on specific filenames, lifecycle state, container, etc. If the system has a worker configured for publishing specific WTDocument content, a custom filter method can be used to keep certain content from being published.
In a custom class you can define a method with the following signature:
public static Boolean docFilterMethod(WTDocument doc, ContentItem ci)
You can use whatever name you want in place of docFilterMethod. Make sure the class that contains your custom method is accessible in the Windchill codebase (i.e. ext.wvs.MyFilterMethods). Notice that this method differs from the EPMDocument filter method signature by including ContentItem as a parameter. This method is called for each ContentItem associated to the WTDocument on check-in. It is also called for uploads. For example if you had a WTDocument with .doc file as primary content and a .xls file as secondary content, this method would be called twice; once with each content item (pending a worker was associated to both types of content).
The next step is to add the class and method to wvs.properties.xconf. The following property is empty out-of-the-box. Update it to include your class and filter method in the format “class/method”.
<Property default="ext.wvs.MyFilterMethods/docFilterMethod"
name="publish.service.filterdocumentpublishmethod"/>
Once you make the change use the xconfmanager to propagate the changes to wvs.properties.
Every time a check-in or upload occurs where publishing of WTDocument content would normally occur, this method will now be invoked. If the method returns Boolean.TRUE publishing will be attempted for the specific WTDocument ContentItem. If the method returns Boolean.FALSE, publishing will not be attempted.
The following example shows how to filter if the WTDocument’s description is “Do Not Publish”, or if the filename of the content starts with “donotpublish”.
public static Boolean docFilterMethod(WTDocument doc, ContentItem ci) {

if (doc.getDescription().equals("Do Not Publish")) {
return Boolean.FALSE;
}
if (ci instanceof ApplicationData) {
String filename = ((ApplicationData)ci).getFileName();
if (filename.startsWith("donotpublish") {
return Boolean.FALSE;
}
}
return Boolean.TRUE;
}
An Advanced Technique for Custom Check-in Based Publishing
Using the techniques in Filter Publishing for EPMDocument Check-in and Filter Publishing for WTDocument Check-in or Upload do not allow you to provide input for creating Publish Jobs to specify the name of the Representation, description of the Representation, etc. Combining the concepts in Procedure — Invoking Publishing from Custom Code Workflow with the concepts in Filter Publishing for EPMDocument Check-in and Filter Publishing for WTDocument Check-in or Upload can open up a lot of flexibility for check-in based publishing.
The technique simply requires you to insert the use of the doPublish method from the Publisher class into the epmFilterMethod or the docFilterMethod shown in the previous subsections. Since the two filter methods must return a Boolean, simply return Boolean.FALSE and use the doPublish method to cause Publish Jobs to be queued up for execution.
public static Boolean epmFilterMethod(EPMDocument epmdoc) {

if (epmdoc.getDocType().equals(
EPMDocumentType.toEPMDocumentType("MANIKIN_POSTURE"))) {
return Boolean.FALSE;
}
String objRef = ObjectReference.newObjectReference(epmdoc).toString();
Publisher pub = new Publisher();
pub.doPublish(false, true, objRef, (ConfigSpec)null,
(ConfigSpec)null,
"My Rep", "My Description", Publisher.EPM, null, 0);

return Boolean.FALSE;
}
This is the same example used in Filter Publishing for EPMDocument Check-in , but notice the use of the doPublish method shown in bold. This custom job will now create Representations with the name “My Rep” and a description of “My Description”. Also, note that the returned Boolean from the method is Boolean.FALSE.
Refer back to Procedure — Invoking Publishing from Custom Code Workflow for see other useful ways to use the doPublish method.
Procedure – Customizing General Publishing
This section details how to:
Use the property-driven hook: publish.service.filterpublishmethod – see Filtering All Publishing
Incorporate the use of doPublish from the Publisher class in your custom hook – see An Advanced Technique for Custom Check-in Based Publishing
Filtering All Publishing
In addition to the filters specifically for EPMDocuments and WTDocuments described in Procedure-Customizing Check-in Base Publishing, Windchill Visualization Services has a more general hook that is called for anything that can be published (including EPM and WTDocuments). In addition to supporting the filtering of all Representables, this hook also includes publishing of pre-converted data.
In a custom class you can define a method with the following signature:
public static Boolean filterMethod(Persistable p, Boolean
publishFromDB)
You can use whatever name you want in place of filterMethod. Make sure the class that contains your custom method is accessible in the Windchill codebase (i.e. ext.wvs.MyFilterMethods). This method includes a publishFromDB parameter. This Boolean will come in as Boolean.TRUE if the publish is being invoked for data stored in Windchill, i.e. content of an EPMDocument or WTDocument object. The value will come in as Boolean.FALSE if the publish is for data not stored in Windchill, i.e. local data converted from the file system or data from the clipboard. You can use the value of publishFromDB to have your custom code handle the two cases specifically if you wish.
The next step is to add the class and method to wvs.properties.xconf. The following property is empty out-of-the-box. Update it to include your class and filter method in the format “class/method”.
<Property default="ext.wvs.MyFilterMethods/filterMethod"
name="publish.service.filterpublishmethod"/>
Once you make the change use the xconfmanager to propagate the changes to wvs.properties.
Every time publishing would normally occur, this method will now be invoked. If the method returns Boolean.TRUE publishing will be attempted for the Persistable. If the method returns Boolean.FALSE, publishing will not be attempted.
The following is a simple example of how to filter out publishing of the content if the Persistable is LifeCycleManaged and in its final phase of its LifeCyle:
public static Boolean filterMethod(Persistable p, Boolean publishFromDB) {
if (!publishFromDB) return Boolean.TRUE;
if (!(p instanceof LifeCycleManaged)) return Boolean.TRUE;
try {
if (LifeCycleHelper.service.isInFinalPhase((LifeCycleManaged)p)) {
return Boolean.FALSE;
}
} catch (WTException wte) {
wte.printStackTrace();
}
return Boolean.TRUE;
}
* 
In the above example the second line states that if the data requested for publishing is not from the Windchill DB, then just return true. For example if someone is publishing data on a WTPart that was uploaded from their local disk, we are saying we don't wish to filter this out and to simply return Boolean.TRUE.
Limitations
Customization Boundaries
PTC does not support the customizations of the out-of-the-box CadConvert classes (a.k.a. Publishers), the Worker Agent, or the WVS Loader. These components of WVS were not intended for customization and there is no guarantee that future releases would not break customizations attempted with these components.
Custom Schedule Job Performance
Though schedule jobs are run in the background using queues, it is possible to create very resource intensive queries to return in your custom code. The examples in the Procedure-Creating Custom Schedule Jobs section showed one technique of using paging to help avoid problems caused by dealing with large result sets. Be sure your custom schedule jobs are tested on production-like datasets. What works for cases where the result is 100 does not always work as well when you have 10’s or 100’s of thousands of results.
Custom Check-in Filtering Performance
Keep in mind with using the check-in filter techniques shown in Procedure-Customizing Check-in Base Publishing that your method will be ran for every Representable that is a candidate for publishing. You method should be efficient and try to do as little as possible to determine cases where the true or false result can be returned. If some intense logic needs to occur in the filter method, do all you can to rule out the need before executing it.
Additional Resources
Java Development: http://java.sun.com
Getting Started with Windchill Visualization Services
wvs.properties.xconf file in your <Windchill>\codebase directory.
Related Package/Class Javadoc
com.ptc.wvs.common.ui
com.ptc.wvs.server.schedule
Other Related Windchill Documentation
Windchill Business Administrator's Guide
Creo® View MCAD Adapters Installation and Configuration Guide
Creo® View ECAD Adapters Installation and Configuration Guide