Hi everyone this post is about how you can perform login by using DB level user name and password..
(DB level users also known as DB level Schema like HR Schema or SCOTT Schema)
To read more detail click Here
For this example i am using jdeveloper 11.1.2.3.0
Lets start
1) Create a simple Application , connect to Database ( i have contacted with hr schema) create DepartmentsView VO and create two jsf pages ( i ) Login.jsf ( ii ) Home.jsf
2) On Login.jsf page drag and drop two input text fields and one button to perform login and drope DepartmentsView VO on Home page
4) To support Dynamic JDBC Credentials in adf we need to override the doFilter() method of oracle.adf.model.servlet.ADFBindingFilter Servlet
this ADF Binding Filter is a servlet filter that is used to sets up the binding context for the ADF application
this filter is fired and request for application module instance before any page is displayed to the end user. But we need to provide user name and password at run time so we need to display a login page to the end user where they can enter user name and password
so we need to override the doFilter() method to perform run time login
to override this method we also need to add "BC4j Client" library in ViewController
to add this edit the ViewController project's properties and add this library..
to override the method create a java class in ViewController project name as DynamicJDBCFilter and and exteds ADFBindingFilter
Here is the complete code
package view;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import oracle.adf.model.servlet.ADFBindingFilter;
import oracle.jbo.JboException;
import oracle.jbo.client.Configuration;
public class DynamicJDBCFilter extends ADFBindingFilter{
public DynamicJDBCFilter()
{
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
HttpSession session = ((HttpServletRequest) request).getSession(false);
if (session != null && session.getAttribute("loggedin") == null)
{
System.out.println("i am in doFilter method.........");
String usrName = (String) session.getAttribute("uName");
String pswd = (String) session.getAttribute("uPassword");
System.out.println("the uname is "+usrName);
System.out.println("the pw is "+pswd);
if (usrName != null && session.getAttribute("loggedin") == null)
{
try
{
if (usrName == null || usrName.length() == 0 || pswd == null || pswd.length() == 0)
{
throw new JboException("Blank User name or Password");
}
session.setAttribute(Configuration.DB_USERNAME_PROPERTY, usrName);
session.setAttribute(Configuration.DB_PASSWORD_PROPERTY, pswd);
super.doFilter(request, response, chain);
session.setAttribute("loggedin", "loggedin");
}
catch (oracle.jbo.JboException e)
{
try
{
session.setAttribute("loggedin", null);
session.invalidate();
}
catch (Exception e2)
{
}
request.getRequestDispatcher("/faces/login.jspx").forward(request, response);
}
}
else
{
super.doFilter(request, response, chain);
}
}
else
{
super.doFilter(request, response, chain);
}
}
}
i have added this statement System.out.println("i am in doFilter method.........");
in DynamicJDBCFilter class..
now Right click on Login.jsf page and click on Run , the above statement should print on console
until now your application can connect to database ... but for ADF Business Components we need to do the following steps
6 ) ADF Business Components need to connect to the current user at run time , So for this ADF Business components uses oracle.jbo.common.ampool.EnvInfoProvider interface . This interface will invoked by ADF Business Components at run time when it is necessary to connect AM instance to DB.
to implement this interface create a new java class and implement oracle.jbo.common.ampool.EnvInfoProvider ....
The operations declared by the EnvInfoProvider interface are all invoked at different points in the AM creation / connection life cycle by the ADF Bussiness Components at run time.
But we implement getInfo method , because it is used to connect ADF Business Components at run time
Here is the complete code
package view;
import java.util.Hashtable;
import oracle.jbo.common.ampool.EnvInfoProvider;
import oracle.jbo.client.Configuration;
public class DynamicEnvInfoProvider implements EnvInfoProvider {
private final String un;
private final String upw;
public DynamicEnvInfoProvider(String uname, String upassword)
{
un = uname;
upw = upassword;
}
public Object getInfo(String info, Object connEnvironment)
{
if(un != null)
{
((Hashtable)connEnvironment).put(Configuration.DB_USERNAME_PROPERTY, un);
}
if(upw != null)
{
((Hashtable)connEnvironment).put(Configuration.DB_PASSWORD_PROPERTY, upw);
}
return null;
}
public void modifyInitialContext(Object p0)
{
}
public int getNumOfRetries()
{
return 0;
}
}
7 ) Reference this DynamicEnvInfoProvider
To uniquely identify every session in application pool , the Application Pool use oracle.jbo.common.ampool.SessionCookie class . So , every HTTP request that requires AM instance from Application pool will create a Session Cookie and remains live until the session ended. At run time this Session Cookie instance will reuse every time when ever the session requires an AM instance from application pool.
to connect the ADF Business Components with session ,an object of EnvInfoProvider save in Session Cookie
ADF Business Components API provides the SessionCookie.setEnvInfoProvider (EnvInfoProvider) method to store a reference of EnvInfoProiver instance in SessionCookie. The Application Pool also check the existence of EnvInfoProvider instance when AM instance need to connect .
Create SessionCooike Implementation
create a java class in ViewController and extends it with HttpSessionCookieImpl
Here is the complete code
package view;
import oracle.jbo.common.ampool.ApplicationPool;
import oracle.jbo.http.HttpSessionCookieImpl;
import oracle.jbo.common.ampool.EnvInfoProvider;
public class DynamicSessionCookieImpl extends HttpSessionCookieImpl {
public DynamicSessionCookieImpl(java.lang.String applicationId,
java.lang.String sessionId, ApplicationPool pool)
{
super(applicationId, sessionId, pool);
}
public DynamicSessionCookieImpl(java.lang.String applicationId,
java.lang.String sessionId, ApplicationPool pool, java.security.Principal userPrincipal,
javax.servlet.http.HttpServletRequest request)
{
super(applicationId, sessionId, pool, userPrincipal, request);
}
public DynamicSessionCookieImpl(java.lang.String applicationId,
java.lang.String sessionId, ApplicationPool pool, java.security.Principal userPrincipal,
javax.servlet.http.HttpSession session)
{
super(applicationId, sessionId, pool, userPrincipal, session);
}
public void setEnvInfoProvider(EnvInfoProvider envInfoProvider)
{
if (envInfoProvider != null)
{
super.setEnvInfoProvider(envInfoProvider);
}
}
}
8 ) Create a Session Cookie Factory
This Session Cookie Factory will use to initialize the new SessionCookies along with EnvInfoProvider instance
create a new java class in ViewController Project and extends it with HttpSessionCookieFactory
Complete code here
package view;
import oracle.jbo.common.ampool.SessionCookie;
import oracle.jbo.common.ampool.ApplicationPool;
import oracle.jbo.common.ampool.EnvInfoProvider;
import java.util.Properties;
import java.util.Hashtable;
import oracle.jbo.http.HttpSessionCookieFactory;
import oracle.jbo.client.Configuration;
import javax.servlet.http.HttpSession;
public class SessionCookieFactory extends HttpSessionCookieFactory {
public SessionCookie createSessionCookie(String name, String value, ApplicationPool pool, Properties properties)
{
SessionCookie cookie = super.createSessionCookie(name, value, pool, properties);
if (properties != null)
{
HttpSession session = (HttpSession) properties.get(HTTP_SESSION);
if (session != null)
{
Hashtable env = pool.getEnvironment();
env.remove(Configuration.DB_USERNAME_PROPERTY);
env.remove(Configuration.DB_PASSWORD_PROPERTY);
pool.setUserName(null);
pool.setPassword(null);
EnvInfoProvider provider = new DynamicEnvInfoProvider(
(String) session.getAttribute(Configuration.DB_USERNAME_PROPERTY),
(String) session.getAttribute(Configuration.DB_PASSWORD_PROPERTY));
cookie.setEnvInfoProvider(provider);
}
}
return cookie;
}
public Class getSessionCookieClass()
{
try
{
return Class.forName("view.DynamicSessionCookieImpl");// path to DynamicJDBCHttpSessionCookieImpl class
}
catch (ClassNotFoundException cnfe)
{
cnfe.printStackTrace();
return null;
}
}
}
9 ) AppModule Setting
Finally after creating your own SessionCookieFactory , to force the Application pool to use this factory instead of default , we need to update the jbo.ampool.SessionCookieFactory property
So open the AM Configurations update the following setting for both
AppModuleShared and
AppModuleLocal
Set connection type to JDBC URL
update jbo.ampool.SessionCookieFactory property
now run your Application , i am connecting with HR Schema , it Will show the data of Department table
Then i create another user as gul and login by using this user name and password
and the out put will be
Thanks
(DB level users also known as DB level Schema like HR Schema or SCOTT Schema)
To read more detail click Here
For this example i am using jdeveloper 11.1.2.3.0
Lets start
1) Create a simple Application , connect to Database ( i have contacted with hr schema) create DepartmentsView VO and create two jsf pages ( i ) Login.jsf ( ii ) Home.jsf
2) On Login.jsf page drag and drop two input text fields and one button to perform login and drope DepartmentsView VO on Home page
3) Now create a request scope been name as Login , create a login() method and bind it to button of login page, to verify user name and password and to set user name and password in Global variables (Later we use these Global variables for login in doFilter() method of ADFBindingFilter Servlet )
Note :- this Login been will only used to verify the user name and password , to set user name and password in Global variables and to perform logout
Here is the code to of Login been
package view;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import javax.faces.application.FacesMessage;
import javax.faces.application.ViewHandler;
import javax.faces.component.UIViewRoot;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpSession;
import org.apache.myfaces.trinidad.render.ExtendedRenderKitService;
import org.apache.myfaces.trinidad.util.Service;
public class Login {
private String uname;
private String upw;
//varify user name and password , set session scope values
public Login() {
}
public String login() {
if(null != this.uname && null!=this.upw){
Connection conn;
//set user name and password in session scope variables
FacesContext ctx = FacesContext.getCurrentInstance();
HttpSession session = (HttpSession) ctx.getExternalContext().getSession(true);
session.setAttribute("uName", this.uname.toUpperCase());
session.setAttribute("uPassword", this.upw.toUpperCase());
//to varify user name and password
try {
conn = this.getConnection();
String page="http://127.0.0.1:7101/dye_planing-ViewController-context-root/faces/home.jsf";
this.launchNewPage(page);
//to refresh the page
FacesContext fc = FacesContext.getCurrentInstance();
String refreshpage = fc.getViewRoot().getViewId();
ViewHandler ViewH =
fc.getApplication().getViewHandler();
UIViewRoot UIV = ViewH.createView(fc,refreshpage);
UIV.setViewId(refreshpage);
fc.setViewRoot(UIV);
}
catch (SQLException e) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Wrong ID or Password..!"));
}
}else
{
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Please Enter User Name and Password..!"));
}
return null;
}
//to varify the user name and password
public Connection getConnection() throws SQLException {
String username = this.uname.toUpperCase();
String password = this.upw.toUpperCase();
String thinConn = "jdbc:oracle:thin:@ your system or server ip : your port address :mis";
DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
Connection conn = DriverManager.getConnection(thinConn, username, password);
conn.setAutoCommit(false);
return conn;
}
//to perform logout
public String onLogout(){
FacesContext fctx = FacesContext.getCurrentInstance();
ExternalContext ectx = fctx.getExternalContext();
//String url = ectx.getRequestContextPath() + "/adfAuthentication?logout=true&end_url=/faces/Login.jspx";
String page="http://127.0.0.1:7101/dye_planing-ViewController-context-root/faces/ULogin.jsf";
this.launchNewPage(page);
HttpSession session = (HttpSession)ectx.getSession(false);
session.invalidate();
return null;
}
//method to luch new pages
public void launchNewPage(String p) {
String newPage = p;
FacesContext ctx = FacesContext.getCurrentInstance();
ExtendedRenderKitService erks = Service.getService(ctx.getRenderKit(), ExtendedRenderKitService.class);
String url = "window.open('" + newPage + "','_self');";
erks.addScript(FacesContext.getCurrentInstance(), url);
}
//method to get gat values from expression
public static Object getEL(String el) {
FacesContext facesContext = FacesContext.getCurrentInstance();
ELContext elContext = facesContext.getELContext();
ExpressionFactory expressionFactory =
facesContext.getApplication().getExpressionFactory();
ValueExpression exp =
expressionFactory.createValueExpression(elContext, el,
Object.class);
return exp.getValue(elContext);
}
//method to set values for expersion
public static void setEL(String el, Object val) {
FacesContext facesContext = FacesContext.getCurrentInstance();
ELContext elContext = facesContext.getELContext();
ExpressionFactory expressionFactory =
facesContext.getApplication().getExpressionFactory();
ValueExpression exp =
expressionFactory.createValueExpression(elContext, el,
Object.class);
exp.setValue(elContext, val);
}
public void setUname(String uname) {
this.uname = uname;
}
public String getUname() {
return uname;
}
public void setUpw(String upw) {
this.upw = upw;
}
public String getUpw() {
return upw;
}
}
this ADF Binding Filter is a servlet filter that is used to sets up the binding context for the ADF application
this filter is fired and request for application module instance before any page is displayed to the end user. But we need to provide user name and password at run time so we need to display a login page to the end user where they can enter user name and password
so we need to override the doFilter() method to perform run time login
to override this method we also need to add "BC4j Client" library in ViewController
to add this edit the ViewController project's properties and add this library..
to override the method create a java class in ViewController project name as DynamicJDBCFilter and and exteds ADFBindingFilter
Here is the complete code
package view;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import oracle.adf.model.servlet.ADFBindingFilter;
import oracle.jbo.JboException;
import oracle.jbo.client.Configuration;
public class DynamicJDBCFilter extends ADFBindingFilter{
public DynamicJDBCFilter()
{
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
HttpSession session = ((HttpServletRequest) request).getSession(false);
if (session != null && session.getAttribute("loggedin") == null)
{
System.out.println("i am in doFilter method.........");
String usrName = (String) session.getAttribute("uName");
String pswd = (String) session.getAttribute("uPassword");
System.out.println("the uname is "+usrName);
System.out.println("the pw is "+pswd);
if (usrName != null && session.getAttribute("loggedin") == null)
{
try
{
if (usrName == null || usrName.length() == 0 || pswd == null || pswd.length() == 0)
{
throw new JboException("Blank User name or Password");
}
session.setAttribute(Configuration.DB_USERNAME_PROPERTY, usrName);
session.setAttribute(Configuration.DB_PASSWORD_PROPERTY, pswd);
super.doFilter(request, response, chain);
session.setAttribute("loggedin", "loggedin");
}
catch (oracle.jbo.JboException e)
{
try
{
session.setAttribute("loggedin", null);
session.invalidate();
}
catch (Exception e2)
{
}
request.getRequestDispatcher("/faces/login.jspx").forward(request, response);
}
}
else
{
super.doFilter(request, response, chain);
}
}
else
{
super.doFilter(request, response, chain);
}
}
}
5) Modify web.xml file
we need to update filters and filter Mapings , to update Filter open web.xml file , click on Filter tab
and update or add adfBindings and filter Mappings like the following ...
and update or add adfBindings and filter Mappings like the following ...
i have added this statement System.out.println("i am in doFilter method.........");
in DynamicJDBCFilter class..
now Right click on Login.jsf page and click on Run , the above statement should print on console
until now your application can connect to database ... but for ADF Business Components we need to do the following steps
6 ) ADF Business Components need to connect to the current user at run time , So for this ADF Business components uses oracle.jbo.common.ampool.EnvInfoProvider interface . This interface will invoked by ADF Business Components at run time when it is necessary to connect AM instance to DB.
to implement this interface create a new java class and implement oracle.jbo.common.ampool.EnvInfoProvider ....
The operations declared by the EnvInfoProvider interface are all invoked at different points in the AM creation / connection life cycle by the ADF Bussiness Components at run time.
But we implement getInfo method , because it is used to connect ADF Business Components at run time
Here is the complete code
package view;
import java.util.Hashtable;
import oracle.jbo.common.ampool.EnvInfoProvider;
import oracle.jbo.client.Configuration;
public class DynamicEnvInfoProvider implements EnvInfoProvider {
private final String un;
private final String upw;
public DynamicEnvInfoProvider(String uname, String upassword)
{
un = uname;
upw = upassword;
}
public Object getInfo(String info, Object connEnvironment)
{
if(un != null)
{
((Hashtable)connEnvironment).put(Configuration.DB_USERNAME_PROPERTY, un);
}
if(upw != null)
{
((Hashtable)connEnvironment).put(Configuration.DB_PASSWORD_PROPERTY, upw);
}
return null;
}
public void modifyInitialContext(Object p0)
{
}
public int getNumOfRetries()
{
return 0;
}
}
7 ) Reference this DynamicEnvInfoProvider
To uniquely identify every session in application pool , the Application Pool use oracle.jbo.common.ampool.SessionCookie class . So , every HTTP request that requires AM instance from Application pool will create a Session Cookie and remains live until the session ended. At run time this Session Cookie instance will reuse every time when ever the session requires an AM instance from application pool.
to connect the ADF Business Components with session ,an object of EnvInfoProvider save in Session Cookie
ADF Business Components API provides the SessionCookie.setEnvInfoProvider (EnvInfoProvider) method to store a reference of EnvInfoProiver instance in SessionCookie. The Application Pool also check the existence of EnvInfoProvider instance when AM instance need to connect .
Create SessionCooike Implementation
create a java class in ViewController and extends it with HttpSessionCookieImpl
Here is the complete code
package view;
import oracle.jbo.common.ampool.ApplicationPool;
import oracle.jbo.http.HttpSessionCookieImpl;
import oracle.jbo.common.ampool.EnvInfoProvider;
public class DynamicSessionCookieImpl extends HttpSessionCookieImpl {
public DynamicSessionCookieImpl(java.lang.String applicationId,
java.lang.String sessionId, ApplicationPool pool)
{
super(applicationId, sessionId, pool);
}
public DynamicSessionCookieImpl(java.lang.String applicationId,
java.lang.String sessionId, ApplicationPool pool, java.security.Principal userPrincipal,
javax.servlet.http.HttpServletRequest request)
{
super(applicationId, sessionId, pool, userPrincipal, request);
}
public DynamicSessionCookieImpl(java.lang.String applicationId,
java.lang.String sessionId, ApplicationPool pool, java.security.Principal userPrincipal,
javax.servlet.http.HttpSession session)
{
super(applicationId, sessionId, pool, userPrincipal, session);
}
public void setEnvInfoProvider(EnvInfoProvider envInfoProvider)
{
if (envInfoProvider != null)
{
super.setEnvInfoProvider(envInfoProvider);
}
}
}
This Session Cookie Factory will use to initialize the new SessionCookies along with EnvInfoProvider instance
create a new java class in ViewController Project and extends it with HttpSessionCookieFactory
Complete code here
package view;
import oracle.jbo.common.ampool.SessionCookie;
import oracle.jbo.common.ampool.ApplicationPool;
import oracle.jbo.common.ampool.EnvInfoProvider;
import java.util.Properties;
import java.util.Hashtable;
import oracle.jbo.http.HttpSessionCookieFactory;
import oracle.jbo.client.Configuration;
import javax.servlet.http.HttpSession;
public class SessionCookieFactory extends HttpSessionCookieFactory {
public SessionCookie createSessionCookie(String name, String value, ApplicationPool pool, Properties properties)
{
SessionCookie cookie = super.createSessionCookie(name, value, pool, properties);
if (properties != null)
{
HttpSession session = (HttpSession) properties.get(HTTP_SESSION);
if (session != null)
{
Hashtable env = pool.getEnvironment();
env.remove(Configuration.DB_USERNAME_PROPERTY);
env.remove(Configuration.DB_PASSWORD_PROPERTY);
pool.setUserName(null);
pool.setPassword(null);
EnvInfoProvider provider = new DynamicEnvInfoProvider(
(String) session.getAttribute(Configuration.DB_USERNAME_PROPERTY),
(String) session.getAttribute(Configuration.DB_PASSWORD_PROPERTY));
cookie.setEnvInfoProvider(provider);
}
}
return cookie;
}
public Class getSessionCookieClass()
{
try
{
return Class.forName("view.DynamicSessionCookieImpl");// path to DynamicJDBCHttpSessionCookieImpl class
}
catch (ClassNotFoundException cnfe)
{
cnfe.printStackTrace();
return null;
}
}
}
9 ) AppModule Setting
Finally after creating your own SessionCookieFactory , to force the Application pool to use this factory instead of default , we need to update the jbo.ampool.SessionCookieFactory property
So open the AM Configurations update the following setting for both
AppModuleShared and
AppModuleLocal
update jbo.ampool.SessionCookieFactory property
now run your Application , i am connecting with HR Schema , it Will show the data of Department table
and the out put will be
Thanks
HI, I have one question in addition to this tutorial. First of all, it works, but there is one more problem about this. When I try to login with wrong password or username (intentionally) it remebers whole session. I must close browser and try again. If I try again without closing the browser it remembers session and the result is that login method let me into the app, but cannot fetch the dataset. Do you have any advice how to work this out?
ReplyDeletethank you in advance
HI, Is it possible to provide the link for download above code bnr.network@gmail.com.
ReplyDeletetoo complex
ReplyDelete