9 Replies Latest reply on Jan 30, 2002 11:40 PM by vincent

    Configuration Information Best Practice

    hunterhillegas

      What is the best way to manage configuration information for your EJBs?

      I mean stuff that isn't in the deployment descriptor... Paths, URLs, etc...

      What are you people doing to manage this stuff?

        • 1. Re: Configuration Information Best Practice
          supertbone

          i mostly use the env-entry tags in the deployment description, if the extra config is to complicated for an entry then i use resources(ClassLoading mechanism) with a property or xml file.

          But there isn't any pattern shows how this should be done.(except for the resource loading by the classloader)

          Greetz Tbone,

          • 2. Re: Configuration Information Best Practice
            alu1344

            Mine could not be the best config in the world, I have rewritten it fully at least three times.

            I have encapsulated in one class (singleton) all the env-entry variables. At construction time it reads everything. The drawback is that you then have to specify these variables in web.xml, not in ejb-jar.xml (since the config variables are common to all the app). The reason is because I use these variables *very* often and performance was suffering.

            I also use two ResourceBundles, since I need to keep some client i18n messages.

            Whenever you need to specify a text string more than once in the code, I specify it as a static final public in the Config class. I am talking about the name of everything that gets referenced via JNDI or via a ResourceBundle, or in a HttpSession.

            For URLs I use an ad hoc Factory. Could not be the best approach in the world, but it happens that I haven't found anything better.

            With this approach I know I could keep things in the Database. I have moved config info from static code to the JNDI without consecuences in the rest of the app.

            • 3. Re: Configuration Information Best Practice
              sikandar

              What about plain vanilla window's ini file/registry concept?

              I load config name-value parameters from properties file at load time. This way I can change them at production m/c without recompiling code.

              • 4. Re: Configuration Information Best Practice
                foglesa

                I have been on contracts where it is done in basically one of two ways. One which i hate, and the other fairly common. so the one i hate? A static class. Its not bad if things do not change much, but you have locked the client into needing to recompile if anything changes.

                the other one is just a plain old properties file. Works great, can be edited by anyone almost, it is very system admin friendly :)

                Al

                • 5. Re: Configuration Information Best Practice
                  fcrabus

                  > I have been on contracts where it is done in
                  > basically one of two ways. One which i hate, and the
                  > other fairly common. so the one i hate? A static
                  > class. Its not bad if things do not change much, but
                  > you have locked the client into needing to recompile
                  > if anything changes.
                  >
                  > the other one is just a plain old properties file.
                  > Works great, can be edited by anyone almost, it is
                  > very system admin friendly :)
                  >
                  > Al

                  But with your plain ol' properties file you'll get some
                  problems - at least later on.
                  - In a cluster you have to update all files.
                  - You have to put it somewhere in the filesystem which
                  can be a pain in the ass or you have to package it
                  along with your jars (which is basically very nice, but
                  it's somewhat cumbersome to edit it then).
                  - If you need those properties often then you need to
                  cache them (so typically you have a singleton along
                  with your properties file which will be a problem in
                  cluster of course)
                  - loads of other problems (I've had my share of experience there)

                  So a better thing to do is to put your properties in
                  a db. Then you'll add an accessor class with some
                  built-in caching and store it in JNDI.
                  Or as a compromise you store you're properties dynamically into JNDI:
                  Let's say on startup a properties file is read, its
                  values are stored in JNDI. And later on you can change
                  those values via a servlet and a web front end.

                  But there're for sure other better solutions...any
                  ideas?

                  Bye,
                  Fabian

                  • 6. Re: Configuration Information Best Practice
                    kryptontri

                    Just a simple question to all you heavies ..

                    Assuming I build an application that requires regular config updating, what would be the best way without restarting the server/services ?

                    1. From the web container, write a utility class to continually check a given config file for date changes and then reload when the file has been changed. This obviously involves IO or using xml files - still IO ?

                    2. Within the EJB Container do the same. But am i allowed to do this ie call IO to monitor a file via a helper class ? Surely if this util is not an EJB so this should be ok ?

                    Any thoughts would be appreciated.

                    • 7. Re: Configuration Information Best Practice
                      vincent

                      JMX anybody ?
                      The EJB/WEB talks to a JMX to get sth.
                      This JMX can be "stop/start" or "reload" to get a new version of a xml file or any "string like" parameter.
                      Or attach to a Timer to reload itself dynamically.
                      JMX JMX JMX ouh ah...

                      • 8. Re: Configuration Information Best Practice
                        sleepycrom

                        Do you have some nice samples that do all this ?
                        - How do this work in cluster ? Do you have to you the RMI Connector ?

                        • 9. Re: Configuration Information Best Practice
                          vincent

                          Writing a MBean is a lot more simple than writing a EJB ;)
                          Simply write a class and its MBean interface and it starts. Look at ... all Jboss to find example.
                          I don't use cluster and don't know exactly how to handle this problem in JMX. (BTW is the marc/juha book on JMX out ?). For the moment I would simply deploy my MBean in all the servers I am running. For example I use 2 servers at devel time on for tomcat 3.2 and one for ejb, ... Both runs the MBean.
                          I could use the RMI connector (I tries it without problems) but it is a jboss specific so I prefer not using it anymore.
                          What took me long time to catch is the fact that MBean is not just there for JBoss. It is also there for a lot of configuration issue that users face in any project. IMHO, using env definition in ejb is less and less a good option for "configuration" stuff.

                          Example :

                          public class EISIntegratorLoader
                          extends FileLoader
                          implements EISIntegratorLoaderMBean{

                          // ----------------------------------------------------------------- Logging
                          transient static Category cat=Category.getInstance(EISIntegratorLoader.class);

                          private String fileName;
                          private boolean started;
                          private Map mapping = new Hashtable();

                          public String getName(){
                          if (cat.isDebugEnabled()) cat.debug("getName()");
                          return "SecureActionLoader";
                          }

                          public String getConfigFile(){
                          if (cat.isDebugEnabled()) cat.debug("getConfigFile()");
                          return fileName;
                          }

                          public void setConfigFile(String fileName)
                          throws FileNotFoundException{
                          if (cat.isDebugEnabled()) cat.debug("setConfigFile("+fileName+")");
                          this.fileName = fileName;
                          Document doc = extractDoc(findFile(fileName));
                          List list = doc.getRootElement().getChildren("mapping");
                          //List list = doc.getMixedContent();
                          if (cat.isDebugEnabled()) cat.debug("MAPPING Number = "+list.size());
                          Iterator i = list.iterator();
                          while (i.hasNext()){
                          Element el = (Element)i.next();
                          String source = el.getChildText("source");
                          String destination = el.getChildText("destination");
                          if (!mapping.containsKey(source)){
                          mapping.put(source,destination);
                          if (cat.isDebugEnabled()) cat.debug("MAPPING : "+source+" ==> "+destination);
                          }
                          }
                          }

                          public Map getMapping(){
                          if (cat.isDebugEnabled()) cat.debug("getMapping");
                          return this.mapping;
                          }

                          public void start() throws Exception{
                          cat.info("start()");
                          started = true;
                          }

                          public void stop(){
                          cat.info("stop()");
                          started = false;
                          }

                          // ----------------------------------------------------------------- Private

                          /** This will build the Document object
                          * @param url the URL for the XML configuration file
                          * @return a {@link Document} representing the actions
                          * definition
                          */
                          private Document extractDoc(URL url){
                          if (cat.isDebugEnabled()) cat.debug("Executing extractDoc");
                          SAXBuilder builder = new SAXBuilder();
                          if (cat.isDebugEnabled()) cat.debug("Builder="+builder);
                          // build the document
                          Document doc;
                          try{
                          doc = builder.build(url);
                          if (cat.isDebugEnabled()) cat.debug("Doc="+doc);
                          } catch (Exception e){
                          cat.debug("Exception",e);
                          throw new IllegalStateException("JDOMException"+e.getMessage());
                          }
                          Document actionDoc = new Document(doc.getRootElement().getChild("mappings"));
                          return actionDoc;
                          }

                          The interface is

                          public String getConfigFile();
                          public void setConfigFile(String fileName) throws FileNotFoundException;

                          public Document getDocument();

                          public void start() throws Exception;
                          public void stop() throws Exception;


                          With FileLoader being

                          protected URL findFile(String fileName) throws IllegalStateException {
                          Class confClass = this.getClass();
                          ClassLoader loader = confClass.getClassLoader();
                          URL fileURL = loader.getResource(fileName);

                          // Was the resource found?
                          if (fileURL == null) {
                          cat.error("Can't find the file: '" + fileName + "'");
                          throw new IllegalStateException("Can't locate file: '" + fileName + "'");
                          }
                          else {
                          return fileURL;
                          }
                          }

                          The call is done like this (in j2ee pattern singleton ServiceLocator) :

                          private ServiceLocator() {
                          if (cat.isDebugEnabled()) cat.debug("Constructor");
                          try{
                          if (useCache) cache = new Hashtable();
                          // Get the JNDI Initial Context (local and remote)
                          initial = new InitialContext();
                          if (cat.isDebugEnabled()) cat.debug("InitialContext="+initial);
                          // Get the Deployment Description
                          ArrayList servers = MBeanServerFactory.findMBeanServer(null);
                          if (cat.isDebugEnabled()) cat.debug("List of MBean Server = " + servers);

                          if (servers == null || servers.size() == 0) {
                          // Try to connect remotely (TestSecAConfigurator will do that)
                          // Remove it for jboss 3.0 compatibility
                          //JMXConnector server = new RMIClientConnectorImpl(InetAddress.getLocalHost().getHostName());
                          //ObjectName objName = new ObjectName("HubMethods:service=EISIntegratorLoader");
                          //mapping = (Map) server.getAttribute(objName, "Mapping");
                          mapping = new FastHashMap();
                          } else {
                          try{
                          MBeanServer server = (MBeanServer) servers.get(0);
                          ObjectName objName = new ObjectName("HubMethods:service=EISIntegratorLoader");
                          mapping = (Map) server.getAttribute(objName, "Mapping");
                          }catch (Exception e){
                          cat.warn("EISIntegratorLoader MBean could not be accessed "+e.getMessage());
                          mapping = new FastHashMap();
                          }
                          }
                          if (cat.isDebugEnabled()) cat.debug("Mapping Size : "+mapping.size());

                          }catch (Exception e){
                          cat.error("Exception",e);
                          }
                          }