Advanced Customization > Services and Infrastructure Customization > Import Export Framework > How to Write an IX Application
  
How to Write an IX Application
The export starts with Export application. The code of the application that invokes export should look as follows:
ExportHandler appHandler = new ExportHandler ();
Exporter exporter = IxbHelper.newExporter(handle,
IxbHelper.STANDARD_DTD,
clientSettingsElement,
policyFile==null?(File)null:policyFile.getFile());

Iterator iter = objectSet.iterator();
while (iter.hasNext()) {
Persistable ob = (Persistable)iter.next();
exporter.doExport(ob);
}
exporter.finalizeExport();
appHandler.cleanUp ();
Create an Application Export Handler (appHandler). This is an instance of a class either implementing ApplicationExportHandler interface or extending the abstract class ApplicationExportHandlerTemplate. In the export application in StandardIXBService, the appHandler extends ApplicationExportHandlerForJar, a subclass of ApplicationExportHandlerTemplate
The job of the appHandler is:
To create a file to store exported objects (e.g. a JAR file).
To store logs to be sent back to the client (optional).
To clean up temporary files and do other clean-up jobs (advised, but optional).
To create, the following methods must be implemented in appHandler:
storeLogMessage(...) methods are used to send logs back to clients. It is up to the developer how to implement the mechanism to send the logs back. If you do not want to send any log messages, make your Export Handler extend ApplicationExportHandlerTemplate. This class has the default storeLogMessage() (empty method).
It is optional to have clean up and other concluding tasks here, and these jobs must be called explicitly after exporter.finalizeExport().
The Application Export Handler may also contain methods to perform tasks of transforming the output if the application needs to modify the exported XML. For example, PDXExportHandler has methods for XSL transformation to PDX format. These methods must be called explicitly after exporter.finalizeExport().
The existing implementations of the Application Export Handler is:
PDXExportHandler extends ApplicationExportHandlerTemplate. This class performs specific tasks connected with export to PDX format. This includes creating additional XML attributes/elements and XSL transformation to PDX format.
Create an instance of the Exporter class, and use it to export objects by calling exporter.doExport(obj), where obj runs through all WT objects collected for export.
After this, call exporter.finalizeExport(), perform any additional tasks (for example, transformation to another format), call methods of appHandler to clean up after the export process, send log messages to client.
The methods doExport(…), doExportImpl(…) and the inner class ExportHandler in StandardIXBService are examples of one export application. Please see the details of the example in Navigating Through an Object’s Structure with ObjectSet Application.
Prerequisite
In order to create the export jar at a client specific location, the following prerequisite needs to be satisfied before calling the doExport api of StandardIXBService:
The context key ISBStreamer.CLIENT_SAVE_AS_FILE needs to be set with the complete client side file path:
WTContext.getContext().put(IXBStreamer.CLIENT_SAVE_AS_FILE,CLIENT
JAR);
Where CLIENT_JAR is the complete client side file path, e.g.c:\\mydocuments\\impex.jar.
Exporter Class
The details of the exporter class are as follows:
Definition:
public class Exporter extends ExpImporter{…};
Constructor:
Exporter (ApplicationExportHandler _applicationExportHandler,
WTContainerRef _sourceContainer,
String targetDTD,
File localMappingRuleFile,
File policyRuleFile,
String actionName)
throws WTException {
super ("export", ( localMappingRuleFile==null?null:
localMappingRuleFile.getAbsolutePath() ));
//assign Container
sourceContainer = _sourceContainer;
// -- init expActionTuner --
applicationExportHandler = _applicationExportHandler;
dtd = targetDTD;

this.expImpContextData = new ExportContextData();

expActionTuner = new ExportActionTuner (policyRuleFile, actionName);
}
An explanation of the arguments follows:
_applicationExportHandler - an instance of any class that either implements the interface ApplicationExportHandler, extends the abstract class ApplicationExportHandlerTemplate or extends the abstract class ApplicationExportHandlerForJar.
The class ApplicationExportHandlerForJar extends the class ApplicationExportHandlerTemplate. The class ApplicationExportHandlerForJar provides methods for storing XML and content files in export jar file. It handles both ApplicationData content and content residing in local file system.
_applicationExportHandler has a job of creating a Jar file (or any other way of storing) of the resulting collection of XML pieces (exported objects). It must implement two methods:
storeContent (ApplicationData);

