Subversion Repositories HomeAutomation

Rev

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