]> sjero.net Git - linphone/blob - p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/ModuleManager.java
81fb365bad208599c91882dad7b900981f9cbd3f
[linphone] / p2pproxy / dependencies-src / jxse-src-2.5 / impl / src / net / jxta / impl / util / ModuleManager.java
1 /*
2  * Copyright (c) 2001-2007 Sun Microsystems, Inc.  All rights reserved.
3  *  
4  *  The Sun Project JXTA(TM) Software License
5  *  
6  *  Redistribution and use in source and binary forms, with or without 
7  *  modification, are permitted provided that the following conditions are met:
8  *  
9  *  1. Redistributions of source code must retain the above copyright notice,
10  *     this list of conditions and the following disclaimer.
11  *  
12  *  2. Redistributions in binary form must reproduce the above copyright notice, 
13  *     this list of conditions and the following disclaimer in the documentation 
14  *     and/or other materials provided with the distribution.
15  *  
16  *  3. The end-user documentation included with the redistribution, if any, must 
17  *     include the following acknowledgment: "This product includes software 
18  *     developed by Sun Microsystems, Inc. for JXTA(TM) technology." 
19  *     Alternately, this acknowledgment may appear in the software itself, if 
20  *     and wherever such third-party acknowledgments normally appear.
21  *  
22  *  4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must 
23  *     not be used to endorse or promote products derived from this software 
24  *     without prior written permission. For written permission, please contact 
25  *     Project JXTA at http://www.jxta.org.
26  *  
27  *  5. Products derived from this software may not be called "JXTA", nor may 
28  *     "JXTA" appear in their name, without prior written permission of Sun.
29  *  
30  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
31  *  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
32  *  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN 
33  *  MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
34  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
35  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
36  *  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
37  *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
38  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
39  *  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40  *  
41  *  JXTA is a registered trademark of Sun Microsystems, Inc. in the United 
42  *  States and other countries.
43  *  
44  *  Please see the license information page at :
45  *  <http://www.jxta.org/project/www/license.html> for instructions on use of 
46  *  the license in source files.
47  *  
48  *  ====================================================================
49  *  
50  *  This software consists of voluntary contributions made by many individuals 
51  *  on behalf of Project JXTA. For more information on Project JXTA, please see 
52  *  http://www.jxta.org.
53  *  
54  *  This license is based on the BSD license adopted by the Apache Foundation. 
55  */
56
57 package net.jxta.impl.util;
58
59
60 import java.util.Enumeration;
61 import java.util.Hashtable;
62 import java.io.IOException;
63
64 import net.jxta.platform.Module;
65 import net.jxta.platform.ModuleClassID;
66 import net.jxta.platform.ModuleSpecID;
67 import net.jxta.discovery.DiscoveryService;
68 import net.jxta.document.Advertisement;
69 import net.jxta.document.AdvertisementFactory;
70 import net.jxta.document.Element;
71 import net.jxta.document.MimeMediaType;
72 import net.jxta.document.StructuredDocument;
73 import net.jxta.document.StructuredDocumentFactory;
74 import net.jxta.document.StructuredDocumentUtils;
75 import net.jxta.document.TextElement;
76 import net.jxta.protocol.ModuleClassAdvertisement;
77 import net.jxta.protocol.ModuleImplAdvertisement;
78 import net.jxta.protocol.ModuleSpecAdvertisement;
79 import net.jxta.peergroup.PeerGroup;
80 import net.jxta.peergroup.PeerGroupID;
81 import net.jxta.id.IDFactory;
82
83
84 /**
85  * Module Manager.
86  *
87  * This class allows to manage modules to be loaded, started and stopped
88  * within a PeerGroup. Modules that are loaded using the ModuleManager do not need
89  * to be listed within the PeerGroup advertisement, nor do they have to have
90  * published their ModuleSpec and ModuleImpl advertisements: the ModuleManager
91  * takes care of this task. However, other peers which may want to load the Module
92  * will also have to use its own loader (or the ModuleManager itself, of course):
93  * the ModuleManager only manages Modules on the local peer.
94  *
95  * The Module Manager allows, as an option, to use an application provided class loader.
96  * The default class loader is the PeerGroup class loader.
97  *
98  * The following example shows how to use the ModuleManager:
99  *
100  *
101  * <pre>
102  *      // Get the peergroup
103  *      PeerGroup group = getMyPeerGroup();
104  *      // Get the ModuleManager
105  *      ModuleManager moduleManager = ModuleManager.getModuleManager (group);
106  *
107  *      // Is the Module already loaded ?
108  *      Module module = moduleManager.lookupModule ("SampleModule");
109  *      if (module == null) {
110  *          // SampleModue is not loaded yet. Load it now.
111  *          module = moduleManager.loadModule ( "SampleModule", "net.jxta.app.SampleModule.SampleModule");
112  *      }
113  *
114  *      // Start SampleModule
115  *      moduleManager.startModule ("SampleModule", moduleArgs);
116  * </pre>
117  */
118
119 public class ModuleManager {
120
121     private static Hashtable<PeerGroupID, ModuleManager> managers = null;
122     private static long LOCAL_ADV_TTL = 5 * 60 * 1000;
123     // 5 minutes is more than sufficient
124     private static long REMOTE_ADV_TTL = 0;
125     // We do not allow remote access of the advertisements.
126
127     private final Hashtable<String, ModuleDesc> modules = new Hashtable<String, ModuleDesc>();
128     private final PeerGroup group;
129
130     /**
131      * Private constructor that allows to create an instance of the Module Manager for each
132      * PeerGroup.
133      *
134      * @param  group  the PeerGroup for which the ModuleManager needs to allocated a new instance
135      * of itself.
136      */
137     private ModuleManager(PeerGroup group) {
138         this.group = group;
139     }
140
141     /**
142      * startModule
143      *
144      * This method is invoked by the application to start a previously loaded
145      * module.
146      *
147      * @param  moduleName  is the symbolic name of the module.
148      * @param  args        is an array of String containing optional arguments for the module. This
149      * array is passed directly to the startApp (String[] ) method of the Module.
150      */
151     public void startModule(String moduleName, String[] args) {
152
153         ModuleDesc moduleDesc = modules.get(moduleName);
154
155         if (moduleDesc == null) {
156             // Cannot find such a module
157             return;
158         }
159         moduleDesc.startApp(args);
160     }
161
162     /**
163      * stopModule
164      *
165      * This method is invoked by the application to stop a running module.
166      *
167      * @param  moduleName  is the symbolic name of the module.
168      */
169     public void stopModule(String moduleName) {
170
171         ModuleDesc moduleDesc = modules.get(moduleName);
172
173         if (moduleDesc == null) {
174             // Cannot find such a module
175             return;
176         }
177         moduleDesc.stopApp();
178     }
179
180     /**
181      * getModuleManager
182      *
183      * This method is used in order to get the instance of the ModuleManager for a given
184      * PeerGroup. getModuleManager will create a new instance automatically if there is no
185      * instance for the given PeerGroup.
186      *
187      * @param  group  the PeerGroup for which the ModuleManager is asked.
188      * @return        the ModuleManager instance for the given PeerGroup.
189      */
190     public static ModuleManager getModuleManager(PeerGroup group) {
191
192         if (managers == null) {
193             // This is the first time the ModuleManager is invoked. Create
194             // the Hashtable
195             managers = new Hashtable<PeerGroupID, ModuleManager>();
196         }
197         ModuleManager manager;
198
199         manager = managers.get(group.getPeerGroupID());
200
201         if (manager == null) {
202             manager = new ModuleManager(group);
203             managers.put(group.getPeerGroupID(), manager);
204         }
205         return manager;
206     }
207
208     /**
209      *  Description of the Method
210      *
211      * @param  moduleName  Description of the Parameter
212      * @param  module      Description of the Parameter
213      * @return             Description of the Return Value
214      */
215     private synchronized boolean registerModule(String moduleName, Module module) {
216
217         ModuleDesc moduleDesc = modules.get(moduleName);
218
219         if (moduleDesc != null) {
220             // There is already a module registered to that name.
221             return false;
222         }
223         moduleDesc = new ModuleDesc(module);
224         modules.put(moduleName, moduleDesc);
225         return true;
226     }
227
228     /**
229      * lookupModule
230      *
231      * Get the Module from its symbolic name.
232      *
233      * @param  moduleName  symbolic name of the Module
234      * @return             the Module for the given name. null is returned if there is no module
235      * of the given name.
236      */
237     public synchronized Module lookupModule(String moduleName) {
238
239         ModuleDesc moduleDesc = modules.get(moduleName);
240
241         if (moduleDesc == null) {
242             // There is not any module registered to that name.
243             return null;
244         }
245         return moduleDesc.module;
246     }
247
248     /**
249      * loadModule
250      *
251      * Loads a Module. A class loaded is provided by the application.
252      * If the module has already been loaded, the existing Module is returned.
253      *
254      * @param  moduleName  symbolic name of the Module
255      * @param  loader      application provided class loader
256      * @return             the Module for the given name. null is returned if the module could not be
257      * loaded
258      */
259
260     public synchronized Module loadModule(String moduleName, ModuleManagerLoader loader) {
261
262         // First check if the module is already loaded and registered
263         Module module = lookupModule(moduleName);
264
265         if (module != null) {
266             return module;
267         }
268         module = loader.loadModule(moduleName);
269         if (module != null) {
270             // Since this module is not started by the standard
271             // JXTA PeerGroup, we need to initialize ourself.
272             // Note that the ID and the ModuleImplAdvertisement is
273             // then set to null, which is fine, since that has been
274             // the decision from the application to actually not use
275             // the standard PeerGroup Module loading scheme.
276             try {
277                 module.init(group, null, null);
278             } catch (Exception e) {
279                 // Init failed, the module cannot be initialized
280                 return null;
281             }
282             registerModule(moduleName, module);
283         }
284         return module;
285     }
286
287     /**
288      * loadModule
289      *
290      * Loads a Module. The default PeerGroup class loader will be used. The class
291      * must be within the CLASSPATH of the platform.
292      * If the module has already been loaded, the existing Module is returned.
293      *
294      * @param  moduleName  symbolic name of the Module
295      * @param  moduleCode  the name of the class to be loaded.
296      * @return             the Module for the given name. null is returned if the module could not be
297      * loaded
298      */
299     public synchronized Module loadModule(String moduleName, String moduleCode) {
300
301         // First check if the module is already loaded and registered
302         Module module = lookupModule(moduleName);
303
304         if (module != null) {
305             return module;
306         }
307
308         if (!createModuleAdvs(moduleName, null, moduleCode, null, LOCAL_ADV_TTL, REMOTE_ADV_TTL)) {
309
310             // Creation of the module advertisement has failed.
311             return null;
312         }
313         // Get the module. This should always work since the advertisements have
314         // just been created.
315         module = loadModule(moduleName);
316         if (module == null) {
317             // There is really nothing more we can do here.
318             return null;
319         }
320         return module;
321     }
322
323     /**
324      *  Description of the Method
325      *
326      * @param  moduleName  Description of the Parameter
327      * @return             Description of the Return Value
328      */
329     private synchronized Module loadModule(String moduleName) {
330
331         // First check if the module is already loaded and registered
332         Module module = lookupModule(moduleName);
333
334         if (module != null) {
335             return module;
336         }
337
338         try {
339             // Recover the ModuleClassAdvertisement
340             Enumeration each = group.getDiscoveryService().getLocalAdvertisements(DiscoveryService.ADV, "Name", moduleName);
341
342             if (!each.hasMoreElements()) {
343                 // No advertisement.
344                 return null;
345             }
346
347             ModuleClassAdvertisement mcAdv = null;
348
349             while (each.hasMoreElements()) {
350                 try {
351                     mcAdv = (ModuleClassAdvertisement) each.nextElement();
352                     break;
353                 } catch (Exception ez1) {// ignored
354                 }
355             }
356
357             // Revover the Module Specification Advertisement
358             each = group.getDiscoveryService().getLocalAdvertisements(DiscoveryService.ADV, "Name", moduleName);
359             if (!each.hasMoreElements()) {
360                 return null;
361             }
362
363             ModuleSpecAdvertisement mSpecAdv = null;
364
365             while (each.hasMoreElements()) {
366                 try {
367                     mSpecAdv = (ModuleSpecAdvertisement) each.nextElement();
368                     break;
369                 } catch (Exception ez1) {// ignored
370                 }
371             }
372
373             module = group.loadModule(mcAdv.getModuleClassID(), mSpecAdv.getModuleSpecID(), PeerGroup.Here);
374
375             if (module != null) {
376                 registerModule(moduleName, module);
377             }
378             return module;
379         } catch (Exception ez2) {
380             return null;
381         }
382     }
383
384     /**
385      *  Description of the Method
386      *
387      * @param  moduleName     Description of the Parameter
388      * @param  moduleSpecURI  Description of the Parameter
389      * @param  moduleCode     Description of the Parameter
390      * @param  moduleCodeURI  Description of the Parameter
391      * @param  localTTL       Description of the Parameter
392      * @param  remoteTTL      Description of the Parameter
393      * @return                Description of the Return Value
394      */
395     private boolean createModuleAdvs(String moduleName, String moduleSpecURI, String moduleCode, String moduleCodeURI, long localTTL, long remoteTTL) {
396
397         DiscoveryService disco = group.getDiscoveryService();
398
399         try {
400             // First create the Module class advertisement associated with the module
401             // We build the module class advertisement using the advertisement
402             // Factory class by passing it the type of the advertisement we
403             // want to construct. The Module class advertisement is to be used
404             // to simply advertise the existence of the module. This is a
405             // a very small advertisement that only advertise the existence
406             // of module. In order to access the module, a peer will
407             // have to discover the associated module spec advertisement.
408
409             ModuleClassAdvertisement mcadv = (ModuleClassAdvertisement)
410                     AdvertisementFactory.newAdvertisement(ModuleClassAdvertisement.getAdvertisementType());
411
412             mcadv.setName(moduleName);
413             mcadv.setDescription("Created by ModuleManager: " + moduleName);
414
415             ModuleClassID mcID = IDFactory.newModuleClassID();
416
417             mcadv.setModuleClassID(mcID);
418
419             // Ok the Module Class advertisement was created, just publish
420             // it in my local cache and to my peergroup. This
421             // is the NetPeerGroup
422             disco.publish(mcadv, localTTL, remoteTTL);
423
424             // Create the Module Spec advertisement associated with the module
425             // We build the module Spec Advertisement using the advertisement
426             // Factory class by passing in the type of the advertisement we
427             // want to construct. The Module Spec advertisement will contain
428             // all the information necessary for a client to contact the module
429             // for instance it will contain a pipe advertisement to
430             // be used to contact the module
431
432             ModuleSpecAdvertisement mdadv = (ModuleSpecAdvertisement)
433                     AdvertisementFactory.newAdvertisement(ModuleSpecAdvertisement.getAdvertisementType());
434
435             // ModuleManager does not allow to set up any customized
436             // information for the Module.
437
438             mdadv.setName(moduleName);
439             mdadv.setCreator("jxta.org");
440             mdadv.setModuleSpecID(IDFactory.newModuleSpecID(mcID));
441
442             if (moduleSpecURI != null) {
443                 mdadv.setSpecURI(moduleSpecURI);
444             }
445
446             // Ok the Module advertisement was created, just publish
447             // it in my local cache and into the NetPeerGroup.
448             disco.publish(mdadv, localTTL, remoteTTL);
449
450             // Create the Module Implementation advertisement
451             ModuleImplAdvertisement miadv = (ModuleImplAdvertisement)
452                     AdvertisementFactory.newAdvertisement(ModuleImplAdvertisement.getAdvertisementType());
453
454             miadv.setModuleSpecID(mdadv.getModuleSpecID());
455             if (moduleCode != null) {
456                 miadv.setCode(moduleCode);
457             }
458
459             if (moduleCodeURI != null) {
460                 miadv.setUri(moduleCodeURI);
461             }
462             miadv.setDescription("Created by ModuleManager: " + moduleName);
463
464             // Steal the compat, provider, and uri from the
465             // group's own impl adv. We DO want them identical in
466             // this case.
467             ModuleImplAdvertisement pgImpl = (ModuleImplAdvertisement) group.getImplAdvertisement();
468
469             miadv.setCompat(pgImpl.getCompat());
470             miadv.setUri(pgImpl.getUri());
471
472             // Ok the Module Class advertisement was created, just publish
473             // it in my local cache and to my peergroup. This
474             // is the NetPeerGroup
475             disco.publish(miadv, localTTL, remoteTTL);
476         } catch (Exception ex) {
477             return false;
478         }
479         return true;
480     }
481
482     // FIXME this method should be refactored
483     /**
484      *  Creates a Module Class, Spec, and Impl advertisements, and adds the service
485      *  Advertisement as part of the Module Impl Advertisement, and publishes the advertisements
486      *  in local cache
487      *
488      * @param  group            group 
489      * @param  moduleName       module name
490      * @param  description      module description 
491      * @param  moduleSpecURI    module spec uri
492      * @param  moduleCode       module code
493      * @param  moduleCodeURI    module code uri 
494      * @param  mcID             module class id
495      * @param  msID             module spec id
496      * @param code              module code
497      * @param  serviceAdv       service advertisement
498      * @param  localTTL         local cache lifetime in ms
499      * @param  remoteTTL        remote cache lifetime in ms
500      * @exception  IOException  if an io error occurs
501      */
502     public void createServiceAdvertisement(PeerGroup group, String moduleName, String description, String moduleSpecURI, String moduleCode, String moduleCodeURI, ModuleClassID mcID, ModuleSpecID msID, String code, Advertisement serviceAdv, long localTTL, long remoteTTL) throws IOException {
503
504         DiscoveryService discovery = group.getDiscoveryService();
505         // Create module class advertisement
506         ModuleClassAdvertisement mcadv = (ModuleClassAdvertisement)
507                 AdvertisementFactory.newAdvertisement(ModuleClassAdvertisement.getAdvertisementType());
508
509         mcadv.setModuleClassID(mcID);
510         mcadv.setName(moduleName);
511         mcadv.setDescription(description);
512
513         // Module spec advertisement
514         ModuleSpecAdvertisement mdspec = (ModuleSpecAdvertisement)
515                 AdvertisementFactory.newAdvertisement(ModuleSpecAdvertisement.getAdvertisementType());
516
517         mdspec.setModuleSpecID(msID);
518         mdspec.setName(moduleName);
519         mdspec.setSpecURI(moduleSpecURI);
520
521         // Module implementation advertisement
522         ModuleImplAdvertisement miadv = (ModuleImplAdvertisement)
523                 AdvertisementFactory.newAdvertisement(ModuleImplAdvertisement.getAdvertisementType());
524
525         miadv.setModuleSpecID(mdspec.getModuleSpecID());
526         miadv.setDescription(description);
527         if (moduleCodeURI != null) {
528             miadv.setUri(moduleCodeURI);
529         }
530         if (moduleCode != null) {
531             miadv.setCode(moduleCode);
532         }
533         // Steal the compat, provider, and uri from the
534         // group's own impl adv. We DO want them identical in
535         // this case.
536         ModuleImplAdvertisement pgImpl = (ModuleImplAdvertisement) group.getImplAdvertisement();
537
538         miadv.setCompat(pgImpl.getCompat());
539         miadv.setCode(code);
540         Element pEl = (Element) serviceAdv.getDocument(MimeMediaType.XMLUTF8);
541         StructuredDocument svcParm = StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Parm");
542
543         StructuredDocumentUtils.copyElements(svcParm, svcParm, pEl);
544         miadv.setParam(svcParm);
545         // publish the advertisements
546         discovery.publish(mcadv, localTTL, remoteTTL);
547         discovery.publish(mdspec, localTTL, remoteTTL);
548         discovery.publish(miadv, localTTL, remoteTTL);
549     }
550
551     /**
552      *  Retreives a Service Advertisement from a module impl advertisement
553      * @param  group             peer group
554      * @param  mia               ModuleImplAdvertisement
555      * @param  advertismentType  service advertisment string Type
556      * @return                   The service Advertisement 
557      * @exception  IOException   if an io error occurs
558      */
559     public Advertisement getServiceAdvertisement(PeerGroup group, ModuleImplAdvertisement mia, String advertismentType) throws IOException {
560         Element param = mia.getParam();
561         Element pel = null;
562
563         if (param != null) {
564             Enumeration list = param.getChildren(advertismentType);
565
566             if (list.hasMoreElements()) {
567                 pel = (Element) list.nextElement();
568             }
569         }
570         Advertisement adv = AdvertisementFactory.newAdvertisement((TextElement) pel);
571
572         return adv;
573     }
574
575     /**
576      *  Description of the Class
577      */
578     private class ModuleDesc {
579
580         /**
581          *  Description of the Field
582          */
583         protected Module module = null;
584         private boolean started = false;
585         private boolean stopped = true;
586
587         /**
588          *Constructor for the ModuleDesc object
589          *
590          * @param  module  Description of the Parameter
591          */
592         public ModuleDesc(Module module) {
593             this.module = module;
594         }
595
596         /**
597          *  Description of the Method
598          *
599          * @param  args  Description of the Parameter
600          */
601         public void startApp(String[] args) {
602             if (module == null) {
603                 return;
604             }
605             if (started) {
606                 // Already started - nothing to do
607                 return;
608             }
609             module.startApp(args);
610             started = true;
611             stopped = false;
612         }
613
614         /**
615          *  Description of the Method
616          */
617         public void stopApp() {
618             if (module == null) {
619                 return;
620             }
621             if (stopped) {
622                 // Already stopped - nothing to do
623                 return;
624             }
625             module.stopApp();
626             stopped = true;
627             started = false;
628         }
629     }
630
631
632     /**
633      * ModuleManagerLoader interface.
634      * This interface is used by the application in order to provide its own
635      * class loader instead of using the standard PeerGroup loader.
636      */
637
638     public interface ModuleManagerLoader {
639
640         /**
641          * This method is invoked by the ModuleManager when it is time to load
642          * the class associated to the module. The name of the module is provided,
643          * which allows the application provided loader to be able to load a variety
644          * of modules, if that is necessary for the application. Note that the ModuleManager
645          * assumes that the module which is loaded by the provided loader is not started:
646          * loading and starting a module are two different operations for the ModuleManager.
647          *
648          * @param  moduleName  is the symbolic name of the Module.
649          * @return             Module the object that has been loaded.
650          */
651         public Module loadModule(String moduleName);
652     }
653
654 }
655