Monday, April 23, 2012

How to track style problems in NatJet

In NatJet style sheets can be quite tricky and you may enter an error in it.

  • If a style contains an error, the graphical element will be incorrectly displayed by the designer.
  • If the error breaks the XML syntax, no style will be applied in the designer. The panel will be displayed with no style.

Identifying the cause of the problem may be quite difficult especially in the second case.

Hopefully you can activate the log of the designer in NatJet 4. In NatJet 5, the log should already be activated.

NatJet Designer Log file

The log file can be found in the sub folder eclipse of your NatJet directory (where it has been installed). For example it could be C:\NatJet5.0.0\eclipse.

The name of the file is natjet-designer.log.

Activating log for the designer

In subfolder eclipse\plugins of your NatJet installation, you should have a folder with its name starting with fr.natsystem.natjet.graphicaldesigner_.

If you enter this subfolder, you should see a log4j.properties file. This file allows configuration of the way the graphical designer log error.

The first line maybe in NatJet 4.0 :

log4j.rootCategory=WARN, console

If you want to trace error, you should replace it by :

log4j.rootCategory=INFO, nslogFile

Then the complete log4j.properties file should be :

log4j.rootCategory=INFO, nslogFile
log4j.appender.nslogFile=org.apache.log4j.RollingFileAppender
log4j.appender.nslogFile.File = natjet-designer.log
##log4j.appender.nslogFile.FilteredLevel=INFO,ERROR,DEBUG,TRACE,FATAL
log4j.appender.nslogFile.MaxBackupIndex=20
log4j.appender.nslogFile.layout=org.apache.log4j.PatternLayout
log4j.appender.nslogFile.layout.ConversionPattern=%d{ISO8601} [%-10t] - %m%n

 
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Threshold=DEBUG
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%c %d{ISO8601} -- %p -- %m%n

Conclusion

You know how to activate log for the designer and where to look at if you get a problem.

Notice, that so far, in 3 years, I’ve only need it once, and it was on a alpha version.

Wednesday, January 4, 2012

NatJet and Database Connections pool with WebSphere 6.1

In our previous post we saw how to deploy a NatJet webapp on WebSphere 6.1. In this post, I will describe how to set an efficient database connection pool in WebSphere.

This post is oriented for NatJet but it should works for any JEE WebApp that needs to use the WebSphere database pool.

We will used a Oracle database (I won’t explain here how to install or configure the database). Notice that using a MySql database may be more difficult as IBM does not provide a out of the box connector for MySql.

We will start with a schema that summarizes the main resources and their interactions.

MappingWASDatabaseConection

In your webapp you have two files that will be impacted :

  • WEB-INF/web.xml : in this file you need to declare the jndi resource that you want to used
  • hibernate.cfg.xml : this file defines the database connection, will just reference the declared jndi resource of the web.xml

In WebSphere, the process is more tricky :

  • WebSphere stores in a central place all authentications (couples of login/password) independently of their usage
  • The WebSphere JDBC provider will link together all information necessary to establish a database connection : the type of database (important to handle correctly the connection in the pool), the connection URL (where is the database) and the credential defined previously
  • And when you will deploy your webApp into WebSphere, it will request you to map any jndi resources defined in the web.xml to one of its jndi resource (in our case a JDBC provider) : this is the mapping object of our schema)

  This means, that there will be 3 stages in our process:

  1. Development : adapt two files, hibernate.cfg.xml and web.xml, to declare and use a jndi datasource
  2. Configure Websphere : declare and configure a jndi datasource
  3. Deploy your application and map the two jndi datasources : the one defined at development stage and the one configure in websphere

Development stage

This is the tasks you need to do at development time, before delivering your NatJet WebApp.

Compare to a standard development, you just need to modify two files :

  • hibernate.cfg.xml
  • web.xml

In some case, this even won’t be necessary (if you are already using a JNDI Datasource). In this case, you should still check the web.xml file as Tomcat is not so rigorous about the definition of JNDI datasources.

Configure hibernate with hibernate.cfg.xml

NatJet automatically creates a file hibernate.cfg.xml in the src folder. This file allows us to configure hibernate.

Usually, this file contains database information to establish the connection (login, password, url…). All this information should be deleted in the case of a datasource and replace by one property : connection.datasource.

This property defines the name of the JNDI datasource we want to use. Notice, that all resources defined in the web.xml belong to the namespace java:comp/env/.

Convention is to prefix by jdbc all JDBC connections. Thus the name of our JNDI datasource will be jdbc/OracleDS and the way to access it from our application will be “java:comp/env/jdbc/OracleDS”.

We still need to indicate hibernate the dialect.

Follow a sample hibernate.cfg.xml, the line you need to add is in bold.

<?xml version="1.0" encoding="UTF-8"?>


<hibernate-configuration>
    <session-factory>      
        <property name="connection.datasource">java:comp/env/jdbc/OracleDS</property>
        <property name="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</property>

   
         
        <mapping class="fr.natsystem.demo.was.datamodel.PersonBO"/>    
         
    </session-factory>
</hibernate-configuration>

 

Defining the JNDI datasource in the web.xml

We need to add the resource in the web.xml as a resource-ref. We have to reuse the JNDI name we’ve used in hibernate.cfg.xml.

The part has been added at the end of the file : it’s in bold.

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" 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">
    <display-name>NatJetWebSphere</display-name>
    <servlet>
        <servlet-name>WebContainerSpringServletNS</servlet-name>
        <servlet-class>
            fr.natsystem.natjet.echo2.webcontainer.WebContainerSpringServletNS</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>WebContainerSpringServletNS</servlet-name>
        <url-pattern>/app</url-pattern>
    </servlet-mapping>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <listener>
        <listener-class>
            org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
    <session-config>
        <session-timeout>5</session-timeout>
    </session-config>
    <resource-ref>
      <description>DB Connection</description>
      <res-ref-name>jdbc/OracleDS</res-ref-name>
      <res-type>javax.sql.DataSource</res-type>
      <res-auth>Container</res-auth>
    </resource-ref>
   
</web-app>

Notice that we have to indicate its type : sql.Datasource

Check nsCommonContext.xml

In a NatJet WebApp, you define the way you connect the database in the nsCommonContext.xml file. This file should already be correct, nevertheless we are going to check that :

  • you are using the correct hibernate.cfg.xml file
  • you’ve optimized your webApp configuration by forcing database connection at starting time and not the first time a user connects.

Use XML editor to open nsCommonContext and find the natorb bean definition.

  • forceInitSession to true to force database connection at the beginning.
  • check that sessionResource indicate the right hibernate.cfg.xml (you can use a file with a different name than the default one, but in this case you should change the sessionResource property.

<bean id="natorb" class="fr.natsys.natorb.utils.NatOrbUtil" scope="singleton" init-method="init" destroy-method="terminate">
    <property name="forceInitSession" value="true" />
    <property name="sessionFlushMode" value="commit" />
    <property name="defaultSessionName" value="default"/>
    <property name="sessionsMap">
        <map>
            <entry key="default">
                <bean class="fr.natsys.natorb.utils.NatOrbSessionInfo">
                    <property name="sessionType" value="Hibernate"/>
                    <property name="sessionResource" value="hibernate.cfg.xml"/>
                </bean>
            </entry>
        </map>
    </property>
</bean>

 

Defining a JDBC provider in WebSphere

The following process is an administrative task in WebSphere : you may not have to do it. Your WebSphere administrator may request you to use an existing and configured datasource.

This process first defines 2 resources (oracle driver and authentication) and then links both of them to create a JNDI Datasource.

Defining Oracle driver

This is the first administrative step : you need to provide WebSphere the jdbc Oracle driver.

When prototyping a webApp, you usually include the Oracle ojdbc14.jar in the WEB-INF/lib folder of your WebApp. Thus, the jar is delivered with your WebApp.

When you want to use a datasource (and this is true for any web server as Tomcat, JBoss or WebSphere), this is the web server that establishes the database connection independently of any WebApp. Thus the driver should be available to the server even if the webApp is not deployed : it is no more possible to put the ojdbc14.jar in your WEB-INF/lib folder : Or, more exactly, this will be of no help.

To solve this problem, you should define with your WebSphere administrator where should be stored jdbc drivers for you WebSphere server. Some store the jar in ${WAS_INSTALL_ROOT}/lib. In our case we will create a folder C:\IBM\driver as we are working under Windows and WebSphere is installed under C:\IBM\WebSphere.

Copy the Oracle JDBC driver ojdbc14.jar to the directory you’ve previously selected (in our case C:\IBM\driver).

The ojdbc14.jar driver can be retrieve from your Oracle install or from Oracle website http://www.oracle.com/technetwork/database/features/jdbc/index-091264.html but if you’ve already tested your WebApp, you should already have somewhere (like WEB-INF/lib) this ojdbc14.jar file.

Notice : classe12.jar,the former Oracle driver should be considered as obsolete and replaced by a ojdbc14.jar. It is also better to upgrade your ojdbc14.jar to a version superior or equals to the one provided with Oracle 10G R2.

Define Database Authentication in WebSphere

Connect to your administrative WebSphere console : https://nomserveur:9043/ibm/console.

  • In the node "Activités guidées", select the link "Connexion à la base de données".
  • Open the node "Configuration des justificatifs pour l'accès sécurisé à une base de données"
  • On the bottom, click on the link "Cliquer pour l'exécution"

NJWA12JAAS

Then press the button “Nouveau/New” in the “JAAS – Données d’authentification J2C” panel.

In the new “JAAS – Données d’authentification J2C > Nouveau/New”

Enter the following value :

  • Alias : OracleDemo
  • ID utilisateur/login : the user login for the database. The famous default scott for Oracle Database
  • Mot de passe/Password : the user password for the database (the famous default tiger)
  • Description : Database Oracle for demo

Press button "Valider/validate" and then"Ok"

At the end of the node "Configuration des justificatifs pour l'accès sécurisé à une base de données",
there is a link "Etape suivante/Next Step". click on this link to move to the next step of the process.

Configure a JDBC Provider

When you’ve pressed on the link "Etape suivante/Next Step", a new node should have opened : "Configuration d'un fournisseur JDBC/Configure a JDBC provider”.

In this step you will define the right to use an Oracle driver from any WebApp. in WebSphere terminology, we are talking of a JDBC Provider. You need only one JDBC Provider by database type : It means one for all your Oracle 10G R2 databases. A JDBC Provider is neither link to a login/password, neither to a database URL.

Notice that if you need to define a new JDBC Provider, you will need at the end of the process to restart your WebSphere server.

Continuing, at the end of the text, there is a link "Cliquer pour l'exécution". Click on this link. A new panel “Fournisseur JDBC/JDBC provider” is displayed.

In this panel "Fournisseur JDBC/JDBC provider" :

1. select node: server1 for the field “portée/scope”
2. press button Nouveau/New

In the new panel "Créez un fournisseur JDBC/Create a new JDBC provider" input :

  • Type base de données/Database type : Oracle
  • Type de fournisseur/provider type : Oracle JDBC driver
  • Type d’implementation/Implementation type : Connection pool data source. That means we want WebSphere to manage this database pool of connections. We are doing all this fuss to use this mechanism, so pick this one.
  • Nom/Name : Oracle JDBC Driver Demo
  • Description : My Oracle JDBC provider for demo

Then press button “Suivant/Next”

At this step we need to provide the path to the JDBC driver we’ve copied before. The path will be available in the ORACLE_JDBC_DRIVER_PATH variable.

Thus in the field : “Chemin d’accès aux classes” input the value “C:/IBM/driver/ojdbc14.jar”.

Press button “Suivant/Next”, the summary of the definition is displayed.

Then press “Terminer/Terminate”. The panel “Fournisseurs JDBC/JDBC Providers” is displayed. You should see a new line “Oracle JDBC Driver Demo”. The name match the Nom/Name define in "Créez un fournisseur JDBC/Create a new JDBC provider".

At this point you’ve configured a JDBC provider : in WebSphere that means that you can use a Oracle driver. You haven’t yet configured a database connection. This is just the right to use Oracle driver.

Close the node "Configuration d'un fournisseur JDBC".

Configure a JNDI datasource

Open the next node : "Configuration d'une source de données".

At the end of the text, there is a link "Cliquer pour l'exécution". Click on this link. A new panel “Fournisseur JDBC/JDBC provider” is displayed.

In this panel "Fournisseur JDBC/JDBC provider" :

1. select node: server1 for the field “portée/scope”
2. click on the line “Oracle JDBC Driver Demo” : this matches the one you’ve just created.

The panel "Fournisseurs JDBC > Oracle JDBC Driver Demo" is displayed. You should have for the field “Chemin d'accès aux classes :” the following value : ${ORACLE_JDBC_DRIVER_PATH}/ojdbc14.jar

In the right part of the page, there is a link "Sources de données/Data source". Click on this link. A new panel : "Fournisseurs JDBC > Oracle JDBC Driver Demo > Source de données" is displayed.

Press button "Nouveau/New", and input in panel “Entrez les informations de base relatives à la source de données/Enter basic data source information” the following :

  • “Nom de la source de données/Data source name” : Oracle JDBC Driver Demo. This is just a display name
  • “Nom JNDI/JNDI name” :jdbc/OracleDS. This is the jndi name of the datasource.
  • For “Alias d'authentification géré par composant/Component-managed authentication alias and XA recovery authentication data”, select : OracleDemo. this is the value you’ve defined in chapter “database Authentication in WebSphere”.

Press button “Suivant/Next”, the step 2 is displayed. At this point you should define the URL to access your database : this should match the hibernate.connection.url property of your former hibernate.cfg.xml file.

It should be something like : jdbc:oracle:thin:@servername:1521:ORCL where servername is the name of your server or it IP address, 1521 is the port, ORCL is the Oracle database name.

Be careful not to use an URL that specifies the username and its password.

Select “Classe auxiliare au magasin de données”

And uncheck “Utiliser cette source de données dans la persistence CMP”

Press button “Suivant/Next”, the summary is displayed.

Press button “Terminer/Terminate”. The panel  "Fournisseurs JDBC/JDBC Provider > Oracle JDBC Driver Demo > Source de données/Datasource" is displayed. You should see a line with JNDI name “jdbc/OracleDS” displayed.

You can click on link “Tester la connexion/test connection” to validate the connection is working.

Now you can save your new configuration : just click on link Save/Sauvegarder on top of the page.

Restart WebSphere server

At this point, you need to restart the server. Yes, the server ! not just the WebApp. This is compulsory if you’ve just defined the JDBC Provider (the ojdbc14.jar). If you reused an existing one (A JDBC Provider) you shouldn’t have to restart the server.

Stopping a server request the administrative password in Windows.

This cannot be done from the administrative web console.

Notice that at this point, all configuration you’ve made in WebSphere are independent from your WebApp. Part of the configuration is dependent from the database but none from your WebApp. This means that you can reuse this part from one WebApp to the other as far as they use the same database.

Deployment

This is the last step of the process and it has to be done only once for each WebApp. If you redeploy the same WebApp after some bug fixing or a new version this specific part is not necessary.

To deploy a WebApp in WebSphere you need to be connected to the web admin console : https://nomserveur:9043/ibm/console.

Then you go to the node “Applications” and select “Applications d’entreprise”. If your WebApp appears in the list you need to stop it and the Update it. When you go through the process of updating at step 3, you will be required to map resources. This is the one thing you should do that is new when using a JNDI Datasource.

So you are in Step 3 “Mapper les références de ressources vers les ressources", you have a group javax.sql.Datasource displayed.

Press the button “Parcourir/Browse”. The panel "Applications d'entreprise/Entreprise application > Application d'entreprise > ressources disponibles/available resources" is displayed. A line jdbc/OracleDS should appear in the list.

Select the line “jdbc/OracleDS” and press button “Valider/Validate”.

You should go back to “javax;sql.Datasource” and in the list at the bottom, the JNDI name for the web.xml module of your application should be jdbc/OracleDS.

Above, this list, :

  1. select radio button “Utiliser la méthode par défaut/Use default method”
  2. Select in drop down list "OracleDemo". This is the credential you’ve defined before.
  3. Check the box of your line in the former list
  4. Press button “Valider/Validate”

The page is refreshed, the column configuration of the connection is updated :

  • Conteneur/Container : Méthode d’authentification/Authentication method
  • DefaultPrincipalMapping : mypcnameNode01/OracleDemo

You can process as usual for the end of the deployment.

If you deploy a new application, you should get the same step where you will be requested to define the mapping of the Database JNDI resources. This step appears every time deployment encounters a new resource defined in the web.xml of a WebApp.

Conclusion

Using the database connections pool provided by your WebSphere Server should be your preferred solution to access database. One of the main effort of high ended webserver providers as IBM, is research on optimization for efficient database pooling. It will be quite inconsistent of using WebSphere and rely on the non production hibernate pooling for database access : this is what happens when you don’t use a JNDI datasource with hibernate, you let hibernate handle the pool of connections. JBoss that provides Hibernate, does not consider this embedded pool as reliable for production.

The process may appear quite cumbersome, but it is a standard part of WepSphere administration, and your admin should provide to you,the developer, a configure JNDI datasource to access your database. In this case, you shouldn’t need to go through all this long process and focus on the development part.

Friday, December 9, 2011

WebSphere 6.1 and NatJet

In this post, I will show how to deploy a simple NatJet Web application on WebSphere 6.1.

WebSphere is the IBM web app server. Version 6.1 is the first version to rely on Java 5 which is a minimum for NatJet. WebSphere uses its own Java runtime : IBM Java runtime. It is installed when installing WebSphere.

The IBM documentation says that WebSphere 6.1 supports Servlet 2.4. The default Servlet of a NatJet 4.0 project is 2.5. I have noticed that for some projects I got an error with the default NatJet project. I’ve needed to change the web.xml to have a 2.4 declaration and then it  has worked.

When writing this post, I was not anymore on the default Websphere 6.1 : I had added two feature packs : EJB 3.0 and WebService supports (it was a 6.1.0.13). I didn’t found anything on the documentation, but it seems that the feature packs add the support of Servlet 2.5, because I haven’t had any problem when writing this tutorial with a Servlet 2.5 declaration in the web.xml. This sound quite possible because one difference between 2.4 and 2.5 is the support of annotations and this is needed for EJB and WebServices.

NatJet 4.0 supports servlet specification 2.4 and plus. The 2.4 minimal request is due to Spring listener RequestContextListener, we rely on.

Complete JEE application servers like WebLogic and JBoss or WebSphere come with some additional libraries. By default, these jar libraries supersedes the ones delivered with your web app. I won’t go deeper on this point as it was not a problem with NatJet.

For this kind of server, security is a must and you must follow production standard : this means mainly in our case, two things :

  • deploying with a EAR
  • a database connections pool handled by the server.

NatJet with WebSphere

Deploying a NatJet application on a WebSphere server implies 2 additional tasks compare to deploying on Tomcat. These tasks are common tasks for deploying on WebSphere :

  • building an EAR file instead of a simple WAR
  • configuring the database pool

As we seen before some versions 6.1 of WebSphere supported only servlet 2.4. In this case we need adapting the web.xml to WebSphere with moving it back to 2.4.

I want this post to be a good starting point to somebody not really aware of WebSphere administration. As guiding someone through WebSphere administration is quite a long process, I will split the problem in two posts :

  • this post will describe
    • the basic NatJet project and its ant task
    • and deploying onto WebSphere 6.1
  • A second post that will describe the configuration of the database pool.

To allow you to follow me easily, I will create a very simple NatJet project : in this post, it will not use any database connection.

At the end of this post, I show you how to handle some problem you may encounter as changing the servlet specification of you web.xml.

Part I : Simple NatJet Web App

In this post, I will work with a very simple NatJet Web App without database connection. This part is mainly on NatJet .

Creating a simple NatJet Web App

I will go quickly to the essential, as I suppose you may already be familiar with some basics of NatJet.

In the NatJet Perspective, select in the File menu New –> NatJet Project Wizard.

  • The name of the new project will be NatJetWebSphere.
  • I let the target runtime as : Apache runtime
  • I change the Dynamic web version to 2.5. When doing so, the Configuration move to Custom instead of NatJet
  • I put back in Configuration, “NatJet v4.0 Project”

Press 3 times the button Next to get the “Configure NatJet Project” screen.

Select Custom Package root and enter the following indication :

  • Package root : fr.natsystem.demo.was
  • Main Module Name : NatJetWebSphere
  • Package name for the main Module : fr.natsystem.demo.was.ui

And then press the Finish button.

The project is created.

Creating Ant configuration

At this point, we want to deploy on WebSphere and we need to build a EAR file. We will do this using an ant task.

I already went through a quite complete post on using ant with NatJet : http://insidenatjet.blogspot.com/2010/11/using-ant-with-natjet.html. I will go quickly on this point.

We will work with a buildConfDir folder that will handle configuration files that may be specific to an environment.

We will store the application.xml file needed for a EAR in this folder.

We will then create the build.xml ant file and the build.properties. Inthis file we will add the ant task that generate the EAR file at the end.

Creating buildConfDir and application.xml

First we will create the new folder as root of our project.

Right click on the project node in the project explorer, and select New –> Other…. In the dialog box that popup, select the folder “General” and the node “Folder” and then press Next.

Enter “buildConfDir” as folder name and press Finish. The folder is created.

Then we will create the PRODapplication.xml file that will be used by the ant task.

Right click on the new “buildConfDir” node in the project explorer, and select New –> Other…. In the dialog box that popup, select the folder “XML” and the node “XML” and then press Next.

Enter “PRODapplication.xml” as file name and press Finish. The file is created and opened. As it has been opened with the wrong editor, close it and open it with the XML Editor.

Complete the file with the following code :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE application PUBLIC "-//Sun Microsystems, Inc.//DTD J2EE Application 1.3//EN" "http://java.sun.com/dtd/application_1_3.dtd">

   <application id="Application_ID">
      <display-name>NatJetWebSphere</display-name>
      <module id="WebModule_1">
         <web>
            <web-uri>NatJetWebSphere.war</web-uri>
            <context-root>/NatJetWebSphere</context-root>
         </web>
      </module>
   </application>

I put in bold, the part of the file that may need to be adapted to your configuration/project.

Creating build.properties

This file is created at the root level of the project

Right click on the project node in the project explorer, and select New –> Other…. In the dialog box that popup, select the folder “General” and the node “File” and then press Next.

Enter “build.properties” as file name and press Finish. The file is created and opened for editing. I click on the tab build.properties on the bottom of the editor to use the text editor

Complete the file with the following code :

project-name = NatJetWebSphere
tomcat-home = C:/NatJet4.0.0/thirdparty/apache-tomcat-6.0.29
builder=Nat System
#Specific environnement propeties
dtdLocation="../webapps/myProject/hibernate-configuration-3.0.dtd"

contextFile=contextProd.xml
#Contient les fichiers de configuration
buildConf-directory=buildConfDir

For explanation on this file refer to my post on ant with NatJet : http://insidenatjet.blogspot.com/2010/11/using-ant-with-natjet.html.

You may need to adapt the tomcat-home repository to the one available on you PC.

Creating build.xml ant file

This file is also created at the root level of the project

Right click on the project node in the project explorer, and select New –> Other…. In the dialog box that popup, select the folder “XML” and the node “XML” and then press Next.

Enter “build.xml” as file name and press Finish. The file is created and opened. As it has been opened with the wrong editor, close it and open it with the XML Editor.

Complete the file with the following code :

I put in bold the part that may be specific to the project or the standard configuration. These parts are :

  • the project name
  • the junit.package that will be excluded from compilation
  • the compile task were we force Java 1.5 as JDK to be compliant with WebSphere 6.1
  • the ant task at the end : this is the task that use the PRODapplication.xml file created before

<?xml version="1.0" encoding="UTF-8"?>
<project name="NatJetWebSphere" basedir="." default="war">

    <property file="build.properties" />

    <!-- Define Web Project Environnement -->
    <property name="source-directory"  value="src" />
    <property name="classes-directory"  value="build/classes" />
    <property name="web-directory"  value="WebContent" />
    <property name="war-file-name" value="${project-name}.war" />
    <property name="web-xml-file" value="${web-directory}/WEB-INF/web.xml" />
  
    <!-- Allow to exclude jUnit testcase—>
<property name="junit.package" value="fr/natsystem/demo/test/**" />

  
    <fail message="You need to specify contextFile property" unless="contextFile"/>
  
    <tstamp prefix="build-info">
        <format property="current-date" pattern="d-MMMM-yyyy" locale="fr" />
        <format property="current-time" pattern="hh:mm:ss a z" locale="fr" />
        <format property="year-month-day" pattern="yyyy-MM-dd" locale="fr" />
    </tstamp>
    <property name="build-directory" value="build" />

    <path id="project-classpath">
        <fileset dir="${web-directory}/WEB-INF/lib" includes="*.jar" />
        <fileset dir="${tomcat-home}/bin" includes="*.jar" />
        <fileset dir="${tomcat-home}/lib" includes="*.jar" />
    </path>

    <target name="clean">
        <delete dir="${classes-directory}" />
        <mkdir dir="${classes-directory}" />
    </target>

<target name="clean-context" description="Prepare files that needs to be modified depending on environment">
    <delete file="${source-directory}/hibernate.cfg.xml"/>
    <copy file="${source-directory}/hibernateAntMaster.cfg.xml" tofile="${source-directory}/hibernate.cfg.xml"/>      
</target>

<target name="copy-context-delivery" depends="clean-context" description="Task that updates files for the target environment">
    <replace file="${source-directory}/hibernate.cfg.xml" token="@@DTD-Declaration@@" value="${dtdLocation}"/>
    <delete file="${web-directory}/META-INF/context.xml"/>
    <copy file="${web-directory}/META-INF/${contextFile}" tofile="${web-directory}/META-INF/context.xml"/>
</target>
  
    <target name="copy-context-dev" depends="clean-context" description="Task to set the development environment, should be used to update modification of master files">
    <replace file="${source-directory}/hibernate.cfg.xml" token="@@DTD-Declaration@@" value="http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"/>
    <delete file="${web-directory}/META-INF/context.xml"/>
    <copy file="${web-directory}/META-INF/contextDev.xml" tofile="${web-directory}/META-INF/context.xml"/>

    </target>
  
    <target name="copy-non-java-files">
        <copy todir="${classes-directory}" includeemptydirs="false">
            <fileset dir="${source-directory}" excludes="**/*.java" />
        </copy>
    </target>

   <!-- Pour WAS java 1.5 -->
    <target name="compile" depends="clean,copy-non-java-files">
        <echo>jUnit Package ${junit.package}</echo>
        <javac srcdir="${source-directory}" destdir="${classes-directory}"
        classpathref="project-classpath"
               compiler="javac1.5"
            source="1.5"
            target="1.5"
        excludes="${junit.package}"/>
    </target>

    <target name="war" depends="compile">
        <mkdir dir="${build-directory}/bin" />
        <delete file="${build-directory}/bin/${war-file-name}" />
        <war warfile="${build-directory}/bin/${war-file-name}" webxml="${web-xml-file}">
            <classes dir="${classes-directory}" />
          
            <fileset dir="${web-directory}">
                <!-- Need to exclude it since webxml is an attribute of the war tag above -->
                <exclude name="WEB-INF/web.xml" />
                <!-- Exclude NatJet xml files for the description of panels -->
                <exclude name="resources/**" />
                <excludesfile/>
            </fileset>
            <manifest>
                <attribute name="Built-By" value="${builder}" />
                <attribute name="Built-On" value="${build-info.current-date}" />
                <attribute name="Built-At" value="${build-info.current-time}" />
            </manifest>
        </war>
    </target>
   
    <!-- CREATION DU binaire EAR de PROD -->
    <target name="ear-PROD" depends="war"
        description="création du fichier EAR de Production de l'application">
        <ear destfile="${build-directory}/bin/${project-name}.ear" appxml="${basedir}/${buildConf-directory}/PRODapplication.xml">
            <fileset dir="${build-directory}/bin" includes="${war-file-name}"/>
            <manifest>
                <attribute name="Environment" value="PROD" />
                <attribute name="Built-By" value="${builder}" />
                <attribute name="Built-On" value="${build-info.current-date}" />
                <attribute name="Built-At" value="${build-info.current-time}" />
            </manifest>
        </ear>
    </target>
   

</project>

For explanation on this file refer to my post on ant with NatJet : http://insidenatjet.blogspot.com/2010/11/using-ant-with-natjet.html.

In this version, we rely on a buildConfDir where we store the configuration file : in my previous post we store the file directly in the project. The approach in this post is better as we do not deliver configuration file from other environments.

All the files used by this ant file are not available at this point of the project.

Fixing Java files

If we try to build the project with ant, we may have the following error fro 6 java files :

src\fr\natsystem\demo\was\NatJetWebSphere.java:6: package fr.natsystem.resource.localization.NatJetWebSphere does not exist
[javac] import fr.natsystem.resource.localization.NatJetWebSphere.*;

We are going to fix these errors.

Before starting, we need to rebuild with Eclipse our project : the ant task has deleted all class files. Thus a lot of your Java class may shows up in error (already or at the first save you will do).

  1. To fix this point, go to menu “Project” and select menu item “Clean…”
  2. Select your project : and press OK. This will rebuild the project.

If you do not do this after an incorrect ant build, you will have plenty of errors in your project as the class files have been deleted.

Then for each of the files with the error, you edit the file and do an “Organize imports” (Crt Shift O) and save it. This will delete from the Java class the import to an empty package.

Then you can rebuild using ant. This time, you should get the following output

Buildfile: C:\Users\jltho.NATSYSTEM\Documents\wksp400\NatJetWebSphere\build.xml
clean:
   [delete] Deleting directory C:\Users\jltho.NATSYSTEM\Documents\wksp400\NatJetWebSphere\build\classes
    [mkdir] Created dir: C:\Users\jltho.NATSYSTEM\Documents\wksp400\NatJetWebSphere\build\classes
copy-non-java-files:
     [copy] Copying 12 files to C:\Users\jltho.NATSYSTEM\Documents\wksp400\NatJetWebSphere\build\classes
compile:
     [echo] jUnit Package fr/natsystem/demo/test/**
    [javac] Compiling 12 source files to C:\Users\jltho.NATSYSTEM\Documents\wksp400\NatJetWebSphere\build\classes
    [javac] Note: Some input files use or override a deprecated API.
    [javac] Note: Recompile with -Xlint:deprecation for details.
war:
    [mkdir] Created dir: C:\Users\jltho.NATSYSTEM\Documents\wksp400\NatJetWebSphere\build\bin
      [war] Building war: C:\Users\jltho.NATSYSTEM\Documents\wksp400\NatJetWebSphere\build\bin\NatJetWebSphere.war
ear-PROD:
      [ear] Building ear: C:\Users\jltho.NATSYSTEM\Documents\wksp400\NatJetWebSphere\build\bin\NatJetWebSphere.ear
BUILD SUCCESSFUL
Total time: 10 seconds

If you do a refresh of the project (F5) you should now see in build/bin the file NatJetWebSphere.ear.

 

Part II : Deploying on WebSphere 6.1

Your server should be started.

To know if it is started you can try to connect to the administrative console : https://localhost:9043/ibm/console/logon.jsp

If you got the login form, the server is started.

If this is not the case go to your Windows menu : “Tous les programmes” –> “IBM Websphere” –> “Application Server V6.1” –> Profils –> AppSrv01 –> “Démarrer le serveur”.

Connect to the administrative console : https://localhost:9043/ibm/console/logon.jsp

You will need a login account. Then select in “Applications” the link : “Installation d’une nouvelle application” (sorry but my web console is in French).

NJWAS01installed

In the next page, using the Browse button to select your EAR.

NJWAS02installedSelectEAR

And then press Next/Suivant button. You should got after a few seconds, the following page :

NJWAS03installedOption

Just press Next/Suivant on this first step.

After a while you should get the mapping page (step 2) :

NJWAS04installedMapping

Just press Next/Suivant, you should get the page (step 3) :

NJWAS05installedStep3

Just press Next/Suivant, to get the summary page

NJWAS06installedStep4SUmmary

Then press Terminate/Terminer. You have to wait several long seconds before to get the result.

Then press Save and go to start the application.

You should get on the top of the application page after a while :

NJWAS07Started

Testing

At this point you should be able to display your web app in the browser at the following URL : http://localhost:9080/NatJetWebSphere

It should display the standard page of a new NatJet project.

 

Problems you may encounter

Servlet 2.5 does not work

If your WebSphere 6.1 is really the basic version, it may not support servlet 2.5. In this case, you need to change your web.xml file.

If you don’t you wil get an error message when deploying or starting the web  app.

To fix your problem, you need to edit the WebContent/WEB-INF/web.xml file, and change the web-app declaration tag of your XML file.

You should have now the following code :

<?xml version="1.0" encoding="UTF-8"?>

<web-app id="WebApp_ID" version="2.4"
    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">

    <display-name>NatJetWebSphere</display-name>
    <servlet>
        <servlet-name>WebContainerSpringServletNS</servlet-name>
        <servlet-class>
            fr.natsystem.natjet.echo2.webcontainer.WebContainerSpringServletNS</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>WebContainerSpringServletNS</servlet-name>
        <url-pattern>/app</url-pattern>
    </servlet-mapping>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <listener>
        <listener-class>
            org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
    <session-config>
        <session-timeout>5</session-timeout>
    </session-config>
</web-app>

This point should fix your problem. This is the way to move back a NatJet web app to a servlet 2.4 container.

 

Deploying EAR on WebSphere doesn’t finish

Sometimes deploying on WebSpshere 6.1, I get stuck on the following items (action SEJ0400I) :

ADMA5005I: L'application NatJetWebSphere est configuré dans le référentiel WebSphere Application Server.

SECJ0400I: La mise à jour de l'application NatJetWebSphere avec les informations appContextIDForSecurity information a abouti.

 

 
When I get this, I first wait one or two minutes as this task can be long, and the if nothing change I click on the link “application entreprise” on the left panel. The new page have a warning message on the top :
 
NJWAS08Blocked
 
Click on the link “Save/Sauvegarder”.
Then I can start your web app.
 
This work around help me a lot when working on WebSphere 6.1. I’m not a WebSphere admin and I didn’t have time to understand what was going on, but the trick does the job.
 

Conclusion

We’ve seen how to deploy a simple NatJet applications on WebSphere 6.1 and how to handle some little problems.

In this post you have a complete build.xml sample that will help you build a EAR with ant from a NatJet project.

Deploying a NatJet web app that used a database connection (if you are using the server database connection pool) may be a bit more complicated (due to WebSphere). I will try to write soon a post on this subject.

Wednesday, September 7, 2011

How to send email from a NatJet WebApp

Having to send an email, it is a quite common task for a Web App : it may be a receipt, a confirmation message… This kind of email are automatically sent by the web application : there is no need for a human interaction.

This post is a tutorial on how to send an email from a NatJet application.

Architecture

The solution will rely on :

  • NatJet 4.0
  • Spring
  • JavaMail.

Testing will be achieved using jUnit 4.0.

Introducing JavaMail

The main Java library to send email is JavaMail : This is the Oracle’s (former Sun) standard to send email. JavaMail allows a Java application to behave as a client mail : you still need a mail server as Microsoft Exchange, SendMail or any email services like GMail or Yahoo Mail.

JavaMail behaves as an abstraction layer on top of different mail protocols as IMAP or SMTP that allows communication between a client mail and its server.

NatJet 4.0 Architecture with Spring

NatJet 4.0 includes Spring 3.0. Spring includes some services to configure and use easily JavaMail.

As always with Spring, this solution is a nice and easy way to separate the configuration of the communication between the client and the server from you application code.

The Bean org.springframework.mail.javamail.JavaMailSenderImpl from Spring will allows the configuration of the service. It’s part of NatJet 4.0.

Remember that the NatJet application and NatJet application context are two NatJet beans created by Spring : so it will be quite easy to inject the Spring mail service inside a NatJet application.

Spring Beans

The solution relies on 3 beans

  • mailSender : this is the Spring Bean that handles the JavaMail configuration. The implementation is org.springframework.mail.javamail.JavaMailSenderImpl as seen before.
  • sendMailManager : this is a bean that we will develop to render the service of sending an email. This bean relies on the previous bean. This is where we will code using the JavaMail API
  • NatJet Application bean (called applicationInstance) : This bean can be simply retrieved from NatJet with the getApp() method. That’s why we will simply inject the bean sendMailManager there allowing an easy access to it.

 

Configuration of the Project

The first step is to create a NatJet project for the demo. Then we will add the necessary JavaMail jars. And we will configure Spring to create and inject the correct beans.

Creating a new NatJet Project

In the NatJet Perspective, select in the File menu New –> NatJet Project Wizard. The name of the new project will be NatJetMail. Press 3 times the button Next to get the “Configure NatJet Project” screen.

Select Custom Package root and enter the following indication :

  • Package root : fr.natsystem.demo.email
  • Main Module Name : NatJetMail
  • Package name for the main Module : fr.natsystem.demo.email.ui

TE02Creationprojet

And then press the Finish button.

The project is created.

Add JavaMail Jar

For the demo, we need to download JavaMail.jar and the Activation.jar if you use Java 5.0 as I do.

Go to the Oracle website : www.oracle.com/technetwork/java/javamail. Select on the right part the Download link.

I’ve used the JavaMail 1.4.4 version. Press the Download button. Read and accept the Licence Agreement to get access to the link : javamail1_4_4.zip. Download and save the file.

TE07ConfigureDownload

Extract the file, we will use only the jar file mail.jar in javamail1_4_4.

If you are using Java 5.0 we need as specified on Oracle website to download the JavaBean Activation Framework. The best, is starting from www.oracle.com/technetwork/java/javamail, click on link “Javabeans Activation Framework (JAF)”.

Then on the new page, select JAF_1.1.1 link. On the next page, select Download button. On the new page, Accept License Agreement et click on link jaf-1_1_1.zip.

Download and save on your disk, then extract files. We will use only the jar file activation.jar in jaf-1_1_1.

To add the two jars to your NatJet project, in Eclipse open the node WebContent/WEB-INF/lib. Select the jar mail.jar in javamail1_4_4 in the Windows Explorer and drag and drop it on the lib node. Do the same with the file activation.jar in jaf-1_1_1.

TE08ConfigureAjoutMail.jar

You’ve just added two new jars in your NatJet project :

  • activation.jar
  • mail.jar

 

Defining beans in natjetInstanceContext.xml

In WebContent/WEB-INF you can find several configuration xml file for Spring. We will modified natjetInstanceContext.xml to add there the declaration of the two new beans : mailSender et sendMailManager.

This is also where you can find the declaration of the NatJet Application bean applicationInstance that we need to modify : we need to inject the new sendMailManager bean.

In NatJetMail project select natjetInstanceContext.xml node in WebContent/WEB-INF, click right and select Open with… –> XML editor.

The XML file is opened. Modify the file as following (new or modified sections are in bold).

Order of beans are important, so we need to add the two new beans declaration before the import declaration.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    <!-- <bean/> definitions here –>

<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="smtp.gmail.com"/>
<property name="username" value="myemail@mycompany.fr"/>
<property name="password" value="mypassword"/>
<property name="javaMailProperties">
<props>
<prop key="mail.smtp.auth">true</prop>
<!-- used by gmail smtp server -->
<prop key="mail.smtp.starttls.enable">true</prop>
</props>
</property>
</bean>

<bean id="sendMailManager" class="fr.natsystem.demo.email.servicemail.SendMailManager">
<property name="mailSender" ref="mailSender"/>
</bean>


<import resource="ContextBean/emptyContextBean.xml" />


<bean id="applicationInstance" class="fr.natsystem.demo.email.NatJetMail"
        scope="prototype"> 
   <property name="context"> 
        <ref bean="natjetSessionContext" /> 
   </property> 
   <property name="sendMailManager" ref="sendMailManager"/>         
</bean>

<bean id="mainLayout" class="fr.natsystem.demo.email.ui.Layout3Panels"
        scope="prototype"> 
</bean>
</beans>

Be careful ! You need to adapt at least the username and password fields, but you may need to change more parameters depending of your email server.

For GMail or Google Apps Gmail, username is your email : myaccouunt@gmail.com for a  personnal gmail account or myemail@mycompany.fr if you are using Google Apps. The password is the one of your email account.

Save and close the file.

Modifying Application Class : NatJetMail.java

In the src node of your project, you can find the Application class NatJetMail in fr.natsystem.demo.email.

We need to add a new property and setter to store and retrieve the sendMailManager bean. Be careful to be consistent with the declaration we’ve made in the previous chapter : the name of the property in the java class should match the name of the property in the bean.

Edit the class and add the sendMailManager property and its getter and setter as follow.

public class NatJetMail extends AbstractNatJetMail {
    private static final long serialVersionUID = -4417253215596027617L;
    //Spring Bean : Email service
    private SendMailManager sendMailManager;
   
  public NatJetMail () {
    super();
  }
 
  public fr.natsystem.natjet.window.NsMainLayout initApp() {
    NsLogger.debug(this, " init application ");
    fr.natsystem.natjet.window.NsMainLayout natJetMainWindow = (fr.natsystem.natjet.window.NsMainLayout) NsConfig.getSpringBean("mainLayout");
    setMainWindow(natJetMainWindow);
    return natJetMainWindow;
  }

public SendMailManager getSendMailManager() {
    return sendMailManager;
}

public void setSendMailManager(SendMailManager sendMailManager) {
    this.sendMailManager = sendMailManager;
}
 
 
}

The class is in error as the SendMailManager as not yet been defined. Save and close.

Creating SendMailManager class

This is the main part of the coding. This is where we send email using JavaMail API.

We will do 2 samples :

  • a simple email message
  • a mail with an attachment as a JPEG file or a PDF file

Create the class SendMailManager

Select in the File menu, the New –> Class item.

Enter as follow :

  • Package : fr.natsystem.demo.email.servicemail
  • Name : SendMailManager

This has to map the Spring declaration of the bean sendMailManager.

TE05ClassMailManager

Press Finish button. The class is created, we need now to complete it.

We need, first to add the property we specified in the bean declaration : mailSender and it setter.

At this point, the class should look like this :

package fr.natsystem.demo.email.servicemail;

import org.springframework.mail.javamail.JavaMailSender;

public class SendMailManager {
    private JavaMailSender mailSender;

    public void setMailSender(JavaMailSender mailSender) {
        this.mailSender = mailSender;
    }
   
}

 

Update NatJetMail

Before continuing, edit the class NatJetMail.java and do an Organize Import (ctrl Shift O). Save. This will add the correct import for SendMailManager. You shouldn’t have any error left.

Method to send a simple mail

The first sample we are going to do is sending a simple email in which we will specify :

  • Recipient
  • Subject
  • Body

For this we will create the method sendSimpleMail:

public void sendSimpleMail(final String pEmail, final String pSubject,  final String pEmailText) {
    
     MimeMessagePreparator preparator = new MimeMessagePreparator() {
   
        public void prepare(MimeMessage mimeMessage) throws Exception {
   
            mimeMessage.setRecipient(Message.RecipientType.TO,
                    new InternetAddress(pEmail));
            mimeMessage.setText(pEmailText);
            mimeMessage.setSubject(pSubject);
        }
    };
    try {
        this.mailSender.send(preparator);
    }
    catch (MailException ex) {
        // simply log it and go on...
        System.err.println(ex.getMessage());           
    }
}

We need to add the following import declaration :

import javax.mail.Message;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import org.springframework.mail.MailException;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessagePreparator;

Save the java class.

Using the service form NatJet

To use the service we will modify the MainPanel panel.

MainPanel.xml

In WebContent/resources/NatJetMail select the MainPanel.xml and double click on it to open it with NatJet editor.

We will add :

  • 2 labels : “Email recipient” and “Text email”
  • 1 Textfield emailTF for the email address with the Regex Type email.
  • 1 Textarea textTA for the text
  • 1 PushButton sendSimpleMailPB to send the email

It could look to the following panel :

TE03Ecran

Save the panel.

Calling the mail service from NatJet

Select the pushbutton Send, and in the Properties view select Executed event and press the arrow. The java code for MainPanel.java is displayed.

To complete the action, we need to retrieve the service bean to send email : this is quite simple as there is a method getApp() to retrieve the NatJet application instance. Then as we add a getter to the bean in this class, we have the bean and we just need to trigger the method handling the correct parameters :

  • emailTF.getText() to retrieve the email input by the user
  • For the subject we will use a static value : “Simple mail”
  • textTA.getText() to retrieve the text.

The java code of the method is as follow :

@Override
public void sendSimpleMailPB_ExecutedEvent(NsExecutedEvent arg0){
    getApp().getSendMailManager().sendSimpleMail(emailTF.getText(), "Simple mail", textTA.getText());
}

Save the java class.

Testing

Testing from NatJet Web App

First we will test from the NatJet Web App

At this point it is easy to test your NatJet Web App as usual : just select your NatJetMail node and select Run As >  Run on server. Select you server and run.

You should get an opened browser with your NatJet page.

Enter an email and a text message and press Send button. A quick “Please wait…” message may appear and then you should receive an email with subject “Simple mail”.

Testing from JUnit

As we build a service class, it can be efficient to test the service from JUnit.

The first step is to add the JUnit library to the project. Then we will build a JUnit test class and the test configuration file.

Adding JUnit 4 to a NatJet project

In the Package Explorer view, select the node of NatJetMail project and click right. Select “Build path” menu and “Add library…” menu item. The dialog “Add Library” is opened.

Select JUnit and press “Next>” button. On next screen, select JUnit 4 as JUnit library version, and then press Finish.

TE34junitAddJarJunit

A JUnit 4 node will appear in Package Explorer view under your project node NatJetMail.

Adding a JUnit test class

In the File menu, select New –> Other… The dialog New is opened.

Select JUnit Test Case in the folder JUnit and press Newt> button.

On the New JUnit Test Case dialog :

  • Select radio button “New JUnit 4 test”
  • Package : fr.natsystem.test.demo.email.servicemail : this naming convention allows to exclude easily all test package when packaging the final production delivery.
  • Name: TestSendMailManager

You can select class SendMailManager for class under test, but this will only create an empty test method for SendSimpleMail.

The class is created, then we will add some Spring plumbing :

  • First we will add the RunWith and ContextConfiguration annotations to tell JUnit that we will used Spring to run the test and use a Spring Configuration file
  • Then, we will add a Autowired property to store and retrieve the bean sendMailManager that we want to test.

To finish, we need to call the service. In our case, this is quite easy we just need to call the method with some parameters.

The final java code for the class is :

package fr.natsystem.test.demo.email.servicemail;

import static org.junit.Assert.fail;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import fr.natsystem.demo.email.servicemail.SendMailManager;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"EmailTestConfig.xml"})
public class TestSendMailManager {
   
    @Autowired
    private SendMailManager sendMailManager;

    /**
     * Test method for {@link fr.natsystem.demo.email.servicemail.SendMailManager#sendSimpleMail(java.lang.String, java.lang.String, java.lang.String)}.
     */
    @Test
    public final void testSendSimpleMail() {
        sendMailManager.sendSimpleMail("testaccount@mycompany.fr", "Suject : testSendSimpleMail",
"This is a simple JUnit test");
    }

}

