February 28, 2010

Using JAX-WS in a Web Archive, as a Servlet, Running on JBoss 5.1

In my previous blog I showed how to get started with JAX-WS in a EJB archieve, in this blog I will show you how to do the same thing, but in a web archive instead, as a Servlet. If you think about it, the two different approaches ends with the same result – a Servlet that answer HTTP request with SOAP content.

Now lets create a simple web archieve with Maven archetype plugin.

$ mvn archetype:create -DgroupId=se.msc.example -DartifactId=ws-web -DarchetypeArtifactId=maven-archetype-webapp


Now lets add EJB dependency and JBoss Maven plugin that will do our deployment work.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 <modelversion>4.0.0</modelVersion>
 <groupid>se.msc.example</groupId>
 <artifactid>ws-web</artifactId>
 <packaging>war</packaging>
 <version>1.0-SNAPSHOT</version>
 <name>ws-web Maven Webapp</name>
 <url>http://www.msc.se/example/ws-web</url>
 <developers>
  <developer>
   <id>magnus.k.karlsson</id>
   <name>Magnus K Karlsson</name>
   <email>magnus.k.karlsson@msc.se</email>
   <organization>MSC</organization>
  </developer>
 </developers>
 <properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  <jboss.home>/home/magnus/applications/jboss-5.1.0.GA-jdk6</jboss.home>
 </properties>
 <dependencies>
  <!-- sun's ejb 3.0 api -->
  <dependency>
   <groupid>javax.ejb</groupId>
   <artifactid>ejb-api</artifactId>
   <version>3.0</version>
   <scope>provided</scope>
  </dependency>
  <!-- jboss logging impl (jboss 5.1.0 GA) -->
  <dependency>
   <groupid>log4j</groupId>
   <artifactid>log4j</artifactId>
   <version>1.2.14</version>
   <scope>provided</scope>
  </dependency>
  <!-- unit testing -->
  <dependency>
   <groupid>junit</groupId>
   <artifactid>junit</artifactId>
   <version>4.7</version>
   <scope>test</scope>
  </dependency>
 </dependencies>
 <build>
  <finalname>ws-web</finalName>
  <plugins>
   <!-- to compile with jdk 1.6 -->
   <plugin>
    <groupid>org.apache.maven.plugins</groupId>
    <artifactid>maven-compiler-plugin</artifactId>
    <version>2.1</version>
    <configuration>
     <source>1.6</source>
     <target>1.6</target>
     <debug>true</debug>
     <debuglevel>lines,vars,source</debuglevel>
     <optimize>true</optimize>
     <showdeprecation>true</showDeprecation>
     <showwarnings>true</showWarnings>
    </configuration>
   </plugin>
            <!-- plugin to harddeploy, hardundeploy, start and stop jboss -->
            <plugin>
                <groupid>org.codehaus.mojo</groupId>
                <artifactid>jboss-maven-plugin</artifactId>
                <version>1.4</version>
                <configuration>
                    <jbosshome>${jboss.home}</jbossHome>
                    <servername>default</serverName>
                    <port>8080</port>
                </configuration>
            </plugin>   
  </plugins>
 </build>
</project>


Then we continue with our Web Service class.

package se.msc.example.ws.web;

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

@WebService
public class PersonServiceBean {

 @WebMethod
    public String getName() {
     return "Magnus K Karlsson";
    }
}


Not that we don't need to define a interface. Then we write our web.xml, that points to our concrete Web Service class.

<?xml version="1.0" encoding="UTF-8"?>
<web-app 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"
 version="2.5">

 <display-name>MSC Demo Web Service</display-name>
 <servlet>
    <servlet-name>PersonServiceBean</servlet-name>
    <servlet-class>se.msc.example.ws.web.PersonServiceBean</servlet-class>
 </servlet>
 <servlet-mapping>
    <servlet-name>PersonServiceBean</servlet-name>
    <url-pattern>/personServiceBean</url-pattern>
 </servlet-mapping>
</web-app>


Finally we need to add the JBoss specific web deployment descriptor. Note the location of the file – src/main/webapp/META-INF/jboss-web.xml, i.e. not in the WEB-INF directory, beside the web.xml.

