pxGrid Context-In Code

Use this code as a sample for your development application.
This is a modification of the custom service provider code where we publish the attributes defined under the Assets array and the custom attributes defined under the AssetCustomAttributes

package com.cisco.pxgrid.samples.ise;

import java.io.IOException;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import javax.websocket.Session;

import org.apache.commons.cli.ParseException;
import org.glassfish.tyrus.client.ClientManager;
import org.glassfish.tyrus.client.ClientProperties;
import org.glassfish.tyrus.client.SslEngineConfigurator;
import org.glassfish.tyrus.client.auth.Credentials;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.cisco.pxgrid.samples.ise.model.AccountState;
import com.cisco.pxgrid.samples.ise.model.Service;
import com.cisco.pxgrid.samples.ise.model.ServiceRegisterResponse;
import com.google.gson.Gson;

/**
 * Demonstrate how to create a custom service that publishes data
 * 
 * The flow of the application is as follows:
 * 1. Parse arguments for configurations
 * 2. Activate Account. This will then require ISE Admin to approve this new node.
 * 3. pxGrid ServiceRegister to register the new custom service
 * 4. Schedule periodic pxGrid ServiceReregister to signify the service is still alive
 * 5. pxGrid ServiceLookup for ISE pubsub service
 * 6. pxGrid get AccessSecret for the ISE pubsub node
 * 7. Establish WebSocket connection with the ISE pubsub node
 * 8. Establish STOMP connection for pubsub messaging
 * 9. Schedule periodic publish of data
 * 10. Wait for keyboard input for stopping the application
 */
public class ContextInPublishing {
    private static Logger logger = LoggerFactory.getLogger(ContextInPublishing.class);

    
    public static void main(String[] args) throws Exception {
        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();

        // Parse arguments
        SampleConfiguration config = new SampleConfiguration();
        try {
            config.parse(args);
        } catch (ParseException e) {
            config.printHelp("CustomServiceProvider");
            System.exit(1);
        }

        // AccountActivate
        PxgridControl control = new PxgridControl(config);
        while (control.accountActivate() != AccountState.ENABLED) {
            Thread.sleep(60000);
        }
        logger.info("pxGrid controller version={}", control.getControllerVersion());

        // pxGrid ServiceRegister
        Map<String, String> sessionProperties = new HashMap<>();
        sessionProperties.put("wsPubsubService", "com.cisco.ise.pubsub");
        sessionProperties.put("assetTopic", "/topic/com.cisco.endpoint.asset");
        ServiceRegisterResponse response = control.serviceRegister("com.cisco.endpoint.asset", sessionProperties);
        String registrationId = response.getId();
        long reregisterTimeMillis = response.getReregisterTimeMillis();

        // Schedule pxGrid ServiceReregister
        executor.scheduleWithFixedDelay(() -> {
            try {
                control.serviceReregister(registrationId);
            } catch (IOException e) {
                logger.error("Reregister failure");
            }
        }, reregisterTimeMillis, reregisterTimeMillis, TimeUnit.MILLISECONDS);

        // pxGrid ServiceLookup for pubsub service
        Service[] services = control.serviceLookup("com.cisco.ise.pubsub");
        if (services.length == 0) {
            logger.info("Pubsub service unavailabe");
            return;
        }
        // Use first service
        Service wsPubsubService = services[0];
        String wsURL = wsPubsubService.getProperties().get("wsUrl");
        logger.info("wsUrl={}", wsURL);

        // pxGrid AccessSecret
        String secret = control.getAccessSecret(wsPubsubService.getNodeName());

        // Setup WebSocket client
        ClientManager client = ClientManager.createClient();
        SslEngineConfigurator sslEngineConfigurator = new SslEngineConfigurator(config.getSSLContext());
        client.getProperties().put(ClientProperties.SSL_ENGINE_CONFIGURATOR, sslEngineConfigurator);
        client.getProperties().put(ClientProperties.CREDENTIALS,
                new Credentials(config.getNodeName(), secret.getBytes()));

        // WebSocket connect
        StompPubsubClientEndpoint endpoint = new StompPubsubClientEndpoint();
        URI uri = new URI(wsURL);
        Session session = client.connectToServer(endpoint, uri);

        // STOMP connect
        endpoint.connect(uri.getHost());

        Asset asset = new Asset();
        asset.setAssetId("1");
        asset.setAssetName("pxGrid2-PC");
        asset.setAssetIpAddress("10.0.0.21");
        asset.setAssetMacAddress("00:0C:29:C1:7B:2C");
        asset.setAssetHwRevision("5.6");
        asset.setAssetProtocol("CIP");
        AssetConnectedLink[] assetConnectedLinks = new AssetConnectedLink[1];
        AssetConnectedLink link = new AssetConnectedLink();
        link.setKey("indattr1");
        link.setValue("1");
        assetConnectedLinks[0] = link;
        
        // Define the number of custom attributes
            AssetCustomAttribute[] assetCustomAttributes = new AssetCustomAttribute[3];
        
         // Add each custom attribute to each object. Here it is for the DeviceType customAttribute.
            AssetCustomAttribute deviceTypeattr = new AssetCustomAttribute();
            deviceTypeattr.setKey("DeviceType");
            deviceTypeattr.setValue("1");
            assetCustomAttributes[0] = deviceTypeattr;


         // Add the seconds custom attribute to each object. Here it is for the Score customAttribute.
            AssetCustomAttribute scoreAttr = new AssetCustomAttribute();
            scoreAttr.setKey("Score");
            scoreAttr.setValue("10");
            assetCustomAttributes[1] = scoreAttr;


         // Add the seconds custom attribute to each object. Here it is for the Manufacturer customAttribute
            AssetCustomAttribute manufacturerAttr = new AssetCustomAttribute();
            manufacturerAttr.setKey("Manufacturer");
            manufacturerAttr.setValue("Apple");
            assetCustomAttributes[2] = manufacturerAttr;

        // Finally add all the three custom attributes using a single array to the asset object which is sent to the pxGrid topic
            asset.setAssetCustomAttributes(assetCustomAttributes);

/** If there is a need to add another attribute (for example, SoftwareType), first increase the array size by replacing the following command mentioned in the definition of custom attributes earlier:
* AssetCustomAttribute[] assetCustomAttributes = new AssetCustomAttribute[3];
* with
* AssetCustomAttribute[] assetCustomAttributes = new AssetCustomAttribute[4];
*
* Now add the new customAttribute to the array using the following commands. Here it is for the Software customAttribute.
* AssetCustomAttribute softwareAttr = new AssetCustomAttribute();
* softwareAttr.setKey(“SoftwareAttribute”);
* softwareAttr.setValue("Apple");
* assetCustomAttributes[3] = softwareAttr;
*/

        AssetOperation assetOperation = new AssetOperation();
        assetOperation.setAsset(asset);
        assetOperation.setOpType("UPDATE");

        Gson gson = new Gson();
        String data = gson.toJson(assetOperation);	
    
        // STOMP send periodically
        executor.scheduleWithFixedDelay(() -> {
            try {
                endpoint.publish("/topic/com.cisco.endpoint.asset", data.getBytes() );
                        
            } catch (IOException e) {
                logger.error("Publish failure");
            }
        }, 0, 5, TimeUnit.SECONDS);

        SampleHelper.prompt("press <enter> to disconnect...");

        // pxGrid ServerUnregister
        control.unregisterService(registrationId);
        
        // Stop executor
        executor.shutdown();
        executor.awaitTermination(5, TimeUnit.SECONDS);

        // STOMP disconnect
        endpoint.disconnect("ID-123");
        // Wait for disconnect receipt
        Thread.sleep(3000);

        // Websocket close
        session.close();
    }
    
