From a2f2f71fffb5103f2dcc01457f6fb31ace8fb579 Mon Sep 17 00:00:00 2001 From: jestin Date: Thu, 20 Jul 2006 12:27:07 +0000 Subject: major rewrite of the debian packaging to use dhelper bug fix in jafter adding jdaemon shell script --- doc/ivy-java.sgml | 294 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 231 insertions(+), 63 deletions(-) (limited to 'doc') diff --git a/doc/ivy-java.sgml b/doc/ivy-java.sgml index 4470c6e..92fe115 100644 --- a/doc/ivy-java.sgml +++ b/doc/ivy-java.sgml @@ -1,12 +1,12 @@ @@ -17,11 +17,6 @@ - -2005 -DGAC/DSNA/DTI - - The Ivy Java library guide CENA NT02-819 NT02-819 © CENA @@ -29,13 +24,13 @@ YannickJestin -
jestin@cena.fr
+
yannick.jestin@enac.fr
-November 22, 2005 +July 20, 2006 -2005 +2006 DGAC/DSNA/DTI @@ -43,7 +38,7 @@ This document is a programmer's guide that describes how to use the Ivy Java library to connect applications to an Ivy bus. This guide describes -version 1.2.8 of the library. This document itself is part of the Java +version 1.2.10 of the library. This document itself is part of the Java package, available on the Ivy web site. @@ -65,7 +60,7 @@ incomplete, is quite ugly. We'll try and improve it. What is Ivy? -Ivy is a software bus designed at CENA. A software bus is a system that allows software applications to exchange information with the illusion of broadcasting that information, selection being performed by the receiving @@ -98,16 +93,18 @@ available from the Ivy Web sit The Ivy Java library (aka libivy-java or fr.dgac.ivy) is a Java package that allows you to connect applications to an Ivy bus. You can use it to write -applications in Java. You can also use it to integrate any thread-safe Java -application on an Ivy bus. So far, this library has been tested and used on a variety of -Java virtual machines (from 1.1.7 to 1.4.2), and on a variety of architectures -(GNU/Linux, Solaris, Windows NT,XP,2000, MacOSX). +applications in Java. You can also use it to connect any thread-safe Java +application to an Ivy bus. So far, this library has been tested and used on a variety of +Java virtual machines (from 1.1.7 to 1.5.0), a variety of vendors (kaffe+gcj, +sun jdk, blackdown) and on a variety of architectures (GNU/Linux, Solaris, +Windows NT,XP,2000, MacOSX). It is developped and maintain on a Debian +GNU/Linux unstable distribution. -The Ivy Java library was originally developed by François-Régis Colin and is -now maintained by Yannick Jestin at CENA within a group at CENA (Toulouse, -France). +The Ivy Java library was originally developed by François-Régis Colin and +Yannick Jestin within a group at CENA (Toulouse, France). It is now maintained +by Yannick. @@ -130,12 +127,7 @@ mistakes is to put it in the command line each time you want to use ivy -The package contains the documentation, the sources and the class files for the fr.dgac.ivy package, -alongside with examples and a couple of useful tools, IvyDaemon and Probe. You -will need the Apache Jakarta -project regexp library -and the gnu getopt library. -Those could be included in the jar file, but not in the debian package. +The package contains the documentation, the sources and the class files for the fr.dgac.ivy package, alongside with examples and a small set of tools ( IvyDaemon, jrobe, jafter). You will need the Apache Jakarta project regexp library and the gnu getopt library. Those could be included in the jar file, but not in the debian package. @@ -146,10 +138,12 @@ $ java fr.dgac.ivy.tools.Probe If should display a line about broadcasting on a strange address, this is OK and means it is ready and working. If it complains about a missing class ( java.lang.NoClassDefFoundError ), then you have not pointed your virtual -machine to the jar file or your installation is incomplete. - -Alternatively, you can use the jprobe shell script. +machine to the jar file or your installation is incomplete. Alternatively, you can use the jprobe shell script. + +$ jprobe + + @@ -207,10 +201,9 @@ class ivyTranslater implements IvyMessageListener { Compiling it You should be able to compile the application with the -following command (if the ivy-java jar is in your development classpath): +following command (the classpath may vary): -$ javac ivyTranslater.java -$ +$ javac -cp /usr/share/java/ivy.jar ivyTranslater.java @@ -219,7 +212,7 @@ $ We are going to test our application with fr.dgac.ivy.tools.Probe. In a shell, launch ivyTranslater: -$ java ivyTranslater +$ java cp .:/usr/share/java/regexp.jar:/usr/share/java/ivy.jar ivyTranslater In another shell, launch java fr.dgac.ivy.tools.Probe '(.*)'. You can see that the IvyTranslater has joined the bus, published its @@ -257,28 +250,29 @@ $ Basic functions -The javadoc generated files are available on line on the ivy web site, and -should be included in your ivy java package (or in -/usr/share/doc/libivy-java, alongside with this very manual). Here are more details -on those functions. +The javadoc generated files are available on line on the ivy web site, and should be included in your ivy java package (or in /usr/share/doc/libivy-java, alongside with this very manual). Here are more details on those functions. -Initialisation an Ivy object and joining the bus +Initialization an Ivy object and joining the bus -Initialising a Java Ivy agent is a two step process. First of all, you must +Initializing a Java Ivy agent is a two step process. First of all, you must create an fr.dgac.ivy.Ivy object. It will be the repository of your agent name, network state, subscriptions, etc. Once this object is created, you can subscribe to the various Ivy events: text messages through Perl compatible regular expressions, other agents' arrival, departure, subscription or unsubscription to regexps, direct messages or die command -issued by other agents. At this point, your ivy application is still not connected. In +issued by other agents. + + + +At this point, your application is still not connected. In order to join the bus, call the start(string domain) method on your Ivy object. This will spawn two threads that will remain active until you call the stop() method on your Ivy object or until some other agent sends you a die message. Once this start() method has been called, -the network machinery is set up according to the ivy protocol, and your agent is ready to -handle messages on the bus ! +the network machinery is set up according to the ivy protocol, and your agent +is eventually ready to handle messages on the bus. fr.dgac.ivy.Ivy(String name,String message, IvyApplicationListener appcb) @@ -368,8 +362,9 @@ Use the bindMsg() method to bind a callback to a pattern, a public int bindMsg(String regexp, IvyMessageListener callback); public void unBindMsg(int id); -The regexp follows the PCRE syntax (see man -pcrepattern(3)), grouping is done with brackets. The callback +The regexp follows the PCRE syntax (see the pcre web site or the pcrepattern(3) man +page), grouping is done with brackets. The callback is an object implementing the IvyMessageListener interface, with the receive method. The thread listening on the connexion with the sending agent will execute the callback. @@ -379,7 +374,7 @@ There are two ways of defining the callback: the first one is to make an object an implementation of the IvyMessageListener interface, and to implement the public void receive(Ivyclient ic, String[] args) method. But this is limited to one method per class, so the second method used -is the one of inner classes, introduced since Java 1.1 and widely used in +is the one of anonymous inner classes, introduced since Java 1.1 and widely used in swing programs, for instance: bindMsg("^a*(.*)c*$", new IvyMessageListener() { @@ -397,7 +392,18 @@ see in the advanced functions. Subscribing to application events -TODO +Either at the creation time of your Ivy object or later +on with Ivy.addApplicationListener(), you can add add +some behaviour to perform callbacks upon different events: + +when an agent joins the bus +when an agent leaves the bus +when an agent sends you a direct message +when an agent forces you to leave the bus + +This can be handy if you design an agent requiring somme coordination with +other dedicated agents to run properly. To do so, the easiest way is to use +the ready messages. You can find later a description of the Ivy.waitForClient() method to implement a correct synchronization. @@ -409,7 +415,7 @@ TODO By default, an application doesn't send the messages to itself. Usually, there are more efficient and convenient ways to communicate withing a program. -However, if you want to take benefit of the ease of ivy or to be as +However, if you want to take benefit of the ease of Ivy or to be as transparent as possible, you can set the Ivy object so that the pattern matching and message sending will be done for the sender too. @@ -431,9 +437,10 @@ provides the programmer with two useful function: public static String getDomain(String arg); public static String getDomainArgs(String progname,String[] args); -The getDomain() function, if arg is non null, will return arg, otherwise it +The Ivy.getDomain() function, if arg is non null, will return arg, otherwise it will return the IVYBUS property, otherwise the DEFAULT_DOMAIN. A very simple -way to start an Ivy agent is with ivy.start(getDomain(null)). The +way to start an Ivy agent is with +Ivy.start(getDomain(null)). The getDomainArgs(name,args) will add very simple processing of the args given to the main() function, and give higher priority to the command line argument. @@ -466,6 +473,15 @@ won't be much documented, in order to make it harder to use. +Ivy and swing GUI + +Swing requires the code to run in the main swing thread. In order to avoid +problems, be sure tu use the SwingUtilities.invokeLater() or +SwingUtilities.invokeAndWait() methods if you Ivy callbacks impact swing +components. + + + Asynchronous Subscription to messages For each and every remote agent on the bus, a thread is in charge of handling the encoding @@ -542,15 +558,57 @@ chance to match the message you're sending, use the +Message classes + +When your Ivy bus is populated with many agents, the cost of pattern matching +becomes painful. For instance, a bus with 20+ agents, with 2000+ +subscriptions, with hundreds of messages per second might cause a high CPU +load, thus leading to slow responsiveness in GUI animations. To limit this +phenomenon, use bounded regexp as much as possible like ^NAME +VALUE=(.*) ( see the programmer's style guide later on ). However, +2000+ subscription are still 2000+ tests of bounded regexp, even if is less +costful. It is possible not to do the tests provided some requirements are +met: + +your agent knows exhaustively and exactly the prefixes of all +the messages it will send +your use the Ivy.setFilter() before +starting the bus, with the list of prefixes ( e.g.: { "TOTO1" "PREFIX", "ETC" +} ) + + + + +If you use the message classes, your Ivy agent will ignore the bounded subscriptions +of other agents that will never match any of your prefixes ( e.g: ^COUCOU +neither matches TOTO1, PREFIX, nor ETC ). The check is made this way: + +if the regexp is bounded, the filter extracts the first word +according to this regexp: ^\\^([a-zA-Z0-9_-]+).* +the word is compared character to character to all the +prefixes in the message class; if it is not present, the subscription is +discarded + + + + +When your agent sends a message, many pattern matching won't be made, and it +might save some time. Be sure to activate the setFilter() +when you are sure that you know perfectly the message classes. You can play +with the message classes with jprobe and see the problems that can arise. + + + Utilities -Probe +jprobe -Probe is your swiss army knife as an Ivy Java developer. Use it +jprobe is your swiss army knife as an Ivy Java developer. Use it to try your regular expressions, to check the installation of the system, to -log the messages, etc. To use it, either run fr.dgac.ivy.tools.Probe, or run the jar -file directly with $ java -jar ivy.jar +log the messages, etc. To use it, either run java +fr.dgac.ivy.tools.Probe, run the jar file directly with $ +java -jar ivy.jar, or use the jprobe shell script. @@ -585,13 +643,16 @@ VY_DEBUG property ( java -DIVY_DEBUG fr.dgac.ivy.tools.Probe is the same as java fr.dgac.ivy.tools.Probe -d ) --c MESSAGECLASS uses a message filter (see Ivy.setFilter()), for example +-c MESSAGECLASS uses a message filter (see Ivy.setFilter()), for example 'Word1,Word2,Word3' -h dumps the command line options help. + + + The run time commands are preceded by a single dot (.) at the beginning of the line. Issue ".help" at the prompt ( without the double quotes ) to have the list of available commands. If the lines does not begin with a dot, jprobe tries @@ -642,24 +703,131 @@ The "hello world" message will be sent on the default Ivy Bus to anyone having subscribe to a matching pattern -After +jafter -TODO +jafter ( or fr.dgac.ivy.tools.JAfter ) is a simple utility that can be used +within shell script. The rationale is to block the processing until a specific +message is received, then continue. This can be used to wait for a ready +message before lauching another agent. The jafter program can wait forever or +timeout. It the timeout is triggered, a negative value is returned to the +shell. programmer's style guide -TODO +There are many specific programming patterns in Ivy. Some of them are Ivy +related, some are java related. See the jprobe source code to get an example +of some programming patterns. Here are some of them, to be completed later... + +join the right bus + +To join the right bus, you have to honor the IVYBUS property. It is a good way +to let the system get it, and an ever better way to override it with command +line options (e.g.: -b :3110). Here is a snippet to perform this task: + +import fr.dgac.ivy.* ; +import gnu.getopt.Getopt; + +public static void main(String[] args) throws IvyException { + Getopt opt = new Getopt("After",args,"b:"); // add more options ... + String domain=Ivy.getDomain(null); // gets IVYDOMAIN from property + // or, if none is set, defaults to Ivy.DEFAULT_DOMAIN + while ((c = opt.getopt()) != -1) switch (c) { + case 'b': domain=opt.getOptarg(); break; // overrides + // and more options + default: System.out.println(helpmsg); System.exit(0); + } + Ivy bus=new Ivy(name,name+" ready",null); + bus.start(domain); // sets the properties for children processes ... +} + + + + + +nice regular expressions + +To avoid CPU consuming pattern matching operation, be sure to use bounded +regexps as much as possible. For instance, if we consider the regexp1 "^coord +x=(\d+)", the regexp2 "x=(\d+)" and the message msg "coord x=12 y=15". When +another agent sends the message msg, both regexp will match and trigger the +callback with on argument, the string "12". However, when another message is +sent, the regexp1 will fail as soon as possible, probably the very first +character, but the regexp2 will do some processing before failing. + + + +Something's not working + +To trace the behaviour of an heavily multithread application is quite tedious, +especially when it's connected to others. The easiest path is to use the +built-in basic tracing mechanism provided by Ivy : run your jvm with the +-DIVY_DEBUG property set. Use jprobe to monitor what's going on with the +greedy regexp '(.*)' in a separate terminal. If in doubt, just join the Ivy mailing +list. + + + +time consuming callbacks + +For each remote agent, the Ivy object has an IvyClient with a dedicated +working thread. This thread deals with the Ivy protocol coding and decoding, +and performs the callbacks. If your agent has time consuming callbacks, +involving CPU, or long IO, or so, then it might be better to run each callback +in a dedicated thread. You can write this yourself, or just use the +Ivy.bindAsyncMsg() function. The problem is that there is +a slight overhead in thread management. + + + +how to perform requests + +When agent A needs to make a request to another agent B, you +can use the following pattern: + +B has subscribed to ^MyRequest ID=([^ ]+) QUERY=(.*) +A subscribes to ^MyResult ID=someSpecificId RESULT=(.*) +A send to MyRequest ID=someSpecificId QUERY=2+2 +B receives, computes the results, then sends MyResult ID=someSpecificId RESULT=4 +A receives, and unsubscribes to his subscription + + + +To program this, you have to get a gentle way of choosing the +specificId, associate this to the subscription number returned by +Ivy.bindMsg(), and add code within the callback to perform the unsubscription. +Moreover, you have to be sure that there are not two "B type" agents on the +bus, otherwise you'll eventually perform your callback twice if the results +are sent during the short lapse of time before unsubscription. + + +The preferred way is to to let the API provide this singleton mechanism +with Ivy.getWBUID() function returning an unique ID, and +the Ivy.bindMsgOnce() that handles all the mechanisms +ensuring that the callback will be run on time only, and that the +unsubscription will take place. + + String id = bus.getWBUID(); // a more or less unique ID + bus.bindMsgOnce("MyResult ID="+id+" RESULT=(.*)",{ + public void receive(IvyClient ic,String[] args) { + System.out.println("2+2="+args[0]); + // the unsubscription is done for me + } + }); + bus.sendMsg("MyRequest ID="+id+" QUER=2+2"); + + + + + -Contacting the author +Contacting the authors -The Ivy Java library is now maintained by Yannick Jestin. For bug reports or -comments on the library itself or about this document, please send him an -email at jestin@cena.fr. For comments and ideas about Ivy itself -(protocol, applications, etc), please join and use the Ivy mailing list -ivy@cena.fr. +For bug reports or comments on the library itself or about this document, +please me an email at yannick.jestin@enac.fr. For comments and ideas about Ivy itself (protocol, applications, etc), please join and use the +Ivy mailing list -- cgit v1.1