Building a Realtime AngularJS Dashboard using Spring Rest and MongoDB — Part 3

Building a Realtime AngularJS Dashboard using Spring Rest and MongoDB — Part 3

This post is a continuation of where we left off from our previous post “Building a Realtime AngularJS Dashboard using Spring Rest and MongoDB — Part 2”.

Our Realtime Dashboard AngularJS Application

DashboardCpu

The Model Class for Process (Process.java)

package com.avaldes.model;

public class Process {
  private long threads;
  private long stopped_procs;
  private long idle_procs;
  private long sleeping_procs;
  private long running_procs;
  private long zombie_procs;
  private long total_procs;
  private long creationTime;
  
  public long getThreads() {
    return threads;
  }
  
  public Process(long threads, long stopped_procs, long idle_procs,
      long sleeping_procs, long running_procs, long zombie_procs,
      long total_procs, long creationTime) {
    super();
    this.threads = threads;
    this.stopped_procs = stopped_procs;
    this.idle_procs = idle_procs;
    this.sleeping_procs = sleeping_procs;
    this.running_procs = running_procs;
    this.zombie_procs = zombie_procs;
    this.total_procs = total_procs;
    this.creationTime = creationTime;
  }

  public void setThreads(long threads) {
    this.threads = threads;
  }
  
  public long getStopped_procs() {
    return stopped_procs;
  }
  
  public void setStopped_procs(long stopped_procs) {
    this.stopped_procs = stopped_procs;
  }
  
  public long getIdle_procs() {
    return idle_procs;
  }
  
  public void setIdle_procs(long idle_procs) {
    this.idle_procs = idle_procs;
  }
  
  public long getSleeping_procs() {
    return sleeping_procs;
  }
  
  public void setSleeping_procs(long sleeping_procs) {
    this.sleeping_procs = sleeping_procs;
  }
  
  public long getRunning_procs() {
    return running_procs;
  }
  
  public void setRunning_procs(long running_procs) {
    this.running_procs = running_procs;
  }
  
  public long getZombie_procs() {
    return zombie_procs;
  }
  
  public void setZombie_procs(long zombie_procs) {
    this.zombie_procs = zombie_procs;
  }
  
  public long getTotal_procs() {
    return total_procs;
  }
  
  public void setTotal_procs(long total_procs) {
    this.total_procs = total_procs;
  }
  
  public long getCreationTime() {
    return creationTime;
  }
  
  public void setCreationTime(long creationTime) {
    this.creationTime = creationTime;
  }

  @Override
  public String toString() {
    return "Process [threads=" + threads + ", stopped_procs="
      + stopped_procs + ", idle_procs=" + idle_procs
      + ", sleeping_procs=" + sleeping_procs + ", running_procs="
      + running_procs + ", zombie_procs=" + zombie_procs
      + ", total_procs=" + total_procs + ", creationTime="
      + creationTime + "]";
  } 
}

The Model Class for Statistics (Statistics.java)

package com.avaldes.model;

import java.io.Serializable;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import org.codehaus.jackson.annotate.JsonProperty;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

@Document
@XmlRootElement(name = "statistics")
public class Statistics implements Serializable {
  private static final long serialVersionUID = -1982982909309202L;

  @Id private String id;
  private String todayHeading;
  private int todayCount;
  private double todayAverage;
  private String todayAverageSubheading;
  private String onboardedHeading;
  private int onboardedCount;
  private String onboardedSubheading;
  private String signupsHeading;
  private int signupsCount;
  private String signupsSubheading;

  @XmlElement(name="id", type=String.class) 
  @JsonProperty("id")
  public String getId() {
    return id;
  }

  public void setId(String id) {
    this.id = id;
  }
  
  @XmlElement(name="today_heading", type=String.class) 
  @JsonProperty("today_heading")
  public String getTodayHeading() {
    return todayHeading;
  }

  public void setTodayHeading(String todayHeading) {
    this.todayHeading = todayHeading;
  }

