29 June 2006

Client setup for connecting to OC4J using JSR160

When connecting from remote JMX clients to OC4J using JSR160, there's a couple of things to keep in mind.

  1. For OC4J, the Service URL specifies the use of the RMI protocol

    service:jmx:rmi://[oc4j-host]:[oc4j-ormiport]


  2. For OracleAS, the Service URL additionally specifies the use of the OPMN mechanism to obtain the ORMI port of the specified OC4J instance

    service:jmx:rmi:///opmn://[opmn-host]:[opmn-port]/[oc4j-name]

  3. The client needs to be told where to locate the RMI implementation.

    For programatic clients, this is done using the environment passed to the JMXConnectorFactory

    Hashtable env= new Hashtable();

    env.put(JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES,
    "oracle.oc4j.admin.jmx.remote"
    );

    Hashtable credentials= new Hashtable();

    credentials.put(JMXConnectorConstant.CREDENTIALS_LOGIN_KEY,"oc4jadmin");
    credentials.put(JMXConnectorConstant.CREDENTIALS_PASSWORD_KEY,"welcome1");

    env.put(JMXConnector.CREDENTIALS, credentials);

    jmxCon = JMXConnectorFactory.newJMXConnector(serviceUrl, env);

    For pre-built clients, this is done using a System property:

    -Djmx.remote.protocol.provider.pkgs=oracle.oc4j.admin.jmx.remote

  4. The client classpath needs to include the $ORACLE_HOME/j2ee/home/admin_client.jar library. This library contains references to all the libraries needed to establish remote JMX connections in its Manifest.mf Class-Path entry. It's a nice one-stop shop.
This combination of things usually solves most of the problems I get asked about in this area.

The OC4J J2EE Developer's Guide has a good section on remote connections.

23 June 2006

Go the Socceroos

Could it be bandwagon jumping? Never! Well maybe but I'll watch Australia play just about anything.

But what an effort by the Australian team at the World Cup! I was leaping off my couch this morning watching their effort against Croatia -- go you Socceroos!

While I'm on the Soccer theme -- ever wondered what your Brazilian soccer name would be?

http://www.minimalsworld.net/BrazilName/brazilian.shtml


DataSource lookup using java:comp/env

Helped someone out this week where the claim was OC4J doesn't support the same standards they are used to developing with on Tomcat.

The reported problem was that the developer was trying to lookup a DataSource using the standard ENC approach -- java:comp/env/jdbc/DataSource from within a Servlet.

"It doesn't work with OC4J, I must change all my code to lookup the datasource using its actual name!"

OK, lets take a look at it -- that's not quite true.

Yes, we do enable a direct datasource lookup to be done using just the jndiLocation value of the DataSource in need. For example, if there is an actual physical datasource defined on the J2EE container with a location of "jdbc/OracleDS" then it can be looked up using the actual name:
  DataSource ds = (DataSource)ic.lookup("jdbc/OracleDS");

But this is a convenience mechanism only. It's not something I'd recommend or use other than for something quick and dirty. It hardcodes the application code so that it requires a physical datasource to be defined on the J2EE container.

If I was developing I'd opt for the standard, portable approach so that the application makes no assumptions about its target environments.

Which basically means using the ENC (Environment Naming Context) model which is implemented by J2EE servers to abstract application resources away from their physical manifestations. I've always wanted to use that word somewhere ...

To use the ENC model you need to do two things.

1. Do the Logical

In the application, you define a logical representation of the resources you need to use. This is done using resource-ref definitions in the standard J2EE deployment descriptor files. Whenever you need to get hold of the resource, you look it up from the JNDI ENC and use it.

This means the application is free from using anything specific to a physical environment in the code. So it becomes portable.

Here's an example. Lets say I have a Servlet which needs to connect to a database and execute a query. I want the Servlet to be portable so it can be deployed anywhere.

What I do is to first define a resource-ref element in the web.xml file which identifes the logical datasource name to be used:
  <resource-ref>
<res-auth>Container</res-auth>
<res-ref-name>bing/Bang</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
</resource-ref>

This says to the J2EE container when the app is deployed that a DataSource should be mapped to the jndiLocation "bing/Bang".

To get hold of this DataSource in the Servlet code, it is looked up like this:
  InitialContext ic = new InitialContext();
DataSource bingBang = (DataSource)ic.lookup("java:comp/env/bing/Bang");
Connection con = bingBang.getConnection();
...

OK -- all standards stuff. Note the use of the java:comp/env prefix here when looking up the resource. This is needed because resource-ref declarations are bound by the J2EE container into the ENC and this java:comp/env is the way to reach into the ENC.

But how does this logical "bing/Bang" actually get married up to a database to connect to?

2. Do the Physical

A physical datasource is configured at the J2EE container with details such as which database to connect to, the username password combination and any other special properties. It is given a unique name so it can be identified and used -- for example "jdbc/MyXEDatabase"

Once the application has been packaged, its time for deployment. And its at deployment time that the person doing the deployment makes the decision on how to map the logical resource-ref entries to their physical counterparts on the server.

