Saturday, July 3, 2010

Creating pop ups with JQuery

Background:
I like Jquery as well as YUI .I have used some components of Jquery in few cases. But there are specific things which you should be careful while you are using this nice frameworks .

Sample
:
Jquery dialogs are used for pop ups .Have a look at the code below :
// Dialog
$('#dialog').dialog({
autoOpen: false,
modal:true,
width: 600
});
As you can see "dialog" is the document id where a div based dialog will be created .It will look like







Up to this it is fine .Now if I have multiple pop ups in my page should I be creating multiple different div ids to create them ? Answer is no .
1. Create a Java script global variable , var popupDivId = "#panelDivId" and replace the line $('#dialog').dialog with $(popupDivId).dialog.
2.Similarly assign a closing function to the dialog ,like
$(popupDivId).dialog({
autoOpen: false,
modal:true,
width: 600,
beforeclose: function(event, ui) { performClosingTask(); }
});
This performClosingTask method will remove the div id ,when the dialog is closed .
var containerDiv = doc.getElementById(popupDivId );
containerDiv.parentNode.removeChild(containerDiv);

Note:
With this strategy, you should also have a check before you create open any pop up, whether already another popup is already opened or not .that is
if(docObj.getElementById(panelDivId))
{
window.status = 'Div with id ' + panelDivId + 'is already found ' ;
return;
}
If already one pop up is opened new pop up should not be opened , the already opened pop up should be closed ,then only new pop up should be opened .

Thursday, July 1, 2010

Generic code to detect browser close

Problem description:
You need to detect the browser close , irrespective of the fact how the user has closed it !

Background:

I had a code that was detecting whether the user has attempted to close the browser or not .If yes ,then there should be a message ,other wise not .The code that was working fine ,is was like
<html>
<head>
<title>Detecting browser close in IE</title>
<script type="text/javascript">
var message='Browser close attempt is detected';
function ConfirmClose()
{
if (event.clientY < 0)
{
event.returnValue = message;
}
}
</script>
</head>
<body onbeforeunload="ConfirmClose()" >
<h4>Close browser!</h4>
</body>
</html>
This works fine but with two exceptions .
1.If the user does right-click on the title bar , an option to close the browser appears.Now , if he clicks on that close option browser gets closed without any message .
2.If the browser is minimized and the user right-clicks on the minimized browser , an option to close the browser appears.Now also if close option clicked browser gets closed without any message .

Both of the cases do occur as the condition mentioned in my code i.e.
"event.clientY < 0 " is violated .Now that code above is not good, because I am considering on the mouse coordination!!! The mouse could be anywhere. An alternative would be

<html>
<head>
<title>Detecting browser close in IE</title>
</head>
<body onbeforeunload="return 'Browser close attempt is detected';">
<h4>Close browser!</h4>
</body>
</html>

Now the problem with the code is that 'onbeforeunload' will be fired even when a new page gets loaded ,if the user navigates from one page to another .In that case ,this message would appear irrespective of the situation whether the user wants to close the browser or wants navigate to other page .That is where the risk lies .

So far I have thought about handling two things
1.Catch any kind of window termination (formal close)
2. Do not catch navigations to other pages of the application.
[But wait there can be other variations also :).For example if the user has a google toolbar and tries to search somthing with it in my application, or even directly open another URL in the window of your page...that makes 2 kind of navigation. internal & external. (and some externals like the google one, will result in coming back to your page again).So by having this in mind, do you want to "Dont Catch" all type of navigations? or only internal ones? ]
3.POWER LOSS !!
4.Ending the IExplorer.exe from task manager and so on ...
Confusing.Is'nt it ? Lets re-frame the entire thing little bit .First ask ourselves why we want to detect a browser close ? why ? In most of the cases it is detected , to log out the user who has closed the browser .Say there is a logout url in the page for a logged in user , but he has not clicked the ,instead he has just closed the browser.But now an updation in the database should be done when the user logs out .So while the user logs out (or CLOSES THE BROWSER!!) I need to trap that event and fire an updated to the DB.
For the time if I can trap following three events it will be sufficient for me .
1.If the user closes the browser using the 'X' button at the top right at the corner.
2.If the user does right-click on the title bar , an option to close the browser appears.Now if he clicks on that close option browser gets closed without any message .
3.If the browser is minimized and the user does right-click on the minimized browser , an option to close the browser appears.Now the user clicks that option.

First I need to need to display a message to the user while closing the browser ,in these cases.The code below shows a Message on the above conditions I mentioned earlier.The message MUST NOT APPEAR when:
1. User hits a hyperlink (by mouse or keyboard).
2. User submits a form.

How does it work:
If you hit on a hyperlink or submit a form, a variable called "Navigating" turns "true".
It's because all links.onclick & forms.onsubmit events are registered with this line of code (Navigating=true;) without loosing the old registered event handler of them (if there is any).So, afterwards the event "body.beforeunload" fires, then it only shows you the message if "Navigating" is not "true". That on this point the message will not appear.But if you only use those 3 kinds of closing options you've mentioned, the "Navigating" variable doesn't change (remains "false") and the message will appear.

Some issues ,fixes and enhancements:
Currently this code defines 2 kinds of navigations that could be trapped by links.onclick & forms.onsubmit events.If you have any other kinds of navigations on your pages, that you can trap them on any events, just register the line (Navigating=true;) with that event. use the function "ChargeHandler" to do that without loosing the old event handlers...
and just use a code like the last lines of javascript codes, to cover all instances of that event on the page...
Please note, if you dynamically add links or forms (or even other defined types of navigations that you added) after the page is loaded, the message may appear for navigations launched by these new elements.For fixing this issue you should call "ChargeHandler" after adding such element to the page.So the final code is ....
<html>
<body onbeforeunload="if(!Navigating){return 'Browser close attempt is detected';}else{Navigating=false;}">
<!-- Unimportant Sample Links & Forms to test all kinds of them, with/without event handlers... -->
<a href="http://www.google.com/">Navigate Away 1 (No Event Handler)</a><br>
<a href="http://www.google.com/" onclick="alert('Link Event Handler 1');">Navigate Away 2 (Event Handler 1)</a><br>

<form action="http://www.google.com/">
<input type="submit" value="Navigate Away Submit Case 1 (No Event Handler)">
</form>
<form action="http://www.google.com/" onsubmit="alert('Form Event Handler');">
<input type="submit" value="Navigate Away Submit Case 2(Event Handler)">
</form>
<!-- End of Unimportant Samples! -->
<script language="javascript">
var Navigating=false;
function ChargeHandler(obj,eve)
{
obj.oldHandler=obj[eve];
obj[eve]=function()
{
if(obj.oldHandler!=null) obj.oldHandler();
Navigating=true;
};
}
//Add Navigating=true; to all links.onclick & all forms.onsubmit event handlers...
for(i=0;i<document.links.length;i++) ChargeHandler(document.links[i],'onclick');
for(i=0;i<document.forms.length;i++) ChargeHandler(document.forms[i],'onsubmit');
</script>
</body>
</html>

Notes:
The final solution that I have mentioned above is a result derived from the valuable feed backs ,opinions as well as sample codes of my several colleagues and specifically some experts from different forums . Many thanks to them.
My role was of merely an observer and coordinator and nothing more.

Blob fails with merge on Hibernate 3.x

Problem description :
Blob fails with merge on Hibernate 3.x.
Blobs are saved correctly using saveOrUpdate(). Few days back I downloaded the latest version of Hibernate ( i.e. 3.5.3) and had a look at the org.hibernate.type.BlobType class .I found out the replace method written as ...

/**
* {@inheritDoc}
*/
public Object replace(
Object original,
Object target,
SessionImplementor session,
Object owner,
Map copyCache) throws HibernateException {
//Blobs are ignored by merge()
return target;
}

