KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > fr > dyade > aaa > agent > AgentServer


1 /*
2  * Copyright (C) 2001 - 2006 ScalAgent Distributed Technologies
3  * Copyright (C) 2004 - France Telecom R&D
4  * Copyright (C) 1996 - 2000 BULL
5  * Copyright (C) 1996 - 2000 INRIA
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20  * USA.
21  *
22  * Initial developer(s): Dyade
23  * Contributor(s): ScalAgent Distributed Technologies
24  */

25 package fr.dyade.aaa.agent;
26
27 import java.io.*;
28 import java.util.*;
29
30 import org.objectweb.util.monolog.api.BasicLevel;
31 import org.objectweb.util.monolog.api.Logger;
32 import org.objectweb.util.monolog.api.LoggerFactory;
33
34 import fr.dyade.aaa.util.*;
35 import fr.dyade.aaa.agent.conf.*;
36 import fr.dyade.aaa.util.management.MXWrapper;
37
38 /**
39  * The <code>AgentServer</code> class manages the global configuration
40  * of an agent server. It reads the configuration file, then it creates
41  * and configure {@link Engine <code>Engine</code>},
42  * {@link Channel <code>Channel</code>},
43  * {@link Network <code>Network</code>s}.
44  * This class contains the main method for AgentServer, for example to
45  * acivate a server you have to run this class with two parameters: the
46  * server id. and the path of the root of persistancy. You can also use
47  * a specialized main calling methods initi and start.
48  * <p><hr>
49  * To start the agents server an XML configuration file describing the
50  * architecture of the agent platform is needed. By default, this file is
51  * the a3servers.xml file and it should be located inside the running
52  * directory where the server is launched. Each server must use the same
53  * configuration file.<p>
54  * The configuration file contains a <code>config</code> element, that
55  * is essentially made up of <code>domain</code>s elements, and servers
56  * (<code>server</code>s elements):
57  * <ul>
58  * <li>Each domain of the configuration is described by an XML element with
59  * attributes giving the name and the classname for <code>Network</code>
60  * implementation (class {@link SimpleNetwork <code>SimpleNetwork</code>}
61  * by default).
62  * <li>Each server is described by an XML element with attributes giving
63  * the id, the name (optional) and the node (the <code>hostname</code>
64  * attribute describes the name or the IP address of this node)
65  * <ul>
66  * <li>Each persistent server must be part of a domain (at least one), to
67  * do this you need to define a <code>network</code> element with attributes
68  * giving the domain's name (<code>domain</code> attribute) and the
69  * communication port (<code>port</code> attribute).
70  * <li>A service can be declared on any of these servers by inserting a
71  * <code>service</code> element describing it.
72  * </ul>
73  * <li>Additonnaly, you can define property for the global configuration
74  * or for a particular server, it depends where you define it: in the
75  * <code>config</code> element or in a server one.
76  * </ul>
77  * Each server that is part of two domains is named a "router", be careful,
78  * it should have only one route between two domains. If it is not true the
79  * configuration failed.
80  * <p><hr>
81  * A simple example of a3servers.xml follows:
82  * <p><blockquote><pre>
83  * &lt;?xml version="1.0"?&gt;
84  * &lt;!DOCTYPE config SYSTEM "a3config.dtd"&gt;
85  *
86  * &lt;config&gt;
87  * &lt;domain name="D1"/&gt;
88  * &lt;domain name="D2" class="fr.dyade.aaa.agent.PoolCnxNetwork"/&gt;
89  *
90  * &lt;property name="D2.nbMaxCnx" value="1"\&gt;
91  *
92  * &lt;server id="0" name="S0" hostname="acores"&gt;
93  * &lt;network domain="D1" port="16300"/&gt;
94  * &lt;service class=\"fr.dyade.aaa.ns.NameService\" args=\"\"/&gt;
95  * &lt;property name="A3DEBUG_PROXY" value="true"\&gt;
96  * &lt;/server&gt;
97  *
98  * &lt;server id="2" name="S2" hostname="bermudes"&gt;
99  * &lt;network domain="D1" port="16310"/&gt;
100  * &lt;network domain="D2" port="16312"/&gt;
101  * &lt;/server&gt;
102  *
103  * &lt;server id="3" name="S3" hostname="baleares"&gt;
104  * &lt;network domain="D2" port="16320"/&gt;
105  * &lt;/server&gt;
106  * &lt;/config&gt;
107  * </pre></blockquote>
108  * <p>
109  * This file described a 2 domains configuration D1 and D2, D1 with default
110  * network protocol and D2 with the <code>PoolCnxNetwork</code> one, and 4
111  * servers:
112  * <ul>
113  * <li>The first server (id 0 and name "S0") is hosted by acores, it is
114  * in domain D1, and listen on port 16300. It defines a service and a
115  * property.
116  * <li>The second server (id 2) is hosted by bermudes and it is the router
117  * between D1 and D2.
118  * <li>The last server is a persistent one, it is hosted on baleares and it
119  * runs in domain D2.
120  * </ul>
121  * At the beginning of the file, there is a global property that defines
122  * the maximum number of connection handled by each server of domain D2.
123  * <hr>
124  * @see Engine
125  * @see Channel
126  * @see Network
127  * @see MessageQueue
128  * @see fr.dyade.aaa.util.Transaction
129  */

130 public final class AgentServer {
131   public final static short NULL_ID = -1;
132
133   public final static String JavaDoc ADMIN_DOMAIN = "D0";
134   public final static String JavaDoc ADMIN_SERVER = "s0";
135
136   private static short serverId = NULL_ID;
137
138   private static Logger logmon = null;
139
140   public final static String JavaDoc CFG_DIR_PROPERTY = "fr.dyade.aaa.agent.A3CONF_DIR";
141   public final static String JavaDoc DEFAULT_CFG_DIR = null;
142   
143   public final static String JavaDoc CFG_FILE_PROPERTY = "fr.dyade.aaa.agent.A3CONF_FILE";
144   public final static String JavaDoc DEFAULT_CFG_FILE = "a3servers.xml";
145   public final static String JavaDoc DEFAULT_SER_CFG_FILE = "a3cmlconfig";
146   
147   public final static String JavaDoc CFG_NAME_PROPERTY = "fr.dyade.aaa.agent.A3CONF_NAME";
148   public final static String JavaDoc DEFAULT_CFG_NAME = "default";
149   
150   public final static String JavaDoc A3CMLWRP_PROPERTY = "fr.dyade.aaa.agent.A3CMLWrapper";
151   public final static String JavaDoc DEFAULT_A3CMLWRP = "fr.dyade.aaa.agent.conf.A3CMLSaxWrapper";
152
153   static ThreadGroup JavaDoc tgroup = null;
154
155   public static ThreadGroup JavaDoc getThreadGroup() {
156     return tgroup;
157   }
158
159  /**
160    * Static reference to the engine. Used in <code>Channel.sendTo</code> to
161    * know if the method is called from a react or no.
162    * <p><hr>
163    * AF: I think we must supress this dependency in order to be able to run
164    * multiples engine.
165    */

166   static Engine engine = null;
167
168   /**
169    * Returns the agent server engine.
170    */

171   public static Engine getEngine() {
172     return engine;
173   }
174
175   /** Static reference to the transactional monitor. */
176   private static Transaction transaction = null;
177
178   /**
179    * Returns the agent server transaction context.
180    */

181   public static Transaction getTransaction() {
182     return transaction;
183   }
184
185   private static JGroups jgroups = null;
186   private static short clusterId = NULL_ID;
187
188   private static ConfigController configController;
189
190   public static ConfigController getConfigController() {
191     return configController;
192   }
193
194   /**
195    * Static references to all messages consumers initialized in this
196    * agent server (including <code>Engine</code>).
197    */

198   private static Hashtable consumers = null;
199
200   static void addConsumer(String JavaDoc domain,
201                           MessageConsumer cons) throws Exception JavaDoc {
202     if (consumers.containsKey(domain))
203       throw new Exception JavaDoc("Consumer for domain " + domain + " already exist");
204
205     consumers.put(domain, cons);
206
207     try {
208       MXWrapper.registerMBean(cons,
209                               "AgentServer",
210                               "server=" + getName() + ",cons=" + cons.getName());
211     } catch (Exception JavaDoc exc) {
212       logmon.log(BasicLevel.ERROR, getName() + " jmx failed", exc);
213     }
214   }
215
216   static Enumeration getConsumers() {
217     if (consumers == null)
218       return null;
219     else
220       return consumers.elements();
221   }
222
223   static MessageConsumer getConsumer(String JavaDoc domain) throws Exception JavaDoc {
224     if (! consumers.containsKey(domain))
225       throw new Exception JavaDoc("Unknown consumer for domain " + domain);
226     return (MessageConsumer) consumers.get(domain);
227   }
228
229   static void removeConsumer(String JavaDoc domain) {
230     MessageConsumer cons = (MessageConsumer) consumers.remove(domain);
231     if (cons != null) cons.stop();
232
233     try {
234       MXWrapper.unregisterMBean("AgentServer",
235                                 "server=" + getName() + ",cons=" + cons.getName());
236     } catch (Exception JavaDoc exc) {
237       logmon.log(BasicLevel.ERROR, getName() + " jmx failed", exc);
238     }
239   }
240
241   /** Static reference to the configuration. */
242   private static A3CMLConfig a3config = null;
243
244   /**
245    * Set the agent server configuration. Be careful, this method cannot
246    * be called after initialization.
247    *
248    * @param a3config A3CMLConfig
249    * @exception Exception Server is already initialized.
250    */

251   public final static void setConfig(A3CMLConfig a3config) throws Exception JavaDoc {
252     setConfig(a3config, false);
253   }
254
255   final static void setConfig(A3CMLConfig a3config,
256                               boolean force) throws Exception JavaDoc {
257     if (! force) {
258       synchronized(status) {
259         if (status.value != Status.INSTALLED)
260           throw new Exception JavaDoc("cannot set config, bad status: " + status.value);
261       }
262     }
263     AgentServer.a3config = a3config;
264   }
265   
266   /**
267    * Returns the agent server configuration.
268    *
269    * @return agent server configuration (A3CMLConfig)
270    */

271   public final static A3CMLConfig getConfig() throws Exception JavaDoc {
272     if (a3config == null) throw new Exception JavaDoc("Server not configured");
273     return a3config;
274   }
275
276   /**
277    * Gets configuration of agent servers for a domain from the current
278    * A3CMLConfig object. This method fills the object graph configuration
279    * in a <code>A3CMLConfig</code> object.
280    *
281    * @param domains list of domain's names
282    * @return a <code>A3CMLConfig</code> object.
283    */

284   public static A3CMLConfig getAppConfig(String JavaDoc[] domains) throws Exception JavaDoc {
285     return getConfig().getDomainConfig(domains);
286   }
287
288   public final static short getServerId() {
289     return serverId;
290   }
291
292   public final static short getClusterId() {
293     return clusterId;
294   }
295
296   private static String JavaDoc name = null;
297
298   public final static String JavaDoc getName() {
299     return name;
300   }
301
302   /**
303    * Returns the identifier of the agent server which name is specified.
304    *
305    * @param name the name of the agent server
306    * @return the identifier of the agent server
307    * @exception Exception if the server name is unknown.
308    */

309   public static short getServerIdByName(String JavaDoc name) throws Exception JavaDoc {
310     return getConfig().getServerIdByName(name);
311   }
312   
313   /**
314    * Searches for the property with the specified key in the server property
315    * list.
316    *
317    * @param key the hashtable key.
318    * @return the value with the specified key value.
319    */

320   public static String JavaDoc getProperty(String JavaDoc key) {
321     return System.getProperty(key);
322   }
323
324   /**
325    * Searches for the property with the specified key in the server property
326    * list.
327    *
328    * @param key the hashtable key.
329    * @param value a default value.
330    * @return the value with the specified key value.
331    */

332   public static String JavaDoc getProperty(String JavaDoc key, String JavaDoc value) {
333     return System.getProperty(key, value);
334   }
335
336   /**
337    * Determines the integer value of the server property with the
338    * specified name.
339    *
340    * @param key property name.
341    * @return the Integer value of the property.
342    */

343   public static Integer JavaDoc getInteger(String JavaDoc key) {
344     try {
345       return Integer.getInteger(key);
346     } catch (Exception JavaDoc exc) {
347       return null;
348     }
349   }
350
351   /**
352    * Determines the integer value of the server property with the
353    * specified name.
354    *
355    * @param key property name.
356    * @param value a default value.
357    * @return the Integer value of the property.
358    */

359   public static Integer JavaDoc getInteger(String JavaDoc key, int value) {
360     try {
361       return Integer.getInteger(key, value);
362     } catch (Exception JavaDoc exc) {
363       return null;
364     }
365   }
366
367   /** Static description of all known agent servers in ascending order. */
368   private static ServersHT servers = null;
369
370   static void addServerDesc(ServerDesc desc) throws Exception JavaDoc {
371     if (desc == null) return;
372     servers.put(desc);
373   }
374
375   static ServerDesc removeServerDesc(short sid) throws Exception JavaDoc {
376     return servers.remove(sid);
377   }
378
379   public static Enumeration elementsServerDesc() {
380     return servers.elements();
381   }
382
383   public static Enumeration getServersIds() {
384     return servers.keys();
385   }
386
387   /**
388    * Gets the number of server known on the current server.
389    *
390    * @return the number of server.
391    */

392   final static int getServerNb() {
393     return servers.size();
394   }
395
396   /**
397    * Gets the characteristics of the corresponding server.
398    *
399    * @param sid agent server id.
400    * @return the server's descriptor.
401    */

402   final static ServerDesc getServerDesc(short sid) throws UnknownServerException {
403     ServerDesc serverDesc = servers.get(sid);
404     if (serverDesc == null)
405       throw new UnknownServerException("Unknow server id. #" + sid);
406     return serverDesc;
407   }
408
409   /**
410    * Gets the message consumer for the corresponding server.
411    *
412    * @param sid agent server id.
413    * @return the corresponding message consumer.
414    */

415   final static MessageConsumer getConsumer(short sid) throws UnknownServerException {
416     return getServerDesc(sid).domain;
417   }
418
419   /**
420    * Get the host name of an agent server.
421    *
422    * @param sid agent server id
423    * @return server host name as declared in configuration file
424    */

425   public final static String JavaDoc getHostname(short sid) throws UnknownServerException {
426     return getServerDesc(sid).getHostname();
427   }
428
429   /**
430    * Get the description of all services of the current agent server.
431    *
432    * @return server host name as declared in configuration file
433    */

434   final static ServiceDesc[] getServices() throws UnknownServerException {
435     return getServerDesc(getServerId()).services;
436   }
437
438   /**
439    * Get the argument strings for a particular service.
440    * The information provides from the A3 configuration file, so it's
441    * only available if this file contains service's informations for all
442    * nodes.
443    *
444    * @see A3CMLConfig#getServiceArgs(short,String)
445    *
446    * @param sid agent server id
447    * @param classname the service class name
448    * @return the arguments as declared in configuration file
449    * @exception UnknownServerException
450    * The specified server does not exist.
451    * @exception UnknownServiceException
452    * The specified service is not declared on this server.
453    * @exception Exception
454    * Probably there is no configuration defined.
455    */

456   public final static
457   String JavaDoc getServiceArgs(short sid,
458             String JavaDoc classname) throws Exception JavaDoc {
459     return getConfig().getServiceArgs(sid, classname);
460   }
461
462   /**
463    * Get the argument strings for a particular service running on a server
464    * identified by its host.
465    * The information provides from the A3 configuration file, so it's
466    * only available if this file contains service's informations for all
467    * nodes.
468    *
469    * @see A3CMLConfig#getServiceArgs(String, String)
470    *
471    * @param hostname hostname
472    * @param classname the service class name
473    * @return the arguments as declared in configuration file
474    * @exception UnknownServiceException
475    * The specified service is not declared on this server.
476    * @exception Exception
477    * Probably there is no configuration defined.
478    */

479   public final static
480   String JavaDoc getServiceArgs(String JavaDoc hostname,
481             String JavaDoc classname) throws Exception JavaDoc {
482     return getConfig().getServiceArgsHost(hostname, classname);
483   }
484
485   /**
486    * The second step of initialization. It needs the Transaction component
487    * be up, then it initializes all <code>AgentServer</code> structures from
488    * the <code>A3CMLConfig</code> ones. In particular the servers array is
489    * initialized.
490    */

491   private static void configure() throws Exception JavaDoc {
492     A3CMLServer root = getConfig().getServer(serverId, clusterId);
493     //Allocates the temporary descriptors hashtable for each server.
494
servers = new ServersHT();
495     // Initialized the descriptor of current server in order to permit
496
// Channel and Engine initialization.
497
ServerDesc local = new ServerDesc(root.sid, root.name, root.hostname, -1);
498     servers.put(local);
499
500     // Parse configuration in order to fix route related to the
501
// current server
502
getConfig().configure(root);
503
504     // Creates all the local MessageConsumer.
505
createConsumers(root);
506     
507     for (Enumeration s = getConfig().servers.elements();
508          s.hasMoreElements();) {
509       A3CMLServer server = (A3CMLServer) s.nextElement();
510       if (server.sid == root.sid) continue;
511
512       ServerDesc desc = createServerDesc(server);
513       addServerDesc(desc);
514     }
515
516     // for clusters
517
for (Enumeration c = getConfig().clusters.elements();
518          c.hasMoreElements();) {
519       A3CMLCluster cluster = (A3CMLCluster) c.nextElement();
520
521       for (Enumeration s = cluster.servers.elements();
522            s.hasMoreElements();) {
523         A3CMLServer server = (A3CMLServer) s.nextElement();
524         if (server.sid == root.sid) continue;
525
526         ServerDesc desc = servers.get(server.sid);
527         if (desc == null) {
528           desc = createServerDesc(server);
529           addServerDesc(desc);
530         } else {
531           desc.addSockAddr(server.hostname, server.port);
532         }
533       }
534     }
535
536     initServices(root, local);
537     local.domain = engine;
538
539 // if (logmon.isLoggable(BasicLevel.DEBUG)) {
540
// for (int i=0; i<servers.length; i++) {
541
// logmon.log(BasicLevel.DEBUG,
542
// getName() + ", servers[" + i + "]=(" +
543
// "sid=" + servers[i].sid +
544
// ", name=" + servers[i].name +
545
// ", gateway=" + servers[i].gateway +
546
// ", domain=" + servers[i].domain + ")");
547
// }
548
// }
549

550     return;
551   }
552
553   private static void createConsumers(A3CMLServer root) throws Exception JavaDoc {
554     consumers = new Hashtable();
555
556     // Creates the local MessageConsumer: the Engine.
557
engine = Engine.newInstance();
558     addConsumer("local", engine);
559
560     // if JGroups
561
if (clusterId > NULL_ID) {
562       jgroups = new JGroups();
563       if (engine instanceof HAEngine) {
564         jgroups.setEngine((HAEngine) engine);
565         ((HAEngine) engine).setJGroups(jgroups);
566       } else
567         logmon.log(BasicLevel.ERROR, getName() + ", createConsumers(" + root + ")\n" +
568                    "engine [" + engine + "] is not a HAEngine");
569     }
570
571     // Search alls directly accessible domains.
572
for (Enumeration n = root.networks.elements();
573      n.hasMoreElements();) {
574       A3CMLNetwork network = (A3CMLNetwork) n.nextElement();
575
576       A3CMLDomain domain = getConfig().getDomain(network.domain);
577       // Creates the corresponding MessageConsumer.
578
try {
579         Network consumer = (Network) Class.forName(domain.network).newInstance();
580         // Initializes it with domain description. Be careful, this array
581
// is kept in consumer, don't reuse it!!
582
consumer.init(domain.name, network.port, domain.getServersId());
583         if (consumer instanceof SimpleNetwork &&
584             jgroups != null) {//NTA modify to SimpleHANetwork
585
((SimpleNetwork) consumer).setJGroups(jgroups);
586           jgroups.setNetWork((SimpleNetwork) consumer);
587         }
588 // domain.consumer = consumer;
589
addConsumer(network.domain, consumer);
590       } catch (ClassNotFoundException JavaDoc exc) {
591         throw exc;
592       } catch (InstantiationException JavaDoc exc) {
593         throw exc;
594       } catch (IllegalAccessException JavaDoc exc) {
595         throw exc;
596       }
597     }
598   }
599
600   static void initServerDesc(ServerDesc desc,
601                              A3CMLServer server) throws Exception JavaDoc {
602     desc.gateway = server.gateway;
603     // For each server set the gateway to the real next destination of
604
// messages; if the server is directly accessible: itself.
605
if ((desc.gateway == -1) || (desc.gateway == server.sid)) {
606       desc.gateway = server.sid;
607       desc.updateSockAddr(desc.getHostname(), server.port);
608       A3CMLServer current = getConfig().getServer(getServerId(),getClusterId());
609       if (current.containsNat(server.sid)) {
610         A3CMLNat nat = current.getNat(server.sid);
611         desc.updateSockAddr(nat.host, nat.port);
612         if (logmon.isLoggable(BasicLevel.DEBUG))
613           logmon.log(BasicLevel.DEBUG, getName() + " : NAT sDesc = " + desc);
614       }
615     }
616     desc.domain = getConsumer(server.domain);
617   }
618
619   private static ServerDesc
620       createServerDesc(A3CMLServer server) throws Exception JavaDoc {
621     if (! server.visited)
622       throw new Exception JavaDoc(server + " inaccessible");
623     
624     ServerDesc desc = new ServerDesc(server.sid,
625                                      server.name,
626                                      server.hostname,
627                                      -1);
628
629     initServerDesc(desc, server);
630     initServices(server, desc);
631
632     return desc;
633   }
634
635   private static void initServices(A3CMLServer server, ServerDesc desc) {
636     if (server.services != null) {
637       ServiceDesc services[] = new ServiceDesc[server.services.size()];
638       int idx = 0;
639       for (Enumeration x = server.services.elements();
640            x.hasMoreElements();) {
641         A3CMLService service = (A3CMLService) x.nextElement();
642         services[idx++] = new ServiceDesc(service.classname, service.args);
643       }
644       desc.services = services;
645     }
646   }
647   
648   private static void setProperties(short sid, short cid) throws Exception JavaDoc {
649     if (a3config == null) return;
650
651     // add global properties
652
if (a3config.properties != null) {
653       for (Enumeration e = a3config.properties.elements(); e.hasMoreElements();) {
654         A3CMLProperty p = (A3CMLProperty) e.nextElement();
655         System.getProperties().put(p.name,p.value);
656       }
657     }
658
659     A3CMLServer server = null;
660     if (cid != NULL_ID) {
661       A3CMLCluster cluster = null;
662       cluster = a3config.getCluster(sid);
663
664       // add cluster properties
665
if (cluster != null
666           && cluster.properties != null
667           && cluster.properties.size() > 0) {
668         Enumeration e = cluster.properties.elements();
669         do {
670           A3CMLProperty p = (A3CMLProperty) e.nextElement();
671           System.getProperties().put(p.name,p.value);
672         } while (e.hasMoreElements());
673       }
674       server = cluster.getServer(cid);
675     } else {
676       server = a3config.getServer(sid);
677     }
678
679     // add server properties
680
if (server != null && server.properties != null) {
681       Enumeration e = server.properties.elements();
682       do {
683         A3CMLProperty p = (A3CMLProperty) e.nextElement();
684         System.getProperties().put(p.name,p.value);
685       } while (e.hasMoreElements());
686     }
687   }
688   
689   public static class Status {
690     public static final int INSTALLED = 0;
691     public static final int INITIALIZING = 0x1;
692     public static final int INITIALIZED = 0x2;
693     public static final int STARTING = 0x3;
694     public static final int STARTED = 0x4;
695     public static final int STOPPING = 0x5;
696     public static final int STOPPED = 0x6;
697     public static final int RESETING = 0x7;
698
699     private int value = INSTALLED;
700
701     public static String JavaDoc[] info = {"installed",
702                                    "initializing", "initialized",
703                                    "starting", "started",
704                                    "stopping", "stopped",
705                                    "reseting"};
706   }
707
708   static Status status = new Status();
709
710   public static int getStatus() {
711     return status.value;
712   }
713
714   public static String JavaDoc getStatusInfo() {
715     return Status.info[status.value];
716   }
717
718   /**
719    * Parses agent server arguments, then initializes this agent server. The
720    * <code>start</code> function is then called to start this agent server
721    * execution. Between the <code>init</code> and </code>start</code> calls,
722    * agents may be created and deployed, and notifications may be sent using
723    * the <code>Channel</code> <code>sendTo</code> function.
724    *
725    * @param args lauching arguments, the first one is the server id
726    * and the second one the persistency directory.
727    * @return number of arguments consumed in args
728    *
729    * @exception Exception
730    * unspecialized exception
731    */

732   public static int init(String JavaDoc args[]) throws Exception JavaDoc {
733     if (args.length < 2)
734       throw new Exception JavaDoc("usage: java <main> sid storage");
735     short sid = NULL_ID;
736     try {
737       sid = (short) Integer.parseInt(args[0]);
738     } catch (NumberFormatException JavaDoc exc) {
739       throw new Exception JavaDoc("usage: java <main> sid storage");
740     }
741     String JavaDoc path = args[1];
742     short cid = NULL_ID;
743     try {
744       if (args.length == 3)
745       cid = (short) Integer.parseInt(args[2]);
746     } catch (NumberFormatException JavaDoc exc) {}
747
748     init(sid, path, null, cid);
749
750     configController = new ConfigController();
751
752     return 2;
753   }
754
755   public static void reset(boolean force) {
756     if (force) {
757       synchronized(status) {
758         if (status.value != Status.STOPPED) {
759           logmon.log(BasicLevel.WARN,
760                      getName() + ", force status: " + status.value);
761         }
762         status.value = Status.STOPPED;
763       }
764     }
765     reset();
766   }
767
768   /**
769    * Cleans an AgentServer configuration in order to restart it from
770    * persistent storage.
771    */

772   public static void reset() {
773     synchronized(status) {
774       if (status.value != Status.STOPPED) {
775         logmon.log(BasicLevel.WARN,
776                    getName() + ", cannot reset, bad status: " + status.value);
777         return;
778       }
779       status.value = Status.RESETING;
780     }
781
782     // Remove all consumers Mbean
783
Enumeration e = getConsumers();
784     if (e != null) {
785       for (; e.hasMoreElements();) {
786         MessageConsumer cons = (MessageConsumer) e.nextElement();
787         try {
788           MXWrapper.unregisterMBean(
789             "AgentServer",
790             "server=" + getName() + ",cons=" + cons.getName());
791         } catch (Exception JavaDoc exc) {
792           logmon.log(BasicLevel.DEBUG,
793                      getName() + ", jmx failed: " +
794                      "server=" + getName() + ",cons=" + cons.getName(), exc);
795         }
796       }
797       consumers = null;
798     }
799
800     try {
801       MXWrapper.unregisterMBean("AgentServer",
802                                 "server=" + getName() + ",cons=Transaction");
803     } catch (Exception JavaDoc exc) {
804       logmon.log(BasicLevel.DEBUG,
805                  getName() + ", jmx failed: " +
806                  "server=" + getName() + ",cons=Transaction", exc);
807     }
808
809     if (transaction != null) transaction.close();
810     transaction = null;
811
812     try {
813       MXWrapper.unregisterMBean("AgentServer", "server=" + getName());
814     } catch (Exception JavaDoc exc) {
815       logmon.log(BasicLevel.DEBUG,
816                  getName() + " jmx failed: "+ "server=" + getName(), exc);
817     }
818     
819     a3config = null;
820
821     synchronized(status) {
822       status.value = Status.INSTALLED;
823     }
824   }
825
826  /**
827    * Initializes this agent server.
828    * <code>start</code> function is then called to start this agent server
829    * execution. Between the <code>init</code> and </code>start</code> calls,
830    * agents may be created and deployed, and notifications may be sent using
831    * the <code>Channel</code> <code>sendTo</code> function.
832    *
833    * @param sid the server id
834    * @param path the persistency directory.
835    * @param loggerFactory the monolog LoggerFactory;
836    *
837    *
838    * @exception Exception
839    * unspecialized exception
840    */

841   public static void init(short sid,
842                           String JavaDoc path,
843                           LoggerFactory loggerFactory) throws Exception JavaDoc {
844     init(sid, path, loggerFactory, NULL_ID);
845   }
846
847  /**
848    * Initializes this agent server.
849    * <code>start</code> function is then called to start this agent server
850    * execution. Between the <code>init</code> and </code>start</code> calls,
851    * agents may be created and deployed, and notifications may be sent using
852    * the <code>Channel</code> <code>sendTo</code> function.
853    *
854    * @param sid the server id
855    * @param path the persistency directory.
856    * @param loggerFactory the monolog LoggerFactory;
857    * @param cid the cluster id
858    *
859    *
860    * @exception Exception
861    * unspecialized exception
862    */

863   public static void init(short sid,
864                           String JavaDoc path,
865                           LoggerFactory loggerFactory,
866                           short cid) throws Exception JavaDoc {
867     name = new StringBuffer JavaDoc("AgentServer#").append(sid).toString();
868
869     if (loggerFactory != null) Debug.setLoggerFactory(loggerFactory);
870     logmon = Debug.getLogger(Debug.A3Debug + ".AgentServer.#" + sid);
871
872     if (logmon.isLoggable(BasicLevel.DEBUG))
873       logmon.log(BasicLevel.DEBUG, getName() + ", init()", new Exception JavaDoc());
874     else
875       logmon.log(BasicLevel.WARN, getName() + ", init()");
876
877     synchronized(status) {
878       if (status.value == Status.STOPPED) {
879         logmon.log(BasicLevel.DEBUG, getName() + ", reset configuration");
880         reset();
881       }
882       if (status.value != Status.INSTALLED)
883         throw new Exception JavaDoc("cannot initialize, bad status: " + status.value);
884       status.value = Status.INITIALIZING;
885     }
886
887     try {
888       serverId = sid;
889
890       tgroup = new ThreadGroup JavaDoc(getName()) {
891           public void uncaughtException(Thread JavaDoc t, Throwable JavaDoc e) {
892             if (logmon.isLoggable(BasicLevel.WARN)) {
893               logmon.log(BasicLevel.WARN,
894                          "Abnormal termination for " +
895                          t.getThreadGroup().getName() + "." + t.getName(),
896                          e);
897             }
898           }
899         };
900    
901       // Try to get transaction type from disk, then initialize the rigth
902
// transaction manager and get the configuration.
903
File dir = new File(path);
904       if (dir.exists() && dir.isDirectory()) {
905         File tfc = new File(dir, "TFC");
906         if (tfc.exists()) {
907           DataInputStream dis = null;
908           try {
909             dis = new DataInputStream(new FileInputStream(tfc));
910             String JavaDoc tname = dis.readUTF();
911             Class JavaDoc tclass = Class.forName(tname);
912             transaction = (Transaction) tclass.newInstance();
913           } catch (Exception JavaDoc exc) {
914             logmon.log(BasicLevel.FATAL,
915                        getName() + ", can't instanciate transaction manager",
916                        exc);
917             throw new Exception JavaDoc("Can't instanciate transaction manager");
918           } finally {
919             if (dis != null) dis.close();
920           }
921           try {
922             transaction.init(path);
923           } catch (IOException exc) {
924             logmon.log(BasicLevel.FATAL,
925                        getName() + ", can't start transaction manager", exc);
926             throw new Except