    private static class Asset {
          private String assetId;
          private String assetName;
          private String assetIpAddress;
          private String assetMacAddress;
          private String assetVendor;
          private String assetProductId;
          private String assetSerialNumber;
          private String assetDeviceType;
          private String assetSwRevision;
          private String assetHwRevision;
          private String assetProtocol;
          private AssetCustomAttribute assetCustomAttributes[];
          private AssetConnectedLink assetConnectedLinks[];
          public void setAssetId(String assetId) {
            this.assetId = assetId;
          }
          public void setAssetName(String assetName) {
            this.assetName = assetName;
          }
          public void setAssetIpAddress(String assetIpAddress) {
            this.assetIpAddress = assetIpAddress;
          }
          public void setAssetMacAddress(String assetMacAddress) {
            this.assetMacAddress = assetMacAddress;
          }
          public void setAssetVendor(String assetVendor) {
            this.assetVendor = assetVendor;
          }
          public void setAssetProductId(String assetProductId) {
            this.assetProductId = assetProductId;
          }
          public void setAssetSerialNumber(String assetSerialNumber) {
            this.assetSerialNumber = assetSerialNumber;
          }
          public void setAssetDeviceType(String assetDeviceType) {
            this.assetDeviceType = assetDeviceType;
          }
          public void setAssetSwRevision(String assetSwRevision) {
            this.assetSwRevision = assetSwRevision;
          }
          public void setAssetHwRevision(String assetHwRevision) {
            this.assetHwRevision = assetHwRevision;
          }
          public void setAssetProtocol(String assetProtocol) {
            this.assetProtocol = assetProtocol;
          }
          public void setAssetCustomAttributes(AssetCustomAttribute[] assetCustomAttributes) {
            this.assetCustomAttributes = assetCustomAttributes;
          }
          public void setAssetConnectedLinks(AssetConnectedLink[] assetConnectedLinks) {
            this.assetConnectedLinks = assetConnectedLinks;
          }
        }

