package org.openslx.dnbd3.status; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.openslx.dnbd3.status.output.EdgeSerializer; import org.openslx.dnbd3.status.output.OutputMain; import org.openslx.dnbd3.status.output.ServerStats; import org.openslx.dnbd3.status.poller.ServerPoller; import org.openslx.dnbd3.status.rpc.Client; import org.openslx.dnbd3.status.rpc.Status; import org.openslx.graph.ClientNode; import org.openslx.graph.Edge; import org.openslx.graph.Graph; import org.openslx.graph.Node; import org.openslx.graph.ServerNode; import com.google.gson.Gson; import com.google.gson.GsonBuilder; public class StatisticsGenerator { private final List pollers; private volatile long lastUpdate = 0; private ExecutorService threadPool = new ThreadPoolExecutor( 3, 8, 1, TimeUnit.MINUTES, new SynchronousQueue() ); private List> futureStatusList = new ArrayList<>(); private List statusList = new ArrayList<>(); private final Gson exposedJsonBuilder; private final Gson defaultJsonBuilder; private final Graph graph = new Graph( "DNBD 3 Status" ); private byte[] imgData = null; private final OutputMain output = new OutputMain(); private final OutputMain newOutput = new OutputMain(); public StatisticsGenerator( List pollers ) { this.pollers = pollers; for ( ServerPoller poller : pollers ) { Node server = new ServerNode( poller.getAddress() ); server.activate(); graph.addNode( server ); } // Prepare json serializer for graph final GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.excludeFieldsWithoutExposeAnnotation(); gsonBuilder.registerTypeHierarchyAdapter( Edge.class, new EdgeSerializer() ); exposedJsonBuilder = gsonBuilder.create(); defaultJsonBuilder = new GsonBuilder().create(); output.graph = graph; output.servers = new ArrayList<>(); output.timestamp = 0; newOutput.servers = new ArrayList<>(); newOutput.timestamp = 0; } private synchronized void updateAll() { futureStatusList.clear(); for ( final ServerPoller p : pollers ) { Callable task = new Callable() { @Override public Status call() throws Exception { return p.update(); } }; try { Future ret = threadPool.submit( task ); futureStatusList.add( ret ); } catch ( Exception e ) { e.printStackTrace(); } } statusList.clear(); output.servers.clear(); newOutput.servers.clear(); for ( Future future : futureStatusList ) { Status status; try { status = future.get(); } catch ( Exception e ) { System.out.println("Future timeout"); continue; } if ( status == null ) continue; statusList.add( status ); ServerStats srv = new ServerStats(); srv.address = status.getAddress(); srv.bytesReceived = status.getBytesReceived(); srv.bytesSent = status.getBytesSent(); srv.clientCount = status.getClientCount(); srv.serverCount = status.getServerCount(); srv.uptime = status.getUptime(); srv.timestamp = status.getTimestamp(); output.servers.add( srv ); srv = srv.clone(); srv.images = status.getImages(); srv.clients = status.getClients(); if (srv.clientCount == 0 && srv.serverCount == 0) { // For older dnbd3-server srv.clientCount = srv.clients.size(); } newOutput.servers.add( srv ); } newOutput.timestamp = output.timestamp = System.currentTimeMillis(); synchronized ( graph ) { graph.decay(); for ( Status status : statusList ) { String serverIp = status.getAddress(); Node server = graph.getNode( serverIp ); if ( server == null ) server = new ServerNode( serverIp ); server.activate(); for ( Client client : status.getClients() ) { if ( client.getAddress() == null ) continue; String ip = client.getAddress().replaceFirst( "\\:\\d+$", "" ); Node n = graph.getNode( ip ); if ( n == null ) n = new ClientNode( ip ); n.activate(); graph.setEdge( server, n, ( client.getBytesSent() >> 12 ) + 1 ); } } imgData = null; } } private synchronized void ensureUpToDate() { final long now = System.currentTimeMillis(); if ( now - lastUpdate > 1900 ) { lastUpdate = now; updateAll(); } } public byte[] getImagePng() { ensureUpToDate(); synchronized ( graph ) { if ( imgData == null ) { imgData = graph.makeNextImage(); } } return imgData; } public String getJson( boolean newFormat ) { ensureUpToDate(); if ( newFormat ) { synchronized ( newOutput ) { return defaultJsonBuilder.toJson( newOutput ); } } else { synchronized ( output ) { return exposedJsonBuilder.toJson( output ); } } } }