Save the java class.

Creating JUnit Spring Configuration file

In the ContextConfiguration annotation we specified a file name : this is the configuration file Spring will use. This file need at least to specify the sendMailManager to allow the Autowired annotation to work.

Select the package fr.natsystem.test.demo.email.servicemail, then right click and select New –> Other… The dialog New is opened.

Select XML in the folder XML and press Newt> button.

Enter EmailTestConfig.xml in the file name and press Finish.

The file is created, closed the tab and reopen it with a right click and “open wit XML editor”.

Enter the following code:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
   
    xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

    <!-- <bean/> definitions here
        <property name="loggerFormat" value="[%id:%ip] %M : ATtention %M est très couteux" />
    -->
    <bean id="nslogger" class="fr.natsystem.nslogger.NsLogger">
        <property name="loggerFormat" value="***[%id:%ip]" />
        <property name="storeRequest" value="true" />
        <property name="dumpRequest" value="false" />
        <property name="logElapsedTime" value="false" />
    </bean>
   
    <!-- Pour JUnit -->
    <bean id="nsconfig" class="fr.natsystem.nsconfig.NsConfig">
    </bean>

    <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
          <property name="host" value="smtp.gmail.com"/>
          <property name="username" value="testaccount@mycompany.fr"/>
          <property name="password" value="mypassword"/>
        <property name="javaMailProperties">
        <props>
            <prop key="mail.smtp.auth">true</prop>
            <!-- used by gmail smtp server -->
            <prop key="mail.smtp.starttls.enable">true</prop>
        </props>
        </property>
    </bean>


    <bean id="sendMailManager" class="fr.natsystem.demo.email.servicemail.SendMailManager">
          <property name="mailSender" ref="mailSender"/>
    </bean>
