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

org.btrplace.json.plan.ActionConverter Maven / Gradle / Ivy

There is a newer version: 1.12.10
Show newest version
/*
 * Copyright (c) 2016 University Nice Sophia Antipolis
 *
 * This file is part of btrplace.
 * This library 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 library 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 this program.  If not, see .
 */

package org.btrplace.json.plan;

import net.minidev.json.JSONArray;
import net.minidev.json.JSONObject;
import org.btrplace.json.JSONConverterException;
import org.btrplace.model.Model;
import org.btrplace.plan.event.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static org.btrplace.json.JSONs.*;

/**
 * JSON converter for {@link Action}.
 *
 * @author Fabien Hermenier
 */
public class ActionConverter implements ActionVisitor {

    /**
     * Key that indicates the beginning an action.
     */
    public static final String START_LABEL = "start";

    /**
     * Key that indicates the end an action.
     */
    public static final String END_LABEL = "end";

    /**
     * Key that indicates a VM identifier.
     */
    public static final String VM_LABEL = "vm";

    /**
     * Key that indicates a node identifier.
     */
    public static final String NODE_LABEL = "node";

    /**
     * Key that indicates the current position of a VM.
     */
    public static final String ON_LABEL = "on";

    /**
     * Ket that indicates the hooks.
     */
    public static final String HOOK_LABEL = "hooks";

    /**
     * Key that indicate the action identifier
     */
    public static final String ACTION_ID_LABEL = "id";

    public static final String VM_LOCATION_LABEL = "from";

    public static final String VM_DESTINATION_LABEL = "to";

    public static final String BANDWIDTH = "bw";

    /**
     * Key to indicate a resource identifier.
     */
    public static final String RC_LABEL = "rc";

    /**
     * Key to indicate a resource amount.
     */
    public static final String RC_AMOUNT_LABEL = "amount";

    /**
     * Key to indicate an allocation event or action
     */
    public static final String RC_ALLOCATE_LABEL = "allocate";

    private Model mo;

    /**
     * A new converter
     *
     * @param mo the model to rely on.
     */
    public ActionConverter(Model mo) {
        this.mo = mo;
    }

    /**
     * decode a json-encoded action.
     * @param in the action to decode
     * @return the resulting action
     * @throws JSONConverterException if the conversion failed
     */
    public Action fromJSON(JSONObject in) throws JSONConverterException {
        String id = requiredString(in, ACTION_ID_LABEL);
        Action a;

        switch (id) {
            case "bootVM":
                a = bootVMFromJSON(in);
                break;
            case "shutdownVM":
                a = shutdownVMFromJSON(in);
                break;
            case "shutdownNode":
                a = shutdownNodeFromJSON(in);
                break;
            case "bootNode":
                a = bootNodeFromJSON(in);
                break;
            case "forgeVM":
                a = forgeVMFromJSON(in);
                break;
            case "killVM":
                a = killVMFromJSON(in);
                break;
            case "migrateVM":
                a = migrateVMFromJSON(in);
                break;
            case "resumeVM":
                a = resumeVMFromJSON(in);
                break;
            case "suspendVM":
                a = suspendVMFromJSON(in);
                break;
            case RC_ALLOCATE_LABEL:
                a = allocateFromJSON(in);
                break;
            default:
                throw new JSONConverterException("Unsupported action '" + id + "'");
        }

        attachEvents(a, in);
        return a;
    }

    /**
     * Decorate the action with optional events.
     *
     * @param a  the action to decorate
     * @param in the JSON message containing the event at the "hook" key
     * @throws JSONConverterException in case of error
     */
    private void attachEvents(Action a, JSONObject in) throws JSONConverterException {
        if (in.containsKey(HOOK_LABEL)) {
            JSONObject hooks = (JSONObject) in.get(HOOK_LABEL);
            for (Map.Entry e : hooks.entrySet()) {
                String k = e.getKey();
                try {
                    Action.Hook h = Action.Hook.valueOf(k.toUpperCase());
                    for (Object o : (JSONArray) e.getValue()) {
                        a.addEvent(h, eventFromJSON((JSONObject) o));
                    }
                } catch (IllegalArgumentException ex) {
                    throw new JSONConverterException("Unsupported hook type '" + k + "'", ex);
                }
            }
        }
    }

    private Event eventFromJSON(JSONObject o) throws JSONConverterException {
        String id = requiredString(o, ACTION_ID_LABEL);

        switch (id) {
            case RC_ALLOCATE_LABEL:
                return allocateEventFromJSON(o);
            case "substitutedVM":
                return substitutedVMEventFromJSON(o);
            default:
                throw new JSONConverterException("Unsupported type of action '" + id + "'");
        }
    }


    @Override
    public JSONObject visit(BootVM a) {
        JSONObject o = makeActionSkeleton(a);
        o.put(ACTION_ID_LABEL, "bootVM");
        o.put(VM_LABEL, elementToJSON(a.getVM()));
        o.put(VM_DESTINATION_LABEL, elementToJSON(a.getDestinationNode()));
        return o;
    }

    private BootVM bootVMFromJSON(JSONObject in) throws JSONConverterException {
        return new BootVM(requiredVM(mo, in, VM_LABEL),
                requiredNode(mo, in, VM_DESTINATION_LABEL),
                requiredInt(in, START_LABEL),
                requiredInt(in, END_LABEL));
    }

    @Override
    public JSONObject visit(ShutdownVM a) {
        JSONObject o = makeActionSkeleton(a);
        o.put(ACTION_ID_LABEL, "shutdownVM");
        o.put(VM_LABEL, elementToJSON(a.getVM()));
        o.put(ON_LABEL, elementToJSON(a.getNode()));
        return o;
    }

    private ShutdownVM shutdownVMFromJSON(JSONObject in) throws JSONConverterException {
        return new ShutdownVM(requiredVM(mo, in, VM_LABEL),
                requiredNode(mo, in, ON_LABEL),
                requiredInt(in, START_LABEL),
                requiredInt(in, END_LABEL));
    }

    @Override
    public JSONObject visit(ShutdownNode a) {
        JSONObject o = makeActionSkeleton(a);
        o.put(ACTION_ID_LABEL, "shutdownNode");
        o.put(NODE_LABEL, elementToJSON(a.getNode()));
        return o;
    }

    private ShutdownNode shutdownNodeFromJSON(JSONObject in) throws JSONConverterException {
        return new ShutdownNode(requiredNode(mo, in, NODE_LABEL),
                requiredInt(in, START_LABEL),
                requiredInt(in, END_LABEL));
    }

    @Override
    public JSONObject visit(BootNode a) {
        JSONObject o = makeActionSkeleton(a);
        o.put(ACTION_ID_LABEL, "bootNode");
        o.put(NODE_LABEL, elementToJSON(a.getNode()));
        return o;
    }

    private BootNode bootNodeFromJSON(JSONObject in) throws JSONConverterException {
        return new BootNode(requiredNode(mo, in, NODE_LABEL),
                requiredInt(in, START_LABEL),
                requiredInt(in, END_LABEL));
    }

    @Override
    public JSONObject visit(MigrateVM a) {
        JSONObject o = makeActionSkeleton(a);
        o.put(ACTION_ID_LABEL, "migrateVM");
        o.put(VM_LABEL, elementToJSON(a.getVM()));
        o.put(VM_DESTINATION_LABEL, elementToJSON(a.getDestinationNode()));
        o.put(VM_LOCATION_LABEL, elementToJSON(a.getSourceNode()));
        o.put(BANDWIDTH, a.getBandwidth());
        return o;
    }


    private MigrateVM migrateVMFromJSON(JSONObject in) throws JSONConverterException {
        return new MigrateVM(requiredVM(mo, in, VM_LABEL),
                requiredNode(mo, in, VM_LOCATION_LABEL),
                requiredNode(mo, in, VM_DESTINATION_LABEL),
                requiredInt(in, START_LABEL),
                requiredInt(in, END_LABEL),
                optInt(in, BANDWIDTH, Integer.MAX_VALUE)
                );
    }

    @Override
    public JSONObject visit(SuspendVM a) {
        JSONObject o = makeActionSkeleton(a);
        o.put(ACTION_ID_LABEL, "suspendVM");
        o.put(VM_LABEL, elementToJSON(a.getVM()));
        o.put(VM_DESTINATION_LABEL, elementToJSON(a.getDestinationNode()));
        o.put(VM_LOCATION_LABEL, elementToJSON(a.getSourceNode()));
        return o;
    }

    private SuspendVM suspendVMFromJSON(JSONObject in) throws JSONConverterException {
        return new SuspendVM(requiredVM(mo, in, VM_LABEL),
                requiredNode(mo, in, VM_LOCATION_LABEL),
                requiredNode(mo, in, VM_DESTINATION_LABEL),
                requiredInt(in, START_LABEL),
                requiredInt(in, END_LABEL));
    }

    @Override
    public JSONObject visit(ResumeVM a) {
        JSONObject o = makeActionSkeleton(a);
        o.put(ACTION_ID_LABEL, "resumeVM");
        o.put(VM_LABEL, elementToJSON(a.getVM()));
        o.put(VM_DESTINATION_LABEL, elementToJSON(a.getDestinationNode()));
        o.put(VM_LOCATION_LABEL, elementToJSON(a.getSourceNode()));
        return o;
    }

    private ResumeVM resumeVMFromJSON(JSONObject in) throws JSONConverterException {
        return new ResumeVM(requiredVM(mo, in, VM_LABEL),
                requiredNode(mo, in, VM_LOCATION_LABEL),
                requiredNode(mo, in, VM_DESTINATION_LABEL),
                requiredInt(in, START_LABEL),
                requiredInt(in, END_LABEL));
    }

    @Override
    public JSONObject visit(KillVM a) {
        JSONObject o = makeActionSkeleton(a);
        o.put(ACTION_ID_LABEL, "killVM");
        o.put(VM_LABEL, elementToJSON(a.getVM()));
        o.put(ON_LABEL, elementToJSON(a.getNode()));
        return o;
    }

    private KillVM killVMFromJSON(JSONObject in) throws JSONConverterException {
        return new KillVM(requiredVM(mo, in, VM_LABEL),
                requiredNode(mo, in, ON_LABEL),
                requiredInt(in, START_LABEL),
                requiredInt(in, END_LABEL));

    }

    @Override
    public JSONObject visit(ForgeVM a) {
        JSONObject o = makeActionSkeleton(a);
        o.put(ACTION_ID_LABEL, "forgeVM");
        o.put(VM_LABEL, elementToJSON(a.getVM()));
        return o;

    }

    private ForgeVM forgeVMFromJSON(JSONObject in) throws JSONConverterException {
        return new ForgeVM(requiredVM(mo, in, VM_LABEL),
                requiredInt(in, START_LABEL),
                requiredInt(in, END_LABEL));
    }

    @Override
    public JSONObject visit(Allocate a) {
        JSONObject o = makeActionSkeleton(a);
        o.put(ACTION_ID_LABEL, RC_ALLOCATE_LABEL);
        o.put(VM_LABEL, elementToJSON(a.getVM()));
        o.put(RC_LABEL, a.getResourceId());
        o.put(RC_AMOUNT_LABEL, a.getAmount());
        o.put(ON_LABEL, elementToJSON(a.getHost()));
        return o;
    }

    private Allocate allocateFromJSON(JSONObject in) throws JSONConverterException {
        return new Allocate(requiredVM(mo, in, VM_LABEL),
                requiredNode(mo, in, ON_LABEL),
                requiredString(in, RC_LABEL),
                requiredInt(in, RC_AMOUNT_LABEL),
                requiredInt(in, START_LABEL),
                requiredInt(in, END_LABEL));
    }

    @Override
    public Object visit(AllocateEvent a) {
        JSONObject o = new JSONObject();
        o.put(ACTION_ID_LABEL, RC_ALLOCATE_LABEL);
        o.put(RC_LABEL, a.getResourceId());
        o.put(VM_LABEL, elementToJSON(a.getVM()));
        o.put(RC_AMOUNT_LABEL, a.getAmount());
        return o;
    }

    private AllocateEvent allocateEventFromJSON(JSONObject o) throws JSONConverterException {
        return new AllocateEvent(requiredVM(mo, o, VM_LABEL),
                requiredString(o, RC_LABEL),
                requiredInt(o, RC_AMOUNT_LABEL));
    }

    @Override
    public Object visit(SubstitutedVMEvent a) {
        JSONObject o = new JSONObject();
        o.put(ACTION_ID_LABEL, "substitutedVM");
        o.put(VM_LABEL, elementToJSON(a.getVM()));
        o.put("newVm", elementToJSON(a.getNewVM()));
        return o;
    }

    private SubstitutedVMEvent substitutedVMEventFromJSON(JSONObject o) throws JSONConverterException {
        return new SubstitutedVMEvent(requiredVM(mo, o, VM_LABEL),
                requiredVM(mo, o, "newVm"));
    }

    /**
     * Serialise an action.
     * @param a the action
     * @return the resulting encoded action
     * @throws JSONConverterException if the conversion exploded
     */
    public JSONObject toJSON(Action a) {
        return (JSONObject) a.visit(this);
    }

    /**
     * Just create the JSONObject and set the consume and the end attribute.
     *
     * @param a the action to convert
     * @return a skeleton JSONObject
     */
    private JSONObject makeActionSkeleton(Action a) {
        JSONObject o = new JSONObject();
        o.put(START_LABEL, a.getStart());
        o.put(END_LABEL, a.getEnd());
        JSONObject hooks = new JSONObject();
        for (Action.Hook k : Action.Hook.values()) {
            JSONArray arr = new JSONArray();
            for (Event e : a.getEvents(k)) {
                arr.add(toJSON(e));
            }
            hooks.put(k.toString(), arr);
        }
        o.put(HOOK_LABEL, hooks);
        return o;
    }


    private JSONObject toJSON(Event e) {
        return (JSONObject) e.visit(this);
    }

    /**
     * Convert a list of json-encoded actions.
     * @param in the list to decode
     * @return the action list. Might be empty
     * @throws JSONConverterException if the conversion failed
     */
    public List listFromJSON(JSONArray in) throws JSONConverterException {
        List l = new ArrayList<>(in.size());
        for (Object o : in) {
            if (!(o instanceof JSONObject)) {
                throw new JSONConverterException("Expected an array of JSONObject but got an array of " + o.getClass().getName());
            }
            l.add(fromJSON((JSONObject) o));
        }
        return l;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy