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.

        domenica 1 gennaio 2012

        Create Web Services with netbeans7.0 and Glassfish 3.1

        In this example I use:

        - netbeans 7.0: http://netbeans.org/downloads/index.html
        - glassfish3.1: http://netbeans.org/downloads/index.html
        - postgresSQL 8.3: http://www.enterprisedb.com/products-services-training/pgdownload#windows
        - pgAdminIII: http://www.enterprisedb.com/products-services-training/pgdownload#windows

        Let's consider a very simple real example of a library where we define a basic model to describe the reality. There are three entities:

        - author
        - book
        - reader

        with these relations:

        - an author write many books
        - a book has only one author
        - a book is read by many readers
        - a reader read many books

        so we can describe these relation as:

        - author-book: one-to-many
        - book-reader: many-to-many

        With these rules we can  write our database:

        create table author
        (
        id bigint not null,
        cod_author varchar(10) not null,
        des_author varchar(100) not null
        );

        create table book
        (
        id bigint not null,
        cod_book varchar(10) not null,
        des_title varchar(100) not null,
        id_author bigint not null
        );

        create table reader
        (
        id bigint not null,
        cod_reader varchar(10) not null,
        des_reader varchar(100) not null
        );

        create table reader_book_ref
        (
        id_reader bigint not null,
        id_book bigint not null
        );


        alter table author add primary key(id);
        alter table book add primary key(id);
        alter table reader add primary key(id);
        alter table reader_book_ref add primary key(id_reader, id_book);

        create unique index idx_author_cod_author on author(cod_author);
        create unique index idx_book_cod_book on book(cod_book);
        create unique index idx_reader_cod_reader on reader(cod_reader);

        alter table book add foreign key(id_author) references author(id);
        alter table reader_book_ref add foreign key(id_reader) references reader(id);
        alter table reader_book_ref add foreign key(id_book) references book(id);

        Now follow these steps:

        First Step: open pgAdminIII and connect PostgresSQL server. Then right click on Database voice of the menu and create new database called libdb. Right click on db libdb and click on "CREATE code". Put script listed above on the window and execute to build our database libdb.

        Second Step: create an empty folder BiblioProject, the open netbeans IDE and click file --> New project --> JavaEE --> Enterprise Application and fill the field of the wizard as it follows:


        click next and confirm the build of ejb module and Web App Module as follows:


        and click finish.

        Click on the tab services, open Database-->Divers, if you don't have Postgres Driver right click on Drivers and add new Driver as follows:


        Now add connection to libdb: right click on databases and add new Connection typing information as follows: 



        Test connection to verify that is all correct.

        Now turn back on the tab Projects, click on EABlio-ejb module--> new --> entity classes from database --> select data source --> add new data source:

        add all tables in the available tables window on selected tables windows:



        and click next. in the following window type the package where insert the classes generated com.entities:


        Click finish and you can see that Netbeans generate for you all entity classes of your database. In this  case in com.entities we have insert the classes Author.java, Book.java, Reader.java that include jpa annotation.

        Now right click on EABiblio-ejb module and click on "New Session Bean from Entity" and add all entity classes from Available Entity classes list to Selected Entity classes list:



        click next, then replace package name with com.session and check local:


        When you click on finish button Netbeans generate for you alla facade netbeans that will be the interface to your database.

        At the end you can create a web service that allows you insert, update or extract data from database libdb. Right click on EABliblio-ejb module and click on "New Web Service" --> type WSAuthor as name of the web service, ws.author as package and check option "Create Web Service from Existing session bean" and browse for select the Session Bean AuthorFacade:



        Follow the same step to create WSBook and WSReader. Now you have created Web Service!

        To test the execution of the web service right click on EABiblio Application and click on deploy: glssfish server will be started and the application will be deployed on it. At this point you can go to tab Services, open voice servers on the tree and see that glasfish is started and it contains EABiblio applications  and WSBook, WSAuthor and WSReader services.

        Turn back to tab projects and open voice Web Service on the tree of the EABiblio-ejb module, right click on WSAuthor and will be opened the browser with address http://localhost:8080/WSAuthor/WSAuthor?Tester, if yuo replace WSDL instead of Tester at the end of the address, you can see the wsdl generated. If you put Tester again:




         you can click for example on findAll() button and see the SOAP Response:







        lunedì 26 dicembre 2011

        Create a Web Service with JAX-WS, Eclipse, Maven2 and deploy on Tomcat or Jetty

        We create a web service in these steps:

        1 - create Web service endpoint interface
        2 - create Web service endpoint that implements interface
        3 - publish Web Service with Endpoint publisher
        4 - create Client for Web Service generated with wsimport command
        5 - create Web Project with Maven2
        6 - generate web service classes with wsgen command
        7 - configure web service on web.xml and sun-jaxws.xml files
        8 - create war file with Maven2
        9 - deploy on jetty server (with Maven2) and also on Tomcat

        For this example I have downloaded:
        - Eclipse Indigo: http://www.eclipse.org/downloads/
        - Tomcat7: http://tomcat.apache.org/download-70.cgi
        - jdk7: http://www.oracle.com/technetwork/java/javase/downloads/index.html
        - Maven 3.0.3: http://maven.apache.org/download.html

        1 - create Web service endpoint interface:

        open eclipse --> create new Java Project named JAX-WS and the endpoint web service interface below:


        package com.myapp;


        import javax.jws.WebService;
        import javax.jws.WebMethod;


        @WebService
        public interface MyService 
        {
        @WebMethod
        String getMessage(String name);
        }


        2 - Now we create the endpoint implementation of the interface:


        package com.myapp;


        import javax.jws.WebService;


        @WebService(endpointInterface = "com.myapp.MyService")
        public class MyServiceImpl implements MyService
        {
        @Override
        public String getMessage(String yourName)
        {
        return "Hello " + yourName + " this is your first web service in JAX-WS";
        }
        }



        3 - Now we publish the web service using the static method of the Endpoint class, creating and running the Main class below:

        package com.publisher;

        import javax.xml.ws.Endpoint;

        import com.myapp.MyServiceImpl;

        public class PublisherMain 
        {

        public static void main(String[] args)
        {
        Endpoint.publish("http://localhost:8080/WS/MyService", new MyServiceImpl());
        }
        }


        After running the PublisherMain class we can put the address http://localhost:8080/WS/MyService?wsdl on address bar of the browser and see the wsdl file generated.

        4 - Create the client:

        Create a new Java Project named JAX-WS Client, open prompt and go into src folder in JAX-WS Client project, then put this command:

        wsimport –s . http://localhost:8080/WS/MyService?wsdl


        In this way you have generated all client classes. At the end you can create the java Main class to call  the service below:


        package com.client;


        import com.myapp.MyService;
        import com.myapp.MyServiceImplService;


        public class MyServiceClient {


        public static void main(String[] args)
        {
        MyServiceImplService myService = new MyServiceImplService();
        MyService service = myService.getMyServiceImplPort();
        System.out.println(service.getMessage("Christian"));
        }
        }

        Running the client class above we can see the message printed on console.

        5 - We create Web project using Maven. After installing maven we set environment variabile M2_HOME on installation folder of Maven and link path variable on bin folder of %M2_HOME% folder.

        After step above we can create project folder, for example MyWebProject, and in the prompt we can go in this folder and put this command:

        mvn archetype:create -DgroupId=com.myapp -DartifactId=MyWebProject -DarchetypeArtifactId=maven-archetype-webapp.





        If you want build project in the command line go to MyWebProject folder and type this command:

        mvn clean package 

        This will generate a folder named target  under MyWebProject folder and inside it the file MyWebProject.war.


        But let's insert our service into the web project MyWebProject:

        go into MyWebProject and create under src/main the folders /java/com/myapp. In this folder put MyService.java and MyServiceImpl.java implemented above.

        Now open file pom.xml under MyWebProject folder and into the tag <build> insert the following two plugins:

        - plugin to compile project
        - plugin to build project on server jetty

          <build>
            <finalName>MyProject-webapp</finalName>
                 <plugins>
                   <plugin>
                      <groupId>org.apache.maven.plugins</groupId>
                      <artifactId>maven-compiler-plugin</artifactId>
                      <configuration>
                           <source>1.5</source>
                           <target>1.5</target>
                      </configuration>
                   </plugin>
                     <plugin>
                          <groupId>org.mortbay.jetty</groupId>
                          <artifactId>maven-jetty-plugin</artifactId>
                     </plugin>
                 </plugins>
        </build>


        Now you can build the project going under MyWebProject folder through  the command line and typing this command: mvn install 

        With the command above appear target folder under MyWebProject folder and under target folder ther is MyWebProject.war and also the file .classes under folder target/classes/com/myapp.

        Now you have to generate web service classes with this command under MyWebProject folder:

        wsgen -s src -d target/classes -cp build/classes com.myapp.MyServiceImpl

        the command above generates com.myapp.jaxws package under MyWebProject/src folder and the classes GetMessage.java and GetMessageResponse.java.

        Open web.xml and configure Web Service as Listner and servlet:

         <?xml version="1.0" encoding="UTF-8"?>
        <web-app xmlns="http://java.sun.com/xml/ns/j2ee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
        http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
        version="2.4">
        <listener>
        <listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
        </listener>
        <servlet>
        <servlet-name>MyServiceWS</servlet-name>
        <servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
        </servlet>
        <servlet-mapping>
        <servlet-name>MyServiceWS</servlet-name>
        <url-pattern>/myservice</url-pattern>
        </servlet-mapping>
        </web-app>

        Then create under webapp/WEB-INF the file sun-jaxws like this:


        <?xml version="1.0" encoding="UTF-8"?>
        <endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime" version="2.0">
        <endpoint name="MyServiceWS"
         implementation="com.myapp.MyServiceImpl"
         url-pattern="/myservice"/>
        </endpoints>

        At the end you have to put into webapp/WEB-INF/lib all libreries needed for JAX-WS that are all these:

        activation.jar
        FastInfoset.jar
        http.jar
        jaxb-api.jar
        jaxb-impl.jar
        jaxb-rpc.jar
        jaxws-api.jar
        jaxws-rt.jar
        jaxws-tools.jar
        jsr173_api.jar
        jsr181-api.jar
        jsr250-api.jar
        resolver.jar
        saaj-api.jar
        saaj-impl.jar
        sjsxp.jar
        stax-ex.jar
        streambuffer.jar

        At this point you can build application with "mvn install" command (another way to build project without plugin is with command "mvn clean package" in the root folder of MyWebProject) and then you can deploy the project on server Jetty with this command: mvn jetty:run


        then you can open browser and put this address in the address bar:

        http://localhost:8080/MyWebProject/myservice?wsdl

        and view the wsdl.

        At the end close server jetty with ctrl+C on prompt and let's deploy on tomcat: in the command line reach the bin folder under installation folder of tomcat. For Example: cd apache-tomcat-7.0.23 --> cd bin. Then type the command startup to start Tomcat. Now you can open browser and type this address: http://localhost:8080/manager. At this point tomcat manager will ask you login and password to access and they are configureable on file conf/tomcat-users.xml and you have to configure somthing like this:


        <tomcat-users>  
          <role rolename="manager-gui"/>
          <user username="admin" password="admin" roles="manager-gui"/>
        </tomcat-users>



        After this is done you can access to Tomcat manager with login admin and password admin.

        Under the list of application you can see that there is the possibility to choose the war file to deploy. We choose MyWebProject.war and deploy it. Now type the address

        http://localhost:8080/MyWebProject/myservice?wsdl

        on the address bar of the browser and you will see the wsdl.