Sunday, January 01, 2017

Malaysia : Petaling Jaya : Wat Chetawan Temple

“The most beautiful experience we can have is the mysterious. It is the fundamental emotion that stands at the cradle of true art and true science.” 

― Albert Einstein, The World As I See It

We visited the Thai Buddhist Chetawan Temple ( Wat Chetawan Temple ), at Petaling Jaya, on 31st December 2016. 

It's one of the most beautiful Buddhist Temples you can ever visit. 

I'd highly recommend a visit to the temple, for it's amazing beauty, the serene atmosphere, and to learn about Thai Buddhist Temples. I'll make an attempt to here sprinkle some of the terms used in the temple. 

The Buddhist Temples in Thailand are called " wat ". 


The intricate carvings, shrines, statues are really exquisite, and have been designed by some of the best artisans from Thailand. 



The entire atmosphere at the temple is serene and calm. The Kuan Yin ( Quan Yin or Guan Yin ) pavilion and shrine reflect this serene atmosphere :-



The stupa is usually called a " Chedi ". It's usually a bell shaped tower, and can be seen from a large distance. 




The Maitreya Buddha Shrine contains a large & impressive white statue.


The " Wihan " ( or " Wihran " or " Wihara ") is the main hall that contains several Buddha statues. It also serves as the main prayer hall.



The Bell Tower, usually used to call / signal the faithful for a prayer


The many-headed serpent ( " Naga " ) can be seen encircling the main shrine. The coils of the Naga are believed to serve as a cushion, while the heads act as an umbrella for the Buddha. 


The symbol of " Garuda " can be seen at many places in the temple. Garuda is Lord Vishnu's mount and his symbol & statuses can be usually found in Vishnu & Buddhist temples. 


The " Kinnari " is a mythological being who's half-woman and half-swan. They are believed to have expertise in singing and dancing. 



The Nark Puggsee ( Snake Bird ) can be seen on one of the top panels 



The temple has much more stories to tell. It's only my first visit, and I have made an attempt to collate the information I that gather from the folks there. 

I'll post more, during my next visit. 



Thursday, December 27, 2012

Professional Work

" Professional work is therefore distinguished from work involving routine mental, manual, mechanical or physical work. A professional employee generally uses the advanced knowledge to analyze, interpret or make deductions from varying facts or circumstances. "


I was recently made aware of the above definition of Professional Work, as given in the U.S. Department of Labor Fact Sheet #17D.

The document further attempts to differentiate a Learned Professional in this manner :-

" The employee’s primary duty must be the performance of work requiring advanced knowledge, defined as work which is predominantly intellectual in character and which includes work requiring the consistent exercise of discretion and judgment. "

I feel the key differentiators here are the " consistent exercise of discretion and judgment.". A “Work requiring advanced knowledge” is defined as :-
  • predominantly intellectual in character
  • includes work requiring the consistent exercise of discretion and judgment
And, finally, a moment of true realization :- " Advanced knowledge cannot be attained at the high school level. "

Please do take a look at the Department Of Labor : Fact Sheet #17D. It's an enlightening read.

Wednesday, June 20, 2012

Who is a Professional

" There are two parts to learning craftsmanship: knowledge and work. You must gain
the knowledge of principles, patterns, practices, and heuristics that a craftsman knows, and
you must also grind that knowledge into your fingers, eyes, and gut by working hard and
practicing. "


-- Clean Code, Robert Martin

I was reading Clean Code by Robert Martin & his frank opinion about Craftsmanship / Professionalism struck a note. It takes years of study & practice to become a Professional & Robert Martin would definitely know about it.

Robert has more frank advice about writing clean & good code :-
  • Learning to write clean code is hard work. 
  • It requires more than just the knowledge of principles and patterns.
  • You must sweat over it. You must practice it yourself, and watch yourself fail. 
  • You must watch others practice it and fail. 
  • You must see them stumble and retrace their steps. 
  • You must see them agonize over decisions and see the price they pay for making those decisions the wrong way.

Clean Code by Robert Martin is definitely a must read for all Developers.

I'd like to present another quote, which defines the credo of Professionalism in just two latin words :-

“As recently as 1963, Everett Hughes wrote that the central feature of professionalism was a doctrine of credat emptor—”let the buyer trust”—rather than the commercial maxim of caveat emptor—”let the buyer beware.” 

Saturday, June 16, 2012

Profession

" Professions produce uniquely expert work, not routine or repetitive work. "


I was reading an interesting White Paper (  White Paper : Profession of Arms ) and I found the definition of a Profession, to be interesting and distinct. A Profession truly produces uniquely expert work, as opposed to labour, that produces routine or repititive work.

The WhitePaper also outlines some of the traits of a Profession :-

  • Professionals require years of study and practice before they are capable of expert work.
  • Professions earn the trust of their clients through their Ethic – which is their means of motivation and self-control.
  • The servant ethic of professions is characterized as cedat emptor, ―let the taker believe in us.
  • A self-policing Ethic is an absolute necessity
How different is choosing a Profession from just being employed ? Again, it's a state of mind and as outlined in the WhitePaper :-

Organizations motivate their workers through extrinsic factors such as :-
  • Salary
  • Benefits
  • Promotions.
Professions use inspirational, intrinsic factors like :-
  • the life-long pursuit of expert knowledge
  • the privilege and honor of service
  • camaraderie, and
  • the status of membership in an ancient, honorable, and revered occupation.
Software Engineering or Consultancy may not yet be an ancient occupation - it is defenitely an honorable, and revered occupation.
The White Paper : Profession of Arms focusses moslty on the Profession of Arms, but some of the sections are defenitely relevent to any Profession.

Thursday, July 07, 2011

DOS : Count number of lines in a file

You can use this neat command to count the number of lines in a file, using DOS :-

find /c /v "~`!@#$%^&*()_+" file.txt
It'll give an output like this :-

---------- file.txt: 943526

Friday, June 17, 2011

Cygwin Java and Classpath Problem

" The cygpath program is a utility that converts Windows native filenames to Cygwin POSIX-style pathnames and vice versa. "
-- Cygwin Utilities

If you are trying to run a Java Class using a Shell Script running off Cygwin, you are sure to see a ClassNotFoundException.

The problem is due to these :-

  • java.exe is a Windows executable program
  • java.exe expects its paths & classpaths to be in the Windows Format - paths separated by semi-colon ( ; )
  • Cygwin wants its paths in the LINUX Format - paths separated by a colon ( : )
Ok, we know the problem now and here's a quick fix solution if you are running Shell Scripts off Cygwin :-

CLASSPATH=.:../lib/junit.jar:../lib/weblogic.jar:../lib/ojdbc6.jar

# Convert paths to help cygwin see Classpaths
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`

java -classpath "$CLASSPATH" com.test.PreLoadTester

Please be sure not to check this into a Production environment - cygpath is only available as part of the Cygwin Utilities.

Monday, June 13, 2011

Three Key Tools

"We will encourage you to develop the three great virtues of a programmer: laziness, impatience, and hubris."
-- LarryWall

If you are a Developer ( to quote a phrase overused recently by Head Hunters - " Hand On Developer " ), & if you are using Windows for all your development activities, you'd better have these three tools in your kit.

What do these Tools do ? Well, they solve some of the most nagging & frustrating problems that you always run into.

Please take a look at Sundar's Blog for more about these goodies. And, keep an eye on his Blog for more of these goodies.

Back After a long Hiatus !

Time is very slow for those who wait Very fast for those who are scared very long for those who lament Very short for those who celebrate But for those who love time is eternal"
— William Shakespeare

Ok, I am back to Blogging after a long Hiatus. During the space in time, I underwent a good lot of challenges - personal & professional - that demanded more than a fair share of my time.

Anyways, back to Blogging - as they say:-

" You can either be the sun that provides the light, or the mirror that reflects it."

Its time to do my share as a humble mirror and reflect the light of knowledge - any streak of light that I stumble upon.

Sunday, March 28, 2010

Weblogic Portal : 10.3.2 : Eclipse Subversion Integration : Plugin

" The Subversive project aims to provide Subversion (SVN) integration for Eclipse. You can work with Subversion repositories in almost exactly the same way you can now work with CVS repositories using the CVS plug-in bundled in the standard Eclipse distribution. "


If you are working in a team, then a Source Control Repository is mandatory. A Source Control Repository becomes an integral part of your Project Infrastructure, apart from the Software, Systems, etc. used to build your Solutions.

You can take a look at the Subversive Project, which provides a wonderful plugin to work conveniently with Subversion Source Control Repositories directly from your Eclipse IDE :-


You can find a wealth of literature on Subversion, Eclipse and the Subversive Eclipse Plugin. I have cobbled up a simple Installation Guide to help folks who are in a hurry ( like myself ) to see something working. You can download the Guide from this location :-


As always, please remember to "clean" the Eclipse Project before you upload the Artifacts.

If you need more insight into Eclipse Upgrades, Tips & Tricks, please do take a look at this article ( " Tips to Updating and Upgrading with Eclipse " ) from Scott Nelson :-




Friday, March 26, 2010

Weblogic Portal : 10.3.2 : Installation : SYSTABLES

" SELECT COUNT(*) FROM SYSTABLES; ORA-00942: table or view does not exist"

- Weblogic Server Domain Creation Wizard

You'll see this error when you are creating a Domain for Oracle Weblogic Portal 10.3.2.

The Weblogic Server DataSource uses this query to check if the connection is valid to a Database ( including an Oracle Database ! ) :-

SELECT COUNT(*) FROM SYSTABLES;

The error is so infuriating that at time, the Server forcefully shuts down quoting that the tables is not present. The Table is not required to be present in an Oracle Database.

Aw, well, you are in a tight deadline and you don't want to fuss over this :-

Go ahead and create a dummy table SYSTABLES in your Database Schema :-

CREATE TABLE SYSTABLES ( DUMMY NUMBER );

The Domain Creation Wizard is happy, you are happy and you can move ahead to more interesting tasks.

If you have spare time ( if you really have ), go ahead and take a look under the $WEBLOGIC_DOMAIN_HOME/config/jdbc folder - you'll see the XML files for your Data Sources. You can go ahead and change the Testing Query used in the files and bounce your server.

Thursday, March 25, 2010

Weblogic Portal : 10.3.2 : Installation : Eclipse

" This certified set of Eclipse plug-ins is designed to help develop, deploy and debug applications for Oracle WebLogic Server. It installs as a plug-in to your existing Eclipse, or will install Eclipse for you, and enhances Eclipse's capabilities for Java, Java EE, Spring, ORM and Web Services. "


I discovered an anomaly during the installation of Oracle Weblogic Portal 10.3.2 and am Blogging about it. I installed the Oracle Weblogic Portal 10.3.2 and after installation, I discovered that the Eclipse IDE did not have anything that I could use to develop Weblogic Portal solutions !

Eclipse 3.5.2 is now used as IDE for Weblogic Portal 10.3.2. Eclipse with OEPE (Oracle Enterprise Pack for Eclipse) replaces Workshop and post-installation, the Eclipse IDE should come with all the required Weblogic Portal plugins installed.

You can start using the Eclipse IDE from :-

Windows : [ INSTALL_HOME ] / oepe_11gR1PS1 / eclipse / eclipse.exe
LINUX : [ INSTALL_HOME ] / oepe_11gR1PS1 / eclipse / eclipse.sh

However, after the installation I was in for a shock - I opened the Eclipse IDE, only to notice that I couldn't create any Weblogic Portal artifacts. I didn't see any of these familiar options :-

  • Portal EAR Project
  • Portal Web Project
  • Portal Perspective
After much Googling, I came across an interesting OTN posts which pointed to the same solution :-


During the installation Process:-

  • The "installation Type" Screen is displayed.
  • Select the "Custom" install type.
  • The "Choose Products and Components" Screen is displayed.
  • Under the WebLogic Portal section, select the "Workshop Portal Extension" Box
  • Under the WebLogic Server section, select the "Samples" Box
  • Proceed with the installation.
After the installation, when you run the Eclipse IDE, you'll notice that you have a full-fledged IDE at your disposal, with all the Portal Bells & Whistles.

I tried a lot to get this with the "Default Installation" type, but gave up after 4 iterations.

I feel this is a non-intuitive way to get a full Eclipse IDE for Weblogic Portal Development.

I can only imagine the impact it can have on newbies to Weblogic Portal, when they discover that there's a disconnect between the popular Tutorials and the IDE in front of them.

Anyways, as usual, the folks who take their time of to help others on OTN threw light on this and saved countless hours of time.


Tuesday, December 22, 2009

WebLogic Server : Flush the Application Cache

" On our system, what I normally do is to stop the server with the cache that needs to be flushed, then delete the tmp and cache directories of the server "

- Java Ranch Forum Post

Weblogic server maintains certain "caches" in tmp and cache folders. The caches can sometimes prove to be nuisance - especially, the tmp folder.

You can usually find the tmp folder for your application under :-

$DOMAIN_HOME/tmp/_WL_user/myApplication/
I recently ran into this issue and it gave me a couple of sleepless nights.

I had deployed my Application and started it. I then hit the URL in my browser and promptly received an error, which indicated that my cocktail of JAR files were sour and some libraries did not like the other ones.

During the next iteration of development, decided to use newer versions of a particular library. I deleted all the old libraries, provided a "gold" set of libraries ( that were certified on the vendor's website ) and then re-deployed my application.

However, I still noticed that same error. I was baffled as I was *certain* that I had removed all the old libraries.

First, I decided to investigate which JAR file was contributing the class. I retorted to good ol' Java Reflection for this - I just put this neat little piece of code in my Servlet :-

.class.getProtectionDomain().getCodeSource().getLocation();


I printed this using a simple statement and ensured that the output gets imprinted in the Server's Domain Log.

Alright, I now redeployed my application and when I invoked the Servlet, I saw this in my log file :-

$DOMAIN_HOME/servers/tmp/_WL_user/myApplication/ub48zr/war/WEB-INF/lib/myOldJARFile .jar

Bingo ! I promptly cleared the "cache" and redeployed the application. I re-invoked my Servlet and it works fine !!

I have modified my build.xml to include this minor operation - to clear the contents of the _WL_user folder and then undeploy / redeploy.



Weblogic Server : Quick EAR Deployment using WLST

" The WebLogic Scripting Tool (WLST) is a command-line scripting environment that you can use to create, manage, and monitor WebLogic Server domains. "


You can use WLST to quickly deploy an Application EAR File in a Weblogic Server.

What do you need ?
  • the EAR file ( uploaded to a directory in the target WebLogic Server )
  • A simple WLST script
  • Credentials for the Weblogic Server ( preferrably, the weblogic user ).
How do we do it ?
  • Upload your EAR file to a directory in the target Weblogic Server
/app/home/myUser/
  • Write a simple WLST Script to do your work and save it as "myApp.py"

print '*** WEBLOGIC : START ***'

print 'connecting to admin server....'
connect( 'weblogic', 'weblogic', 't3://localhost:8001', adminServerName='AdminServer' )

print 'stopping and undeploying ....'

stopApplication('myApplication')
undeploy('myApplication')

print 'deploying....'

deploy('myApplication', '/app/home/myUser/myApplication.ear', targets='AdminServer')
startApplication('FoundationSearch')

print 'disconnecting from admin server....'
disconnect()
exit()

print '*** WEBLOGIC : STOP ***'
  • Open a Terminal Window / Command Prompt
  • Run the setDomainEnv.sh ( or setDomainEnv.bat ) script to set the required environment variables.
  • Switch to the /common/bin directory of your Weblogic Server
  • run the wlst.sh / wlst.bat script to open the Scripting Environment.
  • Execute your WLST Script :-
execfile('myApp.py')


That's it ! You can now stop an application, undeloy it, deploy it & start an application with a simple script !

You need to watch out for two small things :-

  • The WAR File and some of the classes / libs are "cached" under the /tmp/_WL_user/myApplication/ folder. You may need to delete them before you execute your script.
  • Make sure the EAR file is available in a folder in the same node as the Server.

Friday, June 19, 2009

Oracle BPEL and Weblogic and Java - JAR Hell

" JAR hell is a term used to describe all the various ways in which the classloading process can end up not working. "

- JAR Hell ( Wikipedia )

Avijeet , Raghu and myself - we are working on a challenging customer engagement and the environment has an Oracle BPEL 10.1.3.4 Server running off an Weblogic 9.2 Server. We recently encountered a scenario where we had to have a Java Client call a BPEL process deployed in this environment.

We used to regular boiler-plate Java BPEL Client code that you can get in the documentation, blogs, etc.

You can find a good example on Charles Piazza's SOA Blog.

However, to our chagrin, we noticed that the code always returned an opaque error :-

Exception in thread "main" java.lang.Exception:
Failed to create "ejb/collaxa/system/FinderBean" bean; exception reported is: "javax.naming.CommunicationException [Root exception is java.rmi.ConnectIOException:
error during JRMP connection establishment; nested exception is:
java.io.EOFException]
at weblogic.jrmp.Context.lookup(Context.java:189)
at weblogic.jrmp.Context.lookup(Context.java:195)
at javax.naming.InitialContext.lookup(InitialContext.java:351)
at com.oracle.bpel.client.util.BeanRegistry.lookupFinderBean(BeanRegistry.java:337)
at com.oracle.bpel.client.Locator.getFinder(Locator.java:956)
at com.oracle.bpel.client.Locator.listInstances(Locator.java:585)
at com.oracle.bpel.client.Locator.listInstances(Locator.java:554)

We pciked our brains on this for almost two days - until, suddenly, it hit us !

It was a classic case of JAR hell.

I had included all the JAR libraries of Oracle BPEL 10.1.3.4 and Weblogic 9.2 - for some strange reason, a few libraries in these two sets didn't like each other and this disgust resulted in the opaque "bean" exception.

Avijeet pointed this out & we both painstakingly removed the Weblogic Jar's one-by-one, until we noticed that we only required two sets of JARs to run the Java Class :-
  1. All the Oracle BPEL 10.1.3.4 Libraries.
  2. Only the weblogic.jar from Weblogic 9.2
Cool ! So, now it works and we can celebrate another victory against JAR hell !

Moral of the storey : Be very very careful with the JARs you use !


Sunday, February 22, 2009

Recursive Java Decompiler by Adarsh

" Often we encounter situations where the only solution to a certain Java problem is to decompile the contents of an entire JAR file, edit the resulting the source, rebuild and repackage before using. "


I found myself in this situation today & was struggling with CAVAJ and JAD to recursively generate Java classes present in an EAR file. I initially tried my hand at writing my own DOS Script to do this, but soon found that it takes a lot of time, patience & effort to write a script that does what I need. And time, unfortuantely, is in very limited supply today !

I Googled around looking for solutions & landed on this post by Adarsh. The Recursive Decompiler provided by Adarsh works like a charm *& saved a lot of time !

Thanks a lot Adarsh !

Monday, February 09, 2009

DWR Hello World !

" DWR is a Java library that enables Java on the server and JavaScript in a browser to interact and call each other as simply as possible. "

- Direct Web Remoting ( DwR )

I was snooping around for an AJAX library that I can use in one of my projects & narrowed down to DWR, after reading a lot of rave reviews about it. I was looking out for some AJAX library that'll allow me to call the methods in my Java classes with minimum effort.

I decided to take it for a test drive & check out the features. The usual sources were the DWR Documentation and Google.

I don't want to duplicate the good & decent documentation available for DWR at the "Get Started" page.

At a high level, I would like to just summarize the steps involved ( with the mistakes I made highlighted ) :-
  • Put dwr.jar in your Project's lib.
  • Put the Commons Logging Jar in your Projects's lib. ( Dwr uses Apache Commons Logging )
  • Add the configuration settings in your web.xml for the DWR Servlet.
  • Add the debugging parameters for the DWR Servlet during the development phase.
  • Add the dwr.xml under WEB-INF and configure it to expose your Java Classes.
  • Add the converters in dwr.xml to ensure the conversion of Java POJOs to JavaScript Objects & vice versa.
  • Include the reference to all the JavaScript libraries required in your JSPs.
Overall, I am impressed with this & I am going ahead with my implementation using DWR.

Tuesday, February 03, 2009

WebLogic Server 10 : Deployment : Error 149003

" WebLogic Deployer:149003 Unable to access application source information "

You might bump into this error during deployment. I just noticed that someone was struggling with this error & had reported this on the OTN Forums.

The Stack Trace for the error usually looks like this :-

Error is: 'weblogic.management.DeploymentException:
[Deployer:149003]Unable to access application source information in
'/home/bea/bea/user_projects/domains/myDomain/servers/myServer/stage
app/app.war' for application 'roller'. The specific error is:
[Deployer:149158]No application files exist at
'/home/bea/bea/user_projects/domains/my/servers/myServer/stage
appapp.war'
The error occurs when the WebLogic Server is unable to locate the EAR file. The common causes for the EAR file could be :-

  • ANT Deployment : The EAR file was not uploaded to a directory that the server can access.
  • Console Deployment: You might need to look at "Source Availablity" [ Copy this application onto every target for me ], if you wish to copy the application to all the managed servers in a Cluster.
The error vanishes once the server can access the EAR file.

Spring LDAP caches user credentials

" Spring-LDAP caches environment properties by default "



I was facing this rather peculiar problem of User Credentials getting cached by Spring LDAP. I discovered this accidentally ( absent-minded, to be precise :) ) . I changed the password of a User in my ApacheDS but tried to login with the old password - and guess what ? it worked !

Well, I looked at the first place I would go to in these situations - the Spring-LDAP Community Forums.

I noticed that the problem has already been discussed in one of the threads.

The solution suggested in the thread is use the setCacheEnvironmentProperties() method in the AbstractContectSource class & set it to false. The Java doc for the API seems to explain this more :-

Set whether environment properties should be cached between requsts for anonymous environment. Default is true; setting this property to false causes the environment Hashmap to be rebuilt from the current property settings of this instance between each request for an anonymous environment.

Well, just one of those queer things in the fascinating Spring LDAP API.

JSF Managed Bean in a Servlet Filter

" How do you get a JSF Managed Bean, with session scope, in a Servlet Filter ? "

- Two bewildered comrades

The question posed above can be reworded in a simpler way :-

" Which came first, the Chicken or the Egg ? "

- A timeless paradox

We just hit this problem of accessing a JSF managed bean from a Servlet Filter. The requirement is quite simple - Oracle Single Sign On authenticates a user, passes on useful information about the user in the request headers & this information needs be passed on downstream to a Managed Bean for furthe consumption.

However, try as much as we can, we only hit the simple NullPointerException, which quaintly informs us that we aren't getting the FacesContext to proceed further.

A bit of Googling landed us on a post on the Sun Java Forums, where one of the legends of the Java Universe - Craig McClanahan - has suggested that this might not be possible. He has eloquently described how the Servlet Filters get triggered much before the Servlets & hence, the FacesContext doesn't stand a chance of getting initialized unless the flow hits the FacesServlet.

However, on further Googling, we hit upon this curious post on the Thougths About blog that offers an amazing alternative! We tried the code posted on the blog and.... it just works !

Thanks a million to the Thougths About blog for shaving off a few precious hours off the already-harried schedule of a couple of developers !

You can also find a very good explanation about the differences between a Filter and a PhaseListener on the same Blog.

Now, it's time for a cup of coffee.....

Wednesday, January 21, 2009

Spring LDAP : My experiments

" Spring LDAP is a Java library for simplifying LDAP operations, based on the pattern of Spring's JdbcTemplate. The framework relieves the user of common chores, such as looking up and closing contexts, looping through results, encoding/decoding values and filters, and more. "

Spring LDAP

I took some time to explore the Spring LDAP library & I am impressed with it. The library aims to make a developer productive by eliminating a lot of plumbing code that one would encounter with plain-vanilla JNDI. I have worked on building an User Management application using JNDI & when I compare it with the facilities provided in Spring LDAP, I defenitely would think twice before coding in regular JNDI.

I created a sample application, by using the principles listed out in the Spring LDAP Reference Documentation & some of the samples I found using my favourite Google.

The steps to use Spring LDAP are quite the same for any Spring application :-

1. Get the Spring LDAP libraries.
2. Configure the applicationContext.xml
3. Write any utility classes you may need.
4. Write the Interface and Implementation class.
5. Write a test harness to see if all these gule together & work ( of course, it will ! :) ).

Let's take it one step at a time...

1. Get the Spring LDAP libraries.

You can get it from the Spring LDAP home page.

After downloading the library, you can unizp it & have a look at the README file. The file usually outlines the dependencies very clearly. In my case, I had to include all these libraries in my project :-
  • spring-ldap-core-tiger-x.x.jar
  • Commons Logging
  • Commons Lang
  • Commons Pool
  • spring-beans
  • spring-core
  • spring-context
  • spring-jdbc
  • spring-tx
  • ldapbp
2. Configure the applicationContext.xml

Here's my applicationContext.xml :-

< ?xml version="1.0" encoding="UTF-8"? >
< !DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd" >
<>

< !-- The Spring LDAP Context Source Configuration. The information provided here is used to create an instance of InitialLdapContext -- >
< id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource">
< name="url" value="ldap://ecmser.idc.oracle.com:389">
< name="base" value="cn=Users,dc=idc,dc=oracle,dc=com">
< name="userDn" value="cn=orcladmin">
< name="password" value="allstate1">
< /bean >

< !-- The Spring LDAP Template executes tcore LDAP functionalities. It requires the Context Source for its operations. -- >
< id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
< ref="contextSource">
< /bean >

< !-- Our User Bean that makes uses of the pre-configured Spring LDAP Template-- >
< id="user" class="com.org.sandeep.dao.impl.UserDAOImpl">
< name="ldapTemplate" ref="ldapTemplate">
< /bean >

< /beans >

3. Write any utility classes you may need.

First, I an interface as a placeholder for some of the constants :-

package com.org.sandeep.util;

public interface UserConstants
{
String FIRST_NAME = "cn";
String LAST_NAME = "sn";
String BLANK = "";
String OBJECT_CLASS = "objectclass";
String PERSON = "person";
}


Next, I wrote my bean class :-

package com.org.sandeep.bean;

public class UserBean
{
private String firstName;
private String lastName;

public UserBean()
{
}

public UserBean(String firstName,String lastName)
{
this.firstName = firstName;
this.lastName = lastName;
}

public void setFirstName(String firstName)
{
this.firstName = firstName;
}

public String getFirstName()
{
return firstName;
}

public void setLastName(String lastName)
{
this.lastName = lastName;
}

public String getLastName()
{
return lastName;
}


public String toString()
{
return firstName + " : "+lastName;
}
}

Finally, I wrote an AttributesMapper class the implements Spring's AttributeMapper interface. To quote from the Spring LDAP Reference Manual :-

An interface used by LdapTemplate for mapping LDAP Attributes to beans. Implementions of this interface perform the actual work of extracting results, but need not worry about exception handling. NamingExceptions will be caught and handled correctly by the LdapTemplate class.

Here's my AttributesMapper class :-

package com.org.sandeep.mapper;

import com.org.sandeep.bean.UserBean;
import com.org.sandeep.util.UserConstants;

import javax.naming.NamingException;
import javax.naming.directory.Attributes;

import org.springframework.ldap.core.AttributesMapper;

public class UserMapper implements AttributesMapper
{
public Object mapFromAttributes(Attributes attributes)
{
UserBean userBean = null;

String firstName = null;
String lastName = null;

try
{
firstName = (String)attributes.get(UserConstants.FIRST_NAME).get();
lastName = (String)attributes.get(UserConstants.LAST_NAME ).get();
}
catch (NamingException objNamingException)
{
objNamingException.printStackTrace();
}

if ( firstName != null || lastName != null )
{
userBean = new UserBean(firstName,lastName);
}

return userBean;
}
}


4. Write the Interface and Implementation class.

First, we need an interface :-

package com.org.sandeep.dao;

import com.org.sandeep.bean.UserBean;

import java.util.List;

public interface UserDAO
{
public List get(UserBean user);
public void add(UserBean user);
public void modify(UserBean user);
public void remove(UserBean user);
}
Next, we need an implementation class that uses the interface :-

package com.org.sandeep.dao.impl;

import com.org.sandeep.bean.UserBean;
import com.org.sandeep.dao.UserDAO;
import com.org.sandeep.mapper.UserMapper;

import com.org.sandeep.util.UserConstants;

import java.util.List;

import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;

import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.filter.AndFilter;
import org.springframework.ldap.filter.EqualsFilter;


public class UserDAOImpl implements UserDAO
{
private LdapTemplate ldapTemplate;

public UserDAOImpl()
{
}

public void setLdapTemplate(LdapTemplate ldapTemplate)
{
this.ldapTemplate = ldapTemplate;
}

public List get(UserBean user)
{

String firstName = null;
String lastName = null;

AndFilter andFilter = null;

firstName = user.getFirstName();
lastName = user.getLastName();

andFilter = new AndFilter();
andFilter.and(new EqualsFilter(UserConstants.OBJECT_CLASS,UserConstants.PERSON));
andFilter.and(new EqualsFilter(UserConstants.FIRST_NAME,firstName));
andFilter.and(new EqualsFilter(UserConstants.LAST_NAME,lastName));

return ldapTemplate.search(UserConstants.BLANK, andFilter.encode(),new UserMapper());
}

public void add(UserBean user)
{
Attributes userAttributes = null;
BasicAttribute userBasicAttribute = null;
DistinguishedName userDN = null;


userAttributes = new BasicAttributes();
userBasicAttribute = new BasicAttribute(UserConstants.OBJECT_CLASS);

userBasicAttribute.add(UserConstants.PERSON);
userAttributes.put(userBasicAttribute);
userAttributes.put(UserConstants.FIRST_NAME, user.getFirstName());
userAttributes.put(UserConstants.LAST_NAME, user.getLastName());

userDN = new DistinguishedName(UserConstants.BLANK);
userDN.add(UserConstants.FIRST_NAME, user.getFirstName());

ldapTemplate.bind(userDN, null, userAttributes);
}

public void modify(UserBean user)
{
Attributes userAttributes = null;
BasicAttribute userBasicAttribute = null;
DistinguishedName userDN = null;


userAttributes = new BasicAttributes();
userBasicAttribute = new BasicAttribute(UserConstants.OBJECT_CLASS);

userBasicAttribute.add(UserConstants.PERSON);
userAttributes.put(userBasicAttribute);
userAttributes.put(UserConstants.FIRST_NAME, user.getFirstName());
userAttributes.put(UserConstants.LAST_NAME, user.getLastName());

userDN = new DistinguishedName(UserConstants.BLANK);
userDN.add(UserConstants.FIRST_NAME, user.getLastName());

ldapTemplate.rebind(userDN, null, userAttributes);
}

public void remove(UserBean user)
{
DistinguishedName userDN = new DistinguishedName(UserConstants.BLANK);
userDN.add(UserConstants.FIRST_NAME, user.getFirstName());
ldapTemplate.unbind(userDN);
}
}


5. Write a test harness to see if all these gule together & work

Well, we have reached the finish line ! The only remaining step is to see if all these gel together !

Here's my test client :-

package com.org.sandeep.client;

import com.org.sandeep.bean.UserBean;
import com.org.sandeep.dao.UserDAO;

import java.util.List;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.dao.DataAccessException;


public class UserClient
{

public static void main(String[] args)
{
try
{
Resource resource = new ClassPathResource("applicationContext.xml");
BeanFactory factory = new XmlBeanFactory(resource);
UserDAO userDAO = (UserDAO)factory.getBean("user");

UserBean userBean = new UserBean("Sandeep","Seshan");

userDAO.add(userBean);

System.out.println("Done");

List userList = userDAO.get(userBean);

System.out.println("User "+userList);

userDAO.remove(userBean);

System.out.println("Done & Deleted");

}
catch (DataAccessException objDataAccessException )
{
objDataAccessException .printStackTrace();
}
}
}


That's it ! It's that simple !