Search This Blog

Friday, May 30, 2014

Coding against specific OIM bundle patch jars

One of the difficulties of coding with the OIM API is that it occasionally changes.  A specific example occurred sometime before OIM 11gR2 BP11 where the behavior of the ProvisioningService.getAccountsProvisionedToUser(usrKey, searchCriteria) method call changed; at BP11 and above, this method call no longer returns the AccountData object in the Account instance.  This can obviously cause problems, and the person coding the Event Handler, Scheduled Task, or Process Task jar file won't know about the change until run time.  Use of Maven and JUnit testing will expose these issues during unit testing and prevent problems from occurring.

Best practice for dealing with this is to pull the needed jars file from the OIM server and push them up as jar files in your Maven repository.  One example that is used to provide many of the APIs is the file oimclient.jar so that will be described here.

I use a numbering scheme to reference the version similar to what Oracle does, for example the oimclient.jar file from the base R2, BP11 will be 11.1.2.0.11 and the oimclient.jar file from PS2 BP1 would be 11.1.2.2.1 and so on.  You can specify the version in your Maven dependencies of the pom file, but that doesn't make the file go into the repo.  You have to do that manually.

Here's how to push, for example, the oimclient.jar file from R2 BP11 up to Maven:

mvn install:install-file -Dfile=oimclient.jar -DgroupId=com.oracle -DartifactId=oimclient -Dversion=11.1.2.0.11 -Dpackaging=jar

Once that is pushed you can reference it successfully in your pom file.

One last thing, where do you get the oimclient.jar file from BP11 (or any BP)?  You should know by now that for R2, bundle patches are not done by overwriting all of the jars with new jars, and so you can't go into the bundle patch zip file and just pull out the jar files.  Bundle patches occasionally have a whole new jar file, usually if a class is to be removed from a jar, but most bundle patches are deltas, where in the patch folder the new classes are organized and the patch process replaces the class files in the jar files in place.  So the moral of the story is you have to patch a system before you can pull out the latest jar files, those jar files are nothing more than the current state of an organic system.  To figure out where the file is, use find: 

$ find $MW_HOME -name oimclient.jar -ls

Wednesday, May 21, 2014

Location of some jar files in OIM

Sometimes it is difficult to remember where the jar files are in OIM.  Here's my running list.

oracle.iam.connectors.icfcommon.* are in icf-oim-intg.jar

most of the rest of oracle.iam are located in OIMServer.jar including:

The implementation for ProvisioningService is in OIMServer.jar under:
oracle.iam.provisioning.implProvisioningServiceImpl

oracle.iam.selfservice.self.selfmgmt.impl.AuthenticatedSelfServiceImpl
oracle.iam.identity.usermgmt.impl.UserManagerImpl

oracle.iam.platform.tx.OIMTransactionManager is in oimclient.jar, iam-platform-utils.jar
com.thortech.xl.xjb.beansimpl.tcLookupOperationsBean is in xlDataObjectBeans.jar

org.apache.xml.serializer.ToStream is in xalan-2.6.0.jar

Thor.API.Operations.* interfaces, are implemented by classes in com.thortech.xl.ejb.beansimpl and are in the xlDataObjectBeans.jar file.

These often call a class com.thortech.xl.dataobj.APIUtils which is found in xlDataObjects.jar

Mappings getMapping are done by com.thortech.xl.orb.api.tcMapping which is in xlVO.jar which just converts a Map into an array of tcMapping objects.

The conversions are done in getColumnNameMap which maps the long values into short ones.  This is done in Thor.API.tcBaseUtility.getColumnNameMap and is in oimclient.jar

The query is:
select lku_field, lku_type_string_key from lku where lku_type='f' and lku_type_string_key in (" + msbCodeList + ")";

I have a utility called findclass that I use to search jar files for class names. 

Design Console - designconsole - The name of the Design Console is tcAppWindow and it is located in the file $OIM_ORACLE_HOME/server/client/lib/XellerateClient.jar

 




Thursday, February 27, 2014

OIM 11gR2 Connector Server setup mojo

Just some simple tips for setting up the connector server.  Some of these tips are from my colleagues, some I have modified what my colleagues are doing and so are my own take on things.

When building a connector server machine, it works very well to create a separate disk where all of the connector server software can be loaded and run from.  For a physical machine (iron) the D drive will be taken by a CD/DVD drive, and you can use E: for the connector server.  On a VM, you could choose to use D: or E:, whatever your preference.

On install never accept the Program Files folder for where the software is installed to.  If you followed the advice above you will install the software into the D: or E: drive, if not, install in the C: drive, so your top folder is E:\Identity Connectors (or your drive).  Under that you should have a Connector Server folder.