</beans>

Save the file.

Be careful to change at least the username and password properties of the mailSender bean.

Run JUnit test

This is as for all JUnit test, right click on the TestSendMailManager java class, select the menu Run As -> JUnit Test.

The test is launch and you should receive quickly a new email on your test account.

This test does not allow checking the result : thus you may have noticed that we didn’t use the assertEqual method. The only errors you can get is an exception or not receiving an email.

Sending an attached File

To finish, this tutorial we will add the case of sending an email with an attached file.

For this, we will create a new method in SendMailManager.java class and a new test method in TestSendMailManager java.

Sending email with attachment in JavaMail

Open SendMailManager.java and add the following method

public void sendMailWithAttachment( String pEmail,  String pSubject, String pEmailText,  String pFileName) throws IOException {

    // Retrieve the mimeMessage from Spring
    MimeMessage mimeMessage = mailSender.createMimeMessage();

    try {
        mimeMessage.setRecipient(Message.RecipientType.TO,
                new InternetAddress(pEmail));
        // In MultiPart email : setText in the MimeMessage is useless
        // It has to be done on one of the part (usually the first)
         mimeMessage.setSubject(pSubject);

         // --------------------------------Message Part
        MimeBodyPart mbp1 = new MimeBodyPart();
        mbp1.setText(pEmailText);
        // --------------------------------Attachment
        MimeBodyPart mbp2 = new MimeBodyPart();
        mbp2.attachFile(pFileName);

        // --------------------------------Merging message + Attachment
        Multipart mp = new MimeMultipart();

        mp.addBodyPart(mbp1);
        mp.addBodyPart(mbp2);

        mimeMessage.setContent(mp);
        // --------------------------------------------------------//
       
        // Sending the email
        this.mailSender.send(mimeMessage);


    }
    catch (MessagingException e) {
        NsLogger.error(this, "sendMailWithAttachment MessagingException:"+e.getMessage());
        NsLogger.printStack(e);
    }
}

