All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.agentsoz.dataInterface.DataServer Maven / Gradle / Ivy

package io.github.agentsoz.dataInterface;

/*
 * #%L
 * BDI-ABM Integration Package
 * %%
 * Copyright (C) 2014 - 2015 by its authors. See AUTHORS file.
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentSkipListMap;

// TODO:
// Add pull mechanism for clients

public class DataServer {
   
   private double                            time          = 0.0;
   private double                            timeStep      = 1.0;
   private Map< String, List< DataClient > > subscriptions = new HashMap< String, List< DataClient > >();
   private Map< String, List< DataSource > > sources       = new HashMap< String, List< DataSource > >();
   private SortedMap< Double, Map< String, List< DataSource > > > timedUpdates
      = new ConcurrentSkipListMap< Double, Map< String, List< DataSource > > >();
   private static Map< String, DataServer >  servers       = new HashMap< String, DataServer >();
   
   public DataServer( String name ) {
      
      servers.put( name, this );
   }
   
   public static DataServer getServer( String name ) {
      
      if (!servers.containsKey( name )) { new DataServer( name ); }
      return servers.get( name );
   }

   // subscribe the given DataClient to data updates of a given type
   // updates are sent immediately on being published
   public void subscribe( DataClient client, String dataType ) {
      
      if (subscriptions.containsKey( dataType )) { subscriptions.get( dataType ).add( client ); }
      else {
         List< DataClient > subscribers = new ArrayList< DataClient >();
         subscribers.add( client );
         subscriptions.put( dataType, subscribers );
      }
   }
   public void subscribe( DataClient client, String[] dataTypes ) {
      
      for (String dataType: dataTypes) { subscribe( client, dataType ); }
   }
   
   public boolean setTimeStep( Double newTimeStep ) {
      
      if (newTimeStep < 0.0) { return false; }
      timeStep = newTimeStep;
      return true;
   }
   
   public double getTimeStep() {
      
      return timeStep;
   }
   
   // register a source for passive (timed) data updates
   // sources that actively publish data don't need to register
   public void registerSource( String dataType, DataSource source ) {

      if (sources.containsKey( dataType )) { sources.get( dataType ).add( source ); }
      else {
         List< DataSource > sourcesForType = new ArrayList< DataSource >();
         sourcesForType.add( source );
         sources.put( dataType, sourcesForType );
      }
   }
   
   // register a source for a future timed update
   // the data server will query this source at the specified time
   public void registerTimedUpdate( String dataType, DataSource source, double nextUpdate ) {

      if (!timedUpdates.containsKey( nextUpdate )) {
         timedUpdates.put( nextUpdate, new HashMap< String, List< DataSource > >() );
      }
      if (!timedUpdates.get( nextUpdate ).containsKey( dataType )) {
         timedUpdates.get( nextUpdate ).put( dataType, new ArrayList< DataSource >() );
      }
      timedUpdates.get( nextUpdate ).get( dataType ).add( source );
   }

   // when the data server's time moves forward, all data sources are polled for new updates
   // new updates are published immediately
   void updateTimedSources() {

      for (String dataType : sources.keySet()) {
         for (DataSource source : sources.get( dataType )) {
            Object data = source.getNewData( time, null );
            if (data != null) { publish( dataType, data ); }
         }
      }
      // check for new timed updates; publish and retrieve any that are found
      while (!timedUpdates.isEmpty() && timedUpdates.firstKey() < time) {
         
         double t = timedUpdates.firstKey();
         Iterator< Entry< String, List< DataSource > > > i = timedUpdates.get( t ).entrySet().iterator();
         
         while (i.hasNext()) {
            
            Entry< String, List< DataSource > > sourcesForType = i.next();
            String dataType = sourcesForType.getKey();
            
            for (DataSource source: sourcesForType.getValue()) {
               
               Object data = source.getNewData( time, null );
               if (data != null) { publish( dataType, data ); }
            }
         }
         timedUpdates.remove( t );
      }
   }
   
   public void stepTime() {
      
      time += timeStep;
      updateTimedSources();
   }
   
   // increase time by a given amount and poll for new timed updates
   public boolean stepTime( double t ) {
      
      if (t <= 0.0) { return false; }
      time += t;
      updateTimedSources();
      return true;
   }
   
   // manually set the data server's time to a given value and poll for new timed updates
   public boolean setTime( double t ) {
      
      if (t <= time) { return false; }
      
      time = t;
      updateTimedSources();
      return true;
   }
   
   public boolean setTimeStep( double t ) {
      
      if (t <= 0.0) { return false; }
      timeStep = t;
      return true;
   }
   
   public double getTime() { return time; }
   
   // send a new data update to all clients that have subscribed to the data type
   public boolean publish( String dataType, Object data ) {
      
      if (!subscriptions.containsKey( dataType )) { return false; }
      log(dataType, data );
      for (DataClient dc : subscriptions.get( dataType )) { dc.dataUpdate( time, dataType, data );}
      return true;
   }
   
   private void log (String dataType, Object data ){
	   //TODO it might be useful to log all message traffic for testing
//	      System.out.println("dataServer: " + dataType);
   }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy