Analytics


Google

Monday, November 24, 2008

Accessing LDAP using Java

The easiest way to access LDAP in Java is to use JNDI (Java Naming and Directory Interface).

A good example on how to do that can be obtained from Sun website. Snippet is as follows:


In the LDAP, authentication information is supplied in the "bind" operation. In LDAP v2, a client initiates a connection with the LDAP server by sending the server a "bind" operation that contains the authentication information.

In the LDAP v3, this operation serves the same purpose, but it is optional. A client that sends an LDAP request without doing a "bind" is treated as an anonymous client (see the Anonymous Authentication section for details). In the LDAP v3, the "bind" operation may be sent at any time, possibly more than once, during the connection. A client can send a "bind" request in the middle of a connection to change its identity. If the request is successful, then all outstanding requests that use the old identity on the connection are discarded and the connection is associated with the new identity.

The authentication information supplied in the "bind" operation depends on the authentication mechanism that the client chooses. See the next section for a discussion of the authentication mechanism.

Authenticating to the LDAP by Using the JNDI
In the JNDI, authentication information is specified in environment properties. When you create an initial context by using the InitialDirContext(in the API reference documentation) class (or its superclass or subclass), you supply a set of environment properties, some of which might contain authentication information. You can use the following environment properties to specify the authentication information.

* Context.SECURITY_AUTHENTICATION(in the API reference documentation) ("java.naming.security.authentication").
Specifies the authentication mechanism to use. For the Sun LDAP service provider, this can be one of the following strings: "none", "simple", sasl_mech, where sasl_mech is a space-separated list of SASL mechanism names. See the next section for a description of these strings.
* Context.SECURITY_PRINCIPAL(in the API reference documentation) ("java.naming.security.principal").
Specifies the name of the user/program doing the authentication and depends on the value of the Context.SECURITY_AUTHENTICATION property. See the next few sections in this lesson for details and examples.
* Context.SECURITY_CREDENTIALS(in the API reference documentation) ("java.naming.security.credentials").
Specifies the credentials of the user/program doing the authentication and depends on the value of the Context.SECURITY_AUTHENTICATION property. See the next few sections in this lesson for details and examples.

When the initial context is created, the underlying LDAP service provider extracts the authentication information from these environment properties and uses the LDAP "bind" operation to pass them to the server.

The following example shows how, by using a simple clear-text password, a client authenticates to an LDAP server.

// Set up the environment for creating the initial context
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=JNDITutorial");

// Authenticate as S. User and password "mysecret"
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "cn=S. User, ou=NewHires, o=JNDITutorial");
env.put(Context.SECURITY_CREDENTIALS, "mysecret");

// Create the initial context
DirContext ctx = new InitialDirContext(env);

// ... do something useful with ctx

Using Different Authentication Information for a Context
If you want to use different authentication information for an existing context, then you can use Context.addToEnvironment()(in the API reference documentation) and Context.removeFromEnvironment()(in the API reference documentation) to update the environment properties that contain the authentication information. Subsequent invocations of methods on the context will use the new authentication information to communicate with the server.

The following example shows how the authentication information of a context is changed to "none" after the context has been created.

// Authenticate as S. User and the password "mysecret"
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "cn=S. User, ou=NewHires, o=JNDITutorial");
env.put(Context.SECURITY_CREDENTIALS, "mysecret");

// Create the initial context
DirContext ctx = new InitialDirContext(env);

// ... do something useful with ctx

// Change to using no authentication
ctx.addToEnvironment(Context.SECURITY_AUTHENTICATION, "none");

// ... do something useful with ctx

Authentication Failures
Authentication can fail for a number of reasons. For example, if you supply incorrect authentication information, such as an incorrect password or principal name, then an AuthenticationException(in the API reference documentation) is thrown.

Here's an example that is a variation of the previous example. This time, an incorrect password causes the authentication to fail.

// Authenticate as S. User and give an incorrect password
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "cn=S. User, ou=NewHires, o=JNDITutorial");
env.put(Context.SECURITY_CREDENTIALS, "notmysecret");

This produces the following output.

javax.naming.AuthenticationException: [LDAP: Invalid Credentials]
at java.lang.Throwable.(Compiled Code)
at java.lang.Exception.(Compiled Code)
...

Because different servers support different authentication mechanisms, you might request an authentication mechanism that the server does not support. In this case, an AuthenticationNotSupportedException(in the API reference documentation) will be thrown.

Here's an example that is a variation of the previous example. This time, an unsupported authentication mechanism ("custom") causes the authentication to fail.

// Authenticate as S. User and the password "mysecret"
env.put(Context.SECURITY_AUTHENTICATION, "custom");
env.put(Context.SECURITY_PRINCIPAL, "cn=S. User, ou=NewHires, o=JNDITutorial");
env.put(Context.SECURITY_CREDENTIALS, "mysecret");

This produces the following output.

javax.naming.AuthenticationNotSupportedException: Unsupported value for java.naming.security.authentication property.
at java.lang.Throwable.(Compiled Code)
at java.lang.Exception.(Compiled Code)
at javax.naming.NamingException.(Compiled Code)
...

Wednesday, November 19, 2008

Understanding J2EE Programming

I have bought many books on J2ee programming and I found a lot of times the concept is very difficult to grasp - especially for a person who is from .Net programming background.

However, I found so far the best explanation to help understand the concept is from theserverside web site. The provide some complete books on the subject in PDF format for free download. One of them is Mastering EJB.

If you are interested in the subject, this is an excellent place to start. However, the book may be a little outdated but I believe most of the concepts on the stateful and stateless beans are still explained nicely in the book. There is also a more uptodate version of it (again free download of the complete pdf) - Mastering Enterprise JavaBean 3.

One of the problems I have with J2EE, is they keep adding other framework like Struts, JavaFaces, Hibernate etc. The above book does not cover those.

Saturday, November 15, 2008

Rich experience programming on the Web

I read a pretty good review on the launch of Java 1.6u10 release. In one of the comments, there is a reference to Interactive Pulp which provides samples of how to write very nice applets which rivals Flash - link is here.

Also, I see that Microsoft is coming with similar competition to Flash called SilverLight. The installation is only 4 Mbytes.

Monday, November 10, 2008

Too Many Open Cursors

Occasionally, you may find your program encountering "Too Many Open Cursor" when using Oracle.

You may be able to resolve this by:
  1. Closing any open resultset.
  2. Dispose any database adapter after use.
  3. Disposing your database command object after use (either oleDBCommand or OracleCommand) whether or not it is a prepared statement or not.

What sometimes happen is after you create a database command within your subroutine and then you perform a query a cursor is opened. We sometimes assume that when we exit the routine, the GC (garbage collector) will automatically close the open cursors and dispose of the objects that are no longer used. However, I found out that it does not always happen. In an environment where you perform a lot of query or update, the system may not know that it can reuse the existing open cursor and will open new cursors during each iteration or call and sooner or later will hit the limit.

This applies whether you are using .Net framework or Java.

I have found this has helped me avoid the "Too Many Open Cursors" issue in both environment.

Saturday, November 8, 2008

Compiling invalid Oracle Object

If you use a lot of packages, stored functions and procedures, they may sometimes become invalid if an object it depends on is changed. We have encountered in a few occasions, our application will hang as a result. To address this, we are using a script (shown below) and schedule it to run once an hour to recompile any invalid objects it encounters.

This is a script is obtained from another blog but was modified so that it will continue to compile the rest even if it encounters error (in case, there are procedures that are in the schema that is still being edited and will not compile correctly, so other invalid object (but compilable) will still get compiled ).
rem -----------------------------------------------------------------------
rem Filename:   cmpall2.sql
rem Purpose:    Compile all invalid database objects
rem             Run this script after each database upgrade or whenever
rem             required.
rem Notes:      If the dependencies between objects are complicated, you can
rem             end up re-compiling it many times, as recompiling some
rem             invalidates others. This script uses dyamic SQL, and
rem             recompile objects based on reverse dependency order.
rem Date:       24-Sep-1998
rem Author:     Fiona Lindsay <f_lindsay@hotmail.com>
rem -----------------------------------------------------------------------

set serveroutput on size 1000000

declare
   sql_statement varchar2(200);
   cursor_id     number;
   ret_val       number;
begin

   dbms_output.put_line(chr(0));
   dbms_output.put_line('Re-compilation of Invalid Objects');
   dbms_output.put_line('---------------------------------');
   dbms_output.put_line(chr(0));

   for invalid in (select object_type, object_name
                   from   user_objects o
                   where  o.status       = 'INVALID'
                     and  o.object_type in ('PACKAGE', 'PACKAGE BODY',
                                            'FUNCTION',
                                            'PROCEDURE', 'TRIGGER',
                                            'VIEW')
                   order  by o.object_type) loop

      begin
       if invalid.object_type = 'PACKAGE BODY' then
          sql_statement := 'alter package '||invalid.object_name||
                           ' compile body';
       else
          sql_statement := 'alter '||invalid.object_type||' '||
                           invalid.object_name||' compile';
       end if;
 
       /* now parse and execute the alter table statement */
       cursor_id := dbms_sql.open_cursor;
       dbms_sql.parse(cursor_id, sql_statement, dbms_sql.native);
       ret_val := dbms_sql.execute(cursor_id);
       dbms_sql.close_cursor(cursor_id);
 
       dbms_output.put_line(rpad(initcap(invalid.object_type)||' '||
                                invalid.object_name, 32)||' : compiled');
      EXCEPTION
          When others then
             dbms_output.put_line('Error in '|| invalid.object_name || ' - Continuing');
      end;
   end loop;

end;
/
EXIT

To use the above script, just copy into a text file and save it as comp_obj.sql. You can then use a batch file to run it as follows:

sqlplus scott/tiger@orcl @comp_obj >> comp_obj.log

Wednesday, November 5, 2008

Review Google Chrome Browser

I realize that there are many reviews of Chrome already but I am approaching this as a programmer blogger.

Things I like about Chrome:
  • It is fast.
  • In some cases where I get timeout with either IE or Firefox, the page still gets rendered in Chrome.
  • The incognito page is often handy when you want to do research and don't want to leave any trail on the PC of where you have been.
  • You can open a set of book marks in a new window (similar functionality available in firefox).
Things I don't like about Chrome:

  • When you perform compose in Blogger, it encloses the subsequent paragraph between <div> </div> tag. Both IE and Firefox does not add these extra tags.
  • It does not have an option to undo close tab which you may have accidentally closed (this is available in FireFox - haven't noticed it in IE7 - not sure if it is there or not).
  • If you want to have properly aligned table, you can enter your information into Excel and then paste in into the compose screen in Firefox and the data will align correctly. See examples below.
  • Assuming you have your photos in Flickr, you can switch to view source and search for <img src="http://farm When you do that in Firefox, it will highlight and select the text for you. In Chrome, the text is selected but not highlighted. (I do this because I upload my images to flickr and then display them in my blogs).
Pasting from Excel into Blogger compose screen:

This is how the excel looks like:


Using Firefox:

Date Mileage time
1-Jan-08 10 1 hr
2-Jan-08 5 0.5 hr



Using IE:

Date
Mileage
time
1-Jan-08
10
1 hr
2-Jan-08
5
0.5 hr

Using Chrome:


Date Mileage time 1-Jan-08 10 1 hr 2-Jan-08 5 0.5 hr