1 /*------------------------------------------------------------------------------
  2 Name:      TestSubMulti.java
  3 Project:   xmlBlaster.org
  4 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
  5 Comment:   Demo code for a client using xmlBlaster
  6 Version:   $Id: TestSubMulti.java 14833 2006-03-06 21:38:58Z laghi $
  7 ------------------------------------------------------------------------------*/
  8 package org.xmlBlaster.test.qos;
  9 
 10 import java.util.logging.Logger;
 11 import java.util.logging.Level;
 12 import org.xmlBlaster.util.Global;
 13 import org.xmlBlaster.util.XmlBlasterException;
 14 import org.xmlBlaster.util.Timestamp;
 15 import org.xmlBlaster.client.qos.ConnectQos;
 16 import org.xmlBlaster.client.I_XmlBlasterAccess;
 17 import org.xmlBlaster.client.I_Callback;
 18 import org.xmlBlaster.client.key.UpdateKey;
 19 import org.xmlBlaster.client.qos.UpdateQos;
 20 import org.xmlBlaster.client.qos.EraseReturnQos;
 21 import org.xmlBlaster.client.key.SubscribeKey;
 22 import org.xmlBlaster.client.qos.SubscribeQos;
 23 import org.xmlBlaster.client.key.PublishKey;
 24 import org.xmlBlaster.client.qos.PublishQos;
 25 import org.xmlBlaster.util.MsgUnit;
 26 
 27 import junit.framework.*;
 28 
 29 
 30 /**
 31  * This client tests multi subscribe() with a later publish() with XPath query.
 32  * <br />
 33  * The subscribes should be recognized for this later arriving publish()
 34  * Test is based on a bug report by Juergen Freidling
 35  * <p>
 36  * This client may be invoked multiple time on the same xmlBlaster server,
 37  * as it cleans up everything after his tests are done.
 38  * <p>
 39  * Invoke examples:<br />
 40  * <pre>
 41  *    java junit.textui.TestRunner org.xmlBlaster.test.qos.TestSubMulti
 42  *    java junit.swingui.TestRunner -noloading org.xmlBlaster.test.qos.TestSubMulti
 43  * </pre>
 44  */
 45 public class TestSubMulti extends TestCase implements I_Callback
 46 {
 47    private static String ME = "TestSubMulti";
 48    private final Global glob;
 49    private static Logger log = Logger.getLogger(TestSubMulti.class.getName());
 50 
 51    private String publishOid = "";
 52    private I_XmlBlasterAccess con;
 53    private String senderName;
 54    private String senderContent;
 55    private String receiverName;         // sender/receiver is here the same client
 56    private Timestamp sentTimestamp;
 57 
 58    private int numReceived = 0;         // error checking
 59    private final String contentMime = "text/xml";
 60    private final String contentMimeExtended = "action";
 61 
 62    /**
 63     * Constructs the TestSubMulti object.
 64     * <p />
 65     * @param testName  The name used in the test suite
 66     * @param loginName The name to login to the xmlBlaster
 67     */
 68    public TestSubMulti(Global glob, String testName, String loginName)
 69    {
 70        super(testName);
 71        this.glob = glob;
 72 
 73        this.senderName = loginName;
 74        this.receiverName = loginName;
 75    }
 76 
 77 
 78    /**
 79     * Sets up the fixture.
 80     * <p />
 81     * Connect to xmlBlaster and login
 82     */
 83    protected void setUp()
 84    {
 85       try {
 86          con = glob.getXmlBlasterAccess();
 87          String passwd = "secret";
 88          ConnectQos qos = new ConnectQos(glob, senderName, passwd);
 89          con.connect(qos, this); // Login to xmlBlaster
 90       }
 91       catch (Exception e) {
 92           log.severe("Login failed: " + e.toString());
 93           e.printStackTrace();
 94           assertTrue("Login failed: " + e.toString(), false);
 95       }
 96    }
 97 
 98 
 99    /**
100     * Tears down the fixture.
101     * <p />
102     * cleaning up .... erase() the previous message OID and logout
103     */
104    protected void tearDown()
105    {
106       try {
107          EraseReturnQos[] arr = con.erase("<key oid='"+publishOid+"'/>", "<qos/>");
108          assertEquals("Erase", 1, arr.length);
109       } catch(XmlBlasterException e) { fail("Erase XmlBlasterException: " + e.getMessage()); }
110 
111       con.disconnect(null);
112    }
113 
114 
115    /**
116     * TEST: Subscribe twice to messages with XPATH.
117     */
118    public void testSubscribeXPath()
119    {
120       log.info("Subscribing using XPath syntax ...");
121       try {
122         {
123           SubscribeKey key = new SubscribeKey(glob, "//key/location[@dest='agent-192.168.10.218']", "XPATH");
124           SubscribeQos qos = new SubscribeQos(glob);
125           con.subscribe(key.toXml(), qos.toXml(),this);
126         }
127 
128         {
129           SubscribeKey key = new SubscribeKey(glob, "//key[@contentMimeExtended='action']/location[@dest='agent-192.168.10.218' and @driver='PSD1']", "XPATH");
130           SubscribeQos qos = new SubscribeQos(glob);
131           con.subscribe(key.toXml(), qos.toXml(), this);
132         }
133       }
134       catch(XmlBlasterException e) {
135         log.warning("XmlBlasterException: " + e.getMessage());
136         assertTrue("publish - XmlBlasterException: " + e.getMessage(), false);
137       }
138    }
139 
140 
141    /**
142     * TEST: Construct a message and publish it.
143     */
144    public void testPublish()
145    {
146       log.info("Publishing a message ...");
147       numReceived = 0;
148 
149       PublishKey key = new PublishKey(glob, "", contentMime, contentMimeExtended);
150       key.setClientTags("<location dest='agent-192.168.10.218' driver='PSD1'></location>");
151       PublishQos qos = new PublishQos(glob);
152       senderContent = "some content";
153       try {
154          MsgUnit msgUnit = new MsgUnit(key.toXml(), senderContent.getBytes(), qos.toXml());
155          sentTimestamp = new Timestamp();
156          publishOid = con.publish(msgUnit).getKeyOid();
157          log.info("Success: Publishing done, returned oid=" + publishOid);
158       } catch(XmlBlasterException e) {
159          log.warning("XmlBlasterException: " + e.getMessage());
160          assertTrue("publish - XmlBlasterException: " + e.getMessage(), false);
161       }
162    }
163 
164 
165    /**
166     * TEST: Construct a message and publish it,<br />
167     * the previous XPath subscription should match and send an update.
168     */
169    public void testPublishAfterSubscribeXPath()
170    {
171       testSubscribeXPath();
172       waitOnUpdate(1000L, 0); // Wait some time for callback to arrive ... there should be no Callback
173 
174       testPublish();
175       waitOnUpdate(4000L, 2);
176    }
177 
178 
179    /**
180     * This is the callback method invoked from xmlBlaster
181     * delivering us a new asynchronous message. 
182     * @see org.xmlBlaster.client.I_Callback#update(String, UpdateKey, byte[], UpdateQos)
183     */
184    public String update(String cbSessionId, UpdateKey updateKey, byte[] content, UpdateQos updateQos)
185    {
186       log.info("Receiving update of message oid=" + updateKey.getOid() + "...");
187 
188       numReceived += 1;
189 
190       if (updateQos.isErased()) {
191          return "";
192       }
193 
194       assertEquals("Wrong sender", senderName, updateQos.getSender().getLoginName());
195       try { Thread.sleep(1000); } catch( InterruptedException i) {} // Sleep to assure that publish() is returned with publishOid
196       assertEquals("Wrong oid of message returned", publishOid, updateKey.getOid());
197       assertEquals("Message content is corrupted", new String(senderContent), new String(content));
198       assertEquals("Message contentMime is corrupted", contentMime, updateKey.getContentMime());
199       assertEquals("Message contentMimeExtended is corrupted", contentMimeExtended, updateKey.getContentMimeExtended());
200 
201       // Test requirement "engine.qos.update.rcvTimestamp":
202       assertTrue("sentTimestamp="+sentTimestamp+" not in hamony with rcvTimestamp="+updateQos.getRcvTimestamp(),
203              sentTimestamp.getMillis() < updateQos.getRcvTimestamp().getMillis() &&
204              (sentTimestamp.getMillis()+1000) > updateQos.getRcvTimestamp().getMillis());
205       return "";
206    }
207 
208    /**
209     * Little helper, waits until the wanted number of messages are arrived
210     * or returns when the given timeout occurs.
211     * <p />
212     * @param timeout in milliseconds
213     * @param numWait how many messages to wait
214     */
215    private void waitOnUpdate(final long timeout, final int numWait)
216    {
217       long pollingInterval = 50L;  // check every 0.05 seconds
218       if (timeout < 50)  pollingInterval = timeout / 10L;
219       long sum = 0L;
220       // check if too few are arriving
221       while (numReceived < numWait) {
222          try { Thread.sleep(pollingInterval); } catch( InterruptedException i) {}
223          sum += pollingInterval;
224          assertTrue("Timeout of " + timeout + " occurred without update", sum <= timeout);
225       }
226 
227       // check if too many are arriving
228       try { Thread.sleep(timeout); } catch( InterruptedException i) {}
229       assertEquals("Wrong number of messages arrived", numWait, numReceived);
230 
231       numReceived = 0;
232    }
233 
234    /**
235     * Method is used by TestRunner to load these tests
236     */
237    public static Test suite()
238    {
239        TestSuite suite= new TestSuite();
240        String loginName = "Tim";
241        suite.addTest(new TestSubMulti(new Global(), "testPublishAfterSubscribeXPath", loginName));
242        return suite;
243    }
244 
245 
246    /**
247     * Invoke: java org.xmlBlaster.test.qos.TestSubMulti
248     * @deprecated Use the TestRunner from the testsuite to run it:<p />
249     * <pre>   java -Djava.compiler= junit.textui.TestRunner org.xmlBlaster.test.qos.TestSubMulti</pre>
250     */
251    public static void main(String args[])
252    {
253       TestSubMulti testSub = new TestSubMulti(new Global(args), "TestSubMulti", "Tim");
254       testSub.setUp();
255       testSub.testPublishAfterSubscribeXPath();
256       testSub.tearDown();
257    }
258 }


syntax highlighted by Code2HTML, v. 0.9.1