http://cloudsole-metrics.herokuapp.com
https://github.com/thysmichels/cloudsole-metrics
1. Basic WebAppInitializer
2. WebConfiguration with EnableScheduling
3. WebSocketConfiguration with EnableWebSocketMessageBroker
4. Random Number Generator with ApplicationListener
5. Sock.js Javascript
1. Basic WebAppInitializer
package com.thysmichels.websockets.configuration; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRegistration; import org.springframework.web.WebApplicationInitializer; import org.springframework.web.context.ContextLoaderListener; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.context.support.GenericWebApplicationContext; import org.springframework.web.servlet.DispatcherServlet; public class WebAppInitializer implements WebApplicationInitializer { @Override public void onStartup(final ServletContext context) throws ServletException { final AnnotationConfigWebApplicationContext root = new AnnotationConfigWebApplicationContext(); root.scan("com.thysmichels.websockets"); context.addListener(new ContextLoaderListener(root)); final ServletRegistration.Dynamic appServlet = context.addServlet("appServlet",new DispatcherServlet(new GenericWebApplicationContext())); appServlet.setAsyncSupported(true); appServlet.setLoadOnStartup(1); appServlet.addMapping("/*"); } }
2. WebConfiguration with EnableScheduling
package com.thysmichels.websockets.configuration; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @Configuration @EnableWebMvc @EnableScheduling public class WebConfiguration extends WebMvcConfigurerAdapter { @Override public void configureDefaultServletHandling( final DefaultServletHandlerConfigurer configurer) { configurer.enable(); } }
3. WebSocketConfiguration with EnableWebSocketMessageBroker
package com.thysmichels.websockets.configuration; import org.springframework.context.annotation.Configuration; import org.springframework.messaging.simp.config.ChannelRegistration; import org.springframework.messaging.simp.config.MessageBrokerRegistry; import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; import org.springframework.web.socket.config.annotation.StompEndpointRegistry; import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; @Configuration @EnableWebSocketMessageBroker public class WebSocketConfiguration implements WebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { } @Override public void registerStompEndpoints(final StompEndpointRegistry registry) { registry.addEndpoint("/metrics").withSockJS(); } @Override public void configureClientInboundChannel(final ChannelRegistration registration) {} @Override public void configureClientOutboundChannel(final ChannelRegistration registration) { } }
4. Random Number Generator with ApplicationListener
package com.thysmichels.websockets.utils; import java.util.Random; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.messaging.core.MessageSendingOperations; import org.springframework.messaging.simp.broker.BrokerAvailabilityEvent; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component public class RandomDataGenerator implements ApplicationListener<BrokerAvailabilityEvent> { private final MessageSendingOperations<String> messagingTemplate; @Autowired public RandomDataGenerator(final MessageSendingOperations<String> messagingTemplate) { this.messagingTemplate = messagingTemplate; } @Override public void onApplicationEvent(final BrokerAvailabilityEvent event) { } @Scheduled(fixedDelay = 1000) public void sendDataUpdates() { this.messagingTemplate.convertAndSend("/data", new Random().nextInt(100)); } }
5. Sock.js Javascript
/** * Created by tmichels on 8/19/14. */ //var stompClient = null; var updateOpts = {'minVal':'0','maxVal':'100','newVal':'1'}; var randomData; var socket = new SockJS('/metrics'); var client = Stomp.over(socket); client.connect('admin', 'password', function(frame) { client.subscribe("/data", function(message) { var point = [ (new Date()).getTime(), parseInt(message.body) ]; gaugeUpdate('cf-gauge-1', {'minVal':'0','maxVal':'100','newVal':parseInt(message.body)}) $('#spark-1').each(function(){ customSparkOptions = {}; customSparkOptions.minSpotColor = true; var sparkOptions = cf_defaultSparkOpts; var sparkOptions = $.extend({}, cf_defaultSparkOpts, customSparkOptions); data.push(parseInt(message.body)); createSparkline($(this), data, sparkOptions); }); $('#metric-1 .metric').html(message.body); $('#metric-1 .large').html(message.body); $('#metric-2 .metric').html(message.body); $('#metric-2 .large').html(message.body); var element = $(this).data('update'); cf_rSVPs[$('#svp-1').attr('id')].chart.update(parseInt(message.body)); $('#svp-1 .chart').data('percent', parseInt(message.body)); $('#svp-1 .metric').html(message.body); // $('#cf-svmc-sparkline .metric').html(message.body); $('#cf-rag-1').each(function(){ // Dummy data for RAG ragData = [60,30,parseInt(message.body)]; ragLabels = ['Success','Bounce','Abandoned']; ragOpts = {postfix:'%'} cf_rRags[$(this).prop('id')] = new RagChart($(this).prop('id'), ragData, ragLabels, ragOpts); }); $('#cf-pie-1').each(function(){ var pdata = [ { value : parseInt(message.body), color : pieSegColors[3], label: 'Success' }, { value : parseInt(message.body)+50, color : pieSegColors[2], label: 'Bounce' }, { value: parseInt(message.body)+100, color: pieSegColors[1], label: 'Abandoned' } ] var $container = $(this); var pId = $container.prop('id'); // Store chart information cf_rPs[pId] = {}; cf_rPs[pId].data = pdata; // Set options per chart customOptions = {}; customOptions.animation = false; cf_rPs[pId].options = customOptions; // Create chart createPieChart($container); }); $('#cf-funnel-1').each(function(){ funData = [parseInt(message.body)+3000,parseInt(message.body)+1500,parseInt(message.body)+500,parseInt(message.body)+250,parseInt(message.body)]; funLabels = ['Visits','Cart','Checkout','Purchase','Refund']; funOptions = {barOpacity:true, layout:'left'}; cf_rFunnels[$(this).prop('id')] = new FunnelChart($(this).prop('id'), funData, funLabels, funOptions); }); }); });