martes, 29 de mayo de 2018

01. Create a Java 10 project with Maven and JSF

1. Introduction

It is required :

  • Open JDK 10.x
  • Lombok
  • Eclipse Oxygen 3a (4.7.3a)
  • WTP Update 3.9.4 (Due to a bug when using Java>8 with Tomcat that uses the forbidden  "endorsed dirs".
  • Tomcat 9.08 

2. Installation

  • Download and install Open JDK10 as teaches Wesam in StackOverflow.
  • Download and install Eclipse Oxygen. Now you can use Eclipse Photon.
  • Download and execute Lombok.jar (version 1.18) and search for your eclipse installation
  • If your have Eclipse Oxygen then Update to WTP 3.9.4 in Eclipse (Help > Install New Software > Work with: http://download.eclipse.org/releases/oxygen/ 
  • Download and install Tomcat 9.

3. Create an Eclipse Maven Project

1) File > New > Maven Project

2) Check only:
    🗹 Create a simple project (skip archetype selection).
    🗹 Use default Workspace location.
    Press Next

3) Fill these fields (I have used these values. But don't forget to select war packaging!)
    Group Id: ximodante
    Artifact Id: DantePmf
    Packaging : war
    Name : DantePmf
    Description: Dante's Primefaces project
    Press Finish

4. Edit the pom.xml file so that we can use:

  • an
  • Hibernated 
  • JSF
  • XML and other stuff that has been omitted in Java>8
  • Lombok...


<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>ximodante</groupId>
  <artifactId>DantePmf</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  <name>DantePmf</name>
  <description>Dante's Primefaces project</description>
  
  <properties>
   
    <failOnMissingWebXml>false</failOnMissingWebXml>
    
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    
    <maven.compiler.plugin>3.7.0</maven.compiler.plugin>
    <maven.compiler.source>10</maven.compiler.source>
    <maven.compiler.target>10</maven.compiler.target>
    
    
    <hibernate.version>5.2.16.Final</hibernate.version>
    <jaxb.version>2.3.0</jaxb.version>
    <activation.version>1.2.0</activation.version>
    <jackson.version>2.9.5</jackson.version>

  </properties>
  
  <dependencies>
  
    <!-- 2018-04 Java Servlet API-->    
    <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
      <scope>provided</scope>
    </dependency>
    
         
    <!-- 2018-03-29 JSF Mojarra 2.4.0 -->
    <!-- https://mvnrepository.com/artifact/org.glassfish/javax.faces -->
    <dependency>
      <groupId>org.glassfish</groupId>
      <artifactId>javax.faces</artifactId>
      <version>2.4.0</version>
    </dependency>
    

    <!-- 2018-02-28 Primefaces -->
    <!-- https://mvnrepository.com/artifact/org.primefaces/primefaces -->
    <dependency>
      <groupId>org.primefaces</groupId>
      <artifactId>primefaces</artifactId>
      <version>6.2</version>
    </dependency>

    <!-- Primefaces Themes 2013-04 -->
    <!-- https://mvnrepository.com/artifact/org.primefaces.themes/all-themes -->
    <dependency>
      <groupId>org.primefaces.themes</groupId>
      <artifactId>all-themes</artifactId>
      <version>1.0.10</version>
    </dependency>

    
    <!-- 2018-04-24 Weld CDI for Tomcat with all dependencies included (does not fulfill all capabilities !!!) -->
    <dependency>
      <groupId>org.jboss.weld.servlet</groupId>
      <artifactId>weld-servlet-shaded</artifactId>
      <version>3.0.4.Final</version>
    </dependency>
    
        
    <!-- JPA & Postgres -->
    <!-- 2017-10 Javassist required by Hibernate in some computers -->
    <!-- https://mvnrepository.com/artifact/org.javassist/javassist -->
     <dependency>
      <groupId>org.javassist</groupId>
      <artifactId>javassist</artifactId>
      <version>3.22.0-GA</version>
    </dependency>
    
    <!-- JPA 2.1 Provider -->
    <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-core</artifactId>
      <version>${hibernate.version}</version>
    </dependency>
    
    <!-- Envers for auditing the database -->
    <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-envers -->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-envers</artifactId>
      <version>${hibernate.version}</version>
    </dependency>
    
    <!-- Hibernate Testing !!! -->
    <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-testing -->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-testing</artifactId>
      <version>${hibernate.version}</version>
      <scope>test</scope>
    </dependency>
    
    <!-- 2018-05 Hibernate Bean Validator Optional Doesn't follow the same versioning !!-->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>6.0.10.Final</version>
    </dependency>
    
    <!-- 2018-03 PostgreSQL -->
    <!-- https://mvnrepository.com/artifact/org.postgresql/postgresql -->
    <dependency>
      <groupId>org.postgresql</groupId>
      <artifactId>postgresql</artifactId>
      <version>42.2.2</version>
    </dependency>  
     
    <!-- 2018-05 Lombok for setters and getters -->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.16.20</version>
    </dependency>
    
       
    <!-- 2017-10 Apache commons codec for md5 digest -->
    <!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
    <dependency>
      <groupId>commons-codec</groupId>
      <artifactId>commons-codec</artifactId>
      <version>1.11</version>
    </dependency>
    
    
    
    <!-- 2017-11 Apache commons lang3 with stringUtils --> 
    <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.7</version>
    </dependency>

    <!--  2017-04 Evaluate expressions Apache-commons-JEXL -->
    <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-jexl3 -->
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-jexl3</artifactId>
      <version>3.1</version>
    </dependency>
    
    <!-- 2016-09 Apache commons BeanUtils --> 
    <!-- https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils -->
    <dependency>
     <groupId>commons-beanutils</groupId>
     <artifactId>commons-beanutils</artifactId>
     <version>1.9.3</version>
    </dependency>

    <!-- 2018-04 Tomcat database connection pooling package--> 
    <!-- https://mvnrepository.com/artifact/org.apache.tomcat/tomcat-dbcp -->
    <dependency>
      <groupId>org.apache.tomcat</groupId>
      <artifactId>tomcat-dbcp</artifactId>
      <version>9.0.8</version>
    </dependency>
   
 

    <!-- 2008-02 Java CSV csvreader & csvwriter -->
    <!-- https://mvnrepository.com/artifact/net.sourceforge.javacsv/javacsv -->
    <dependency>
      <groupId>net.sourceforge.javacsv</groupId>
      <artifactId>javacsv</artifactId>
      <version>2.0</version>
    </dependency>

    
    
    <!--BEGIN Java 9 references to JEE  not included in JDK9-->
    <!-- 2017-07 JAXB API -->
    <!-- https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api -->
    <dependency>
      <groupId>javax.xml.bind</groupId>
      <artifactId>jaxb-api</artifactId>
      <version>${jaxb.version}</version>
    </dependency>
    
    <!-- 2017-08 JAXB Implementation -->
    <!-- https://mvnrepository.com/artifact/com.sun.xml.bind/jaxb-impl -->
    <dependency>
      <groupId>com.sun.xml.bind</groupId>
      <artifactId>jaxb-impl</artifactId>
      <version>${jaxb.version}</version>
    </dependency>
        
    <!-- 2017-08 Old JAXB Core -->
    <!-- https://mvnrepository.com/artifact/com.sun.xml.bind/jaxb-core -->
    <dependency>
      <groupId>com.sun.xml.bind</groupId>
      <artifactId>jaxb-core</artifactId>
      <version>${jaxb.version}</version>
    </dependency>
    
    <!-- 2017-09-06 Activation API -->
    <!-- https://mvnrepository.com/artifact/javax.activation/javax.activation-api -->
    <dependency>
      <groupId>javax.activation</groupId>
      <artifactId>javax.activation-api</artifactId>
      <version>${activation.version}</version>
    </dependency>

    <!-- 2017-09-06 Activation Implementation -->
    <!-- https://mvnrepository.com/artifact/com.sun.activation/javax.activation -->
    <dependency>
      <groupId>com.sun.activation</groupId>
      <artifactId>javax.activation</artifactId>
      <version>${activation.version}</version>
    </dependency>

    <!-- END Java 9 references to JEE  not included in JDK9-->



    <!-- YAML (and JSON And XML ) dependencies -->
    <!-- 2018-03-26 Jackson Databind -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>${jackson.version}</version>
    </dependency>
    
    <!-- 2018-03-26 Jackson Dataformat YAML -->
    <dependency>
      <groupId>com.fasterxml.jackson.dataformat</groupId>
      <artifactId>jackson-dataformat-yaml</artifactId>
      <version>${jackson.version}</version>
    </dependency>
    
    <!-- 2018-03-26 Jackson Dataformat XML -->
    <dependency>
      <groupId>com.fasterxml.jackson.dataformat</groupId>
      <artifactId>jackson-dataformat-xml</artifactId>
      <version>${jackson.version}</version>
    </dependency>
    
    <!-- END YAML dependencies -->
    
  </dependencies>


  <!--  to load from primefaces maven repository !! -->
  <!-- see https://stackoverflow.com/questions/21705509/primefaces-all-themes-v-1-0-10-installation -->
  <repositories>
<repository> <id>prime-repo</id> <name>PrimeFaces Maven Repository</name> <url>http://repository.primefaces.org</url> <layout>default</layout> </repository> </repositories> </project>

3. Additional files: 

1. Create a new folder into webapp folder called WEB-INF

2. Create an empty file beans.xml in the WEB-INF folder. This file may be required by CDI (Context and dependency injection). For more information see BalusC.

3. Create the file faces-config.xml in the WEB-INF folder. This file is referenced in coreservlets from Marti Hall


1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?>
<faces-config 
              xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
              xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"
              version="2.2">  

</faces-config>

4. (Optional)In future posts we will need including local jar files (dependencies) that are not in Maven Central repository. So in the previous WEB-INF folder let's create the folder lib, that will contain these jars. (There are other options to solve this problem, but it is good for me. See Roufid for more accepted solutions)

5. (Optional) Also in a future, we will be using JNDI datasources in Tomcat (and will be referenced in JPA). So we need to create the META-INF folder (in the webapp folder). We will include in this folder the empty file context.xml.


4. Additional files in the src/main/resources folder

(Optional) In a future we will put this files in the src/main resources:

1.  META_INF/persistence.xml (for JPA)
2.  properties/application.properties (for properties files)
3.  bundles/language.properties (for resources bundles)
4.  Other stuff

5. LoginBean.java and test02-login-page.xhtml

1. Let's create the package org.ximodante.jsf.login into src/main/java.
2. Create the java class LoginBean.java 


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package org.ximodante.jsf.login;

import java.io.Serializable;

import javax.enterprise.context.SessionScoped;
import javax.inject.Named;

import lombok.Getter;
import lombok.Setter;


@Named
@SessionScoped
public class LoginBean implements Serializable{
 private static final long serialVersionUID = 1L;
 @Getter @Setter private String user;
 @Getter @Setter private String password;
 @Getter private String myError="";
 
 
 public String login () {
  if (user.equalsIgnoreCase("ximo") && password.equals("password")) {
   return "test02-application-page";
  } else {
   myError="Bad User/password";
   return "test02-login-page";
  }
 }

} 

Note:

  • We are using CDI that uses its own annotations. Please do not mix JSF annotation with CDI annotation
  • In CDI all beans should implement Serializable interface or else Tomcat won't start.
  • We are using Lombok annotations @Getter and @Setter.
  • When user is "ximo" and password is "password" we are redirected to the application-page
3. Let's create (optionally) the folder "pages" into the folder "webapp".
4. Let's create the file test02-login-page.xhtml in the folder "pages"


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<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:p="http://primefaces.org/ui">  
    <h:head>  
    </h:head>  
      
    <h:body>  
      <h:form>  
        <p:panel header="Login Page">    
          <h:outputLabel value="username " />
    <h:inputText value="#{loginBean.user}" />
    <br />
    <h:outputLabel value="password" />
    <h:inputSecret value="#{loginBean.password}"></h:inputSecret>
    <br />
    <h:outputText value="#{loginBean.myError}" />
     </p:panel>
        <p:commandButton value="Login" action="#{loginBean.login}"/>
       </h:form>
    </h:body>  
</html>

5. Let's create a simple application page, to whom we will be redirected when filling the login page. This file is test02-application-page.xhtml and is placed in the same folder "pages"


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<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:p="http://primefaces.org/ui">  
    <h:head>  
    </h:head>  
      
    <h:body>  
      <h:form>  
        <p:panel header="Application Page (from test02-login-page?)">    
          <h:outputLabel value="This is the application page" />
    
        </p:panel>
        
     </h:form>
   </h:body>  
</html>



6. Project structure

This is the proposed project structure. Take into account that the strictly needed files for this example are displayed in bold style.

Java Resources (src/main/java folder)
  |--src/main/java 
     |--org.ximodante.jsf.login
        |-- LoginBean.java

  |--src/main/resources

     |--META-INF
        |-- persistence.xml
     |--properties
        |--application.properties
     |--bundles
        |--language.properties
     |--other stuff
  
Deployed Resources (src/main folder)
   |--webapp
      |--WEB-INF
         |--beans.xml
         |--faces-config.xml
         |--lib
            |--additional local jars 
      |--pages
         |--test02-login-page.xhtml
         |--test02-application-page.xhtml
      |--META-INF
         |--context.xml
      |--other stuff like css, icons ..
     


7. Executing the page


I if we right-click on test02-login-page.xhtml and select Run As - Run on Server this page will be shown:

If we insert user=ximo and password=password and press Login (button), the application page will be displayed.

We should notice that:

1. LoginBean is a session scoped bean. So its value won't change while the session is active !! Many programmers may not agree with this approach!

2. If we introduce a bad user/password, the attribute "myError" changes its value, but it is not reflected in the form. This will be the subject of a new post.