Notice the instruction to retrieve a JavaMail MimeMessage : generally it is created by coding. Working with Spring we retrieve it from the mailSender bean with the correct initialization.

It is then possible to use all standard JavaMail API.

MimeMessage mimeMessage = mailSender.createMimeMessage();

The method can throw an IOException when the filename is incorrect.

Save the java class.

JUnit test.

We add to the JUnit test class 2 new methods :

  • one to test a correct use of the method
  • one to test the reaction with an invalid email address

 

@Test
public final void testSendAttachment() {
    try {
        sendMailManager.sendMailWithAttachment("testaccount@mycompany.fr", "Suject : testSendAttachment", "This is a  JUnit test with a file attached","C:/yourJpeg.jpg" );
    } catch (IOException e) {
        NsLogger.printStack(e);
        fail("incorrect file IOException"+e.getMessage());
    }
}

@Test
public final void testSendAttachmentInvalidEmail() {
    try {
    sendMailManager.sendMailWithAttachment("invalidemail", "Suject : testSendAttachmentInvalidEmail", "This is a  JUnit test with a file attached","C:/yourJpeg.jpg" );
} catch (IOException e) {
    NsLogger.printStack(e);
    fail("incorrect file IOException"+e.getMessage());
} catch (MailException e) {
    assertEquals("Check error message when invalid adress :"  ,"Failed messages: javax.mail.SendFailedException: Invalid Addresses;",e.getMessage().substring(0, 67));
    assertNull("testSendAttachmentInvalidEmail MailException getRootCause:",e.getCause());
}
}

