Subversion Repositories HomeAutomation

Rev

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