storeDocument (IxbElement );
sourceContainer: Reference of container.
targetDTD: string that specifies what DTD must be used for export process. The IX framework will find appropriate handlers for objects and Document Type Definition for objects based on this DTD string. The DTD string for Windchill Release 10.X is standard20.dtd.
Generally the intent was to be able to export objects in any DTD. As you will see below the class export handlers are resolved using the DTD identifier. The string targetDTD is also written to the XML file of exported objects, so the import process could know what DTD should be used to import objects.
localMapppingRules: XML file or XSL file that is used to override, change or exclude certain attributes objects when the export process takes place.
The following XML rule file overrides the Team Template attribute, and no matter what team an object belonged to when it was exported, its team template attribute will be “Change Team” in the “/System” domain.
<?xml version="1.0" encoding="UTF-8"?>
<userSettings>
<mappingRules>
<COPY_AS>
<tag>teamIdentity</tag>
<value>*</value>
<newValue>Change Team (/System)</newValue>
</COPY_AS>
</mappingRules>
</userSettings>
The XSL rule file tests if the exported object has the name of “part_c”, it will override the Team Template attribute and version information, and tests if the exported object has the name of “PART_B”, it will override the Team Template attribute.
If you don’t want to override anything, just pass “null” for the argument localMapppingRules.
policyRuleFile: XSL file that is used to override, change or exclude certain attributes objects when the export process takes place.
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="@* | node()" priority="-9">
</xsl:template>
<xsl:template match="WTPart">
<xsl:choose>
<xsl:when test="name='part_c'">
<newInfo>
<teamIdentity>Default (/System)</teamIdentity>
<folderPath>/Design</folderPath>
<versionInfo>
<versionId>B</versionId>
<iterationId>2</iterationId>
<versionLevel>1</versionLevel>
</versionInfo>
</newInfo>
</xsl:when>
<xsl:when test="number='PART_B'">
<newInfo>
<teamIdentity>Default (/System)</teamIdentity>
<folderPath>/Design</folderPath>
</newInfo>
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
For example the policy rule file specifies that check out exported WTPart objects in the database after exporting them. If an exported WTDocument object has the number of “TESTDOC-1”, check it out after exporting it. With all other exported WTDocuments, lock them in the database after exporting them.
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl=http://www.w3.org/1999/XSL/Transform
version="2.0">
<xsl:output method="xml" indent="no" encoding="UTF-8"/>

<!--
The syntax of Export Policy is standard XSL syntax. The output of
XSLT using the XSL policy file
must only have at most one element of the form:

<actionInfo>
<action>...</action>
</actionInfo>
-->

The following is a sample of a well-formed xsl. In the cases, where
there are no specific actions to be performed, nothing needs to be
done, which is the default action that would transpire as shown in
the uncommented section below.
-->

<xsl:template match="@* | node()" priority="-9">
</xsl:template>

<xsl:template match="WTPart">
<actionInfo>
<action>Checkout</action>
</actionInfo>
</xsl:template>

<xsl:template match="WTDocument">
<actionInfo>
<xsl:choose>
<xsl:when test="number='TESTDOC-1">
<action>Checkout</action>
</xsl:when>
<xsl:otherwise>
<action>Lock</action>
</xsl:otherwise>
</xsl:choose>
</actionInfo>
</xsl:template>

-->

<!-- Do nothing by default -->
<xsl:template match="@* | node()" priority="-9">
</xsl:template>