After install, decide where you want to put the log files.  The default is C: and that is a bad location for the files.  You can put the logs inside the Connector Server folder, in a separate folder, or on a third drive letter, for that matter.  I call my logs folder Logs with a capital L since this is Microsoft and we give civilized names to our folders in Windows, not like those "lower case-no blanks" Linux savages.

The bundles of course go into the Connector Server folder per the install guides for each connector.  Be sure to set the key first.  I will cover logging in a separate post.

I install WinSCP and Notepad++ on my connector servers so I can manage things easily.  I also make sure the Remote Admin tools including Active Directory Administrative Center, AD module for Windows PowerShell, Web Server (IIS) Tools, Telnet Client, and .NET 3.5.1 Framework Windows features are installed.

Finally, many people don't know how to set up a VIP on a windows box.  The command is:

netsh interface ip add address "Local Area Connection" <vip-address> <netmask>

The name "Local Area Connection" is an example, this needs to be the name of your existing Ethernet adapter.  Sometimes it is named Local Area Connection, other times it is named Online Network, but you need to find out what it is called by running ipconfig /all and noting it.  You are adding an address to the existing interface, so it needs to be the same.


Wednesday, February 26, 2014

Oracle Diagnostic Logging - getting deeper into OIM11gR2

Going deeper into OIM is a little different using ODL instead of the old log4j.properties file in OIM 9.1.0.2

If you have read my previous post on how to set up and hand modify the ODL files for your server, you will be able to perform these tasks.

Here are some interesting logging points I have tried:

  <logger name='oracle.iam.provisioning' level='TRACE:32'>
   <handler name='odl-handler'/>
  </logger>
  <logger name='oracle.iam.identity' level='TRACE:1'>
   <handler name='odl-handler'/>
  </logger>
  <logger name='Thor.API.Operations' level='TRACE:32'>
   <handler name='odl-handler'/>
  </logger>
  <logger name='XELLERATE.DATABASE' level='NOTIFICATION:32'>
   <handler name='odl-handler'/>
  </logger>
  <logger name='XELLERATE.SERVER' level='NOTIFICATION:1'>
   <handler name='odl-handler'/>
  </logger>
  <logger name='XELLERATE.SCHEDULER' level='NOTIFICATION:1'>
   <handler name='odl-handler'/>
  </logger>

 

The handler name was changed back to odl-handler, but I use my own handler that segregates the parts I am interested in.  I put all of the parts I am interested in, into a handler I call edu-handler, so in my logging.xml file, all of the above odl-handler references actually are edu-handler.  I just want someone who wants to copy/paste to not have a failure because they haven't defined an edu-handler.


OIM 11gR2 How to make plugins easier to manage

Making plugins easier to manage is simple.  I have a prior post that is not as detailed but is still applicable.  First, occasionally run this query against your database and export the results:

SELECT DISTINCT(ID) FROM PLUGINS ORDER BY ID ASC

This will give you a list of the current plugins you have. If you want to know more try this query:

SELECT ID,VERSION,NAME,TYPE FROM PLUGINS ORDER BY ID ASC, VERSION DESC

The second query will show if you have multiple versions.  The system should pick the highest numbered version, but I do not trust that.  IMHO, always keep just the latest copy of each plugin.

The second thing to do is to make the plugin utility easier to use.  Here's how:  Open the ant.properties file and make sure you have filled in the provided values.  I use MW_HOME in these examples but they need to be your $MW_HOME, spelled out in the file.

wls.home=$MW_HOME/wlserver_10.3
oim.home=$MW_HOME/Oracle_IDM1/server
login.config=${oim.home}/config/authwl.conf
mw.home=$MW_HOME

Correction: ant does not pick up the environment variables

mw.home=/u01/app/oracle/fmw
wls.home=/u01/app/oracle/fmw/wlserver_10.3
oim.home=/u01/app/oracle/fmw/Oracle_IDM1/server

Third, add the next 3 lines to the same file:

OIM.Username=xelsysadm
OIM.UserPassword=<your password>
ServerURL=t3://yourservice.yoursystem.yourdomain:14000
CtxFactory=weblogic.jndi.WLInitialContextFactory

Then you just run ant -f pluginregistration.xml unregister
All you have to type in is the password for xelsysadm
and paste the full class name from the export you did in step 1.

For the file names when you are running ant -f pluginregistration.xml register
I copy the files into a /home/oracle/plugins folder and then use:

find ~/plugins -name '*plugin*' -print


And then copy the line with the full pathname before I run the ant script.  Again I just enter the password for xelsysadm and then paste the filename.

Be sure to fully stop and restart all servers (no rolling restarts) to make the new plugins active.  I have found that PurgeCache does not work.


