From f6ae688d1eb33feb2ca0b77dd2f905da4221268c Mon Sep 17 00:00:00 2001
From: Ludovic Apvrille <ludovic.apvrille@telecom-paristech.fr>
Date: Fri, 12 Jun 2020 13:26:22 +0200
Subject: [PATCH] Update on plugins: doc and co. Still to implement: custom
 commands

---
 .../ttool_development_infrastructure.tex      |  61 +++-
 .../CustomizerGraphicalComponent.java         |  79 ++++-
 src/main/java/cli/Interpreter.java            |   2 +-
 src/main/java/cli/PluginAction.java           | 278 ++++++++++++++++++
 src/main/java/myutil/Plugin.java              |  81 ++++-
 src/main/java/myutil/PluginManager.java       |   3 +-
 6 files changed, 482 insertions(+), 22 deletions(-)
 create mode 100644 src/main/java/cli/PluginAction.java

diff --git a/doc/dev_infrastructure/ttool_development_infrastructure.tex b/doc/dev_infrastructure/ttool_development_infrastructure.tex
index a4520677c8..9ee2edc1a9 100644
--- a/doc/dev_infrastructure/ttool_development_infrastructure.tex
+++ b/doc/dev_infrastructure/ttool_development_infrastructure.tex
@@ -1581,6 +1581,65 @@ if (instance == null) {
 
 
 \subsection{Using plugins from the command line interface}
-Under development.
+\subsubsection{Main commands}
+\begin{itemize}
+\item \textit{plugin load <path> <plugin name> [optional: plugin package]}: loads a plugin
+\begin{verbatim}
+$ cd TTool/bin
+$ java -jar ttool-cli.jar -interact
+0> plugin list
+plugin list
+No plugins
+1> plugin load ../plugins CustomizerGraphicalComponent.jar
+plugin load ../plugins CustomizerGraphicalComponent.jar
+2> plugin list
+plugin list
+CustomizerGraphicalComponent.jar
+\end{verbatim}
+\item \textit{plugin info <plugin name>}: provides information on a given plugin
+\begin{verbatim}
+\item \textit{plugin list}: list all the loaded plugins
+\begin{verbatim}
+$ plugin list
+CustomizerAvatarJavaCodeGeneration.jar
+CustomizerGraphicalComponent.jar
+\end{verbatim}
+\item \textit{plugin info <plugin name>}: provides information on a given plugin
+\begin{verbatim}
+$ plugin info CustomizerGraphicalComponent.jar
+Package:	
+Path:	../plugins
+Has graphical component?	false
+Has Avatar code generator?	true
+Has Diplodocus code generator?	false
+Custom commands: getPanelClassName getWidth getHeight setDefaultWidth 
+\end{verbatim}
+\end{itemize}
+\item \textit{plugin info-command <plugin name> <command name>}: provides information on a given command provided by a plugin
+\begin{verbatim}
+$ plugin info-command CustomizerGraphicalComponent.jar setDefaultWidth
+static void setDefaultWidth(int defaultWidth): makes it possible to set the default width
+\end{verbatim}
+\end{itemize}
+
+\subsubsection{Mandatory functions}
+A plugin that may be used by the command line interface must define the following methods:
+\begin{itemize}
+\item  \textit{public static String hasCommandLineInterface()}: returns the class of the plugin implementing custom commands
+\item  \textit{public static String getCommandsOfCommandLineInterface()}: returns all the  names of custom commands (for instance: "getValue")
+\item \textit{public static String getHelpOnCommandLineInterfaceFunction(String command)}: returns some help about the function given as parameter.
+\end{itemize}
+
+
+\subsubsection{Custom commands}
+A plugin can define a list of custom commands. These commands can take only \textit{String} as parameter and can return either nothing or a String. They have to be implemented with a method having the same name as the command. The method must also be \textbf{static}.
+
+For instance:
+\begin{verbatim}
+public static String getWidthS() {
+        return "100";
+}
+\end{verbatim}
+
 
 \end{document}
diff --git a/plugins/testPluginGraphicalComponent/CustomizerGraphicalComponent.java b/plugins/testPluginGraphicalComponent/CustomizerGraphicalComponent.java
index dbec671d78..f64f728563 100644
--- a/plugins/testPluginGraphicalComponent/CustomizerGraphicalComponent.java
+++ b/plugins/testPluginGraphicalComponent/CustomizerGraphicalComponent.java
@@ -38,16 +38,36 @@
  * /**
  * Class CustomizerAvatarJavaCodeGeneration
  * Creation: 27/06/2017
- * @version 1.0 27/06/2017
+ * @version 1.1 12/06/2020
  * @author Ludovic APVRILLE
  * @see
  */
 
+
 import java.awt.*;
 import java.net.URL;
 import javax.swing.*;
      
 public class CustomizerGraphicalComponent {
+    private final static String[] CLI_COMMANDS =  {"getPanelClassName",
+            "getWidthS",
+            "getHeightS",
+            "setDefaultWidth"};
+    private final static String[] CLI_PROTOTYPES =  {"getPanelClassName: returns a String",
+            "getWidthS: returns a String",
+            "getHeightS: returns a String",
+            "setDefaultWidth <int defaultWidth>: returns void"};
+
+    private final static String[] CLI_HELP_COMMANDS = {
+            "returns the associated panel name of the component",
+            "returns the default width",
+            "returns the default height",
+            "makes it possible to set the default width"
+    };
+
+    private static int DEFAULT_WIDTH = 100;
+
+
     public static ImageIcon myIcon;
     
     public CustomizerGraphicalComponent() {
@@ -58,6 +78,32 @@ public class CustomizerGraphicalComponent {
 	return "CustomizerGraphicalComponent";
     }
 
+    public static String hasCommandLineInterface() {
+        return "CustomizerGraphicalComponent";
+    }
+
+    public static String getCommandsOfCommandLineInterface() {
+        StringBuffer sb = new StringBuffer("");
+        for(String s: CLI_COMMANDS) {
+            sb.append(s + " " );
+        }
+        return sb.toString();
+    }
+
+    public static String getHelpOnCommandLineInterfaceFunction(String command) {
+        int cpt = 0;
+
+        command = command.toLowerCase();
+        for(String s: CLI_COMMANDS) {
+            if (s.toLowerCase().compareTo(command) == 0) {
+                return CLI_PROTOTYPES[cpt] + ": " + CLI_HELP_COMMANDS[cpt];
+            }
+            cpt ++;
+        }
+        return null;
+
+    }
+
     public static String getPanelClassName() {
 	return "TMLArchiDiagramPanel";
     }
@@ -88,6 +134,15 @@ public class CustomizerGraphicalComponent {
 	return "Plugin component";
     }
 
+
+    public static String getWidthS() {
+        return "100";
+    }
+
+    public static String getHeightS() {
+        return "50";
+    }
+
     public static int getWidth() {
 	return 100;
     }
@@ -96,6 +151,10 @@ public class CustomizerGraphicalComponent {
 	return 50;
     }
 
+    public static void setDefaultWidth(int defaultWith) {
+        DEFAULT_WIDTH = defaultWith;
+    }
+
 
     public boolean isMoveable() {
 	return true;
@@ -119,8 +178,8 @@ public class CustomizerGraphicalComponent {
 
     
     public int getWidth(Graphics g, String _value) {
-	int w = g.getFontMetrics ().stringWidth (_value);
-	return w + 20;	
+	    int w = g.getFontMetrics ().stringWidth (_value);
+	    return w + 20;
     }
 
     public int getHeight(Graphics g, String _value) {
@@ -128,23 +187,23 @@ public class CustomizerGraphicalComponent {
     }
     
     public void internalDrawing(Graphics g, int _x, int _y, int _width, int _height, String _value, String _diagramName) {
-	g.drawRect(_x, _y, _width, _height);
-	g.drawString(_value, _x+5, _y+20);
+	    g.drawRect(_x, _y, _width, _height);
+	    g.drawString(_value, _x+5, _y+20);
     }
 
     public boolean isOnMe(int _x, int _y, int _width, int _height, int _xP, int _yP) {
-	if ((_xP>_x) && (_xP<_x+_width) && (_yP>_y) && (_yP<_y+_height)) {
-	    return true;
-	}
+	    if ((_xP>_x) && (_xP<_x+_width) && (_yP>_y) && (_yP<_y+_height)) {
+	        return true;
+	    }
 	return false;
     }
 
     public String editOnDoubleClick(JFrame _frame, String _value) {
-	String s = (String)JOptionPane.showInputDialog(_frame, "My plugin component name",
+	    String s = (String)JOptionPane.showInputDialog(_frame, "My plugin component name",
 						       "setting value", JOptionPane.PLAIN_MESSAGE, myIcon,
                                                            null,
                                                            _value);
-	return s;
+	    return s;
     }
     
     public static void main(String[] args) {
diff --git a/src/main/java/cli/Interpreter.java b/src/main/java/cli/Interpreter.java
index b5f027076f..991d47d615 100644
--- a/src/main/java/cli/Interpreter.java
+++ b/src/main/java/cli/Interpreter.java
@@ -58,7 +58,7 @@ import java.util.Vector;
  */
 public class Interpreter implements Runnable, TerminalProviderInterface {
 
-    public final static Command[] commands = {new Action(), new Help(), new History(), new Print(), new Quit(),
+    public final static Command[] commands = {new Action(), new Help(), new History(), new Print(), new PluginAction(), new Quit(),
             new TestSpecific(), new TML(), new Set(), new Wait(), new Robot(), new BF(), new SimulatorScript()};
 
     // Errors
diff --git a/src/main/java/cli/PluginAction.java b/src/main/java/cli/PluginAction.java
new file mode 100644
index 0000000000..e4c960ea98
--- /dev/null
+++ b/src/main/java/cli/PluginAction.java
@@ -0,0 +1,278 @@
+/* Copyright or (C) or Copr. GET / ENST, Telecom-Paris, Ludovic Apvrille
+ *
+ * ludovic.apvrille AT enst.fr
+ *
+ * This software is a computer program whose purpose is to allow the
+ * edition of TURTLE analysis, design and deployment diagrams, to
+ * allow the generation of RT-LOTOS or Java code from this diagram,
+ * and at last to allow the analysis of formal validation traces
+ * obtained from external tools, e.g. RTL from LAAS-CNRS and CADP
+ * from INRIA Rhone-Alpes.
+ *
+ * This software is governed by the CeCILL  license under French law and
+ * abiding by the rules of distribution of free software.  You can  use,
+ * modify and/ or redistribute the software under the terms of the CeCILL
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and  rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty  and the software's author,  the holder of the
+ * economic rights,  and the successive licensors  have only  limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading,  using,  modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean  that it is complicated to manipulate,  and  that  also
+ * therefore means  that it is reserved for developers  and  experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and,  more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms.
+ */
+
+
+package cli;
+
+import avatartranslator.AvatarSpecification;
+import avatartranslator.modelchecker.AvatarModelChecker;
+import avatartranslator.modelcheckervalidator.ModelCheckerValidator;
+import common.ConfigurationTTool;
+import common.SpecConfigTTool;
+import graph.RG;
+import launcher.RTLLauncher;
+import myutil.*;
+import tmltranslator.TMLMapping;
+import tmltranslator.TMLModeling;
+import ui.MainGUI;
+import ui.util.IconManager;
+import ui.window.JDialogSystemCGeneration;
+import ui.*;
+import java.awt.*;
+import java.io.File;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.List;
+
+
+/**
+ * Class PluginAction
+ * Creation: 12/06/2020
+ * Version 2.0 12/06/2020
+ *
+ * @author Ludovic APVRILLE
+ */
+public class PluginAction extends Command {
+    // Action commands
+    private final static String LIST_PLUGIN = "list";
+    private final static String INFO_PLUGIN = "info";
+    private final static String INFO_COMMAND_PLUGIN = "info-command";
+    private final static String LOAD_PLUGIN = "load";
+
+
+
+    public PluginAction() {
+
+    }
+
+    public List<Command> getListOfSubCommands() {
+        return subcommands;
+    }
+
+    public String getCommand() {
+        return "plugin";
+    }
+
+    public String getShortCommand() {
+        return "pl";
+    }
+
+    public String getUsage() {
+        return "action <subcommand> <options>";
+    }
+
+    public String getDescription() {
+        return "Can be used to performe actions with pluginsT";
+    }
+
+
+
+
+    public void fillSubCommands() {
+        // List
+        Command list = new Command() {
+            public String getCommand() {
+                return LIST_PLUGIN;
+            }
+
+            public String getShortCommand() {
+                return "li";
+            }
+
+            public String getDescription() {
+                return "List loaded plugins";
+            }
+
+            public String executeCommand(String command, Interpreter interpreter) {
+                if (PluginManager.pluginManager == null) {
+                    System.out.println("No plugins");
+                    return null;
+                }
+
+                StringBuffer sb = new StringBuffer("");
+                for(Plugin p: PluginManager.pluginManager.plugins) {
+                    sb.append(p.getName() + "\n");
+                }
+                System.out.println(sb.toString());
+
+                return null;
+            }
+        };
+
+        // info
+        Command info = new Command() {
+            public String getCommand() {
+                return INFO_PLUGIN;
+            }
+
+            public String getShortCommand() {
+                return "i";
+            }
+
+            public String getDescription() {
+                return "Get information on a given plugin";
+            }
+
+            public String executeCommand(String command, Interpreter interpreter) {
+                if (PluginManager.pluginManager == null) {
+                    return "No plugins";
+                }
+
+                String[] commands = command.split(" ");
+                if (commands.length < 1) {
+                    return Interpreter.BAD;
+                }
+
+                System.out.println("Info on plugin:" + commands[0]);
+                Plugin p = PluginManager.pluginManager.getPlugin(commands[0]);
+                if (p == null) {
+                    return "Unknown plugin " + commands[0];
+                }
+                StringBuffer sb = new StringBuffer("");
+                sb.append("Package:\t" + p.getPackageName() + "\n");
+                sb.append("Path:\t" + p.getPath() + "\n");
+                sb.append("Has graphical component?\t");
+                if (p.hasGraphicalComponent()) { sb.append("true\n");} else {sb.append("false\n");}
+                sb.append("Has Avatar code generator?\t");
+                if (p.hasAvatarCodeGenerator()) { sb.append("true\n");} else {sb.append("false\n");}
+                sb.append("Has Diplodocus code generator?\t");
+                if (p.hasDiplodocusCodeGenerator()) { sb.append("true\n");} else {sb.append("false\n");}
+                sb.append("Has Command line interface?\t");
+                if (p.hasCommandLineInterface()) {
+                    sb.append("true\n");
+                    sb.append("Custom commands: " + p.getCommandLineInterfaceFunctions());
+                } else {sb.append("false\n");}
+
+
+                System.out.println(sb.toString());
+
+                return null;
+            }
+        };
+
+
+        // info on command
+        Command infoCommand = new Command() {
+            public String getCommand() {
+                return INFO_COMMAND_PLUGIN;
+            }
+
+            public String getShortCommand() {
+                return "ic";
+            }
+
+            public String getDescription() {
+                return "Get information on a given command of a plugin";
+            }
+
+            public String executeCommand(String command, Interpreter interpreter) {
+                if (PluginManager.pluginManager == null) {
+                    return "No plugins";
+                }
+
+                String[] commands = command.split(" ");
+                if (commands.length < 2) {
+                    return Interpreter.BAD;
+                }
+
+                Plugin p = PluginManager.pluginManager.getPlugin(commands[0]);
+                if (p == null) {
+                    return "No such plugin";
+                }
+
+                String s = p.getHelpOnCommandLineInterfaceFunction(commands[1]);
+
+                if ((s == null) || (s.length() == 0))  {
+                    return "No such function";
+                }
+
+                System.out.println(s);
+
+                return null;
+            }
+        };
+
+        // load
+        Command load = new Command() {
+            public String getCommand() {
+                return LOAD_PLUGIN;
+            }
+
+            public String getShortCommand() {
+                return "lo";
+            }
+
+            public String getDescription() {
+                return "Load a new plugin. pl l <plugin path> <plugin name> <plugin package>";
+            }
+
+            public String executeCommand(String command, Interpreter interpreter) {
+                if (PluginManager.pluginManager == null) {
+                    PluginManager.pluginManager = new PluginManager();
+                }
+
+                String[] commands = command.split(" ");
+                if (commands.length < 2) {
+                    return Interpreter.BAD;
+                }
+
+                String []names = new String[1];
+                names[0] = commands[1];
+                String []packages = new String[1];
+                if (commands.length == 3) {
+                    packages[0] = commands[2];
+                } else {
+                    packages[0] = "";
+                }
+
+                PluginManager.pluginManager.preparePlugins(commands[0], names, packages);
+
+                return null;
+            }
+        };
+
+
+        addAndSortSubcommand(list);
+        addAndSortSubcommand(info);
+        addAndSortSubcommand(infoCommand);
+        addAndSortSubcommand(load);
+
+    }
+
+}
diff --git a/src/main/java/myutil/Plugin.java b/src/main/java/myutil/Plugin.java
index b4af971882..206af642db 100644
--- a/src/main/java/myutil/Plugin.java
+++ b/src/main/java/myutil/Plugin.java
@@ -62,6 +62,7 @@ public class Plugin {
     private Class classAvatarCodeGenerator;
     private Class classDiplodocusCodeGenerator;
     private Class classGraphicalComponent;
+    private Class classCommandLineInterface;
 
 
     public Plugin(String _path, String _name, String _packageName) {
@@ -75,17 +76,27 @@ public class Plugin {
         return name;
     }
 
+    public String getPackageName() {
+        return packageName;
+    }
+
     public String getPath() {
         return path;
     }
 
     public boolean hasAvatarCodeGenerator() {
-        String ret = executeRetStringMethod(removeJar(name), "hasAvatarCodeGenerator");
-        if (ret != null) {
-            classAvatarCodeGenerator = getClass(ret);
-            return true;
+        String ret = null;
+        try {
+            ret = executeRetStringMethod(removeJar(name), "hasAvatarCodeGenerator");
+            if (ret != null) {
+                classAvatarCodeGenerator = getClass(ret);
+                return true;
+            }
+        } catch(Exception e) {
+            return false;
         }
 
+
         return false;
     }
 
@@ -104,6 +115,41 @@ public class Plugin {
         return desc;
     }
 
+    public boolean hasCommandLineInterface() {
+        String ret = executeRetStringMethod(removeJar(name), "hasCommandLineInterface");
+        if (ret != null) {
+            classCommandLineInterface = getClass(ret);
+            return true;
+        }
+
+        return false;
+    }
+
+    public String getCommandLineInterfaceFunctions() {
+        String ret = executeRetStringMethod(removeJar(name), "getCommandsOfCommandLineInterface");
+        if (ret != null) {
+            return ret;
+        }
+
+        return "";
+    }
+
+    public String getHelpOnCommandLineInterfaceFunction(String command) {
+        if (classCommandLineInterface == null) {
+            hasCommandLineInterface();
+        }
+        if (classCommandLineInterface == null) {
+            return "";
+        }
+
+        String ret = executeStaticRetStringOneStringMethod(classCommandLineInterface,"getHelpOnCommandLineInterfaceFunction", command);
+        if (ret != null) {
+            return ret;
+        }
+
+        return "";
+    }
+
     public ImageIcon getDiplodocusCodeGeneratorLogo() {
         String mName = "getLogoImage";
         //TraceManager.addDev("Getting image with method=" + mName);
@@ -222,7 +268,7 @@ public class Plugin {
 
             return c.getMethod(_methodName);
         } catch (Exception e) {
-            e.printStackTrace( System.out );
+            //e.printStackTrace( System.out );
             TraceManager.addDev("Exception when using plugin " + name + " with className=" + _className + " and method " + _methodName);
             return null;
         }
@@ -231,11 +277,11 @@ public class Plugin {
 
     public String executeRetStringMethod(String _className, String _methodName) {
         // We have a valid plugin. We now need to get the Method
-        //TraceManager.addDev("-------- Getting " + _methodName + " of class " + _className);
+        TraceManager.addDev("-------- Getting " + _methodName + " of class " + _className);
         Method m = getMethod(_className, _methodName);
-        //TraceManager.addDev("-------- Got " + _methodName + " of class " + _className);
+        TraceManager.addDev("-------- Got " + _methodName + " of class " + _className);
         if (m == null) {
-            //TraceManager.addDev("Null method with class as a string class=" + _className + " _method=" + _methodName);
+            TraceManager.addDev("Null method with class as a string class=" + _className + " _method=" + _methodName);
             return null;
         }
 
@@ -296,6 +342,25 @@ public class Plugin {
         method.invoke(instance, value);
     }
 
+    public static String executeStaticRetStringOneStringMethod(Class<?> c, String _methodName, String value)  {
+        try {
+            Class[] cArg = new Class[1];
+            cArg[0] = String.class;
+            //TraceManager.addDev("Getting <" + _methodName + "> in class <" + c.getName() + ">");
+            Method m = c.getMethod(_methodName, cArg);
+
+            if (m == null) {
+                TraceManager.addDev("Null method in executeRetStringMethod with Class parameter");
+                return null;
+            }
+            return (String) (m.invoke(null, value));
+        } catch (Exception e) {
+            TraceManager.addDev("Exception occurred when executing method " + _methodName + " Exception: " + e.getMessage());
+            e.printStackTrace( System.out );
+            return null;
+        }
+    }
+
 
     public ImageIcon executeRetImageIconMethod(Class<?> c, String _methodName) {
         // We have a valid plugin. We now need to get the Method
diff --git a/src/main/java/myutil/PluginManager.java b/src/main/java/myutil/PluginManager.java
index 2a6b4e5cd3..e4308a1bbc 100644
--- a/src/main/java/myutil/PluginManager.java
+++ b/src/main/java/myutil/PluginManager.java
@@ -56,13 +56,12 @@ public class PluginManager {
     public static String PLUGIN_PATH = "";
 
     public ArrayList<Plugin> plugins;
-    public ArrayList<Plugin> pluginPackages;
 
     public PluginManager() {
         plugins = new ArrayList<Plugin>();
-        pluginPackages = new ArrayList<Plugin>();
     }
 
+
     public void preparePlugins(String path, String[] plugins, String[] packages) {
         PLUGIN_PATH = path;
         int cpt = 0;
-- 
GitLab