jdk/test/javax/management/namespace/JMXNamespaceViewTest.java
changeset 4159 9e3aae7675f1
parent 4158 0b4d21bc8b5c
parent 4156 acaa49a2768a
child 4160 bda0a85afcb7
equal deleted inserted replaced
4158:0b4d21bc8b5c 4159:9e3aae7675f1
     1 /*
       
     2  * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    20  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    21  * have any questions.
       
    22  */
       
    23 /*
       
    24  *
       
    25  * @test JMXNamespaceViewTest.java
       
    26  * @summary Test the JMXNamespaceView class.
       
    27  * @bug 5072476
       
    28  * @author Daniel Fuchs
       
    29  * @run clean JMXNamespaceViewTest Wombat WombatMBean
       
    30  * @run build JMXNamespaceViewTest Wombat WombatMBean
       
    31  * @run main JMXNamespaceViewTest
       
    32  */
       
    33 
       
    34 
       
    35 import java.lang.management.ManagementFactory;
       
    36 import java.net.ServerSocket;
       
    37 import java.rmi.registry.LocateRegistry;
       
    38 import java.util.ArrayList;
       
    39 import java.util.Arrays;
       
    40 import java.util.HashMap;
       
    41 import java.util.HashSet;
       
    42 import java.util.List;
       
    43 import java.util.Map;
       
    44 import java.util.Set;
       
    45 import javax.management.ClientContext;
       
    46 import javax.management.JMException;
       
    47 import javax.management.MBeanRegistration;
       
    48 import javax.management.MBeanServer;
       
    49 import javax.management.MBeanServerFactory;
       
    50 import javax.management.ObjectInstance;
       
    51 import javax.management.ObjectName;
       
    52 import javax.management.namespace.JMXNamespace;
       
    53 import javax.management.namespace.JMXNamespaceView;
       
    54 import javax.management.namespace.JMXNamespaces;
       
    55 import javax.management.namespace.JMXRemoteNamespace;
       
    56 import javax.management.remote.JMXConnectorServer;
       
    57 import javax.management.remote.JMXConnectorServerFactory;
       
    58 import javax.management.remote.JMXServiceURL;
       
    59 
       
    60 /**
       
    61  * A simple test to test the JMXNamespaceViewTest...
       
    62  * @author dfuchs
       
    63  */
       
    64 public class JMXNamespaceViewTest {
       
    65 
       
    66     /**
       
    67      * Describe the configuration of a namespace
       
    68      */
       
    69     public static class NamespaceConfig {
       
    70         /** name of the namespace - no // allowed **/
       
    71         public String name;
       
    72         /**
       
    73          * JMXServiceURL through which the namespace is exported, if it
       
    74          * is a remote namespace. {@code null} if the namespace is local.
       
    75          * This is an inpur URL - eg: new JMXServiceURL("rmi",null,0).toString()
       
    76          * is acceptable here.
       
    77          */
       
    78         public String jmxurl;
       
    79         /**
       
    80          * Values of the name= key for each WombatMBean contained in the
       
    81          * namespace.
       
    82          */
       
    83         public String[] wombats;
       
    84         /** list of child namespace **/
       
    85         public NamespaceConfig[] children;
       
    86     }
       
    87 
       
    88     /**
       
    89      * Creates a NamespaceConfig record for a local namespace.
       
    90      * @param name     name  of the namespace
       
    91      * @param wombats  names of WombatMBean it should contain.
       
    92      * @return a NamespaceConfig.
       
    93      */
       
    94     public static NamespaceConfig config(String name, String[] wombats) {
       
    95         return config(name,null,wombats);
       
    96     }
       
    97 
       
    98     /**
       
    99      * Creates a NamespaceConfig record for a remote namespace.
       
   100      * @param name    name  of the namespace
       
   101      * @param jmxurl  input JMXServiceURL for creating the JMXConnectorServer
       
   102      * @param wombats names of WombatMBean it should contain.
       
   103      * @return a NamespaceConfig.
       
   104      */
       
   105     public static NamespaceConfig config(String name, String jmxurl,
       
   106             String[] wombats) {
       
   107         return config(name,jmxurl,wombats,(NamespaceConfig[])null);
       
   108     }
       
   109 
       
   110     /**
       
   111      * Creates a NamespaceConfig record for a local namespace.
       
   112      * @param name     name  of the namespace
       
   113      * @param wombats  names of WombatMBean it should contain.
       
   114      * @param children list  of sub namespaces.
       
   115      * @return a NamespaceConfig.
       
   116      */
       
   117     public static NamespaceConfig config(String name, String[] wombats,
       
   118             NamespaceConfig... children) {
       
   119         return config(name,null,wombats,children);
       
   120     }
       
   121 
       
   122     /**
       
   123      * Creates a NamespaceConfig record for a remote namespace.
       
   124      * @param name    name  of the namespace
       
   125      * @param jmxurl  input JMXServiceURL for creating the JMXConnectorServer
       
   126      * @param wombats names of WombatMBean it should contain.
       
   127      * @param children list  of sub namespaces.
       
   128      * @return a NamespaceConfig.
       
   129      */
       
   130     static NamespaceConfig config(String name, String jmxurl, String[] wombats,
       
   131             NamespaceConfig... children) {
       
   132          final NamespaceConfig cfg = new NamespaceConfig();
       
   133          cfg.name=name; cfg.jmxurl=jmxurl; cfg.wombats=wombats;
       
   134          cfg.children=children;
       
   135          return cfg;
       
   136     }
       
   137 
       
   138     /**
       
   139      * Returns the given names. This is a utility method to ease code
       
   140      * reading.
       
   141      * @param names names of Wombat MBeans.
       
   142      * @return the given names.
       
   143      */
       
   144     static String[] wombats(String... names) {
       
   145         return names;
       
   146     }
       
   147 
       
   148     /**
       
   149      * Creates a JMXServiceURL string for the given protocol.
       
   150      * This is also a utility method to ease code reading.
       
   151      * @param protocol The protocol name (e.g. "rmi")
       
   152      * @return A JMXServiceURL string.
       
   153      * @throws Exception if creation of the JMXServiceURL fails.
       
   154      */
       
   155     static String url(String protocol) throws Exception {
       
   156         return new JMXServiceURL(protocol,null,0).toString();
       
   157     }
       
   158 
       
   159     /**
       
   160      * Creates a config for a hierarchy of namespaces, mixing local namespaces
       
   161      * and remote namespaces using the given protocol.
       
   162      * @param protocol The protocol that should be used for remote namespaces.
       
   163      * @return A namespace config hierarchy.
       
   164      * @throws java.lang.Exception
       
   165      */
       
   166     public static NamespaceConfig[] makeConfig(String protocol)
       
   167         throws Exception {
       
   168         final NamespaceConfig[] config = {
       
   169         // Top level namespace "top1" (local)
       
   170         config("top1",wombats("wchief","w1","w2","w3"),
       
   171                 // top1//local1
       
   172                 config("local1",wombats("wchief","ww1","ww2")),
       
   173                 // top1//local2
       
   174                 config("local2",wombats("wchief","ww4","ww5","ww6"),
       
   175                     // top1//local2//local3
       
   176                     config("local3",wombats("wchief","www1","www2")),
       
   177                     // top1//local2//rmi1
       
   178                     config("rmi1",url(protocol),wombats("wchief","www3","www4","www5"))),
       
   179                 // top1//rmi2
       
   180                 config("rmi2",url(protocol),wombats("wchief","ww7","ww8","ww9"),
       
   181                     // top1//rmi2//local4
       
   182                     config("local4",wombats("wchief","www6","www7")),
       
   183                     // top1//rmi2//rmi3
       
   184                     config("rmi3",url(protocol),wombats("wchief","www3","www4","www5"),
       
   185                         // top1//rmi2//rmi3//local5
       
   186                         config("local5",wombats("wchief","wwww1"))))),
       
   187         // Top level namespace "top2" (local)
       
   188         config("top2",wombats("wchief","w21","w22","w23"),
       
   189                 // top2//local21
       
   190                 config("local21",wombats("wchief","ww21","ww22")),
       
   191                 // top2//rmi22
       
   192                 config("rmi22",url(protocol),wombats("wchief","ww27","ww28","ww29"),
       
   193                     // top2//rmi22//local24
       
   194                     config("local24",wombats("wchief","www26","www27")),
       
   195                     // top2//rmi22//rmi23
       
   196                     config("rmi23",url(protocol),wombats("wchief","www23","www24","www25"),
       
   197                         // top2//rmi22//rmi23//local25
       
   198                         config("local25",wombats("wchief","wwww21"))))),
       
   199         // Top level namespace "top3" (remote)
       
   200         config("top3",url(protocol),wombats("wchief","w31","w32","w33"),
       
   201                 // top3//local31
       
   202                 config("local31",wombats("wchief","ww31","ww32")),
       
   203                 // top3//rmi32
       
   204                 config("rmi32",url(protocol),wombats("wchief","ww37","ww38","ww39"),
       
   205                     // top3//rmi32//local34
       
   206                     config("local34",wombats("wchief","www36","www37")),
       
   207                     // top3//rmi32//rmi33
       
   208                     config("rmi33",url(protocol),wombats("wchief","www33","www34","www35"),
       
   209                         // top3//rmi32//local35
       
   210                         config("local35",wombats("wchief","wwww31"))))),
       
   211         };
       
   212         return config;
       
   213     }
       
   214 
       
   215     /**
       
   216      * Close all connector servers in the list.
       
   217      * @param cslist List of connector servers to close.
       
   218      */
       
   219     public static void closeAll(List<JMXConnectorServer> cslist) {
       
   220             for (JMXConnectorServer cs : cslist) {
       
   221                 try {
       
   222                     cs.stop();
       
   223                 } catch (Exception xx) {
       
   224                     System.err.println("Failed to stop connector: " + xx);
       
   225                 }
       
   226             }
       
   227     }
       
   228 
       
   229     public static class MBeanServerConfigCreator {
       
   230         public MBeanServer createMBeanServerFor(NamespaceConfig config) {
       
   231             return MBeanServerFactory.newMBeanServer();
       
   232         }
       
   233     }
       
   234 
       
   235     /**
       
   236      * Load the given namespace configuration inside the given MBeanServer.
       
   237      * Return a list of connector servers created in the process.
       
   238      * @param server      The MBeanServer in which the namespaces must
       
   239      *                    be created.
       
   240      * @param namespaces  The list of namespaces to create.
       
   241      * @return a list of started connector servers.
       
   242      * @throws java.lang.Exception failed to create the specified namespaces.
       
   243      */
       
   244     public static List<JMXConnectorServer> load(MBeanServer server,
       
   245            MBeanServerConfigCreator factory,
       
   246            NamespaceConfig... namespaces) throws Exception {
       
   247         final List<JMXConnectorServer> cslist =
       
   248                 new ArrayList<JMXConnectorServer>();
       
   249         try {
       
   250             final ObjectName creator =
       
   251                     new ObjectName("jmx.creator:type=JMXNamespaceCreator");
       
   252             if (System.getProperty("jmx.wait")!=null
       
   253                     && !server.isRegistered(creator)) {
       
   254                 server.registerMBean(new JMXNamespaceCreator(),creator);
       
   255             }
       
   256             for (NamespaceConfig cfg : namespaces) {
       
   257                 final MBeanServer srv = factory.createMBeanServerFor(cfg);
       
   258                 if (System.getProperty("jmx.wait")!=null
       
   259                     && !srv.isRegistered(creator)) {
       
   260                     srv.registerMBean(new JMXNamespaceCreator(),creator);
       
   261                 }
       
   262                 if (cfg.wombats != null) {
       
   263                     for (String w : cfg.wombats) {
       
   264                         final ObjectName n =
       
   265                                 new ObjectName("wombat:type=Wombat,name=" + w);
       
   266                         final WombatMBean ww = new Wombat();
       
   267                         srv.registerMBean(ww, n);
       
   268                     }
       
   269                 }
       
   270                 if (cfg.children != null) {
       
   271                     cslist.addAll(load(srv, factory, cfg.children));
       
   272                 }
       
   273                 JMXNamespace nm;
       
   274                 if (cfg.jmxurl == null) {
       
   275                     nm = new JMXNamespace(srv);
       
   276                 } else {
       
   277                     JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(new JMXServiceURL(cfg.jmxurl),
       
   278                             null, srv);
       
   279                     srv.registerMBean(cs,
       
   280                             new ObjectName("jmx.remote:type=JMXConnectorServer"));
       
   281                     cs.start();
       
   282                     cslist.add(cs);
       
   283                     nm = JMXRemoteNamespace.
       
   284                             newJMXRemoteNamespace(cs.getAddress(),
       
   285                             null);
       
   286                 }
       
   287                 server.registerMBean(nm,
       
   288                         JMXNamespaces.getNamespaceObjectName(cfg.name));
       
   289                 if (nm instanceof JMXRemoteNamespace) {
       
   290                     server.invoke(
       
   291                             JMXNamespaces.getNamespaceObjectName(cfg.name),
       
   292                             "connect", null, null);
       
   293                 }
       
   294             }
       
   295         } catch (Exception x) {
       
   296             closeAll(cslist);
       
   297             throw x;
       
   298         }
       
   299         return cslist;
       
   300     }
       
   301 
       
   302     /**
       
   303      * Add an entry {@code <path,NamespaceConfig>} in the map for the given
       
   304      * namespace and its subnamespaces.
       
   305      * @param map    A {@code Map<path,NamespaceConfig>}.
       
   306      * @param parent The path of the parent workspace.
       
   307      * @param cfg    The NamespaceConfig hierarchy to index in the map.
       
   308      */
       
   309     public static void fillMap(Map<String,NamespaceConfig> map, String parent,
       
   310             NamespaceConfig cfg) {
       
   311 
       
   312         final String where;
       
   313         if (parent == null || parent.equals(""))
       
   314             where=cfg.name;
       
   315         else
       
   316             where=parent+JMXNamespaces.NAMESPACE_SEPARATOR+cfg.name;
       
   317         map.put(where,cfg);
       
   318         if (cfg.children==null) return;
       
   319         for(NamespaceConfig child:cfg.children) {
       
   320             fillMap(map,where,child);
       
   321         }
       
   322     }
       
   323 
       
   324     /**
       
   325      * Compare a list of namespace names obtained from JMXNamespaceView.list()
       
   326      * with the expected clildren list of the corresponding NamespaceConfig.
       
   327      * @param list      A list of namespace names
       
   328      * @param children  A list of NamespaceConfig correspondng to expected
       
   329      *                  namespace.
       
   330      * @param fail      If true and the comparison yields false, throws an
       
   331      *                  exception instead of simply returning false.
       
   332      * @return true if OK, false if NOK.
       
   333      */
       
   334     private static boolean compare(String[] list, NamespaceConfig[] children,
       
   335             boolean fail) {
       
   336         final List<String> found = new ArrayList<String>(Arrays.asList(list));
       
   337         if (found.contains(ClientContext.NAMESPACE))
       
   338             found.remove(ClientContext.NAMESPACE);
       
   339 
       
   340         if (children == null && found.size()==0) return  true;
       
   341         if (children == null && fail == false) return false;
       
   342         if (children == null) throw new RuntimeException(
       
   343                 "No child expected. Found "+Arrays.toString(list));
       
   344         final Set<String> names = new HashSet<String>();
       
   345         for (NamespaceConfig cfg : children) {
       
   346             names.add(cfg.name);
       
   347             if (found.contains(cfg.name)) continue;
       
   348             if (!fail) return false;
       
   349             throw new RuntimeException(cfg.name+" not found in "+
       
   350                     found);
       
   351         }
       
   352         found.removeAll(names);
       
   353         if (found.size()==0) return true;
       
   354         if (fail==false) return false;
       
   355         throw new RuntimeException("found additional namespaces: "+
       
   356                 found);
       
   357     }
       
   358 
       
   359     /**
       
   360      * Compares the result of queryNames(null,null) with a set of expected
       
   361      * wombats.
       
   362      * @param where    The path of the namespace that was queried.
       
   363      * @param list     The set of ObjectNames found.
       
   364      * @param wombats  The expected list of wombats.
       
   365      * @param fail      If true and the comparison yields false, throws an
       
   366      *                  exception instead of simply returning false.
       
   367      * @return true if OK, false if NOK.
       
   368      * @throws java.lang.Exception something went wrong.
       
   369      */
       
   370     private static boolean compare(String where,
       
   371             Set<ObjectName>list, String[] wombats,
       
   372             boolean fail) throws Exception {
       
   373         final Set<ObjectName> found = new HashSet<ObjectName>();
       
   374         final Set<ObjectName> expected = new HashSet<ObjectName>();
       
   375         for (ObjectName n : list) {
       
   376             if ("Wombat".equals(n.getKeyProperty("type")))
       
   377                found.add(n);
       
   378         }
       
   379         for(String w : wombats) {
       
   380             final ObjectName n =
       
   381                     new ObjectName("wombat:type=Wombat,name=" + w);
       
   382             expected.add(n);
       
   383             if (found.contains(n)) continue;
       
   384             if (fail == false) return false;
       
   385             throw new RuntimeException(where+
       
   386                     ": Wombat "+w+" not found in "+found);
       
   387         }
       
   388         found.removeAll(expected);
       
   389         if (found.size()==0) {
       
   390             System.out.println(where+": found all expected: "+expected);
       
   391             return true;
       
   392         }
       
   393         if (fail==false) return false;
       
   394         throw new RuntimeException(where+": found additional MBeans: "+
       
   395                 found);
       
   396     }
       
   397 
       
   398     /**
       
   399      * A generic test to test JMXNamespaceView over a namespace configuration.
       
   400      * @param server      The MBeanServer in which to load the namespace
       
   401      *                    config.
       
   402      * @param namespaces  The namespace config to run the test over...
       
   403      * @throws java.lang.Exception
       
   404      */
       
   405     public static void doTest(MBeanServer server, NamespaceConfig... namespaces)
       
   406             throws Exception {
       
   407         List<JMXConnectorServer> cslist = load(server,
       
   408                 new MBeanServerConfigCreator(), namespaces);
       
   409         Map<String,NamespaceConfig> inputMap =
       
   410                 new HashMap<String,NamespaceConfig>();
       
   411 
       
   412         for (NamespaceConfig cfg : namespaces) {
       
   413             fillMap(inputMap,"",cfg);
       
   414         }
       
   415         try {
       
   416             final JMXNamespaceView root = new JMXNamespaceView(server);
       
   417             List<JMXNamespaceView> vlist = new ArrayList<JMXNamespaceView>();
       
   418             vlist.add(root);
       
   419 
       
   420             while (!vlist.isEmpty()) {
       
   421                 JMXNamespaceView v = vlist.remove(0);
       
   422                 final String where = v.isRoot()?"root":v.where();
       
   423                 System.out.println(where+": "+
       
   424                    v.getMBeanServerConnection().queryNames(null,null));
       
   425                 for (String ns : v.list()) {
       
   426                     final JMXNamespaceView down = v.down(ns);
       
   427                     vlist.add(down);
       
   428                     if (!down.where().equals(v.isRoot()?ns:where+
       
   429                             JMXNamespaces.NAMESPACE_SEPARATOR+ns)) {
       
   430                         throw new RuntimeException("path of "+down.where()+
       
   431                             " should be "+(v.isRoot()?ns:where+
       
   432                             JMXNamespaces.NAMESPACE_SEPARATOR+ns));
       
   433                     }
       
   434                     if (down.up().equals(v)) continue;
       
   435                     throw new RuntimeException("parent of "+down.where()+
       
   436                             " should be "+where);
       
   437                 }
       
   438                 final NamespaceConfig[] children;
       
   439                 final NamespaceConfig   cfg;
       
   440                 if (v.isRoot()) {
       
   441                     children=namespaces;
       
   442                     cfg = null;
       
   443                 } else {
       
   444                     cfg = inputMap.get(where);
       
   445                     children = cfg==null?null:cfg.children;
       
   446                 }
       
   447                 compare(v.list(),children,true);
       
   448                 if (!v.isRoot()) {
       
   449                     if (where.endsWith(ClientContext.NAMESPACE)) {
       
   450                         System.out.println(where+": skipping queryNames analysis");
       
   451                         continue;
       
   452                     }
       
   453                     //System.out.println(where+": cfg is: "+cfg);
       
   454                     compare(where,v.getMBeanServerConnection().
       
   455                         queryNames(null, null),cfg.wombats,true);
       
   456                 }
       
   457             }
       
   458 
       
   459             exportAndWaitIfNeeded(server);
       
   460         } finally {
       
   461             closeAll(cslist);
       
   462         }
       
   463     }
       
   464 
       
   465     public static interface JMXNamespaceCreatorMBean {
       
   466         public ObjectInstance createLocalNamespace(String namespace)
       
   467                 throws JMException ;
       
   468         public void removeLocalNamespace(String namespace)
       
   469                 throws JMException;
       
   470     }
       
   471 
       
   472     public static class JMXNamespaceCreator
       
   473             implements MBeanRegistration,
       
   474                       JMXNamespaceCreatorMBean {
       
   475 
       
   476         private volatile MBeanServer mbeanServer;
       
   477 
       
   478         public ObjectInstance createLocalNamespace(String namespace)
       
   479             throws JMException {
       
   480             return mbeanServer.registerMBean(
       
   481                     new JMXNamespace(MBeanServerFactory.newMBeanServer()),
       
   482                     JMXNamespaces.getNamespaceObjectName(namespace));
       
   483         }
       
   484 
       
   485         public void removeLocalNamespace(String namespace)
       
   486             throws JMException {
       
   487             mbeanServer.unregisterMBean(
       
   488                     JMXNamespaces.getNamespaceObjectName(namespace));
       
   489         }
       
   490 
       
   491         public ObjectName preRegister(MBeanServer server, ObjectName name)
       
   492                 throws Exception {
       
   493             mbeanServer = server;
       
   494             return name;
       
   495         }
       
   496 
       
   497         public void postRegister(Boolean registrationDone) {
       
   498         }
       
   499 
       
   500         public void preDeregister() throws Exception {
       
   501          }
       
   502 
       
   503         public void postDeregister() {
       
   504         }
       
   505 
       
   506     }
       
   507 
       
   508     public static void exportAndWaitIfNeeded(MBeanServer server)
       
   509         throws Exception {
       
   510                 if (System.getProperty("jmx.wait")!=null) {
       
   511                 final int port = getPortFor("rmi");
       
   512                 LocateRegistry.createRegistry(port);
       
   513                 final JMXServiceURL url =
       
   514                         new JMXServiceURL("rmi",null,port,
       
   515                         "/jndi/rmi://localhost:"+port+"/jmxrmi");
       
   516                 final JMXConnectorServer cs =
       
   517                         JMXConnectorServerFactory.
       
   518                         newJMXConnectorServer(url, null, server);
       
   519                 cs.start();
       
   520                 try {
       
   521                     System.out.println("RMI Server waiting at: "+cs.getAddress());
       
   522                     System.in.read();
       
   523                 } finally {
       
   524                     cs.stop();
       
   525                 }
       
   526             }
       
   527     }
       
   528 
       
   529     public static int getPortFor(String protocol) throws Exception {
       
   530         final int aport =
       
   531               Integer.valueOf(System.getProperty("jmx."+protocol+".port","0"));
       
   532         if (aport > 0) return aport;
       
   533         final ServerSocket s = new ServerSocket(0);
       
   534         try {
       
   535             final int port = s.getLocalPort();
       
   536             return port;
       
   537         } finally {
       
   538             s.close();
       
   539         }
       
   540     }
       
   541 
       
   542     public static void main(String[] args) throws Exception {
       
   543         doTest(ManagementFactory.getPlatformMBeanServer(),makeConfig("rmi"));
       
   544     }
       
   545 
       
   546 }