What this means in this specific case during the deployment process, the deployment manager will extract the list of logical references it finds in the standard deployment descriptors (DataSource - bing/Bang) and allow you to specify which of the physical datasources it should be be mapped to -- in this case "jdbc/MyXEDatabase".

This gets automatically generated into a deployment descriptor which is read by OC4J:
  <orion-web-app>
<resource-ref-mapping location="bing/Bang" name="jdbc/MyXEDatabase"/>
</orion-web-app>

So that when an application looks up bing/Bang it really gets given jdbc/MyXEDatabase

And there you have it.

14 June 2006

Adding a Mozilla Search Engine

Gee, I'm a bit of a lazy bugger.

We have an internal application we use to enter/view/manage bugs. Not that we have any bugs of course. A bug is identified by a bug number, which can be supplied to our bugdb application and the relevant bug text displayed. Of course you can perform many more complex and combined forms of queries but the simple 'can you check this bug please' usually results in the simple bug number type of query.

It struck me that it'd be cool to somehow add our bugdb application as a search engine for Mozilla. So I could just enter the bug number in the search field and press enter, without needing to go to the actual bug application first.

Yes, I know. I must be really, really lazy.

I thought it'd be hard. I thought wrong. Those Mozilla people, what enablers!

If you look in the $MOZILLA_HOME/searchplugins directory, you'll probably see a bunch of files. The files ending with .src define a search plugin.

Looking at one of the .src examples, you can pretty easily see how it works.

For my bugdb search I really just needed to specify the URL of the bugdb application and specify the name of the query parameter it uses.

<search
version="1.0"
name="Oracle Bug DB"
description="Oracle Bug DB"
action="http://bugserver/pls/bug/webbug_print.show"
searchForm="http://bugserver/pls/bug/webbug_print.show"
method="GET"
>

<input name="c_rptno" user>

</search>

You then save this as a .src file into the searchplugins directory, restart Mozilla and bango! you have a new search option.



How easy can it be!

I then hunted around and found some doc off the Mozilla website which actually explains how it all works. Good job Mozilla folks.

Even better, it shows how you can remotely install these things using a bit of JavaScript, which will add the .src file and an accompanying icon (16x16) to a client browser.

See http://mycroft.mozdev.org/deepdocs/installing.html#server which has a working example of the JavaScript calls:
  window.sidebar.addSearchEngine(
"http://localhost.localdomain/plugins directory/"+name+".src",
"http://localhost.localdomain/plugins directory/"+name+"."+ext,
name,
cat );


Now of course this is for our internal application, so it won't for you folks out there. But if you ever wanted to add a new option to the Mozilla search engine list, then try it out. No code required!

07 June 2006

Parsing XSDs

When things are little quiet on the blog front usually means its hot on the work front. I don't want to say the inverse is true since that could say something about my daily acitivities.

So this is just a short and sweet post today.

I've been tackling a task this week which required me to provide some details about the OC4J configuration parameters. To make it easy, I thought I'd derive the data I wanted directly from the OC4J schema files -- after all they pretty much define what our config files can contain.

Besides the drudgery of writing the parsing routines by hand, the biggest thing I discovered was that in order to parse an XSD file you have to set the namespaceAware property to true.




DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder parser = factory.newDocumentBuilder();
Document document = parser.parse(fis);



Until I did that, the document returned was basically null.

As I was working on this short term task -- my mind kept thinking back to what would the good practices for working with XSD files themselves? Could/should I have spent a little more time checking into using Castor/JAXB/commons-digester/etc. instead of crufting something manually? Would that have been worth the effort?

I ended up doing what I knew would work to get the job done, but it's code I'll never let off my laptop, I promise.

01 June 2006

More info on remote jconsole connections

[update] the bug has now been fixed in our 10.1.3.1 code line so this will work out of the box in the coming 10.1.3.1 release.

It turns out that jconsole (which I never found the src to!) supplies the jmx credentials as a String array, such as:

String s5 = userNameUrl.getText().trim();
String s7 = passwordUrl.getText();
String as[] = { s5, s7 };
connectionparameters.map.put("jmx.remote.credentials", as);

whereas we were expecting the credentials to be in a Map.

I don't like to leave things hanging ... so I made some changes to the effected classes in an isolated view just to see if I could get it to work -- fear not, Product Managers don't touch production code!


With the changes in place, I was then able to get jconsole to connect remotely to both a OC4J standalone and an Oracle Application Server instance using their respective URL forms:
  • service:jmx:rmi://[oc4j-host]:[oc4j-port]
  • service:jmx:rmi:///opmn://[opmn-host]:[opmn-port]/[oc4j-name]
I've logged a bug and try and work this fix into the 10.1.3.1 release.

I also found once I'd connected that I needed a couple of extra libraries on the client side to make jconsole work fully -- javax77.jar to get the Stats classes and dms.jar.

Here's the set of Oracle libraries required:
  • ${ORACLE_HOME}/j2ee/home/oc4jclient.jar
  • ${ORACLE_HOME}/j2ee/home/lib/adminclient.jar
  • ${ORACLE_HOME}/j2ee/home/lib/javax77.jar
  • ${ORACLE_HOME}/dms/lib/dms.jar