Wednesday, December 30, 2015

Apply Dynamic JDBC in ADF Application (Step-by-Step)

In some situations the business require that ADF application can connect to different database users depending on the login user. For example if user1 login, the ADF application will connect to database user hr/hr. If user2 login, the ADF application will connect to database user hr2/hr2.
This is call Dynamic JDBC.

In this url you can see how to apply this dynamic JDBC, but in my post I will simplify this url by creating a sample ADF application and go step by step for how to apply dynamic JDBC to this ADF application.

I use JDeveloper 11.1.2.4.0.

Note: From Step1 to Step5 it just steps for creating a simple ADF application. Applying the Dynamic JDBC to this simple application is starting from Step6.

Step1:
Create a simple ADF Application connect to "hr" database, this application will contains only 1 ViewObject (Employees) and will contains 2 jspx pages (login.jspx and emp.jspx)



Step2:
From faces-config.xml --> Navigation Rules define outcome to the two jspx pages.
login.jspx---> login
emp.jspx----> emp


Step3:
- In the login.jspx page add two inputTexts (Username and Password) and one command button for login.
- Bind Username inputText and Password inputText to the back bean.
- Create action for the login command button to read the username and password then navigate to emp.jspx page.

<af:document title="login.jspx" id="d1">
<af:form id="f1" defaultCommand="cb1">
<af:panelFormLayout id="pfl1">
<af:inputText label="Username" id="it1" autoSubmit="true" binding="#{login.usernameComponent}"/>
<af:inputText label="Password" id="it2" autoSubmit="true" binding="#{login.passwordComponent}"/>
<f:facet name="footer">
<af:commandButton text="Login" id="cb1" action="#{login.loginAction}"/>
</f:facet>
</af:panelFormLayout>
</af:form>
</af:document>
view raw login.xml hosted with ❤ by GitHub


Step4:
In the emp.jspx drag EmployeesView1 to the page and add logout link to the page 



The back bean should be:

public class LoginBean
{
private RichInputText usernameComponent;
private RichInputText passwordComponent;
public LoginBean()
{
}
public void setUsernameComponent(RichInputText usernameComponent)
{
this.usernameComponent = usernameComponent;
}
public RichInputText getUsernameComponent()
{
return usernameComponent;
}
public void setPasswordComponent(RichInputText passwordComponent)
{
this.passwordComponent = passwordComponent;
}
public RichInputText getPasswordComponent()
{
return passwordComponent;
}
public String loginAction()
{
String username = (String) getUsernameComponent().getValue();
String password = (String) getPasswordComponent().getValue();
System.out.println("Username= " + username + " - Password= " + password);
return "emp";//
}
public String logoutAction()
{
try
{
FacesContext context = FacesContext.getCurrentInstance();
HttpSession session = (HttpSession)context.getExternalContext().getSession(true);
if ( session != null )
{
session.invalidate();
}
}
catch (Exception e)
{
System.out.println("Session Invalidated...");
}
return "login";
}
}
view raw login.java hosted with ❤ by GitHub

Step5:
Run login.jspx page.

Now we have created a simple ADF application and we will now apply dynamic jdbc to this application.

Step6:
Open AppModule and set "Connection Type" to JDBC URL for both AppModuleShared and AppModuleLocal



Step7:
In the login button action we will store username/password it in session.
The login button action will be:

public String loginAction()
{
String username = (String) getUsernameComponent().getValue();
String password = (String) getPasswordComponent().getValue();
System.out.println("Username= " + username + " - Password= " + password);
FacesContext ctx = FacesContext.getCurrentInstance();
HttpSession session = (HttpSession) ctx.getExternalContext().getSession(true);
session.setAttribute("dbUser", username);
session.setAttribute("dbPassword", password);
return "emp";// outcome to emp.jspx page
}
view raw loginAtion.java hosted with ❤ by GitHub


Step8:
Create new Filter (DynamicJDBCBindingFilter.java) extends ADFBindingFilter.

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 DynamicJDBCBindingFilter extends ADFBindingFilter
{
public DynamicJDBCBindingFilter()
{
}
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)
{
String usrName = (String) session.getAttribute("dbUser");
String pswd = (String) session.getAttribute("dbPassword");
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);
}
}
}


Step9:
Create Class (DynamicJDBCEnvInfoProvider) as

import java.util.Hashtable;
import oracle.jbo.common.ampool.EnvInfoProvider;
import oracle.jbo.client.Configuration;
public class DynamicJDBCEnvInfoProvider implements EnvInfoProvider
{
private final String mJDBCUserName;
private final String mJDBCPassword;
public DynamicJDBCEnvInfoProvider(String jdbcUserName, String jdbcPassword)
{
mJDBCUserName = jdbcUserName;
mJDBCPassword = jdbcPassword;
}
public Object getInfo(String info, Object connEnvironment)
{
if(mJDBCUserName != null)
{
((Hashtable)connEnvironment).put(Configuration.DB_USERNAME_PROPERTY, mJDBCUserName);
}
if(mJDBCPassword != null)
{
((Hashtable)connEnvironment).put(Configuration.DB_PASSWORD_PROPERTY, mJDBCPassword);
}
return null;
}
public void modifyInitialContext(Object p0)
{
}
public int getNumOfRetries()
{
return 0;
}
}


Step10:
Create Class (DynamicJDBCHttpSessionCookieImpl) as

import oracle.jbo.common.ampool.ApplicationPool;
import oracle.jbo.http.HttpSessionCookieImpl;
import oracle.jbo.common.ampool.EnvInfoProvider;
public class DynamicJDBCHttpSessionCookieImpl extends HttpSessionCookieImpl
{
public DynamicJDBCHttpSessionCookieImpl(java.lang.String applicationId,
java.lang.String sessionId, ApplicationPool pool)
{
super(applicationId, sessionId, pool);
}
public DynamicJDBCHttpSessionCookieImpl(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 DynamicJDBCHttpSessionCookieImpl(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);
}
}
}


Step11: 
Create Class (DynamicJDBCSessionCookieFactory) as

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 DynamicJDBCSessionCookieFactory 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 DynamicJDBCEnvInfoProvider(
(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.DynamicJDBCHttpSessionCookieImpl");// path to DynamicJDBCHttpSessionCookieImpl class
}
catch (ClassNotFoundException cnfe)
{
cnfe.printStackTrace();
return null;
}
}
}


Step12:
In web.xml update adfBindings and make it point to DynamicJDBCBindingFilter

<filter>
<filter-name>adfBindings</filter-name>
<filter-class>view.DynamicJDBCBindingFilter</filter-class>
</filter>
view raw web.xml hosted with ❤ by GitHub


then add filter mapping to adfBindings filter

<filter-mapping>
<filter-name>adfBindings</filter-name>
<url-pattern>*.jsp</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>adfBindings</filter-name>
<url-pattern>*.jspx</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>adfBindings</filter-name>
<url-pattern>*.jsf</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
view raw web.xml hosted with ❤ by GitHub



Step13:
In AppModule update jbo.ampool.sessioncookiefactoryclass in AppModuleLocal and AppModuleShare to point to DynamicJDBCSessionCookieFactory




Step14:

Now run login.jspx and login with database username/password = hr/hr you will successfully login and  get the data



Logout then login again with wrong password as hr/hr1 you will get "Invalid username/password".





You can download the sample application from here




1 comment:

  1. Its excellent example .I am facing one problem. When i will use task-flow , instead of direct page (emp.jspx) . I can see only blank page .Let me know any solution.

    ReplyDelete