Implementing a Domain Class
There are a number of steps required to implement each OSLC domain classes. These all follow the pattern implemented and verified for DeviceType.
Implement the resource specific methods
These are the changes to the generated resource class in package com.ibm.oslc.adaptor.iotp.resources.
Make sure to add any imports in the Implement a constructor to convert from JSON to the Java class instance
This resource class constructor converts from the JSON accessed by the adaptor manager CRUD methods into an instance of the associated Java class. This should call super() to set any OSLC properties in the superclass. Then its gets the JSON members and uses them to set the properties of the Java object.
See class IotDeviceType for a typical implementation.
Implement the resource toJson() method
This method converts the Java class to a JSON object as defined by the IoT Platform REST APIs.
See class IotDeviceType for a typical implementation.
Update the Resource toString() method
Update the resource’s toString(boolean) method to return getTitle(). This provides a useful representation of the resource in various lists in a selection dialog, etc.
// Start of user code toString_finalize
if (getTitle() != null) result = getTitle();
// End of user code
return result;
This ensures that Links to resources (which might not have the title set) will also display properly.
Implement the Connector Manager CRUD methods
The adaptor manager CE4IoTConnectorManager is the key class generated by the code generator that supports HTTP methods on the resource. All the CRUD methods for all the domain resources are generated as static methods in this class. User code needs to be added to implement these methods.
Implement the Connector Manager create method
Implement the CE4IoTConnectorManager.create<resource)() method to create a new resource instance. This method uses the constructor to actually create the resource.
This method is typically called when an OSLC application requests a creation dialog, the user fills in the fields and presses the submit button. The IotPlatformService class provides the JAX-RS methods that dispatch to these connector manager creation methods.
Heres' a typical implementation:
// Start of user code createDeviceType
try {
IotpServiceProviderInfo info = IoTAPIImplementation.getIotpServiceProviderInfo(httpServletRequest, iotId);
IoTPClient client = (IoTPClient)httpServletRequest.getSession().getAttribute(IoTPClient.IOTPCLIENT_ATTRIBUTE);
String uri = "device/types";
// Create the JSon Element representing the device.
JsonObject json = aResource.toJson().getAsJsonObject();
// Remove any properties that can't be assigned in case they were copied from another resource
json.remove("createdDateTime");
json.remove("updatedDateTime");
// Convert the result back
JsonElement result = client.createIoTResource(info.name, uri, json);
// we do not create any logical and physical interfaces here
if (result != null) newResource = new DeviceType(info, aResource.getIdentifier(), result, null, null);
} catch (Exception e) {
e.printStackTrace();
throw new WebApplicationException(e, Status.INTERNAL_SERVER_ERROR);
}
// End of user code
The ServiceProviderInfo is obtained from the IoT Platform organization id (since organizations are containers of resources and are therefore treated as OSLC ServiceProvider instances). The info contains the information needed to formulate the IoT Platform URI for the resource including the HTTP protocol, platform base, and API version.
The IoTPClient is obtained from the session and is an instance of the client for a particular logged in (or authenticated) IoT Platform user.
The Java representation of the OSLC resources is then converted to JSON using its toJson() instance method (see below). A few JSON attributes that the IoT Platform REST APIs do not allow in the POST method are removed. Then the IoTPClient is used to create the IoT Platform device based on the service provider information, the resource identifier, and the JSON object.
Implement the Manager read method
Implement the CE4IoTConnectorManager.get
Here's a typical implementation:
// Start of user code getDeviceType
try {
if (deviceTypeId == null) {
throw new Exception("Device ID must not be null");
}
final IotpServiceProviderInfo info = IoTAPIImplementation.getIotpServiceProviderInfo(httpServletRequest, iotId);
IoTPClient client = (IoTPClient)httpServletRequest.getSession().getAttribute(IoTPClient.IOTPCLIENT_ATTRIBUTE);
String uri = "device/types/" + deviceTypeId;
JsonElement deviceType = client.readIoTResource(info.name, uri);
if (deviceType == null) return aResource;
// Also get the draft serviceInterface and logicalInterfaces
JsonElement physicalInterface = client.readIoTResource(info.name, "draft/"+uri+"/physicalinterface");
JsonElement logicalInterfaces = client.readIoTResource(info.name, "draft/"+uri+"/logicalinterfaces");
aResource = new DeviceType(info, deviceTypeId, deviceType, physicalInterface, logicalInterfaces);
} catch (Exception e) {
e.printStackTrace();
throw new WebApplicationException(e, Status.INTERNAL_SERVER_ERROR);
}
// End of user code
Again, each of these CRUD methods access the ServiceProviderInfo for the IoT Platform organization in order to get the details required to form the IoT Platform URI for the resource.
As in all the CRUD methods, the IoTPClient instance for the particular user is obtained from the HTTP session information.
The IoTPClient is then used to read the resource which is then converted to the proper Java class using a constructor created for the purpose (see below).
Implement the Manager query method
Implement the CE4IoTConnectorManager.query
Here's a typical implementation:
// Start of user code queryDeviceTypes
try {
IotpServiceProviderInfo info = IoTAPIImplementation.getIotpServiceProviderInfo(httpServletRequest, iotId);
IoTPClient client = (IoTPClient)httpServletRequest.getSession().getAttribute(IoTPClient.IOTPCLIENT_ATTRIBUTE);
String uri = "device/types";
JsonObject result = client.readIoTResource(info.name, uri).getAsJsonObject();
JsonArray results = result.getAsJsonArray("results");
resources = new ArrayList<DeviceType>(results.size());
for (int i = 0; i < results.size(); i++) {
JsonObject obj = results.get(i).getAsJsonObject();
// TODO: query doesn't include logical and physical interfaces
DeviceType deviceType = new DeviceType(info, obj.get("id").getAsString(), obj, null, null);
// Note: toString() methods are used to display the resource in the selection dialog, so we use that here.
// This will generally be the dcterms:label
// Handle dangling meta char '*' for user convenience
if (where == null || where.equals("") || where.equals("*")) where = ".*";
if (deviceType.toString().matches(where)) resources.add(deviceType);
}
} catch (PatternSyntaxException e) {
} catch (Exception e) {
e.printStackTrace();
throw new WebApplicationException(e, Status.INTERNAL_SERVER_ERROR);
}
// End of user code
The IoTPClient is used to read the IoT Platform resource, in this case using a URI that returns a JSON object that contains a list of object instances. This is then converted into an ArrayList of the corresponding OSLC Java objects using the same constructors used in the read method.
Implement the Manager update method
Implement the CE4IoTConnectorManager.update
Here's a typical implementation:
// Start of user code updateDeviceType
try {
// RQM attempts to set the backlink without a properly constructed resource, ignore this since we can't store any links
if (aResource.getIdentifier() == null) return aResource;
IotpServiceProviderInfo info = IoTAPIImplementation.getIotpServiceProviderInfo(httpServletRequest, iotId);
IoTPClient client = (IoTPClient)httpServletRequest.getSession().getAttribute(IoTPClient.IOTPCLIENT_ATTRIBUTE);
String uri = "device/types/" + deviceTypeId;
JsonObject json = aResource.toJson().getAsJsonObject();
// Remove the properties that can't be updated
json.remove("id");
json.remove("classId");
json.remove("createdDateTime");
json.remove("updatedDateTime");
JsonElement result = client.updateIoTResource(info.name, uri, json);
// logical and physical interfaces are updated directly, not through the device type
if (result != null) updatedResource = new DeviceType(info, aResource.getIdentifier(), result, null, null);
} catch (Exception e) {
e.printStackTrace();
throw new WebApplicationException(e, Status.INTERNAL_SERVER_ERROR);
}
// End of user code
The OSLC Java representation of the resource is converted to its JSON representation using its toJson() method. Then the JSON attributes that cannot be updated are removed from the object. Finally the IoTPClient is used to update the IoT Platform resource given the service provider information, resource identifier, and its JSON representation.
Implement the Manager delete method
Implement the CE4IoTConnectorManager.delete{resource}() method to delete a resource with a given id.
Here's a typical implementation:
// Start of user code deleteDeviceType
try {
IotpServiceProviderInfo info = IoTAPIImplementation.getIotpServiceProviderInfo(httpServletRequest, iotId);
IoTPClient client = (IoTPClient)httpServletRequest.getSession().getAttribute(IoTPClient.IOTPCLIENT_ATTRIBUTE);
String uri = "device/types/" + deviceTypeId;
deleted = client.deleteIoTResource(info.name, uri);
} catch (Exception e) {
e.printStackTrace();
throw new WebApplicationException(e, Status.INTERNAL_SERVER_ERROR);
}
// End of user code
Add the resource instances to the selection dialog
Implement the CE4IoTConnectorManager.DeviceTypeAndRuleAndThingTypeSelector() method to include the resources in the selection dialog as needed. This uses the query methods implemented above. This method is used to access all instances of all resources of any type that are members of an organization (or service provider). It is often used for generic selection dialogs to enable selection of any organization resource. More specific IoT Platform resource browsers may use the more specific query methods directly to fill in content for a particular IoT Platform hierarchical resource browser.
The initial implementation to include the IoT Platform DeviceType resources is:
// Start of user code DeviceTypeAndRuleAndThingTypeSelector
// TODO: edit this method to have only top-level resources when the selection dialog navigator is implemented
// These resources are displayed in the IoT Platform tree view browser in the selection dialog
try {
IotpServiceProviderInfo info = IoTAPIImplementation.getIotpServiceProviderInfo(httpServletRequest, iotId);
resources = new ArrayList<AbstractResource>();
resources.addAll(queryDeviceTypes(httpServletRequest, info.iotId, terms, 1, 10000));
resources.addAll(queryPhysicalInterfaces(httpServletRequest, info.iotId, terms, 1, 10000));
resources.addAll(queryLogicalInterfaces(httpServletRequest, info.iotId, terms, 1, 10000));
resources.addAll(queryEventTypes(httpServletRequest, info.iotId, terms, 1, 10000));
resources.addAll(querySchemas(httpServletRequest, info.iotId, terms, 1, 10000));
resources.addAll(queryThingTypes(httpServletRequest, info.iotId, terms, 1, 10000));
resources.addAll(queryRules(httpServletRequest, info.iotId, terms, 1, 10000));
} catch (Exception e) {
e.printStackTrace();
throw new WebApplicationException(e, Status.INTERNAL_SERVER_ERROR);
}
// End of user code
A resources.addAll line needs to be added for each new IoT Platform Domain resource.
Here's the implementation for the NodREDAppSelector() method that returns the Bluemix resources that should be include in the selection dialog:
// Start of user code NodeREDAppSelector
List<NodeREDApp> apps = queryNodeREDApps(httpServletRequest, bmxId, terms, 1, 1000);
resources = new ArrayList<NodeREDApp>(apps.size());
resources.addAll(apps);
// End of user code
return resources;
Implement the Resource ETag method
Implement the CE4IoTConnectorManager.getETagFrom{resource}() method to identify a particular version of a resource. This is needed to ensure a resource hasn’t changed between a GETn and subsequent PUT.
Here's a typical implementation:
// Start of user code getETagFromIotDeviceType
// TODO Implement code to return an ETag for a particular resource
// End of user code
Update Creation Dialog Creator Method
Update IotPlatformService.createResourceAndChangeRequestAndRequirement to use the type parameter to determine which IoT Platform resource to create, and calls the appropriate CE4IoTConnectorManager.create method
The creation dialogs are in src/main/webapp/creators/
Redirect text/html to the IoT Platform dashboard UI
In the IoTPlatformService and BluemixServices classes, in each get{resource}asHtml()
method, add this code in the _setAttributes user code area:
// Start of user code getDeviceTypeAsHtml_setAttributes
// Redirect to the Watson IoT Platform dashboard as best you can for the resource
try {
IotpServiceProviderInfo info = IoTAPIImplementation.getIotpServiceProviderInfo(httpServletRequest, iotId);
String iotDashboardURI = "https://"+ iotId + "."+info.platformBase + "/dashboard/#/devices/deviceTypes-v2";
httpServletResponse.sendRedirect(iotDashboardURI);
return Response.ok().build();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// End of user code
The iotDashboardURI currently opens the IoT Platform Dashboard to show the defined DeviceTypes. That is currently as close as we can get to the logical and physical interfaces, event types and schemas. We also don't know that the URI would be for thing types and rules since they are not implemented yet. As the IoT Platform Dashboard evolves, these redirect URIs may need to change in order to get the user closer to the actual resource in the IoT Platform dashboard.
As of RELM 6.0.6, Thing, ThingType and RUL have no platform UI. These links should not be redirected until there is supported platform UI to redirect to.
Resource Preview
Update the {resource}smallpreview.jsp and largepreview.jsp files to remove any properties that don't need to be included in the small preview, and provide any formatting or style guides desired. Note that the generated content is created inside the protected user code, so any changes you make here will be preserved when the code is generated.
Note that the src/main/webapp/com/ibm/oslc/adaptor/iotp/{resource-name}.jsp generated by the Lyo Designer is used for the large preview.