Oracle had his strategy briefing with his plans for BEA not too long ago. The BEA stack will have some overlap on the different parts of the fusion stack. One of these will be the Oracle ESB and the BEA AquaLogic Service Bus. Both products will be merged into the new ‘Oracle Service Bus’. Customers from both products will get the opportunity to upgrade to the new one. Some rumours told us the AquaLogic Service Bus will be the lead in supporting most of the new functionality for the new bus. Changes planned for the new 11g release will be integrated into the new OSB. Most important changes in this Oracle BEA AquaLogic Service Bus will be the JCA support and the migration of the 100+ adapters from the current Oracle ESB. So..for the consultants who developed with the Oracle ESB it’s a good moment to start looking at the AquaLogic Service Bus.

The installation
First download the installation-files :

Extract the zipfile and we’re ready for the installation.
The installation of the BEA products can use the following modes for installation :
- Graphical mode
- Console mode
- Silent mode
We’re ready for the installation.
./alsb300_wls100_linux32.bin -log=/tmp/alsb/alsb_install.log -Djava.io.tmpdir=/tmp/alsb
This will start the installer by default in graphical mode. The ’-log’ option will create a verbose log file during installation. The ‘-Djava.io.tmpdir=/tmp/alsb’ will set the tmp-dir for installation.

start installation

create new home directory

select the products you want to install, we will just install the whole stack

configurate the locations of the seperate products

quickstart window for some extra learning options and tools
In you started the installation in graphical mode, you’ll have the option to start the quickstart if install is finished. The quickstart will give the first-time users some options for learning and evaluating the WebLogic products.
To manually start the quickstart-installer :
<bea_home>/wlserver_10.0/common/bin/quickstart.sh
Well..installation of the BEA AquaLogic Service Bus is done!
Configuration of domains
Before we can start developing our applications we need to create a domain. Parts of a domain are Administration Server, Managed Server and Cluster. A domain will include one WebLogin Server instance which is configured as an Administration Server. In this domain the default BEA applications like the Administration Console will be installed. If we compair this to the Oracle OC4J, this would be the default home oc4j-container. All the other instances in a domain will be called Managed Servers. In those instances our custom applications will be installed. In Oracle OC4J this will be all the other installed containers besides the home-container (for example : oc4j_ws for the webservices we develop). Oracle recommends not to deploy custom application in the home-container. It’s best to leave this default, and deploy your own applications to some other created application. BEA recommends the same for WebLogic Server. By default the applications for management tasks will get installed in the Administration Server. Our own applications we will install in a Managed Server instances.
The Configuration Wizard will help us creating the domains. The installed can be used in the following modes :
- Graphical mode
- Console mode
To start the wizard :
</bea_home><bea_home>/wlserver_10.0/common/bin/config.sh
This will start the wizard in graphical mode.

create new domain or extend an existing one.

select for which products we want to create the domain, we will first only use it for the alsb.

configurate the administrator account, remember those settings, you will need them later for the console login.

select the startup mode of the domain (production/development) and the jvm you’re going to use.
for testing we will just select development and the sun sdk.

if you want to customize some of the default setting of the domain

domainname and the location where the configfiles will get stored

And the configuration of the domain is done. The configuration-files for our newly created domain can be found overhere :
</bea_home><bea_home>/user_projects/domains/iteye_domain
In the root of this domain we need to execute startWebLogic.sh to start the domain.
<mar 30, 2008 12:55:41 AM CET> <notice> <weblogicserver> <bea -000360> <server started in RUNNING mode>
The domain is running.
The default location of the AquaLogic Service Bus Console :
http://yourownhostname:7001/sbconsole
For the Username/password use the info we just used at the Configuration Wizard.

