/**
Copyright 2014 ATOS SPAIN S.A.
Licensed under the Apache License, Version 2.0 (the License);
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Authors :
Francisco Javier Nieto. Atos Research and Innovation, Atos SPAIN SA
@email francisco.nieto@atos.net
Sergio GarcĂa Villalonga. Atos Research and Innovation, Atos, SPAIN SA
@email sergio.garciavillalonga@atos.net
**/
package eu.betaas.taas.taasresourcesmanager.endpointsmanager;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import org.apache.log4j.Logger;
import eu.betaas.taas.bigdatamanager.database.service.ThingsData;
import eu.betaas.taas.qosmanager.monitoring.api.impl.SLACalculation;
import eu.betaas.taas.taasresourcesmanager.catalogs.Resource;
import eu.betaas.taas.taasresourcesmanager.catalogs.ResourcesCatalog;
import eu.betaas.taas.taasresourcesmanager.taasrmclient.AdaptTAClient;
import eu.betaas.taas.taasresourcesmanager.taasrmclient.ServiceSMClient;
import eu.betaas.taas.taasresourcesmanager.taasrmclient.TaaSQoSMClient;
import eu.betaas.taas.taasresourcesmanager.taasrmclient.TaaSRMClient;
public class PushManager
{
private Logger logger= Logger.getLogger("betaas.taas");
private String localGateway;
static private PushManager _instance = null;
private TaaSQoSMClient myQoSClient;
private HashMap<String, ArrayList<Subscription>> rtSubsList;
private HashMap<String, ArrayList<Subscription>> nrtSubsList;
private HashMap<String, ActiveFeature> activeFeatures;
private PushManager (String gateway)
{
localGateway = gateway;
rtSubsList = new HashMap<String, ArrayList<Subscription>>();
nrtSubsList = new HashMap<String, ArrayList<Subscription>>();
activeFeatures = new HashMap<String, ActiveFeature>();
myQoSClient = TaaSQoSMClient.instance();
}
public static synchronized PushManager instance(String gateway)
{
if (null == _instance)
{
_instance = new PushManager(gateway);
Logger myLogger= Logger.getLogger("betaas.taas");
myLogger.info("A new instance of the Push Manager was created!");
}
return _instance;
}
public boolean receiveRemoteTAMeasurement (String thingServiceID, ThingsData data, String featureId)
{
// Check the feature identifier is valid
if (!activeFeatures.containsKey(featureId))
{
logger.error("The remote measurement received is not valid!! -> " + featureId);
return false;
}
//Get the corresponding ActiveFeature
ActiveFeature currentActFeature = activeFeatures.get(featureId);
currentActFeature.notifyReceived(thingServiceID, data);
//Send local notification (to the SM)
ServiceSMClient mySMClient = ServiceSMClient.instance();
boolean done = mySMClient.notifyServiceData(currentActFeature.getFeatureResult(), currentActFeature.getFeatureServiceId());
logger.info("Local notification with remote data sent to SM!");
return done;
}
public boolean receiveTAMeasurement(String thingServiceID, ThingsData data)
{
return receiveMeasurement(thingServiceID, data, rtSubsList);
}
public boolean receiveCMMeasurement(String thingServiceID, ThingsData data)
{
//TODO change this after demo!
return receiveMeasurement(thingServiceID, data, rtSubsList);
//return receiveMeasurement(thingServiceID, data, nrtSubsList);
}
public void addSubscription (Subscription newSubscription, boolean realTime)
{
//Determine the correct list
if (realTime)
{
//Retrieve the adequate list for the thing service
ArrayList<Subscription> currentList = rtSubsList.get(newSubscription.getThingServiceId());
if (currentList == null)
{
currentList = new ArrayList<Subscription>();
}
//Add the new subscription, sort and put the new list
currentList.add(newSubscription);
Collections.sort(currentList);
rtSubsList.put(newSubscription.getThingServiceId(), currentList);
logger.info("Real time subscription added in the PushManager for: " + newSubscription.getThingServiceId());
//Activate SLA monitoring
myQoSClient.activateSLAPushMonitoring(newSubscription.getThingServiceId(), (int)newSubscription.getPeriod(), newSubscription.getFeatureId());
logger.info("SLA activated for thing service: " + newSubscription.getThingServiceId());
}
else
{
//Retrieve the adequate list for the thing service
ArrayList<Subscription> currentList = nrtSubsList.get(newSubscription.getThingServiceId());
if (currentList == null)
{
currentList = new ArrayList<Subscription>();
}
//Add the new subscription, sort and put the new list
currentList.add(newSubscription);
Collections.sort(currentList);
nrtSubsList.put(newSubscription.getThingServiceId(), currentList);
logger.info("Non real time subscription added in the PushManager for: " + newSubscription.getThingServiceId());
}
//Manage the active feature
ActiveFeature theFeature = activeFeatures.get(newSubscription.getFeatureId());
theFeature.addSubscription(newSubscription.getThingServiceId());
activeFeatures.put(newSubscription.getFeatureId(), theFeature);
logger.info("Active features list updated!");
}
public void requestFeature (String idFeature, String operation)
{
// Create the new active feature only if it doesn't exist
if (!activeFeatures.containsKey(idFeature))
{
activeFeatures.put(idFeature, new ActiveFeature(idFeature, operation));
}
else
{
//activeFeatures.get(idFeature).clean();
}
}
public void removeFeature (String idFeature)
{
// Create the new active feature only if it doesn't exist
if (!activeFeatures.containsKey(idFeature))
{
activeFeatures.remove(idFeature);
}
}
public boolean removeSubscription (String idThingService, String idFeature)
{
if (activeFeatures.containsKey(idFeature))
{
//Retrieve thing services to unsubscribe from the Active Feature
ActiveFeature myFeature = activeFeatures.get(idFeature);
ArrayList<String> currentSubscriptions = myFeature.getThingServicesList();
//Look for each thing service subscription, in order to remove it
logger.info("Removing " + idThingService + " subscription for feature: " + idFeature);
ArrayList<Subscription> subsList = rtSubsList.get(idThingService);
//Retrieve all subscriptions for the thing service
Iterator<Subscription> myIter = subsList.iterator();
int position = 0;
while (myIter.hasNext())
{
//Check if the current subscription corresponds to our feature
if (myIter.next().getFeatureId().equalsIgnoreCase(idFeature))
{
//Remove and stop the iteration
logger.debug("Subscription to " + idThingService + " removed!");
subsList.remove(position);
break;
}
position++;
}
// Remove known subscription from the Resource Catalog and recalculate period
Resource theResource = ResourcesCatalog.instance().getResource(idThingService);
theResource.removeFeature(idFeature);
//Once subscriptions are removed, remove ActiveFeature if no more subscriptions are available
myFeature.removeSubscription(idThingService);
if (currentSubscriptions.size()<2)
{
activeFeatures.remove(idFeature);
}
//Finalize operation
logger.info("Operation completed!");
return true;
}
// If the feature is not active, the operation can't be done
logger.error("No active subscriptions were found for feature " + idFeature);
return false;
}
public void determineSubscriptionsRemoval (String idThingService)
{
//If all subscriptions for a thing service were removed, remove the TS from the maps and TA subs
ArrayList<Subscription> subsList = rtSubsList.get(idThingService);
AdaptTAClient taClient = AdaptTAClient.instance();
String idThing = ResourcesCatalog.instance().getResource(idThingService).getPhysicalResourceId();
if (subsList.size()==0)
{
logger.info("Thing Service " + idThingService + " has no more active subscriptions -> Removing all data!");
rtSubsList.remove(idThingService);
taClient.unSubscribeToThing(idThing);
}
else
{
// Update the subscription period to the re-calculated one
int period = ResourcesCatalog.instance().getResource(idThingService).getCommonPeriod();
logger.info("Thing Service " + idThingService + " has yet active subscriptions -> Updating period!");
taClient.subscribeToThing(idThing, period);
}
}
private boolean receiveMeasurement (String thingServiceID, ThingsData data, HashMap<String, ArrayList<Subscription>> subscriptionList) {
//Get current date
Date nowDate = Calendar.getInstance().getTime();
boolean done = false;
if (subscriptionList == rtSubsList) {
logger.info("Real time measurement received");
} else if (subscriptionList == nrtSubsList) {
logger.info("Non real time measurement received");
}
logger.debug("Looking for subscriptions waiting for notifications");
//Retrieve appropriate subscription element
ArrayList<Subscription> currentList = subscriptionList.get(thingServiceID);
ArrayList<Subscription> notifList = new ArrayList<Subscription>();
Iterator<Subscription> myIter = currentList.iterator();
while (myIter.hasNext() && !done)
{
Subscription currentSubs = myIter.next();
logger.debug("Checking expected date for: " + currentSubs.getThingServiceId());
if (currentSubs.getExpectedDate().compareTo(nowDate)<=0)
{
//Get subscriptions waiting for notifications
currentSubs.setReceived();
notifList.add(currentSubs);
logger.info("Get subscriptions waiting for notifications");
}
else
{
//Too early for more notifications
//break;
done = true;
logger.info("Too early for more notifications");
}
}
logger.info("Found " + notifList.size() + " subscriptions");
//Sort again the subscriptions list
Collections.sort(currentList);
//Send notifications
myIter = notifList.iterator();
while (myIter.hasNext())
{
Subscription currentNotif = myIter.next();
//Check application location
if (currentNotif.getFeatureLocation().equalsIgnoreCase("localhost"))
{
//Get the corresponding ActiveFeature
ActiveFeature currentActFeature = activeFeatures.get(currentNotif.getFeatureId());
currentActFeature.notifyReceived(thingServiceID, data);
//Send local notification (to the SM)
ServiceSMClient mySMClient = ServiceSMClient.instance();
done = done & mySMClient.notifyServiceData(currentActFeature.getFeatureResult(), currentActFeature.getFeatureServiceId());
logger.debug("Data sent: " + currentActFeature.getFeatureResult().getData());
logger.info("Local notification sent");
//Calculate SLA
SLACalculation currentSLA = myQoSClient.retrieveSLAPushCalculation(currentNotif.getThingServiceId(), currentNotif.getLastResponseTime());
logger.info("SLA retrieved for the thing service " + currentNotif.getThingServiceId() + " -> RT=" + currentNotif.getLastResponseTime() + " secs.");
if (currentSLA.getQoSparamsNoFulfill()>0)
{
//SLA has been violated -> Notify SM
mySMClient.notifySLAData(currentActFeature.getFeatureServiceId());
}
}
else
{
//Send remote notification to another gateway (to a remote TaaSRM)
TaaSRMClient myRMCli = TaaSRMClient.instance(localGateway, "PushManager");
done = done & myRMCli.remoteDataNotification(data, currentNotif.getFeatureId(), thingServiceID, currentNotif.getFeatureLocation());
logger.info("Remote notification sent");
}
}
return done;
}
}