Saturday, February 7, 2015

JAVA EE 6 WAR with MAVEN

Starting with Java EE 6 developers could use WARs instead of EARs. Developers can use WAR-module, which has a compile-scoped dependency to several <packaging>jar</packaging> typed modules. This article presented a simple way to packing multiply WAR modules into only one Web application.


1. Create pom-root(root project) and multiple WAR modules(web-1, web-2, and web-parent projects).


pom.xml of root project is applied to share dependencies to other web projects.

<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/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.blogshot.wittakarn</groupId>
 <artifactId>root</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>pom</packaging>
 <name>root</name>

 <properties>
  <endorsed.dir>
                    ${project.build.directory}/endorsed
                </endorsed.dir>
  <project.build.sourceEncoding>
                    UTF-8
                </project.build.sourceEncoding>

  <!-- Maven Build Plugin Properties -->
  <my.maven.compiler>3.0</my.maven.compiler>
  <my.maven.war>2.4</my.maven.war>

  <!-- Java Properties -->
  <my.java>1.7</my.java>

  <!-- Dependency Properties -->
  <my.org.primefaces>5.1</my.org.primefaces>
  <my.commons.fileupload>1.2.2</my.commons.fileupload>
  <my.commons.io>2.4</my.commons.io>
  <my.maven.resources>2.6</my.maven.resources>

  <!-- Scope provided -->
  <my.javaee.web.api>6.0</my.javaee.web.api>
  <my.mojarra>2.2.6</my.mojarra>

 </properties>

 <build>
 <plugins>
 <plugin>
  <groupId>
   org.apache.maven.plugins
  </groupId>
  <artifactId>
   maven-compiler-plugin
  </artifactId>
  <version>
   ${my.maven.compiler}
  </version>
  <configuration>
   <source>
    ${my.java}
   </source>
   <target>
    ${my.java}
   </target>
   <encoding>
    ${project.build.sourceEncoding}
   </encoding>
   <showDeprecation>
    true
   </showDeprecation>
  </configuration>
 </plugin>

 <plugin>
  <groupId>
   org.apache.maven.plugins
  </groupId>
  <artifactId>
   maven-war-plugin
  </artifactId>
  <version>${my.maven.war}</version>
  <configuration>
   <failOnMissingWebXml>
    false
   </failOnMissingWebXml>
   <attachClasses>true</attachClasses>
   <archiveClasses>true</archiveClasses>
   <archive>
    <manifest>
     <addDefaultImplementationEntries>
      true
     </addDefaultImplementationEntries>
     <addDefaultSpecificationEntries>
      true
     </addDefaultSpecificationEntries>
    </manifest>
   </archive>
  </configuration>
 </plugin>

 <plugin>
  <inherited>true</inherited>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-resources-plugin</artifactId>
  <version>${my.maven.resources}</version>
  <executions>
   <execution>
    <id>copy-resources</id>
    <phase>prepare-package</phase>
    <goals>
     <goal>copy-resources</goal>
    </goals>
    <configuration>
     <outputDirectory>
      ${basedir}/target/classes
     </outputDirectory>
     <resources>
     <resource>
     <directory>
      ${basedir}/src/main/webapp
     </directory>
     <includes>
      <include>**/*</include>
     </includes>
     <excludes>
      <exclude>WEB-INF/**</exclude>
     </excludes>
     <targetPath>
      /META-INF/resources
     </targetPath>
     </resource>

     <resource>
     <directory>
      src/main/resources
     </directory>
     <filtering>true</filtering>
     </resource>

     <resource>
     <directory>
     ${basedir}/src/main/webapp/WEB-INF
     </directory>
     <includes>
      <include>
       faces-config.xml
      </include>
     </includes>
     <targetPath>/META-INF</targetPath>
     </resource>
     </resources>
    </configuration>
   </execution>
  </executions>
 </plugin>
 </plugins>
 </build>

 <dependencies>
  <dependency>
   <groupId>javax</groupId>
   <artifactId>javaee-web-api</artifactId>
   <version>${my.javaee.web.api}</version>
   <scope>provided</scope>
  </dependency>

  <dependency>
   <groupId>commons-fileupload</groupId>
   <artifactId>commons-fileupload</artifactId>
   <version>${my.commons.fileupload}</version>
   <scope>compile</scope>
  </dependency>

  <dependency>
   <groupId>commons-io</groupId>
   <artifactId>commons-io</artifactId>
   <version>${my.commons.io}</version>
   <scope>compile</scope>
  </dependency>

  <dependency>
   <groupId>org.glassfish</groupId>
   <artifactId>javax.faces</artifactId>
   <version>${my.mojarra}</version>
   <scope>provided</scope>
  </dependency>

  <dependency>
   <groupId>org.primefaces</groupId>
   <artifactId>primefaces</artifactId>
   <version>${my.org.primefaces}</version>
   <scope>compile</scope>
  </dependency>

 </dependencies>
</project>

All of web projects(web-1, web-2, and web-parent projects) will reference to root project in order to get dependencies.

pom.xml of web-1 project.

<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/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

  

    <parent>

  <artifactId>root</artifactId>

  <groupId>com.blogshot.wittakarn</groupId>

  <version>0.0.1-SNAPSHOT</version>

 </parent>



    <groupId>com.blogshot.wittakarn.web</groupId>

    <artifactId>web-1</artifactId>

    <version>0.0.1-SNAPSHOT</version>

    <packaging>war</packaging>



    <name>web-1</name>

</project>



pom.xml of web-2 project.

<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/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

  

    <parent>

  <artifactId>root</artifactId>

  <groupId>com.blogshot.wittakarn</groupId>

  <version>0.0.1-SNAPSHOT</version>

 </parent>



    <groupId>com.blogshot.wittakarn.web</groupId>

    <artifactId>web-2</artifactId>

    <version>0.0.1-SNAPSHOT</version>

    <packaging>war</packaging>


    <name>web-2</name>

</project>


2. Including web-1 and web-2 projects inside web-parent project
Developers can include multiple WAR modules by packing as a jar inside another WAR module. In the case of web-1 and web-2 are sub modules of web-parent, develops just include dependency  of web-1 and web-2 as following.

<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/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

   

    <parent>

  <artifactId>root</artifactId>

  <groupId>com.blogshot.wittakarn</groupId>

  <version>0.0.1-SNAPSHOT</version>

 </parent>



    <groupId>com.blogshot.wittakarn.web</groupId>

    <artifactId>web-parent</artifactId>

    <version>0.0.1-SNAPSHOT</version>

    <packaging>war</packaging>



    <name>web-parent</name>

   

    <dependencies>

  <dependency>

   <groupId>com.blogshot.wittakarn.web</groupId>

   <artifactId>web-1</artifactId>

   <version>0.0.1-SNAPSHOT</version>

   <classifier>classes</classifier>

  </dependency>

  <dependency>

   <groupId>com.blogshot.wittakarn.web</groupId>

   <artifactId>web-2</artifactId>

   <version>0.0.1-SNAPSHOT</version>

   <classifier>classes</classifier>

  </dependency>

 </dependencies>



</project>


The dependency hierarchy is shown below.

Dependency Hierachy of web-parent

After developers build root, web-1, web-2, and web-parent respectively. The result of war will show as below figure.

Then the wab-parent-0.0.1-SNAPSHOT.war is ready to deploy on JAVA EE web application server such as Weblogic 12c, Glassfish 3.1.2.2 and so on.

Friday, January 16, 2015

JSF and PrimeFaces: Time Counter For Session Timeout Handling

      In generally, Developers can define their web applications session timeout at the web.xml as following.

web.xml
 <session-config>
  <session-timeout>10</session-timeout>
 </session-config>

      For detection session expired in web application, developers can use HttpSessionListener to detect session's expiration immediately whenever the container invoke the HttpSessionListener#sessionDestroyed event.
The below example is applyed for detecting data in session before timeout.

/**
 *
 * @author Wittakarn
 */
public class SimpleSessionListener implements 
        HttpSessionListener, Serializable {

    @Override
    public void sessionCreated(HttpSessionEvent se) {
        System.out.println("session created : " + se.getSession().getId());
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        HttpSession session = se.getSession();
        UserSession user = (UserSession) session.getAttribute("userSession");

        if(user != null)
            System.out.println("login user :" + user.getUsername());
        
        /*Do some bussiness logic such as save audit logs to db, 
        save logout history, and so on.*/
        
        System.out.println("session destroyed :" + 
                session.getId() + " Logging out user...");
    }
}

      At last, definition session listener in web.xml.
<listener>
  <listener-class>
    com.wittakarn.listener.SimpleSessionListener
  </listener-class>
</listener>


      However, detection session expired by using HttpSessionListener cannot resolve some user's requirements. In the case of requirement, that require to popup dialog for notifing before session out. In this proposed, I would like to present Time Counter For Session Timeout Handling by applying JSF and primefaces 5.1.

index.xhtml

index.xhtml











<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:p="http://primefaces.org/ui">
    <h:head>
        <f:facet name="first">
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
            <meta name="viewport" 
                  content="user-scalable=no, 
                  width=device-width, 
                  initial-scale=1.0, 
                  maximum-scale=1.0"/>
            <meta name="apple-mobile-web-app-capable" content="yes" />
        </f:facet>

        <title>Login</title>
    </h:head>

    <h:body>
        <h:form>
            <p:outputLabel value="user"/>
            <p:inputText value="#{loginBean.user.username}"
                         required="true"/>
            <br/>
            <p:outputLabel value="password"/>
            <p:password value="#{loginBean.user.password}"
                        required="true"/>
            <br/>
            <p:commandButton value="Login" 
                             process="@form" 
                             update="@form"
                             action="#{loginBean.submit}"/>
        </h:form>
    </h:body>
</html>

display.xhtml

display.xhtml












<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:p="http://primefaces.org/ui">
    <h:head>
        <f:facet name="first">
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
            <meta name="viewport" 
                  content="user-scalable=no, 
                  width=device-width, 
                  initial-scale=1.0, 
                  maximum-scale=1.0"/>
            <meta name="apple-mobile-web-app-capable" content="yes" />
        </f:facet>

        <title>Display</title>
    </h:head>

    <h:body>
        <h:form>
            <p:outputLabel value="user "/>
            <p:outputLabel value="#{loginBean.user.username}"/>
            <p:outputLabel value=" login success..."/>

            <p:idleMonitor timeout="5000"
                           onidle="PF('alertExpire').show();">
            </p:idleMonitor>
        </h:form>

        <p:dialog header="Basic Dialog" 
                  widgetVar="alertExpire" 
                  onShow="startIdleMonitor()">
            <h:outputText value="Your browser session is expiring in " />
            <h:outputText id="dialog-countdown" style="font-weight: bold;"/>
            <h:outputText value=" second." />
            <br/>
            <h:outputText value="Do you want to continue your session?" />
            <h:form>
                <p:commandButton value="Yes" 
                                 process="@this" 
                                 update="@all"
                                 onclick="stopCount()"/>
                <p:commandButton value="No" 
                                 process="@this" 
                                 update="@all"
                                 action="#{loginBean.logout}"/>
                <p:remoteCommand name="logout" action="#{loginBean.logout}" />
            </h:form>
            <script type="text/javascript">
                var TIME = 10; // in seconds
                var countTimer = TIME;
                var processTimer;
                var timer_is_on = 0;

                var countDownDiv = "dialog-countdown";
                var txtCountDown = null;
                if (!txtCountDown)
                    txtCountDown = document.getElementById(countDownDiv);

                function startIdleMonitor() {
                    countTimer = TIME;
                    txtCountDown.innerHTML = countTimer;
                    doTimer();
                }
                function timedCount() {
                    txtCountDown.innerHTML = countTimer;
                    if (countTimer == 0) {
                        stopCount();
                        logout();
                        return;
                    }
                    countTimer = countTimer - 1;
                    processTimer = setTimeout("timedCount()", 1000);
                }
                function doTimer() {
                    if (!timer_is_on) {
                        timer_is_on = 1;
                        timedCount();
                    }
                }
                function stopCount() {
                    clearTimeout(processTimer);
                    timer_is_on = 0;
                }
            </script>
        </p:dialog>
    </h:body>
</html>

LoginBean.java
/**
 *
 * @author Wittakarn
 */
@ViewScoped
@ManagedBean(name = "loginBean")
public class LoginBean {
    @ManagedProperty(value = "#{userSession}")
    private UserSession user;

    public UserSession getUser() {
        return user;
    }

    public void setUser(UserSession user) {
        this.user = user;
    }
    
    public String submit(){
        return "display.xhtml";
    }
    
    public String logout(){
        FacesContext.getCurrentInstance()
                .getExternalContext()
                .invalidateSession();
        return "/index.xhtml?faces-redirect=true";
    }
}

UserSession.java
/**
 *
 * @author Wittakarn
 */
@SessionScoped
@ManagedBean(name = "userSession")
public class UserSession implements Serializable{
    private String username;
    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}