@GET
 @Produces(MediaType.APPLICATION_JSON)
 @Path("{nodeName}/status")
 public Response getStatus(@PathParam("nodeName") String nodeName) {
   Response response = null;
   try {
     org.nikhil.webapp.nodeadmin.entity.Node fetchedNode = nodeOperation.getNode(nodeName);
     String status = nodeOperation.getNodeStatus(nodeName, true);
     Object jsonObj = NodeAdminUtils.createObjectFromRawData("status", status, null);
     response =
         NodeAdminUtils.buildStandardRESTHTTPResponse(
             200, "Node " + nodeName + " Status Retrieved Successfully", status, null);
   } catch (Exception e) {
     e.printStackTrace();
     response =
         NodeAdminUtils.buildStandardRESTHTTPResponse(
             500, "Server Error getting the status of the Node " + nodeName, null, null);
   }
   return response;
 }
  @POST
  @Produces(MediaType.APPLICATION_JSON)
  public Response addNode(Node node) {
    Response response = null;
    try {
      org.nikhil.webapp.nodeadmin.entity.Node newNode = getJPANodeFromJSONNode(node);
      nodeOperation.addNode(newNode);
      response =
          NodeAdminUtils.buildStandardRESTHTTPResponse(
              201, "Node " + node.getName() + " Added Successfully", null, null);

    } catch (Exception e) {
      e.printStackTrace();
      response =
          NodeAdminUtils.buildStandardRESTHTTPResponse(500, "Server Error Adding Node", null, null);
    }
    return response;
  }
 @GET
 @Produces(MediaType.APPLICATION_JSON)
 @Path("{nodeName}/stop")
 public Response stop(@PathParam("nodeName") String nodeName) {
   Response response = null;
   try {
     nodeOperation.reStartNode(nodeName);
     response =
         NodeAdminUtils.buildStandardRESTHTTPResponse(
             200, "Node " + nodeName + " Stopped Successfully", null, null);
   } catch (Exception e) {
     e.printStackTrace();
     response =
         NodeAdminUtils.buildStandardRESTHTTPResponse(
             500, "Server Error Stopping the Node " + nodeName, null, null);
   }
   return response;
 }
  @DELETE
  @Produces(MediaType.APPLICATION_JSON)
  @Path("/{nodeName}")
  public Response deleteNode(@PathParam("nodeName") String nodeName) {
    Response response = null;
    try {
      nodeOperation.deleteNode(nodeName);
      response =
          NodeAdminUtils.buildStandardRESTHTTPResponse(
              200, "Node " + nodeName + " Deleted Successfully", null, null);

    } catch (Exception e) {
      e.printStackTrace();
      response =
          NodeAdminUtils.buildStandardRESTHTTPResponse(
              500, "Server Error Deleting Node", null, null);
    }

    return response;
  }
  @GET
  @Produces(MediaType.APPLICATION_JSON)
  public Response getNodes() {
    Response response = null;

    try {
      List<Node> flattenedNodeList = new ArrayList<>();
      List<org.nikhil.webapp.nodeadmin.entity.Node> list = nodeOperation.listNodes();
      for (org.nikhil.webapp.nodeadmin.entity.Node node : list) {
        flattenedNodeList.add(getNodeJSONFromNodeEntity(node));
      }
      response =
          NodeAdminUtils.buildStandardRESTHTTPResponseForCollection(
              200, "Node List Retrieved Successfully", flattenedNodeList, null);
    } catch (Exception e) {
      e.printStackTrace();
      response =
          NodeAdminUtils.buildStandardRESTHTTPResponse(
              500, "Server Error Retrieving Node List", null, null);
    }
    return response;
  }
 @GET
 @Produces(MediaType.APPLICATION_JSON)
 @Path("/{nodeName}")
 public Response getANode(@PathParam("nodeName") String nodeName) {
   Response response = null;
   try {
     org.nikhil.webapp.nodeadmin.entity.Node fetchedNode = nodeOperation.getNode(nodeName);
     if (fetchedNode == null) {
       response = NodeAdminUtils.buildStandardRESTHTTPResponse(404, "No Such Node", null, null);
     } else {
       Node flattenedNode = getNodeJSONFromNodeEntity(fetchedNode);
       response =
           NodeAdminUtils.buildStandardRESTHTTPResponse(
               200, "Node Retrieved Successfully", flattenedNode, null);
     }
   } catch (Exception e) {
     e.printStackTrace();
     response =
         NodeAdminUtils.buildStandardRESTHTTPResponse(
             500, "Server Error Retrieving Node " + nodeName, null, null);
   }
   return response;
 }
  /**
   * Creates or fetches a JPA Node Entity for JSON Node Used for PUT and POST Requests for
   * NodeResource The services and commands are updated from that of the JSON Node
   *
   * @param nodeEntity
   * @return
   */
  public org.nikhil.webapp.nodeadmin.entity.Node getJPANodeFromJSONNode(Node jsonNode) {

    String nodeName = jsonNode.getName();
    org.nikhil.webapp.nodeadmin.entity.Node jpaNode = nodeOperation.getNode(nodeName);
    boolean addingANode = false;
    boolean prevServicesPresent = false;
    boolean prevCmmandsPresent = false;

    if (jpaNode == null) {
      // Create Mode
      jpaNode = new org.nikhil.webapp.nodeadmin.entity.Node();
      jpaNode.setName(nodeName);
      addingANode = true;
    }
    // create / update Mode
    jpaNode.setDescription(jsonNode.getDescription());
    jpaNode.setIpAddress(jsonNode.getIpAddress());
    jpaNode.setMaster(jsonNode.isMaster());
    jpaNode.setUserName(jsonNode.getUserName());
    jpaNode.setPassword(jsonNode.getPassword());
    jpaNode.setShutdownTimer(jsonNode.getShutdownTimer());
    jpaNode.setRestartTimer(jsonNode.getRestartTimer());
    jpaNode.setStatus(jsonNode.getStatus());

    /*		Add or Update the existing NodeService relationships
    	optimizing single fetch for node services
    */
    List<NodeAndService> nodeAssiginedServices = jpaNode.getNodeServices();

    if (jsonNode.getServices().size() > 0) {
      prevServicesPresent = true;
      for (Service jsonService : jsonNode.getServices()) {
        org.nikhil.webapp.nodeadmin.entity.Service jpaService = null;
        org.nikhil.webapp.nodeadmin.entity.NodeAndService jpaNodeAndService = null;
        boolean serviceFoundAlreadyLinked = false;

        if (nodeAssiginedServices.size() > 0) {
          for (org.nikhil.webapp.nodeadmin.entity.NodeAndService fetchedNodeAndService :
              nodeAssiginedServices) {
            if (fetchedNodeAndService
                .getCompositePK()
                .getService()
                .getName()
                .equals(jsonService.getName())) {
              jpaNodeAndService = fetchedNodeAndService;
              serviceFoundAlreadyLinked = true;
              break;
            }
          }
        }
        // Add service relationship for current json service
        if (!serviceFoundAlreadyLinked || nodeAssiginedServices.size() == 0) {
          jpaService = serviceOperation.getService(jsonService.getName());
          jpaNodeAndService = new NodeAndService();
          jpaNodeAndService.setCompositePK(new NodeAndServiceId(jpaNode, jpaService));
          // adding relationship
          jpaNode.getNodeServices().add(jpaNodeAndService);
        }

        // so here we have jpanodeandservice identified either new and added or retrieved from node
        // itself - update it now
        jpaNodeAndService.setAdditionalRunParamsStart(jsonService.getAdditionalRunParamsStart());
        jpaNodeAndService.setAdditionalRunParamsStop(jsonService.getAdditionalRunParamsStop());
        jpaNodeAndService.setStatusWildCardOverride(jsonService.getStatusWildCardOverride());
        jpaNodeAndService.setStatusCommandOverride(jsonService.getStatusCommandOverride());
        jpaNodeAndService.setRundir(jsonService.getRundir());
        jpaNodeAndService.setRunning(jsonService.isRunning());
      }

      /* delete the relationships that are not part of new assignment
       * if adding a node all service relationships are new so no need to delete anything from jpaNode
       */
      if (prevServicesPresent && !addingANode) {
        int index = 0;
        ArrayList<Integer> deleteIndices = new ArrayList<Integer>();
        for (org.nikhil.webapp.nodeadmin.entity.NodeAndService fetchedNodeAndService :
            nodeAssiginedServices) {

          boolean serviceMatched = false;
          for (Service jsonService : jsonNode.getServices()) {
            if (fetchedNodeAndService
                .getCompositePK()
                .getService()
                .getName()
                .equals(jsonService.getName())) {
              serviceMatched = true;
              break;
            }
          }

          if (!serviceMatched) {
            deleteIndices.add(index);
          }
          index++;
        }

        // delete unmatched services
        for (Integer indexToDelete : deleteIndices) {
          nodeAssiginedServices.remove(indexToDelete.intValue());
        }
      }
    }

    List<NodeAndCommand> nodeAssiginedCommands = jpaNode.getNodeCommands();

    if (jsonNode.getCommands().size() > 0) {
      prevCmmandsPresent = true;
      for (Command jsonCommand : jsonNode.getCommands()) {
        org.nikhil.webapp.nodeadmin.entity.Command jpaCommand = null;
        org.nikhil.webapp.nodeadmin.entity.NodeAndCommand jpaNodeAndCommand = null;
        boolean commandFoundAlreadyLinked = false;

        if (nodeAssiginedCommands.size() > 0) {
          for (org.nikhil.webapp.nodeadmin.entity.NodeAndCommand fetchedNodeAndCommand :
              nodeAssiginedCommands) {
            if (fetchedNodeAndCommand
                .getCompositePK()
                .getCommand()
                .getName()
                .equals(jsonCommand.getName())) {
              jpaNodeAndCommand = fetchedNodeAndCommand;
              commandFoundAlreadyLinked = true;
              break;
            }
          }
        }
        // Add command relationship for current json command
        if (!commandFoundAlreadyLinked || nodeAssiginedCommands.size() == 0) {
          jpaCommand = commandOperation.getCommand(jsonCommand.getName());
          jpaNodeAndCommand = new NodeAndCommand();
          jpaNodeAndCommand.setCompositePK(new NodeAndCommandId(jpaNode, jpaCommand));
          // adding relationship
          jpaNode.getNodeCommands().add(jpaNodeAndCommand);
        }

        // so here we have jpanodeandcommand identified either new and added or retrieved from node
        // itself - update it now
        jpaNodeAndCommand.setAdditionalRunParams(jsonCommand.getAdditionalRunParams());
        jpaNodeAndCommand.setAlwaysRunInBackground(jsonCommand.isAlwaysRunInBackground());
        jpaNodeAndCommand.setRundir(jsonCommand.getRundir());
      }

      /* delete the relationships that are not part of new assignment
       * if adding a node all command relationships are new so no need to delete anything from jpaNode
       */
      if (prevCmmandsPresent && !addingANode) {
        int index = 0;
        ArrayList<Integer> deleteIndices = new ArrayList<Integer>();
        for (org.nikhil.webapp.nodeadmin.entity.NodeAndCommand fetchedNodeAndCommand :
            nodeAssiginedCommands) {

          boolean commandMatched = false;
          for (Command jsonCommand : jsonNode.getCommands()) {
            if (fetchedNodeAndCommand
                .getCompositePK()
                .getCommand()
                .getName()
                .equals(jsonCommand.getName())) {
              commandMatched = true;
              break;
            }
          }

          if (!commandMatched) {
            deleteIndices.add(index);
          }
          index++;
        }

        // delete unmatched commands
        for (Integer indexToDelete : deleteIndices) {
          nodeAssiginedCommands.remove(indexToDelete.intValue());
        }
      }
    }

    return jpaNode;
  }