sabato 14 gennaio 2012

Using of JNDI to configure a web application

INTRODUCTION

Often it happens that customers ask, in their requirements, for the possibility to change settings of the application on their own.

The most safe way to satisfy the request is develop an application support, dedicated only to configuration, that uses a database with this aim. But often the time in which this system can work into production environment is not compliant with the choice to develop an application support. Therefore at the end it's better to manage configuration and settings through files usage that in most cases are XML files or properties files.

To choose the most short way, we need that customer has the possibility to access to configuration files on his own for all changes desired . The only possibility is that these files aren't included into distribution file (WAR or EAR) of the application and, rather, they aren't in general at disposition in the classpath, but they are in a repository that it could be a directory, established from local systems, outside the same application server.

The JNDI technology is very well adapted to allow to web application the access to an outside resource. The aim is to show how is possible to produce a web application that reads the outside file content through JNDI using only the configuration way of the file as outside resource.

Requirement for reading is knowledge about J2EE, JNDI and all application servers treated.

APPLICATION DEVELOPMENT

First, we develop a web application that reads an outside properties file content that we bind throw JNDI in the application server and we upload through traditional lookup. The output will be an HTML page that include the list of properties in key=value format.

We choose Netbeans 7.0.1 as development enviroment. The first step is to create a new project of java class library type that we call jndi-resource-sample. We configure the project with following properties:

  • We choose Java 1.6 as java platform even if every version since 1.3 is good because JNDI is supported since this JDK version, but we advise the 1.6.
  • We add any J2EE library to compile the servlet we need. For thi aim it's good the one integrated in Netbeans called java-EE-Glassfish-v3.
  • We add a package named com.mycompany.servlet and the following servlet that we use to read the file and to print the properties list defined in it:

      package com.mycompany.servlet;
      import java.io.IOException;
      import java.io.PrintWriter;
      import java.net.URL;
      import java.util.Properties;
      import javax.naming.InitialContext;
      import javax.naming.NamingException;
      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      public class LookupServlet extends HttpServlet
      {
        private static final long serialVersionUID=4811742497268394996L;
        protected void processRequest(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException
        {
          response.setContentType("text/html;charset=UTF-8");
          PrintWriter out=response.getWriter();
          try
          {
            InitialContext ctx=new InitialContext();
            URL url=(URL)ctx.lookup("url/properties");
            Properties p=new Properties();
            p.load(url.openStream());
            out.println("<html><body>");
            for (String s:p.stringPropertyNames())
              out.println("<p>"+s+"="+p.getProperty(s)+"</p>");
            out.println("</body></html>");
          }
          catch (NamingException x)
          {
            x.printStackTrace(out);
          }
          finally
          {
            out.close();
          }
        }
        @Override
        protected void doGet(HttpServletRequest request,HttpServletResponse response)
            throws ServletException,IOException
        {
          processRequest(request,response);
        }
        @Override
        protected void doPost(HttpServletRequest request,HttpServletResponse response)
            throws ServletException,IOException
        {
          processRequest(request,response);
        }
        @Override
        public String getServletInfo()
        {
          return "JNDI ObjectFactory lookup sample";
        }
      }

    The project that includes this servlet will be used to link it in various projects that we will create to be deployed in the application servers treated.
    DEPLOY ON JBOSS
    Let's take as reference JBOSS 5.1, that we guess installed with all right rules and configured ad application server inside Netbeans, however the procedure worth for all JBOSS' versions since the 4'th. Let's create a project of Web Application Type named jndi-resource-jboss-sample. We configure the project with the following properties:
  • we choose Java 1.6 as Java Platform
    • We choose Jboss 5.1 as Application Server that we assume installed and configured inside Netbeans
      • We link the project jndi-resource-sample to current project
        • We handle the file web.xml as it follows:
          <?xml version="1.0" encoding="UTF-8"?>
          <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
              <servlet>
                  <servlet-name>LookupServlet</servlet-name>
                  <servlet-class>com.mycompany.servlet.LookupServlet</servlet-class>
              </servlet>
              <servlet-mapping>
                  <servlet-name>LookupServlet</servlet-name>
                  <url-pattern>/LookupServlet</url-pattern>
              </servlet-mapping>
              <session-config>
                  <session-timeout>30</session-timeout>
              </session-config>
              <welcome-file-list>
                  <welcome-file>LookupServlet</welcome-file>
              </welcome-file-list>
              <resource-ref>
                 <res-ref-name>url/properties</res-ref-name> 
                 <res-type>java.net.URL</res-type>
                 <res-auth>Container</res-auth>
                 <res-sharing-scope>Shareable</res-sharing-scope>
              </resource-ref>
          </web-app>
        • In the folder WEB-INF/lib we create a file named jboss-web.xml with the function of deployment descriptor for JBOSS application server. We need this file to map the configured resource of URL type configured in web.xml called url/properties with JNDI name in which we identify within JBOSS our properties file:
            <?xml version="1.0" encoding="UTF-8"?>
            <jboss-web>
                <context-root>/jndi-resource-jboss-sample</context-root>
                <resource-env-ref>
                    <resource-env-ref-name>url/properties</resource-env-ref-name>
                    <jndi-name>url/properties</jndi-name>
                </resource-env-ref>
            </jboss-web>

          The content of this file specifies that url/properties resource is the reference of the same JNDI name. It isn't necessary that the reference and the JNDI name are identical: we can use the same name only for convenience because in this way we need to remember only one.
          At this point we can compile the web project to get our distribution file called jndi-resource-jboss-sample.war that we arrange to deploy into Jboss, and we can do this simply copying the file from the directory %PRJ_ROOT%/dist of the project into the directory %JBOSS_HOME%/server/default/deploy.
          The last issue that remains to do before the restart of the server and opening the home page of the application is to define the bind of properties file the application has to read in the JNDI tree. This can be done creating a file that under JBOSS standard specification must have the suffix -service.html. We will call it jndi-resource-jboss-sample-service.html. We will save it, as the WAR file, in the directory %JBOSS_HOME%/server/default/deploy and his content wil be the following: 



              <server>
                <mbean code="org.jboss.naming.JNDIBindingServiceMgr" name="jboss.tests:name=prova">
                  <attribute name="BindingsConfig" serialDataType="jbxb">
                    <jndi:bindings xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xmlns:jndi="urn:jboss:jndi-binding-service:1.0"
                        xs:schemaLocation="urn:jboss:jndi-binding-service\resource:jndi-binding-service_1_0.xsd">
                      <jndi:binding name="url/properties">
                      </jndi:binding>
                    </jndi:bindings>
                  </attribute>
                </mbean>
                      </server>
          The content of this file specifies that in the JNDI tree we have done the binding of our properties file assigning to it the name url/properties. The deployment descriptor tell us that this name has been mapped on a resource that has got the reference with the same name and that it has been configured in the web.xml file.
          Now our application is correctly installed and configured in JBOSS, so we can start the server and execute it on the browser. It's obvious that the described procedure allows to the user to change application configuration without the execution of a new deploy. Infact it's anough to access to the properties file in the file system and restart JBOSS. If we change the name of the file it's enough to change URL in jndi-resource-jboss-sample-service.xml and restart JBOSS. The restarting of the server is an issue that customer can manage on their own.
          DEPLOY ON GLASSFISH


          Let's take as reference Glassfish 3.1.1 even if the procedure is valid with all versions from 3.0 onwards. The procedure is simpler with Glassfish then Jboss because Glassfish doesn't need any deployment descriptor to define and link JNDI resource: it's enough to go to administrator's console. Therefore we can reuse the WAR file generated from Jboss and deploy it such as it is on Glassfish. The presence within WAR file of the Jboss deployment descriptor is irrelevant because Glassfish ignores it during deployment's operation.

          To configure the JNDI resource let's proceed as it follows:
        • In menu on the left of administrator's console select the voice Risorse/JNDI/Risorse personalizzate (italian version)

        • In Risorse Personalizzate Panel click on Nuovo Button:

        In Nuova Risorsa Panel indicate:
        • In the field JNDI Name the value url/properties, that coincides with we have specified in web.xml file of the application:
        • In the field Resource Type the class java.net.URL
        • In the field Factory Class leave as indicated


        In the same panel click on Add property Button and in the additional properties table let's specify:


        • At the end click on OK button on the top and on the right side of the panel.
        As an altrernative to the graphic process illustrated we can intervene manually in the domain.xml file to insert following tag:
          <custom-resource res-type="java.net.URL" jndi-name="url/properties"
          </custom-resource>
        At this point we have finished and after have resterted application we are ready for use.

        Nessun commento:

        Posta un commento