Friday, December 14, 2012

Using Bean in Expression language with parameter to check user Authorization

There were many questions in how to build a customized bean and use it in expression language to return user authorization based on specific parameter passed through expression language. In here I will describe the steps in how to build your own bean, accessing its methods and passing parameter to it.

This first step is develop the method that you want to receive your parameter and return the success or failure logic, the authorization roles in my scenario are stored in ViewObject based on dynamic SQL statements that loads the roles from different tables depending on some HR and Assignment statues:


public class AuthorizationBean {
 
    private ApplicationModule appModule=ADFFacesHelper.getAppplicationModule("AppModuleDataControl");

    public AuthorizationBean() {
        super();
    }

    
    public boolean getUserInRole(String RoleCode){
        boolean havePriv=false;
        ViewObject userRoles=appModule.findViewObject("UserRolesVO1");
        RowSet rowSet=userRoles.getRowSet();
        Row row=rowSet.first();
        while(row!=null){         
            String roleCode=row.getAttribute("RoleCode").toString();            
            if(roleCode.equals(RoleCode)){
                havePriv=true;
            }
            row=rowSet.next();
        }
        return havePriv;
    }
 }

The next step is define a bean that will act as an interface between the Authorization bean and expression language, it will receive the parameter from expression language and pass it to a method developed earlier, the class should implements HashMap interface and implements get(Object) method:

import java.util.HashMap;

public class CallAuthorizationBean extends HashMap {
    public CallAuthorizationBean() {
        super();
    }

    public String get(Object key) {
        AuthorizationBean authorization=new AuthorizationBean();
         return ""+authorization.getUserInRole((String)key);
    }
}

Finally, you can call the customized method using expression language like this:
#{Authorization['20180100']=='false'}

Monday, October 8, 2012

Send Parameters to ActionListener and read it programmatically



You can send parameters when invoking ActionListener behavior by adding the f:attribute tag to Action issuer as explained below on commandButton component:



<af:commandButton text="send attribute" id="cb1"    actionListener="#{bean.method1}">    <f:attribute name="param" value="value"/></af:commandButton>




Then you can read  the attribute programmatically inside the method:

 public void method1(ActionEvent actionEvent) {
    String param = (String)actionEvent.getComponent().getAttributes().get("param");
    System.out.println(param);
    }

Saturday, July 7, 2012

Row level Security using ADF and Sys_context package

When Developing a web application you must know that Database connection will be shared between different end users. Traditional Forms applications create a connection for each client connecting to the database while ADF shares the same connection pool and try to activate/passivate connection based on end user transactions.

Implementing Row level security or (Virtual Private Database) VPD can be into two ways:

- By Building a view on each table you have on your owner schema, and then adding the where condition inside view SQL script that will do the predicate based on user context variables.

- Or by using DBMS.RLS package by creating a policy procedure, and then add this policy to schema table using DBMS.RLS.Add_Policy(), the procedure returns the predicate to the table to execute the appropriate command in varchar2 format that contains your conditions.

In here I will demonstrate how to build and use context package through ADF web application using the first approach, the second one is easy to implement once you build the context package and you knew where to call it inside your ADF application.

At first you need to create CTX package at your owner schema:

CREATE OR REPLACE PACKAGE SEC_CTX_PKG IS 
   PROCEDURE SET_SESSION_ID (IN_SESSION_ID VARCHAR2); 
   PROCEDURE SET_CONTEXT (IN_NAME VARCHAR2, IN_VALUE VARCHAR2); 
 END SEC_CTX_PKG;
/

--------------------------------------------------------------------------------------------------
CREATE OR REPLACE PACKAGE BODY SEC_CTX_PKG 
 IS 
   GC$SESSION_ID  VARCHAR2 (100); 
   PROCEDURE SET_SESSION_ID (IN_SESSION_ID VARCHAR2) 
   IS 
   BEGIN 
    GC$SESSION_ID := IN_SESSION_ID;
    DBMS_SESSION.SET_IDENTIFIER (IN_SESSION_ID);
  END;  

