Friday, June 6, 2008

OIM Customization for Resource Distinction

I came across a typical problem in OIM that the approver could not make a distinction of what resource he is approving when multiple resources of the same type are put in one request. Here is the snapshot:




So, here I present you with a customization that would allow your approvers to view the object form details on approval screen. My modifications will allow you to put multiple fields values right on the approval pages seperated by a ";". Please note that the first value will be the object form name itself following by all the multiple fields you want to display the values of. It will even work with Date attribute fields. I have created 2 resources Employee and Manual Application. In one request, I'm going to fill values for these object forms. Then we are going to modify one page in xlWebApp.war file and put in some customization code with a custom lookup. Once this is done, you will get around this issue.

Lets get started and I'll firstly reproduce the problem:



















So, now you see how there is no distinction in what resource the approver is approving.

1. Firstly, Backup your xlWebApp.war in some safe place.

2. Copy this xlWebApp.war in some location say : C:\eclipse\workspace

3. Extract this jar file by using the following command:
jar -xvf xlWebApp.war .

4. Next, lets dig right to the file that needs modification. Look for the following file:
C:\eclipse\workspace\xlWebApp\tiles\requestApprovalDetailTiles.jsp

5. Open this file in a Textpad and add the following lines of code:







<%!


public String getFormDataByObjectInstanceKey(String objectInstanceKey, String resourceName){
Context ctx = null;
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;

try{
String [] temp = null;
String name = "";
ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("java:jdbc/xlDS");
con = ds.getConnection();
con.setAutoCommit(false);
String stmt="select upper(lkv_encoded), lkv_decoded from lkv where upper(lkv_encoded)='"+resourceName.toUpperCase()+"' and lku_key =(select lku_key from lku where lku_type_string_key='Lookup.Resources.ObjectForm.FieldMappings') ";
System.out.println(stmt);
pstmt=con.prepareStatement(stmt);

rs=pstmt.executeQuery();
if(rs!=null && rs.next())
{
temp = rs.getString("LKV_DECODED").split(";");
pstmt=null;
rs=null;

String columns="";
System.out.println("------------");
for (int i = 1 ; i < temp.length ; i++) {
if(i>1)
columns=columns+" , ";
columns=columns+temp[i];
System.out.println("temp["+i+"] is "+temp[i]);
}
System.out.println("------------");

stmt="select "+columns+" from "+temp[0]+ " where obi_key= "+objectInstanceKey;
System.out.println(stmt);
pstmt = con.prepareStatement(stmt);
rs = pstmt.executeQuery();
while (rs.next()) {

for (int i = 1 ; i < temp.length ; i++) {
name =name+ " - "+rs.getString(temp[i]);
}
break;
}
System.out.println("out name : "+ name);
}
return name;
}catch(Exception exp){
exp.printStackTrace();
}finally{
try {
if(rs != null)
rs.close();

if(pstmt != null)
pstmt.close();

if(con != null )
con.close();
}catch(Exception ex)
{
ex.printStackTrace();
}
}

return "";

}



public String getResourceDetails(String requestKey, HttpSession session, String row, String resourceName){
String retVal="";
try {

retVal="Error - No Value Found for row : "+row+ " , request key : "+requestKey;
sessionContainer sessioncontainer;
sessioncontainer = (sessionContainer)session.getAttribute("Xellerate.Session");
tcRequestOperationsIntf tcrequestoperationsintf = sessioncontainer.getRequestOperationsIntf();
HashMap hashmap = new HashMap();
hashmap.put("Requests.Key", requestKey);
tcResultSet tcresultset1 = tcrequestoperationsintf.getRequestObjects(Long.parseLong(requestKey));

//System.out.println("First loop - i count = "+tcresultset1.getRowCount());

for(int i=0; i<tcresultset1.getRowCount(); i++)
{
String x=Integer.toString(i);
if ( x.equals(row)) {
tcresultset1.goToRow(i);
String value = tcresultset1.getStringValue("Object Instance.Key");
System.out.println("Object instance key is = " + value);
retVal = getFormDataByObjectInstanceKey(value, resourceName);
//System.out.println(" form data is = " + retVal);
}
}

}catch(Exception ex)
{
ex.printStackTrace();
}
return retVal;
}



%>

6. Update the following lines of code:

<nested:iterate id="resourceName" name="requestApprovalDetailForm" property="resourceNameList" length="1" offset="<%=indexId.toString()%>">
<% String resName= (String) resourceName; %>
<P class=InstructionText align=left><B><nested:write name="resourceName"/> <%= getResourceDetails(entityKey.toString(), session,indexId.toString(), resName) %></B></P>
</nested:iterate>



7. For your convenience, I am going to put the full modified source in a seperate blog. You may access this whole file here: http://rajnishbhatia19.blogspot.com/2008/06/requestapprovaldetailtilesjsp.html


8. Here is how the object forms looks for these Resource Objects.





9. I have created c.bat and written all the regular useful commands in a batch file. So, you can do the same and run c.bat from your command prompt.



10. Run c.bat and make sure your application is compiled successfully and deployed. Restart your app server.



11. In the design console, add a lookup Lookup.Resources.ObjectForm.FieldMappings that would have a resource name and the field names from the Object Forms.



12. Once you restart the server, here is now how it looks. It displays values from the object form right on the approval screen.





13. If you see the logs, you will see all the queries that are being created and run on the fly against the oim database.



14. When you run this query in the sqlplus, you see the values I am printing on the approval oim customized page.

1 comment:

Unknown said...

OIM Customization for generic asset approvals using AD groups.

Hi Rajnish,
I am new to OIM..
I have a requirement to customize OIM to provision users to one or more Groups in Active Directory.

The requirement is quite simple ->

My Client Org has 10-12 types of assets (Documents PDF,Docs and PS type). Among them few contain confidential information, so their access needs proper authorization approval.
Before allowing the user to view the docuement, the applicaiton will check the user's membership to certain groups in an Active Directory. (similar to manually checking the memberof Tab in AD user properties dialog)

Access to each type of document is by a security group memebership in Active Directory. Each document type has a security group assigned - Ex: Document type 1 has a Group AC_ASSET_DOC_1 in AD. Currently the user is added to this group manually, but we want to automate this process through a OIM approval work flow.

The required flow is

User should have option to request the document type they want access to from the "request for resource " link in OIM.
The request should start a approval work flow..when approved should provision the user to groups in AD corresponding to the document/resource.

My questions are

1 How to show documents as resources in AD so that Users can request and approvers can approve/reject.


2 How to provision a user to multiple groups in AD.


I did post this to OIM Oracle User group. Got some response but not the final okay.. Just wanted to double check with you guys.

this what I came up with..

On OIM I create a group corresponding to the security group in Active directory.
Create a Group access policy as and have only the corresponding group in AD in the Child form .

create a Generic resource for a document that needs to be protected. ( ultimately there would be one such resource for each document type)
configure an Approval and Provisioning workflow for this generic resource.

Approval workflow contains the required logic.


In the provisioning workflow create a task to provision the user to this OIM group ?

I still havent understood how the provisioning to AD group would work (specially the case when the user alaready exisits ..)

Is this correct.. please let me know

Thanks in advance.. you guys are