package org.yamcs.xtceproc; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.List; import java.util.Map; import org.yamcs.ErrorInCommand; import org.yamcs.parameter.Value; import org.yamcs.xtce.Argument; import org.yamcs.xtce.ArgumentAssignment; import org.yamcs.xtce.ArgumentType; import org.yamcs.xtce.MetaCommand; import org.yamcs.xtce.MetaCommandContainer; public class MetaCommandProcessor { public static CommandBuildResult buildCommand(MetaCommand mc, List<ArgumentAssignment> argAssignmentList) throws ErrorInCommand { return buildCommand(new ProcessorData(), mc, argAssignmentList); } public static CommandBuildResult buildCommand(ProcessorData pdata, MetaCommand mc, List<ArgumentAssignment> argAssignmentList) throws ErrorInCommand { if(mc.isAbstract()) { throw new ErrorInCommand("Will not build command "+mc.getQualifiedName()+" because it is abstract"); } MetaCommandContainer def = mc.getCommandContainer(); if(def==null) { throw new ErrorInCommand("MetaCommand has no container: "+def); } Map<Argument, Value> args = new HashMap<>(); Map<String,String> argAssignment = new HashMap<> (); for(ArgumentAssignment aa: argAssignmentList) { argAssignment.put(aa.getArgumentName(), aa.getArgumentValue()); } collectAndCheckArguments(mc, args, argAssignment); TcProcessingContext pcontext = new TcProcessingContext(pdata, ByteBuffer.allocate(1000), 0); pcontext.argValues = args; pcontext.mccProcessor.encode(mc); byte[] b = new byte[pcontext.size]; pcontext.bb.position(0); pcontext.bb.get(b, 0, pcontext.size); return new CommandBuildResult(b, args); } /** * Builds the argument values args based on the argAssignment (which is basically the user input) * and on the inheritance assignments * * The argAssignment is emptied as values are being used so if at the end of the call there are still assignment not used -> invalid argument provided * * This function is called recursively. * * @param args * @param argAssignment * @throws ErrorInCommand */ private static void collectAndCheckArguments(MetaCommand mc, Map<Argument, Value> args, Map<String, String> argAssignment) throws ErrorInCommand { List<Argument> argList = mc.getArgumentList(); if(argList!=null) { //check for each argument that we either have an assignment or a value for(Argument a: argList) { if(args.containsKey(a)) { continue; } String stringValue = null; String argInitialValue = null; Value argTypeInitialValue = null; if(!argAssignment.containsKey(a.getName())) { argInitialValue = a.getInitialValue(); argTypeInitialValue = ArgumentTypeProcessor.getInitialValue(a.getArgumentType()); if(argInitialValue == null && argTypeInitialValue == null) { throw new ErrorInCommand("No value provided for argument "+a.getName()+" (and the argument has no default value either)"); } } else { stringValue = argAssignment.remove(a.getName()); } ArgumentType type = a.getArgumentType(); try { Value v; // default value argInitialValue overwrites argTypeInitialValue if(stringValue == null) stringValue = argInitialValue; if(stringValue !=null) v = ArgumentTypeProcessor.parseAndCheckRange(type, stringValue); else v= argTypeInitialValue; args.put(a, v); } catch (Exception e) { throw new ErrorInCommand("Cannot assign value to "+a.getName()+": "+e.getMessage()); } } } //now, go to the parent MetaCommand parent = mc.getBaseMetaCommand(); if(parent!=null) { List<ArgumentAssignment> aaList = mc.getArgumentAssignmentList(); if(aaList!=null) { for(ArgumentAssignment aa:aaList) { if(argAssignment.containsKey(aa.getArgumentName())) { throw new ErrorInCommand("Cannot overwrite the argument "+aa.getArgumentName()+" which is defined in the inheritance assignment list"); } argAssignment.put(aa.getArgumentName(), aa.getArgumentValue()); } } collectAndCheckArguments(parent, args, argAssignment); } } static public class CommandBuildResult { byte[] cmdPacket; Map<Argument, Value> args; public CommandBuildResult(byte[] b, Map<Argument, Value> args) { this.cmdPacket = b; this.args = args; } public byte[] getCmdPacket() { return cmdPacket; } public Map<Argument, Value> getArgs() { return args; } } }