<?xml version="1.0" encoding="UTF-8"?>
<jboss-web xmlns="http://www.jboss.com/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-web_5_1.xsd"
 version="5.1">
 
 <!-- Read about Schema documentation in $JBOSS_HOME/docs/schema/jboss-web_5_1.xsd -->
</jboss-web>    


Now we are ready to build and deploy our archieve

$ mvn clean install jboss:harddeploy


Then we start our JBoss server and opens a web browser pointing to http://localhost:8080/ws-web/personServiceBean?wsdl and checks that the web service is working. Instead of building a web service client by hand, we use the soapUI tool.

 

 

Now soapUI has created us a testcase that we can double click and click the green play button on.

February 25, 2010

How To See Expiration Date and other Information of a p12 File (PKCS12).

Sooner or later your client or server certificate will expire and it will be nice to update that before it really happens, but to do that you need to know how to get that information. In this blog I will show you how to do that in a Linux environment with openssl, that is a typical scenario when the certificate is located on a remote Linux server that you access with ssh.

First thing to do is to convert the p12 file (PKCS12 format) to X509 format, to do so we use the openssl command.

$ openssl pkcs12 -in maka.p12 -info


When prompted enter the password. Now is the content printed out, find out which CN (Common Name) that is for the server, typically it is the dns name of the server. After located the certificate then copy everything between the below start and end tag,

-----BEGIN CERTIFICATE-----
The content to copy...
-----END CERTIFICATE-----


Past the copied content into a file with prefix .crt. If you were on a Windows system you could now simple double click the crt-file and the information of the certification would be display, but here we will continue using openssl. To use openssl, use the below command using the file name of the file you pasted the certificate into.

$ openssl x509 -in <your_file.crt> -inform PEM -text


Now is the expiration date printed among other information.

February 21, 2010

Configure Apache Web Server as Reverse Proxy in front of a Tomcat or J2EE Container

One production like scenario when using SSL or load balancing is to use a Apache Web Server in front of a Java Web Container or J2EE Container. There are two ways to make the Apache Web Server and the behind Java container – mod_proxy or mod_jk. In this blog I will show you how to use the mod_proxy alternative, acting as a reverse proxy. I will also use Ubuntu to show you how easy there is to install software on Ubuntu with Synaptic Package Manager.

The first thing to do is to install Apache Web Server and the Tomcat Container.

$ sudo apt-get install apache2 tomcat6


After installing the above software you can use the apache2ctl command to view the active sites configuration

$ sudo apache2ctl -S


or you can also list the files in /etc/apache2/sites-enabled

$ ls -al 
lrwxrwxrwx 1 root root   26 2010-02-19 07:34 000-default -> ../sites-available/default 


Before continue you can also check that everything is working by open a web browser and open http://localhost/ (Apache Web Server) and http://localhost:8080/ (Tomcat)

Now we go ahead and creating a new virtual host that is going to act as reverse proxy.

$cd /etc/apache2/sites-available 
$ sudo gedit customerapp


<virtualhost *:80="">
    ServerName customerapp.msc.se
    ServerAlias *.customer.msc.se
    ProxyRequests Off
    <proxy *="">
        Order deny,allow
        Allow from all
    </proxy>
    ProxyPass / http://localhost:8080/examples/
    ProxyPassReverse / http://localhost:8080/examples/
</virtualhost>


After creating the new site we need to link it from sites-enabled, either use ln -s or you can use the apache tool – a2ensite.

$ sudo a2ensite customerapp


With the configuration in place, you need to separate the virtual host in customapp and default. For a locale environment you can separate them by using different IP – 127.0.0.1 and your computer IP.

<virtualhost 192.168.1.4:80="">
<virtualhost 127.0.0.1:80="">


The last thing before restarting the Apache Web Server is to install proxy and proxy_http modules you can do that with the Apache tool a2enmod

$ sudo a2enmod proxy
$ sudo a2enmod proxy_http


And finally you need to restart the Apache Web Server.

$ sudo /etc/init.d/apache2 restart

February 18, 2010

Getting Started with JBoss Web Serivce using JAX-WS on JBoss 5.1 using Maven, OpenEJB and eviware soapUI

