TeamcenterKnowledge

Customization

Dispatcher: The Four Levels of Custom Translator

"Custom translator" and "custom handler" get used for four genuinely different pieces of work. They are not equally hard, and people routinely quote the cost of level 3 for a job that only needs level 0.

Decide which level you are actually at before you plan anything.

Level 0: no code at all

You need: an XML block in translator.xml, a launch script, and two preference files imported with preferences_manager.

Siemens ships generic, preference-driven implementations of both Teamcenter-side classes:

Translator.XYZ.ppttopdf.Prepare=com.teamcenter.ets.translator.ugs.basic.TaskPrep
Translator.XYZ.ppttopdf.Load=com.teamcenter.ets.translator.ugs.basic.DatabaseOperation

Those basic classes read preferences to learn which dataset type to extract from, which named reference to pull, and which dataset type, named reference and relation to create on the way back in. No compilation, no jar, no classpath.

This is the right answer for the large majority of "we need a new translator" requests, and it is buried in a sample Readme.txt rather than being the headline of chapter 7. Full recipe: Zero-Java custom translator.

Effort: hours. Risk: low. Ceiling: one source dataset in, one result dataset out, on a fixed relation.

Level 1: a launch script

You need: everything from level 0, plus real logic in the script the Module invokes.

The contract is a shell script contract and nothing more. Dispatcher stages input files in a working directory, calls your script with -inputpath= / -outputpath= style arguments as declared in translator.xml, and reads the exit code. Non-zero fails. It also scans stdout and stderr for the strings you declare in <TransErrorStrings>, which is how a translator that exits 0 but printed not privileged still gets marked failed.

The shipped plmxmltojt.pl is 223 lines, of which roughly 170 are generic argument-parsing helpers. Its header says the intent out loud:

System Admins are expected to customise this wrapper for individual site needs

Effort: a day. Risk: low, because you can run the script standalone before Dispatcher ever sees it. Every shipped translator supports -help and is designed to be exercised from a command prompt first.

Level 2: a Module-side wrapper class

You need: a Java class extending com.teamcenter.tstk.translator.DefaultTranslator, compiled against Module/lib, referenced by wrapperclass= in translator.xml.

Use this when the command line needs computing rather than templating, or when output filenames need rewriting, or when you need per-translator concurrency and retry control.

The shipped sample, Module/samples/ProEToDxf.java, is 63 lines including the copyright banner and overrides exactly one method:

package com.teamcenter.tstk.server.translator.ugs.proetodxf;

import com.teamcenter.tstk.translator.DefaultTranslator;
import com.teamcenter.tstk.translator.TranslatorException;

public class ProEToDxf extends DefaultTranslator
{
   final static private String DOT_DRW = "\\.drw";

   public ProEToDxf( String scTag ) throws TranslatorException { super(scTag); }

   public String getOutputFileName( String scFileName )
   {
     return super.getOutputFileName( scFileName.replaceAll(DOT_DRW, "") );
   }
}

AbstractTranslator exposes roughly 45 overridable methods. The ones that actually get overridden in practice: getCommandArray() to build the command line yourself, getOutputFileName(), hasValidInputExtension() / hasValidOutputExtension(), setMaxLimit(), setReTries(), setSrcPathLimit().

Only 8 of the 78 OOTB services declare a wrapperclass at all. That ratio is the honest signal about how often you need this.

Effort: a day or two, most of it setting up a build. Risk: low.

Level 3: TaskPrep and DatabaseOperation

You need: two Java classes on the Dispatcher Client side, packaged as a jar into DispatcherClient/lib, bound in conf/Service.properties.

This is the real work, and the only level where you are writing Teamcenter data- model logic. TaskPrep.prepareTask() decides what comes out of Teamcenter; DatabaseOperation.load() decides what goes back in and how it is related.

Take this level when the level-0 preference model cannot express your mapping: multiple result datasets, conditional typing, results attached to something other than the source item revision, BOM-aware output, or reading structure to decide what to extract.

Details and the worked proetojt example: TaskPrep and DatabaseOperation.

Effort: a week or more, and it wants a live Dispatcher to iterate against. Risk: moderate. This is the level people mean when they say "custom code", and it is usually not the level the task needs.

Adjacent: custom filters

Separate from all four levels, AbstractSubmitFilter (Module side, admission control) and the Dispatcher Client filter classes (request validation) let you reject or defer requests without touching translation logic at all. A sample TranslatorFilter.java ships in DispatcherClient/sample/integration/filters/. Chapter 7 of the admin guide covers "Create custom filters" before it covers translators, which is a hint that filters solve more problems than people expect.

⚠ Choosing the load pattern is a separate decision

Independent of levels 0 to 3, decide who writes the result into Teamcenter. Getting this wrong is silent and expensive.

Dispatcher loads Direct translator
Who writes to TC basic.DatabaseOperation or your DatabaseOperation Your translator, itself
Load binding in Service.properties present absent
OutputNeeded true false
Result mapping _ets_dst_* preferences your own code, or PostProcessor.xml
Can produce exactly one file, one type, one relation any number of artifacts
Stock examples tozipfile, nxdwgtotif nxtopvdirect, nxtransdirect, qsearchprocessqueue

The deciding question is how many artifacts your translator produces. basic.DatabaseOperation loads a single file named <sourceBaseName><_ets_dst_nr_fileext> from the task's result directory, and attaches it with one dataset type and one relation. That is the whole contract.

A translator that emits a primary artifact plus evidence, reports, logs or metrics cannot use it. Configure it that way and Dispatcher will load the first file and silently discard everything else, which looks like success.

Observed live: a translator producing a converted XML plus three coverage and baseline JSON files was registered with a Load binding. It would have stored the XML and thrown away the evidence that was the entire point of the pipeline. The fix was to drop the Load binding and set OutputNeeded="false", letting the translator check in its own artifacts.

Rule of thumb: one file out, let Dispatcher load it. More than one, or any conditional typing, go direct.

Choosing

If the requirement is... Level
Run an existing exe on a dataset, attach the result as one new dataset 0
Same, but the invocation needs real logic, retries, or multi-step orchestration 1
The command line or output filenames must be computed per job 2
The Teamcenter-side extract or load cannot be expressed as "one type in, one type out" 3
Some requests should never run, or should be throttled by a site rule Filter

The honest constraint

None of these levels is hard as code. What eats schedule is environment: getting Scheduler and Module deployed and talking, resolving every CHANGE_ME, proving the Dispatcher Client can obtain FMS tickets so output actually lands on a dataset, and discovering that the service is registered but still isactive="false". Budget accordingly, and see the deployment checklist.

Source: Shipped Dispatcher SDK samples; Dispatcher Deployment and Administration (2506), ch. 7 · retrieved 2026-08-03