  @XmlElement(name="today_count") 
  @JsonProperty("today_count")
  public int getTodayCount() {
    return todayCount;
  }

  public void setTodayCount(int todayCount) {
    this.todayCount = todayCount;
  }

  @XmlElement(name="today_avg") 
  @JsonProperty("today_avg")
  public double getTodayAverage() {
    return todayAverage;
  }

  public void setTodayAverage(double todayAverage) {
    this.todayAverage = todayAverage;
  }

  @XmlElement(name="today_avg_subheading", type=String.class) 
  @JsonProperty("today_avg_subheading")
  public String getTodayAverageSubheading() {
    return todayAverageSubheading;
  }

  public void setTodayAverageSubheading(String todayAverageSubheading) {
    this.todayAverageSubheading = todayAverageSubheading;
  }

  @XmlElement(name="onboarded_heading", type=String.class) 
  @JsonProperty("onboarded_heading")
  public String getOnboardedHeading() {
    return onboardedHeading;
  }

  public void setOnboardedHeading(String onboardedHeading) {
    this.onboardedHeading = onboardedHeading;
  }

  @XmlElement(name="onboarded_count") 
  @JsonProperty("onboarded_count")
  public int getOnboardedCount() {
    return onboardedCount;
  }

  public void setOnboardedCount(int onboardedCount) {
    this.onboardedCount = onboardedCount;
  }

  @XmlElement(name="onboarded_subheading", type=String.class) 
  @JsonProperty("onboarded_subheading")
  public String getOnboardedSubheading() {
    return onboardedSubheading;
  }

  public void setOnboardedSubheading(String onboardedSubheading) {
    this.onboardedSubheading = onboardedSubheading;
  }

  @XmlElement(name="signups_heading", type=String.class) 
  @JsonProperty("signups_heading")
  public String getSignupsHeading() {
    return signupsHeading;
  }

  public void setSignupsHeading(String signupsHeading) {
    this.signupsHeading = signupsHeading;
  }

  @XmlElement(name="signups_count") 
  @JsonProperty("signups_count")
  public int getSignupsCount() {
    return signupsCount;
  }

  public void setSignupsCount(int signupsCount) {
    this.signupsCount = signupsCount;
  }

  @XmlElement(name="signups_subheading", type=String.class) 
  @JsonProperty("signups_subheading")
  public String getSignupsSubheading() {
    return signupsSubheading;
  }

  public void setSignupsSubheading(String signupsSubheading) {
    this.signupsSubheading = signupsSubheading;
  }

  @Override
  public String toString() {
    return "Statistics [id=" + id + ", todayHeading=" 
      + todayHeading + ", todayCount=" + todayCount
      + ", todayAverage=" + todayAverage 
      + ", todayAverageSubheading=" + todayAverageSubheading
      + ", onboardingHeading=" + onboardedHeading 
      + ", onboardedCount=" + onboardedCount 
      + ", onboardedSubheading=" + onboardedSubheading 
      + ", signupsHeading=" + signupsHeading
      + ", signupsCount=" + signupsCount 
      + ", signupsSubheading=" + signupsSubheading + "]";
  }
}

The Model Class for Swap (Swap.java)

package com.avaldes.model;

public class Swap {
  private long swapTotal;
  private long swapUsed;
  private long swapFree;
  private long creationTime;
  
  public Swap(long swapTotal, long swapUsed, long swapFree) {
    long now = System.currentTimeMillis();
    
    this.swapTotal = swapTotal;
    this.swapUsed = swapUsed;
    this.swapFree = swapFree;
    this.creationTime = now;
  }
  
  public long getSwapTotal() {
    return swapTotal;
  } 

  public void setSwapTotal(long swapTotal) {
    this.swapTotal = swapTotal;
  }
  
  public long getSwapUsed() {
    return swapUsed;
  }
  
  public void setSwapUsed(long swapUsed) {
    this.swapUsed = swapUsed;
  }
  