The easiest way to get started with writing Web Service is using Java API for XML Web Service, JAX-WS. The downside with this is that the creation of the WSDL file is automatic, and that is not the preferred way of writing cross platform independent web service. If that is your design goal, you should handwrite the WSDL, i.e. contract first. But if you know that the only clients are going to be Java client, than automatically generating the WSDL could be fine.

A good practice when writing all kind of code, is to make the code testable and also make it testable outside the container. To achieve that I will use OpenEJB, if have never heard or used OpenEJB and you are writing EJB 3.0 applications, it is definitely worth the time to check it out.

Lets start with writing a standard Stateless EJB.

package se.msc.example.jbossws;

import javax.ejb.Remote;
import javax.jws.WebService;

@Remote
public interface HelloService {

 public String sayHello();
}


package se.msc.example.jbossws;

import javax.ejb.Stateless;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;

@Stateless
public class HelloServiceBean implements HelloService {

 @Override
 public String sayHello() {
  return "Hello World.";
 }
}


src/main/resources/META-INF/ejb-jar.xml
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar 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/ejb-jar_3_0.xsd"
 version="3.0">

</ejb-jar>


src/main/resources/META-INF/jboss.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- 
<jboss xmlns="http://www.jboss.com/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss_5_1.xsd"
       version="3.0"> 
-->
<jboss>       
 
</jboss>


pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 <modelversion>4.0.0</modelVersion>
 <groupid>se.msc.example</groupId>
 <artifactid>jbossws</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>ejb</packaging>
 <name>JBoss WS Test</name>
 <url>http://www.msc.se/example/jbossws</url>
 <developers>
  <developer>
   <id>magnus.k.karlsson</id>
   <name>Magnus K Karlsson</name>
   <email>magnus.k.karlsson@msc.se</email>
   <organization>MSC</organization>
  </developer>
 </developers>
 <repositories>
  <repository>
   <id>repository.jboss.org</id>
   <name>Jboss Repository for Maven</name>
   <url>http://repository.jboss.org/maven2/</url>
  </repository>
 </repositories>
 <pluginrepositories>
  <pluginrepository>
   <id>repository.jboss.org</id>
   <name>Jboss Repository for Maven</name>
   <url>http://repository.jboss.org/maven2/</url>
  </pluginRepository>
 </pluginRepositories>
 <properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <jboss.home>/home/magnus/applications/jboss-5.1.0.GA-jdk6</jboss.home>
 </properties>
 <dependencies>
  <!-- sun's ejb 3.0 api -->
  <dependency>
   <groupid>javax.ejb</groupId>
   <artifactid>ejb-api</artifactId>
   <version>3.0</version>
   <scope>provided</scope>
  </dependency>
  <!-- jboss logging impl (jboss 5.1.0 GA) -->
  <dependency>
   <groupid>log4j</groupId>
   <artifactid>log4j</artifactId>
   <version>1.2.14</version>
   <scope>provided</scope>
  </dependency>
  <!-- unit testing -->
  <dependency>
   <groupid>junit</groupId>
   <artifactid>junit</artifactId>
   <version>4.7</version>
   <scope>test</scope>
  </dependency>
 </dependencies>
 <build>
  <finalname>jbossws-example</finalName>
  <plugins>
   <!-- to compile with jdk 1.6 -->
   <plugin>
    <groupid>org.apache.maven.plugins</groupId>
    <artifactid>maven-compiler-plugin</artifactId>
    <version>2.1</version>
    <configuration>
     <source>1.6</source>
     <target>1.6</target>
    </configuration>
   </plugin>
   <!-- ejb 3.0 plugin -->
   <plugin>
    <groupid>org.apache.maven.plugins</groupId>
    <artifactid>maven-ejb-plugin</artifactId>
    <version>2.2</version>
    <configuration>
     <ejbversion>3.0</ejbVersion>
    </configuration>
   </plugin>
   <!-- plugin to harddeploy, hardundeploy, start and stop jboss -->
   <plugin>
    <groupid>org.codehaus.mojo</groupId>
    <artifactid>jboss-maven-plugin</artifactId>
    <version>1.4</version>
    <configuration>
     <jbosshome>${jboss.home}</jbossHome>
     <servername>default</serverName>
     <port>8080</port>
    </configuration>
   </plugin>
  </plugins>
 </build>
