Subversion Repositories HomeAutomation

Rev

Rev 641 | Details | Compare with Previous | Last modification | View Log | SVN | RSS feed

Rev Author Line No. Line
15 arune 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
 
18 arune 10
import java.io.File;
15 arune 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);
18 arune 216
            //configFile = "Config\\mod" + name() + ".xml";
217
            configFile = "Config"+File.separator+"mod" + name() + ".xml";
15 arune 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
}