1 /*------------------------------------------------------------------------------
  2 Name:      TestSubMultiSubscribe.java
  3 Project:   xmlBlaster.org
  4 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
  5 ------------------------------------------------------------------------------*/
  6 package org.xmlBlaster.test.qos;
  7 
  8 import java.util.logging.Logger;
  9 import java.util.logging.Level;
 10 import org.xmlBlaster.util.Global;
 11 import org.xmlBlaster.client.qos.ConnectQos;
 12 import org.xmlBlaster.util.XmlBlasterException;
 13 import org.xmlBlaster.util.def.Constants;
 14 import org.xmlBlaster.client.I_XmlBlasterAccess;
 15 import org.xmlBlaster.client.key.SubscribeKey;
 16 import org.xmlBlaster.client.qos.SubscribeQos;
 17 import org.xmlBlaster.client.key.UpdateKey;
 18 import org.xmlBlaster.client.qos.UpdateQos;
 19 import org.xmlBlaster.client.qos.EraseReturnQos;
 20 import org.xmlBlaster.client.qos.SubscribeReturnQos;
 21 import org.xmlBlaster.util.qos.AccessFilterQos;
 22 import org.xmlBlaster.util.MsgUnit;
 23 
 24 import org.xmlBlaster.test.Util;
 25 import org.xmlBlaster.test.Msg;
 26 import org.xmlBlaster.test.MsgInterceptor;
 27 
 28 import junit.framework.*;
 29 
 30 
 31 /**
 32  * This client tests a subscribe() with multiSubscribe=false to avoid receiving
 33  * duplicate updates from the same topic on multiple subscribes. 
 34  * <br />
 35  * This client may be invoked multiple time on the same xmlBlaster server,
 36  * as it cleans up everything after his tests are done.
 37  * <p>
 38  * Invoke examples:<br />
 39  * <pre>
 40  *    java junit.textui.TestRunner org.xmlBlaster.test.qos.TestSubMultiSubscribe
 41  *    java junit.swingui.TestRunner -noloading org.xmlBlaster.test.qos.TestSubMultiSubscribe
 42  * </pre>
 43  * @see <a href="http://www.xmlblaster.org/xmlBlaster/doc/requirements/engine.qos.subscribe.multiSubscribe.html" target="others">interface subscribe requirement</a>
 44  */
 45 public class TestSubMultiSubscribe extends TestCase
 46 {
 47    private static String ME = "TestSubMultiSubscribe";
 48    private final Global glob;
 49    private static Logger log = Logger.getLogger(TestSubMultiSubscribe.class.getName());
 50 
 51    private String subscribeId;
 52    private final String myDomain = "myDomain";
 53    private MsgInterceptor updateInterceptor;
 54    
 55    private String publishOid = "HelloMessageMultiSub";
 56    private I_XmlBlasterAccess connection;
 57 
 58    /**
 59     * Constructs the TestSubMultiSubscribe object.
 60     * <p />
 61     * @param testName  The name used in the test suite
 62     */
 63    public TestSubMultiSubscribe(Global glob, String testName) {
 64        super(testName);
 65        this.glob = glob;
 66 
 67    }
 68 
 69    /**
 70     * Sets up the fixture.
 71     */
 72    protected void setUp() {
 73       this.subscribeId = null;
 74       try {
 75          connection = glob.getXmlBlasterAccess(); // Find orb
 76          ConnectQos qos = new ConnectQos(glob);
 77          this.updateInterceptor = new MsgInterceptor(glob,log, null);
 78          connection.connect(qos, this.updateInterceptor);
 79       }
 80       catch (Exception e) {
 81           log.severe("Login failed: " + e.toString());
 82           e.printStackTrace();
 83           fail("Login failed: " + e.toString());
 84       }
 85    }
 86 
 87    /**
 88     * Tears down the fixture.
 89     * <p />
 90     * cleaning up .... erase() the previous message OID and logout
 91     */
 92    protected void tearDown() {
 93       if (this.connection != null) {
 94          if (this.publishOid != null) {
 95             String xmlKey = "<key oid='" + this.publishOid + "' queryType='EXACT'/>";
 96             try {
 97                EraseReturnQos[] arr = this.connection.erase(xmlKey, "<qos/>");
 98                assertEquals("Erase", 1, arr.length);
 99             } catch(XmlBlasterException e) { fail("Erase XmlBlasterException: " + e.getMessage()); }
100          }
101 
102          this.connection.disconnect(null);
103          this.connection = null;
104       }
105    }
106 
107    /**
108     * Subscribe multiple times to the same message with &lt;multiSubscribe>false&lt;/multiSubscribe>
109     */
110    public void subscribe(String queryString, String queryType, AccessFilterQos aq, int numSub) {
111       if (log.isLoggable(Level.FINE)) log.fine("Subscribing ...");
112       try {
113          for(int i=0; i<numSub; i++) {
114             SubscribeKey key = new SubscribeKey(glob, queryString, queryType);
115             SubscribeQos qos = new SubscribeQos(glob);
116             qos.setMultiSubscribe(false);
117             if (aq != null) {
118                qos.addAccessFilter(aq);
119             }
120             SubscribeReturnQos ret = this.connection.subscribe(key.toXml(), qos.toXml());
121             log.info("Subscribe #" + i + " state=" + ret.getState() + " subscriptionId=" + ret.getSubscriptionId());
122             if (subscribeId == null) {
123                subscribeId = ret.getSubscriptionId();
124                assertEquals("", Constants.STATE_OK, ret.getState());
125                continue;
126             }
127             assertEquals("", subscribeId, ret.getSubscriptionId());
128             assertEquals("", Constants.STATE_WARN, ret.getState());
129          }
130       } catch(XmlBlasterException e) {
131          log.warning("XmlBlasterException: " + e.getMessage());
132          fail("subscribe - XmlBlasterException: " + e.getMessage());
133       }
134    }
135 
136    /**
137     * Construct a message and publish it.
138     */
139    public void publish() {
140       if (log.isLoggable(Level.FINE)) log.fine("Publishing a message ...");
141 
142       String xmlKey = "<key oid='" + publishOid + "' domain='"+myDomain+"'/>";
143       String senderContent = "Yeahh, i'm the new content";
144       String xmlQos = "<qos><clientProperty name='phone'>1200003</clientProperty></qos>";
145       try {
146          MsgUnit msgUnit = new MsgUnit(xmlKey, senderContent.getBytes(), xmlQos);
147          publishOid = connection.publish(msgUnit).getKeyOid();
148          log.info("Success: Publishing done, returned oid=" + publishOid);
149       } catch(XmlBlasterException e) {
150          log.warning("XmlBlasterException: " + e.getMessage());
151          fail("publish - XmlBlasterException: " + e.getMessage());
152       }
153 
154       assertTrue("returned publishOid == null", publishOid != null);
155       assertTrue("returned publishOid", 0 != publishOid.length());
156    }
157 
158    /**
159     * unSubscribe twice to same message. 
160     */
161    public void unSubscribe() {
162       if (log.isLoggable(Level.FINE)) log.fine("unSubscribing ...");
163 
164       String qos = "<qos/>";
165       try {
166          connection.unSubscribe("<key oid='" + subscribeId + "'/>", qos);
167          log.info("Success: unSubscribe 1 on " + subscribeId + " done");
168       } catch(XmlBlasterException e) {
169          log.warning("XmlBlasterException: " + e.getMessage());
170          fail("unSubscribe - XmlBlasterException: " + e.getMessage());
171       }
172    }
173 
174    /**
175     * TEST: Construct a message and publish it,
176     * the first subscription shouldn't  receive the message as local==false
177     */
178    public void testMultiSubscribeOid() {
179       log.info("testMultiSubscribeOid ...");
180       
181       subscribe(publishOid, Constants.EXACT, null, 10);   // there should be no Callback 
182       assertEquals("", 0, this.updateInterceptor.waitOnUpdate(1000L, 0));
183 
184       int numPub = 5;
185       for (int i=0; i<numPub; i++)
186          publish();     // We expect numPub updates only
187       assertEquals("", numPub, this.updateInterceptor.waitOnUpdate(1000L, publishOid, Constants.STATE_OK));
188       this.updateInterceptor.clear();
189 
190       unSubscribe(); // One single unSubscribe should be enough
191 
192       publish();
193       assertEquals("", 0, this.updateInterceptor.waitOnUpdate(1000L, 0));
194    }
195 
196    /**
197     * TEST: Construct a message and publish it,
198     * the first subscription shouldn't  receive the message as local==false
199     */
200    public void testMultiSubscribeXPath() {
201       log.info("testMultiSubscribeXPath ...");
202       
203       subscribe("//key[@oid='"+publishOid+"']", Constants.XPATH, null, 10);   // there should be no Callback 
204       assertEquals("", 0, this.updateInterceptor.waitOnUpdate(1000L, 0));
205 
206       int numPub = 5;
207       for (int i=0; i<numPub; i++)
208          publish();     // We expect numPub updates only
209       assertEquals("", numPub, this.updateInterceptor.waitOnUpdate(1000L, publishOid, Constants.STATE_OK));
210       this.updateInterceptor.clear();
211 
212       unSubscribe(); // One single unSubscribe should be enough
213 
214       publish();
215       assertEquals("", 0, this.updateInterceptor.waitOnUpdate(1000L, 0));
216    }
217 
218    /**
219     * TEST: Change AccessFilter of SubscribeQos and test if reconfiguration works. 
220     */
221    public void testSubscribeReconfigure() {
222       log.info("testSubscribeReconfigure ...");
223 
224       final String filterType = "Sql92Filter";
225       final String filterVersion = "1.0";
226       String filterQuery = "phone LIKE '12%3'";
227 
228       {
229          log.info("Matching accessFilter");
230          AccessFilterQos aq = new AccessFilterQos(glob, filterType, filterVersion, filterQuery);
231          subscribe("//key[@oid='"+publishOid+"']", Constants.XPATH, aq, 1);
232          assertEquals("", 0, this.updateInterceptor.waitOnUpdate(1000L, 0));
233 
234          publish();
235          assertEquals("", 1, this.updateInterceptor.waitOnUpdate(1000L, publishOid, Constants.STATE_OK));
236          this.updateInterceptor.clear();
237       }
238 
239       {
240          log.info("NOT matching accessFilter");
241          filterQuery = "phone LIKE '1XX%3'";
242          AccessFilterQos aq = new AccessFilterQos(glob, filterType, filterVersion, filterQuery);
243          subscribe("//key[@oid='"+publishOid+"']", Constants.XPATH, aq, 1);
244          assertEquals("", 0, this.updateInterceptor.waitOnUpdate(1000L, 0));
245 
246          publish();
247          assertEquals("", 0, this.updateInterceptor.waitOnUpdate(1000L, 0));
248          this.updateInterceptor.clear();
249       }
250 
251       {
252          log.info("Matching accessFilter");
253          filterQuery = "phone LIKE '12%3'";
254          AccessFilterQos aq = new AccessFilterQos(glob, filterType, filterVersion, filterQuery);
255          subscribe("//key[@oid='"+publishOid+"']", Constants.XPATH, aq, 1);
256          assertEquals("", 0, this.updateInterceptor.waitOnUpdate(1000L, 0));
257 
258          publish();
259          assertEquals("", 1, this.updateInterceptor.waitOnUpdate(1000L, publishOid, Constants.STATE_OK));
260          this.updateInterceptor.clear();
261       }
262 
263       unSubscribe(); // One single unSubscribe should be enough
264 
265       publish();
266       assertEquals("", 0, this.updateInterceptor.waitOnUpdate(1000L, 0));
267    }
268 
269    /**
270     * TEST: Construct a message and publish it,
271     * the first subscription shouldn't  receive the message as local==false
272     */
273    public void testMultiSubscribeDomain() {
274       log.info("testMultiSubscribeDomain ...");
275       
276       // For domain queries the topic must exist: Therefor publish one message to create it!
277       publish();     // We expect numPub updates only
278 
279       subscribe(myDomain, Constants.DOMAIN, null, 10);   // there should be no Callback 
280       assertEquals("", 1, this.updateInterceptor.waitOnUpdate(1000L, 1));
281       this.updateInterceptor.clear();
282 
283       int numPub = 5;
284       for (int i=0; i<numPub; i++)
285          publish();     // We expect numPub updates only
286       assertEquals("", numPub, this.updateInterceptor.waitOnUpdate(1000L, publishOid, Constants.STATE_OK));
287       this.updateInterceptor.clear();
288 
289       unSubscribe(); // One single unSubscribe should be enough
290 
291       publish();
292       assertEquals("", 0, this.updateInterceptor.waitOnUpdate(1000L, 0));
293    }
294 
295    /**
296     * Method is used by TestRunner to load these tests
297     */
298    public static Test suite() {
299        TestSuite suite= new TestSuite();
300        suite.addTest(new TestSubMultiSubscribe(new Global(), "testMultiSubscribeOid"));
301        suite.addTest(new TestSubMultiSubscribe(new Global(), "testMultiSubscribeXPath"));
302        suite.addTest(new TestSubMultiSubscribe(new Global(), "testSubscribeReconfigure"));
303        suite.addTest(new TestSubMultiSubscribe(new Global(), "testMultiSubscribeDomain"));
304        return suite;
305    }
306 
307    /**
308     * Invoke: java org.xmlBlaster.test.qos.TestSubMultiSubscribe
309     * @deprecated Use the TestRunner from the testsuite to run it:<p />
310     * <pre>   java -Djava.compiler= junit.textui.TestRunner org.xmlBlaster.test.qos.TestSubMultiSubscribe</pre>
311     */
312    public static void main(String args[]) {
313       Global glob = new Global();
314       if (glob.init(args) != 0) {
315          System.err.println("Init failed");
316          System.exit(1);
317       }
318       TestSubMultiSubscribe testSub = new TestSubMultiSubscribe(glob, "TestSubMultiSubscribe");
319       testSub.setUp();
320       //testSub.testMultiSubscribeOid();
321       //testSub.testMultiSubscribeXPath();
322       testSub.testSubscribeReconfigure();
323       //testSub.testMultiSubscribeDomain();
324       testSub.tearDown();
325    }
326 }


syntax highlighted by Code2HTML, v. 0.9.1