Pages

Saturday, February 23, 2008

JNDI connections lookup with RMI and LDAP

In java you can lookup connections and datasources with JNDI. The Oracle java libraries enables you to do this against the OC4J Container with rmi or against the OID server with ldap ( probably this will work with other ldap servers too). The first part of this blog is about the ldap jndi lookup and second part is about the rmi lookup.
I use the ldap server of Oracle Identity Management 10g (10.1.4.0.1) to register the connection, which you can download at otn. First we have to rename the object OracleDBConnection and its cn attribute to lowercase. Now we can register the connection with java. We have to set server_dn so java can find the oracledbconnection object. In all the Oracle examples they use searchbase but this is not going to work then you get the following error message cn=oracledbconnections,null.

Hashtable env = new Hashtable(5, 0.75f);
// env.put(Context.INITIAL_CONTEXT_FACTORY, AQjmsConstants.INIT_CTX_FACTORY);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://win2003_2:389");
env.put("server_dn", "cn=IDENT, cn=OracleContext");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "cn=orcladmin");
env.put(Context.SECURITY_CREDENTIALS, "Welcome01");

String url = "jdbc:oracle:thin:@XPCND7010XMP:1521:orcl";
Properties properties = new Properties();
properties.setProperty("user","scott");
properties.setProperty("password","tiger");

try {
AQjmsFactory.registerConnectionFactory(env, "scott", url ,properties, "queue");

} catch ( JMSException e) {
e.printStackTrace();
}

This is how it looks in ldap.



Now we can try to lookup the scott connection and create a queueconnection so we can dequeue the scott.JMS_IN queue

Hashtable env = new Hashtable(5, 0.75f);
DirContext ctx;
QueueConnectionFactory queueConnectionFact;

env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://win2003_2:389");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "cn=orcladmin");
env.put(Context.SECURITY_CREDENTIALS, "Welcome01");

try {
ctx = new InitialDirContext(env);
ctx = (DirContext)ctx.lookup("cn=oracledbconnections,cn=IDENT,cn=OracleContext");
queueConnectionFact = (QueueConnectionFactory)ctx.lookup("cn=scott");
// Start QueueConnection
try {
connection = queueConnectionFact.createQueueConnection();

session = connection.createQueueSession(true, QueueSession.CLIENT_ACKNOWLEDGE);
connection.start();
queue = ((AQjmsSession)session).getQueue("scott", "JMS_IN");
sender = ((AQjmsSession)session).createSender(queue);

String xmlData = "1111";
TextMessage message = session.createTextMessage(xmlData);
sender.send(message);
session.commit();
} catch (JMSException e) {
// TODO
e.printStackTrace();
}
} catch (NamingException ee) {
// TODO
ee.printStackTrace();
}


We can also lookup the jdbc/scott datasource with JNDI and rmi. First we have to create a datasource in the oc4j container. You can do this with the em webapp or go the datasources.xml in the config folder. You need a lot of oc4j container libraries to get this working. ( oc4jclient.jar , oc4j-internal.jar, connector.jar, bcel.jar, pcl.jar, jazn.jar and adminclient.jar )

Context ctx;
try {
Properties parm = new Properties();
parm.setProperty("java.naming.factory.initial","com.evermind.server.rmi.RMIInitialContextFactory");
parm.setProperty("java.naming.provider.url","ormi://localhost:23791/");
parm.setProperty("java.naming.security.principal","oc4jadmin");
parm.setProperty("java.naming.security.credentials","welcome");

ctx = new InitialContext(parm);
DataSource ds = (DataSource)ctx.lookup("jdbc/scott");
//Bepaal dbUser:
Connection conn = ds.getConnection();
dbUser = conn.getMetaData().getUserName();
conn.close();
factory = AQjmsFactory.getQueueConnectionFactory(ds);
// Maak QueueConnection
connection = factory.createQueueConnection();
// Maak QueueSession
session = connection.createQueueSession(true, Session.CLIENT_ACKNOWLEDGE);
// Start QueueConnection
connection.start();
// Haal Queue op
queue = ((AQjmsSession)session).getQueue(dbUser, queueTable);
// Maak QueueSender
sender = ((AQjmsSession)session).createSender(queue);
} catch (NamingException e) {
throw new RuntimeException("Fout opgetreden bij het starten ",
e);
} catch (JMSException je) {
throw new RuntimeException("Fout opgetreden bij het starten ",
je);
} catch (Throwable t) {
throw new RuntimeException("Fout opgetreden bij het starten ",
t);
}

