/** * This file is part of CloudML [ http://cloudml.org ] * * Copyright (C) 2012 - SINTEF ICT * Contact: Franck Chauvel <franck.chauvel@sintef.no> * * Module: root * * CloudML 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. * * CloudML 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 CloudML. If not, see * <http://www.gnu.org/licenses/>. */ package org.cloudml.mrt; import java.io.ByteArrayOutputStream; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import org.cloudml.codecs.JsonCodec; import org.cloudml.core.*; import org.cloudml.mrt.cmd.CmdWrapper; import org.cloudml.mrt.cmd.abstracts.Change; import org.cloudml.mrt.cmd.abstracts.Instruction; import org.cloudml.mrt.cmd.abstracts.Listener; import org.cloudml.mrt.cmd.gen.Ack; import org.cloudml.mrt.cmd.gen.CloudMLCmds; import org.cloudml.mrt.cmd.gen.Extended; import org.cloudml.mrt.cmd.gen.Snapshot; import org.cloudml.mrt.sample.SystemOutPeerStub; import org.yaml.snakeyaml.Yaml; /** * @author Hui Song & Nicolas Ferry */ public class Coordinator { public static Coordinator SINGLE_INSTANCE = null; public static final String ADDITIONAL_PREFIX = "!additional"; private static final Logger journal = Logger.getLogger(Coordinator.class.getName()); CommandReception reception = null; CommandExecutor executor = null; List<Change> changeList = new ArrayList<Change>(); NodificationCentre notificationCentre = new NodificationCentre(); Instruction lastInstruction = null; public Coordinator() { ModelRepo repo = new SimpleModelRepo(); executor = new CommandExecutor(repo); } public void updateStatusInternalComponent(String name, String newState, String identity) { //A PeerStub identifies who launches the modifications PeerStub committer = new SystemOutPeerStub(identity); //A wrapper hides the complexity of invoking the coordinator CmdWrapper wrapper = new CmdWrapper(this, committer); //Update the value of status try { Thread.sleep(1500); journal.log(Level.INFO, ">> Updating the model.."); wrapper.eSet("/componentInstances[name='" + name + "']", wrapper.makePair("status", "" + newState + "")); journal.log(Level.INFO, ">> Status of: " + name + " changed in: " + newState + ""); } catch (org.apache.commons.jxpath.JXPathNotFoundException e) { journal.log(Level.INFO, "Machine: " + name + " not in this model"); } catch (InterruptedException e) { e.printStackTrace(); } } public void updateStatus(String name, ComponentInstance.State newState, String identity) { //A PeerStub identifies who launches the modifications PeerStub committer = new SystemOutPeerStub(identity); //A wrapper hides the complexity of invoking the coordinator CmdWrapper wrapper = new CmdWrapper(this, committer); journal.log(Level.INFO, ">> Prepare to update status of: "+name); //Update the value of status try { Thread.sleep(1500); Object res = wrapper.eGet("/componentInstances[name='" + name + "']/status"); ComponentInstance res2=(ComponentInstance)wrapper.eGet("/componentInstances[name='" + name + "']"); if (res !=null) { if (!res.toString().equals(newState.toString())) { journal.log(Level.INFO, ">> Updating the model.."); wrapper.eSet("/componentInstances[name='" + name + "']", wrapper.makePair("status", "" + newState + "")); journal.log(Level.INFO, ">> Status of: " + name + " changed in: " + newState + ""); if(res2 instanceof VMInstance) ((VMInstance)res2).setStatus(newState); } }else{ if(res2 instanceof ExternalComponentInstance) ((ExternalComponentInstance)res2).setStatus(ComponentInstance.State.PENDING); journal.log(Level.INFO, ">> No former status, updating the model.."); wrapper.eSet("/componentInstances[name='" + name + "']", wrapper.makePair("status", "" + newState + "")); journal.log(Level.INFO, ">> Status of: " + name + " changed in: " + newState + ""); if(res2 instanceof VMInstance) ((VMInstance)res2).setStatus(newState); } } catch (org.apache.commons.jxpath.JXPathNotFoundException e) { journal.log(Level.INFO, "Machine: " + name + " not in this model"); } catch (InterruptedException e) { journal.log(Level.SEVERE, ">> Could not update status!"); journal.log(Level.SEVERE, e.getLocalizedMessage(), e); e.printStackTrace(); } } public void ack(String status, String identity){ Ack change=new Ack(identity); change.fromPeer=identity; change.status=status; changeList.add(change); } public void updateIP(String name, String ip, String identity){ PeerStub committer = new SystemOutPeerStub(identity); CmdWrapper wrapper = new CmdWrapper(this, committer); try { Thread.sleep(1500); Object res = wrapper.eGet("/componentInstances[name='" + name + "']/publicAddress"); if (res !=null) { journal.log(Level.INFO, ">> Updating the model.."); wrapper.eSet("/componentInstances[name='" + name + "']", wrapper.makePair("publicAddress", "" + ip + "")); journal.log(Level.INFO, ">> IP of: " + name + " changed in: " + ip + ""); } } catch (org.apache.commons.jxpath.JXPathNotFoundException e) { journal.log(Level.INFO, "Machine: " + name + " not in this model"); } catch (InterruptedException e) { e.printStackTrace(); } } public void setModelRepo(ModelRepo repo) { this.executor.setModelRepo(repo); } public Coordinator(String initModel) { this(); Extended extended = new Extended(); extended.name = "LoadDeployment"; extended.params = Arrays.asList(initModel); this.process(extended, new PeerStub() { @Override public String getID() { return "RootUser"; } @Override public void sendMessage(Object message) { System.out.println(String.format("RootUser:>> %s", message)); } }); } public void start() { if (reception != null) reception.start(); notificationCentre.coordinator = this; notificationCentre.startListening(); } public void removeListener(PeerStub from){ notificationCentre.removeListener(from); } public void setReception(CommandReception reception) { this.reception = reception; } public Object process(Instruction inst, PeerStub from) { //Do something before, such as record every instruction this.lastInstruction = inst; inst.fromPeer = from.getID(); return executor.execute(inst, changeList); //Do something after, such as... } public Object process(Listener listener, PeerStub from) { listener.id = listener.id + from.getID(); if (listener.cancel) { notificationCentre.removeListener(listener); } else { listener.root = executor.repo.getRoot(); notificationCentre.addListener(listener, from); } return null; } public String process(String cmdLiteral, PeerStub from) { if (cmdLiteral.startsWith(ADDITIONAL_PREFIX)) { String additional = cmdLiteral.substring(ADDITIONAL_PREFIX.length()); lastInstruction.addAdditional(additional); return (String) process(lastInstruction, from); } Yaml yaml = CloudMLCmds.INSTANCE.getYaml(); String ret = ""; for (Object cmd : yaml.loadAll(cmdLiteral)) { Object obj = null; if (cmd instanceof Instruction) obj = process((Instruction) cmd, from); else if (cmd instanceof Listener) obj = process((Listener) cmd, from); if (obj != null) { ret += String.format("###return of %s###\n%s\n", cmd.getClass().getSimpleName(), codec(obj)); } } return ret; } public String codec(Object object) { if (object instanceof Deployment) { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); JsonCodec jsonCodec = new JsonCodec(); jsonCodec.save((Deployment) object, baos); return baos.toString("UTF-8"); } catch (UnsupportedEncodingException ex) { Logger.getLogger(Coordinator.class.getName()).log(Level.SEVERE, null, ex); return null; } } else { Snapshot snapshot = new Snapshot(); snapshot.content = object; return CloudMLCmds.INSTANCE.getYaml().dump(snapshot); } } }