KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > sapia > regis > remote > RegistryServer


1 package org.sapia.regis.remote;
2
3 import java.util.Properties JavaDoc;
4
5 import org.sapia.regis.Configurable;
6 import org.sapia.regis.Node;
7 import org.sapia.regis.Path;
8 import org.sapia.regis.RWNode;
9 import org.sapia.regis.RWSession;
10 import org.sapia.regis.RegisSession;
11 import org.sapia.regis.Registry;
12 import org.sapia.regis.RegistryContext;
13 import org.sapia.regis.loader.RegistryConfigLoader;
14 import org.sapia.regis.util.Utils;
15 import org.sapia.ubik.rmi.Consts;
16 import org.sapia.ubik.rmi.server.Hub;
17
18 /**
19  * <h2>Basics</h2>
20  * An instance of this class connects to a registry and exports it as
21  * a remote registry to a Ubik JNDI server, or on an explicit port.
22  * <p>
23  * This class is configured through Java properties. The path to a Java properties
24  * file can be specified at the command-line. This class attempts to load the file from:
25  * <ul>
26  * <li>the file system.
27  * <li>the network (interpreting the given path as a URL).
28  * <li>the classpath.
29  * </ul>
30  * <p>
31  * If no such path is given, this class defaults to the system properties - in fact
32  * this class also defaults to the system properties if a given property could not
33  * be found at the level of the loaded properties.
34  * <p>
35  *
36  * This class expects one of the following properties to be specified:
37  * <ul>
38  * <li>org.sapia.regis.jndi.name: corresponds to the JNDI name under which to bind
39  * the registry, in the Ubik JNDI server.
40  * <li>org.sapia.regis.server.port: corresponds to the explicit port to which to bind the
41  * registry (in this case the Ubik JNDI server is not used).
42  * </ul>
43  * <p>
44  * If the host on which the server is started has multiple network interfaces, then the one
45  * to specifically use can be set through the following system property
46  * (see the Ubik <a target="ubikNaming" HREF="http://www.sapia-oss.org/projects/ubik/tutorial.html#bindaddr">documentation</a>):
47  * <code>ubik.rmi.address-pattern</code>. The value of the property must correspond to a valid regular
48  * expression (for example: <code>192\.\d+\.\d+\.\d+</code>).
49  * <p>
50  * The following provides a sample registry server configuration:
51  * <pre>
52  * org.sapia.regis.factory=org.sapia.regis.local.LocalRegistryFactory
53  * org.sapia.regis.remote.jndi.name=services/regis
54  * java.naming.provider.url=ubik://192.168.0.103:1099/
55  * ubik.jndi.domain=default
56  * org.sapia.regis.remote.p2p=true
57  * ubik.rmi.address-pattern=192\.\d+\.\d+\.\d+
58  * </pre>
59  * The properties are further explained below.
60  *
61  * <p>
62  * Note that if the Ubik JNDI server is used in order to publish the server on the network,
63  * the required Ubik JNDI properties must be given as part of properties loaded by this
64  * server (again, see the Ubik <a target="ubikNaming" HREF="http://www.sapia-oss.org/projects/ubik/naming.html#robust">documentation</a>).
65  *
66  * <h2>Remote Configuration Upload</h2>
67  *
68  * A registry server supports remotely loading configuration files (all remote
69  * registry nodes implement the {@link org.sapia.regis.Configurable} interface).
70  * However, since this can pause a security or access control issue, a registry server supports
71  * username/password authentication. That is: as part of the server's configuration properties, a username
72  * and password can be specified, which are used to perform authentication of remote users that
73  * attempt loading a configuration into the registry.
74  * <p>
75  * The username and password must be given as values of the following properties, respectively:
76  * <ul>
77  * <li>org.sapia.regis.remote.username
78  * <li>org.sapia.regis.remote.password
79  * </ul>
80  * If no username and/or password are given, the following default ones are respectively used:
81  * <ul>
82  * <li>regis
83  * <li>secret
84  * </ul>
85  *
86  * <h2>Bootstrap Configuration</h2>
87  *
88  * A registry server can be provided with a boostrap XML configuration, that it will load at startup to initialize
89  * itself. This can be useful between shutdowns, if the configuration that a registry contains is not persisted.
90  * For bootstrapping to work, the following property must be specified as part of the registry server's properties:
91  * <code>org.sapia.regis.remote.bootstrap</code>. The value of that property consists of a comma-delimited list
92  * of resources that are to be loaded. Each resource is interpreted either as (whichever works first):
93  *
94  * <ul>
95  * <li>a file.
96  * <li>a URL.
97  * <li>a resource on the classpath.
98  * </ul>
99  *
100  * The following is an example of a bootstrap property:
101  * <pre>
102  * org.sapia.regis.remote.bootstrap=/home/conf/host.xml, http://mercury.acmeco.net/global.xml
103  * </pre>
104  * Attempt is made to load all resources (loading does not stop at the first resource that is found).
105  *
106  * <h2>Peer-to-Peer</h2>
107  *
108  * A registry server can act in peer-to-peer mode, meaning that in this case all registry
109  * servers belonging to the same given domain will upload their configuration to their peers.
110  * For example, given registry A and B belonging to the same domain, if registry A is
111  * updated with a configuration by an end-user, it will in turn upload that configuration
112  * to registry B.
113  * <p>
114  * <b>Replication is not performed in the case of boostrap configuration.</b>
115  *
116  * <p>
117  * The domain of a registry server is passed to it through the properties that it loads. It
118  * is identified by the following property: <code>ubik.jndi.domain</code> (the server uses
119  * Ubik's multicast to discover other registry servers in the domain, and publish itself to these
120  * peers). If the property is not specified, <code>default</code> is used as domain name.
121  * <p>
122  * In addition, for the replicated mechanism to work, the following property also has to be
123  * specified: <code>org.sapia.regis.remote.p2p</code>, with a value of <code>true</code>.
124  * <p>
125  * The {@link org.sapia.regis.ant.RegistryTask} Ant task has been implemented in order to
126  * upload registry configuration remotely, from an Ant script.
127  *
128  * @author yduchesne
129  *
130  */

