Sunday, 10 August 2014

Weblogic JSF 2 tutorial

Lets create a very simple Web app (WAR) using JSF 2 and drop it on Weblogic.

Prerequisites:

  You would need a weblogic instance installed and have a domain created. If you do not have one, you can download the server from http://www.oracle.com/technetwork/middleware/weblogic/downloads/wls-main-097127.html. Then you would need to create a domain, this can be done from Configuration Wizard, where you would choose to create a new domain.

  I am using eclipse for this tutorial, with a simple java project (the reason why i choose not to use the web app project type is that it will give you a better sence of what the application is made of).
My weblogic is instaled in the following directory, this is the directory i will be refering throughout the tutorial:

C:\Oracle\Middleware\Oracle_Home

The directory of the created domain in weblogic i have as:


C:\Oracle\Middleware\Oracle_Home\user_projects\domains\technokon

Install JSF 2 libraries in Weblogic

  First thing we need to do is install the jsf2 library on weblogic (this isn't something you would have to do on JBoss or Glassfish servers for example).
  To do this you need to start-up your weblogic domain, so let's do that and go through the process of installing the library. To start the domain i will launch this file:


startWebLogic.cmd

which is right in the domain directory. You would know that the server is running, when you see something like the following in the cmd window log, the the server is using:

<Aug 7, 2014 8:05:22 PM EDT> <Notice> <WebLogicServer> <BEA-000331> <Started the
 WebLogic Server Administration Server "AdminServer" for domain "technokon" running in development mode.>
<Aug 7, 2014 8:05:22 PM EDT> <Notice> <WebLogicServer> <BEA-000360> <The server started in RUNNING mode.>
<Aug 7, 2014 8:05:22 PM EDT> <Notice> <WebLogicServer> <BEA-000365> <Server state changed to RUNNING.>

Now navigate your browser to:

http://localhost:7001/console

and login to console. Note that i am using the default port 7001, that was configured during the domain creation process.

  Now, on the left menu choose:

Deployments, then click on the  button. Now, navigate to the directory where the jfs-2.0.war is, which i have at:


C:\Oracle\Middleware\Oracle_Home\wlserver\common\deployable-libraries

You will see a file there called:

jsf-2.0.war

  Pick this file and click on the   button. Then on the next page pick Install this deployment as a library.
And click next again on the following 2 pages and  after, this will take you to the configuration page.
Now on this page, set the Restart may be required. Deployment Order: to 99 (default is 100), so it is deployed before other auto-deployable apps. adn click  .

  Now lets move over to the project itself.


Java Project

Start your eclipse and in the workspace create a Java project, I called mine JSFTest.

For this tutorial I am usign Ant to help me, with the following build file that I placed in the root of my java project:

<?xml version="1.0" encoding="UTF-8"?>
<!-- ====================================================================== 
     Aug 7, 2014 3:09:10 PM                                                        

     JSF Test    
     JSF 2 Test application
                   
     iakoupov                                                                
     ====================================================================== -->



<project name="JSF Test" default="build">

 <description>
            JSF 2 Test application
    </description>

 <property name="deploy.dir" value="C:\Oracle\Middleware\Oracle_Home\user_projects\domains\technokon\autodeploy\Test.war" />

 <!-- ================================= 
          target: build              
         ================================= -->
 <target name="build" depends="compile" description="JSF 2 Test application">

  <war destfile="${deploy.dir}" webxml="WebContent\WEB-INF\web.xml">
   <fileset dir="WebContent" includes="*.xhtml" />
   <webinf dir="WebContent\WEB-INF">
   </webinf>
  </war>

 </target>

 <!-- - - - - - - - - - - - - - - - - - 
          target: compile                      
         - - - - - - - - - - - - - - - - - -->
 <path id="jsf2.lib">
  <fileset dir="WebContent\WEB-INF\lib" includes="*.jar" />
 </path>
 <target name="compile">

  <delete dir="WebContent\WEB-INF\classes" />

  <copy todir="WebContent\WEB-INF\classes\resources" overwrite="true">
   <fileset dir="src\resources" includes="**/*.properties" />
  </copy>

  <javac srcdir="src" destdir="WebContent\WEB-INF\classes" includeantruntime="true" classpathref="jsf2.lib" debug="on" />
 </target>

</project>

In that file you would need to change the value of the deploy.dir property so it relates to the location of your domain.

Now lets create other folders in the java project that will compose our web app.

1) Create a folder called WebContent in the root of the project. In there create a folder called WEB-INF.
2) In the WEB-INF folder create 2 folders: classes and lib.
In the lib directory, copy following 2 jar files and add them to the project classpath:


C:\Oracle\Middleware\Oracle_Home\wlserver\modules\javax.enterprise.inject_1.2
C:\Oracle\Middleware\Oracle_Home\wlserver\modules\javax.inject-1.jar


3) Under the src folder, create a package called resources.

3) Now lets copy following files to resources package:  application.properties.

application.properties

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# -- welcome --
welcomeTitle=JSF Blank Application

welcomeHeading=Welcome!

welcomeMessage=This is a JSF blank application. \
 You can find the application.properties file with this message in the src/resources folder.
 
titleStandardNumberConverter = Standard converters for numbers - format numbers
titleStandardDateConverter = Standard converters for date and time
titleCustomCarConverter = Custom car converter
titleCustomDateConverter = Custom date converter


