javax.xml.bind.DatatypeConverter.printBase64Binary
because that API is not available on Android. It now uses commons-codec to get base64 support.The Maximo REST client library provides a set of driver APIs that can be consumed by a Java-based web component that wants to interface with a Maximo instance. The client APIs use the Maximo NextGen REST/JSON APIS, which were originally inspired by Linked Data principles. By using this API, you are able to create, update, delete, and query Maximo business objects by using Maximo integration framework object structures.
The following main components are included in this client library:
[MaximoConnector (com.ibm.maximo.oslc.MaximoConnector)] - The driver API that establishes the authenticated HTTP session with the Maximo server. It is used by the other APIs to create, update, delete, and query Maximo data. The authentication and the other basic information can be configured using an [Options (com.ibm.maximo.oslc.Options)] object.
[ResourceSet (com.ibm.maximo.oslc.ResourceSet)] - This API represents a collection of Maximo resources of a given type. The type is determined by the object structure definition that it refers to. In effect, this api is equivalent to the concept of the Maximo MboSet.
[Resource (com.ibm.maximo.oslc.Resource)] - Each member of a ResourceSet is represented by an instance of this class. This class is equivalent to the concept of a Maximo business object (MBO).
[Attachment (com.ibm.maximo.oslc.Attachment)] and [AttachmentSet (com.ibm.maximo.oslc.AttachmentSet)] - These APIs represent the attached documents, or doclinks, in Maximo Asset Management. These APIs are always associated with a Resource object.
Currently the only supported data format is JSON, and we have two flavors of JSON: the lean and the namespaced. The lean format is supported starting in Maximo Asset Management version 7.6.0.1 and is the recommended format to use, because it uses less bandwidth.
Maximo REST Client is available in the Maven Central repository as an open source artifact. It can be included in a Maven project easily by adding the dependency to the project. The Maven will automatically handle the maven transitive dependencies.
Latest Release
<dependency>
<groupId>com.ibm.maximo</groupId>
<artifactId>maximo-restclient</artifactId>
<version>1.0</version>
</dependency>
Last Release
<dependency>
<groupId>com.ibm.maximo</groupId>
<artifactId>maximo-restclient</artifactId>
<version>0.1</version>
</dependency>
You can use a local repository if the Internet is unavailable or it is difficult to access the central repository for some reason. The client can be installed locally. After the installation, it can be included in a Maven project as well.
mvn clean install -Dgpg.skip
at the dictionary of library.<dependency>
<groupId>com.ibm.maximo</groupId>
<artifactId>maximo-restclient</artifactId>
<version>VERSION</version>
</dependency>
Where VERSION is the version you gave this artifact in the pom.xml
.
If the Maven environment is unavailable, the Maximo REST Client can be used as a regular reference library in the Java project. Because the client depends on javax-json, the javax-json and commons-codec libraries are also needed.
You can get it from http://repo1.maven.org/maven2/org/glassfish/javax.json/1.0.4/ or use the Maven dependency as shown in the following code:
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.0.4</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.1</version>
</dependency>
When the javax.json-1.0.4.jar, commons-codec-1.1.jar, and maximo-restclient-0.1.jar files are ready, add them to the Java project as common reference libraries.
Maximo Resources, or object structures, represent a graph of related Maximo business objects (Mbos) that provides an atomic view/object to create, update, delete, and query the releated set of Mbos.
We will use the Work Order, Purchase Order and Companies Resources as examples to show you how to use the Maximo REST Client.
Note: The use cases can be found at TestOSLCApi.java.
The following instruction shows how to query a work order from Maximo Asset Management by using the Maximo RET Client Library.
Before you connect, it is necessary to set up the authentication and environment information in Options.
Options option = new Options().user("maxadmin").password("maxadmin").auth("maxauth");
Note: For Maximo Asset Management Multitenancy, take the tenant code = "00", as an example, in the following Options.
Options option = new Options().user("maxadmin").password("maxadmin").auth("maxauth").mt(true).tenantCode("00");
option.host("host").port(7001).lean(true);
MaximoConnector mc=new MaximoConnector(option).debug(true);
mc.connect();
MaximoConnector mc = new MaximoConnector(new Options().user("maxadmin").password("maxadmin").lean(true).auth("maxauth").host("host").port(7001));
mc.connect();
By object structure name:
ResourceSet rs = mc.resourceSet("mxwodetail").select("wonum","status").where((new QueryWhere()).where("status").equalTo("APPR")).fetch();
By RESTful URI :
ResourceSet rs = mc.resourceSet(new URL("http://host:port/maximo/oslc/os/mxwodetail")).select("wonum","status").where((new QueryWhere()).where("status").equalTo("APPR")).fetch();
ResourceSet rs = mc.resourceSet("mxwodetail").select("wonum","status").where((new QueryWhere()).where("status").equalTo("APPR")).pageSize(10).fetch();
ResourceSet rs = mc.resourceSet("mxwodetail").select("wonum","status").where((new QueryWhere()).where("status").equalTo("APPR")).paging(true).fetch();
ResourceSet rs = mc.resourceSet("mxwodetail").select("wonum","status").where((new QueryWhere()).where("status").equalTo("APPR")).stablePaging(true).fetch();
rs.nextPage();
rs.previousPage();
For stable paging where currently only scrolling forward is supported, a call to previousPage() results in an error.
JsonObject jo = rs.toJSON();
Note: we support JSON output in byte array. Try the following code:
byte[] jodata = rs.toJSONBytes();
By specific URI:
String woUri = "http://host:port/maximo/oslc/os/mxwodetail/_QkVERk9SRC8xMDAw";
By using the ResourceSet
Resource re = rs.fetchMember(woUri);
Or by using MaximoConnector:
MaximoConnector mc = new MaximoConnector(new Options().user("maxadmin").password("maxadmin").lean(true).auth("maxauth").host("host").port(7001));
mc.connect();
Resource re = mc.resource(woUri);
By index, which will query the member resource from the resourceset collection and will not make a trip to the server:
Resource re = rs.member(0);
re.reload("wonum","status","assetnum","location","wplabor.craft");
OR simply
re.reload("*");
JsonObject jo = re.toJSON();
byte[] joBytes = re.toJSONBytes();
In some case, you might need to traverse some or all work orders. There are some helpful API in the Maximo REST Client.
MaximoConnector mc = new MaximoConnector(new Options().user("maxadmin").password("maxadmin").lean(true).auth("maxauth").host("host").port(7001));
mc.connect();
ResourceSet rs = mc.resourceSet("mxwodetail").pageSize(10).
for(int i=0;i<rs.count();i++){
Resource re = rs.member(i);
...//other operations
}
for(int i=0;i<rs.totalCount();)
{
for(int j=0;j<rs.count();j++)
{
Resource re = rs.member(j);
}
i+=rs2.count();
if(!rs2.hasNextPage())
{
break;
}
rs2.nextPage();
}
mc.disconnect();
The following instruction shows how to create a new work order by Maximo Rest Client.
MaximoConnector mc = new MaximoConnector(new Options().user("maxadmin").password("maxadmin").lean(true).auth("maxauth").host("host").port(7001));
mc.connect();
ResourceSet rs = mc.resourceSet("mxwodetail");
For non-lean, add the prefix before the attribute:
JsonObject jo = Json.createObjectBuilder().add("spi:siteid", "BEDFORD").add("spi:description", "test").build();
Resource re = rs.create(jo);
For lean, skip the prefix, and use the attribute directly:
JsonObject jo = Json.createObjectBuilder().add("siteid", "BEDFORD").add("description", "test").build();
Resource re = rs.create(jo);
JsonObject wplJo = Json.createObjectBuilder().add("skilllevel", "FIRSTCLASS").add("craft", "ELECT").build();
JsonArray wpLaborArray = Json.createArrayBuilder().add(wplJo).build();
jo.add("wplabor",wpLaborArray );
Note: The sample uses the lean format.
By default, the create operation will not return any content of the newly created work order. Because many attributes use default values or calues that auto-generated at the server based on Maximo business logic, it often makes sense to get the final representation of the newly created resource.
Instead of reselecting the work order, which makes a round-trip to the server, it is easy to get the resource content in response information when a new work order is created by the Maximo REST Client.
For non-lean:
Resource re = rs.create(jo,"spi:wonum", "spi:status","spi:statusdate","spi:description");
or simply:
Resource re = rs.create(jo,"*");
For lean:
Resource re = rs.create(jo,"wonum", "status","statusdate", "description");
or simply:
Resource re = rs.create(jo,"*");
To update a resource, you can use either the update() or the merge() APIs. The difference between these APIs how they handle the related child objects in the Resource. An example that uses the PO Resource (mxpo) best illustrates this difference. This example will reference two of the Maximo business object that is contained in the Resource: the PO(parent) and POLINE(child).
In this scenario, you have an existing purchase order that has one PO Line child objects. If you wanted to update the PO with a new PO Line entry, which is the second line, you use the merge() api. The merge process goes through the request "poline" array of objects and matches them up with the existing set of polines, which is the current one, and it will compare the rdf:about, if it is present in the new poline, to determine if this line is an existing poline or a new one. If it determines that it is a new one, it will proceed with creating this new poline, and you have two polines. If it finds a match, it will proceed with updating the matched one with the requested poline content, and you have one updated poline. If there are other existing polines, they won't be updated by the process.
If you use the update() API instead of the merge() API for this scenario, have only one PO Line. If there are any other PO Lines, they will be deleted. This deletion is because the update process treats the "poline" element as an atomic object and will update it as a complete replacement. Processing will insert the new PO Line or update the matching PO Line and delete all the other existing PO Lines for that PO.
The update() and merge() behavior applies only for child objects and not for the root object. The root object is always updated by using either API, assuming some attributes of that object have been changed.
In another scenario, you have an exsiting PO that has three polines(1,2,3) and you want to complete the following actions:
You need to do the following tasks:
Use the update() API and send three polines (2,3,4).
The update API will see that the request does not contain PO Line 1 and so it will delete it. It will skip the update of PO Line 2 because no attributes were change, update PO Line 3, and add a new line, PO Line 4.
After the update, the PO has lines 2,3 and 4.
So if you used the merge() API instead, the only difference is that PO Line 1 is not deleted. The PO has lines 1,2,3 and 4.
You can create a new PO Line on a purchase order and then update this purchase order by using the update() API to update the existing PO Line or replace the existing one by the a new PO Line.
If the polinenum(s) is matched, Maximo Asset Management will update the existing poline with a new array.
If the polinenum(s) is not matched, Maximo Asset Management will delete the existing poline array and create a new one with the new array. The array size will be equal to the new array.
MaximoConnector mc = new MaximoConnector(new Options().user("maxadmin").password("maxadmin").lean(true).auth("maxauth").host("host").port(7001));
mc.connect();
ResourceSet reSet = mc.resourceSet("MXPO").fetch();
Resource poRes = reSet.member(0);
JsonObject polineObjIn = Json.createObjectBuilder().add("polinenum", 1).add("itemnum", "560-00").add("storeloc", "CENTRAL").build();
JsonArray polineArray = Json.createArrayBuilder().add(polineObjIn).build();
JsonObject poObj = Json.createObjectBuilder().add("poline", polineArray).build();
poRes.update(poObj);
JsonObject polineObjIn2 = Json.createObjectBuilder().add("polinenum", 2).add("itemnum", "0-0031").add("storeloc", "CENTRAL").build();
JsonArray polineArray2 = Json.createArrayBuilder().add(polineObjIn2).build();
JsonObject poObj2 = Json.createObjectBuilder().add("poline", polineArray2).build();
poRes.update(polineObj2);
At the end of it, you have a PO with 1 POLINE. The steps below explains how it happens:
The server-side framework will attempt to locate a POLINE that has the polinenum 2 and will not find any, because there is only a POLINE with polinenum 1).
It will add a new POLINE that has polinenum 2.
It will delete all the remaining POLINEs that are not present in the JSON object, which will result in PO Line 1 being deleted.
You can create a new poline on a purchase order and then merge this purchase order by using another poline object. You can create a new PO Line on a purchase order and then merge this purchase order by using the merge() API to update the existing line or add an additional line.
If the poline(s) is matched, Maximo Asset Management will update the existing poline with new array, which is similar to using the update() method.
If the poline(s) is not matched, Maximo Asset Management will add the new poline array to the existing poline array.
MaximoConnector mc = new MaximoConnector(new Options().user("maxadmin").password("maxadmin").lean(true).auth("maxauth").host("host").port(7001));
mc.connect();
ResourceSet reSet = mc.resourceSet("MXPO").fetch();
Resource poRes = reSet.member(1);
JsonObject polineObjIn = Json.createObjectBuilder().add("polinenum", 1).add("itemnum", "560-00").add("storeloc", "CENTRAL").build();
JsonArray polineArray = Json.createArrayBuilder().add(polineObjIn).build();
JsonObject poObj = Json.createObjectBuilder().add("poline", polineArray ).build();
poRes.update(poObj);//this creates a POLINE with polinenum 1.
JsonObject polineObjIn3 = Json.createObjectBuilder().add("polinenum", 2).add("itemnum", "0-0031").add("storeloc", "CENTRAL").build();
JsonArray polineArray3 = Json.createArrayBuilder().add(polineObjIn3).build();
JsonObject polineObj3 = Json.createObjectBuilder().add("poline", polineObjIn3).build();
poRes.merge(polineObj3);//this will create a POLINE with polinenum 2.
At the end of it, you have a PO that has 2 POLINEs. The steps below explains how it happens:
The server-side framework will attempt to locate a POLINE that has the polinenum 2 and will not find any, because there is only a POLINE that has polinenum 1.
It will add a new POLINE with polinenum 2.
It will keep the remaining lines, in this case POLINE with polinenum 1, as is.
You can delete an existing work order by using the Maximo REST Client.
MaximoConnector mc = new MaximoConnector(new Options().user("maxadmin").password("maxadmin").lean(true).auth("maxauth").host("host").port(7001));
mc.connect();
ResourceSet rs = mc.resourceSet("mxsr").
By using a specific URI:
String venUri = "http://localhost:7001/maximo/oslc/os/mxsr/_U1IvMTE3Mw--";
By using ResourceSet:
Resource re = rs.fetchMember(srUri);
Or byusing MaximoConnector:
Resource re = mc.resource(srUri);
By index:
Resource re = rs.member(0);
mc.deleteResource(srUri);
re.delete();
Attachments in Maximo Asset Management are documents, files, or images that are attached to a resource, such as a work order or service request. The following example shows how to add and delete an attachment on a work order. In the resource definition, the DOCLINKS object, which is a child of the work order object, supports the attachment data.
MaximoConnector mc = new MaximoConnector(new Options().user("maxadmin").password("maxadmin").lean(true).auth("maxauth").host("host").port(7001));
mc.connect();
ResourceSet rs = mc.resourceSet("mxwodetail").
By specific URI:
String woUri = "http://host:port/maximo/oslc/os/mxwodetail/_QkVERk9SRC8xMDAw";
By using ResourceSet:
Resource re = rs.fetchMember(woUri);
By using MaximoConnector:
Resource re = mc.resource(woUri);
By index (be careful with the range):
Resource re = rs.member(0);
AttachmentSet ats = re.attachmentSet();
String str = "hello world @ "+ Calendar.getInstance().getTime().toString();
byte[] data = str.getBytes("utf-8");
Attachment att = new Attachment().name("attachment.txt").description("test").data(data).meta("FILE", "Attachments");
By default,
att = ats.create(att);
Note: For the custom property name for doclinks such as "customdoclink",
att = ats.create("customdoclink",att);
Attachment att = ats.member(0);
byte[] data = att.toDoc();
JsonObject attMeta = att.toDocMeta();
JsonObject attMeta = att.fetchDocMeta();
String attUri = "http://host/maximo/oslc/os/mxwodetail/_QkVERk9SRC8xMDAw/DOCLINKS/28";
Attachment att = mc.attachment(attUri);
byte[] data = mc.attachedDoc(attUri);
JsonObject attMeta = mc.attachmentDocMeta(attUri);
By specific URI:
String woUri = "http://host:port/maximo/oslc/os/mxwodetail/_QkVERk9SRC8xMDAw";
By using ResourceSet:
Resource re = rs.fetchMember(woUri);
Or by using MaximoConnector:
Resource re = mc.resource(woUri);
By index (be careful with the range):
Resource re = rs.member(0);
AttachmentSet ats = re.attachmentSet();
By index:
Attachment att = ats.member(0);
By using a specific URI:
String attUri = "http://host/maximo/oslc/os/mxwodetail/_QkVERk9SRC8xMDAw/DOCLINKS/28";
By using AttachmentSet:
Attachment att = ats.fetchMember(attUri);
Or by using MaximoConnector:
Attachment att = mc.attachment(attUri);
By using the attachment, which is useful when you already have the attachment:
att.delete();
By using MaximoConnector, which is useful when you have only the URI:
mc.deleteAttachment(attUri);
Maximo Asset Management supports a feature that is called a Saved Query that is a pre-built query for an application, such as the Work Order Tracking application, which allows a user to easily retrieve a common set of data, for example, a list of approved work orders. Assuming public saved queries are present for an application, you can use the savedQuery() API to query records based on defined filter criterion. You also must ensure that the authorized application is set accordingly for the object structure you plan to use.
Take the "OWNER IS ME" query for the Work Order Tracking (WOTRACK) application as an example, which assumes that the MXWODETAIL object structure is setup with "WOTRACK" as the authorized application.
ResourceSet rs = mc.resourceSet("mxwodetail").savedQuery(new SavedQuery().name("WOTRACK:OWNER IS ME")).select("*").fetch();
The select("*") statement queries all attributes for the filtered set of mxwodetail. As mentioned earlier, you can do a partial resource selection, such as select("wonum","status").
You can also do further filtering with the saved query.
ResourceSet rs = mc.resourceSet("mxwodetail").savedQuery(new SavedQuery().name("WOTRACK:OWNER IS ME")).where(new QueryWhere().where("status").in("APPR","WAPPR")).select("wonum","status","statusdate").fetch();
This feature is used mostly for text search. This feature needs the server-side object structure to be set up with the searchable attributes. For example, if it is setup with "description", you can use the hasTerms() API to set the searchable terms.
For example, you can select all the resources from oslcmxsr whose description contains email or finance.
MaximoConnector mc = new MaximoConnector(new Options().user("maxadmin").password("maxadmin").auth("maxauth").host("host").port(7001));
mc.connect();
ResourceSet res = mc.resourceSet("OSLCMXSR").hasTerms("email", "finance").select("spi:description", "spi:ticketid").pageSize(5).fetch();
Actions are functional components of a resource that perform specific tasks, such as changing the status of a resource or moving a resource. This example uses the changeStatus action as an example (the changeStatus method is annotated marked as a WebMethod in the WorkOrder Service),
MaximoConnector mc = new MaximoConnector(new Options().user("maxadmin").password("maxadmin").lean(true).auth("maxauth").host("host").port(7001));
mc.connect();
ResourceSet reSet = mc.resourceSet("MXWODETAIL").where((new QueryWhere()).where("status").equalTo("WAPPR")).fetch();
Resource re = reSet.member(0);
JsonObject jo = Json.createObjectBuilder().add("status","APPR").add("memo","approval").build();
re.invokeAction("wsmethod:changeStatus", jo);