/* * Copyright 2020 The BtrPlace Authors. All rights reserved. * Use of this source code is governed by a LGPL-style * license that can be found in the LICENSE.txt file. */ package org.btrplace.btrpsl.tree; import org.antlr.runtime.Token; import org.antlr.runtime.tree.BaseTree; import org.btrplace.btrpsl.ErrorReporter; import org.btrplace.btrpsl.Script; import org.btrplace.btrpsl.SymbolsTable; import org.btrplace.btrpsl.antlr.ANTLRBtrplaceSL2Parser; import org.btrplace.btrpsl.element.BtrpElement; import org.btrplace.btrpsl.element.BtrpOperand; import org.btrplace.btrpsl.element.BtrpSet; import org.btrplace.btrpsl.element.IgnorableOperand; import org.btrplace.btrpsl.template.ElementBuilderException; import org.btrplace.btrpsl.template.TemplateFactory; import org.btrplace.model.Element; import org.btrplace.model.Model; import org.btrplace.model.Node; import org.btrplace.model.VM; import org.btrplace.model.view.NamingService; import java.util.HashMap; import java.util.List; import java.util.Map; /** * A statement to instantiate VMs or nodes from a specific template. * * @author Fabien Hermenier */ public class TemplateAssignment extends BtrPlaceTree { private final NamingService<Node> namingServiceNodes; private final NamingService<VM> namingServiceVMs; private final Model mo; /** * The current script. */ private final Script script; /** * The template factory. */ private final TemplateFactory tpls; private final SymbolsTable syms; /** * Make a new tree. * * @param t the token to consider * @param s the script that is built * @param tplFactory the template factory * @param symbolsTable the symbol table * @param m the model we focus on * @param nsNodes the NamingService for the nodes * @param nsVMs the NamingService for the VMs * @param errs the errors */ public TemplateAssignment(Token t, Script s, TemplateFactory tplFactory, SymbolsTable symbolsTable, Model m, NamingService<Node> nsNodes, NamingService<VM> nsVMs, ErrorReporter errs) { super(t, errs); this.script = s; this.tpls = tplFactory; this.syms = symbolsTable; this.mo = m; this.namingServiceNodes = nsNodes; this.namingServiceVMs = nsVMs; } private Map<String, String> getTemplateOptions() { Map<String, String> opts = new HashMap<>(); BaseTree t = getChild(1); for (int i = 0; i < t.getChildCount(); i++) { TemplateOptionTree opt = (TemplateOptionTree) t.getChild(i); opt.go(this); opts.put(opt.getKey(), opt.getValue()); } return opts; } @Override public BtrpOperand go(BtrPlaceTree parent) { BtrPlaceTree t = getChild(0); String tplName = getChild(1).getText(); if (!tpls.isAvailable(tplName)) { return ignoreError("Unknown template '" + tplName + "'"); } Map<String, String> opts = getTemplateOptions(); int nType = t.getType(); if (nType == ANTLRBtrplaceSL2Parser.IDENTIFIER) { addVM(tplName, script.id() + "." + t.getText(), opts); } else if (nType == ANTLRBtrplaceSL2Parser.NODE_NAME) { addNode(tplName, t.getText(), opts); } else if (nType == ANTLRBtrplaceSL2Parser.ENUM_ID) { BtrpOperand op = ((EnumElement) t).expand(); if (op == IgnorableOperand.getInstance()) { return op; } for (BtrpOperand o : ((BtrpSet) op).getValues()) { addVM(tplName, o.toString(), opts); } } else if (nType == ANTLRBtrplaceSL2Parser.ENUM_FQDN) { BtrpOperand op = ((EnumElement) t).expand(); if (op == IgnorableOperand.getInstance()) { return op; } for (BtrpOperand o : ((BtrpSet) op).getValues()) { addNode(tplName, o.toString(), opts); } } else if (nType == ANTLRBtrplaceSL2Parser.EXPLODED_SET) { @SuppressWarnings("unchecked") List<BtrPlaceTree> children = (List<BtrPlaceTree>) t.getChildren(); for (BtrPlaceTree child : children) { if (child.getType() == ANTLRBtrplaceSL2Parser.IDENTIFIER) { addVM(tplName, script.id() + "." + child.getText(), opts); } else if (child.getType() == ANTLRBtrplaceSL2Parser.NODE_NAME) { addNode(tplName, child.getText(), opts); } else { return ignoreError("Only VMs or nodes can be declared from templates"); } } } else { ignoreError("Unable to assign the template to '" + t.getText()); } return IgnorableOperand.getInstance(); } private void addVM(String tplName, String id, Map<String, String> opts) { try { Element el = namingServiceVMs.resolve(id); if (el == null) { VM vm = mo.newVM(); mo.getMapping().addReadyVM(vm); //We add the VM to the $me variable if (vm == null) { ignoreError("No UUID to create node '" + id + "'"); } else { namingServiceVMs.register(vm, id); el = vm; ((BtrpSet) syms.getSymbol(SymbolsTable.ME)).getValues().add( new BtrpElement(BtrpOperand.Type.VM, id, el)); } } tpls.check(script, tplName, el, opts); if (!script.add(new BtrpElement(BtrpOperand.Type.VM, id, el))) { ignoreError("VM '" + id + "' already created"); } } catch (ElementBuilderException ex) { ignoreError(ex); } } private void addNode(String tplName, String id, Map<String, String> opts) { try { Element el = namingServiceNodes.resolve(id); if (el == null) { Node n = mo.newNode(); mo.getMapping().addOfflineNode(n); if (n == null) { ignoreError("No UUID to create node '" + id + "'"); } else { namingServiceNodes.register(n, id); el = n; } } tpls.check(script, tplName, el, opts); if (!script.add(new BtrpElement(BtrpOperand.Type.NODE, id, el))) { ignoreError("Node '" + id + "' already created"); } } catch (ElementBuilderException ex) { ignoreError(ex); } } }