Oracle JET is the new open source JavaScript library from Oracle which is great for building Single Page Applications.  In this blog post, I discuss the various steps to create an Oracle JET web application hosted on Java Cloud Service – SaaS Extension that can hold a logged in user Context.  For implementing this, we will leverage the out-of-box capabilities of the Shared Identity Management (SIM) to achieve Single Sign on and Single Log off and integrate with a JAX-RS REST Service that provides User Context.

 

Here is the list of softwares/services I am using:

  • IDE – Netbeans 8.1
  • Oracle JET Quick Start template (version 2.1.0).
  • Oracle Weblogic Server 10.3.6 (for testing locally)
  • Oracle Java Cloud Service – SaaS Extension 16.3.x

 

Pre-requisites

  1. Register the Oracle Weblogic Server in your Netbeans IDE (Tools -> Servers -> Add Server – add the Oracle Home for the Oracle Weblogic Server in the location).  More details can be found in the Netbeans documentation
  2. Make sure you have the Jersey 1.x library for compilation purposes.    If not create a new library in Netbeans  via Tools -> Libraries -> New Library, give it a name of Jersey 1.x and add the following jars under it:

jersey-bundle-1.18.1.jar

jersey-core-1.18.1.jar

jersey-json-1.18.1.jar

jersey-multipart-1.18.1.jar

jersey-server-1.18.1.jar

jersey-servlet-1.18.1.jar

 

You can download these jars from the maven central repository or from the Jersey downloads page.

 

Step 1 – Create a Web Application in Netbeans 8.1

 

Go to File -> New Project -> Java Web.  Choose Web Application as the project type as shown below:

 

NetbeansSetup - create project.png

NetbeansSetup - create project 2.png

 

Give the information required by the New Project Wizard like project name, runtime server environment (Oracle Weblogic) etc.  This will create an empty Web Application with the name you chose with a web.xml, weblogic.xml and an index.jsp

 

Step 2 - Download and Unzip the Quick Start template.

There are multiple ways to scaffold an Oracle JET (web) application as given in the JET documentation.  The technique given here is my preferred one in Netbeans.

 

Download the Oracle JET Quick Start template from here into any directory.  This contains the skeleton of a working Oracle JET project, which you can then change according to your needs.  This is great if you are starting out with Oracle JET.

 

Next unzip the Oracle JET Quick Start template.  This is what the structure looks like:

NetbeansSetup - Quick Start structure.png

 

Step 3 – Copy the contents of the QuickStart to the Netbeans Web Application

Delete the index.jsp that was created by default in the Netbeans Web Application, because we will be using the index.html that is provided with the Oracle JET Quick Start.

NetbeansSetup - index.png

 

Select all the contents in the Quick Start template as shown in Figure 3 and copy them to the Netbeans Web application Web Pages folder.

NetbeansSetup - copyall.png

 

Step 4 – Modify the WEB-INF/web.xml and WEB-INF/weblogic.xml

Add security-constraint and login-config entries to the web.xml.  This will make the application protected by delegating authentication to the SIM which will require a user to log in before he can access index.html

 

The login-config entry has a value of CLIENT-CERT as the auth-method which is Oracle's recommended mode of authentication, as it enables the tenant-specific SSO authentication mode for an application.

 

web.xml

 

<?xml version = '1.0' encoding = 'windows-1252'?>
<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">
    <security-constraint>
        <display-name>name</display-name>
        <web-resource-collection>
            <web-resource-name>name</web-resource-name>
            <url-pattern>/*</url-pattern>
        </web-resource-collection>
    </security-constraint>
    <login-config>
        <auth-method>CLIENT-CERT</auth-method>
        <realm-name>default</realm-name>
    </login-config>
</web-app>

 

 

weblogic.xml

 

<?xml version="1.0" encoding="UTF-8"?>
<weblogic-web-app xmlns="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.0/weblogic-web-app.xsd">
    <container-descriptor>
        <prefer-web-inf-classes>true</prefer-web-inf-classes>
    </container-descriptor>
    <context-root>/QuickStartProject</context-root>
</weblogic-web-app>

 

Now you have a basic Oracle JET web application that is restricted to only tenants having access to JCS-SX.  You can further restrict this to a certain role in web.xml.  For more details consult JCS-SX documentation for securing applications

 

Tip – You can add this skeleton project in Netbeans as a sample project, so that you don’t need to carry out the same steps again.  Here is the tutorial that helps to make this a sample project in NetBeans.

 

 

Running it locally using the Netbeans platform (Project -> Run) will yield the following screen

JET QuickStart - running application.png

 

Not Bad!  But the logged in user is hardcoded (on the top right hand corner) and the ‘Sign Out’ menu (on expanding the user name menu dropdown) doesn’t do anything.  Let us correct that.

 

Tip – If you want to use the minified version of oracle JET JavaScript and not the debug version, change the path in main.js to use the minified JS.

 

'ojs': 'libs/oj/v2.1.0/debug',  

 

to

 

'ojs': 'libs/oj/v2.1.0/min',

 

You can now delete the debug folder  (js/libs/oj/v2.1.0/debug) if you wish, which will make the application smaller in size.

 

Step 5 - To get the logged in User

Let us develop a JAX-RS REST service to get the logged in User.  You can create this in the same project or any other project that will be deployed on the same server.  I am going to do this in the same project.

 

Add the Jersey 1.x library to the project by clicking on Project -> Properties -> Libraries -> Add Library.  If you only see the Jersey 2.x library, click Create and add a custom library called Jersey 1.x as given in prerequisites.

 

The Jersey 1.x is only required for compilation purposes – so make sure the library is not packaged (by unticking the Package checkbox)

 

NetbeansSetup - add Jersey Library.png

 

We need to develop a JAX-RS REST API that the JET application can call which would give the logged in user name.

 

UserApplication.java – This is the JAX-RS Application that is the entry point for the REST Service

 

package com.oracle.rest;

import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.core.Application;

public class UserApplication extends Application {
    @Override
    public Set<Class<?>> getClasses() {
        Set<Class<?>> classes = new HashSet<Class<?>>();
        classes.add(UserService.class);
        return classes;
    }
}

 

UserService.java – This is the JAX-RS resource which contains the logic for getting the logged in user

 

package com.oracle.rest;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;

@Path("rest")
public class UserService {
    public UserService() {
        super();
    }
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    @Path("userinfo")
    public String getLoggedInUser(@Context SecurityContext sc) {
        String userName = "No user";
        if (sc.getUserPrincipal() != null) {
            userName = sc.getUserPrincipal().getName();
        }
        return userName;
    }
}

 

Change the web.xml as below to add the Jersey servlet

 

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 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">
 <servlet>
<servlet-name>jersey</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.oracle.rest.UserApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
<servlet-name>jersey</servlet-name>
<url-pattern>/gateway/*</url-pattern>
</servlet-mapping>

<security-constraint>
<display-name>name</display-name>
 <web-resource-collection>
<web-resource-name>name</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
</security-constraint>
<login-config>
<auth-method>CLIENT-CERT</auth-method>
<realm-name>default</realm-name>
</login-config>
<web-app>

 

 

Deploy the web application on JCS-SX and test the rest service.  For deploying the application on JCS-SX please refer to the documentation.

 

Then test the REST service using

http://<java instance url>/QuickStartProject/gateway/rest/userinfo

 

This should give the logged in user in text/plain format.

 

Now let us call this REST service in our JET application to display the correct user name.  A search for the hardcoded user name (john.hancock@oracle.com) points us to js/appController.js  and sure enough it has the following lines:

 

      self.userLogin = ko.observable("john.hancock@oracle.com");

 

Change this to the following lines

 

                self.userLogin = ko.observable("");
                self.getUserName = function () {
                    return $.ajax({url: "/QuickStartProject/gateway/rest/userinfo",
                        dataType: 'text',
                        type: 'GET'
                    });
                };
               self.getUserName().then(function (result) {
                    self.userLogin(result);
                });

If you deploy and run the application on JCS-SX it will show the logged in user instead of the hardcoded user name.

 

Step 5 - To implement logoff

If you click on the user name, you can see the “Sign Out” button which is not implemented yet.  Let us map it to a LogoutServlet.

 

package com.oracle.servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.*;
import javax.servlet.http.*;

public class LogoutServlet extends HttpServlet {

    public void init(ServletConfig config) throws ServletException {
        super.init(config);
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.getSession().invalidate();
        response.sendRedirect( "/oamsso/logout.html");
    }
}

 

Add the Logout servlet entry in web.xml

 

<servlet>
<servlet-name>LogoutServlet</servlet-name>
<servlet-class>com.oracle.servlet.LogoutServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LogoutServlet</servlet-name>
<url-pattern>/logout</url-pattern>
</servlet-mapping>

 

In index.html, you can see the menu1 element that has the ‘Sign Out’ menu item.  The selection of any menu item triggers function menuItemSelect.

 

<ul id='menu1' data-bind="ojComponent: {component: 'ojMenu', select: menuItemSelect}" style="display:none">
        <!--<li id="pref"><a href="#">Preferences</a></li>-->
        <li id="help"><a href="#">Help</a></li>
        <li id="about"><a href="#">About</a></li>
        <li id="out"><a href="#">Sign Out</a></li>
</ul>

 

In appController.js, add a case for the sign out event

 

self.menuItemSelect = function (event, ui) {
 switch (ui.item.attr("id")) {
 case "about":
 $("#aboutDialog").ojDialog("open");
 break;
 case "out" :
 window.location.href = "/QuickStartProject/logout";
 default:
       }
};

 

 

Deploy and run the application and clicking on Sign Out redirects to the cloud logout page as below:

JET QuickStart - loggedoff.png

 

If you want to display a particular page and not the cloud logout page, customize the URL in the LogoutServlet.

 

response.sendRedirect( "/oamsso/logout.html?end_url=<landing page>");

 

There you have it – a working JET application deployed on JCS-SX with the logged in user context and Single Sign On and Single Logoff features.

 

**The views expressed in this post are my own and do not necessarily reflect the views of Oracle.