The file C:/yourJpeg.jpg has to exist to work, thus you need to adapt your test with the correct email address (for the first one) and a valid filename for both.

Notice that in the second test we analyze the exception to confirm that it’s an invalid email address.

Conclusion

You have through a complete project using JavaMail, Spring and NatJet. The coding of JavaMail is standard programming minus the configuration part that can be handled transparently by Spring.

Wednesday, November 10, 2010

Using Ant with NatJet

In this post, I will present a quite standard Ant build file for a NatJet project. Notice, that as NatJet is a standard Dynamic Web Project in Eclipse, this will also work for any web project having the same structure.

A NatJet project has by default the following structure :

  • src : source directory
  • build : a temporary directory where class files are generated
  • WebContent : a directory that stores files that will be deployed on the web server

I won’t present Ant : I will use it as an automate for integration.

Integration

For me, the main goal of integration is to insure consistency between source and binary. It is not just producing a binary for production : integration has to be the guardian of this consistency.

Second point, I’m using the Run As –> On server menu to test while in development. Ant will only be used in the integration process to deliver a war to a customer for test or production. This means that my configuration is not optimized to speed integration but to insure the consistency.

The way I will use Ant, is directly inspired by this quest. This is important because each solution has strengths and weaknesses : I will therefore be more interested in strength that insure consistency than speed.