So far the installation of the new bus. In some of the next blogs i will try to give some sample esb applications.
Posted July 30th, 2008 by Eric Elzinga | 7 Comments »
Oracle just released Oracle JDeveloper (10.1.3.4) (Build 4270)
And the list of bugfixes ..
Posted July 29th, 2008 by Eric Elzinga | 1 Comment »
In two previous posts i demonstrated how to use openoffice from java (see Getting started using openoffice in java and Mailmerge MS-Word template using OpenOffice and Java). Here’s a small example illustrating how you can show and hide the document window.
When you’ve created an XComponent object for your document, you can get it’s window as follows, and hide and display it using the setVisible method:
XTextDocument xTextDocument = (XTextDocument) UnoRuntime
.queryInterface(XTextDocument.class, document);
xTextDocument.getCurrentController().getFrame().getContainerWindow()
.setVisible(true);
Posted July 28th, 2008 by Andrej Koelewijn | No Comments »
Update When i wrote this post i was pretty skeptical about SOFEA/SOUI, but having build some apps using jquery and grails rest services, i am now convinced that this is a very useful and productive architecture for a lot of applications. Implementing the complete client side using javascript in the browser, communicating with services in SOA containers turns out to be very simple and productive. But i think we need a more appealing name for this architecture. Client Server 2.0 seems to be the most appropriate, although it might not be the most sexy name. Read my follow-up post Client Server 2.0 why i think this name best describes the next step in UI design.
Original post
Last week at the OSCON matt raible did a presentation on Web Frameworks of the Future: Flex, GWT, Grails and Rails. One of the topics in his presentation is service based user interfaces, also known as SOFEA (Service oriented frontend architecture) or SOUI (service oriented user interface).
Core to these architectures is a separation between service layer, and the UI layer. You can run your service layer on a (java) application server, and the UI layer completely in the browser, either using a AJAX or some sort of plugin (FLEX, etc). Communication between the layers can be based on SOAP, XML, JSON, or something similar.
We’ve used a similar architecture on a couple of projects in the past: all services were implemented using webservices, and these webservices were called from the user interface layer. The only difference is that we implemented the user interface using JSF technology. But the goal was the same as with SOFEA/SOUI: create a layer of generic, reusable services, not tied to a particular application.
This goal is good if you achieve it, but it’s not easy to achieve. We ran into some problems:
- lousy productivity – when there’s nothing to reuse, and you have to implement all the services required, productivity is pretty bad. Mostly because there’s just more technology between user interface and database then when you just use jsf+spring+hibernate.
- hard to change – we found the applications hard to change: when you want to add some fields to a form there’s more layers to modify, with less tool support to do it. If you’re just working with java, refactoring is easy, but when you have to deal with soap, xml, xml-schema and even esb and bpel, making one simple change has a lot more impact.
- complex, hard to learn – you have more layers, more technology, so it’s harder to understand and work with. It takes more time to get new developers up to speed, and it’s harder to find cross-functional developers who can implements your requirements from user interface to database, so you need more developers, and more communication.
- hard to design generic services – designing reusable generic services is hard. You have to try to anticipate future use. But often this goes against performance. To achieve good performance we’ve had to put less information into the xml files returned by the services. In the end, often this meant application specific web services, only returning the data required by the user interface. Not very generic, not reusable, so mainly a waste of time and performance to use web services.
- bad performance – lots of unnecessary data translations, from database to java to xml to java to xml to java to html, or even worse depending on the number of esb and bpel processes used.
The funny thing is that recently we did a project the old, conservative, way, using spring framework, hibernate, and jsf, and a lot of the developers like it a lot better. Development is fun again: you can implement user requirements very fast, developers can work on their own features from top to bottom. This also makes project management a lot easier, a simpler critical path. And productivity is a lot better too.
Posted July 28th, 2008 by Andrej Koelewijn | 12 Comments »
Kees Jan Koster has started a forum about Java Administration and Tomcat Administration. Head over if you have any questions or tips on monitoring java applications, or if you need some help on performance tuning your web application.
There’s already a useful thread on using jconsole with different application servers. This thread also mentions tools like jManage, Zapcat and VisualVM. Which tool do you prefer?
Posted July 23rd, 2008 by Andrej Koelewijn | No Comments »
The following example is a bit of a hack, as I’m not really using openoffice’s mailmerge facilities to perform the mailmerge. OpenOffice enables you to register database sources, and link fields in your document to the database.
Actually, mailmerge fields need to be linked to a database source. If they’re not, you have a problem. If you create a new writer document based on an MS-Word template (.dot) in OpenOffice, without having the database used by the mailmerge fields registered, and save the document, you loose the mailmerge fields.
So you need to have the database registered. But, as far as i can tell, you cannot see the database needed by the mailmerge fields when you open de MS-Word template in OpenOffice.
But in my case, i don’t need a database. I just want to replace some fields in the document with values i already have in my java program. So i’ve written my own mailmerge routine, which replaces all the mailmerge fields in the document with the values i have.
The first part is similar to my previous example, Getting started using openoffice in java. Create a connection from java to openoffice:
// connect to open office
com.sun.star.uno.XComponentContext xContext = com.sun.star.comp.helper.Bootstrap
.bootstrap();
com.sun.star.lang.XMultiComponentFactory xMCF = xContext
.getServiceManager();
Object oDesktop = xMCF.createInstanceWithContext(
"com.sun.star.frame.Desktop", xContext);
XComponentLoader xCLoader = (com.sun.star.frame.XComponentLoader) UnoRuntime
.queryInterface(com.sun.star.frame.XComponentLoader.class,
oDesktop);
Next i create a new OpenOffice document based on an MS-Word template containing mailmerge fields:
// create new document based on template
PropertyValue[] loadProps = null;
loadProps = new PropertyValue[1];
loadProps[0] = new PropertyValue();
loadProps[0].Name = "AsTemplate";
loadProps[0].Value = new Boolean(true);
XComponent document = xCLoader.loadComponentFromURL(
"file:///home/akoelewijn/Desktop/letter-template.dot",
"_blank", 0, new PropertyValue[0]);
Here i create an hashtable containing fieldnames, and the values i want to merge into the document:
// specify values for mailmerge fields
Hashtable<string , String> fieldData = new Hashtable</string><string , String>();
fieldData.put("FIELD_1", "Stevens");
fieldData.put("FIELD_2", "John");
fieldData.put("FIELD_3", "January 5th, 1972");
This is the actual mailmerge routine. The program loops through all fields in the document, determines whether it’s a mailmerge field, and replaces the Context property with the value from the hashtable.
// replace mailmerge fields
try {
XTextFieldsSupplier xTextFieldsSupplier = (XTextFieldsSupplier) UnoRuntime
.queryInterface(XTextFieldsSupplier.class, document);
XEnumerationAccess xEnumeratedFields = xTextFieldsSupplier
.getTextFields();
// loop through all fields, as we cannot get ms-merge fields by
// name
XEnumeration e = xEnumeratedFields.createEnumeration();
while (e.hasMoreElements()) {
Any tf = (Any) e.nextElement();
XTextField xtf = (XTextField) tf.getObject();
// get the properties of the field
XPropertySet xPropertySet = (XPropertySet) UnoRuntime
.queryInterface(XPropertySet.class, xtf);
try {
// for ms-word mailmergefield the fieldcode looks
// like: MERGEFIELD FIELD_3 * MERGEFORMAT
String fieldCode = (String) xPropertySet
.getPropertyValue("FieldCode");
// check if this is a mailmerge field
if (fieldCode.trim().startsWith("MERGEFIELD")) {
String fieldName = fieldCode.replaceAll(
"(MERGEFIELD | MERGEFORMAT|\*|\\)", "")
.trim();
if (fieldData.containsKey(fieldName)) {
String value = (String) fieldData
.get(fieldName);
// set the content of the field
xPropertySet.setPropertyValue("Content", value);
}
}
} catch (UnknownPropertyException ex) {
// Fieldcode property doesn't exist, ignore
}
}
} catch (Exception e) {
e.printStackTrace();
}
Now i can save the document as an ODF text document:
// save document
XStorable xStorable = (XStorable) UnoRuntime.queryInterface(
XStorable.class, document);
PropertyValue[] storeProps = new PropertyValue[0];
xStorable.storeAsURL("file:///tmp/merged-letter.odt", storeProps);
And finally i close the the document.
// close document
XCloseable xcloseable = (XCloseable) UnoRuntime.queryInterface(
XCloseable.class, document);
xcloseable.close(false);
Posted July 23rd, 2008 by Andrej Koelewijn | 8 Comments »
I’ve recently started using the OpenOffice api’s to generate documents using Java. The openoffice api’s are very powerful, but not the easiest to work with. So i thought it might be helpful to put some simple examples on this weblog.
Open Source tenzij
The dutch government has a policy called “Open Standaarden en Open Source Tenzij”, translated: “Open Standards and Source Unless”. This means that government agencies are encouraged to use open standards and open source unless it’s not possible. Recently we’ve seen some real effects of this policy: agencies that used to use oracle and microsoft software for everything, now request open source technologies to be used for projects.
Open source and Java is a pretty good match. In fact, it would say that the most popular Java frameworks are open source: the Spring Framework and Hibernate. Also, all Java Standards (JSRs) have to have an open source Reference implementation. So, having to use open source is not a restriction when you’re using Java.
Using an open source operating system is also nothing new: most servers that we use these days run on Linux. Using Linux on the desktop is less common, but certainly doable. I’d say for software developers Linux is a good desktop environment (I have an 24″ iMac at home, but i prefer using my Dell Linux laptop for programming. I use the Mac mostly for video editing, there really isn’t any good Linux Video editing software).
OpenOffice
We are currently helping a dutch local government migrate their software to opensource desktops. The first step in this migration is getting their Oracle Forms running on linux. Currently these Forms use MS-Office to generate letters. Since there’s no MS-office available on Linux, this part needs to be rewritten to use OpenOffice. Using a Java bean embedded in Forms we can use the OpenOffice api’s to merge database values into the document templates. In a later example i’ll show you how you can replace mergefields in a word-template using openoffice and java, but i’ll start with a simpler example. The example below shows you how you can create a new document in Open Office, add some headers and paragraphs, and save the document as an ODF text document and as a PDF document.
OpenOffice and Java
Before you begin, you need to have a copy of OpenOffice.org installed. You also need the following jars on your classpath:
- juh.jar
- jurt.jar
- ridl.jar
- unoil.jar
You can find these jars in your openoffice directory in program/classes, but you can also download them using maven or ivy. You also need the program directory from your openoffice installation directory on your classpath otherwise you’ll get the following error message: com.sun.star.comp.helper.BootstrapException: no office executable found!
First thing you need to do in your application is connect to openoffice. The following code will start an instance of openoffice if it’s not running:
// connect to open office
com.sun.star.uno.XComponentContext xContext =
com.sun.star.comp.helper.Bootstrap.bootstrap();
com.sun.star.lang.XMultiComponentFactory xMCF =
xContext.getServiceManager();
Object oDesktop = xMCF.createInstanceWithContext(
"com.sun.star.frame.Desktop", xContext);
XComponentLoader xCLoader = (com.sun.star.frame.XComponentLoader) UnoRuntime
.queryInterface(com.sun.star.frame.XComponentLoader.class,
oDesktop);
Next we can create an empty document in a new writer window.
// create document
XComponent document = xCLoader.loadComponentFromURL(
"private:factory/swriter", "_blank", 0,
new PropertyValue[0]);
XTextDocument xTextDocument = (XTextDocument)
UnoRuntime.queryInterface(XTextDocument.class,
document);
XText xText = xTextDocument.getText();
I’m going to use some default openoffice paragraph styling, for this i need a paragraph cursor.
// create a paragraph cursor
XParagraphCursor xParagraphCursor = (XParagraphCursor) UnoRuntime
.queryInterface(XParagraphCursor.class, xText
.createTextCursor());
Now i can append my first piece text to the document:
// add some text
xText.insertString(xText.getEnd(), "My First OpenOffice Document",
false);
For styling i need to set the ParaStyleName property of the paragraph cursor to the style i want for the paragraph. As the first line of text contains my document title, i’ll give it the style Heading 1. This is a default openoffice style, so i don’t have to define it.
// style the paragraph
XPropertySet xPropertySet = (XPropertySet) UnoRuntime
.queryInterface(XPropertySet.class, xParagraphCursor);
xPropertySet.setPropertyValue("ParaStyleName", "Heading 1");
Next i can add some more paragraphs. I’m using escape r (r) to specify the start of a new paragraph. After inserting the text i use the paragraph property to specify the style required for the paragraph.
// add some text
xText.insertString(xText.getEnd(),
"rThis is the first line in my paragraph. "
+ "Some more text, just to add some text to this document. ",
false);
xPropertySet.setPropertyValue("ParaStyleName", "Text body");
// Add another heading paragraph
xText.insertString(xText.getEnd(), "rSecond heading", false);
xPropertySet.setPropertyValue("ParaStyleName", "Heading 2");
// And another text body paragraph
xText.insertString(xText.getEnd(),
"rThis is the second normal paragraph.", false);
xPropertySet.setPropertyValue("ParaStyleName", "Text body");
You can store the document as an ODF text document as follows:
// save document
XStorable xStorable = (XStorable) UnoRuntime.queryInterface(
XStorable.class, document);
PropertyValue[] storeProps = new PropertyValue[0];
xStorable.storeAsURL("file:///tmp/first_document.odt", storeProps);
When you want to export the document as a pdf document you need to specify a filtername: writer_pdf_Export. Also note that you need to call storeToURL instead of storeAsURL, otherwise you’ll get the following, very helpful, exception: com.sun.star.task.ErrorCodeIOException.
// export document to pdf
storeProps = new PropertyValue[1];
storeProps[0] = new PropertyValue();
storeProps[0].Name = "FilterName";
storeProps[0].Value = "writer_pdf_Export";
xStorable.storeToURL("file:///tmp/first_document.pdf", storeProps);
Now we can close the document:
// close document
XCloseable xcloseable = (XCloseable) UnoRuntime.queryInterface(
XCloseable.class, document);
xcloseable.close(false);
In the next example i’ll show you how you can replace mergefields in an ms-word template using openoffice and java.
Posted July 22nd, 2008 by Andrej Koelewijn | 13 Comments »
In a previous example, Using iBatis with a stored function returning a ROWTYPE, i demonstrated one way to deal with object type: cast them to simple types using plsql code in your sqlMap file. In this example i’ll show you how you can work with oracle object types using an ibatis typeHandler.
Here’s the object that i’ll be returning from by packages plsql function:
CREATE OR REPLACE type employee_obj
AS
object (
id NUMBER(10) ,
name VARCHAR2(100) ,
date_of_birth DATE
)
/
Here is the function querying a row from a table and returning the row as an oracle object type:
function get_employee_obj_by_id (
p_id in number
) return employee_obj is
l_employee employee_obj;
begin
select employee_obj(id,name,date_of_birth)
into l_employee
from employees
where id = p_id;
return l_employee;
end;
In the sqlMap configuration you need to specify a typeHandler for the object type parameter. The typeName is the name of the oracle object type:
<parametermap id="parameters5" class="map">
<parameter property="employee" jdbcType="STRUCT" typeName="EMPLOYEE_OBJ"
javaType="nl.iteye.ibatis.example1.Employee" mode="OUT"
typeHandler="nl.iteye.ibatis.example1.EmployeeTypeHandlerCallback"/>
<parameter property="id" jdbcType="NUMERIC" javaType="java.lang.Long"
mode="IN"/>
</parametermap>
<procedure id="selectEmployeeObjectByIdFunc" parameterMap="parameters5">
< ![CDATA[
{ ? = call employee_pkg.get_employee_obj_by_id( ? ) }
]]>
</procedure>
In the TypeHandlerCallback it’s sufficient to implement the getResult method:
package nl.iteye.ibatis.example1;
import com.ibatis.sqlmap.client.extensions.ParameterSetter;
import com.ibatis.sqlmap.client.extensions.ResultGetter;
import com.ibatis.sqlmap.client.extensions.TypeHandlerCallback;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.Date;
import oracle.sql.STRUCT;
public class EmployeeTypeHandlerCallback implements TypeHandlerCallback {
public EmployeeTypeHandlerCallback() { }
public void setParameter(ParameterSetter setter, Object parameter) { }
public Object getResult(ResultGetter getter) {
Employee emp = null;
try {
STRUCT s = null;
s = (STRUCT)getter.getObject();
emp = new Employee();
emp.setId(((BigDecimal)s.getAttributes()[0]).longValue());
emp.setName((String)s.getAttributes()[1]);
emp.setDateOfBirth((Date)s.getAttributes()[2]);
} catch (SQLException e) {
e.printStackTrace();
}
System.out.println(emp);
return emp;
}
public Object valueOf(String s) {
return null;
}
}
Now you can use this as follows:
Long id = new Long(3);
Map pars = new HashMap();
pars.put("id", id);
sqlMapper.queryForObject("selectEmployeeObjectByIdFunc", pars);
Employee emp = (Employee) pars.get("employee");
System.out.println("Query by id " + id + ": " + emp);
For more iBatis examples take a look at: Using iBatis with Oracle.
Posted July 21st, 2008 by Andrej Koelewijn | 2 Comments »
Here’s an alternative for the example in my previous post: Using iBatis to cast a returned Collection Type to a Ref Cursor. Instead of using a ref cursor to query all the records in a collection type, i’m going to use an iBatis TypeHandlerCallback to get all the data into java objects.
This example uses the same object type and collection type as the previous example:
CREATE OR REPLACE type employee_obj
AS
object (
id NUMBER(10) ,
name VARCHAR2(100) ,
date_of_birth DATE
)
/
CREATE OR REPLACE type employee_tbl
AS
TABLE OF employee_obj
/
Here’s the function to find employees with a matching name:
function find_employees (
p_name in varchar2
) return employee_tbl is
l_employees_tbl employee_tbl := employee_tbl();
begin
for r in (
select employee_obj(id,name,date_of_birth) as employee_obj
from employees
where name like p_name
) loop
l_employees_tbl.extend;
l_employees_tbl(l_employees_tbl.last) := r.employee_obj;
end loop;
return l_employees_tbl;
end;
The sqlMap configuration is a bit different from the previous example. Instead of an ORACLECURSOR jdbcType we use an ARRAY here. We also specify a typeHandler for the return parameter.
<parametermap id="parameters4b" class="map">
<parameter property="name" jdbcType="VARCHAR" javaType="java.lang.String"
mode="IN"/>
<parameter property="employees" javaType="OBJECT" typeName="EMPLOYEE_TBL"
jdbcType="ARRAY" mode="OUT"
typeHandler="nl.iteye.ibatis.example1.EmployeeTableTypeHandlerCallback"/>
</parametermap>
<procedure id="findEmployeesTbl" parameterMap="parameters4b">
< ![CDATA[
{ call
declare
l_tbl employee_tbl;
begin
l_tbl := employee_pkg.find_employees(?);
? := l_tbl;
end
}
]]>
</procedure>
The typeHandlerCallback implementation looks like this:
package nl.iteye.ibatis.example1;
import com.ibatis.sqlmap.client.extensions.ParameterSetter;
import com.ibatis.sqlmap.client.extensions.ResultGetter;
import com.ibatis.sqlmap.client.extensions.TypeHandlerCallback;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import oracle.sql.ARRAY;
import oracle.sql.STRUCT;
public class EmployeeTableTypeHandlerCallback implements TypeHandlerCallback {
public EmployeeTableTypeHandlerCallback() {
}
public void setParameter(ParameterSetter setter, Object parameter) {
}
public Object getResult(ResultGetter getter) {
ArrayList result = new ArrayList();
try {
ARRAY array = (ARRAY)getter.getObject();
Object[] employees = (Object[])array.getArray();
for (Object emp: employees) {
STRUCT s = (STRUCT)emp;
Employee e = new Employee();
e.setId(((BigDecimal)s.getAttributes()[0]).longValue());
e.setName((String)s.getAttributes()[1]);
e.setDateOfBirth((Date)s.getAttributes()[2]);
result.add(e);
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
public Object valueOf(String s) {
return null;
}
}
The only part we need to implement for this example is the getResult method. It gets the returned Array from the resultset, and creates an ArrayList with Employee objects.
You can use this in the same way as our previous approach:
Map pars = new HashMap();
pars.put("name", "%a%");
sqlMapper.queryForObject("findEmployeesTbl", pars);
ArrayList<employee> emps =
(ArrayList</employee><employee>)pars.get("employees");
for (Employee emp: emps) {
System.out.println("name: " + emp);
}
Next post about ibatis is Using iBatis with a stored function returning an Object Type. More iBatis examples can be found in using iBatis with Oracle.
Posted July 18th, 2008 by Andrej Koelewijn | 6 Comments »
At some point we were discussing if it would be possible to synchronize user account based on group membership using the default procedures of Oracle Identity Management.
The idea is to sync as little user accounts as possible to our Oracle Internet Directory where the user accounts are spread over a width range of Active Directory containers were different policies apply to. Not all users in these containers need to have access to the Oracle applications which are integrated with the Oracle Identity Management.
So by granting a user a special group priviledge (soa) in Active Directory it should be synced to Oracle Internet Directory. Other users should not be synced as they are not part of this special “soa” group. When this grant would be revoked, the user account should also be deleted from our Oracle Internet Directory.
Case1 :We are synchronizing all users from Active Directory to Oracle Internet Directory.
When we use a basic searchfilter like :
searchfilter=(&(objectclass=user)
We get all users added and deleted in AD to be processed in OID. This works.
Case2: We are synchronizing based on Group membership.
We use this searchfilter :
searchfilter=(&(objectclass=user)(MemberOf=CN=soa,OU=groups,OU=nieuwegein,DC=iteye,DC=nl))
Users are added to our OID when they straight away are added to the group “soa”, before the sync ( odi ) checks the changes.
In the scenario when the user is added, the sync runs , the user is granted to the “soa” group. The sync will not add the user anymore.
Deletions are not preformed anymore.
Case3: We are synchronizing based on Attributes, we use the displayname attribute as a trigger to sync or not sync our user.
We want to perform this test to see if we could use an attribute ( for example : displayname ) which would indicate this “group membership” by setting a value 1 in it.
We use this searchfilter :
searchfilter=(&(objectclass=user)(displayname=1))
We get only users added which have the displayname changed to 1. No matter if the User was created and adjusted the displayname within a synchronizing period. So in the scenario when the user is added, the sync runs , the users displayname is changed to 1. The sync will still add the user.
Deletions are not preformed anymore. We are not able to delete ( in case 2 and 3 ) or backfill a user based on groupmembership ( case 2 ) After some research we can see in MSDN the description for the memberOf attribute for an AD user:
—————-
memberOf
The memberOf attribute is a multi-valued attribute that contains groups of which the user is a direct member, depending on the domain controller (DC) from which this attribute is retrieved:
At a DC for the domain that contains the user, memberOf for the user is complete with respect to membership for groups in that domain; however, memberOf does not contain the user’s membership in domain local and global groups in other domains. At a GC server, memberOf for the user is complete with respect to all universal group memberships. If both conditions are true for the DC, both sets of data are contained in memberOf.
Be aware that this attribute lists the groups that contain the user in their member attribute—it does not contain the recursive list of nested predecessors. For example, if user O is a member of group C and group B and group B were nested in group A, the memberOf attribute of user O would list group C and group B, but not group A.
This attribute is not stored—it is a computed back-link attribute.
————–
http://msdn2.microsoft.com/en-us/library/ms677943.aspx
Now, this means that when you add a user to a group in AD, AD is just modifying the group not also the user itself. Going forward with this, that means that uSNChanged is updated only once.
The ODI server is reading the uSNChanged value and runs a search against the AD to retrieve the last changes. Here it will find only the group has been changed. The filter for the change will be formed:
(&(uSNChanged interval)(our_custom_filter))
So, for both cases 2 and 3, we will need to take some actions on the user when the group is changed which is not possible with ODI. ODI works on an entity level (that means the mapping files are applied , and actions are performed only on the entity detected as changed).
For case 3 you will not be able to delete a user when an attibute is changed as deletes are searched from a special DeletedObjects AD container. A user is not added in this DeletedObjects AD container when you change in our case the displayname attribute.
However, we could , as a partial solution create a OID plug-in that will fire in a post-update LDAP operation on the specific groups. So, if a user is removed from a group, after the synchronization runs, it will trigger the plug-in. In the plug-in code we should be able to identify the user that was removed and delete it from OID.
But this means we need to extend the possibilities of the default procedures available in Oracle Identity Management.
Our conclusion at this point is that it’s not possible to sync based on group membership with deleting and / or backfilling users working using the default procedures of Oracle Identity Management. However there are possibilities to write your own plug-in for Oracle Identity Manager to do a post-update operation on your user store ( OID ) to keep it clean and up to date.
Posted July 17th, 2008 by John Paul van Helvoort | 1 Comment »