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