  public long getSwapFree() {
    return swapFree;
  }
  
  public void setSwapFree(long swapFree) {
    this.swapFree = swapFree;
  }

  public long getCreationTime() {
    return creationTime;
  }

  public void setCreationTime(long creationTime) {
    this.creationTime = creationTime;
  }

  @Override
  public String toString() {
    return "Swap [swapTotal=" + swapTotal 
      + ", swapUsed=" + swapUsed + ", swapFree=" 
      + swapFree + ", creationTime=" + creationTime
      + "]";
  }
}

Controller Class (RestController.java)

Our RestController class is the main class that contains all web service mapping end points defined in our table above. The @Controller annotation indicates that this particular class is playing the role of a controller.

package com.avaldes.service;
 
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Date;

import org.hyperic.sigar.FileSystem;
import org.hyperic.sigar.SigarException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.avaldes.dao.DashboardRepository;
import com.avaldes.model.DiskStatistics;
import com.avaldes.model.Disks;
import com.avaldes.model.Heartbeat;
import com.avaldes.model.JvmStatistics;
import com.avaldes.model.NetworkInterfaceDetails;
import com.avaldes.model.NetworkInterfaceStats;
import com.avaldes.model.NetworkInterfaces;
import com.avaldes.model.OperatingSystemDetails;
import com.avaldes.model.Statistics;
import com.avaldes.util.JvmStatisticsUtility;
 
/**
 * Handles requests for the application home page.
 */
@Controller
public class RestController {
 
  private static final Logger logger = LoggerFactory.getLogger(RestController.class);
  public static final String APPLICATION_JSON = "application/json";
  public static final String APPLICATION_XML = "application/xml";
  public static final String APPLICATION_HTML = "text/html";
  private Heartbeat heartbeat = null;
  
  @Autowired 
  private DashboardRepository dashboardRepository; 

  public RestController() {
    InetAddress ip;
    
    heartbeat = new Heartbeat();
    try {
				ip = InetAddress.getLocalHost();
				heartbeat.setIpAddress(ip.getHostAddress());
				logger.info("Your current IP address : " + ip.getHostAddress());
		} catch (UnknownHostException e) {
				e.printStackTrace();
		}
    
    logger.info("Heartbeat = " + heartbeat);
  }
  
  /**
   * Simply selects the home view to render by returning its name.
 
   */
  @RequestMapping(value = "/status", method = RequestMethod.GET, produces=APPLICATION_HTML)
  public @ResponseBody String status() {
    return "Dashboard Backend Status OK...";
  }

  @RequestMapping(value="/statistics", method=RequestMethod.GET, 
			produces={APPLICATION_JSON,APPLICATION_XML})
  public @ResponseBody Statistics getStatistics() {
    logger.info("Inside getStatistics() method...");
 
    Statistics stats = dashboardRepository.getStatisticsByID("1");
    //logger.info("stats: " + stats);
    return stats;
  }

  @RequestMapping(value="/cpu", method=RequestMethod.GET, 
			produces={APPLICATION_JSON,APPLICATION_XML})
  public @ResponseBody JvmStatistics getJVMStatistics() {
    JvmStatistics jvm = null;
    
    JvmStatisticsUtility jvmstats = JvmStatisticsUtility.getInstance();
    try {
      jvm  = jvmstats.getJVMStatistics("State.Name.sw=java"); 
		} catch (SigarException e) {
			logger.error(e.getMessage()); 
		}
    
    return jvm;
  }
  
  @RequestMapping(value="/osdetails", method=RequestMethod.GET, produces={APPLICATION_JSON,APPLICATION_XML})
  public @ResponseBody OperatingSystemDetails getOSDetails() {
    OperatingSystemDetails osDetails = null;
    
    JvmStatisticsUtility jvmstats = JvmStatisticsUtility.getInstance();
    osDetails  = jvmstats.getOSDetails();
  return osDetails;   
  }
  
