26 April 2021

1. Goals

The goal with this tutorial is to understand the create/update integration and how you could import a structure of Parts with attached Specifications having files.

We will see how the create-update integration can use ZIP files as input. The create/update integration will in this tutorial be invoked via a directory listener, but could easily have been supported via a REST call.

2. ZIP file content

The input ZIP file is assumed to follow this structure:

data.zip
├───data.xml
│
└───files
    ├───08b3608d-171c-439e-b233-100892036096
    │   └───generic
    │       └───Specification.pdf
    │
    └───889f20cd-8a7e-4855-9e3e-f137813e9d9d
        └───generic
            ├───drawing-001.pdf
            ├───drawing-002.pdf
            └───mounting-instructions.docx

On the root level, there is a data.xml file that contains the meta-data for the objects and the connections between them.

The files folder holds the files. In this case, each document have its own UUID and this is used to group the files together with the file format.

Note that the structure does not have to follow this format, this is just an example. If you for example dont know what format the files uses in 3DExperience/ENOVIA then you probably will leave that directory out.

3. The data file format

The data.xml file describes the meta-data of the objects and the relationships between these.

For this tutorial the data format as shown in the example below. It contains the Item’s along with their Specification and the structure.

<PackageData>
    <Items>
        <Item>
            <Id>496693e2-8818-473a-b240-1ae6e5e4b091</Id>
            <Type>Part</Type>
            <Name>ASY-JG1</Name>
            <Revision>A</Revision>
            <Description>ASY-JG1</Description>
            <Status>Create</Status>
            <Weight>0.0</Weight>
            <DesignPurchase>Make</DesignPurchase>
        </Item>
        <Item>
            <Id>2cfc41e6-b0e1-4ee8-bfb6-6ef366f543d1</Id>
            <Type>Part</Type>
            <Name>THW-AHG-00011</Name>
            <Revision>A</Revision>
            <Description></Description>
            <Status>Create</Status>
            <Weight>520.0</Weight>
            <DesignPurchase>Make</DesignPurchase>
        </Item>
        <Item>
            <Id>889c9be0-f5e9-4327-b748-01db0b3c4bdf</Id>
            <Type>Part</Type>
            <Name>THW-YHG-69103</Name>
            <Revision>A</Revision>
            <Description></Description>
            <Status>Create</Status>
            <Weight>40.0</Weight>
            <DesignPurchase>Make</DesignPurchase>
            <Specifications> (1)
                <Specification id="889f20cd-8a7e-4855-9e3e-f137813e9d9d" />
                <Specification id="08b3608d-171c-439e-b233-100892036096" />
            </Specifications>
        </Item>
    </Items>

    <Structure>
        <Item id="496693e2-8818-473a-b240-1ae6e5e4b091"> (2)
            <Item id="2cfc41e6-b0e1-4ee8-bfb6-6ef366f543d1" pos="1" qty="1" />
            <Item id="889c9be0-f5e9-4327-b748-01db0b3c4bdf" pos="2" qty="10" />
        </Item>
    </Structure>

    <Specifications>
        <Specification>
            <Id>889f20cd-8a7e-4855-9e3e-f137813e9d9d</Id>
            <Type>Functional Specification</Type>
            <Name>SX-01-339-X-AS</Name>
            <Revision>A</Revision>
            <Title>Lorem ipsum</Title>
            <Description>Foo bar</Description>
        </Specification>
        <Specification>
            <Id>08b3608d-171c-439e-b233-100892036096</Id>
            <Type>Functional Specification</Type>
            <Name>Z98-77X89-A</Name>
            <Revision>A</Revision>
            <Title>Z98-77X89-A</Title>
            <Description>....</Description>
        </Specification>
    </Specifications>
</PackageData>
1 Item references its specifications by a UUID
2 Bill of materials structure defines the items only based upon their UUIDs.

NOTE:

  • The specifications must be created prior to processing the items.

  • The items must be created before creating the connections between them.

4. The Create/Update configuration

On the TIF server we need to create our create/update configuration that defines how to create/update the business objects and connections in the 3DExperience/ENOVIA database, according to the input format.

In our case, the configuration will look like this:

${TIF_ROOT}/modules/enovia/cfg/createconfig/BOMPackageImport.xml
<CreateConfiguration
    txType="update"
    runPrivileged="true"
    historyOff="true"
    triggerOff="true">

    <InputFormats>
        <Zip>
            <InputFiles>data.xml</InputFiles> (1)
        </Zip>
    </InputFormats>

    <EntryPoint
        select="/PackageData/Specifications/Specification"
        mode="create-documents" /> (2)

    <EntryPoint
        select="/PackageData/Items/Item"
        mode="create-objects" /> (3)

    <EntryPoint
        select="/PackageData/Structure/Item"
        mode="bill-of-materials" /> (4)

    <ValueMapper id="design-purchase-mapping"> (5)
        <If is="Buy">Purchase</If>
        <If is="Make">Design</If>
    </ValueMapper>

    <!--+
        | This configuration is used when to create or update
        | all the specifications including checking in all files
        | part of the ZIP file.
        +-->
    <Config match="Specification" mode="create-documents"> (6)
        <IfFound>update</IfFound>
        <IfNotFound>create</IfNotFound>
        <IdentityMatch>
            <Type select="Type/text()" />
            <Name select="Name/text()" />
            <Revision select="Revision/text()"/>
        </IdentityMatch>
        <CreateValues>
            <Policy fallbackValue="policy_Specification"/>
            <Vault fallbackValue="vault_eServiceProduction" />
        </CreateValues>
        <UpdateValues useForCreate="true">
			<Description select="Description/text()"/>
			<Attribute name="attribute_Title" select="Title/text()"/>
        </UpdateValues>
        <EmbeddedFiles>
            <File reuseVersion="true"
                  formatFallback="generic"
                  useFileMapper="true"> (7)
                <FileMapper>
                    <PathItem value="files" />
                    <PathItem select="Id/text()" />
                    <PathItem mapsToFormat="true" />
                </FileMapper>
            </File>
        </EmbeddedFiles>
    </Config>

    <Config match="Item" mode="create-objects"> (8)
        <IfFound>update</IfFound>
        <IfNotFound>create</IfNotFound>
        <IdentityMatch>
            <Type select="Type/text()" />
            <Name select="Name/text()" />
            <Revision select="Revision/text()"/>
        </IdentityMatch>
        <CreateValues>
            <Policy fallbackValue="policy_DevelopmentPart"/>
            <Vault fallbackValue="vault_eServiceProduction" />
        </CreateValues>
		<UpdateValues useForCreate="true">
			<Description select="Description/text()"/>
			<Attribute name="attribute_Weight" select="Weight/text()"/>
            <Attribute
                name="attribute_DesignPurchase"
                valueMapper="design-purchase-mapping"
                select="DesignPurchase/text()"/>
		</UpdateValues>
        <Connections>
            <Connection relationship="relationship_ReferenceDocument"
                        select="Specifications/Specification"
                        mode="connect-specifications"
                        disconnectExisting="false"> (9)
                <IdentityMatch>
                    <Object>
                        <Name select="/PackageData/Specifications/Specification[./Id/text() = current()/@id]/Name/text()" />
                    </Object>
                </IdentityMatch>
            </Connection>
        </Connections>
    </Config>

    <!--+
        | This configuration is used when to find a specifications
        | to connect with in the context when creating items.
        +-->
    <Config match="Specification" mode="connect-specifications"> (10)
        <IfFound>ignore</IfFound>
        <IfNotFound>fail</IfNotFound>
        <IdentityMatch> (11)
            <Type select="/PackageData/Specifications/Specification[./Id/text() = current()/@id]/Type/text()" />
            <Name select="/PackageData/Specifications/Specification[./Id/text() = current()/@id]/Name/text()" />
            <Revision select="/PackageData/Specifications/Specification[./Id/text() = current()/@id]/Revision/text()" />
        </IdentityMatch>
    </Config>

    <Config match="Item" mode="bill-of-materials"> (12)
        <IfFound>update</IfFound>
        <IfNotFound>fail</IfNotFound>
        <IdentityMatch> (13)
            <Type select="/PackageData/Items/Item[./Id/text() = current()/@id]/Type/text()" />
            <Name select="/PackageData/Items/Item[./Id/text() = current()/@id]/Name/text()" />
            <Revision select="/PackageData/Items/Item[./Id/text() = current()/@id]/Revision/text()" />
        </IdentityMatch>
        <Connections>
            <Connection relationship="relationship_EBOM"
                        select="Item"
                        mode="bill-of-materials"
                        disconnectExisting="false"> (14)
                <IdentityMatch>
                    <Relationship>
                        <Attribute name="attribute_FindNumber" select="@pos"/>
                    </Relationship>
                </IdentityMatch>
                <UpdateValues>
                    <Attribute name="attribute_Quantity" select="@qty" />
                </UpdateValues>
            </Connection>
        </Connections>
    </Config>