131 public class RegistryServer implements RemoteConsts{
132   
133   private static RegistryExporter _exporter;
134   private static Properties JavaDoc _bootstrapProps = new Properties JavaDoc();
135   public static boolean startThread = true;
136   
137   
138   public static void main(String JavaDoc[] args) {
139     if(args.length == 1 && (
140        args[0].equals("--help") ||
141        args[0].equals("-h")
142        )){
143       help();
144       return;
145     }
146     try{
147       _bootstrapProps = new Properties JavaDoc(System.getProperties());
148       if(args.length > 0){
149         Utils.loadProps(RegistryServer.class, _bootstrapProps, args[0]);
150       }
151       
152       if(_bootstrapProps.getProperty(Consts.IP_PATTERN_KEY) != null){
153         System.setProperty(Consts.IP_PATTERN_KEY, _bootstrapProps.getProperty(Consts.IP_PATTERN_KEY));
154       }
155       
156       ServerDebug.enabled = _bootstrapProps.getProperty(DEBUG, "true").equalsIgnoreCase("true");
157       
158       RegistryContext ctx = new RegistryContext(_bootstrapProps);
159       Registry reg = ctx.connect();
160       
161       if(_bootstrapProps.getProperty(BOOTSTRAP) != null){
162         try{
163           loadBootStrap(reg, _bootstrapProps.getProperty(BOOTSTRAP), _bootstrapProps);
164         }catch(Exception JavaDoc e){
165           System.out.println("Could not load bootstrap configuration.");
166           System.out.println("Got the following error:");
167           e.printStackTrace();
168           return;
169         }
170       }
171
172       _exporter = new RegistryExporter(
173           _bootstrapProps.getProperty(USERNAME, DEFAULT_USERNAME),
174           _bootstrapProps.getProperty(PASSWORD, DEFAULT_PASSWORD),
175           reg,
176           _bootstrapProps);
177       if(_bootstrapProps.getProperty(Consts.UBIK_DOMAIN_NAME) != null){
178         _exporter.setDomain(_bootstrapProps.getProperty(Consts.UBIK_DOMAIN_NAME));
179       }
180       _exporter.setPeerToPeer(new Boolean JavaDoc(_bootstrapProps.getProperty(PEER_TO_PEER, "false")).booleanValue());
181       if(_bootstrapProps.getProperty(SERVER_JNDI_NAME) != null){
182         _exporter.bind(_bootstrapProps.getProperty(SERVER_JNDI_NAME), _bootstrapProps);
183       }
184       else if(_bootstrapProps.getProperty(SERVER_PORT) != null){
185         _exporter.bind(Integer.parseInt(_bootstrapProps.getProperty(SERVER_PORT)));
186       }
187       else{
188         throw new IllegalStateException JavaDoc("One of the following properties must be specified:" +
189             SERVER_JNDI_NAME + " or " + SERVER_PORT);
190       }
191       System.out.println("Registry server started - typce CTRL-C to abort cleanly.");
192       Runtime.getRuntime().addShutdownHook(new ShutdownHook());
193       
194       if(startThread){
195         while(true){
196           try{
197             Thread.sleep(100000);
198           }catch(InterruptedException JavaDoc e){
199             e.printStackTrace();
200             break;
201           }
202         }
203       }
204     }catch(Exception JavaDoc e){
205       e.printStackTrace();
206     }
207   }
208    
209   static final void help(){
210     System.out.println("Excepted argument: <propfile> ");
211   }
212   
213   static void loadBootStrap(Registry reg, String JavaDoc bootstrap, Properties JavaDoc props) throws Exception JavaDoc{
214     String JavaDoc[] resources = bootstrap.split(",");
215     RegisSession session = null;
216     try{
217       session = reg.open();
218       Node node = reg.getRoot();
219       if(reg instanceof Configurable){
220         loadConfigurable((Configurable)reg, resources);
221       }
222       else if(node instanceof Configurable){
223         loadConfigurable((Configurable)node, resources);
224       }
225       else{
226         RWSession rw = (RWSession)session;
227         rw.begin();
228         try{
229           RegistryConfigLoader loader = new RegistryConfigLoader((RWNode)reg.getRoot());
230           for(int i = 0; i < resources.length; i++){
231             loader.load(Utils.load(RegistryServer.class, resources[i].trim()), props);
232           }
233           rw.commit();
234         }catch(RuntimeException JavaDoc e){
235           rw.rollback();
236           throw e;
237         }
238       }
239     }catch(ClassCastException JavaDoc e){
240       throw new IllegalStateException JavaDoc("Registry does not support write operations; cannot update");
241     }finally{
242       if(session != null){
243         session.close();
244       }
245     }
246   }
247   
248   private static void loadConfigurable(Configurable conf, String JavaDoc[] resources) throws Exception JavaDoc{
249     Path path = Path.parse(Node.ROOT_NAME);
250     for(int i = 0; i < resources.length; i++){
251       String JavaDoc xmlConf = Utils.loadAsString(Utils.load(RegistryServer.class, resources[i].trim()));
252       conf.load(path, null, null, xmlConf, _bootstrapProps);
253     }
254   }
255   
256   public static class ShutdownHook extends Thread JavaDoc{
257     public void run() {
258       try{
259         Hub.shutdown(30000);
260         if(_exporter != null)
261           _exporter.close();
262       }catch(InterruptedException JavaDoc e){
263         e.printStackTrace();
264       }
265       System.out.println("Stopped registry server.");
266     }
267   }
268
269 }
270
Popular Tags