9 Replies Latest reply: Jan 30, 2002 11:40 PM by Vincent Harcq RSS

Configuration Information Best Practice

HunterHillegas Newbie

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
    Philip Van Bogaert Newbie

    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
    Ignacio Newbie

    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
    test Newbie

    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
    Allen Fogleson Newbie

    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
    Fabian Crabus Newbie

    > 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
    krypton Novice

    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 Harcq Newbie

    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
    Audun Wilhelmsen Newbie

    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 Harcq Newbie

    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);
    }
    }