</project>


Now lets test our EJB with OpenEJB. The first thing we need to do, is to add the OpenEJB dependency to our pom.xml

  <dependency>
   <groupid>org.apache.openejb</groupId>
   <artifactid>openejb-core</artifactId>
   <version>3.1.2</version>
   <scope>test</scope>
  </dependency>


Then we write our JUnit test case.

package se.msc.example.jbossws;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class HelloServiceStatelessTest {
 private InitialContext ctx;

 @BeforeClass
 public static void oneTimeSetUp() throws Exception {
 }

 @AfterClass
 public static void oneTimeTearDown() throws Exception {
 }

 @Before
 public void setUp() throws Exception {
  Properties prop = new Properties();
  prop.setProperty(Context.INITIAL_CONTEXT_FACTORY,
    "org.apache.openejb.client.LocalInitialContextFactory");
  ctx = new InitialContext(prop);
 }

 @After
 public void tearDown() throws Exception {
 }

 @Test
 public void testSayHello() throws Exception {
  Object obj = ctx.lookup("HelloServiceBeanRemote");
  assertNotNull(obj);
  assertTrue(obj instanceof HelloService);
  HelloService remote = (HelloService) obj;
  assertEquals("Hello World.", remote.sayHello());
 }
}


After verifying that our Stateless Session Bean is working, we now continue to deploy it to the JBoss container.

$ mvn clean install jboss:harddeploy


We start our JBoss container and checks that the EJB is successfully deployed.

Now lets add Web Service support to our EJB.

package se.msc.example.jbossws;

import javax.ejb.Remote;
import javax.jws.WebService;

@Remote
@WebService(targetNamespace = "http://www.msc.se/examples/jbossws/wsdl")
public interface HelloService {

 public String sayHello();
}


package se.msc.example.jbossws;

import javax.ejb.Stateless;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;

@Stateless
@WebService(serviceName = "HelloService", 
  targetNamespace = "http://www.msc.se/examples/jbossws/wsdl", 
  endpointInterface = "se.msc.example.jbossws.HelloService")
@SOAPBinding(style = Style.DOCUMENT)
public class HelloServiceBean implements HelloService {

 @Override
 public String sayHello() {
  return "Hello World.";
 }
}


Now lets write our JUnit test case, to test our web service outside the JBoss container.

package se.msc.example.jbossws;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import java.net.URL;
import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class HelloServiceWebServiceTest {
 private InitialContext ctx;

 @BeforeClass
 public static void oneTimeSetUp() throws Exception {
 }

 @AfterClass
 public static void oneTimeTearDown() throws Exception {
 }

 @Before
 public void setUp() throws Exception {
  Properties prop = new Properties();
  prop.setProperty(Context.INITIAL_CONTEXT_FACTORY,
    "org.apache.openejb.client.LocalInitialContextFactory");
  prop.setProperty("openejb.embedded.remotable", "true");
  ctx = new InitialContext(prop);
 }

 @After
 public void tearDown() throws Exception {
 }

 @Test
 public void testWebService() throws Exception {
  Service service = Service.create(
    new URL("http://127.0.0.1:4204/HelloServiceBean?wsdl"), 
    new QName("http://www.msc.se/examples/jbossws/wsdl", "HelloService"));
  assertNotNull(service);
  HelloService hello = service.getPort(HelloService.class);
  assertEquals("Hello World.", hello.sayHello());
 }
}


Before running the testcase we need to update our pom.xml with a concrete web service implementation.

  <dependency>
   <groupid>org.apache.openejb</groupId>
   <artifactid>openejb-cxf</artifactId>
   <version>3.1.2</version>
   <scope>test</scope>
  </dependency>


After running the testcase from withing Eclipse, we can now be confident that we our is executing as expected. Now lets deploy our EJB to the JBoss container.

$ mvn clean install jboss:harddeploy


If you have stopped the JBoss, then restarted and verify that everything is looking healthy in the server log. Verify that the web service is working by firing up a web browser and go to http://localhost:8080/jbossws-example/HelloServiceBean?wsdl, to verify that you see the wsdl file.

Instead of writing a web service client, we are going to use a good test tool for testing web service – eviware soapUI. Start the soapUI and then select new project.

 

  

 

February 17, 2010

Viewing/Monitoring your Log4j Generated Log File with Chainsaw

Chainsaw is a open source tool for viewing and/or monitoring Log4j generating system. But the documentation on the homepage lack some explanation how to get started. To begin with maybe the simplest scenario, to view a log4j generated log file. The first thing one might misunderstand is that you need to defines a new configuration file for Chainsaw, so just pointing to your log4j.xm configuration file is not enough. Lets start with a example.

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE log4j:configuration PUBLIC "-//log4j/log4j Configuration//EN" "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

 <appender name="FILE_APPENDER" class="org.apache.log4j.RollingFileAppender">
  <param name="File" value="/tmp/server.log" />


  <param name="Append" value="true" />


  <layout class="org.apache.log4j.PatternLayout">
   <param name="ConversionPattern" value="%d %-5p [%t] %C{2} (%F:%L) - %m%n" />


  </layout>
 </appender>

 <logger name="se.msc.example.log4j.ChainsawTest">
  <level value="DEBUG" />
 </logger>

 <root>
  <level value="ERROR" />
  <appender-ref ref="FILE_APPENDER" />
 </root>

</log4j:configuration>


And the configuration file for Chainsaw.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration PUBLIC "-//log4j/log4j Configuration//EN" "log4j.dtd"> 
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="true">

   <plugin name="logFileReceiver" class="org.apache.log4j.varia.LogFilePatternReceiver">
     <param name="fileURL" value="file:///tmp/server.log" />
     <param name="timestampFormat" value="yyyy-MM-d HH:mm:ss,SSS"/>
     <param name="logFormat" value="TIMESTAMP LEVEL [THREAD] CLASS (FILE:LINE) - MESSAGE"/>
     <param name="name" value="Reciever-name-in-Chainsaw" />
     <param name="tailing" value="true" />
   </plugin>
   <root>
      <level value="debug"/>
   </root>
</log4j:configuration>


Before we open Chainsaw lets write a small test program, that generates some log post, so we have something to view.

package se.msc.example.log4j;

import org.apache.log4j.Logger;
import org.junit.Test;

public class ChainsawTest {
 private static final Logger log = Logger.getLogger(ChainsawTest.class);
 
 @Test
 public void test() throws Exception {
  log.debug("DEBUG text");
  log.info("INFO text");
  log.warn("WARN text");
  log.error("ERROR text");
 }
}


Now lets open Chainsaw. When first starting Chainsaw you are prompted to define a Receiver. Here we select our configuration file.



After selecting our Chainsaw configuration file, Chainsaw opens our log file in a new tab.



You might have already noticed the different formatting of logFormat attribute, compared with the Log4j and it is a question to me why they have done that. You can read more about the format in the LogFilePatternReceiver Javadoc.

February 14, 2010

Sending Log Errors with Log4j and SMTPAppender

Log4j comes with several Appenders and if you like to send mail notification if severe errors occur the you will be pleased to see, that Log4j comes with a SMTPAppender, but there are some pitfalls when using the SMTP appender:
  • The SMTP apppender does not out of the box support a different SMTP port.
  • Using secure connection, such as SSL or TLS.
  • The derived standardized method setThreshold is ignored, and replaced with TriggeringEventEvaluator class.
Configure SMTP appender to use a different port, than the default 25
If your mailserver is configured to answer on a different port than the default 25 for SMTP, you need to configure the underlying javax.mail.Session property "mail.smtp.port". But when looking at the API for SMTPAppender you see no set method for that. What to do? Writing you own extended log4j class? No, that is not neccessary. If you look at the source code of SMTPAppender, you see the following in the createSession():

Properties props = new Properties (System.getProperties());


These means that SMTPAppender is reading system properties, which means you can add the following argument when starting you application.

$ -Dmail.smtp.port=587


This is a not gracefefully way, and sometimes also not applicable, because you are not in charge of the deployment environment. And what happens when you have two different application hosted on the same server, that wants to use different ports?
There is also the oppurtunity to do it programmatically:

System.setProperty("mail.smtp.port", "587");


This has also drawbacks. For examaple if your application is a J2EE application or a web application your code is not the main start class. You can of course always write a boot strap class, but what happens when you have several bootstrap classes, then things starts to get more hard to overlook for a more junior programmer.

Another way if you have problems settings the System Property is to create a class that implements the interface org.apache.log4j.spi.TriggeringEventEvaluator and there set the system properties and then in your log4j properties or xml file override the default EvaluatorClass for SMTPAppender. This is a little hacky, but it will get the work done and it keeps your code clean from log4j configuration code that should in the first place be placed in the log4j configration file.

Also what is lacking is, if you are deploying to a container you might want to define your java.mail.Session properties in the container and then bind them to JNDI, then it should be nice if Log4j could read these property from JNDI, but that is not possible.

Using Secure Connection
The next problem comes when your mailserver uses secure connection as TLS or SSL, then you need to add the following javax.mail.Session properties:

System.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
System.setProperty("mail.smtp.socketFactory.port", "465");
System.setProperty("mail.smtp.socketFactory.fallback", "false");


Bellow follows the source code for the example.
# configure the root logger
log4j.rootLogger=INFO, STDOUT

# configure the console appender
log4j.appender.STDOUT=org.apache.log4j.ConsoleAppender
log4j.appender.STDOUT.Target=System.out
log4j.appender.STDOUT.layout=org.apache.log4j.PatternLayout
log4j.appender.STDOUT.layout.conversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} [%p] %c:%L - %m%n

log4j.logger.se.msc.examples.log4j.Log4jNoSecureConnectionTest=ERROR, SMTP_NO_SECURE_CONNECTION

log4j.appender.SMTP_NO_SECURE_CONNECTION.layout=org.apache.log4j.SimpleLayout
log4j.appender.SMTP_NO_SECURE_CONNECTION=org.apache.log4j.net.SMTPAppender
#log4j.appender.SMTP_NO_SECURE_CONNECTION.Bcc=
# the maximum number of logging events to collect in a cyclic buffer
log4j.appender.SMTP_NO_SECURE_CONNECTION.BufferSize=1
#log4j.appender.SMTP_NO_SECURE_CONNECTION.Cc=
log4j.appender.SMTP_NO_SECURE_CONNECTION.From=system.alert@examples.msc.se
log4j.appender.SMTP_NO_SECURE_CONNECTION.LocationInfo=true
log4j.appender.SMTP_NO_SECURE_CONNECTION.SMTPDebug=true
log4j.appender.SMTP_NO_SECURE_CONNECTION.SMTPHost=smtp.XXX.se
log4j.appender.SMTP_NO_SECURE_CONNECTION.SMTPPassword=YYY
log4j.appender.SMTP_NO_SECURE_CONNECTION.SMTPUsername=ZZZ
log4j.appender.SMTP_NO_SECURE_CONNECTION.Subject=System Alert NO SECURE CONNECTION
log4j.appender.SMTP_NO_SECURE_CONNECTION.To=DDD

log4j.logger.se.msc.examples.log4j.Log4jTLSTest=ERROR, SMTP_TLS

log4j.appender.SMTP_TLS.layout=org.apache.log4j.SimpleLayout
log4j.appender.SMTP_TLS=org.apache.log4j.net.SMTPAppender
#log4j.appender.SMTP_TLS.Bcc=
# the maximum number of logging events to collect in a cyclic buffer
log4j.appender.SMTP_TLS.BufferSize=1
#log4j.appender.SMTP_TLS.Cc=
log4j.appender.SMTP_TLS.From=system.alert@examples.msc.se
log4j.appender.SMTP_TLS.LocationInfo=true
log4j.appender.SMTP_TLS.SMTPDebug=true
log4j.appender.SMTP_TLS.SMTPHost=smtp.gmail.com
log4j.appender.SMTP_TLS.SMTPPassword=FOO
log4j.appender.SMTP_TLS.SMTPUsername=foo.bar@gmail.com
log4j.appender.SMTP_TLS.Subject=System Alert TLS
log4j.appender.SMTP_TLS.To=foo.bar@gmail.com



package se.msc.example.log4j;