</xsl:stylesheet>
If you don’t want to override anything, just pass “null” for the argument policyRuleFile.
actionName : Action name
An instance of the Exporter must be created via the factory method newExporter() of the class IxbHelper. For example:
IxbHelper.newExporter (…..);
Using the Exporter to Export Objects
After you create an instance of the class Exporter, for example exporter, you can use it to export top-level objects. The call to export the object ‘obj’ would be exporter.doExport(obj);
This is actually making a call to the method doExport (Object obj, String targetDTD, String targetElem) in the class Exporter.
In this method, the real Export handler for the object obj will be created.
* 
A list of available export handlers is created based on XML files in the folder <Windchill>\registry\ixb\handlers. If you pass a wrong DTD in the constructor of Exporter (a DTD that is not available in the system), you will not get the handler, so you cannot export the object. Please refer to How to Write Exp/Imp Handlers for information how to add entry for an Export handler to XML files.
If you have more than one object, you have to pass them to the exporter in a collection.
exporter.doExport(collection)
After you export all objects, you must call exporter.finalizeExport();
You can call clean-up methods of appHandler (if there are any). Now the export is finished.
* 
A sample file with comments is distributed along with installation information.
How Import Works
To import objects from XML files in a jar file, import application must do the following:
1. Create a tool to read the imported jar file and extract the list of XML files that are contained in the jar file. Please see the class IXBJarReader for an implementation example.
2. Prepare the String ruleFileName to be passed into an instance of the class Importer. The String ruleFileName can be obtained from an IxbStreamer, from the user, assigned the value null or obtained from somewhere else, depending on the structure of the import application.
3. Process policyFile (if it is not null) to create an XSL StreamSource that contains the import policy.
4. Create an Application Import Handler appHandler. This is an instance of any class that either implements the interface ApplicationImportHandler or extends the abstract class ApplicationImportHandlerTemplate.
5. Create an instance of the class Importer (importer).
6. Get the list of XML files in the jar file.
7. Create IxbDocuments from those XML files.
8. With each IxbDocument, do the following:
If there is an action name passed to the application and the policyFile is null, apply the action name into the IxbDocument. If the policyFile is not null, apply action name and action information in the policyFile into the IxbDocument.
Feed them to the importer one by one by calling the import process:
importer.doImport(IxbDocument Doc);
importer.finalizeImport();
9. Clean up (if needed).
10. Send log messages to client.
The methods doImport(...), doImportImpl(...) and the inner class ImportHandler in the StandardIXBService are an example of one import application. Please see the Navigating Through an Object’s Structure with ObjectSet Application for details.
Versioned objects can be imported in any of ten different manners decided by action name and action information that are written to the IxbDocument fileXML of each importing object. Developers who write import applications must know about action names and their meanings to apply them correctly, but object handlers don’t have to worry about the Actor classes. A list of all available action names can be found in the file <Windchill>\codebase\registry\ixb\handlers\actor.xml.
All of the actions are different from each other in three crucial methods: previewObject, createObject and storeObject. In the classes ClassExporterImporterTemplate and ExpImpForVersionedObject, based on action name and action information that are passed into the IxbDocument fileXML, appropriate actor will be created and this actor’s methods will be called to serve the purpose of previewing, creating and storing versioned objects.
Here is the list by actor names for information.
1. PickExistingObject : Find if an object with the same ufid or same (name, number, version, iteration) with the object in XML file exists in database. If such an object exists, the framework will update the object if the actor believes the object is candidate for update, or do nothing. Otherwise, import the object in XML file.
2. NewIteration : Import object in XML file as the next available iteration in the database.
For example: If there is no version/iteration in the database for the object which is in the XML file, the imported object will get the version / iteration specified in the XML file. If the latest version / iteration of the object in the database is B.2, the imported object will be B.3.
3. NewVersion : Import objects from the XML file as the next available version in the database.
For example: If there is no version / iteration in the database for the object which is in the XML file, the imported object will get the version / iteration specified in the XML file. If the latest version / iteration of the object in the database is B.2, the imported object will be C.1.
4. CheckOut : Find any version/iteration of the object in the XML file (Check the existence of the master object in the database). If there is no version of the object in the XML file, throw an error. Otherwise, find an instance of the object in the database that has the same version (iteration can be different) as the object in the XML file. If such an object exists, check out the latest iteration of the object in the database, update it with information from the XML file. I agree Otherwise, throw an error. It is now checked in
5. ImportNonVersionedAttr : Find an object with the same ufid or same (name, number, version, iteration) with the object in the XML file. If such an object exists, update it with information from the XML file. Otherwise, throw an error.
6. UpdateInPlace : Find an object with the same ufid or same (name, number, version, iteration) with the object in XML file exists in database. If such an object exists AND it is checked out, update it with information from the XML file. Otherwise, throw an error.
7. UnlockAndIterate : Find an object in the database with the same ufid or same (name, number, version, iteration) as the object in the XML file. If such an object exists AND it is locked, unlock and iterate it, then update it with information from the XML file. Otherwise, throw an error.
8. CreateNewObject : Create a brand new object with new name, new number, new version, new iteration provided in Import Policy file. Other information will be extracted from the XML file. This functionality cannot be used alone.
* 
This option cannot work without a policy file to specify the new object identities.
The format of new information that must be provided in ImportPolicy file is:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

<!--
The syntax of Import Policy is standard XSL syntax. The output of XSLT using
the XSL policy file must only have at most one element of the form:

<actionInfo>
<action>...</action>
</actionInfo>

The following is a sample of a well-formed xsl. In the cases, where there are no specific actions to be performed, nothing needs to be done, which is achieved by the following:
<xsl:template match="@* | node()" priority="-9">
</xsl:template>

-->

<xsl:template match="@* | node()" priority="-9">
</xsl:template>

<xsl:template match='WTPart'>
<actionInfo>
<action>PickExistingObject</action>
</actionInfo>
</xsl:template>

<xsl:template match='WTDocument'>
<actionInfo>
<action>PickExistingObject</action>
</actionInfo>
</xsl:template>

<xsl:template match='EPMDocument'>
<actionInfo>
<action>PickExistingObject</action>
</actionInfo>
</xsl:template>

</xsl:stylesheet>
* 
<actionInfo> must always exist.
Criteria can be any valid attribute of the object in XML file.
Between <xsl:choose>, there can be many <xsl: when test ....> with different criteria and different action names.
Only CreateNewObject and SubstituteObject can have action params, and there are only four action params <newName>, <newNumber>, <newVersion>, <newIteration>, all of them must be provided.
SubstituteObject: Substitute the object in the XML file for an object in the database that has the name, number, version, and iteration provided in the ImportPolicy file. If such an object doesn't exist, throw an exception. Format of tag and params for this case is exactly the same with CreateNewObject, but the <action> is SubstituteObject.
Ignore: Do not import the object in the XML file. This action doesn't require any actor.
Importer class
Definition: public class Importer extends ExpImporter
Constructor:
Importer ( ApplicationImportHandler _applicationImportHandler,
WTContainerRef _targetContainer,
String _dtd,
String _ruleFileName,
String _xslPolicyFileName,
String _containerMappingFileName,
String _actorName,
Boolean _overrideConflicts,
Boolean _validate

) throws WTException
Parameters explanation:
applicationImportHandler: an instance of a class that either implements the interface ApplicationImportHandler or extends the abstract class ApplicationImportHandlerTemplate
applicationImportHandler has a job of extracting from the Jar file that stores XML, and its class must implement two methods:
getContentAsInputStream (String contentId);
getContentAsApplicationData (String contentId);
The later method may always return null to indicate that the file does not exist in the Windchill DB.
* 
Please see the ApplicationExportHandlerForJar for an example of implementation of an application import handler.
targetContainer: Container where objects have to be imported 
targetDTD: string that specifies what DTD must be used for import process. The IX framework will find appropriate handlers for objects and Document Type Definition for objects based on this DTD string if the imported file does not specify any. The DTD string used in Windchill Release 10.X is standardX20.dtd.
ruleFileName: Mapping rule file can be XML file (like in previous versions) or XSL file, so this parameter is String. The constructor that uses IxbElement _localMappingRules is deprecated. In the case you do not have mapping rule file and want to put it to null, please do not put the “null” value directly in the constructor, because it will cause one ambiguous reference error. Instead of doing that, you should use a string, assign null value to it, and pass it as ruleFileName. Mapping rule file is used to change, override or exclude certain attributes objects when the import process takes place.
For example, the rule file overrides the Team Template attribute, and no matter what team an object belonged to when it was exported, its team template attribute is replaced by “Change” in the “/System” Domain on import.
<?xml version="1.0" encoding="UTF-8"?>
<userSettings>
<mappingRules>
<COPY_AS>
<tag>teamIdentity</tag>
<value>*</value>
<newValue>Change Team (/System)</newValue>
</COPY_AS>
</mappingRules>
</userSettings>
An example for XSL mapping rule file:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="WTPart">
<xsl:choose>
<xsl:when test="name='part_c'">
<newInfo>
<teamIdentity>Default (/System)</teamIdentity>
<folderPath>/Design</folderPath>
<versionInfo>
<versionId>B</versionId>
<iterationId>2</iterationId>
<versionLevel>1</versionLevel>
</versionInfo>
</newInfo>
</xsl:when>
<xsl:when test="number='PART_B'">
<newInfo>
<teamIdentity>Default (/System)</teamIdentity>
<folderPath>/Design<folderPath>
</newInfo>
</xsl:when>
<xsl:otherwise>

