1 // xmlBlaster/demo/javaclients/HelloWorldPublish.java
  2 package javaclients;
  3 
  4 import java.io.UnsupportedEncodingException;
  5 import java.util.Iterator;
  6 import java.util.Map;
  7 import java.util.Random;
  8 import java.util.logging.Level;
  9 import java.util.logging.Logger;
 10 
 11 import org.xmlBlaster.client.I_Callback;
 12 import org.xmlBlaster.client.I_ConnectionStateListener;
 13 import org.xmlBlaster.client.I_XmlBlasterAccess;
 14 import org.xmlBlaster.client.key.EraseKey;
 15 import org.xmlBlaster.client.key.PublishKey;
 16 import org.xmlBlaster.client.key.UpdateKey;
 17 import org.xmlBlaster.client.qos.ConnectQos;
 18 import org.xmlBlaster.client.qos.ConnectReturnQos;
 19 import org.xmlBlaster.client.qos.DisconnectQos;
 20 import org.xmlBlaster.client.qos.EraseQos;
 21 import org.xmlBlaster.client.qos.PublishQos;
 22 import org.xmlBlaster.client.qos.PublishReturnQos;
 23 import org.xmlBlaster.client.qos.UpdateQos;
 24 import org.xmlBlaster.util.FileLocator;
 25 import org.xmlBlaster.util.Global;
 26 import org.xmlBlaster.util.IsoDateParser;
 27 import org.xmlBlaster.util.MsgUnit;
 28 import org.xmlBlaster.util.SessionName;
 29 import org.xmlBlaster.util.StringPairTokenizer;
 30 import org.xmlBlaster.util.Timestamp;
 31 import org.xmlBlaster.util.XmlBlasterException;
 32 import org.xmlBlaster.util.def.Constants;
 33 import org.xmlBlaster.util.def.MethodName;
 34 import org.xmlBlaster.util.def.PriorityEnum;
 35 import org.xmlBlaster.util.dispatch.ConnectionStateEnum;
 36 import org.xmlBlaster.util.dispatch.I_PostSendListener;
 37 import org.xmlBlaster.util.qos.TopicProperty;
 38 import org.xmlBlaster.util.qos.address.Destination;
 39 import org.xmlBlaster.util.qos.storage.HistoryQueueProperty;
 40 import org.xmlBlaster.util.queuemsg.MsgQueueEntry;
 41 
 42 /**
 43  * This client connects to xmlBlaster and publishes a configurable amount of messages.
 44  * <p>
 45  * This is a nice client to experiment and play with xmlBlaster as there are many
 46  * command line options to specify the type and amount of messages published.
 47  * </p>
 48  * <p>
 49  * Try using 'java javaclients.HelloWorldSubscribe' in another window to subscribe to
 50  * our messages.
 51  * Further you can type 'd' in the window running xmlBlaster to get a server dump.
 52  * </p>
 53  *
 54  * Invoke (after starting the xmlBlaster server):
 55  * <pre>
 56  *Publish manually 10 messages:
 57  * java javaclients.HelloWorldPublish -interactive true -numPublish 10 -oid Hello -persistent true -erase true
 58  *
 59  *Publish automatically 10 messages and sleep 1 sec in between:
 60  * java javaclients.HelloWorldPublish -interactive false -sleep 1000 -numPublish 10 -oid Hello -persistent true -erase true
 61  *
 62  *Publish automatically 10 different topics with different DOM entries:
 63  * java javaclients.HelloWorldPublish -interactive false -numPublish 10 -oid Hello-${counter} -clientTags "<org.xmlBlaster><demo-${counter}/></org.xmlBlaster>"
 64  *
 65  *Login as joe/5 and send one persistent message:
 66  * java javaclients.HelloWorldPublish -session.name joe/5 -passwd secret -persistent true -dump[HelloWorldPublish] true
 67  *
 68  *Send a PtP message:
 69  * java javaclients.HelloWorldPublish -destination jack/17 -forceQueuing true -persistent true -subscribable true
 70  *
 71  *Add some client properties which will be send in the qos to the receivers:
 72  * java javaclients.HelloWorldPublish -clientProperty[transactionId] 0x23345 -clientProperty[myName] jack
 73  *creates a publish Qos containing:
 74  *   &lt;clientProperty name='transactionId'>0x23345&lt;/clientProperty>
 75  *   &lt;clientProperty name='myName'>jack&lt;/clientProperty>
 76  * </pre>
 77  * <p>
 78  * If interactive is false, the sleep gives the number of millis to sleep before publishing the next message.
 79  * </p>
 80  * <p>
 81  * If erase=false the message is not erase at the end, if disconnect=false we don't logout at the end.
 82  * </p>
 83  * <p>
 84  * You can add '${counter}' or '${timestamp}' to the clientTags or the content string, each occurrence will be replaced
 85  * by the current message number and current UTC timestamp.
 86  * </p>
 87  * @see javaclients.HelloWorldSubscribe
 88  * @see <a href="http://www.xmlBlaster.org/xmlBlaster/doc/requirements/interface.html" target="others">xmlBlaster interface</a>
 89  */
 90 public class HelloWorldPublish
 91 {
 92    private final Global glob;
 93    private static Logger log = Logger.getLogger(HelloWorldPublish.class.getName());
 94    private boolean replacePlaceHolders = true;
 95 
 96    public HelloWorldPublish(Global glob) {
 97       this.glob = glob;
 98 
 99       try {
100          replacePlaceHolders = glob.getProperty().get("replacePlaceHolders", replacePlaceHolders);
101          boolean interactive = glob.getProperty().get("interactive", true);
102          boolean oneway = glob.getProperty().get("oneway", false);
103          long sleep = glob.getProperty().get("sleep", 1000L);
104          int numPublish = glob.getProperty().get("numPublish", 2000);
105          String oid = glob.getProperty().get("oid", "Hello");  // "HelloTopic_#${counter}"
106          String domain = glob.getProperty().get("domain", (String)null);
107          String clientTags = glob.getProperty().get("clientTags", "<org.xmlBlaster><demo/></org.xmlBlaster>");
108          //String clientTags = glob.getProperty().get("clientTags", "<org.xmlBlaster><demo-${counter}/></org.xmlBlaster>");
109          String contentStr = glob.getProperty().get("content", "Hi-${counter}-${timestamp}");
110          String contentFile = glob.getProperty().get("contentFile", (String)null);
111          String contentFileLines = glob.getProperty().get("contentFileLines", (String)null); // send line by line from given file
112          PriorityEnum priority = PriorityEnum.toPriorityEnum(glob.getProperty().get("priority", PriorityEnum.NORM_PRIORITY.getInt()));
113          boolean persistent = glob.getProperty().get("persistent", true);
114          long lifeTime = glob.getProperty().get("lifeTime", -1L);
115          boolean forceUpdate = glob.getProperty().get("forceUpdate", true);
116          boolean forceDestroy = glob.getProperty().get("forceDestroy", false);
117          boolean readonly = glob.getProperty().get("readonly", false);
118          long destroyDelay = glob.getProperty().get("destroyDelay", 60000L);
119          boolean createDomEntry = glob.getProperty().get("createDomEntry", true);
120          boolean consumableQueue = glob.getProperty().get("consumableQueue", false);
121          long historyMaxMsg = glob.getProperty().get("queue/history/maxEntries", -1L);
122          boolean forceQueuing = glob.getProperty().get("forceQueuing", true);
123          boolean subscribable = glob.getProperty().get("subscribable", true);
124          String destination = glob.getProperty().get("destination", (String)null);
125          boolean erase = glob.getProperty().get("erase", true);
126          boolean disconnect = glob.getProperty().get("disconnect", true);
127          final boolean eraseTailback = glob.getProperty().get("eraseTailback", false);
128          int contentSize = glob.getProperty().get("contentSize", -1); // 2000000);
129          boolean eraseForceDestroy = glob.getProperty().get("erase.forceDestroy", false);
130          final String updateDumpToFile = glob.getProperty().get("update.dumpToFile", (String)null);
131          boolean connectPersistent = glob.getProperty().get("connect/qos/persistent", false);
132          String contentMime = glob.getProperty().get("contentMime", "text/xml");
133          String contentMimeExtended = glob.getProperty().get("contentMimeExtended", "1.0");
134 
135          Map clientPropertyMap = glob.getProperty().get("clientProperty", (Map)null);
136          Map connectQosClientPropertyMap = glob.getProperty().get("connect/qos/clientProperty", (Map)null);
137 
138          if (historyMaxMsg < 1 && !glob.getProperty().propertyExists("destroyDelay"))
139             destroyDelay = 24L*60L*60L*1000L; // Increase destroyDelay to one day if no history queue is used
140 
141          log.info("Used settings are:");
142          log.info("   -interactive    " + interactive);
143          log.info("   -sleep          " + Timestamp.millisToNice(sleep));
144          log.info("   -oneway         " + oneway);
145          log.info("   -erase          " + erase);
146          log.info("   -disconnect     " + disconnect);
147          log.info("   -eraseTailback  " + eraseTailback);
148          log.info(" Pub/Sub settings");
149          log.info("   -numPublish     " + numPublish);
150          log.info("   -oid            " + oid);
151          log.info("   -contentMime    " + contentMime);
152          log.info("   -contentMimeExtended " + contentMimeExtended);
153          log.info("   -clientTags     " + clientTags);
154          log.info("   -domain         " + ((domain==null)?"":domain));
155          if (contentSize >= 0) {
156             log.info("   -content        [generated]");
157             log.info("   -contentSize    " + contentSize);
158          }
159          //else if (contentFile != null && contentFile.length() > 0) {
160          //   log.info("   -contentFile    " + contentFile);
161          //}
162          else {
163             log.info("   -content        " + contentStr);
164             log.info("   -contentSize    " + contentStr.length());
165             log.info("   -contentFile    " + contentFile);
166             log.info("   -contentFileLines" + contentFileLines);
167          }
168          log.info("   -priority       " + priority.toString());
169          log.info("   -persistent     " + persistent);
170          log.info("   -lifeTime       " + Timestamp.millisToNice(lifeTime));
171          log.info("   -forceUpdate    " + forceUpdate);
172          log.info("   -forceDestroy   " + forceDestroy);
173          if (clientPropertyMap != null) {
174             Iterator it = clientPropertyMap.keySet().iterator();
175             while (it.hasNext()) {
176                String key = (String)it.next();
177                log.info("   -clientProperty["+key+"]   " + clientPropertyMap.get(key).toString());
178             }
179          }
180          else {
181             log.info("   -clientProperty[]   ");
182          }
183          log.info(" Topic settings");
184          log.info("   -readonly       " + readonly);
185          log.info("   -destroyDelay   " + Timestamp.millisToNice(destroyDelay));
186          log.info("   -createDomEntry " + createDomEntry);
187          log.info("   -queue/history/maxEntries " + historyMaxMsg);
188          log.info("   -consumableQueue " + consumableQueue);
189          log.info(" PtP settings");
190          log.info("   -subscribable   " + subscribable);
191          log.info("   -forceQueuing   " + forceQueuing);
192          log.info("   -destination    " + destination);
193          log.info(" Erase settings");
194          log.info("   -erase.forceDestroy " + eraseForceDestroy);
195          log.info("   -erase.domain   " + ((domain==null)?"":domain));
196          log.info(" Update settings");
197          log.info("   -update.dumpToFile " + updateDumpToFile);
198          log.info(" ConnectQos settings");
199          log.info("   -connect/qos/persistent " + connectPersistent);
200          if (connectQosClientPropertyMap != null) {
201             Iterator it = connectQosClientPropertyMap.keySet().iterator();
202             while (it.hasNext()) {
203                String key = (String)it.next();
204                log.info("   -connect/qos/clientProperty["+key+"]   " + connectQosClientPropertyMap.get(key).toString());
205             }
206          }
207          else {
208             log.info("   -connect/qos/clientProperty[]   ");
209          }
210          log.info("For more info please read:");
211          log.info("   http://www.xmlBlaster.org/xmlBlaster/doc/requirements/interface.publish.html");
212 
213          I_XmlBlasterAccess con = glob.getXmlBlasterAccess();
214 
215          // Handle lost server explicitly
216          con.registerConnectionListener(new I_ConnectionStateListener() {
217 
218                public void reachedAlive(ConnectionStateEnum oldState,
219                                         I_XmlBlasterAccess connection) {
220                   /*
221                   ConnectReturnQos conRetQos = connection.getConnectReturnQos();
222                   log.info("I_ConnectionStateListener: We were lucky, connected to " +
223                      connection.getGlobal().getId() + " as " + conRetQos.getSessionName());
224                      */
225                   if (eraseTailback) {
226                      log.info("Destroying " + connection.getQueue().getNumOfEntries() +
227                                   " client side tailback messages");
228                      connection.getQueue().clear();
229                   }
230                }
231                public void reachedPolling(ConnectionStateEnum oldState,
232                                           I_XmlBlasterAccess connection) {
233                   log.warning("I_ConnectionStateListener: No connection to xmlBlaster server, we are polling ...");
234                }
235                public void reachedDead(ConnectionStateEnum oldState,
236                                        I_XmlBlasterAccess connection) {
237                   log.warning("I_ConnectionStateListener: Connection from " +
238                           connection.getGlobal().getId() + " to xmlBlaster is DEAD.");
239                   //System.exit(1);
240                }
241                public void reachedAliveSync(ConnectionStateEnum oldState, I_XmlBlasterAccess connection) {
242                }
243 
244             });
245 
246          // This listener receives only events from asynchronously send messages from queue.
247          // e.g. after a reconnect when client side queued messages are delivered
248          con.registerPostSendListener(new I_PostSendListener() {
249             /**
250              * @see I_PostSendListener#postSend(MsgQueueEntry[])
251              */
252             public void postSend(MsgQueueEntry[] entries) {
253                try {
254                   for (int i=0; i<entries.length; i++) {
255                      if (MethodName.PUBLISH.equals(entries[i].getMethodName())) { 
256                         MsgUnit msg = entries[i].getMsgUnit();
257                         PublishReturnQos retQos = (PublishReturnQos)entries[i].getReturnObj();
258                         log.info("Send asynchronously message '" + msg.getKeyOid() + "' from queue: " + retQos.toXml());
259                      }
260                      else
261                         log.info("Send asynchronously " + entries[i].getMethodName() + " message from queue");
262                   }
263                } catch (Throwable e) {
264                   e.printStackTrace();
265                }
266             }
267 
268             /**
269              * @see I_PostSendListener#sendingFailed(MsgQueueEntry[], XmlBlasterException)
270              */
271             public boolean sendingFailed(MsgQueueEntry[] entries, XmlBlasterException ex) {
272                try {
273                   for (int i=0; i<entries.length; i++) {
274                      if (MethodName.PUBLISH.equals(entries[i].getMethodName())) { 
275                         MsgUnit msg = entries[i].getMsgUnit();
276                         log.info("Send asynchronously message '" + msg.getKeyOid() + "' from queue failed: " + ex.getMessage());
277                      }
278                      else
279                         log.info("Send asynchronously " + entries[i].getMethodName() + " message from queue");
280                   }
281                } catch (Throwable e) {
282                   e.printStackTrace();
283                }
284                //return true; // true: We have handled the case (safely stored the message) and it may be removed from connection queue
285                return false; // false: Default error handling: message remains in queue and we go to dead
286             }
287          });
288 
289          // ConnectQos checks -session.name and -passwd from command line
290          log.info("============= CreatingConnectQos");
291          ConnectQos qos = new ConnectQos(glob);
292          if (connectPersistent) {
293             qos.setPersistent(connectPersistent);
294          }
295          // "__remoteProperties"
296          qos.getData().addClientProperty(Constants.CLIENTPROPERTY_REMOTEPROPERTIES, true);
297          if (connectQosClientPropertyMap != null) {
298             Iterator it = connectQosClientPropertyMap.keySet().iterator();
299             while (it.hasNext()) {
300                String key = (String)it.next();
301                qos.addClientProperty(key, connectQosClientPropertyMap.get(key).toString());
302             }
303          }
304          log.info("ConnectQos is " + qos.toXml());
305          ConnectReturnQos crq = con.connect(qos, new I_Callback() {
306          public String update(String cbSessionId, UpdateKey updateKey, byte[] content, UpdateQos updateQos) throws XmlBlasterException {
307             try {
308                if (updateDumpToFile == null) {
309                   log.info("Received '" + updateKey.getOid() + "':" + new String(content, "UTF-8"));
310                }
311                else {
312                   FileLocator.writeFile(updateDumpToFile, content);
313                   log.info("Received '" + updateKey.getOid() + "' size = " + content.length + " dumped to file " + updateDumpToFile);
314                }
315             } catch (UnsupportedEncodingException e) {
316                log.severe("Update failed: " + e.toString());
317             }
318             return "";
319          }
320          });  // Login to xmlBlaster, register for updates
321          log.info("Connect success as " + crq.toXml());
322 
323          String[] lines = null;
324          if (contentFileLines != null && contentFileLines.length() > 0) {
325              String fileContent = FileLocator.readAsciiFile(contentFileLines);
326           lines = StringPairTokenizer.parseLine(fileContent, '\n');
327           log.info("Sending file " + contentFileLines + " " + lines.length + " lines, line by line");
328           }
329 
330          org.xmlBlaster.util.StopWatch stopWatch = new org.xmlBlaster.util.StopWatch();
331          for(int i=0; true; i++) {
332             if (numPublish != -1)
333                if (i>=numPublish)
334                   break;
335 
336             String currCounter = ""+(i+1);
337             if (numPublish > 0) { // Add leading zeros to have nice justified numbers in dump
338                String tmp = ""+numPublish;
339                int curLen = currCounter.length();
340                currCounter = "";
341                for (int j=curLen; j<tmp.length(); j++) {
342                   currCounter += "0";
343                }
344                currCounter += (i+1);
345             }
346 
347             String ts = IsoDateParser.getCurrentUTCTimestampT();
348             String currOid = replacePlaceHolders(oid, currCounter, ts);
349 
350             if (interactive) {
351                char ret = (char)Global.waitOnKeyboardHit("Hit 'b' to break, hit other key to publish '" + currOid + "' #" + currCounter + "/" + numPublish);
352                if (ret == 'b')
353                   break;
354             }
355             else {
356                if (sleep > 0 && i > 0) {
357                   try { Thread.sleep(sleep); } catch( InterruptedException e) {}
358                }
359                log.info("Publish '" + currOid + "' #" + currCounter + "/" + numPublish);
360             }
361 
362             PublishKey pk = new PublishKey(glob, currOid, contentMime, contentMimeExtended);
363             if (domain != null) pk.setDomain(domain);
364             pk.setClientTags(replacePlaceHolders(clientTags, currCounter, ts));
365             PublishQos pq = new PublishQos(glob);
366             pq.setPriority(priority);
367             pq.setPersistent(persistent);
368             pq.setLifeTime(lifeTime);
369             pq.setForceUpdate(forceUpdate);
370             pq.setForceDestroy(forceDestroy);
371             pq.setSubscribable(subscribable);
372             if (clientPropertyMap != null) {
373                Iterator it = clientPropertyMap.keySet().iterator();
374                while (it.hasNext()) {
375                   String key = (String)it.next();
376                   pq.addClientProperty(key, clientPropertyMap.get(key).toString());
377                }
378                //Example for a typed property:
379                //pq.getData().addClientProperty("ALONG", (new Long(12)));
380             }
381 
382             if (i == 0) {
383                TopicProperty topicProperty = new TopicProperty(glob);
384                topicProperty.setDestroyDelay(destroyDelay);
385                topicProperty.setCreateDomEntry(createDomEntry);
386                topicProperty.setReadonly(readonly);
387                if (historyMaxMsg >= 0L) {
388                   HistoryQueueProperty prop = new HistoryQueueProperty(this.glob, null);
389                   prop.setMaxEntries(historyMaxMsg);
390                   topicProperty.setHistoryQueueProperty(prop);
391                }
392                if (consumableQueue)
393                   topicProperty.setMsgDistributor("ConsumableQueue,1.0");
394                pq.setTopicProperty(topicProperty);
395                log.info("Added TopicProperty on first publish: " + topicProperty.toXml());
396             }
397 
398             if (destination != null) {
399                log.fine("Using destination: '" + destination + "'");
400                Destination dest = new Destination(glob, new SessionName(glob, destination));
401                dest.forceQueuing(forceQueuing);
402                pq.addDestination(dest);
403             }
404 
405             byte[] content;
406             if (contentSize >= 0) {
407                content = new byte[contentSize];
408                Random random = new Random();
409                for (int j=0; j<content.length; j++) {
410                   content[j] = (byte)(random.nextInt(96)+32);
411                   //content[j] = (byte)('X');
412                   //content[j] = (byte)(j % 255);
413                }
414             }
415             else if (contentFile != null && contentFile.length() > 0) {
416                content = FileLocator.readFile(contentFile);
417             }
418             else if (lines != null) {
419                if (i < lines.length) {
420                   String line = replacePlaceHolders(lines[i], currCounter, ts);
421                   log.info("Sending line #" + (i+1) + ": " + line);
422                   content = replacePlaceHolders(lines[i], currCounter, ts).getBytes();
423                }
424                else {
425                   log.info("File " + contentFileLines + " is read and send completely");
426                   break;
427                }
428             }
429             else {
430                content = replacePlaceHolders(contentStr, currCounter, ts).getBytes();
431             }
432 
433             if (log.isLoggable(Level.FINEST)) log.finest("Going to parse publish message: " + pk.toXml() + " : " + content + " : " + pq.toXml());
434             MsgUnit msgUnit = new MsgUnit(pk, content, pq);
435             if (log.isLoggable(Level.FINEST)) log.finest("Going to publish message: " + msgUnit.toXml());
436 
437             if (oneway) {
438                MsgUnit msgUnitArr[] = { msgUnit };
439                con.publishOneway(msgUnitArr);
440                log.info("#" + (i+1) + "/" + numPublish +
441                          ": Published oneway message '" + msgUnit.getKeyOid() + "'");
442             }
443             else {
444                PublishReturnQos prq = con.publish(msgUnit);
445                if (log.isLoggable(Level.FINEST)) log.finest("Returned: " + prq.toXml());
446 
447                log.info("#" + currCounter + "/" + numPublish +
448                          ": Got status='" + prq.getState() +
449                          (prq.getData().hasStateInfo()?"' '" + prq.getStateInfo():"") +
450                          "' rcvTimestamp=" + prq.getRcvTimestamp() +
451                          " for published message '" + prq.getKeyOid() + "'");
452             }
453          }
454          log.info("Elapsed since starting to publish: " + stopWatch.nice(numPublish));
455 
456          if (erase) {
457             char ret = 0;
458             if (interactive) {
459                ret = (char)Global.waitOnKeyboardHit("Hit 'e' to erase topic '"+oid+"', or any other key to keep the topic");
460             }
461 
462             if (ret == 0 || ret == 'e') {
463                EraseKey ek = new EraseKey(glob, oid);
464                if (domain != null) ek.setDomain(domain);
465                EraseQos eq = new EraseQos(glob);
466                eq.setForceDestroy(eraseForceDestroy);
467                if (log.isLoggable(Level.FINEST)) log.finest("Going to erase the topic: " + ek.toXml() + eq.toXml());
468                /*EraseReturnQos[] eraseArr =*/con.erase(ek, eq);
469                log.info("Erase success");
470             }
471          }
472 
473          char ret = 0;
474          if (interactive) {
475             boolean hasQueued = con.getQueue().getNumOfEntries() > 0;
476             while (ret != 'l' && ret != 'd')
477                ret = (char)Global.waitOnKeyboardHit("Hit 'l' to leave server, 'd' to disconnect" + (hasQueued ? "(and destroy client side entries)" : ""));
478          }
479 
480 
481          if (ret == 0 || ret == 'd') {
482             DisconnectQos dq = new DisconnectQos(glob);
483             dq.clearClientQueue(true);
484             con.disconnect(dq);
485             log.info("Disconnected from server, all resources released");
486          }
487          else {
488             con.leaveServer(null);
489             ret = 0;
490             if (interactive) {
491                while (ret != 'q')
492                   ret = (char)Global.waitOnKeyboardHit("Hit 'q' to quit");
493             }
494             log.info("Left server, our server side session remains, bye");
495          }
496       }
497       catch (XmlBlasterException e) {
498          log.severe(e.getMessage());
499       }
500       catch (Exception e) {
501          e.printStackTrace();
502          log.severe(e.toString());
503       }
504    }
505 
506    public String replacePlaceHolders(String value, String currCounter, String timestamp) {
507       if (value == null || !this.replacePlaceHolders)
508          return value;
509       if (value.indexOf("%") != -1) {
510          value = org.xmlBlaster.util.ReplaceVariable.replaceAll(value, "%counter", currCounter); // deprecated
511          value = org.xmlBlaster.util.ReplaceVariable.replaceAll(value, "%date", timestamp.substring(0, 10));
512          value = org.xmlBlaster.util.ReplaceVariable.replaceAll(value, "%timestamp", timestamp);
513       }
514       
515       if (value.indexOf("${") != -1) {
516          value = org.xmlBlaster.util.ReplaceVariable.replaceAll(value, "${timestamp}", timestamp);
517          value = org.xmlBlaster.util.ReplaceVariable.replaceAll(value, "${date}", timestamp.substring(0, 10));
518           value = org.xmlBlaster.util.ReplaceVariable.replaceAll(value, "${counter}", currCounter);
519       }
520        return value;
521    }
522 
523    /**
524     * Try
525     * <pre>
526     *   java javaclients.HelloWorldPublish -help
527     * </pre>
528     * for usage help
529     */
530    public static void main(String args[]) {
531       Global glob = new Global();
532 
533       if (glob.init(args) != 0) { // Get help with -help
534          System.out.println(glob.usage());
535          System.err.println("\nExample:");
536          System.err.println("  java javaclients.HelloWorldPublish -interactive false -sleep 1000 -numPublish 10 -oid Hello -persistent true -erase true\n");
537          System.err.println("  java javaclients.HelloWorldPublish  -clientProperty[myString] Hello -clientProperty[correlationId] 100\n");
538          System.exit(1);
539       }
540 
541       new HelloWorldPublish(glob);
542    }
543 }


syntax highlighted by Code2HTML, v. 0.9.1