Example 11: REST Interface
This example illustrates how to add a REST interface to our WEX using the PTC framework.
You can find the code for the example in our GitHub repository.
Introduction
PTC has introduced a REST (Representational State Transfer) interface into Windchill. It is very effective and provides a number of services out-of-the-box. The following example is used to add a new interface to the standard PTC REST one and automate both the deployment and the Java components of the interface.
The PTC documentation describes its REST features here.
Implementation
The implementation of this REST interface is very simple. We are effectively deploying a standard extension and calling it via a WexInvoke
, taking full advantage of the dynamic nature of the WEX Framework. The REST part is dynamic, it's available at the moment of deployment and does not need a server restart.
The extension is extending the standard PTC v3 domain. The standard way to extend the PTC REST service is to add these files:
The implementation is as follows:
function function_HelloWorld(data, params) {
return "Hello World!";
}
function function_HelloWex(data, params) {
var WindchillRequester = Java.type('com.wincomplm.wex.kernel.api.invoke.WexInvoker');
return WindchillRequester.invoke("com.wincomplm.wex-example-rest","wex-example-rest-methods.hello-world",data, params);
}
It declares the Nashorn
JavaScript. In the Hello World
method we simply return a simple string from Javascript, while in the HelloWex
we call the extension.
The JSON code declares these functions to the ODATA REST Framework that is included in Windchill:
{
"functions": [
{
"name": "HelloWorld",
"importName": "HelloWorld",
"description": "Hello to the world",
"parameters":[],
"returnType": {
"type": "String"
}
},
{
"name": "HelloWex",
"importName": "HelloWex",
"description": "Hello to the world from Wex",
"parameters":[],
"returnType": {
"type": "String"
}
}
]
}
The Java code that is in the extension is as follows:
@WexMethod(name = "hello-world", description = "Hello World")
public String helloWorld(Object data, Object params) throws Exception {
logger.trace("=>helloWorld");
String result = "Hello " + SessionHelper.getPrincipal().getName() + " from Wex!";
logger.trace("<=helloWorld " + result);
return result;
}
Execution
The execution is simple: as these are non-complex GET interfaces, they can be called from a browser; otherwise, we would have to test will a REST tool such as Postman.
Hello World Example
Hello WEX Example
Other Implementations
It is not mandatory to use REST interfaces to get data from Windchill to another system. A simple JSP page that uses a WexInvoker.invoke
method can do the trick:
<%@ page trimDirectiveWhitespaces="true" %>
<%@ page import="com.wincomplm.wex.kernel.api.invoke.WexInvoker"%>
<html>
<body style="font-family: Arial, Helvetica, sans-serif;">
<%= (String) WexInvoker.invoke("com.wincomplm.wex-example-rest","wex-example-rest-methods.getModifiedParts", request,response) %>
</html>
This page can also be secured as seen in previous examples. The access to this information is also handled by Windchill's access control.
Below is the getModifiedParts
method that is being invoked. It simply gets modified parts from X days ago (defined in configuration) and returns raw json.
@WexMethod(name = "getModifiedParts", description = "Gets modified parts from x days ago")
public String getModifiedParts(HttpServletRequest request, HttpServletResponse response) throws Exception {
logger.trace("=>getModifiedParts");
String daysAgo = config.getPartsFromDaysAgo();
Calendar today = Calendar.getInstance();
today.add(Calendar.DATE, -Integer.parseInt(daysAgo));
Date fromDaysAgo = today.getTime();
List<WTPart> parts = getModifiedPartsFrom(fromDaysAgo);
List<WexExamplePart> exParts = new ArrayList();
for (WTPart part : parts) {
WexExamplePart exPart = new WexExamplePart();
exPart.setNumber(part.getNumber());
exPart.setOid(WexQueryHelper.getOid(part));
exPart.setVersion(part.getVersionIdentifier().getValue() + "." + part.getIterationIdentifier().getValue());
exParts.add(exPart);
}
Gson gson = new Gson();
String result = gson.toJson(exParts);
logger.trace("<=getModifiedParts");
return result;
}
private List<WTPart> getModifiedPartsFrom(Date from) throws QueryException, WTException {
QuerySpec qs = new QuerySpec(WTPart.class);
qs.appendWhere(new SearchCondition(
WTPart.class,
WTPart.MODIFY_TIMESTAMP,
SearchCondition.GREATER_THAN_OR_EQUAL,
new Timestamp(from.getTime())),
new int[]{0});
QueryResult qr = PersistenceHelper.manager.find(qs);
return WexQueryHelper.getListFromQueryResult(qr);
}
Because the object WTPart is too complex, we need to create a simpler object that represents the data we need. That is what WexExamplePart
is for and is what we send back as JSON:
public class WexExamplePart {
String number;
String oid;
String version;
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getOid() {
return oid;
}
public void setOid(String oid) {
this.oid = oid;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
}
The result when accessing the JSP {hostname}/Windchill/netmarkets/jsp/com/wincomplm/wex/example/rest/getModifiedParts.jsp is the simple JSON: