Subversion Repositories HomeAutomation

Rev

Rev 15 | Go to most recent revision | Blame | Last modification | View Log | SVN | RSS feed

  1. /**
  2.  * File created by Jimmy
  3.  * at 2003-dec-25 16:15:54
  4.  */
  5. package Macbeth.System;
  6.  
  7. import Macbeth.Utilities.*;
  8. import Macbeth.XML.XMLDataHandler;
  9. import Macbeth.XML.XMLParser;
  10. import Macbeth.Transports.MbLocalTransport;
  11. import Macbeth.Transports.MbInternetTransport;
  12.  
  13. import java.io.*;
  14. import java.util.Iterator;
  15. import java.util.LinkedList;
  16. import java.util.HashMap;
  17. import java.util.List;
  18.  
  19. import org.xml.sax.SAXException;
  20.  
  21. /**
  22.  * The Macbeth kernel. This is the core component that does all the
  23.  * work. You need to extend this class in order to create command-line
  24.  * kernels, GUI-kernels or whatever else.
  25.  * @author Jimmy
  26.  */
  27. public abstract class MbKernel extends MbComponent {
  28.  
  29.     //list of all existing modules (module names mapped to module class names)
  30.     protected HashMap moduleList;
  31.     //list of loaded modules (module names mapped to module objects)
  32.     protected HashMap loadedModules;
  33.     //our debug-output-stream (write meaningless debug-info here)
  34.     protected PrintStream _debug;
  35.     //our info-output-stream (write important info here)
  36.     protected PrintStream _info;
  37.     //our error-output-stream (write error messages here)
  38.     protected PrintStream _errors;
  39.     //our logfile-stream
  40.     protected PrintStream _log;
  41.     //a null-stream that ignores any data written to it
  42.     protected PrintStream _null;
  43.     //list of packet transports
  44.     protected List packetTransports;
  45.     //default transports
  46.     protected MbLocalTransport localTransport;
  47.     protected MbInternetTransport internetTransport;
  48.     //packet dumper
  49.     protected PacketDumper packetDumper;
  50.     //our kernel configuration XML-file
  51.     protected String configFile;
  52.     //our data repository. stores options and other data from the XML-file
  53.     protected DataRepository dataRepository;
  54.     //this points to the options data entry inside the data repository
  55.     protected DataRepository.DataListItem options;
  56.     //in this map, all used script events are mapped to lists filled with MbActions
  57.     protected HashMap scriptEventActions;
  58.  
  59.     /**
  60.      * Creates a new instance of MbKernel.
  61.      * @param configFile The XML-configuration file to use for this kernel.
  62.      */
  63.     public MbKernel(String configFile) {
  64.         //construct MbComponent
  65.         super();
  66.  
  67.         //remember configuration file
  68.         this.configFile = configFile;
  69.  
  70.         //create data repository
  71.         dataRepository = new DataRepository();
  72.         dataRepository.advancedBuild_BeginList("options");
  73.         dataRepository.advancedBuild_BeginListItem();
  74.         dataRepository.advancedBuild_EndListItem();
  75.         dataRepository.advancedBuild_EndList();
  76.         options = (DataRepository.DataListItem)dataRepository.getList("options").firstItem();
  77.  
  78.         //set default values on all our options
  79.         options.putField("kernelname", "Macbeth@" + System.getProperty("user.name").toString());
  80.         //options.putField("moduledirectory", System.getProperty("user.dir") + "\\bin\\");
  81.         options.putField("moduledirectory", System.getProperty("user.dir") + File.separator+"bin"+File.separator);
  82.         options.putField("debugstream.logged", "false");
  83.         options.putField("debugstream.timestamped", "false");
  84.         options.putField("debugstream.visible", "false");
  85.         options.putField("debugstream.prefix", "D ");
  86.         options.putField("infostream.logged", "false");
  87.         options.putField("infostream.timestamped", "true");
  88.         options.putField("infostream.visible", "true");
  89.         options.putField("infostream.prefix", "I ");
  90.         options.putField("errorstream.logged", "false");
  91.         options.putField("errorstream.timestamped", "true");
  92.         options.putField("errorstream.visible", "true");
  93.         options.putField("errorstream.prefix", "E ");
  94.  
  95.         //create output streams
  96.         _debug = System.out;
  97.         _info = System.out;
  98.         _errors = System.err;
  99.  
  100.         //log stream will be created during startup
  101.         _log = null;
  102.  
  103.         //create null stream
  104.         _null = new PrintStream(new PipedOutputStream());
  105.  
  106.         //create module lists
  107.         moduleList = new HashMap(32);
  108.         loadedModules = new HashMap(32);
  109.  
  110.         //create packet transport list
  111.         packetTransports = new LinkedList();
  112.         //TODO: search dynamically for installed transports at runtime instead.
  113.         //add local delivery transport
  114.         localTransport = new MbLocalTransport(this);
  115.         installTransport(localTransport);
  116.         //add internet delivery transport
  117.         internetTransport = new MbInternetTransport(this);
  118.         installTransport(internetTransport);
  119.  
  120.         //create packet dumper
  121.         packetDumper = new PacketDumper();
  122.  
  123.         //create the script map
  124.         scriptEventActions = new HashMap();
  125.     }
  126.  
  127.     /**
  128.      * Installs a packet delivery transport into this kernel.
  129.      * @param t The transport.
  130.      */
  131.     protected void installTransport(MbPacketTransport t) {
  132.         packetTransports.add(t);
  133.     }
  134.  
  135.     /**
  136.      * Gets the name of this kernel. Per default, this is
  137.      * "Macbeth@username" where username is your computer
  138.      * username.
  139.      * @return The kernel name.
  140.      */
  141.     public String name() {
  142.         return (String)options.getField("kernelname");
  143.     }
  144.  
  145.     /**
  146.      * Gets a short description of the kernel. This should
  147.      * be kept short (1-2 lines) and should be formatted as
  148.      * plain text.
  149.      * @return A short description of the kernel.
  150.      */
  151.     public abstract String description();
  152.  
  153.  
  154.     /**
  155.      * Call this when you want to trigger events from the kernel. Note that
  156.      * the event name you provide will automatically be prefixed by the string
  157.      * "Kernel.On" so that the final event string takes the form
  158.      * 'Kernel.OnXXX" where XXX is the event name you provide.
  159.      *
  160.      * @param eventName The name of the event. Please read above.
  161.      */
  162.     private final void triggerEvent(String eventName) {
  163.         triggerMacbethEvent("Kernel.On" + eventName);
  164.     }
  165.  
  166.  
  167.     /**
  168.      * Triggers a Macbeth event. The kernel will perform all Macbeth
  169.      * actions that are associated with this event.
  170.      *
  171.      * @param eventName The name of the Macbeth event that is being triggered.
  172.      */
  173.     public void triggerMacbethEvent(String eventName) {
  174.         //get all actions associated with this event
  175.         List l = (List) scriptEventActions.get(eventName);
  176.         if (l!=null) {
  177.             Iterator it = l.iterator();
  178.             while (it.hasNext()) {
  179.                 MbAction a = (MbAction) it.next();
  180.                 try {
  181.                     performAction(a);
  182.                 } catch (MbActionNotPerformedException e) {
  183.                     _errors.println("The scripted action '" + a.getActionString() + " " + a.getParameters() + "' could not be performed! (" + e.getMessage() + ")");
  184.                 }
  185.             }
  186.         }
  187.     }
  188.  
  189.  
  190.     /**
  191.      * Performs an action (called by scripts or by the user).
  192.      * @param action The Macbeth action that should be performed.
  193.      * @throws MbActionNotPerformedException If, for some reason, this action could not be performed.
  194.      */
  195.     protected void performAction(MbAction action) throws MbActionNotPerformedException {
  196.         //split the action string into owner and action name
  197.         String[] tokens = action.getActionString().split("\\.");
  198.         if (tokens.length!=2) {
  199.             throw new MbActionNotPerformedException("Invalid action string (format should be OWNER.ACTION)");
  200.         }
  201.         //extract owner
  202.         String owner = tokens[0];
  203.         String actionName = tokens[1];
  204.  
  205.         //if the action was owned by us (that is by the kernel), let's perform it
  206.         if (owner.equalsIgnoreCase("Kernel")) {
  207.             if (actionName.equalsIgnoreCase("LoadModule")) {
  208.                 try {
  209.                     loadModule(action.getParameters());
  210.                 } catch (MbModuleNotFoundException e) {
  211.                     throw new MbActionNotPerformedException("Module not found!");
  212.                 } catch (MbModuleLoadException e) {
  213.                     throw new MbActionNotPerformedException("Module found, but couldn't be loaded!");
  214.                 }
  215.             }
  216.             else if (actionName.equalsIgnoreCase("UnloadModule")) {
  217.                 if (!unloadModule(action.getParameters())) {
  218.                     throw new MbActionNotPerformedException("Module not loaded!");
  219.                 }
  220.             }
  221.             //TODO: action that can clean up the packet queue with some filtering abilities
  222.             //TODO: action that reloads all modules
  223.             else {
  224.                 throw new MbActionNotPerformedException("Unknown kernel action!");
  225.             }
  226.         }
  227.         //the action isn't owned by the kernel, so it must be owned by a module
  228.         else {
  229.             //try to get the owner module
  230.             MbModule m = (MbModule) loadedModules.get(owner);
  231.             //check if it existed
  232.             if (m==null) {
  233.                 throw new MbActionNotPerformedException("The module '" + owner + "' isn't loaded!");
  234.             }
  235.             //handle over the action to the module
  236.             m.performAction(action);
  237.         }
  238.     }
  239.  
  240.     /**
  241.      * Starts up this kernel.
  242.      */
  243.     public void startup() throws MbStartupException {
  244.         _debug.println("Macbeth kernel is starting up");
  245.         //start up MbComponent
  246.         super.startup();
  247.  
  248.         //create XML parser and parse configuration file
  249.         _debug.println("Parsing kernel configuration file: " + configFile);
  250.         XMLParser xmlParser = new XMLParser(new ConfigDataHandler());
  251.         try {
  252.             xmlParser.parseFile(configFile);
  253.         } catch (FileNotFoundException e) {
  254.             _errors.println("Configuration file '" + configFile + "' not found. Default settings will be used!");
  255.         } catch (IOException e) {
  256.             _errors.println("I/O error while reading '" + configFile + "'. Default settings will be used!");
  257.         } catch (SAXException e) {
  258.             _errors.println("XML Parsing error while reading '" + configFile + "'. Settings might have been lost. Please check syntax!");
  259.         }
  260.         _debug.println("Finished parsing kernel configuration file");
  261.  
  262.         //start up packet transport systems
  263.         _debug.println("Starting up packet transport systems:");
  264.         Iterator it = packetTransports.iterator();
  265.         while (it.hasNext()) {
  266.             MbPacketTransport pt = (MbPacketTransport)it.next();
  267.             if (pt!=null) {
  268.                 _debug.println("  - " + pt.getName());
  269.                 pt.startup();
  270.             }
  271.         }
  272.         _debug.println("OK, " + packetTransports.size() + " transports installed");
  273.  
  274.         //create a module list
  275.         _debug.println("Enumerating modules...");
  276.         LinkedList classList = new LinkedList();
  277.         try {
  278.             //_debug.println("moduledirectory: " + options.getField("moduledirectory"));
  279.             //try to load all classes that inherit from Macbeth.Systen.MbModule, since these are all modules
  280.             DynamicClassLoader.locateClasses(options.getField("moduledirectory"), "", new String[]{"Macbeth.System.MbModule"}, null, classList);
  281.         } catch (FileNotFoundException e) {
  282.             e.printStackTrace();
  283.         }
  284.         //iterate through the class list to find out the module names
  285.         it = classList.iterator();
  286.         while (it.hasNext()) {
  287.             String classname = (String)it.next();
  288.             try {
  289.                 Class c = DynamicClassLoader.loadClass(options.getField("moduledirectory"), classname);
  290.                 //construct a new module (so we can get its name)
  291.                 MbModule mod = (MbModule)c.newInstance();
  292.                 //save the module name mapped to the full classname in module list
  293.                 moduleList.put(mod.name(),classname);
  294.             } catch (Exception e) {
  295.                 e.printStackTrace();
  296.             }
  297.         }
  298.         _debug.println("OK, " + Integer.toString(classList.size()) + " modules found");
  299.  
  300.         _debug.println("Setting up streams (visibility, timestamping, logging)...");
  301.  
  302.         //create logstreams (that might be needed if logging is enabled)
  303.         String logfile = "Macbeth log " + MyDateTime.now("yyyy-MM-dd HH_mm_ss") + ".log";
  304.  
  305.         //if any logging is enabled
  306.         if (options.getField("debugstream.logged").equalsIgnoreCase("true") ||
  307.             options.getField("infostream.logged").equalsIgnoreCase("true") ||
  308.             options.getField("errorstream.logged").equalsIgnoreCase("true")) {
  309.             //create log stream
  310.             try {
  311.                 _log = new PrintStream(new FileOutputStream(logfile));
  312.             } catch (FileNotFoundException e) {
  313.                 //the log stream has to be valid in order to proceed
  314.                 throw new MbStartupException("Error while trying to create the log file '" + logfile + "'!");
  315.             }
  316.         }
  317.  
  318.         //if visibility is turned off for any of the streams, redirect them to null stream
  319.         if (options.getField("debugstream.visible").equalsIgnoreCase("false")) {
  320.             _debug = _null;
  321.         }
  322.         if (options.getField("infostream.visible").equalsIgnoreCase("false")) {
  323.             _info = _null;
  324.         }
  325.         if (options.getField("errorstream.visible").equalsIgnoreCase("false")) {
  326.             _errors = _null;
  327.         }
  328.  
  329.         //add logging to the streams
  330.         if (options.getField("debugstream.logged").equalsIgnoreCase("true")) {
  331.             _debug = new MultipleStreamsAdapter(_debug, _log);
  332.         }
  333.         if (options.getField("infostream.logged").equalsIgnoreCase("true")) {
  334.             _info = new MultipleStreamsAdapter(_info, _log);
  335.         }
  336.         if (options.getField("errorstream.logged").equalsIgnoreCase("true")) {
  337.             _errors = new MultipleStreamsAdapter(_errors, _log);
  338.         }
  339.  
  340.         //add prefixes to streams
  341.         _debug = new TextFormatterStream(_debug);
  342.         ((TextFormatterStream) _debug).setPreString(options.getField("debugstream.prefix"));
  343.         _info = new TextFormatterStream(_info);
  344.         ((TextFormatterStream) _info).setPreString(options.getField("infostream.prefix"));
  345.         _errors = new TextFormatterStream(_errors);
  346.         ((TextFormatterStream) _errors).setPreString(options.getField("errorstream.prefix"));
  347.  
  348.         //add timestamps to streams
  349.         if (options.getField("debugstream.timestamped").equalsIgnoreCase("true")) {
  350.             _debug = new TimeStampedStream(_debug);
  351.         }
  352.         if (options.getField("infostream.timestamped").equalsIgnoreCase("true")) {
  353.             _info = new TimeStampedStream(_info);
  354.         }
  355.         if (options.getField("errorstream.timestamped").equalsIgnoreCase("true")) {
  356.             _errors = new TimeStampedStream(_errors);
  357.         }
  358.  
  359.         //trigger the Startup-event now so any scripted post-processing can take place
  360.         triggerEvent("Startup");
  361.  
  362.         //everything is started up now
  363.         _info.println("Macbeth kernel started!");
  364.     }
  365.  
  366.     /**
  367.      * Loads and starts up a specific module. Before any modules
  368.      * can be loaded, the module list must have been created. The
  369.      * kernel will do this during startup, so normally this is not
  370.      * a problem.
  371.      * @param moduleName The name of the module that should be loaded.
  372.      * @return true if this module was loaded and started successfully,
  373.      * false if not (because the module was already started!).
  374.      * @throws MbModuleNotFoundException if the specified module isn't found.
  375.      * @throws MbModuleLoadException if the module cannot be loaded and started.
  376.      */
  377.     protected boolean loadModule(String moduleName) throws MbModuleNotFoundException, MbModuleLoadException {
  378.         //if module is already loaded
  379.         if (loadedModules.containsKey(moduleName)) {
  380.             //get out of here
  381.             return false;
  382.         }
  383.         //get classname from our module list
  384.         String classname = (String)moduleList.get(moduleName);
  385.         //if it was in the list
  386.         if (classname!=null) {
  387.             Class c;
  388.             MbModule mod;
  389.             try {
  390.                 //try to load class
  391.                 c = DynamicClassLoader.loadClass(options.getField("moduledirectory"),classname);
  392.                 //try to create new instance (and thus, constuct the module)
  393.                 mod = (MbModule)c.newInstance();
  394.             } catch (Exception e) {
  395.                 //module couldn't be loaded
  396.                 throw new MbModuleLoadException(e.getMessage());
  397.             }
  398.             //work out dependencies for this module
  399.             List dependencies = mod.getDependencies();
  400.             //if there are dependencies
  401.             if (!dependencies.isEmpty()) {
  402.                 //for each dependency
  403.                 Iterator it = dependencies.iterator();
  404.                 while (it.hasNext()) {
  405.                     String dpmod = (String)it.next();
  406.                     if (!loadedModules.containsKey(dpmod)) {
  407.                         _info.println("'" + mod.name() + "' depends on '" + dpmod + "'. This module will now be loaded as well!");
  408.                         loadModule(dpmod);
  409.                     }
  410.                 }
  411.             }
  412.             //try to start up module now
  413.             mod.setParentKernel(this);
  414.             try {
  415.                 mod.startup();
  416.                 //put module in our loaded modules-list
  417.                 loadedModules.put(mod.name(), mod);
  418.             }
  419.             //if module failed to start up
  420.             catch (MbStartupException e) {
  421.                 _errors.println("Module '" + mod.name() + "' failed to load! (" + e.getMessage() + ")");
  422.                 //shut down the parts of the module that were started up
  423.                 mod.shutdown();
  424.                 //and throw exception
  425.                 throw new MbModuleLoadException(e.getMessage());
  426.             }
  427.         }
  428.         //module wasn't found
  429.         else {
  430.             //so throw exception
  431.             throw new MbModuleNotFoundException("Module not found in module list!");
  432.         }
  433.         return true;
  434.     }
  435.  
  436.     /**
  437.      * Shuts down and unloads a specific module.
  438.      * @param moduleName The name of the module that should be unloaded.
  439.      * @return true if the module was shut down, false if not (because
  440.      * it wasn't even started in the first place!).
  441.      */
  442.     protected boolean unloadModule(String moduleName) {
  443.         //get the module from the enumeration list
  444.         MbModule mod = (MbModule)loadedModules.get(moduleName);
  445.         //if module was found (and thus, loaded)
  446.         if (mod != null) {
  447.             //shut it down
  448.             mod.shutdown();
  449.             loadedModules.remove(moduleName);
  450.         }
  451.         //module wasn't started
  452.         else {
  453.             return false;
  454.         }
  455.         return true;
  456.     }
  457.  
  458.     /**
  459.      * Returns a given macbeth module. The module must be loaded
  460.      * in this local kernel, or else an exception will be thrown.
  461.      * @param moduleName Classname of the module.
  462.      * @return The module. Null if it isn't found (that is, not loaded).
  463.      * be found within this kernel.
  464.      */
  465.     public MbModule getModule(String moduleName) {
  466.         return (MbModule)loadedModules.get(moduleName);
  467.     }
  468.  
  469.     /**
  470.      * Shuts down this kernel. Modules will be shut
  471.      * down and removed from module collection.
  472.      */
  473.     public void shutdown() {
  474.         _debug.println("Macbeth kernel is about to shut down");
  475.  
  476.         //trigger shutdown-event first so any scripted pre-processing can take place
  477.         triggerEvent("Shutdown");
  478.  
  479.         //shut down any loaded modules
  480.         if (!loadedModules.isEmpty()) {
  481.             _debug.println("Shutting down started modules:");
  482.             //iterate through all loaded modules
  483.             Iterator it = loadedModules.keySet().iterator();
  484.             while (it.hasNext()) {
  485.                 //shut down each loaded module
  486.                 String modname = (String)it.next();
  487.                 unloadModule(modname);
  488.                 //we have removed a module from the map, so iterator needs to be re-initialized!
  489.                 it = loadedModules.keySet().iterator();
  490.             }
  491.         }
  492.  
  493.         //shut down packet transport systems
  494.         if (!packetTransports.isEmpty()) {
  495.             _debug.println("Shutting down packet transport systems");
  496.             Iterator it = packetTransports.iterator();
  497.             while (it.hasNext()) {
  498.                 MbPacketTransport t = (MbPacketTransport)it.next();
  499.                 if (t!=null) {
  500.                     t.shutdown();
  501.                 }
  502.             }
  503.         }
  504.  
  505.         _info.println("Macbeth kernel successfully shut down");
  506.  
  507.         //shut down stream logging
  508.         if (_log!=null) {
  509.             _log.close();
  510.         }
  511.  
  512.         //shutdown MbComponent
  513.         super.shutdown();
  514.     }
  515.  
  516.     /**
  517.      * Will be called when a packet needs to be delivered to
  518.      * its specified destination module.
  519.      * @param p The packet that needs to be handled.
  520.      */
  521.     public void handlePacket(MbPacket p) {
  522.         //iterate through all registered packet transports
  523.         Iterator it = packetTransports.iterator();
  524.         boolean deliverySuccessful = false;
  525.         while (it.hasNext()) {
  526.             //try to deliver with each transport
  527.             MbPacketTransport t = (MbPacketTransport)it.next();
  528.             if (t!=null) {
  529.                 try {
  530.                     deliverySuccessful = t.deliverPacket(p);
  531.                 } catch (MbPacketTransport.MbPacketDeliveryException e) {
  532.                     //the transport attempted to deliver the packet, but failed
  533.                     _errors.println("Packet delivery error: " + e.getMessage());
  534.                     //dump the packet
  535.                     packetDumper.dumpPacket(p,t.getName() + " attempted to deliver the packet, but failed with the message \"" + e.getMessage() + "\"");
  536.                     //and get out of here
  537.                     return;
  538.                 }
  539.                 //if delivery was successful
  540.                 if (deliverySuccessful) {
  541.                     //get out of here
  542.                     return;
  543.                 }
  544.             }
  545.         }
  546.         //no transport could deliver the packet, so dump it
  547.         packetDumper.dumpPacket(p,"None of the transports could deliver this packet!");
  548.     }
  549.  
  550.  
  551.     /**
  552.      * A data handler for the XML-configuration file parser.
  553.      */
  554.     public class ConfigDataHandler implements XMLDataHandler {
  555.         private String currentEvent = null;
  556.  
  557.         public void XMLstartElement(String element, HashMap attributes) {
  558.             if (element.equals("list")) {
  559.                 if (attributes.containsKey("name")) {
  560.                     dataRepository.advancedBuild_BeginList((String)attributes.get("name"));
  561.                 }
  562.                 else {
  563.                     _errors.println("Syntax error in '" + configFile + "': 'name'-attribute missing in 'list'-tag!");
  564.                 }
  565.             }
  566.             else if (element.equals("item")) {
  567.                 dataRepository.advancedBuild_BeginListItem();
  568.             }
  569.             else if (element.equals("field")) {
  570.                 if (attributes.containsKey("name") && attributes.containsKey("value")) {
  571.                     dataRepository.advancedBuild_PutField((String)attributes.get("name"), (String)attributes.get("value"));
  572.                 }
  573.                 else {
  574.                     _errors.println("Syntax error in '" + configFile + "': 'name' and/or 'value'-attributes missing in 'datafield'-tag!");
  575.                 }
  576.             }
  577.             else if (element.equalsIgnoreCase("option")) {
  578.                 if (attributes.containsKey("name") && attributes.containsKey("value")) {
  579.                     options.putField((String)attributes.get("name"), (String)attributes.get("value"));
  580.                 }
  581.                 else {
  582.                     _errors.println("Syntax error in '" + configFile + "': 'name'- and/or 'value'-attributes are missing in an 'option'-tag!");
  583.                 }
  584.             }
  585.             else if (element.equalsIgnoreCase("event")) {
  586.                 if (attributes.containsKey("name")) {
  587.                     currentEvent = (String) attributes.get("name");
  588.                 }
  589.                 else {
  590.                     _errors.println("Syntax error in '" + configFile + "': 'name'-attribute missing in an 'event'-tag!");
  591.                 }
  592.             }
  593.             else if (element.equalsIgnoreCase("do")) {
  594.                 if (attributes.containsKey("action")) {
  595.                     String action = (String) attributes.get("action");
  596.                     String params = (String) attributes.get("params");
  597.                     //get the list of actions that are associated with this event so far
  598.                     List actionList = (List) scriptEventActions.get(currentEvent);
  599.                     //is this the first action associated with this event?
  600.                     if (actionList==null) {
  601.                         //if so, a new list needs to be created
  602.                         actionList = new LinkedList();
  603.                         //..and put into the events-actions-map
  604.                         scriptEventActions.put(currentEvent,actionList);
  605.                     }
  606.                     //now, add the new action to the list
  607.                     actionList.add(new MbAction(action, params));
  608.                 }
  609.                 else {
  610.                     _errors.println("Syntax error in '" + configFile + "': 'action'-attribute missing in a 'do'-tag!");
  611.                 }
  612.             }
  613.         }
  614.  
  615.         public void XMLendElement(String element) {
  616.             if (element.equals("list")) {
  617.                 dataRepository.advancedBuild_EndList();
  618.             }
  619.             else if (element.equals("item")) {
  620.                 dataRepository.advancedBuild_EndListItem();
  621.             }
  622.             else if (element.equals("event")) {
  623.                 currentEvent = null;
  624.             }
  625.         }
  626.         public void XMLelementData(String data) {}
  627.         public void XMLdocumentStart() {}
  628.         public void XMLdocumentEnd() {}
  629.     }
  630.  
  631.  
  632.     /**
  633.      * A packet dumper. This is invoked to kill packets that cannot be
  634.      * delivered. All packet dumps will be logged to a file,
  635.      */
  636.     protected class PacketDumper {
  637.         protected PrintStream log;
  638.         protected String startupTime;
  639.         protected String startupTime2;
  640.         protected int packetsDumped;
  641.  
  642.         public PacketDumper() {
  643.             //remember the startup time, because when packets are dumped for the first time
  644.             //we will need to create a file whose name contains our startup time.
  645.             startupTime = MyDateTime.now();
  646.             startupTime2 = MyDateTime.now("yyyy-MM-dd HH_mm_ss");
  647.             packetsDumped = 0;
  648.         }
  649.  
  650.         protected void finalize() throws Throwable {
  651.             if (log != null) {
  652.                 //close log stream
  653.                 log.flush();
  654.                 log.close();
  655.             }
  656.             super.finalize();
  657.         }
  658.  
  659.         /**
  660.          * Dumps a packet. Call this when a packet is invalid or the packet destination
  661.          * cannot be found. A log event will be created and the packet will be killed.
  662.          * @param p The packet that is invalid somehow, and thus needs to be dumped.
  663.          * @param reason The reason why the packet needs to be dumped.
  664.          */
  665.         public void dumpPacket(MbPacket p, String reason) {
  666.             if (log == null) {
  667.                 //create log output stream
  668.                 try {
  669.                     log = new PrintStream(new FileOutputStream("dumped packets " + startupTime2 + ".log"));
  670.                     log.println("Macbeth session started at " + startupTime + MySystem.lineBreak);
  671.                 } catch (FileNotFoundException e) {
  672.                     e.printStackTrace();
  673.                 }
  674.             }
  675.             String now = MyDateTime.now();
  676.             log.println("--Packet dump log event-----------------------------------------------");
  677.             log.println("[" + now + "]");
  678.             log.println("Dump reason:");
  679.             log.println(reason);
  680.             log.println("Packet was:");
  681.             log.println(p.serializeToString());
  682.             log.println("----------------------------------------------------------------------");
  683.             log.println();
  684.             _info.println("A packet was dumped! (Reason: " + reason + ")");
  685.             p = null;
  686.             packetsDumped++;
  687.         }
  688.     }
  689.  
  690. }
  691.