  @RequestMapping(value="/getallnetworkinterfaces", method=RequestMethod.GET, 
			produces={APPLICATION_JSON,APPLICATION_XML})
  public @ResponseBody NetworkInterfaces getAllNetworkInterfaces(
      @RequestParam(value="is_filtered", defaultValue="true") boolean isActive) {
		NetworkInterfaces networkInterfaces = null;
   
    JvmStatisticsUtility jvmstats = JvmStatisticsUtility.getInstance();
  networkInterfaces  = jvmstats.getAllNetInterfaces(isActive);

  return networkInterfaces;   
  }
  
  @RequestMapping(value="/getnetworkstats", method=RequestMethod.GET, 	
			produces={APPLICATION_JSON,APPLICATION_XML})
  public @ResponseBody NetworkInterfaceStats getNetworkInterfaceStats
												(@RequestParam("interface") String netInterface) {
												
    NetworkInterfaceStats networkInterfaceStats = null;
    
    JvmStatisticsUtility jvmstats = JvmStatisticsUtility.getInstance();
    try {
    networkInterfaceStats  = jvmstats.getNetworkInterfaceStats(netInterface);
  } catch (SigarException e) {
    e.printStackTrace();
  }

  return networkInterfaceStats;   
  }
  
  @RequestMapping(value="/networkdetails", method=RequestMethod.GET, 
			produces={APPLICATION_JSON,APPLICATION_XML})
  public @ResponseBody NetworkInterfaceDetails getNetworkDetails
			(@RequestParam("interface") String netInterface) {
			
		NetworkInterfaceDetails networkDetails = null;
    
    JvmStatisticsUtility jvmstats = JvmStatisticsUtility.getInstance();
    try {
			networkDetails  = jvmstats.getNetInterfaceDetails(netInterface);
		} catch (SigarException e) {
			e.printStackTrace();
		}
		return networkDetails;  
  }

  @RequestMapping(value="/getalldisks", method=RequestMethod.GET, 
			produces={APPLICATION_JSON,APPLICATION_XML})
  public @ResponseBody Disks getGetAllDisks() {
  DiskStatistics diskDetails = null;
  FileSystem[] fsList = null;
    
    JvmStatisticsUtility jvmstats = JvmStatisticsUtility.getInstance();
    fsList  = jvmstats.getAllFileSystemList();
    Disks allDisks = new Disks();
    for (FileSystem fs: fsList) {
      String drive = fs.getDirName();
      double percent = 0;
      boolean isOnline = false;
      try {
          diskDetails  = jvmstats.getDiskDetails(drive);
          percent = diskDetails.getUsePercentage();
          isOnline = true;
      } catch (SigarException e) {
        isOnline = false;
      }
      allDisks.addDrive(fs.getDirName(), fs.getDevName(), fs.getTypeName(), fs.getSysTypeName(),
                fs.getOptions(), fs.getType(), fs.getFlags(), isOnline, percent*100.0);
    }
    
  return allDisks;  
  }
  
  @RequestMapping(value="/diskdetails", method=RequestMethod.GET, produces={APPLICATION_JSON,APPLICATION_XML})
  public @ResponseBody DiskStatistics getDiskDetails(@RequestParam("drive") String drive) {
    DiskStatistics diskDetails = null;
    
    JvmStatisticsUtility jvmstats = JvmStatisticsUtility.getInstance();
    try {
      diskDetails  = jvmstats.getDiskDetails(drive);
		} catch (SigarException e) {
			e.printStackTrace();
		}
		return diskDetails;   
  }
  
  @RequestMapping(value="/heartbeat", method=RequestMethod.GET, produces={APPLICATION_JSON,APPLICATION_XML})
  public @ResponseBody Heartbeat genHeartbeartAndBroadcast() {
    Date now = new Date();
    heartbeat.setCount(heartbeat.getCount()+1);
    heartbeat.setCurrentDate(now);
    
    return heartbeat;
  }
    
