@Override
 public boolean equals(Object obj) {
   if (this == obj) return true;
   if (obj == null) return false;
   if (getClass() != obj.getClass()) return false;
   AddNodesItem other = (AddNodesItem) obj;
   if (ParentNodeId == null) {
     if (other.ParentNodeId != null) return false;
   } else if (!ParentNodeId.equals(other.ParentNodeId)) return false;
   if (ReferenceTypeId == null) {
     if (other.ReferenceTypeId != null) return false;
   } else if (!ReferenceTypeId.equals(other.ReferenceTypeId)) return false;
   if (RequestedNewNodeId == null) {
     if (other.RequestedNewNodeId != null) return false;
   } else if (!RequestedNewNodeId.equals(other.RequestedNewNodeId)) return false;
   if (BrowseName == null) {
     if (other.BrowseName != null) return false;
   } else if (!BrowseName.equals(other.BrowseName)) return false;
   if (NodeClass == null) {
     if (other.NodeClass != null) return false;
   } else if (!NodeClass.equals(other.NodeClass)) return false;
   if (NodeAttributes == null) {
     if (other.NodeAttributes != null) return false;
   } else if (!NodeAttributes.equals(other.NodeAttributes)) return false;
   if (TypeDefinition == null) {
     if (other.TypeDefinition != null) return false;
   } else if (!TypeDefinition.equals(other.TypeDefinition)) return false;
   return true;
 }
 @Override
 public int hashCode() {
   final int prime = 31;
   int result = 1;
   result = prime * result + ((StatusCode == null) ? 0 : StatusCode.hashCode());
   result = prime * result + ((AddedNodeId == null) ? 0 : AddedNodeId.hashCode());
   return result;
 }
 @Override
 public int hashCode() {
   final int prime = 31;
   int result = 1;
   result = prime * result + ((ResponseHeader == null) ? 0 : ResponseHeader.hashCode());
   result = prime * result + ((SessionId == null) ? 0 : SessionId.hashCode());
   result = prime * result + ((AuthenticationToken == null) ? 0 : AuthenticationToken.hashCode());
   result =
       prime * result + ((RevisedSessionTimeout == null) ? 0 : RevisedSessionTimeout.hashCode());
   result = prime * result + ((ServerNonce == null) ? 0 : ServerNonce.hashCode());
   result = prime * result + ((ServerCertificate == null) ? 0 : ServerCertificate.hashCode());
   result = prime * result + ((ServerEndpoints == null) ? 0 : Arrays.hashCode(ServerEndpoints));
   result =
       prime * result
           + ((ServerSoftwareCertificates == null)
               ? 0
               : Arrays.hashCode(ServerSoftwareCertificates));
   result = prime * result + ((ServerSignature == null) ? 0 : ServerSignature.hashCode());
   result =
       prime * result + ((MaxRequestMessageSize == null) ? 0 : MaxRequestMessageSize.hashCode());
   return result;
 }
 @Override
 public boolean equals(Object obj) {
   if (this == obj) return true;
   if (obj == null) return false;
   if (getClass() != obj.getClass()) return false;
   CreateSessionResponse other = (CreateSessionResponse) obj;
   if (ResponseHeader == null) {
     if (other.ResponseHeader != null) return false;
   } else if (!ResponseHeader.equals(other.ResponseHeader)) return false;
   if (SessionId == null) {
     if (other.SessionId != null) return false;
   } else if (!SessionId.equals(other.SessionId)) return false;
   if (AuthenticationToken == null) {
     if (other.AuthenticationToken != null) return false;
   } else if (!AuthenticationToken.equals(other.AuthenticationToken)) return false;
   if (RevisedSessionTimeout == null) {
     if (other.RevisedSessionTimeout != null) return false;
   } else if (!RevisedSessionTimeout.equals(other.RevisedSessionTimeout)) return false;
   if (ServerNonce == null) {
     if (other.ServerNonce != null) return false;
   } else if (!ServerNonce.equals(other.ServerNonce)) return false;
   if (ServerCertificate == null) {
     if (other.ServerCertificate != null) return false;
   } else if (!ServerCertificate.equals(other.ServerCertificate)) return false;
   if (ServerEndpoints == null) {
     if (other.ServerEndpoints != null) return false;
   } else if (!Arrays.equals(ServerEndpoints, other.ServerEndpoints)) return false;
   if (ServerSoftwareCertificates == null) {
     if (other.ServerSoftwareCertificates != null) return false;
   } else if (!Arrays.equals(ServerSoftwareCertificates, other.ServerSoftwareCertificates))
     return false;
   if (ServerSignature == null) {
     if (other.ServerSignature != null) return false;
   } else if (!ServerSignature.equals(other.ServerSignature)) return false;
   if (MaxRequestMessageSize == null) {
     if (other.MaxRequestMessageSize != null) return false;
   } else if (!MaxRequestMessageSize.equals(other.MaxRequestMessageSize)) return false;
   return true;
 }
 @Override
 public int hashCode() {
   final int prime = 31;
   int result = 1;
   result = prime * result + ((ParentNodeId == null) ? 0 : ParentNodeId.hashCode());
   result = prime * result + ((ReferenceTypeId == null) ? 0 : ReferenceTypeId.hashCode());
   result = prime * result + ((RequestedNewNodeId == null) ? 0 : RequestedNewNodeId.hashCode());
   result = prime * result + ((BrowseName == null) ? 0 : BrowseName.hashCode());
   result = prime * result + ((NodeClass == null) ? 0 : NodeClass.hashCode());
   result = prime * result + ((NodeAttributes == null) ? 0 : NodeAttributes.hashCode());
   result = prime * result + ((TypeDefinition == null) ? 0 : TypeDefinition.hashCode());
   return result;
 }
 @Override
 public boolean equals(Object obj) {
   if (this == obj) return true;
   if (obj == null) return false;
   if (getClass() != obj.getClass()) return false;
   AddNodesResult other = (AddNodesResult) obj;
   if (StatusCode == null) {
     if (other.StatusCode != null) return false;
   } else if (!StatusCode.equals(other.StatusCode)) return false;
   if (AddedNodeId == null) {
     if (other.AddedNodeId != null) return false;
   } else if (!AddedNodeId.equals(other.AddedNodeId)) return false;
   return true;
 }
  public static void main(String[] args) throws Exception {

    System.out.println("Starting ClientPublisher sample");

    if (args.length < 2 || args.length > 3) {
      printHelp();
      return;
    }

    String opcUrl = args[0];
    String connString = args[1];
    IotHubClientProtocol protocol = IotHubClientProtocol.AMQPS;
    if (args.length > 2) {
      String protocolStr = args[2].toLowerCase();
      if (protocolStr.equals("https")) {
        protocol = IotHubClientProtocol.HTTPS;
      } else if (protocolStr.equals("amqps")) {
        protocol = IotHubClientProtocol.AMQPS;
      } else if (protocolStr.equals("mqtt")) {
        protocol = IotHubClientProtocol.MQTT;
      } else if (protocolStr.equals("amqps_ws")) {
        protocol = IotHubClientProtocol.AMQPS_WS;
      } else {
        System.out.format("Protocol: %s not found, using AMQPS instead\n", protocolStr);
      }
    }

    System.out.format("OPC Server: %s\n", opcUrl);
    System.out.format("IoT Hub ConnectionString: %s\n", connString);
    System.out.format("Start communication using protocol %s.\n", protocol.name());

    //////////////  CLIENT  //////////////
    // Load Client's Application Instance Certificate from file
    KeyPair myClientApplicationInstanceCertificate = getOPCCert("ClientPublisher");
    // Create Client
    Client myClient = Client.createClientApplication(myClientApplicationInstanceCertificate);

    ////////// DISCOVER ENDPOINT /////////
    // Discover server's endpoints, and choose one
    String publicHostname = InetAddress.getLocalHost().getHostName();

    EndpointDescription[] endpoints = myClient.discoverEndpoints(opcUrl);
    // Filter out all but opc.tcp protocol endpoints
    if (opcUrl.startsWith("opc.tcp")) {
      endpoints = selectByProtocol(endpoints, "opc.tcp");
      // Filter out all but Signed & Encrypted endpoints
      endpoints = selectByMessageSecurityMode(endpoints, MessageSecurityMode.SignAndEncrypt);
      // Filter out all but Basic128 cryption endpoints
      endpoints = selectBySecurityPolicy(endpoints, SecurityPolicy.BASIC128RSA15);
      // Sort endpoints by security level. The lowest level at the
      // beginning, the highest at the end of the array
      endpoints = sortBySecurityLevel(endpoints);
    } else {
      // we don't have a valid https cert for now
      System.out.format("HTTPS protocol not suported.\n");
      System.exit(0);
      endpoints = selectByProtocol(endpoints, "https");
    }

    // Choose one endpoint
    EndpointDescription endpoint = endpoints[endpoints.length - 1];

    // fix connection issue on localhost
    if (endpoint.getEndpointUrl().contains(publicHostname)) {
      endpoint.setEndpointUrl(endpoint.getEndpointUrl().replace(publicHostname, "localhost"));
    } else {
      // fix .Net UA Server bug, patch localhost with hostname of server
      if (endpoint.getEndpointUrl().contains("localhost")) {
        URL opcURL = new URL(opcUrl.replace("opc.tcp", "http"));
        endpoint.setEndpointUrl(endpoint.getEndpointUrl().replace("localhost", opcURL.getHost()));
      }
    }

    ////////////////////// AZURE IotHub ////////////////////////////
    // connect to Azure IotHub with connection string and protocol
    // see http://www.github.com/Azure/azure-iot-sdks/java
    //
    DeviceClient client = new DeviceClient(connString, protocol);

    System.out.println("Successfully created an IoT Hub client.");

    if (protocol == IotHubClientProtocol.MQTT) {
      MessageCallbackMqtt callback = new MessageCallbackMqtt();
      Counter counter = new Counter(0);
      client.setMessageCallback(callback, counter);
    } else {
      MessageCallback callback = new MessageCallback();
      Counter counter = new Counter(0);
      client.setMessageCallback(callback, counter);
    }
    System.out.println("Successfully set message callback.");

    client.open();

    System.out.println("Opened connection to IoT Hub.");

    System.out.println("Beginning to receive messages...");

    ////////////  SESSION  ////////////
    // Create Session
    SessionChannel mySession = myClient.createSessionChannel(endpoint);
    mySession.activate();

    System.out.println("Opened session to OPC Server.");

    /////////////  EXECUTE  //////////////
    // Browse Root
    BrowseDescription browse = new BrowseDescription();
    browse.setNodeId(Identifiers.RootFolder);
    browse.setBrowseDirection(BrowseDirection.Forward);
    browse.setIncludeSubtypes(true);
    browse.setNodeClassMask(NodeClass.Object, NodeClass.Variable);
    browse.setResultMask(BrowseResultMask.All);
    BrowseResponse browseResponse = mySession.Browse(null, null, null, browse);
    System.out.println(browseResponse);

    /////////////  PUBLISH  /////////////
    // Poll OPC server and publish to Azure IotHub

    int count = 0;
    while (count++ < 100) {
      // Read current time
      NodeId nodeId = Identifiers.Server_ServerStatus_CurrentTime;
      ReadResponse opcCurrentTime =
          mySession.Read(
              null,
              500.0,
              TimestampsToReturn.Both,
              new ReadValueId(nodeId, Attributes.Value, null, null));

      // convert node to JSON
      JSONObject obj = new JSONObject();
      obj.put("Id", nodeId.toString());
      obj.put("Uri", endpoints[0].getServer().getApplicationUri());

      JSONObject value = new JSONObject();
      value.put("Value", opcCurrentTime.getResults()[0].getValue().toString());
      value.put("SourceTimestamp", opcCurrentTime.getResults()[0].getSourceTimestamp().toString());
      value.put("ServerTimestamp", opcCurrentTime.getResults()[0].getServerTimestamp().toString());

      JSONObject monitoredItem = new JSONObject();
      monitoredItem.put("MonitoredItem", obj);
      monitoredItem.put("ClientHandle", 2);
      monitoredItem.put("Value", value);

      // publish JSON string to IotHub
      String msgStr = monitoredItem.toString();
      try {
        Message msg = new Message(msgStr);
        msg.setProperty("messageCount", Integer.toString(count));
        msg.setExpiryTime(5000);
        System.out.println(msgStr);
        EventCallback eventCallback = new EventCallback();
        client.sendEventAsync(msg, eventCallback, count);
      } catch (Exception e) {
        e.printStackTrace();
      }

      try {
        System.out.println(opcCurrentTime);
        System.out.println(msgStr);
        Thread.sleep(2000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }

    /////////////  SHUTDOWN  /////////////
    mySession.close();
    mySession.closeAsync();
    //////////////////////////////////////

    client.close();

    //////////////////////////////////////
    System.exit(0);
  }