/*
* Copyright (c) 2010-2012 Thiago T. Sá
*
* This file is part of CloudReports.
*
* CloudReports is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CloudReports 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 Public License for more details.
*
* For more information about your rights as a user of CloudReports,
* refer to the LICENSE file or see <http://www.gnu.org/licenses/>.
*/
package cloudreports.simulation;
import cloudreports.business.SettingBusiness;
import cloudreports.dao.CustomerRegistryDAO;
import cloudreports.dao.DatacenterRegistryDAO;
import cloudreports.dao.SettingDAO;
import cloudreports.database.HibernateUtil;
import cloudreports.extensions.PowerDatacenter;
import cloudreports.gui.Dialog;
import cloudreports.gui.MainView;
import cloudreports.models.CustomerRegistry;
import cloudreports.models.Setting;
import cloudreports.reports.DataCollector;
import cloudreports.reports.Report;
import cloudreports.utils.*;
import java.io.File;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import org.cloudbus.cloudsim.DatacenterBroker;
import org.cloudbus.cloudsim.Log;
import org.cloudbus.cloudsim.core.CloudSim;
/**
* The Simulation class is responsible for setting up the simulation
* environments and running the all the simulations.
*
* @author Thiago T. Sá
* @since 1.0
*/
public class Simulation implements Runnable {
/** Indicates whether the simulations are over or not. */
private static boolean terminated;
/** A data collector. */
private static DataCollector dataCollector;
/** Indicates whether the mail notification feature is enabled or not. */
private boolean isMailNotificationEnabled;
/**
* Gets a value that indicates whether the simulations are over or not.
*
* @return a boolean that indicates whether the simulations are over or not.
*/
public static boolean hasTerminated() {
return terminated;
}
/**
* Gets the data collector.
*
* @return the data collector.
*/
public static DataCollector getDataCollector() {
return dataCollector;
}
/**
* Loads each simulation environment and run its simulations.
*
* @since 1.0
*/
@Override
public void run() {
terminated = false;
MainView.setStartButtonEnabled(false);
MainView.getSimulationView().setStateToInProgress();
String[] dbNames = MainView.getEnvironmentsNames();
double startTime = Calendar.getInstance().getTimeInMillis();
CloudSim.init(getNumberOfCustomers(), Calendar.getInstance(), false);
CloudSim.startSimulation();
for (String dbName : dbNames) {
HibernateUtil.setActiveDatabase(dbName + ".cre");
runAllSimulations();
}
double finishTime = Calendar.getInstance().getTimeInMillis();
ElapsedTime elapsedTime = new ElapsedTime(finishTime - startTime);
MainView.getSimulationView().setStateToComplete(elapsedTime);
MainView.setStartButtonEnabled(true);
}
/**
* Runs all simulations of a specific environment.
* It creates all CloudSim entities, runs the simulation and generates the
* report. This cycle is repeated the number of times indicated by the
* NumberOfSimulations setting.
*
* @since 1.0
*/
private void runAllSimulations() {
RemovePreviousReports();
isMailNotificationEnabled = SettingBusiness.isMailNotificationEnabled();
int numberOfSimulations = SettingBusiness.getNumberOfSimulations();
for (int simulationId = 1; simulationId <= numberOfSimulations; simulationId++) {
SettingBusiness.setCurrentSimulation(simulationId);
MainView.getSimulationView().setBarLabel("Simulation " + simulationId + " of " + HibernateUtil.getActiveDatabase() + " is in progress...");
Log.setOutput(LogIO.getFileOutputStream());
Log.printLine("CloudReports version 1.1");
Log.print("Verifying available resources...");
ResetCustomersTimeToSend();
if (Verification.verifyVMsDeploymentViability()) {
runSimulation(simulationId);
} else {
Dialog.showErrorMessage(null, "Simulation aborted:\nSome of the virtual machines cannot be deployed by any available host.");
MainView.getSimulationView().dispose();
break;
}
LogIO.removeTempLogFile();
}
}
/**
* Runs a round of a simulation.
*
* @since 1.1
*/
private void runSimulation(int simulationId) {
Log.print("OK\n");
double currentSimulationStartTime = Calendar.getInstance().getTimeInMillis();
CloudSim.init(getNumberOfCustomers(), Calendar.getInstance(), false);
CloudSim.terminateSimulation(SettingBusiness.getTimeToSimulate()*60);
HashMap<String, PowerDatacenter> datacenters = EntityFactory.createDatacenters();
HashMap<String, DatacenterBroker> brokers = EntityFactory.createBrokers();
if (datacenters == null || brokers == null) return;
EntityFactory.setUpNetworkLinks(datacenters, brokers);
try {
Simulation.dataCollector = new DataCollector(datacenters, brokers);
CloudSim.startSimulation();
Simulation.dataCollector.flushData();
MainView.getSimulationView().setBarLabel("Generating report " + simulationId + "...");
double currentSimulationFinishTime = Calendar.getInstance().getTimeInMillis();
ElapsedTime elapsedTime = new ElapsedTime(currentSimulationFinishTime - currentSimulationStartTime);
List<DatacenterBroker> brokersList = Arrays.asList(brokers.values().toArray(new DatacenterBroker[0]));
List<PowerDatacenter> datacentersList = Arrays.asList(datacenters.values().toArray(new PowerDatacenter[0]));
Report.generateReport(datacentersList, brokersList, elapsedTime);
if (hasTerminated()) {
Dialog.showWarning(MainView.getFrames()[0], "Simulation has been abrubtly terminated.");
} else {
//Send mail notification
if (isMailNotificationEnabled) {
Mail.sendMail("Simulation " + simulationId + " of " + HibernateUtil.getActiveDatabase() + " completed.",
"Simulation " + simulationId + " of " + HibernateUtil.getActiveDatabase() + " has completed in " + elapsedTime.toString() + ".");
}
}
} catch (Exception e) {
e.printStackTrace();
CloudSim.init(getNumberOfCustomers(), Calendar.getInstance(), false);
CloudSim.startSimulation();
Dialog.showWarning(null, "Simulation has been interrupted.\nReports may have been generated with inconsistent data.");
//Send mail notification
if (isMailNotificationEnabled) {
double currentFinishTime = Calendar.getInstance().getTimeInMillis();
ElapsedTime elapsedTime = new ElapsedTime(currentFinishTime - currentSimulationStartTime);
Mail.sendMail("Simulation " + simulationId + " of " + HibernateUtil.getActiveDatabase() + " failed.",
"Simulation " + simulationId + " of " + HibernateUtil.getActiveDatabase() + " has failed after " + elapsedTime.toString() + ":\n\n" + e.getMessage());
}
MainView.getSimulationView().dispose();
LogIO.removeTempLogFile();
}
}
/**
* Stops all simulations.
*
* @since 1.0
*/
public static void stopSimulation() {
CloudSim.init(1, Calendar.getInstance(), false);
CloudSim.startSimulation();
CloudSim.stopSimulation();
terminated = true;
}
/**
* Gets the number of simulated customers.
*
* @return the number of simulated customers.
* @since 1.0
*/
private int getNumberOfCustomers() {
CustomerRegistryDAO crDAO = new CustomerRegistryDAO();
return crDAO.getNumOfCustomers();
}
/**
* Removes reports from previous simulations.
*
* @since 1.1
*/
private void RemovePreviousReports() {
String baseDirectory = FileIO.getPathOfExecutable();
File reportsDirectory = new File(baseDirectory + "reports/" + HibernateUtil.getActiveDatabase());
if(reportsDirectory.exists()) FileIO.deleteDirectory(reportsDirectory);
reportsDirectory.mkdirs();
}
/**
* Resets the time to send cloudlets for all customers.
*
* @since 1.1
*/
private void ResetCustomersTimeToSend() {
CustomerRegistryDAO crDAO = new CustomerRegistryDAO();
for (CustomerRegistry cr : crDAO.getListOfCustomers()) {
cr.getUtilizationProfile().setTimeToSend(0);
crDAO.updateCustomerRegistry(cr);
}
}
}