Now you can store your connection in the ldap or Application Server.

Here is the example project. My jdeveloper home is D:\oracle\jdevstudio10133. This is voor j2ee rmi libs

Thursday, February 21, 2008

JAXB 2.0 in JDeveloper 10g and 11g

If you know jaxb 1.0 then you know that xjc generates many classes. With the coming of jaxb 2.0 this is a lot less thanks to annotations and the 2.0 version supports now more xml schema types. In this blog I will show how you can use jaxb 2 in JDeveloper 10.1.3 and in 11g and give some tips how to use it.
JDeveloper 10.1.3 supports jaxb 1 and JDeveloper gives you a wizard where can generate the classes by selecting a xml schema. Go for the wizard to the menu tools and then go the jaxb compilation menu item.

If you want to use jaxb 2 then you should read this blog, this explains how to get jaxb 2 support in jdeveloper 10.1.3.
In JDeveloper 11G you can use jaxb 1 and 2. If you do New and go to business tier / toplink jpa then you see the jaxb 1 and 2 options.

If you use JAXB 2.0 Content model from XML schema then we see the following wizard.

Here is some code where I first generate a xml from java then I read this generated xml back in to initialize java objects. I also use the property jaxb.formatted.output to have a nice formatted xml. With the property Marshaller.JAXB_ENCODING I can control the encoding of the xml

DataMessage msg = new DataMessage();
msg.setRecipient("123");
msg.setRecipient("321");
msg.setRunid(run);
msg.setContentlist(conList);

try {
JAXBContext jaxbContext=JAXBContext.newInstance("nl.ordina.mhs");
Marshaller marshaller=jaxbContext.createMarshaller();


File file = new File("c:/temp/1.xml");
marshaller.setProperty("jaxb.formatted.output", true);
marshaller.setProperty( Marshaller.JAXB_ENCODING, "UTF-8" );

marshaller.marshal(msg,file);

Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
DataMessage msg2 = (DataMessage) unmarshaller.unmarshal(file);


} catch ( JAXBException e) {
e.printStackTrace();
}

If you use anyType in your schema like this <xs:element name="data" type="xs:anyType"/> You may not be so happy with the jaxb generated code. It generates setData(Object data) The marshaller generates the output of this element not to xml but to text(it converts the xml characters)
You can better change the element to xs:any.
<xs:element name="data">
<xs:complexType>
<xs:sequence>
<xs:any processContents="skip"/>
</xs:sequence>
</xs:complexType>
</xs:element>
Now jaxb generates setData(Data value) where Data is a class where you can set an Element. Now the marshaller generates a nice xml with an embedded xml.

Sunday, February 17, 2008

Business Rules in Soa Suite 11g

With the new soa suite patch ( 4 feb ) for the jdeveloper 11g TP3 release we can test the business rules. The 11g version is a totally different then the 10.1.3 version. The first thing is a lot easier to make business rules and you can expose these rules as web services so you can use it in other applications. In 10.1.3 you have a binary br repository which you can use. Now you create service in the BR to expose a particular ruleset or function. You can also use business rules to create advanced approval routing in the workflow component.
The first step is to drag the business rule to the composite.xml. Now you get a wizard to create a new business rule. In my case I made a simple schema with a element total order amount which I use as input and as output boolean element supersize order. You can also check expose as composite service so you can use this br in other applications

Because I checked the expose as composite service you can see that soa suite creates a webservice.

If we open the new BR then we see that soa suite has created xml facts of the input and output element. This is done with jaxb.

Soa suite also creates a service which calls the empty created ruleset. You can add more services based on br functions or other rulesets.

To the created the ruleset we can add a new rule. We select a simple test where we check if the total order is greater then 2000.

Next I select the input element, > and 2000. Now we can add the return value. Choose assert new.

We have to select the output element and in the output element we select true. Now we can make a second rule where the outcome is false when the input is lower then 2000

We are ready with the composite part now we can go to bpel where we add a business rule to the right place in the bpel designer. We have to select the just created br and the right operation, in my case assert facts , execute and retrieve result. We also have to assign the input and output variable of the br.

This is how it looks when we open the business rule scope.

You are ready to deploy this to soa container and test this