</xsl:otherwise>
</xsl:choose>

</xsl:template>
</xsl:stylesheet>
This XSL file says that whenever the import process meet a WTPart named part_c, then change its team identity template to Default (/System), change its folder part to /Design, and change its version to B.2, whenever the import process meet a WTPart with the number PART_B, then change its team identity template to Default (/System), change its folder part to /Design
If you don’t want to override anything, just pass “null” for the argument localMapppingRules.
_xslPolicyFileName : Policy file name
_containerMappingFileName : Container mapping file name Sample container mapping file is shown below:
<?xml version="1.0" encoding="UTF-8"?>
<container-info>
<container>
<source-container>/wt.inf.container.OrgContainer=
Demo Organization/wt.pdmlink.PDMLinkProduct=
DemoSourceProduct</source-container>
<target-container>/wt.inf.container.OrgContainer=
Demo Organization/wt.pdmlink.PDMLinkProduct=
DemoTargetProduct</target-container>
</container>
</container-info>
_actorName : Name of actor to be used
 _overrideConflicts: boolean value specifies whether the import process should override “overridable” conflicts.
_validate: boolean value specifies whether the import process should validate the XML file of the imported object against the DTD.
An instance of the class Importer must be created via the method newImporter() of the class IxbHelper. For example:
Importer importer = IxbHelper.newImporter(…);
Use Importer to import object from XML files
After you create an instance of the class Importer (importer) you can use it to import objects from XML files. If you have more than one XML files to import, you have to give IxbDocument-s that created from XML files to the importer one by one.
As mentioned above, the Import Application server must call two methods to do the import:
importer.doImport(IxbDocument doc);

importer.finalizeImport();
doImport (doc) : This method doesn’t really import the object, but inserts the XML document that represents the object in to a list to be imported later. After all XML documents representing all the imported objects are inserted in the import list, the real import process starts with the call to finalizeImport().
finalizeImport(): The import process is actually performed in this method. It will call to:
doCheckConflicts() - check conflicts for imported objects.
doRealImport () - do the real import for the list of objects by calling importElement (IxbElement doc) for each XML document representing each object in the list.
ImportElement(...) calls importElements(...) : In the method importElements(…) the import handler for a particular type of the object is created by calling getImportHandler(tag).
The method getImportHandler(…) finds the appropriate handler for the importing object as follows.
1. Try to get an import handler by using the DTD string in the <dtd> tag of the XML file of the imported object.
2. If the handler is null, try again using current DTD in the importer. This current DTD is calculated using version of the current Windchill. For Windchill Release 10.X it is standardX20.dtd.
After getting the handler for the element, the importElements(…) calls the following methods:
handler.importElements(…) to do the import task.

handler.outputLog(…) to send log to user.
All handlers for non-versioned objects (for example ReportTemplate ... ) extend the class ClassExporterImporterTemplate, all handlers for link objects (for example, PartUsageLink...) extend the class ExpImpForLinkObject, and and all handlers for versioned objects (for example Parts, Documents, EPMDocuments ...) extend the class ExpImpForVersionedObject.
* 
Handlers for non-versioned objects act like the previous versions.
If the real handler doesn’t implement the method importElements(…), then the call invokes the default method importElements(…) of the class ClassExporterImporterTemplate. In this class, the importElement(…) method calls to findAmongExistingObjects (elements, importer);.
If it finds that the object in the XML file currently exists in the database, it will not import the object. Otherwise, it will call the following methods:
createObjects ( elements, importer);
importObjectsAttributes (elements, importer);
storeObjects (elements, importer);
importObjectsAttributesAfterStore (elements, importer);
finalizeImprtObjects(isNewObject, elements, importer);
Some of these methods should be implemented in the handler, and it is how and when the real handler comes to do its job.
* 
Handlers for versioned objects act different.
If the real handler doesn’t implement the method importElements(…), then the call invokes the default method importElements(…) of the class ExpImpForVersionedObject. In this class, despite the object in the XML file exists in the database or not, the importElements(…) method always calls to:
createObject (elements, importer);
importObjectsAttributes (elements,
importer);
storeObjects (List<ElementObjectPair> pairs, importer);
importObjectsAttributesAfterStore (List<ElementObjectPair> pairs,
importer);
Then, the Import Application can do a clean-up, and send messages to the client. The import process is finished.