4) To the WEB-INF folder copy the following files: web.xmlweblogic.xml, beans.xml,
faces-config.xml.

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
  <display-name>Test</display-name>
  <servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*</url-pattern>
  </servlet-mapping>
  
  <welcome-file-list>
   <welcome-file>index.xhtml</welcome-file>
  </welcome-file-list> 
  
  
</web-app>

weblogic.xml

<?xml version="1.0" encoding="UTF-8"?>
<wls:weblogic-web-app xmlns:wls="http://xmlns.oracle.com/weblogic/weblogic-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_2_5.xsd http://xmlns.oracle.com/weblogic/weblogic-web-app http://xmlns.oracle.com/weblogic/weblogic-web-app/1.4/weblogic-web-app.xsd">
    <wls:weblogic-version>12.1.3</wls:weblogic-version>
    <wls:context-root>Test</wls:context-root>
</wls:weblogic-web-app>

This file is required by weblogic. In there modules are specified, such as ear, war, ejb-jar files.

beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee">
 <scan>
  <exclude name="com.chapter1.*" />
 </scan>
</beans>

Notice the exclude tag, that tells the container not to scan for beans in the pointed-out package.

faces-config.xml

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

<faces-config
    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-facesconfig_2_0.xsd"
    version="2.0">
 <application>
  <message-bundle>resources.application</message-bundle>
  <locale-config>
   <default-locale>en</default-locale>
  </locale-config>
 </application>

</faces-config>

Notice how compact the file is, since there is no mapping declarations made. This is due to new standard of convenction over configuration (COC) and beans may be declared with annotations as you will see later. This file however still needs to be on the classpath.

5) To the WebContent folder, copy 2 xhtml files that we use for this example: index.xhtmllogin.xhtml.

index.xhtml

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"
 xmlns:ui="http://java.sun.com/jsf/facelets"
 xmlns:h="http://java.sun.com/jsf/html"
 xmlns:f="http://java.sun.com/jsf/core">

<f:loadBundle basename="resources.application" var="msg" />

<head>
<title><h:outputText value="#{msg.welcomeTitle}" /></title>
</head>

<body>
 <h3>
  <h:outputText value="#{msg.welcomeHeading}" />
 </h3>
 <p>
  <h:outputText value="#{msg.welcomeMessage}" />
 </p>

 <br />
 <h:link outcome="login" value="Login" />

</body>
</html>


login.xhtml


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"
 xmlns:ui="http://java.sun.com/jsf/facelets"
 xmlns:h="http://java.sun.com/jsf/html"
 xmlns:f="http://java.sun.com/jsf/core">

<f:loadBundle basename="resources.application" var="msg" />

<head>
<title><h:outputText value="#{msg.welcomeTitle}" /></title>
</head>

<body>
 <f:view>
  <h:form id="loginForm">
   <h:panelGrid columns="2" rendered="#{!login.loggedIn}">
    <h:outputLabel for="username">Username:</h:outputLabel>
    <h:inputText id="username" value="#{credentials.username}" />
    <h:outputLabel for="password">Password:</h:outputLabel>
    <h:inputSecret id="password" value="#{credentials.password}" />

   </h:panelGrid>

   <h:commandButton value="Login" action="#{login.login}"
    rendered="#{!login.loggedIn}" />
   <h:commandButton value="Logout" action="#{login.logout}"
    rendered="#{login.loggedIn}" />

  </h:form>
 </f:view>
</body>
</html>

6) Create a package under src folder in eclipse and create Login, User and Credentials classes in there.

Login.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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package com.technokon.bean;

import java.io.Serializable;

import javax.enterprise.inject.Model;
import javax.enterprise.inject.Produces;
import javax.enterprise.context.SessionScoped;
import javax.inject.Inject;

@SessionScoped
@Model
public class Login implements Serializable {
 private static final long serialVersionUID = -7665912439280494601L;
 
 @Inject
 private Credentials credentials;
 
 private User user;
 
 public void login() {
  // DB
  if (credentials.getUsername().equalsIgnoreCase("ADMIN")
    && credentials.getPassword().equals("password")) {
   user = new User();
   user.setUsername(credentials.getUsername());
   user.setPassword(credentials.getPassword());
  }
 }
 
 public void logout() {
  user = null;
 }
 
 public boolean isLoggedIn () {
  return user != null;
 }
 
 @Produces
 User getCurrentUser() throws Exception {
  if (user == null) {
   throw new Exception("Not logged in");
  } else {
   return user;
  }
 }

}

User.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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.technokon.bean;

import javax.enterprise.inject.Model;

@Model
public class User {
 
 private String username;
 
 private String password;
 
 private String firstName;
 
 private String lastName;

 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;
 }

 public String getFirstName() {
  return firstName;
 }

 public void setFirstName(String firstName) {
  this.firstName = firstName;
 }

 public String getLastName() {
  return lastName;
 }

 public void setLastName(String lastName) {
  this.lastName = lastName;
 }
 
 

}

Credentials.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
package com.technokon.bean;

import javax.enterprise.inject.Model;

@Model
public class Credentials {
 
 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;
 }
 
 
}

2 comments:

  1. you are a hero, I have followed your instructions and it all works beautifully. You only forgot to mention that the only username/password accepted are ADMIN/password

    ReplyDelete