Delivery for test or production brings generally some new constraints :

  • database connection is not the same as in development
  • sometimes there are other parameters or some specific constraints to the production environment

In my sample, I will have two specificities to handle :

  1. for database connection, I’m using a datasource which is defined in the context.xml file that is in META-INF repository. I need two different files : one for development one for production. There is no need to insure a consistency between the two files.
  2. as I’m using a datasource, the hibernate.cfg.xml file needs the DTD declaration. This declaration is a problem : either I use an URL but in this case the server needs a internet access or I put a file with a relative path, but in this case the path has to be changed for every server. Anyway, I can’t use the same declaration for development and production. The hibernate.cfg.xml file needs to be the same between both environments : there is only one line that needs to change : the DTD declaration. A hibernate file may evolve quite a lot. In this case, I do not want to have to maintain two files.

Functionalities of my ant build.xml

As I’ve stated it before, the default task of my build.xml will be the the war task that build the war file. The default configuration will correspond to the one of the production environment. There will be defined in the build.properties file.

If you are in a hurry and quite familiar with ant, you may prefer to skip this section and go directly to the two files :Summary : the two files

The sample build.xml ant file will also :

  1. exclude the java files for the jUnit test from the compile task
  2. replace a line in the hibernate.cfg.xml file depending on the configuration
  3. pick up the right context.xml file
  4. exclude xml files corresponding to the panel description

Finally, I have define two ant task to modify file according to the environment

Default task to build a war

The first tag is project tag. This tag defines :

  • project name : It’s just for me a way to attach the build.xml file to a project
  • basedir : It’s usually “.” meaning the root of the eclipse project
  • default : this is the default task, that is highlighted. In my case is will be war. Pepel using ant in the development process use build or compile task as a default.

In my case, it will be :

<project name="my-natjet-project" basedir="." default="war">

As I want to insure consistency of source and binary (the war file), I will have the following chain dependency of my ant tasks :

  • <target name="clean">
  • <target name="copy-non-java-files">
  • <target name="compile" depends="clean,copy-context-delivery,copy-non-java-files">
  • <target name="war" depends="compile">

This means, that when I select the war task, ant will :

  1. clean my build directory
  2. copy non java file
  3. compile
  4. build the war file

In the specified order. Thus I’m sure that any class file of the war file has been built from the last version of its source file. Consistency of source and binary is insured by the process. Notice that in some configuration, the cleaning task may be an option left to the developer. I definitely reject this option as my goal is consistency and not speed.

Exclude some java files from compilation

Your project may contains jUnit java test files. Obviously, this file are not needed in production. But they may even not compile as they need some specific jar files (jUnit jar for example).

A good habit is to group all junit java test in one package distinct from other source : in my case there where all sub package of fr.natsystem.myproject.test.

In the property part of my build.xml file, I‘ve defined the following property :

<property name="junit.package"  value="fr/natsystem/myproject/test/**" />

This property is used in the compile task :

<target name="compile" depends="clean,copy-context-delivery,copy-non-java-files">
    <echo>jUnit Package ${junit.package}</echo>
    <javac srcdir="${source-directory}" destdir="${classes-directory}" classpathref="project-classpath" excludes="${junit.package}"/>
</target>

The excludes property in the javac tag is expecting a relative exclusion path starting at the srcdir (src in our case). That means, it will be the package description where we replace dot by slash.

The last two stars (**) means that all subdirectories and there content are excluded. If you put just one star, you are limiting yourself at files in the specified directory.

Replacing a line in a config file with ant

In my case, I need two versions of my hibernate.cfg.xml file. The only difference was the DTD declaration at its beginning :

For production as I do not have an internet access :

<!DOCTYPE hibernate-configuration PUBLIC  "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

In development, as when I trigger my test from eclipse the file is not found at this position, I opted for the URL

<!DOCTYPE hibernate-configuration PUBLIC  "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "../webapps/myProject/hibernate-configuration-3.0.dtd">

hibernate.cfg.xml files are quite long and specific files that evolves quite a lot in the process of a development. I do not want to have to keep track of this change in two files.

The solution was to have a master hibernate.cfg.xml file called in our case hibernateAntMaster.cfg.xml. This file is the one that will be modified by developers. The DTD declaration is a tag that we will replace by an ant task.

<!DOCTYPE hibernate-configuration PUBLIC  "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "@@DTD-Declaration@@">

We add two tasks in the ant build.xml file :

  • clean-context : this task will delete the actual hibernate.cfg.xml file and copy the reference hibernateAntMaster.cfg.xml as hibernate.cfg.xml. At this point we will have two identical files
  • copy-context-delivery : this task we replace the line in the hibernate.cfg.xml file. This task will do some other context specific tasks that we will see later.

The second task, will put the hibernat.cfg.xml file with the correct DTD declaration.

We use a property dtdLocation that we will specify in the build.properties file.

<target name="clean-context" description="Prepare files that needs to be modified depending on environment">
    <delete file="${source-directory}/hibernate.cfg.xml"/>
    <copy file="${source-directory}/hibernateAntMaster.cfg.xml" tofile="${source-directory}/hibernate.cfg.xml"/>       
</target>

<target name="copy-context-delivery" depends="clean-context" description="Task that updates files for the target environment">
    <replace file="${source-directory}/hibernate.cfg.xml" token="@@DTD-Declaration@@" value="${dtdLocation}"/>
    <delete file="${web-directory}/META-INF/context.xml"/>
    <copy file="${web-directory}/META-INF/${contextFile}" tofile="${web-directory}/META-INF/context.xml"/>
</target>

The replace ant tag allow to define :

  • the file you want to change
  • the token you want to replace in the content of the file : in our case we use @@ to delimit it in a way that avoid collision with existing syntax.
  • the value that will be used to replace the token in the file.

Picking the right config file with ant

We have two different versions of our context.xml file :

  • one for production
  • one for development

This file have little in common. They don’t evolve a lot and modification may be specific to only one of the file.

We just have to use one or the other. In our case, we create 3 files in WebContent/META-INF :

  • context.xml : the file used in test or production
  • contextProd.xml : the version we want to use in production
  • contextDev.xml : the version we want to use in development.