  @RequestMapping(value="/resetheartbeat", method=RequestMethod.GET, produces={APPLICATION_JSON,APPLICATION_XML})
  public @ResponseBody Heartbeat resetHeartbeatAndBroadcast() {
    Date now = new Date();
    heartbeat.setCount(1);      // Reset back to 1
    heartbeat.setStartDate(now);
    heartbeat.setCurrentDate(now);
    
    return heartbeat;
  } 
}

Web Deployment Descriptor (web.xml)

Our web.xml is quite straight forward. Here we define our DispatcherServlet servlet, define our servlet’s application context and define what our URL pattern is going to be for the dispatcher. I have configured Welcome files here so that the application can use the partial URI and start the dashboard upon entry using the URL: http://localhost:8080/MyDashboard/ .

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
  <display-name>MyDashboard</display-name>
  
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
  </welcome-file-list>
    
  <context-param>
    <param-name>log4jConfigLocation</param-name>
    <param-value>classpath:log4j.xml</param-value>
  </context-param>
  
  <servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/dispatcher-servlet.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  
  <servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/rest/*</url-pattern>
  </servlet-mapping>
</web-app>

Configure Spring Web DispatcherServlet (dispatcher-servlet.xml)

Modify the dispatcher-servlet.xml and add the necessary MongoDB configurations. You will notice that I have added MongoTemplate which is used for the mongo operations and MongoFactoryBean which creates the mongo instance to our dispatcher-servlet.xml. MongoTemplate is configured to use the database settings via MongoFactoryBean.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:mvc="http://www.springframework.org/schema/mvc"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:context="http://www.springframework.org/schema/context"
  xmlns:websocket="http://www.springframework.org/schema/websocket"

  xsi:schemaLocation="
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/websocket
    http://www.springframework.org/schema/websocket/spring-websocket-4.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-4.0.xsd">
 
  <!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
 
  <!-- Enables the Spring MVC @Controller programming model -->
  <!-- <beans:bean annotation-driven /> -->
  <mvc:annotation-driven />
 
  <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
  <mvc:resources mapping="/resources/**" location="/resources/" />
 
  <!-- Define the MongoTemplate which handles connectivity with MongoDB -->
  <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
    <constructor-arg name="mongo" ref="mongo" />
    <constructor-arg name="databaseName" value="dashboard" />
  </bean>
  
  <!-- Factory bean that creates the MongoDB instance -->
  <bean id="mongo" class="org.springframework.data.mongodb.core.MongoFactoryBean">
    <property name="host" value="localhost"/>
  </bean>
 
  <!-- Use this post processor to translate any MongoExceptions thrown in @Repository annotated classes -->
  <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
 
  <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="messageConverters">
        <list>
            <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
        </list>
    </property>
</bean>

<context:component-scan base-package="com.avaldes" /> 
 
</beans>

JSON Books Documents

I am including JSON documents in the event that you may want to pre-populate your MongoDB collection.

{
    "_id" : "1",
    "todayHeading" : "API Calls Today",
    "todayCount" : 8651,
    "todayAverage" : 13.560,
    "todayAverageSubheading" : "Daily Average Duration",
    "onboardedHeading" : "New Hires",
    "onboardedCount" : 71,
    "onboardedSubheading" : "Number of users recently hired",
    "signupsHeading" : "New Sales",
    "signupsCount" : 96,
    "signupsSubheading" : "Number of sales initiated"
}

Let’s Test out the Spring MVC REST API calls

For this server-side test, I will be using I’m Only Resting application from Swen Sen Software.

Download the Code

That’s It!

I hope you enjoyed this tutorial. It was certainly a lot of fun putting it together and testing it out. Please continue to share the love and like us so that we can continue bringing you quality tutorials. Happy Coding!!!

Associated Posts

spring_mvc_angular_dashboard

Please Share Us on Social Media

Facebooktwitterredditpinterestlinkedinmail

Leave a Reply

Your email address will not be published. Required fields are marked *