/*
* Copyright (c) Fabien Hermenier
*
* This file is part of Entropy.
*
* Entropy 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.
*
* Entropy 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Entropy. If not, see <http://www.gnu.org/licenses/>.
*/
package entropy.plan.parser;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;
import entropy.configuration.Configuration;
import entropy.configuration.ManagedElementSet;
import entropy.configuration.Node;
import entropy.configuration.VirtualMachine;
import entropy.configuration.parser.ConfigurationSerializerException;
import entropy.configuration.parser.PlainTextConfigurationSerializer;
import entropy.plan.DefaultTimedReconfigurationPlan;
import entropy.plan.TimedReconfigurationPlan;
import entropy.plan.action.Action;
import entropy.plan.action.Migration;
import entropy.plan.action.Pause;
import entropy.plan.action.Resume;
import entropy.plan.action.Run;
import entropy.plan.action.Shutdown;
import entropy.plan.action.Startup;
import entropy.plan.action.Stop;
import entropy.plan.action.Suspend;
import entropy.plan.action.UnPause;
/**
* A serializer to store a plan in a human readable plain text format.
* TODO: Need some tests.
*
* @author Fabien Hermenier
*/
public class PlainTextTimedReconfigurationPlanSerializer extends FileTimedReconfigurationPlanSerializer {
private final static PlainTextTimedReconfigurationPlanSerializer instance = new PlainTextTimedReconfigurationPlanSerializer();
private static final String CONFIG_SEP = "#Reconfiguration Plan";
private static final String MIGRATION = "migrate";
private static final String RUN = "run";
private static final String STOP = "stop";
private static final String STARTUP = "startup";
private static final String SHUTDOWN = "shutdown";
private static final String SUSPEND = "suspend";
private static final String RESUME = "resume";
private static final String PAUSE = "pause";
private static final String UNPAUSE = "unpause";
private BufferedWriter out;
private PlainTextTimedReconfigurationPlanSerializer() {
}
@Override
public TimedReconfigurationPlan unSerialize(InputStream i) throws IOException, TimedReconfigurationPlanSerializerException {
BufferedReader in = null;
TimedReconfigurationPlan p = null;
try {
new StringBuilder();
in = new BufferedReader(new InputStreamReader(i));
Configuration cfg = PlainTextConfigurationSerializer.getInstance().unSerialize(in);
p = new DefaultTimedReconfigurationPlan(cfg);
String line = in.readLine();
if (line.endsWith(CONFIG_SEP)) {
line = in.readLine();
}
while (line != null) {
if (line.length() == 0) {
continue;
}
String[] toks = line.split(" ");
if (toks.length != 2) {
throw new TimedReconfigurationPlanSerializerException("Non viable action line:" + line);
}
String[] moments = toks[0].split(":");
if (moments.length != 2) {
throw new TimedReconfigurationPlanSerializerException("Incorrect time interval:" + toks[0]);
}
try {
int st = Integer.parseInt(moments[0]);
int ed = Integer.parseInt(moments[1]);
if (!line.endsWith(")")) {
throw new TimedReconfigurationPlanSerializerException("Non viable action line:" + line);
}
line = toks[1].substring(0, toks[1].length() - 1);
String[] x = line.split("\\(");
if (x.length != 2) {
throw new TimedReconfigurationPlanSerializerException("Non viable action line:" + line);
}
String[] params = x[1].split(",");
String id = x[0];
//Go to the conversion
Action a = null;
ManagedElementSet<VirtualMachine> vms = cfg.getAllVirtualMachines();
ManagedElementSet<Node> ns = cfg.getAllNodes();
if (id.equals(MIGRATION)) {
a = new Migration(vms.get(params[0]),
ns.get(params[1]),
ns.get(params[2]), st, ed);
} else if (id.equals(STOP)) {
a = new Stop(vms.get(params[0]),
ns.get(params[1]),
st, ed);
} else if (id.equals(RUN)) {
a = new Run(vms.get(params[0]),
ns.get(params[1]),
st, ed);
} else if (id.equals(PAUSE)) {
a = new Pause(vms.get(params[0]),
ns.get(params[1]),
st, ed);
} else if (id.equals(UNPAUSE)) {
a = new UnPause(vms.get(params[0]),
ns.get(params[1]),
st, ed);
} else if (id.equals(SUSPEND)) {
a = new Suspend(vms.get(params[0]),
ns.get(params[1]),
ns.get(params[2]),
st, ed);
} else if (id.equals(RESUME)) {
a = new Resume(vms.get(params[0]),
ns.get(params[1]),
ns.get(params[2]),
st, ed);
} else if (id.equals(STARTUP)) {
a = new Startup(ns.get(params[0]),
st, ed);
} else if (id.equals(SHUTDOWN)) {
a = new Shutdown(ns.get(params[0]),
st, ed);
} else {
throw new TimedReconfigurationPlanSerializerException("Unsupported action: " + id);
}
if (!p.add(a)) {
throw new TimedReconfigurationPlanSerializerException("Unable to add action '" + a + "'");
}
} catch (NumberFormatException e) {
throw new TimedReconfigurationPlanSerializerException("Incorrect time interval for " + toks[0] + ": " + e.getMessage());
}
line = in.readLine();
}
} catch (ConfigurationSerializerException e) {
throw new TimedReconfigurationPlanSerializerException(e);
} finally {
/* if (in != null) {
in.close();
}*/
}
return p;
}
@Override
public void serialize(TimedReconfigurationPlan plan, OutputStream o) throws IOException {
try {
out = new BufferedWriter(new OutputStreamWriter(o));
PlainTextConfigurationSerializer.getInstance().serialize(plan.getSource(), o);
//Separator
out.write(CONFIG_SEP);
out.write("\n");
//Actions are sorted by starting date
Map<Integer, List<Action>> planning = new HashMap<Integer, List<Action>>();
TreeSet<Integer> times = new TreeSet<Integer>();
for (Action action : plan.getActions()) {
int st = action.getStartMoment();
if (!planning.containsKey(st)) {
planning.put(st, new LinkedList<Action>());
times.add(st);
}
planning.get(st).add(action);
}
for (Map.Entry<Integer, List<Action>> e : planning.entrySet()) {
for (Action a : e.getValue()) {
out.write("" + a.getStartMoment());
out.write(":");
out.write("" + a.getFinishMoment());
out.write(" ");
a.serialize(this);
out.write("\n");
}
}
} finally {
if (out != null) {
out.flush();
}
}
}
public static PlainTextTimedReconfigurationPlanSerializer getInstance() {
return instance;
}
@Override
public void serialize(Migration a) throws IOException {
out.write(MIGRATION);
out.write("(");
out.write(a.getVirtualMachine().getName());
out.write(",");
out.write(a.getHost().getName());
out.write(",");
out.write(a.getDestination().getName());
out.write(")");
}
@Override
public void serialize(Run a) throws IOException {
out.write(RUN);
out.write("(");
out.write(a.getVirtualMachine().getName());
out.write(",");
out.write(a.getHost().getName());
out.write(")");
}
@Override
public void serialize(Stop a) throws IOException {
out.write(STOP);
out.write("(");
out.write(a.getVirtualMachine().getName());
out.write(",");
out.write(a.getHost().getName());
out.write(")");
}
@Override
public void serialize(Suspend a) throws IOException {
out.write(SUSPEND);
out.write("(");
out.write(a.getVirtualMachine().getName());
out.write(",");
out.write(a.getHost().getName());
out.write(",");
out.write(a.getDestination().getName());
out.write(")");
}
@Override
public void serialize(Resume a) throws IOException {
out.write(RESUME);
out.write("(");
out.write(a.getVirtualMachine().getName());
out.write(",");
out.write(a.getHost().getName());
out.write(",");
out.write(a.getDestination().getName());
out.write(")");
}
@Override
public void serialize(Startup a) throws IOException {
out.write(STARTUP);
out.write("(");
out.write(a.getNode().getName());
out.write(")");
}
@Override
public void serialize(Shutdown a) throws IOException {
out.write(SHUTDOWN);
out.write("(");
out.write(a.getNode().getName());
out.write(")");
}
@Override
public void serialize(Pause a) throws IOException {
out.write(PAUSE);
out.write("(");
out.write(a.getVirtualMachine().getName());
out.write(")");
}
@Override
public void serialize(UnPause a) throws IOException {
out.write(UNPAUSE);
out.write("(");
out.write(a.getVirtualMachine().getName());
out.write(")");
}
}