Sunday, December 28, 2014

EE Servlet 3: Getting started with web application module and a landing page

Getting started with Servlet 3

Web application module in Java EE is probably the most common type of application module that a developer would encounter and work on. That's because not only it can provide users the UI, but it also supoprt many common web application patterns: Model View Controller, Filter, Session, Context Listener, Http Request, Paramters, Query, and Form handling, Http Response writer, redirect, error etc. You can do all these with Servlet spec alone, so getting to know it well is an important part of learning in writing good web application.

Servlet has been around for a long time, and many developers are already familiar with it. There are many other web frameworks such as Tapestry or Spring MVC that are built on top of Servlet. These frameworks provide separate programming models that suppose to easy development process, but nontheless the core concept is still based on the Servlet technologies (or at least tightly integrated if it were to run by any web container server). In this post, I will try to highlight how to get a web module application started, and configure a typical need: a default landing page.

Hello World

Like many things in EE environment, you would write small components as Java class and then deploy them onto a server and let the server manage it's lifecycle and execution. So as with Servlet, you would write a simple Java class that implements Servlet interface, package it and deploy, and server will do it's magic.

Before Servlet 3.0, your servlet component is configured and mapped in web.xml file, but now you can just add an annotation directly on your servlet class and the app server should be able to automatically deploy and run it. Here is an example of a classic hello world.

package zemian.servlet3example.web;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        PrintWriter writer = resp.getWriter();
        writer.println("<!DOCTYPE html>");
        writer.println("<html>");
        writer.println("<body>");
        writer.println("<p>Hello World!</p>");
        writer.println("</body>");
        writer.println("</html>");
    }
}

In this Servlet, I simply extends an existing base HttpServlet class that should be available in all Serlvet spec. and in response to a http GET request, I write a Hello World message out as html response.

You may find above code in servlet3-example. Build and deploy it and then you can access it with http://localhost/servlet3-exmaple/hello. (I have many other servlet examples in the project, but you may just concentrate in this class for now.)

How to configure a default landing page in Servlet 3

A typical application server will likely default a landing page to "index.html" or "index.jsp" if it exists. For example, if I have written a IndexSerlvet class and mapped to "/index" instead, then you need to tell the server default to there. This will happen if users only type http://localhost/servlet3-example with context path in URL only.

Despite you can can do just about most things in Java annotations with Servlet 3.0 as equivalent to the content found web.xml file, but not the welcome file though. So to do this, you would still need to create this good old web.xml. Here is an example

<web-app 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_3_0.xsd"
         version="3.0">
    <welcome-file-list>
        <welcome-file>index</welcome-file>
    </welcome-file-list>
</web-app>


Above example will default the landing page to a Servlet url mapping with "/index" path.

TIPS: Do NOT to use "/" prefix when definining welcome-file element, else you will get a page not found error and likely your server won't even print any error message in the log!

Another alternate solution instead of overrite welcome-file is simply add a "index.jsp" file in root of webapp folder and do a redirect like this:

<% response.sendRedirect(request.getContextPath() + "/index"); %>


Monday, December 22, 2014

Developing Java EE applications with Maven, NetBeans and Glassfish

I have been working with EE 6 stack lately, and I find it quite pleasant and productive. For my own learning purpose, I intend to explore more deeper on some of the major components available on the EE stack.

I have started a java-ee6-examples project in GitHub, and I plan to add my examples and working demo code there, along with some blog posts whenever I can. The project is seperated into sub-modules that a typical EE application would organized: a parent module, a common library jar module and one or more web modules etc. The project is buildable using Maven 3 tool on command line, and you may use any major IDE that supports Maven (I will try out NetBeans for these demos).

I will also be testing my examples application mainly on Glassfish Server. Glassfish Server is an open source EE application server, and its current 4.x release supports EE 7 already (GF 3.x is for EE 6). We should able to run any EE 6 applications on GF 4.x without much problems, so for my learning purpose, I will restrict my examples to use EE 6 for now (you will notice that I have to set EE 6 version as dependency in Maven pom file!)

So if you are interested in these, watch this blog for future updates.

To help you started with EE development, I jot down few useful links here.

Downloads:
JDK 7
NetBeans IDE
Glassfish Application Server 
(Oracle also provides convenient package download that includes all 3 above!)

References:
EE 6 Tutorial
EE 6 Technologies
EE 6 API
JDK 7 API


Thursday, December 18, 2014

Writing your own logging service?

Application logging is one those things like favorite Editors war: everyone has their own opinions and there are endless of implemenations and flavors out there. Now a days, you likely would want to use something already available such as Log4j or Logback. Even JDK has a built in "java.util.logging" implementation. To avoid couple to a direct logger, many projects would opt to use a facade interface, and there is already couple good ones out there already, such as SLF4J or Apache Common Logging etc.

Despite all these, many project owners still want to try write their own logger service! I wondered if I were to ask and write one myself, what would it be like? So I played around and come up with this simple facade that wraps one of the logger provider (JDK logger in this case), and you can check it out here. With my logger, you can use it like this in your application:

 import zemian.service.logging.*;
 class MyService {
   static Log LOG = LogFactory.createLog(MyService.class);
   public void run() {
    
LOG.info(Message.msg("%s service is running now.", this));
   }
 }


Or you can use the Logger wrapper to avoid many imports:
 import zemian.service.logging.Logger;
 class MyService2 {
   static
Logger LOGGER = new Logger(MyService2.class);
   public void run() {
    
LOGGER.info("%s service is running now.", this);
   }
 }


Some principles I followed when trying this out:
  • Use simple names for different level of messages: error, warn, info, debug and trace (no crazy fine, finer and finest level names.)
  • Seperate Log service from implementation so you can swap provider.
  • Uses Message logging POJO as data encapsulation. It simplifies the log service interface.
  • Use log parameters and lazy format binding to construct log message to speed performance.
Do not go crazy with logging service implemenation make it complex. For example I recommend NOT to mix business logic or data in your logging if possible! If you need custom error codes to be logged for example, you can write your own Exception class and encapsulate there, and then let the logging service do its job: just logging.

Here are some general rules about using logger in your application that I recommend:
  •  Use ERROR log messages when there is reallyl a error! Try not to log an "acceptable" error message in your application. Treat an ERROR as critical problem in your application, like if it's in production, some one should be paged to take care of the problem immediately. Each message should have a full Java stacktrace! Some application might want to assign a unique Error Code to these level of messages for easier identification and troubleshoot purpose.
  • Use WARN log messages if it's a problem that's ignorable during production operation, but not good idea to supress it. Likely these might point to potentially problem in your application or env. Each message should have a full Java stacktrace, if available that is!
  • Use INFO log messages for admin operators or application monitors peoples to see how your application is doing. High level application status or some important and meaningful business information indicators etc. Do not litter your log with developer's messages and unessary verbose and unclear message. Each message should be written in clear sentence so operators knows it's meaningful.
  • Use DEBUG log messages for developers to see and troubleshoot the application. Use this for critical application junction and operation to show objects and services states etc. Try not to add repeated loop info messages here and litter your log content.
  • Use TRACE log message for developers to troubleshoot tight for loop and high traffic messages information.
  • You should select a logger provider that let you configure and turn these logging levels ON or OFF (preferrable at runtime if possible as well). Each level should able to automatically suppress all levels below it. And ofcourse you want a logger provider that can handle log message output to STDOUT and/or to FILE as destination as well.

Thursday, December 11, 2014

Getting started with Glassfish Server and Setting up SLF4J logging

Some notes I jot down while playing with GlassFish Server (3) for EE 6. You may get a working example here: https://github.com/saltnlight5/java-ee6-examples/tree/master/extra/glassfish-logging-example

= Gettin started with Glassfish server

== Start server

1. cd $GF/bin
2. asadmin start-domain domain1

== Stop server

1. cd $GF/bin
2. asadmin stop-domain domain1

== Server Ports

Admin Console Application is at http://localhost:4848
 * Default setup has no user and password restriction!

Web applications is http://localhost:8080

== To create a new domain with diferent ports

1. cd $GF/bin
2. asadmin create-domain --portbase 9000 domain2

* If you accept default then again no password for admin user. After this, your
  admin console app is at http://localhost:9048 while your application is at
  http://localhost:9080

= Glassfish Server Setup

== How to setup SLF4J

1. Copy slf4j-api and slf4j-jdk jars into $GF/lib/endorsed
2. Edit $GF/domains/domain1/config/logging.properties and add your own logging package level
 mypackage.level=FINEST

== How to enable JSTL tag for all web applications

1. Copy jstl-1.2.jar into $GF/domains/domain1/lib

== How to add MySQL Driver for all applications

1. Copy mysql-connector-java-5.1.30-bin.jar into $GF/domains/domain1/lib

Tuesday, December 2, 2014

How to secure a web application by the app server container

There are many benefits to allow a container in managing users, groups and authentication policies. You may configure your WAR application to take advantage of this by adding the following in the WEB-INF/web.xml file

   <security-constraint>
        <web-resource-collection>
            <web-resource-name>webuser</web-resource-name>
            <url-pattern>/*</url-pattern>

        </web-resource-collection>
        <auth-constraint>
            <role-name>webuser</role-name>
        </auth-constraint>
    </security-constraint>
    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>default</realm-name>
    </login-config>
    <security-role>
        <role-name>webuser</role-name>
    </security-role>


Above will secure the entire application and allow only users with "webuser" role to access it. The name "webuser" can be any name you want.

Each app server will manage users differently. In the case of WLS, it lets you create "user" and "user group", and then you can map the defined role above to the group. To do this, add the following to the  WEB-INF/weblogic.xml file.

<weblogic-web-app
    xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.oracle.com/weblogic/weblogic-web-app
        http://xmlns.oracle.com/weblogic/weblogic-web-app/1.2/weblogic-web-app.xsd">

    <security-role-assignment>
        <role-name>webuser</role-name>
        <principal-name>webusergroup</principal-name>
    </security-role-assignment>
</weblogic-web-app>


Here we tell WLS that we map the "webuser" role defined in web.xml to use the "webusergroup", a WLS user group.

To create  user or user group in WLS, you may use the WLS Admin console web application. Go to the Security Realm and select the default "myrealm", and then select User or Group tab. Go ahead and add a user with password under a new group named "webusergroup". After this you can deploy your app, and it would prompt you for user and password whenever you try to access its URL.

You can find out more security info at https://docs.oracle.com/cd/E23943_01/web.1111/e13711/thin_client.htm#SCPRG171.