Subversion Repositories HomeAutomation

Rev

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

Rev Author Line No. Line
15 arune 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());
18 arune 80
        //options.putField("moduledirectory", System.getProperty("user.dir") + "\\bin\\");
81
        options.putField("moduledirectory", System.getProperty("user.dir") + File.separator+"bin"+File.separator);
15 arune 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 {
18 arune 278
            //_debug.println("moduledirectory: " + options.getField("moduledirectory"));
15 arune 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
}