</CreateConfiguration>
1 Specify that we will read the data from a ZIP file, and the data files are named data.xml in the root level.
2 We need to create the documents first, and this entry point specifies the elements to process and in what mode. It will be mapped to the corresponding <Config> element defined later.
3 Specifies the items to be processed
4 Specifies the item structure (bill of materials) to be processed
5 Inlined value mapping to translate values from the incoming data into 3DExperience accepted values.
6 Configuration used for creating or updating the documents.
7 File checkin configuration. Here we specify that we will map the files from the incoming ZIP archive into the object, and we use the UUID identifier on the object to map the folder. The last folder defines the format of the file.
8 Configuration used for creating or updating the items
9 Specifies how to connect the specifications and how we identify the Specification object.
10 The configuration used when to connect the item with the specification. This configuration is only used to actually find the object in the database, hence only the identity match is defined, and we expect the object to actually exist otherwise it is a failure.
11 In the incoming XML data we only have a UUID reference to the specification, hence we need to use an XPath construct that allows us to find the actual Specification element holding the database identifiers.
12 The configuration used when creating the bill of materials structure.
13 Since the information in the XML data only specifies the UUID identifiers, we need to lookup the actual items by using slightly more complicated XPath constructs.
14 The connect specification for EBOM relationships uses the Find Number mapped to the pos attribute to identifying relationships

Key takeaways:

  • In case you process elements with the same but with different purposes, then use the "mode" setting to distinguish the different configurations.

5. The directory listener

Finally, in order to be able to use the file package import utility, we need to setup the directory listener.

We want to allow someone to drop a ZIP package into the directory /mnt/bom-package/in.

In the file ${TIF_ROOT}/modules/enovia/cfg/directorylistener/BOMPackageImport.xml add this

${TIF_ROOT}/modules/enovia/cfg/directorylistener/BOMPackageImport.xml
<tif:DirectoryListener
    xmlns:tif="http://technia.com/TIF/DirectoryListener"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://technia.com/TIF/DirectoryListener http://products.technia.com/tif/schema/latest/DirectoryListener.xsd">

    <tif:Name>Import BOM Package via File</tif:Name>
    <tif:WithContext user="IntegrationAgent" /> (1)
    <tif:Paths>
        <tif:Input>/mnt/bom-package/in</tif:Input> (2)
        <tif:Output>/mnt/bom-package/out</tif:Output>
        <tif:Error>/mnt/bom-package/err</tif:Error>
    </tif:Paths>
    <tif:Handler type="CreateUpdateIntegration" /> (3)
    <tif:Arguments>
        <tif:Argument name="configuration" value="tvc:createconfig/BOMPackageImport.xml" /> (4)
    </tif:Arguments>
</tif:DirectoryListener>
1 Specify what user to run DB calls in 3DExperience as
2 Configure input directory
3 Specify that we are using the CreateUpdateIntegration handler
4 As argument, we need to provide the create update configuration and we point out the previous config we made

The directory listener will after processing create a file with the same name as your input file, in the configured output directory, containing the result of the operation.

If any error happens, a file with the same name as the input file will be created in the error directory, containing error information.