Build
Overview
Building an extension differs from a typically Windchill customization build, the primary difference being that the build is not done on a Windchill server. Instead of that, a standard Maven build is used, which is connected to an online repository provided by Wincom; this makes the whole process Windchill-independent, which means that the developer doesn't need a Windchill server in their machine to develop Windchill Extensions. During the build all required assets are downloaded automatically.
Building a Windchill Extension
Getting started
A quick and easy way to learn the build process is to access the Example 1 - Hello World section of this guide, located in the Developer Examples section, which provides the reader with information about the building and deploying of Windchill Extensions.
Configuration
Wincom provides extensions which the developer can use as dependencies in their projects; they are available on this online repository.
You must have create an account here
and once you have one generate, save and download your settings.xml
and place it in you {user-home}/.m2
folder
Please note that it may take several minutes for this to become active.
After that, every time the developer builds an extension which needs dependencies from the online repository, Maven will automatically download them from it and store them in their m2 folder for future usage.
Please note Wincom does not store the login information as this is managed by Microsoft
Creating a new project using an Archetype
You can create a blank project using an archetype (a type of template)
You can now build this for your version of Windchill
The resulting extension will appear in the targets folder
Troubleshooting
In certain networks, the access to the nexus.wex.solution server may be restricted and the server is not available during build even if the server can be reached via a browser, throwing an error like the one seen below:
In that case, please look at how to setup Maven for a proxy.
Creating a new commons using an Archetype
A commons is a shared java library that contains only Java code. It cannot be annotated but may call the kernel e.g. wex invoke. It is managed as a version controlled entity including the winchill version it supports. They are held in the repo, as is the archetype. and can be referenced in the pom
The archetype is called wex-archetype-commons
Archetype Generation Command
This command is used to create a new empty shell of an extension:
mvn archetype:generate
-DarchetypeGroupId=<archetype-groupId>
-DarchetypeArtifactId=<archetype-artifactId>
-DarchetypeVersion=<archetype-version>
-DgroupId=<my.groupid>
-DartifactId=<my-artifactId>
-Dpackage=com.wincomplm.wex.<artifactId>
As in the following example:
mvn archetype:generate -DarchetypeGroupId=com.wincomplm -DarchetypeArtifactId=wex-archetype -DarchetypeVersion=1.1 -DgroupId=com.mycompany -DartifactId=wex-myproject -Dversion=1.0b1 -Dpackage=com.mycompany.wex.mytest.project
It is good practice to use this archetype as a starting point when developing Windchill Extensions.
Building in an IDE
All modern Java IDEs support Apache Maven, and the extensions can be build within the IDE as normal.
Apache NetBeans Example
Eclipse Example
Example Build
Build Architecture
POM
The Maven build uses the pom.xml
to build the Java code. The pom file has the following sections:
Parent
<parent>
<groupId>com.wincomplm</groupId>
<artifactId>wex-parent</artifactId>
<version>x.x</version>
</parent>
The parent tells Maven how to build the project and to include all the plugins required to build the extensions, while providing the child entity with a set of versions for matching with the extension's dependencies during the building process. A higher version of the parent will mean a more recent version of the dependencies listed in the pom will be included in the build.
Properties
<properties>
<major>1</major>
<minor>0</minor>
<beta>1</beta>
<revision>${major}.${minor}-${wex.wt}</revision>
</properties>
This section holds the versions that are used to populate both the final .wex file and the information held in the definition.xml file, which is used by the platform to identify the extension's version.
Identity Block
<groupId>com.acme</groupId>
<artifactId>wex-helloworld</artifactId>
<version>${revision}</version>
A Windchill Extension is uniquely identified by two parameters: the groupId
and the artifactId
. These are combined to form a unique wexId
that is used in the platform to uniquely identify a WEX. The artifactId
field should match your organization.
Dependencies
<dependencies>
<dependency>
<groupId>com.ptc</groupId>
<artifactId>windchill-pdmlink</artifactId>
</dependency>
<dependency>
<groupId>com.wincomplm</groupId>
<artifactId>wex-kernel</artifactId>
</dependency>
<dependency>
<groupId>com.wincomplm</groupId>
<artifactId>wex-system</artifactId>
</dependency>
<dependency>
<groupId>com.wincomplm</groupId>
<artifactId>wt-framework-commons</artifactId>
<version>1.3-${wex.wt}</version>
</dependency>
<dependency>
<groupId>groovy</groupId>
<artifactId>groovy-xmlrpc</artifactId>
<version>0.3</version>
</dependency>
</dependencies>
This section lists all of the dependencies that Maven will collect when building the Windchill Extensions. There are some mandatory entries when building a WEX: windchill-pdmlink, wex-kernel and wex-system always need to be in this list.
Those three cases are a good example of provided dependencies: they are anticipated to be available on the target system so they are not placed in the extension's own codebase and they can be identified and declared as such with the <scope>provided</scope>
tag. In the case of a commons WEX, however, that would not be the desired behavior, as we don't want them to act as a shared library: a unique copy of it must be placed in the extension. The absence of the <scope>provided</scope>
tag will include the JAR file in the final build's own codebase, which will make it not visible to Windchill, thus preserving isolation.
A 3rd party open source library may be included as a dependency: again, this will be placed in the extension's isolated class path, meaning we can have extensions that use different version of the same library deployed in the same Windchill system. Since the system uses a standard Maven build, we can also include our own plugins and specialized build tools.
WEX Definition File
In addition to the POM file, each extension has a definition.xml
file which is stored in the following path:
src/main/wex/meta/definition.xml
The purpose of this file is to identify the extension and to give the deployment mechanism the necessary information on how to install the WEX. It also contains information added by the signing process. It's good practice to define values such as the version number, groupId and artifactId in the pom.xml
file and then reuse them in this one. The definition.xml
file is composed by the following blocks:
Meta
<meta>
<group-id>${groupId}</group-id>
<artifact-id>${artifactId}</artifact-id>
<display-name>Hello World</display-name>
<system>false</system>
<description>Hello to the world</description>
</meta>
The values in this block are used by the Extension Manager to display the extension's metadata. The system
field is a noteworthy one, since it defines whether the extension is a system one or not: it should be kept as false
except for very particular cases.
Important: Wincom will not support any system malfunctions generated by a misuse of this tag.
Build
<build>
<version>
<major>${major}</major>
<minor>${minor}</minor>
<beta>${beta}</beta>
</version>
<host>
<release>${wex.wt}</release>
</host>
</build>
This block defines the release version and target host's version (e.g. 12.1). The beta field is optional, and will be ignored if not included in the version
tag in the POM file.
All the tags are mandatory in file, but beta may be blank.
Install
<install>
<menus>
<extension menu="more parts actions" file="PartClient-actionmodels" action="edkHelloWorld"/>
<extension menu="header actions" file="navigation-actionModels" action="edkHelloWorldNonPop"/>
</menus>
<actions>
<wizard name="edkHelloWorld" url="edkHelloWorld.jsp" shortcut="false"/>
<page name="edkHelloWorldNonPop" url="edkHelloWorld.jsp"/>
</actions>
</install>
This block is used to instruct the Extension Manager how to install the extension and what modifications it needs to make to the Windchill system to, for example, add menu entries.
Client
This block can exist or maybe added by the signing service. Note that free signing is allowed but will only sign the extension as a trial
<additional>
<trial>false</trial>
<timestamp>1710972501640</timestamp>
<expires>0</expires>
<client-id>604566</client-id>
<client-name>Acme SL</client-name>
<user-id>simonh@wincom-consulting.com</user-id>
</additional>
The information in this block will appear in the manager. The client id and user id will not be shown
WEX File Structure
The result of a successful build process for an extension is a .wex
file that is in ZIP format and presents the following structure:
groupId
--- artifactId
------- bootstrap.xml => Scope information
------- codebase
-------------- JAR files used for the isolated classloader
------- docs
------- meta
-------------- definition.xml => Definition of the extension
------- windchill
From a build point of view, the following are the most relevant files and folders:
bootstrap.xml
This file is generated during the build and its purpose is to manage which files are allowed in the codebase. This is used on startup to remove any unauthorized files and ensure the signing is not violated by old JAR files from previous releases being present.
It also includes elements that are used by the kernel to construct the cascading class loading. In broad terms, it holds the statically (classpath tag) and dynamically (required tag) used elements. An example of it would look like the one below:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<bootstrap>
<uid>com.wincomplm.wex-report-designer</uid>
<service>com.wincomplm.wex.report.designer.impl.bootstrap.WexBootstrap</service>
<classpath>
<element>codebase/wex-config-aux-1.1-11.1.jar</element>
<element>codebase/wt-ui-commons-1.2-11.1.jar</element>
<element>codebase/wt-query-builder-commons-1.0-11.1.jar</element>
<element>codebase/unbescape-1.1.6.RELEASE.jar</element>
<element>codebase/wt-security-commons-1.1-11.1.jar</element>
<element>codebase/wex-store-commons-1.0-11.1.jar</element>
<element>codebase/wt-framework-commons-1.3-11.1.jar</element>
<element>codebase/wex-bo-info-commons-1.1-11.1.jar</element>
<element>codebase/wex-core-aux-1.0-11.1.jar</element>
<element>codebase/wt-appdata-commons-1.4-11.1.jar</element>
<element>codebase/wt-dataprovider-commons-1.4-11.1.jar</element>
<element>codebase/pdfbox-2.0.23.jar</element>
<element>codebase/thymeleaf-3.0.11.RELEASE.jar</element>
<element>codebase/groovy-3.0.7.jar</element>
<element>codebase/wex-report-commons-1.1-11.1.jar</element>
<element>codebase/boxable-1.5.jar</element>
<element>codebase/ognl-3.1.12.jar</element>
<element>codebase/fontbox-2.0.23.jar</element>
<element>codebase/gson-2.8.5.jar</element>
<element>codebase/attoparser-2.0.5.RELEASE.jar</element>
<element>codebase/commons-text-1.9.jar</element>
<element>codebase/wex-report-designer.jar</element>
</classpath>
<required>
<uid>com.wincomplm.wex-log</uid>
<uid>com.wincomplm.wex-system</uid>
<uid>com.wincomplm.wex-store</uid>
<uid>com.wincomplm.wex-wt-framework</uid>
<uid>com.wincomplm.wex-config</uid>
<uid>com.wincomplm.wex-core</uid>
</required>
</bootstrap>
codebase
In this folder are the files that will be loading into the class loader (not cascaded) using the bootstrap.xml
file as the source of truth (the files themselves are not used as the source of truth for security reasons).
windchill
All files in this folder will be transferred on deploy to Windchill home. They should not replace any existing file as they will be removed if the extension is undeployed.
Maven Tools
Build Options
The developer may wish to control the options of the extension build to improve performance and adjust the build to, for example, prevent obfuscation in order to assist with debugging. This can be achieved through the passing of options to the compiler.
Following are some common options:
Name | Default | Description |
---|---|---|
cve.check.skip | false | Prevent security checks on dependencies. |
wex.sign | true | Signs the extension |
obfuscate | false | Obfuscate code (requires the obfuscation build module). |
wex.sign.service.url | false | Use alternative signing service. |
windchill.api.disable | false | Disable api scan (WVE/SCA) |
windchill.api.skip | false | Prevents build stopping for WVE or SCA errors |
windchill.api.approved | List of approved dependencies | |
wex.security.wvedb | Wincom's own db | Specify a .json file with WVE Security Levels which will determine what Security Level the WEX is on build. |
wex.security.wveadb | Wincom's own db | Specify a .json file with WVE Approvals for Extensions. |
wex.security.scaadb | Wincom's own db | Specify a .json file with dependency (CVE) approvals for Extensions. |
complexity.limit | 8 | Default cyclomatic complexity limit |
In Apache NetBeans these parameters can be inputted in Tools > Options > Java > Maven
as seen in the screenshot below:
Cyclomatic Complexity
By using the wex-parent you will ensure your code does not exceed complexity limits, you should be keeping methods under the magic number which is important for code quality but also for security. Read here for more details on complexity
If your code has issues but you do not want to alter it (often a wise choice if the code is already being used) you may add a custom limit (wex-parent 2.46 and above)
-Dcomplexity.limit=20
Dependencies
Maven will collect and manage dependencies. The latest Wincom build tool from wex-builder 1.6
will check for any inconsistencies and automatically add all required 3rd party dependencies into the WEX from any dependent library.
We can check the generated WEX's codebase in order to make sure it included all libraries that were declared in our pom.xml
file.
If different versions of the same library are included by different dependencies, an error will be thrown and the build process will be stopped with a failure. It is crucial that, despite the fact that different Windchill Extensions are able to use different versions of the same library when deployed in one system due to the platform's isolation design principles, no two different versions of the same library can be at the same time in one WEX. In other words, no two versions of the same library can be placed in one codebase.
We can use the dependency:tree
option to find the source of the problem when facing errors like this one, and adjust the versions to allow a correct build to happen:
In wex-parent 2.42 onwards you can define your own wve and sca approvals .json file to manage your approved dependencies and WVE's. If there is a CVE that you determine does not have an attack surface you can add the approval to the specified .json file.
An example of a WVE Approval is:
[
{
"id": "com.wincomplm.wex-example-security",
"rules": ["WVE-2022-0204","WVE-2022-0101","WVE-2022-0201","WVE-2022-0202","WVE-2022-0301","WVE-2022-0401","WVE-2022-0402","WVE-2022-0403","WVE-2022-0501","WVE-2022-0501"],
"falsePositives": ["WVE-2022-0301"]
}
]
An example of a sca approval is:
[
{
"groupId": "com.wincomplm",
"artifactId": "*",
"versions": ["*"]
}
]
If you would like to skip this process use the api.skip and api.approved shown above in Build Options.
Development Mode in Tomcat
In Windchill, Java Server Pages are cached by Tomcat. This means that, if you deploy the same page with the same name, then the page will not be recompiled. By adding the following change in Tomcat, the page will be reloaded if the timestamps changes.
From Windchill 11 onwards the system will recompile the JSP if the Method Server is restarted.
Edit this file:
%WT_HOME%\tomcat\conf\web.xml
and adjust this parameter:
<init-param>
<param-name>development</param-name>
<param-value>true</param-value>
</init-param>
After that, restart your system.
Adding External JAR Files
In order to import a file into your build, follow these steps:
-
Jar all the classes that you want to include (a Maven repository is just a jar of classes).
-
Add the jar into your local Maven using the following command:
mvn install:install-file -Dfile=<path-to-file> -DgroupId=<groupid> -DartifactId=<DartifactId>
For example:
mvn install:install-file –Dfile=windmod.jar -DgroupId=com.ptc -DartifactId=mywindchillmod -Dversion=12.0.2
- Now, add the dependency to your Maven project by adding these lines to your
pom.xml
file:
<dependency>
<groupId>com.ptc</groupId>
<artifactId>mywindchillmod</artifactId>
<version>12.0.2</version>
</dependency>