-------------------------------------------------------------------------------------------------
   PROCEDURE SET_CONTEXT (IN_NAME VARCHAR2, IN_VALUE VARCHAR2) 
   IS 
   BEGIN 
    DBMS_SESSION.SET_CONTEXT ('SEC_CTX', IN_NAME, IN_VALUE, USER, 
                 GC$SESSION_ID); 
   END; 
 END SEC_CTX_PKG;
/


Then you need to create your own context variable:
CREATE OR REPLACE CONTEXT SEC_CTX
 USING SEC_CTX_PKG
 ACCESSED GLOBALLY;

 

You need to create a view on table that you want to filter at database which have the predicate. As an example if I have a table called user_info, I will be building a view called user_info_v as following:
SELECT *
     FROM user_info
    WHERE user_id = SYS_CONTEXT ('SEC_CTX', 'user_id_p');


All Developers should use this view to retrieve, insert, update and delete data.

This is all created at your table owner schema. Now moving to the ADF application part, you need to override the prepareSession method for the application module connecting to schema. The prepareSession allow the application module to initialize user defined context variable at our case user_id_p parameter.

    protected void prepareSession(Session session) {
        super.prepareSession(session);
        setVPDcontext(session);
    }



    private void setVPDcontext(Session session) {
        SessionImpl session2 = (SessionImpl)transaction.getSession();
        String username=session2.getUserPrincipalName();

        CallableStatement stmt = null;
       
        try {          
            String sql = "BEGIN  SEC_CTX_PKG.SET_SESSION_ID ('"+username+"');                  

                        CTX_PKG.SET_CONTEXT ('user_id_p', '"+username+"'); END; ";
            stmt = this.getDBTransaction().createCallableStatement(sql, 0);
            stmt.execute();
        } catch (Exception exp) {
            exp.printStackTrace();
        } finally {
            if (stmt != null) {
                try {
                    stmt.close();
                } catch (Exception exp) {
                    exp.printStackTrace();
                }
            }
        }
    }


Of-course you can add complex conditions, but this for demo only. If you want to filter the data on table base use DBMS.RLS package rather than building view on top of the table.

Sunday, January 22, 2012

Building and Deploying Enterprise Application

If you are building enterprise application you should consider breaking down your modules into workspaces and then deploy these applications separately as shared libraries, then consume through user shell interface.

we will discuses here how to create and deploy shared library, and then how to call task flows in a dynamic region from different shared libraries.

Before we begin you should consider the naming convention and its uniqueness through shared applications. Each project or workspace must have its unique name, the packages inside should be unique as well, the model and viewcontroller projects should have also unique package naming, as an example (com.google.hr) (com.google.crm).


In here we will create two applications, one will be the shared adf library packaged entirely built as ADF application (ChildApp), the second one the Main application (Parent App) that will call the taskflows as dynamic regions from the shared module.


For the ChildApp,  what you need to do after building it is to create a MAINFEST.MF file that have the appropriate extension name and version for your application, the MAINFEST.MF file should be created under src/META-INFO/ directory with the following entries:

Manifest-Version: 1.0
Implementation-Title: webBrain
Extension-Name: webbrain.shared.lib
Specification-Version: 1.0.0
Implementation-Version: 1.0.0
Implementation-Vendor: webBrain

You need to create two deployment descriptors, the first one will be as a WAR file with empty context root.
 

and then you need to add the MAINFEST file created to war options.


Then you need to deploy your war file to weblogic as shared library.


Then you have to create new deployment descriptor and deploy the application as ADF Library Jar file for the sake of compilation at the Main parent application.


At the Main Parent application you need to add the library under the libraries and classpth for your project.


add a dynamic region for your jsf page with managed bean to control the dynamic region taskflows.



modify or create the weblogic.xml file to point the shared library deployed to weblogic server.


remove the ADF Library from the deployment filters, then deploy the main Parent application.