Subversion Repositories HomeAutomation

Rev

Blame | Last modification | View Log | SVN | RSS feed

  1. /*
  2.  * MbModule.java
  3.  *
  4.  * Created on den 25 augusti 2003, 01:23
  5.  */
  6. package Macbeth.System;
  7.  
  8. import org.xml.sax.SAXException;
  9.  
  10. import java.io.PrintStream;
  11. import java.io.IOException;
  12. import java.io.FileNotFoundException;
  13. import java.util.LinkedList;
  14. import java.util.List;
  15. import java.util.HashMap;
  16.  
  17. import Macbeth.XML.XMLDataHandler;
  18. import Macbeth.XML.XMLParser;
  19. import Macbeth.Utilities.TextFormatterStream;
  20. import Macbeth.Utilities.DataRepository;
  21.  
  22. /**
  23.  * The Macbeth Module class. Extend this when creating
  24.  * your own modules.
  25.  * @author Jimmy
  26.  */
  27. abstract public class MbModule extends MbComponent implements MbPacketHandler {
  28.     //our packet XML parser
  29.     private XMLParser packetXMLParser;
  30.     //our configuration data handler (if any)
  31.     private XMLDataHandler configDataHandler;
  32.     //our packet data handler (if any)
  33.     private XMLDataHandler packetDataHandler;
  34.     //our html interface (if any)
  35.     private MbHTMLInterface htmlInterface;
  36.     //a list of other modules that we depend on
  37.     private List dependencies;
  38.     //our configuration file
  39.     protected String configFile;
  40.     //our data repository. stores options and other data from the XML-file
  41.     protected DataRepository dataRepository;
  42.     //this points to the options data entry inside the data repository
  43.     protected DataRepository.DataListItem options;
  44.  
  45.     /**
  46.      * Our debug output stream. Write debug-info to this
  47.      * stream. You can assume that information written
  48.      * to this stream is not necessarily visible to the
  49.      * user (only if he/she has turned it on).
  50.      */
  51.     protected PrintStream _debug;
  52.  
  53.     /**
  54.      * Our information output stream. Write non-critical
  55.      * information to this stream. This information will
  56.      * be visible to the user most of the time (unless
  57.      * he/she has turned it off).
  58.      */
  59.     protected PrintStream _info;
  60.  
  61.     /**
  62.      * Our error output stream. Write all error messages
  63.      * to this stream. This information will always be
  64.      * visible to the user.
  65.      */
  66.     protected PrintStream _errors;
  67.  
  68.     /**
  69.      * The parent kernel that loaded this module.
  70.      */
  71.     protected MbKernel parentKernel;
  72.  
  73.     /**
  74.      * This is always a reference to the packet that
  75.      * is currently being parsed, so if you need access
  76.      * to the packet during XML parsing, you can use this.
  77.      */
  78.     protected MbPacket currentPacket;
  79.  
  80.     /**
  81.      * Creates a new instance of MbModule.
  82.      */
  83.     public MbModule() {
  84.         //construct MbComponent
  85.         super();
  86.         parentKernel = null;
  87.         configDataHandler = null;
  88.         packetDataHandler = null;
  89.         currentPacket = null;
  90.         packetXMLParser = null;
  91.         htmlInterface = null;
  92.         configFile = "";
  93.         //create dependencies-list
  94.         dependencies = new LinkedList();
  95.         //default streams
  96.         _debug = System.out;
  97.         _info = System.out;
  98.         _errors = System.err;
  99.         //create data repository
  100.         dataRepository = new DataRepository();
  101.         dataRepository.advancedBuild_BeginList("options");
  102.         dataRepository.advancedBuild_BeginListItem();
  103.         dataRepository.advancedBuild_EndListItem();
  104.         dataRepository.advancedBuild_EndList();
  105.         options = (DataRepository.DataListItem)dataRepository.getList("options").firstItem();
  106.         //create configuration data handler
  107.         configDataHandler = new ConfigDataHandler();
  108.     }
  109.  
  110.     /**
  111.      * Gets the name of the module.
  112.      * @return The name of the module.
  113.      */
  114.     public abstract String name();
  115.  
  116.     /**
  117.      * Gets a short description of the module. This should
  118.      * be kept short (1-2 lines) and should be formatted as
  119.      * plain text.
  120.      * @return A short description of the component.
  121.      */
  122.     public abstract String description();
  123.  
  124.     /**
  125.      * Selects which XMLDataHandler should take care of the XML-data
  126.      * found when parsing the configuration file for this module.
  127.      * @param configDataHandler The XMLDataHandler.
  128.      * @deprecated Due to new configuration system. Get config data
  129.      * from data repository instead!
  130.      */
  131.     protected void setConfigDataHandler(XMLDataHandler configDataHandler) {
  132.         //this.configDataHandler = configDataHandler;
  133.     }
  134.  
  135.     /**
  136.      * Selects which XMLDataHandler should take care of the XML-data
  137.      * found in incoming packet.
  138.      * @param packetDataHandler The XMLDataHandler.
  139.      */
  140.     protected void setPacketDataHandler(XMLDataHandler packetDataHandler) {
  141.         this.packetDataHandler = packetDataHandler;
  142.     }
  143.  
  144.     /**
  145.      * Sets our HTML-interface.
  146.      * @param htmlInterface The html-interface.
  147.      */
  148.     protected void setHTMLInterface(MbHTMLInterface htmlInterface) {
  149.         this.htmlInterface = htmlInterface;
  150.     }
  151.  
  152.     /**
  153.      * Retreives this modules HTML-interface.
  154.      */
  155.     public MbHTMLInterface getHTMLInterface() {
  156.         return htmlInterface;
  157.     }
  158.  
  159.     /**
  160.      * Adds a module dependency. If your module depends on another
  161.      * modules you should call this with the module names in your
  162.      * constructor. The kernel will then make sure the dependency
  163.      * modules are started up before your module.
  164.      * @param moduleName
  165.      */
  166.     protected final void addDependency(String moduleName) {
  167.         if (!dependencies.contains(moduleName)) {
  168.             dependencies.add(moduleName);
  169.         }
  170.     }
  171.  
  172.     /**
  173.      * Returns this modules dependencies. This is a list containing
  174.      * the names of all modules that this module depend on.
  175.      * @return The dependencies-list.
  176.      */
  177.     public List getDependencies() {
  178.         return dependencies;
  179.     }
  180.  
  181.     /**
  182.      * Returns this modules data repository, which contains all the
  183.      * module options and its data lists.
  184.      * @return this modules data repository.
  185.      */
  186.     public DataRepository getDataRepository() {
  187.         return dataRepository;
  188.     }
  189.  
  190.     /**
  191.      * This method sets default values on all _required_ data
  192.      * fields in the data repository.
  193.      */
  194.     abstract protected void initDataFields();
  195.  
  196.     /**
  197.      * Will be called when this module should start up. Most
  198.      * initialization should be done here (rather than in the
  199.      * constructor).
  200.      * @throws MbStartupException if this module cannot
  201.      * start up for some reason.
  202.      */
  203.     public void startup() throws MbStartupException {
  204.         //this method will set default-values on all required data repository fields
  205.         initDataFields();
  206.         //if there is a packet data handler registered
  207.         if (packetDataHandler!=null) {
  208.             //create packet xml parser
  209.             packetXMLParser = new XMLParser(packetDataHandler);
  210.         }
  211.         //if there is a configuration data handler registered
  212.         if (configDataHandler!=null) {
  213.             //create XML parser and try to parse configuration file
  214.             XMLParser xmlParser = new XMLParser(configDataHandler);
  215.             configFile = "Config\\mod" + name() + ".xml";
  216.             try {
  217.                 xmlParser.parseFile(configFile);
  218.             } catch (FileNotFoundException e) {
  219.                 //no config file existed. that's OK, but warn user
  220.                 // (a config data handler was registered after all)
  221.                 _info.println("WARNING: a configuration data handler exists, but no configuration file was found!");
  222.             } catch (IOException e) {
  223.                 //I/O-exception. that's worse, so lets warn
  224.                 _errors.println("I/O-error while trying to read '" + configFile + "':");
  225.                 _errors.println(e);
  226.                 e.printStackTrace();
  227.             } catch (SAXException e) {
  228.                 _errors.println("The configuration file '" + configFile + "' contains syntax errors:");
  229.                 _errors.println(e);
  230.                 e.printStackTrace();
  231.             }
  232.         }
  233.         //now that config file is parsed, we can let the packet system start up
  234.         super.startup();
  235.         _debug.println("I was started up!");
  236.     }
  237.  
  238.     /**
  239.      * Will be called when this module should shut down itself.
  240.      * You cannot send any packets to other modules here, they
  241.      * might have been shut down already!
  242.      */
  243.     public void shutdown() {
  244.         super.shutdown();
  245.         _debug.println("I was shut down!");
  246.     }
  247.  
  248.     /**
  249.      * Sets this module's parent kernel.
  250.      * @param parentKernel The parent kernel that loaded this module.
  251.      */
  252.     public void setParentKernel(MbKernel parentKernel) {
  253.         this.parentKernel = parentKernel;
  254.         _debug = new TextFormatterStream(parentKernel._debug);
  255.         ((TextFormatterStream)_debug).setPreString(name() + ": ");
  256.         _info = new TextFormatterStream(parentKernel._info);
  257.         ((TextFormatterStream)_info).setPreString(name() + ": ");
  258.         _errors = new TextFormatterStream(parentKernel._errors);
  259.         ((TextFormatterStream)_errors).setPreString(name() + ": ");
  260.     }
  261.  
  262.     /**
  263.      * Sends a packet to the parent kernel.
  264.      * @param p The packet that should be sent.
  265.      */
  266.     final public void sendPacket(MbPacket p) {
  267.         //put our kernel- and module name into the packet source field
  268.         p.setSource(new MbLocation(parentKernel.name(),this.name()));
  269.         //tell kernel to receive the packet now
  270.         parentKernel.packetReceived(p);
  271.     }
  272.  
  273.     /**
  274.      * Will be called when a packet needs to be handled.
  275.      * Per default, this method invokes the XML-parser
  276.      * to parse the contents of the packet.
  277.      * @param p The packet that needs to be handled.
  278.      */
  279.     public void handlePacket(MbPacket p) {
  280.         //if we have an XML parser for packets
  281.         if (packetXMLParser!=null) {
  282.             //set current packet reference
  283.             currentPacket = p;
  284.             //try to parse this packets contents
  285.             try {
  286.                 packetXMLParser.parseString(p.serializeToString());
  287.             } catch (SAXException e) {
  288.                 _errors.println("Error while parsing packet. Probably bad syntax!");
  289.                 _errors.println("Error description was: " + e.getMessage());
  290.                 _errors.println("The packet was:");
  291.                 _errors.println(p.serializeToString());
  292.                 //probably not valid xml data
  293.                 e.printStackTrace();
  294.             } catch (IOException e) {
  295.                 e.printStackTrace();
  296.             }
  297.         }
  298.     }
  299.  
  300.  
  301.     /**
  302.      * Performs an action. This is where yor module can expose functionality
  303.      * for scripts and for the user.
  304.      *
  305.      * @param action The Macbeth action that should be performed.
  306.      * @throws MbActionNotPerformedException If the action ID is invalid.
  307.      */
  308.     public void performAction(MbAction action) throws MbActionNotPerformedException {
  309.         throw new MbActionNotPerformedException("Unknown action command!");
  310.     }
  311.  
  312.  
  313.     /**
  314.      * Call this when you want to trigger events from your module. Note that
  315.      * the event name you provide will automatically be prefixed by the module
  316.      * name and the string ".On" so that the final event string takes the form
  317.      * 'modulename.OnXXX" where XXX is the event name you provide.
  318.      *
  319.      * @param eventName The name of the event. Please read above.
  320.      */
  321.     private final void triggerEvent(String eventName) {
  322.         parentKernel.triggerMacbethEvent(name() + ".On" + eventName);
  323.     }
  324.  
  325.  
  326.     /**
  327.      * Takes care of XML-data found in configuration files.
  328.      */
  329.     private class ConfigDataHandler implements XMLDataHandler {
  330.         /**
  331.          * Called when start of a new element is found in the XML-data.
  332.          * @param element    The name of the element.
  333.          * @param attributes The element attributes.
  334.          */
  335.         public void XMLstartElement(String element, HashMap attributes) {
  336.             if (element.equals("list")) {
  337.                 if (attributes.containsKey("name")) {
  338.                     dataRepository.advancedBuild_BeginList((String)attributes.get("name"));
  339.                 }
  340.                 else {
  341.                     _errors.println("Syntax error in configuration file: 'name'-attribute missing in 'list'-tag!");
  342.                 }
  343.             }
  344.             else if (element.equals("item")) {
  345.                 dataRepository.advancedBuild_BeginListItem();
  346.             }
  347.             else if (element.equals("field")) {
  348.                 if (attributes.containsKey("name") && attributes.containsKey("value")) {
  349.                     dataRepository.advancedBuild_PutField((String)attributes.get("name"), (String)attributes.get("value"));
  350.                 }
  351.                 else {
  352.                     _errors.println("Syntax error in configuration file: 'name' and/or 'value'-attributes missing in 'datafield'-tag!");
  353.                 }
  354.             }
  355.             else if (element.equalsIgnoreCase("option")) {
  356.                 if (attributes.containsKey("name") && attributes.containsKey("value")) {
  357.                     options.putField((String)attributes.get("name"), (String)attributes.get("value"));
  358.                 }
  359.                 else {
  360.                     _errors.println("Syntax error in '" + configFile + "' - 'name'- and/or 'value'-attributes are missing in an 'option'-tag!");
  361.                 }
  362.             }
  363.         }
  364.  
  365.         public void XMLendElement(String element) {
  366.             if (element.equals("list")) {
  367.                 dataRepository.advancedBuild_EndList();
  368.             }
  369.             else if (element.equals("item")) {
  370.                 dataRepository.advancedBuild_EndListItem();
  371.             }
  372.         }
  373.  
  374.         public void XMLelementData(String data) {
  375.         }
  376.  
  377.         public void XMLdocumentStart() {
  378.         }
  379.  
  380.         public void XMLdocumentEnd() {
  381.         }
  382.     }
  383.  
  384. }
  385.