        private static class AssetOperation {
          private Asset asset;
          private String opType;
          public void setAsset(Asset asset) {
            this.asset = asset;
          }
          public void setOpType(String opType) {
            this.opType = opType;
          }
        }

        private static class AssetCustomAttribute {
          private String key;
          private String value;
          public void setKey(String key) {
            this.key = key;
          }
          public void setValue(String value) {
            this.value = value;
          }
        }

        private static class AssetConnectedLink {
          private String key;
          private String value;
          public void setKey(String key) {
            this.key = key;
          }
          public void setValue(String value) {
            this.value = value;
          }
        }	
    
}

Output

------ config ------
  hostname = ise24fc3.lab10.com
  nodename = IOTSolution
  password = (not specified)
  description = (not specified)
  keystorefilename = /Applications/sdk24/pxgrid-sdk-2.0.0.14/samples/bin/sdk24.jks
  keystorepassword = Cisco123
  truststorefilename = /Applications/sdk24/pxgrid-sdk-2.0.0.14/samples/bin/sdk24root.jks
  truststorepassword = Cisco123
--------------------
09:30:18.446 [main] INFO com.cisco.pxgrid.samples.ise.PxgridControl - AccountActivate request={}
09:30:21.931 [main] INFO com.cisco.pxgrid.samples.ise.PxgridControl - AccountActivate response={"accountState":"ENABLED","version":"2.0.0.13"}
09:30:21.932 [main] INFO com.cisco.pxgrid.samples.ise.ContextInPublishing - pxGrid controller version=2.0.0.13
09:30:21.959 [main] INFO com.cisco.pxgrid.samples.ise.PxgridControl - ServiceRegister request={"name":"com.cisco.endpoint.asset","properties":{"wsPubsubService":"com.cisco.ise.pubsub","assetTopic":"/topic/com.cisco.endpoint.asset"}}
09:30:22.114 [main] INFO com.cisco.pxgrid.samples.ise.PxgridControl - ServiceRegister response={"id":"46a9512d-0523-4c7c-9f38-edf3e5a685e4","reregisterTimeMillis":300000}
09:30:22.155 [main] INFO com.cisco.pxgrid.samples.ise.PxgridControl - ServiceLookup request={"name":"com.cisco.ise.pubsub"}
09:30:22.168 [main] INFO com.cisco.pxgrid.samples.ise.PxgridControl - ServiceLookup response={"services":[{"name":"com.cisco.ise.pubsub","nodeName":"ise-pubsub-ise24fc3","properties":{"wsUrl":"wss://ise24fc3.lab10.com:8910/pxgrid/ise/pubsub"}}]}
09:30:22.169 [main] INFO com.cisco.pxgrid.samples.ise.ContextInPublishing - wsUrl=wss://ise24fc3.lab10.com:8910/pxgrid/ise/pubsub
09:30:22.170 [main] INFO com.cisco.pxgrid.samples.ise.PxgridControl - AccessSecret request={"peerNodeName":"ise-pubsub-ise24fc3"}
09:30:22.342 [main] INFO com.cisco.pxgrid.samples.ise.PxgridControl - AccessSecret response={"secret":"vMwqOy391DSyIIS1"}
09:30:23.954 [Grizzly(1)] INFO com.cisco.pxgrid.samples.ise.StompPubsubClientEndpoint - WS onOpen
09:30:23.992 [main] INFO com.cisco.pxgrid.samples.ise.StompPubsubClientEndpoint - STOMP CONNECT host=ise24fc3.lab10.com
09:30:24.002 [pool-1-thread-1] INFO com.cisco.pxgrid.samples.ise.StompPubsubClientEndpoint - STOMP SEND topic=/topic/com.cisco.endpoint.asset
09:30:24.008 [Grizzly(2)] INFO com.cisco.pxgrid.samples.ise.StompPubsubClientEndpoint - STOMP CONNECTED version=1.2
press <enter> to disconnect...
09:30:29.007 [pool-1-thread-1] INFO com.cisco.pxgrid.samples.ise.StompPubsubClientEndpoint - STOMP SEND topic=/topic/com.cisco.endpoint.asset
09:30:34.010 [pool-1-thread-1] INFO com.cisco.pxgrid.samples.ise.StompPubsubClientEndpoint - STOMP SEND topic=/topic/com.cisco.endpoint.asset

What to see in ISE

Select Administration->pxGrid Services, you should see IOTSolutions registered

Select Administration->pxGrid Services->Web Clients, you should see IOTSolutions publishing to the Endpoint Asset Topic

Select Operations->RADIUS->Live Logs, you should see the endpoint classified as an IOT device and a Security Group Tag (SGT) of IOT example assigned to the Authorization policy

Select Context Visibility->Endpoints->Endpoint Classification