It is already commented out there,that Blobs are ignored :(

Analysis :

First of all, I am not sure it is a bug or not. If you check Hibernate forum here
It is clearly mentioned by one of the Hibernate team members ...
'As per the EJB3 spec
"Fields or properties of type java.sql.Blob and java.sql.Clob are ignored by the merge operation"
But we should not throw any exception and we should explicit it in the doc if not yet..'

But then, if it is not a bug then what about this JIRA entry ?

Workaround :
For the time being use saveOrUpdate or save for Blob,Clob etc.

Tuesday, June 29, 2010

Generic solution to prepare the application URL from server end.

Problem description :
I was quite annoyed few days back when I got stuck for sometime while doing a very small task .
The requirement was to display an URL on a JSP page and the situation was such that, the URL value should be a DTO property value (may be populated by an Struts action class or whatever ) .
Say your application URL is "http://xyz.com:9080/PayrollApp".Now you want to display an URL which is like "http://xyz.com:9080/PayrollApp/edit.do".How to create such URL String ( without any sort of hard coding ) from an action class ? Well apparently it is quite simple , in fact it is , specially after you read this post , but trust me otherwise it is not.

The first thing that comes to our mind is "request.getContextPath()" will serve the purpose . Yes off course , but wait a minute ....it will do your job only partially . You will only get the application name (in this case the "PayrollApp" portion ) using request.getContextPath().


What about the previous parts ? The schema,host name ,port number ? How you will populate their value ? Confused ? Honestly speaking , I was .

Lets discuss about URLs in general . Generally what are the different parts of an URL ?
1.The first part is the protocol (here it is http).
2.The protocol is followed by ://
3.Next comes the host (in our example it is "xyz.com" )
4.You may have a port number also after the host name (9080 ) .
5. After the domain you may have your application name (as we have PayrollApp) .But always that is not the case.


Analysis and solution:

Well , the following code is self explanatory .Just use it ...

Sample Code:

String applicationPath = request.getScheme()+"://"+request.getServerName()+":"+
request.getServerPort()+request.getContextPath();


String finalURI=applicationPath+"/edit.do"

Notes :
Please note I have kept the "request.getServerPort()" , but that is not always the case .

Create a DB2 Data Source in JBOSS access it programmetically outside JBOSS context.

Problem Description:

It was a long lasting pain which only sufferers understand!!


Solution:
Just follow the steps mentioned one by one ...

1.We begin by adding its driver to the CLASSPATH: copy db2java.zip to the /server/default/lib directory. To configure the JBoss server with the DB2 data source, copy /docs/examples/jca/db2-ds.xml to the /server/default/deploy directory.

2.Next we modify the db2-ds.xml configuration file, by setting to

COM.ibm.db2.jdbc.app.DB2Driver and to jdbc:db2:, where is the DB2 database name.

Here it is start of db2-ds.xml

################################

"



test

false

jdbc:db2:tset

COM.ibm.db2.jdbc.app.DB2Driver

db2admin

db2admin

2

SELECT * FROM TEST.USER_TABLE

DB2


"

####################################

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

PLEASE NOTE :In the above file I have one entry

false

It is kept false for connecting to JBoss Datasource from a standalone client.

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

3.Remove hsqldb-ds.xml from /server/default/deploy

4.Go to jboss-4.2.0.GA\server\default\conf\standardjbosscmp-jdbc.xml

Then we modify standardjaws.xml (or jaws.xml) to set and .

java:/lkrgt

DB2

5.Now We need to test the data source from a Java class .

Copy all jar files from jboss-4.2.0.GA\client and place to lib or add to class path



Sample code:

package com.ayan;

import java.sql.Connection;

import java.sql.ResultSet;

import java.sql.Statement;

import java.util.Hashtable;


import javax.naming.InitialContext;

import javax.sql.DataSource;


public class TestConnect

{

public static void main(String[] args)

{

try

{

final String sql = "select * from LKRGT.TRAINING_REQUEST ";

Hashtable ht=new Hashtable();

ht.put(InitialContext.INITIAL_CONTEXT_FACTORY,

"org.jnp.interfaces.NamingContextFactory");

ht.put(InitialContext.PROVIDER_URL,"jnp://localhost:1099");

ht.put(InitialContext.URL_PKG_PREFIXES,"org.jboss.naming:org.jnp.interfaces");

InitialContext ic=new InitialContext(ht);

if(ic!=null)

{

System.out.println("Initial Context success");

}

DataSource ds=(DataSource)ic.lookup("lkrgt");

if(ds!=null)

{

System.out.println("Data Source success");

}

Connection con = null;

Statement stmt = null;

ResultSet rs = null;

try

{

con = ds.getConnection();

stmt = con.createStatement();

rs = stmt.executeQuery(sql);

while(rs.next()) {

System.out.println("Query '" + sql + "' returned " + rs.getString(1));

}

}

finally

{

if(rs != null)

rs.close();

if(stmt != null)

stmt.close();

if(con != null)

con.close();

}

}

catch (Exception e)

{

e.printStackTrace();

}

}


}



Generate DDL to a text file using Hibernate rather than firing it to DB.

Problem Description:
I never liked the idea of using hbm2ddl.auto attribute directly inside hibernate.cfg.xml file directly . Suppose you have this mapping equal to "update" or "create" in local/development environment and somehow you change the connection related parameters to connect to production environment .Now if forget to change/disable the hbm2ddl.auto property,what next ?? This is really really dangerous .But then how to generate the DDL ?

I do not want the risk of using hbm2ddl.auto , but I want the DDL .

Solution:
Using the following code which uses SchemaExport class of Hibernate , generate the text file which contains the DDL.Copy that DDL and fire to DB as per your requirement .

Sample code:
public class SchemaExportUtil
{
public static void main(String[] args)
{

Configuration configuration = new Configuration();
configuration.configure();
SchemaExport schemaExport = new SchemaExport(configuration);
boolean generateScript = true;
boolean fireScriptToDB = false;
String schemaExportFileName = "c://script/DDL.txt";
schemaExport.setOutputFile(schemaExportFileName);
schemaExport.create(generateScript, fireScriptToDB);

}

}

How to use this program :

If the mappings are correct scripts will be generated according to the dialect mentioned in hibernate.cfg.xml.

If you the script to be fired at the database , just set fireScriptToDB=true.Otherwise it will write the DDL to the mentioned text file.The choice is yours now !

Mapping issue with nullable primitive types in hibernate.

Problem description :
You have many columns in a table which are mapped as primitives in Hibernate and you have the getters and setters ready .But the code is giving "PropertyAccessException" .It is quite a common exception for hibernate users .There is a post regarding this in the Hibernate Official Web site in common problem section , which is like the following :

Hibernate throws a PropertyAccessException or NullPointerException
when I load or query an object!
A PropertyAccessException often occurs when the object being passed to the setter method is of the wrong type. Check your type mappings for the offending property. (To see exactly which property was the problem, you might need to disable the CGLIB reflection optimizer.) However, the most common cause of this problem is that Hibernate attempted to assign null to a property of primitive type.
If your object has a primitive-type property mapped to a nullable database column then you will need to use a Hibernate custom type to assign a sensible default (primitive) value for the case of a
null column value. A better solution is usually to use a wrapper type for the Java property.

Analysis and solution:
Fair enough...,providing an Integer mapping instead of int (i.e. using wrapper class of Java) is off course a better solution (as well as common practice ) when the design is in your hand .
But
what if the POJOs are already written and you can not modify them? (Oh my God !!!)

Well, in that case my solution is using Hibernates formula attribute .It will be like the following:

property name="primitiveNullableDemoField" formula=”COALESCE(primitiveNullableDemoField, 0)


So the core idea is to replace the null field with default (not null ) initialization value.

Disclaimer:
Now there are two issues
1. COALESCE () function is DB2 specific solution; it will not work in Oracle.
2. Adding a function in the query adds to database overhead .I have heard about situations where DBAs do not allow to the developers to fire any DB functions considering the performance issue in critical scenarios (Too much, isn’t it?).
Regarding point 1, I do not know a common or generic function to replace null value that works for all Databases. Instead we can use case statements to bypass this.

Monday, June 28, 2010

You need to read an application server log file , but you do not know where it is !!!

Background:

One Friday at around 10.30 at night , a very close friend of mine called me on my mobile and told me that he is facing a problem.He is working on a maintenance project which runs on a server , of which the log file location is unknown.He does not have the documents or time to do RnD on searching the log files also.But he needs to have a look at the log immediately !! There is a severe bug he needs to fix within few hours , otherwise there will be some sort of escalations.

Initially I suggested him to read the server related docs (which I myself have read on rare occasions !! ) and do some Googling on this .In reply he told me that he has already done that and still he is stuck .He needs a quick simple working solution for the time being !!

Problem Description:

To get the log file of a server at a known directory , irrespective of its default location.

Solution (or patch ?? ):

What I suggested for a quick fix is to use the System.setErr() and System.setOut() method of java, to point the console output to a custom location.Both methods should have a PrintStream object as argument, which will point to a specific file provided by you .In that case all the prints or exceptions will be stored in that specific location.

Sample code:


package com.ayan.util;

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;

/**
* This class is an utility class containing a method to change the console
* output location as per the choice of the user .
*
* To use this util file ,the User just needs to add one liner code like :
* ConsoleUtil.setSystemOutPutLocation(outFileLocation,isError);
*
*
* @author ayandutta
*
*/
public class ConsoleUtil
{
public static String NORMAL_OUTPUT_FILE_NAME = "SysoutFile.txt";
public static String ERROR_FILE_NAME = "SysError.txt";
public static String OUTPUT_DIRECTORY = "c:" ;

public static String NORMAL_OUTPUT_FILE_LOCATION = OUTPUT_DIRECTORY + File.separator + File.separator+NORMAL_OUTPUT_FILE_NAME;
public static String ERROR_FILE_LOCATION =OUTPUT_DIRECTORY + File.separator + File.separator+ERROR_FILE_NAME;

/**
* This method sets the console out put location file.
* It works for sysout or syserror
* @param outFileLocation
* @param isError
*/
public static void setSystemOutPutLocation(String outFileLocation,boolean isError)
{
try
{
FileOutputStream outFileStr = new FileOutputStream(outFileLocation, true);
PrintStream outFilePrintStream = new PrintStream(outFileStr);
if(isError)
{
System.setErr(outFilePrintStream);
//System.out.println(" Error file is changed to : " +outFileLocation);
}
else
{
System.setOut(outFilePrintStream);
//System.out.println(" Output file is changed to : " +outFileLocation);
}
}
catch (Exception e)
{
System.out.println("Exception inside method setSystemOutPutLocation(),printing stack trace...");
e.printStackTrace();
}
}

public static void main(String[] args)
{


//Normal Sysouts and Syserrors Before console location is changed
System.out.println("Text for normal out put before file configuration");
System.err.println("Text error out put before file configuration");

//Here is the code where Sysouts and Syserrors console location is changed
setSystemOutPutLocation(NORMAL_OUTPUT_FILE_LOCATION, false);
setSystemOutPutLocation(ERROR_FILE_LOCATION, true);

//Normal Sysouts and Syserrors after console location is changed
System.out.println("Text for normal out put after file configuration");
System.err.println("Text error out put after file configuration");


//By force generating an Exception
generateException();
}

/**
* Just a method to create an exception by force
*/
public static void generateException()
{
try
{
String nullStr = null;
System.out.println(nullStr.length());
}
catch (Exception e)
{
System.out.println("Exception inside method generateException(),printing stack trace...");
e.printStackTrace();
}
}

/**
* Just a method to create an exception by force
*/
public static void printExecutionLocation()
{
System.out.println(System.getProperty("user.dir"));
}

public static void printAllEnvironmentInfo()
{
System.out.println(System.getProperties());
}
}

How to use this program :

Now invoke setSystemOutPutLocation(NORMAL_OUTPUT_FILE_LOCATION, false) and setSystemOutPutLocation(ERROR_FILE_LOCATION, true) from any of the classes of your running application .The log file will be generated on the location provided.

Disclaimer:

The solution (I would rather mention it as a patch ) that I provided at that point of time is just for solving the log file related issue quickly .It is not at all a complete solution .