import org.apache.log4j.Logger;
import org.junit.Test;

public class Log4jNoSecureConnectionTest {
 private static final Logger log = Logger.getLogger(Log4jNoSecureConnectionTest.class);
 
 @Test
 public void testFoo() throws Exception {
  // Either set smtp properties programmatically or via JVM argument -D
  System.setProperty("mail.smtp.port", "587");
  log.error("Fatal log message.", new NullPointerException("Null pointer exceptopn."));
 }

}



package se.msc.example.log4j;

import org.apache.log4j.Logger;
import org.junit.Test;

public class Log4jTLSTest {
 private static final Logger log = Logger.getLogger(Log4jTLSTest.class);
 
 @Test
 public void testFoo() throws Exception {
  // Either set smtp properties programmatically or via JVM argument -D
  System.setProperty("mail.smtp.port", "465");
  System.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
  System.setProperty("mail.smtp.socketFactory.port", "465");
  System.setProperty("mail.smtp.socketFactory.fallback", "false");
  log.error("Fatal log message.", new NullPointerException("Null pointer exceptopn."));
 }

}



<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

 <modelVersion>4.0.0</modelVersion>
 <groupId>se.msc.example</groupId>
 <artifactId>log4j</artifactId>
 <packaging>jar</packaging>
 <version>1.0-SNAPSHOT</version>
 <name>Log4J Test</name>
 <url>http://www.msc.se/example/log4j</url>

 <developers>
  <developer>
   <id>magnus.k.karlsson</id>
   <name>Magnus K Karlsson</name>
   <email>magnus.k.karlsson@msc.se</email>
   <organization>MSC</organization>
  </developer>
 </developers>

 <properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 </properties>

 <dependencies>
  <dependency>
   <groupId>log4j</groupId>
   <artifactId>log4j</artifactId>
   <version>1.2.15</version>
  </dependency>
  <!-- sun java mail -->
  <dependency>
   <groupId>javax.mail</groupId>
   <artifactId>mail</artifactId>
   <version>1.4.1</version>
  </dependency>  
  <!-- unit testing -->  
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.7</version>
   <scope>test</scope>
  </dependency>
 </dependencies>

 <build>
  <plugins>
   <!-- to compile with JDK 1.6 -->
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
     <source>1.6</source>
     <target>1.6</target>
    </configuration>
   </plugin>
  </plugins>
 </build>

</project>

February 1, 2010

Java Generics Example Strategy Pattern

With Java Generics Java has continued its path to make it's language more strong typed, with comparison to all new dynamic language where they have thrown out strong typing. But Java Generics can also be hard to understand and one of the best example to show the main benefit with it is the strategy pattern. Lets start to look of a example.


If we were using Java JDK 1.4 we have to do down-casting in the concrete strategy classes, but with Generics that is not necessary.

The Strategy Context/Client
package se.msc.examples.generics;

public abstract class Data<D extends Data<D>> {
 public static final Strategy<FooData> FOO_STRATEGY = new FooStrategy();
 public static final Strategy<BarData> BAR_STRATEGY = new BarStrategy(); 
}


The Strategy itself
package se.msc.examples.generics;

public abstract class Strategy<D extends Data<?>> {
 public abstract String exec(D data); 
}



And the extended Data classes
package se.msc.examples.generics;

public class FooData extends Data<FooData> {
 public final double value; 
 
 public FooData(double value) {
  this.value = value;
 }

 public double getValue() {
  return value;
 }
}


And the extended Strategy
package se.msc.examples.generics;

public class FooStrategy extends Strategy<FooData> {

 public String exec(FooData data) {
  return "Hi " + data.getValue();
 }
}


And our test class.
package se.msc.examples.generics;

import static org.junit.Assert.*;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class StrategyTest {

 @BeforeClass
 public static void oneTimeSetUp() throws Exception {
 }

 @AfterClass
 public static void oneTimeTearDown() {
 }

 @Before
 public void setUp() throws Exception {
 }

 @After
 public void tearDown() throws Exception {
 }

 @Test
 public void testFooStrategy() throws Exception {
  assertEquals("Hi 3.0", Data.FOO_STRATEGY.exec(new FooData(3)));
 }
}