To achieve, the task we use the same copy-context-delivery task seen before :

<target name="copy-context-delivery" depends="clean-context" description="Task that updates files for the target environment">
    <replace file="${source-directory}/hibernate.cfg.xml" token="@@DTD-Declaration@@" value="${dtdLocation}"/>
    <delete file="${web-directory}/META-INF/context.xml"/>
    <copy file="${web-directory}/META-INF/${contextFile}" tofile="${web-directory}/META-INF/context.xml"/
>
</target>

First we delete the context.xml file, then we copy the right context file as context.xml file.

We use a contextFile property defined in the build.properties file.

Excluding directories in the ant war task

NatJet project have a directory resources in the WebContent directory. This directory contains the xml description of the panels. These descriptions are not used in production : they are transformed as java abstract class for execution.

We want to exclude this directory from the war file. The war file is build in ant from a build directory that contains classes and a WebContent directory that will be the root of the archive. We want to be able to use directly the WebContent directory at it is the rule. We do not want to have to build a second temporary directory.

To achieve, this goal we used the exclude tag to get the following definition :

<target name="war" depends="compile">
    <mkdir dir="${build-directory}" />
    <delete file="${build-directory}/${war-file-name}" />
    <war warfile="${build-directory}/${war-file-name}" webxml="${web-xml-file}">
        <classes dir="${classes-directory}" />
       
        <fileset dir="${web-directory}">
            <!-- Need to exclude it since webxml is an attribute of the war tag above -->
            <exclude name="WEB-INF/web.xml" />
            <!-- Exclude NatJet xml files for the description of panels -->
            <exclude name="resources/**" />
            <excludesfile/>
        </fileset>
        <manifest>
            <attribute name="Built-By" value="${builder}" />
            <attribute name="Built-On" value="${build-info.current-date}" />
            <attribute name="Built-At" value="${build-info.current-time}" />
        </manifest>
    </war>
</target>

Notice the manifest section : this will build a MANIFEST.MF file that will be in the META-INF directory of the war file. This allows to keep track of the version or the build number of the war.

Ant task to configure development environment

You’ve noticed that we have to deal with two environments : production and development. Two files (context.xml and hibernate.cfg.xml) depends on the selected environment.

We build the default of our ant build.xml and build.properties file to be the production environment. This is consistent with our main goal : integration for a customer delivery.

The process may affect the eclipse development environment. Thus as we have the ant infrastructure configured for our project it is quite straightforward to add a little task to configure the development environment.

For this we duplicate the copy-context-delivery ant task into copy-context-dev. The task will do the exact same thing, but we do not want to go through picking or modifying a build.properties file we replace properties by their direct definition.

In our case, it was :

  • the value in the replace tag
  • the filename of the file to copy as context.xml file
<target name="copy-context-dev" depends="clean-context" description="Task to set the development environment, should be used to update modification of master files">
    <replace file="${source-directory}/hibernate.cfg.xml" token="@@DTD-Declaration@@" value="http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"/>
    <delete file="${web-directory}/META-INF/context.xml"/>
    <copy file="${web-directory}/META-INF/contextDev.xml" tofile="${web-directory}/META-INF/context.xml"/>
</target>

In development, to set your environment you just pick this task and then do a refresh (F5) on the project node in your project explorer.

When you modify the hibernateAntMaster.cfg.xml, you just need to run this ant task to update the hibernate.cfg.xml file.

Notice, that this approach works fine, because we usually keep development environment quite consistent among the development team and we do not need specific configuration for each developer.

Summary : the complete files

We have two files both on the root of the eclipse project at the same level :

  • build.xml
  • build;properties

To edit build.xml, it may be better for you to use the right click : Open with and pick up the Ant Editor menu. This will bring syntax coloring and code completion.

To run the task, just right click on build.xml and select the menu Run As –> Ant Build… : this will opens a dialog where you can pick up the task : either choose war if you want to build the war files for delivery, or copy-context-dev to set the development environment or refresh the hibernate.cfg.xml or context file after a modification od the corresponding master.

build.properties file

The properties specific to the project or the environment will be set in this file.

Follow, the complete file:

project-name = myWarName
tomcat-home = C:/NatJet4.0.0/thirdparty/apache-tomcat-6.0.20
builder=Nat System
#Specific environnement propeties
dtdLocation="../webapps/myProject/hibernate-configuration-3.0.dtd”

contextFile=contextProd.xml

The project-name will be the name of the war file.

build.xml file

Follow the complete file :

<?xml version="1.0" encoding="UTF-8"?>
<project name="my-natjet-project" basedir="." default="war">

    <property file="build.properties" />

    <!-- Define Web Project Environnement -->
    <property name="source-directory"  value="src" />
    <property name="classes-directory"  value="build/classes" />
    <property name="web-directory"  value="WebContent" />
    <property name="war-file-name" value="${project-name}.war" />
    <property name="web-xml-file" value="${web-directory}/WEB-INF/web.xml" />
   
    <!-- Allow to exclude jUnit testcase-->
   <property name="junit.package" value="fr/natsystem/myproject/test/**" />
   
    <fail message="You need to specify contextFile property" unless="contextFile"/>
   
    <tstamp prefix="build-info">
        <format property="current-date" pattern="d-MMMM-yyyy" locale="fr" />
        <format property="current-time" pattern="hh:mm:ss a z" locale="fr" />
        <format property="year-month-day" pattern="yyyy-MM-dd" locale="fr" />
    </tstamp>
    <property name="build-directory" value="build" />

    <path id="project-classpath">
        <fileset dir="${web-directory}/WEB-INF/lib" includes="*.jar" />
        <fileset dir="${tomcat-home}/bin" includes="*.jar" />
        <fileset dir="${tomcat-home}/lib" includes="*.jar" />
    </path>

    <target name="clean">
        <delete dir="${classes-directory}" />
        <mkdir dir="${classes-directory}" />
    </target>

    <target name="clean-context" description="Prepare files that needs to be modified depending on environment">
    <delete file="${source-directory}/hibernate.cfg.xml"/>
    <copy file="${source-directory}/hibernateAntMaster.cfg.xml" tofile="${source-directory}/hibernate.cfg.xml"/>       
</target>

<target name="copy-context-delivery" depends="clean-context" description="Task that updates files for the target environment">
    <replace file="${source-directory}/hibernate.cfg.xml" token="@@DTD-Declaration@@" value="${dtdLocation}"/>
    <delete file="${web-directory}/META-INF/context.xml"/>
    <copy file="${web-directory}/META-INF/${contextFile}" tofile="${web-directory}/META-INF/context.xml"/>

    </target>
   
    <target name="copy-context-dev" depends="clean-context" description="Task to set the development environment, should be used to update modification of master files">
    <replace file="${source-directory}/hibernate.cfg.xml" token="@@DTD-Declaration@@" value="http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"/>
    <delete file="${web-directory}/META-INF/context.xml"/>
    <copy file="${web-directory}/META-INF/contextDev.xml" tofile="${web-directory}/META-INF/context.xml"/>

    </target>
   
    <target name="copy-non-java-files">
        <copy todir="${classes-directory}" includeemptydirs="false">
            <fileset dir="${source-directory}" excludes="**/*.java" />
        </copy>
    </target>

   
    <target name="compile" depends="clean,copy-context-delivery,copy-non-java-files">
        <echo>jUnit Package ${junit.package}</echo>
        <javac srcdir="${source-directory}" destdir="${classes-directory}" classpathref="project-classpath" excludes="${junit.package}"/>
    </target>

    <target name="war" depends="compile">
        <mkdir dir="${build-directory}" />
        <delete file="${build-directory}/${war-file-name}" />
        <war warfile="${build-directory}/${war-file-name}" webxml="${web-xml-file}">
            <classes dir="${classes-directory}" />
           
            <fileset dir="${web-directory}">
                <!-- Need to exclude it since webxml is an attribute of the war tag above -->
                <exclude name="WEB-INF/web.xml" />
                <!-- Exclude NatJet xml files for the description of panels -->
                <exclude name="resources/**" />
                <excludesfile/>
            </fileset>
            <manifest>
                <attribute name="Built-By" value="${builder}" />
                <attribute name="Built-On" value="${build-info.current-date}" />
                <attribute name="Built-At" value="${build-info.current-time}" />
            </manifest>
        </war>
    </target>

</project>

Conclusion

The two files can be used quite easily with any NatJet project. You may need to adapt or delete the clean-context and copy-context-delivery. I will recommend to put in comment their content in a first step because I’m almost sure that at one point you will have to deal with the same problematic. The other parts can be used as there are.