Thursday, February 20, 2014

OIM 11gR2 - When to use Platform.getServiceForEventHandlers

Just a quick reminder when creating Event Handlers (not for Scheduled Tasks)

UserManager usrMgr=Platform.getService (UserManager.class);

is used when you need to query for user parameters, such as when an orchestration might change one field, and you need to fill in other fields from the USR table in order to provide some kind of an update.  An example is Display Name, which, if only the Last Name is changed, you will want to retrieve the First and Middle Name fields in order to properly construct the Display Name.

Platform.getServiceForEventHandlers is used when you want to perform any kind of updates within an Event Handler.  Example:

ProvisioningService provSvcUP = Platform.getServiceForEventHandlers(ProvisioningService.class,
    null, "ADMIN","XXXHandler", null);


Tuesday, February 18, 2014

OIM11gR2 Using the old Thor interfaces

Sometimes you need to use the old Thor interfaces for getting information from the system. Lookups are one of these items, and that will be the example used here.

Also see my other posting OIM How to pull an IT Resource Parameter

Import the resource:

import Thor.API.Operations.tcLookupOperationsIntf;

Define the interface (spell something differently, in this case I used lower case L in lookup):

tcLookupOperationsIntf tclookupOperationsIntf =null;

Get the service:

tclookupOperationsintf = Platform.getService(tcLookupOperationsIntf.class);

Optionally you can do this all in one line.  You should null check the returned value.

Here's a completed task that just checks to see if a value is in a list:

Thor.API.tcResultSet rs=null;
try {
  rs=tclookupOperationsIntf.getLookupValues(validAccountLookup);
  int rowcount=rs.getRowCount();
  for (int irow=0; irow < rowcount; ++irow) {
    rs.goToRow(irow);
    String codeKey=rs.getStringValue

      ("Lookup Definition.Lookup Code Information.Code Key");
    String decode=rs.getStringValue
      ("Lookup Definition.Lookup Code Information.Decode");
    if (appInstanceName.equals(codeKey)) {
      logger.logp(Level.FINE, getClass().getName(), methodName,
        "Found "+appInstanceName+" in row "+irow+", returning true");
      return true;
    }
  }

}

I left out all of the checks and catches, just showing functional code.

Wednesday, February 12, 2014

Interesting point on SQL comparisons

Here's an interesting point regarding SQL in-equality comparisons.

An inequality expression normally looks like this:

where usr_udf_vegan <> '1'

If you work with OIM you will recognize the database field as a User Defined Field (UDF) and the value as the value of a "checked" checkbox which is a string value of '1' - but this is not limited to only OIM.

Now if you try to run this query against a table of values of '1', '0', and NULL, you might see that the NULL values don't get flagged as true.  You would think they would because they are not '1'.

In order to overcome this, add the following:

where (usr_udf_vegan is null or usr_udf_vegan <> '1')

The following also does not work:
where usr_udf_vegan not in ('1')

This specific issue came up with OIM role inequality comparisons and the fix is in the latest bundle patch of OIM.

Friday, January 17, 2014

Oracle OIM11gR2 finding the uploaded jar files

Thanks again to my colleagues for pointing this out.

The jar files you uploaded through UploadJars.sh are contained in the OIMHOME_JARS table.  It doesn't appear to use the update date so you will need to download the BLOB and SHA1 it to see if it is exactly what you expected to see.

Here's a hint.  Don't use a version numbered file for Java Tasks jar files.  You basically have to maintain that version number forever.  Better to use the non-version numbered jar file for deployment and use SHA1 to check a version numbered copy against what you have deployed.

Update: you can use a version numbered jar file for Java Tasks jar files.  The only issue is that you will see references to the older versions in the task adapters and you may be confused.  It is not an issue and the class loader will go to the new jar file.

Oracle Diagnostic Logging on Weblogic - Manual Modifications

My last post on this subject involved setup.  If you are a situation where you have classes in packages such as com.mycompany.subject.specificarea and you log into the ODL logging area, you can't easily search on com.  This is why I suggested your class packages are something more like mycompany.subject.specificarea leaving off the com part.

You can search on you mycompany name in the ODL log configuration page, but you won't get the high level box like if you search on com.  And so you have to change the logging level of each individual class, and if the class you are developing has never been called, it will not be in the list.  How to fix?

Start by setting a persistent log level for one of the classes in your package structure.  Don't do it for a second or more, that's overkill.  Next, save and log out of EM.

Next, log into your server and navigate to the domain for your admin server.  Then navigate to config/fmwconfig/servers/oim_server1 (or whatever your server name is) and then edit logging.xml

Find the section which contains your class name that you just modified.  Trim back the name as far back as you desire.  Generally I leave the com.mycompany

Log levels in this file are:

INCIDENT_ERROR:1 (SEVERE+100)

ERROR:1 (SEVERE)
WARNING:1 (WARN)
WARNING:32
NOTIFICATION:1 (INFO)
NOTIFICATION:16 (CONFIG)
NOTIFICATION:32
TRACE:1 (FINE)
TRACE:16 (FINER)
TRACE:32 (FINEST)

Restart the managed server.





Sunday, January 5, 2014

OIM11gR2 running design console on Windows machine

To run the design console on Windows:

Make sure you have a version of JRockit 1.6 on your Windows machine and have that path in your JAVA_HOME environment variable.

On the OIM machine, cd to $OIM_ORACLE_HOME which should be defined as $MW_HOME/Oracle_IDM1
Next, zip up the designconsole folder like this:

$ zip -r ~/designconsole.zip designconsole

Copy that file to your windows machine into a folder that reflects the environment it will connect to.

Unzip the file so it creates a designconsole folder with the xlclient.cmd file in that folder.

Edit the xlclient.cmd file.
Change the first part of the command to read "%JAVA_HOME%\bin\java"

Change the HOME_DIR to read -DXL.HomeDir=.

That's a single dot to indicate the current folder.

Change the auth to read:
-Djava.security.auth.login.config=config\authwl.conf

Save the file.

Now go back to the workstation and copy the following files to the ext folder:

$MW_HOME/oracle_common/modules/oracle.jrf_11.1.1/jrf-api.jar

At the very end of the classpath.bat file, there is a reference to the oracle_common/modules/jrf folder associated with the jrf-api.jar file.  Fix that so it references the ext folder.

This should allow you to double-click on the xlclient.cmd file to start the design console.

Oracle database scripts I like to use:

This blog is for my reference in quickly getting to Oracle database scripts I like to use.  Some of these are taken from other websites either verbatim or customized to my own preferences.

show_profiles.sql

clear breaks
set linesize 120
set pagesize 10000
select * from dba_profiles order by profile, resource_name;


show_users.sql

clear breaks
set linesize 120
set pagesize 10000
select username, profile, account_status from dba_users;


show_tablespaces.sql

clear breaks
SET linesize 130
SET pagesize 60
break ON tablespace_name skip 1
col tablespace_name format a15
col file_name format a50
col tablespace_kb heading 'TABLESPACE|TOTAL KB'
col kbytes_free heading 'TOTAL FREE|KBYTES'
SELECT dd.tablespace_name tablespace_name, dd.file_name file_name, dd.bytes/1024 TABLESPACE_KB, SUM(fs.bytes)/1024 KBYTES_FREE, MAX(fs.bytes)/1024 NEXT_FREE
FROM sys.dba_free_space fs, sys.dba_data_files dd
WHERE dd.tablespace_name = fs.tablespace_name
AND dd.file_id = fs.file_id
GROUP BY dd.tablespace_name, dd.file_name, dd.bytes/1024
ORDER BY dd.tablespace_name, dd.file_name;


show_datafiles.sql

clear breaks
set linesize 120
set pagesize 10000
col file_name format a70
col tablespace_name format a20
SELECT file_name, tablespace_name, ROUND(bytes/1024000) MB
FROM dba_data_files
ORDER BY 1;


show_freespace.sql

clear breaks
set linesize 120
set pagesize 10000
SELECT df.tablespace_name TABLESPACE, df.total_space TOTAL_SPACE,
fs.free_space FREE_SPACE, df.total_space_mb TOTAL_SPACE_MB,
(df.total_space_mb - fs.free_space_mb) USED_SPACE_MB,
fs.free_space_mb FREE_SPACE_MB,
ROUND(100 * (fs.free_space / df.total_space),2) PCT_FREE
FROM (SELECT tablespace_name, SUM(bytes) TOTAL_SPACE,
      ROUND(SUM(bytes) / 1048576) TOTAL_SPACE_MB
      FROM dba_data_files
      GROUP BY tablespace_name) df,
     (SELECT tablespace_name, SUM(bytes) FREE_SPACE,
       ROUND(SUM(bytes) / 1048576) FREE_SPACE_MB
       FROM dba_free_space
       GROUP BY tablespace_name) fs
WHERE df.tablespace_name = fs.tablespace_name(+)
ORDER BY fs.tablespace_name;


show_tables.sql <- uses a parameter

clear breaks
set linesize 120
set pagesize 10000
select owner, table_name, tablespace_name
from dba_tables
where tablespace_name='&1';


Here is a great link on formatting: 

And another link on selecting the first few rows: