1 /*-----t-------------------------------------------------------------------------
2 Name: TestPollerPlugin.java
3 Project: xmlBlaster.org
4 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
5 ------------------------------------------------------------------------------*/
6 package org.xmlBlaster.test.client;
7
8 import java.io.File;
9 import java.io.FileOutputStream;
10 import java.io.IOException;
11 import java.util.Properties;
12
13 import java.util.logging.Logger;
14 import org.xmlBlaster.client.I_Callback;
15 import org.xmlBlaster.client.filepoller.Publisher;
16 import org.xmlBlaster.client.key.SubscribeKey;
17 import org.xmlBlaster.client.key.UnSubscribeKey;
18 import org.xmlBlaster.client.key.UpdateKey;
19 import org.xmlBlaster.client.qos.ConnectQos;
20 import org.xmlBlaster.client.qos.DisconnectQos;
21 import org.xmlBlaster.client.qos.SubscribeQos;
22 import org.xmlBlaster.client.qos.UnSubscribeQos;
23 import org.xmlBlaster.client.qos.UpdateQos;
24 import org.xmlBlaster.test.MsgInterceptor;
25 import org.xmlBlaster.util.Global;
26 import org.xmlBlaster.util.XmlBlasterException;
27 import org.xmlBlaster.util.plugin.I_PluginConfig;
28 import org.xmlBlaster.util.qos.address.Address;
29
30 import junit.framework.TestCase;
31
32
33 /**
34 * <p>
35 * This is an interesting example, since it creates a XmlBlaster server instance
36 * in the same JVM , but in a separate thread, talking over CORBA with it.
37 * <p>
38 * Invoke examples:<br />
39 * <pre>
40 * java junit.textui.TestRunner -noloading org.xmlBlaster.test.client.TestFilePollerPlugin
41 * java junit.swingui.TestRunner -noloading org.xmlBlaster.test.client.TestFilePollerPlugin
42 * </pre>
43 * @see org.xmlBlaster.client.I_XmlBlasterAccess
44 */
45 public class TestFilePollerPlugin extends TestCase implements I_Callback {
46 private static String ME = "TestFilePollerPlugin";
47 private Global global;
48 private static Logger log = Logger.getLogger(TestFilePollerPlugin.class.getName());
49 private Global connGlobal;
50 private String oid = "filepollerTest";
51 private String dirName;
52 private String dirNameSent;
53 private String dirNameDiscarded;
54 private MsgInterceptor updateInterceptor;
55
56 private class PluginProperties extends Properties implements I_PluginConfig {
57 private final static long serialVersionUID = 1L;
58
59 public PluginProperties() {
60 super();
61 }
62
63 /**
64 * @see org.xmlBlaster.util.plugin.I_PluginConfig#getParameters()
65 */
66 public Properties getParameters() {
67 return this;
68 }
69
70 /**
71 * @see org.xmlBlaster.util.plugin.I_PluginConfig#getPrefix()
72 */
73 public String getPrefix() {
74 return "";
75 }
76
77 public String getType() {
78 return "";
79 }
80
81 public String getVersion() {
82 return "";
83 }
84 }
85
86 public TestFilePollerPlugin() {
87 this(null);
88 }
89
90 private void getBaseDir() {
91 try {
92 File dummy = File.createTempFile("dummy", null);
93 String path = dummy.getCanonicalPath();
94 dummy.delete();
95 int pos = path.lastIndexOf(File.separator);
96 if (pos < 0)
97 fail("the temporary path is not absolute '" + path + "'");
98 this.dirName = path.substring(0, pos) + "/testsuitePoller";
99 log.info("WILL USE THE DIRECTORY '" + this.dirName + "' AS THE BASE DIRECTORY");
100 this.dirNameSent = this.dirName + "/Sent";
101 this.dirNameDiscarded = this.dirName + "/Discarded";
102 }
103 catch(Exception ex) {
104 ex.printStackTrace();
105 fail("exception occured when trying to find out temporary path");
106 }
107 }
108
109
110 public TestFilePollerPlugin(Global global) {
111 super("TestFilePollerPlugin");
112 this.global = global;
113 if (this.global == null) {
114 this.global = new Global();
115 this.global.init((String[])null);
116 }
117
118 getBaseDir();
119 }
120
121 /**
122 * Sets up the fixture.
123 * <p />
124 * Connect to xmlBlaster and login
125 */
126 protected void setUp() {
127 /*
128 File file = new File(this.dirName);
129 if (file.exists())
130 FileLocator.deleteDir(file);
131 */
132 try {
133 this.connGlobal = this.global.getClone(null);
134 this.updateInterceptor = new MsgInterceptor(this.connGlobal, log, null);
135 this.connGlobal.getXmlBlasterAccess().connect(new ConnectQos(this.connGlobal), this.updateInterceptor);
136 SubscribeQos subQos = new SubscribeQos(this.connGlobal);
137 subQos.setWantInitialUpdate(false);
138 this.connGlobal.getXmlBlasterAccess().subscribe(new SubscribeKey(this.connGlobal, this.oid), subQos);
139 }
140 catch (XmlBlasterException ex) {
141 ex.printStackTrace();
142 fail("aborting since exception ex: " + ex.getMessage());
143 }
144 }
145
146
147 /**
148 * Tears down the fixture.
149 * <p />
150 * cleaning up .... erase() the previous message OID and logout
151 */
152 protected void tearDown() {
153 log.info("Entering tearDown(), test is finished");
154 cleanUpDirs();
155 try {
156 this.connGlobal.getXmlBlasterAccess().unSubscribe(new UnSubscribeKey(this.connGlobal, this.oid), new UnSubscribeQos(this.connGlobal));
157 this.connGlobal.getXmlBlasterAccess().disconnect(new DisconnectQos(this.connGlobal));
158 this.connGlobal.shutdown();
159 this.connGlobal = null;
160 }
161 catch (XmlBlasterException ex) {
162 ex.printStackTrace();
163 fail("aborting since exception ex: " + ex.getMessage());
164 }
165 }
166
167 public String update(String cbSessionId, UpdateKey updateKey, byte[] content, UpdateQos updateQos) throws XmlBlasterException {
168 String contentStr = new String(content);
169 String cont = (contentStr.length() > 10) ? (contentStr.substring(0,10)+"...") : contentStr;
170 log.info("Receiving update of a message oid=" + updateKey.getOid() +
171 " priority=" + updateQos.getPriority() +
172 " state=" + updateQos.getState() +
173 " content=" + cont);
174 log.info("further log for receiving update of a message cbSessionId=" + cbSessionId +
175 updateKey.toXml() + "\n" + new String(content) + updateQos.toXml());
176 log.severe("update: should never be invoked (msgInterceptors take care of it since they are passed on subscriptions)");
177
178 return "OK";
179 }
180
181 /**
182 * Tests the creation of the necessary directories
183 *
184 */
185 public void testDirectories() {
186 // absolute path
187 PluginProperties prop = new PluginProperties();
188 prop.put("topicName", "dummy");
189 prop.put("directoryName", this.dirName);
190 prop.put("sent", this.dirNameSent);
191 prop.put("discarded", this.dirNameDiscarded);
192 try {
193 new Publisher(this.global, "test", prop);
194 }
195 catch (XmlBlasterException ex) {
196 ex.printStackTrace();
197 assertTrue("An exception should not occur here " + ex.getMessage(), false);
198 }
199 checkDirs();
200
201 // repeat that with already existing directories
202 prop = new PluginProperties();
203 prop.put("topicName", "dummy");
204 prop.put("directoryName", this.dirName);
205 prop.put("sent", this.dirNameSent);
206 prop.put("discarded", this.dirNameDiscarded);
207 try {
208 new Publisher(this.global, "test", prop);
209 }
210 catch (XmlBlasterException ex) {
211 ex.printStackTrace();
212 assertTrue("An exception should not occur here " + ex.getMessage(), false);
213 }
214 checkDirs();
215 cleanUpDirs();
216
217 // relative path are added to the 'directoryName'
218 prop = new PluginProperties();
219 prop.put("topicName", "dummy");
220 prop.put("directoryName", this.dirName);
221 prop.put("sent", "Sent");
222 prop.put("discarded", "Discarded");
223 try {
224 new Publisher(this.global, "test", prop);
225 }
226 catch (XmlBlasterException ex) {
227 ex.printStackTrace();
228 assertTrue("An exception should not occur here " + ex.getMessage(), false);
229 }
230 checkDirs();
231 // relative path are added to the 'directoryName' repeat with existing directories
232 prop = new PluginProperties();
233 prop.put("topicName", "dummy");
234 prop.put("directoryName", this.dirName);
235 prop.put("sent", "Sent");
236 prop.put("discarded", "Discarded");
237 try {
238 new Publisher(this.global, "test", prop);
239 }
240 catch (XmlBlasterException ex) {
241 ex.printStackTrace();
242 assertTrue("An exception should not occur here " + ex.getMessage(), false);
243 }
244 checkDirs();
245
246 cleanUpDirs();
247
248 // now some which should fail:
249 // existing file but not a directory
250 File file = new File(this.dirName);
251 try {
252 file.createNewFile();
253 }
254 catch (IOException ex) {
255 assertTrue("could not create the file '" + this.dirName + "'", false);
256 }
257
258 prop = new PluginProperties();
259 prop.put("topicName", "dummy");
260 prop.put("directoryName", this.dirName);
261 prop.put("sent", "Sent");
262 prop.put("discarded", "Discarded");
263 try {
264 new Publisher(this.global, "test", prop);
265 assertTrue("an exception should occur since '" + this.dirName + "' is a file and should be a directory", false);
266 }
267 catch (XmlBlasterException ex) {
268 log.info("Exception is OK here");
269 }
270 cleanUpDirs();
271
272 try {
273 file = new File(this.dirName);
274 boolean ret = file.mkdir();
275 assertTrue("could not create directory '" + this.dirName + "'", ret);
276 file = new File(this.dirNameSent);
277 file.createNewFile();
278 }
279 catch (IOException ex) {
280 assertTrue("could not create the file '" + this.dirNameSent + "'", false);
281 }
282
283 prop = new PluginProperties();
284 prop.put("topicName", "dummy");
285 prop.put("directoryName", this.dirName);
286 prop.put("sent", "Sent");
287 prop.put("discarded", "Discarded");
288 try {
289 new Publisher(this.global, "test", prop);
290 assertTrue("an exception should occur since '" + this.dirName + "' is a file and should be a directory", false);
291 }
292 catch (XmlBlasterException ex) {
293 log.info("Exception is OK here");
294 }
295 cleanUpDirs();
296 }
297
298 private void singleDump(String filename, int filesize, String lockExt, long delay, boolean deliver, boolean absSubPath, String movedDir) {
299 String okFile = this.dirName + File.separator + filename;
300 byte[] okBuf = writeFile(okFile, filesize, lockExt, delay);
301 int ret = this.updateInterceptor.waitOnUpdate(delay);
302 boolean exist = false;
303 int sent = 1;
304 String txt = "";
305 if (!deliver) {
306 exist = true;
307 sent = 0;
308 txt = "not ";
309 }
310 assertEquals("expected '" + sent + "' update", sent, ret);
311 File tmp = new File(okFile);
312 assertEquals("the file '" + okFile + "' should " + txt + "have been removed", exist, tmp.exists());
313 if (deliver) {
314 checkMoved(filename, absSubPath, movedDir);
315 boolean sameContent = compareContent(okBuf, this.updateInterceptor.getMsgs()[0].getContent());
316 assertTrue("the content of the file is not the same as the arrived content of the update method", sameContent);
317 String fileName = this.updateInterceptor.getMsgs()[0].getUpdateQos().getClientProperty("_fileName", (String)null);
318 assertNotNull("The fileName is null", fileName);
319 assertEquals("", filename, fileName);
320 }
321 this.updateInterceptor.clear();
322 }
323
324 private void checkMoved(String name, boolean absSubPath, String subDirName) {
325 if (subDirName == null)
326 return;
327 File discDir = null;
328 if (absSubPath) {
329 discDir = new File(subDirName);
330 }
331 else {
332 discDir = new File(new File(this.dirName), subDirName);
333 }
334 File tmp = new File(discDir, name);
335 assertTrue("The directory '" + subDirName + "' must exist", discDir.exists());
336 assertTrue("The file '" + name + "' must exist in '" + subDirName + "' directory", tmp.exists());
337 }
338
339
340 private void doPublish(PluginProperties prop, boolean deliverFirst, boolean deliverSecond, boolean absSubPath) {
341 String lockExt = prop.getProperty("lockExtention", null);
342
343 prop.put("topicName", this.oid);
344 prop.put("directoryName", this.dirName);
345
346 int maximumSize = 10000;
347 long delaySinceLastChange = 1000L;
348 long pollInterval = 600L;
349 prop.put("maximumFileSize", "" + maximumSize);
350 prop.put("delaySinceLastFileChange", "" + delaySinceLastChange);
351 prop.put("pollInterval", "" + pollInterval);
352 prop.put("warnOnEmptyFileDelay", "1000");
353
354 String sent = prop.getProperty("sent", null);
355 String discarded = prop.getProperty("discarded", null);
356
357 org.xmlBlaster.engine.ServerScope engineGlobal = new org.xmlBlaster.engine.ServerScope();
358 prop.put("connectQos", this.getConnectQos(engineGlobal));
359
360 Publisher publisher = null;
361 try {
362 publisher = new Publisher(engineGlobal, "test", prop);
363 publisher.init();
364
365 this.updateInterceptor.clear();
366 // too big
367 String tooBig = this.dirName + File.separator + "tooBig.dat";
368 writeFile(tooBig, maximumSize+1, lockExt, delaySinceLastChange* 2);
369 int ret = this.updateInterceptor.waitOnUpdate(delaySinceLastChange* 2);
370 assertEquals("expected no updates", 0, ret);
371
372 File tmp = new File(tooBig);
373 if (deliverFirst) {
374 assertFalse("the file '" + tooBig + "' should have been removed", tmp.exists());
375 checkMoved("tooBig.dat", absSubPath, discarded);
376 }
377 else {
378 assertTrue("the file '" + tooBig + "' should still be here", tmp.exists());
379 }
380
381 this.updateInterceptor.clear();
382
383 singleDump("ok.dat", maximumSize-1, lockExt, delaySinceLastChange* 2, deliverFirst, absSubPath, sent);
384 singleDump("ok.gif", maximumSize-1, lockExt, delaySinceLastChange* 2, deliverSecond, absSubPath, sent);
385 }
386 catch (XmlBlasterException ex) {
387 ex.printStackTrace();
388 assertTrue("An exception should not occur here " + ex.getMessage(), false);
389 }
390 finally {
391 if (publisher != null) {
392 try {
393 publisher.shutdown();
394 }
395 catch (Throwable ex) {
396 ex.printStackTrace();
397 fail("exception when shutting down the poller " + ex.getMessage());
398 }
399 }
400 }
401 }
402
403 public void testSimplePublish() {
404 boolean deliverDat = true;
405 boolean deliverGif = true;
406 boolean absSubPath = true;
407 PluginProperties prop = new PluginProperties();
408 doPublish(prop, deliverDat, deliverGif, absSubPath);
409 }
410
411 public void testSimplePublishWithFilter() {
412 boolean deliverDat = false;
413 boolean deliverGif = true;
414 boolean absSubPath = true;
415 PluginProperties prop = new PluginProperties();
416 prop.put("fileFilter", "*.gif");
417 doPublish(prop, deliverDat, deliverGif, absSubPath);
418 }
419
420 public void testSimplePublishWithFilterRegex() {
421 boolean deliverDat = true;
422 boolean deliverGif = true;
423 boolean absSubPath = true;
424 PluginProperties prop = new PluginProperties();
425 prop.put("filterType", "regex");
426 // note that the double backslash would be simple if read from the configuration file
427 prop.put("fileFilter", "(.*\\.dat)|(.*\\.gif)");
428 doPublish(prop, deliverDat, deliverGif, absSubPath);
429 }
430
431 public void testPublishWithMoveAbsolute() {
432 boolean deliverDat = true;
433 boolean deliverGif = true;
434 boolean absSubPath = true;
435 PluginProperties prop = new PluginProperties();
436 prop.put("sent", this.dirName + File.separator + "Sent");
437 prop.put("discarded", this.dirName + File.separator + "Discarded");
438 doPublish(prop, deliverDat, deliverGif, absSubPath);
439 }
440
441 public void testPublishWithMoveRelative() {
442 boolean deliverDat = true;
443 boolean deliverGif = true;
444 boolean absSubPath = false;
445 PluginProperties prop = new PluginProperties();
446 prop.put("sent", "Sent");
447 prop.put("discarded", "Discarded");
448 doPublish(prop, deliverDat, deliverGif, absSubPath);
449 }
450
451 public void testPublishWithMoveRelativeLockMode() {
452 boolean deliverDat = true;
453 boolean deliverGif = true;
454 boolean absSubPath = false;
455 PluginProperties prop = new PluginProperties();
456 prop.put("sent", "Sent");
457 prop.put("discarded", "Discarded");
458 prop.put("lockExtention", "*.lck");
459 doPublish(prop, deliverDat, deliverGif, absSubPath);
460 }
461
462 public void testSimplePublishWithFilterLockMode() {
463 boolean deliverDat = false;
464 boolean deliverGif = true;
465 boolean absSubPath = true;
466 PluginProperties prop = new PluginProperties();
467 prop.put("fileFilter", "*.gif");
468 prop.put("lockExtention", "*.lck");
469 doPublish(prop, deliverDat, deliverGif, absSubPath);
470 }
471
472 /*
473 prop.put("sent", "Sent");
474 prop.put("discarded", "Discarded");
475 prop.put("publishKey", "");
476 prop.put("publishQos", "");
477 prop.put("connectQos", "");
478 prop.put("loginName", "");
479 prop.put("password", "");
480 prop.put("fileFilter", "");
481 prop.put("lockExtention", "*.lck");
482 */
483
484 private boolean compareContent(byte[] buf1, byte[] buf2) {
485 if (buf1 == null && buf2 == null)
486 return true;
487
488 if (buf1 == null || buf2 == null)
489 return false;
490
491 if (buf1.length != buf2.length)
492 return false;
493 for (int i=0; i < buf1.length; i++) {
494 if (buf1[i] != buf2[i])
495 return false;
496 }
497 return true;
498 }
499
500 private byte[] writeFile(String filename, int size, String lockExt, long timeToWait) {
501 try {
502 File lock = null;
503 if (lockExt != null) {
504 String tmp = filename + lockExt.substring(1);
505 lock = new File(tmp);
506 boolean ret = lock.createNewFile();
507 assertTrue("could not create lock file '" + tmp + "'", ret);
508 int upd = this.updateInterceptor.waitOnUpdate(timeToWait);
509 assertEquals("when writing lock file should not update", 0, upd);
510 }
511 else
512 this.updateInterceptor.waitOnUpdate(timeToWait);
513
514 byte[] buf = new byte[size];
515 for (int i=0; i < size; i++) {
516 buf[i] = (byte)i;
517 }
518 FileOutputStream fos = new FileOutputStream(filename);
519 fos.write(buf);
520 fos.close();
521
522 if (lockExt != null) {
523 int upd = this.updateInterceptor.waitOnUpdate(timeToWait);
524 assertEquals("when still locked by lockfile should not update", 0, upd);
525 File tmp = new File(filename);
526 assertTrue("file '" + filename + "' should still exist since lock file exists", tmp.exists());
527 }
528 else
529 this.updateInterceptor.waitOnUpdate(timeToWait);
530 if (lock != null) {
531 boolean ret = lock.delete();
532 assertTrue("could not remove lock file '" + filename + lockExt.substring(1) + "'", ret);
533 }
534 return buf;
535 }
536 catch (IOException ex) {
537 ex.printStackTrace();
538 fail("could not write to file '" + filename + "'");
539 return null; // fake return to make compiler happy
540 }
541 }
542
543
544 private void checkDirs() {
545 File file = new File(this.dirName);
546 assertTrue("file '" + this.dirName + "' does not exist", file.exists());
547 file = new File(this.dirNameSent);
548 assertTrue("file '" + this.dirNameSent + "' does not exist", file.exists());
549 file = new File(this.dirNameDiscarded);
550 assertTrue("file '" + this.dirNameDiscarded + "' does not exist", file.exists());
551 }
552
553 private String getConnectQos(Global glob) {
554 try {
555 ConnectQos connQos = new ConnectQos(glob, "filePollerTestUser", "secret");
556 connQos.setMaxSessions(100);
557 Address address = connQos.getAddress();
558 address.setPingInterval(0L);
559 address.setCollectTime(0L);
560 connQos.getClientQueueProperty().setType("RAM");
561 connQos.getClientQueueProperty().setVersion("1.0");
562 return connQos.toXml();
563 }
564 catch (XmlBlasterException ex) {
565 fail("an exception when building the connect qos: " + ex.getMessage());
566 return null;
567 }
568 }
569
570 private void delete(String filename) {
571 try {
572 (new File(filename)).delete();
573 }
574 catch (Throwable ex) {
575 }
576 }
577
578 private void cleanUpDirs() {
579 delete(this.dirNameSent + File.separator + "ok.dat");
580 delete(this.dirNameSent + File.separator + "ok.gif");
581 delete(this.dirNameSent);
582 delete(this.dirNameDiscarded + File.separator + "tooBig.dat");
583 delete(this.dirNameDiscarded);
584 delete(this.dirName + File.separator + "ok.dat");
585 delete(this.dirName + File.separator + "ok.dat.lck");
586 delete(this.dirName + File.separator + "ok.gif");
587 delete(this.dirName + File.separator + "ok.gif.lck");
588 delete(this.dirName + File.separator + "tooBig.dat");
589 delete(this.dirName + File.separator + "tooBig.dat.lck");
590
591 delete(this.dirName);
592 }
593
594
595 /**
596 * Invoke: java org.xmlBlaster.test.client.TestFilePollerPlugin
597 * <p />
598 * @deprecated Use the TestRunner from the testsuite to run it:<p />
599 * <pre> java -Djava.compiler= junit.textui.TestRunner org.xmlBlaster.test.client.TestFilePollerPlugin</pre>
600 */
601 public static void main(String args[]) {
602 Global global = new Global();
603 if (global.init(args) != 0) {
604 System.out.println(ME + ": Init failed");
605 System.exit(1);
606 }
607
608 TestFilePollerPlugin test = new TestFilePollerPlugin(global);
609 /*
610 test.setUp();
611 test.testDirectories();
612 test.tearDown();
613
614 test.setUp();
615 test.testSimplePublish();
616 test.tearDown();
617
618 test.setUp();
619 test.testSimplePublishWithFilter();
620 test.tearDown();
621
622 test.setUp();
623 test.testSimplePublishWithFilterRegex();
624 test.tearDown();
625
626 test.setUp();
627 test.testPublishWithMoveAbsolute();
628 test.tearDown();
629
630 test.setUp();
631 test.testPublishWithMoveRelative();
632 test.tearDown();
633
634 test.setUp();
635 test.testPublishWithMoveRelativeLockMode();
636 test.tearDown();
637 */
638 test.setUp();
639 test.testSimplePublishWithFilterLockMode();
640 test.tearDown();
641 }
642 }
syntax highlighted by Code2HTML, v. 0.9.1