Monday, February 8, 2010

How to Handle Session Expire in Ajax Call (Prototype Framework)

Steps:
1. Call is made to server using XMLHttpRequest either get or post method
2. Check string token like "session expired" or "sessionexpired" the result data. If so then it indicates that session is expired.
3. If session expired then redirect it to the Session Expire Page using following code:
var sessionExpiryURL="/global/sessionExpired.jspx";
window.location=sessionExpiryURL;


Sample Codes:

Note: Sample code uses prototype framework.

Script uses handling Session Expire:
var sessionExpiryURL="/global/sessionExpired.xhtml";

/*
    The following method checks if the session has expired or not
    Pre: Applicable for Ajax call only and the ajaxResponseText must pass the responseText from the AJax call
*/
function isSessionExpired_OnResponseText(ajaxResponseText){
    if (ajaxResponseText != null ){
        var lclAjaxResponseText = ajaxResponseText.toLowerCase();
        if (lclAjaxResponseText.indexOf("session expired") >=0 || lclAjaxResponseText.indexOf("sessionexpired") >=0 ){
            return true;
        }
    }
    return false;
}
/*
    The following method checks if the session expired and redirects to session expiry  page
    Pre: Applicable for Ajax call only and the ajaxResponseText must pass the responseText from the AJax call
*/
function handleSessionExpiry_OnResponseText(ajaxResponseText){
    if(isSessionExpired_OnResponseText(ajaxResponseText) == true){
            window.location=sessionExpiryURL;
    }
}

/*
    The following method checks if the session has expired or not
    Pre: Applicable for Ajax call only and the ajaxResponseText must pass the responseText from the AJax call
*/
function isSessionExpired(ajaxResponseObj){
    if (ajaxResponseObj!= null ){
            var contentText =ajaxResponseObj.responseText;
            return isSessionExpired_OnResponseText(contentText);
    }
   
}

/*
    The following method checks if the session expired and redirects to session expiry  page
    Pre: Applicable for Ajax call only and the ajaxResponseText must pass the responseText from the AJax call
   
*/
function handleSessionExpiry(ajaxResponseObj){
    if (ajaxResponseObj!= null ){
            var contentText =ajaxResponseObj.responseText;
            return handleSessionExpiry_OnResponseText(contentText);
    }
}

Script uses to post Ajax Call:

var jScript = Class.create();
    jScript .prototype =  {
    initialize: function()
    {
          // Initialization Stuff, It is called before calling any mothod of jScript
    },


/* funtion defination
@ URL - URL to be submitted to server
@ params-Associative array (Hash) to carry data from client to server
@ sourceObj- Ideally onchange of source object event; it posts the ajax request
@ targetObj- Ideally  targetObj is the placeholder for the response like populating some data into it.
/*
post: function(URL, params, sourceObj, targetObj) {
        var url = strURL ;
        var responseText = "";
        new Ajax.Request(strURL, {
                parameters: parameters,
                method:'post',
                onSuccess:function(transport) {
                    try {
// Algorithm uses to extract data from response and populate to the targetObj
                        }
                     }catch(e) {
                            if(isSessionExpired(transport)==true) {
                                handleSessionExpiry(transport);
                                return;
                            }
                            alert("System Error" );
                     }
                },
                 onFailure:function(transport) {
                    alert("An  error occurred");
                    alert("Error occurred: " + transport.responseText);    //Debug purpose only
                    //TODO handle errors
                 }
        });
    },


//AJAX Function
    loadStates: function (){
   var sourceObj = $('countryName'); // country name selected in dropdown
    var targetObj = $('stateNames'); // dropdown list box to  hold state names
    var parameters = new Hash();

    var strURL="../Country/getStates.xhtml"; // Servlet to provide state names
    parameters['countryName'] = sourceObj.value;
    parameters.set('ajaxParam', '1');
    this.post(strURL, parameters,  sourceObj , targetObj );
    }
};

jScript .Initializer = function() {
        jScript = new jScript ();
}

Event.observe(window, 'load', jScript .Initializer);

Tuesday, February 2, 2010

jQuery Autocomplete Field Sample Code (Using Plugins)

1. Auto complete plugin - http://www.pengoworks.com/workshop/jquery/autocomplete.htm
2. Javascript:
<script type="text/javascript">

/** AJAX - Call back
This function will submit the form when any item is selected from the autocompleted text field
@param li - item submited from the autocomplete field
*/

function findValue(li) {
if( li == null ){
return;
}

var selectedValue;
if( !!li.extra ){
selectedValue = li.extra[0];
}
else {
selectedValue = li.selectValue;
}
j$("studentNameQS").value=j$("studentName").value;
// Action class method name
j$("testForm").action = "showStudentDetailsById.xhtml";
j$("testForm").submit();

}

/** AJAX - Call back
A JavaScript function that will be called when an item is selected. The autocompleter will specify a single argument, being the LI element selected.
This LI element will have an attribute "extra" that contains an array of all cells that the backend specified.
@param li - item submited from the autocomplete field
*/
function selectItem(li) {
findValue(li);
}


/** AJAX - Call back
A JavaScript function that will be called when item are populated in the select box.
@param row - item in string format laying inbetween line separator.
*/

function displayItem (row) {
return row[0];
}

/** AJAX - Call back
A JavaScript funcion that can provide advanced markup for an item. For each row of results, this function will be called.
The returned value will be displayed inside an LI element in the results list.
Autocompleter will provide 3 parameters:
the results row,
the position of the row in the list of results,
and the number of items in the list of results.
@param row - item in string format laying inbetween line separator.
*/

function formatItem(row) {
return row[0];
}

j$(document).ready(function() {
// Register autocomplete plugin with the given textfield id i.e. #studentNameQS once the DOM is ready.
j$("#studentNameQS").autocomplete(
"findStudentDetails.xhtml", // URL
{
delay:10,
minChars:4,
matchSubset:1,
matchContains:1,
cacheLength:10,
maxItemsToShow:10,
formatItem:formatItem,
onItemSelect:selectItem,
onFindValue:findValue,
lineSeparator:'|',
cellSeparator: '~',
autoFill:true
}
);
});
</script>

3. Form:

<s:form name="ajaxStudentForm" id="ajaxStudentForm" action="showStudentDetailsById.xhtml">
<s:hidden name="studentNameQS"/>

</s:form>

<input id="studentName" type="text" maxlength="254" size="55"/>

4. Action Class

/**
* Method to get Student Name based on the Search criteria
* It is used for the Student Name Quick search functionality i.e. to show available names during typing
*
* @return String
* @throws Exception
*/
public String findStudentNames() throws Exception{

response.setContentType("text");
response.setHeader("Cache-Control", "no-cache");
// "searchQuery" is constructed by jquery-autocomplete.js - makeUrl()
// Should be verify in makeUrl(); what is used for the parameter
studentNameWildCard = request.getParameter("searchQuery");

// There is nothing supplied for RoleName
if (studentNameWildCard == null) {
response.getWriter().write("");
return null;
}

//Get the data from DB Based on the wild card chars

StringBuilder studentNameIds = new StringBuilder();

// Going to construct (ROLENAME~ID) like "|ABC~123|BCD~234|CDE~345|"
String[] staticNames = new String[ABC~123|BCD~234|CDE~345|]
// Put pipeline (|) as a line separator
studentNameIds.append("|");
studentNameIds.append("Ram");
// Put tild (~) as a cell separator
studentNameIds.append("~");
studentNameIds.append(1);
studentNameIds.append("|");
studentNameIds.append("Shiv");
// Put tild (~) as a cell separator
studentNameIds.append("~");
studentNameIds.append(2);

response.getWriter().write(studentNameIds.toString());
return null;
}

Wednesday, January 20, 2010

How to pass jsp:param in jsp:include and access from struts 2 tag

1. Include a jsp file in the first page by passing the parameters like "text" as follows:

first.jspx:
..
..
<jsp:include page="/WEB-INF/jsp/middle.jspx">
<jsp:param name="text" value="Good Morning!!!" />
</jsp:include>
..
..

2. middle.jspx
..
..
<jsp:include page="/WEB-INF/jsp/last.jspx">
<jsp:param name="text" value="${param.text}" />
</jsp:include>
..
..

3. last.jspx

..
..
<c:set var="text" value="${param.text}"/>

Your Passed Text is == <s:property value="%{#attr.text}"/>
..
..

Note:Unfortunately you can't use JSTL in Struts 2 tags anymore. The above solution is a work around by using JSTL to set the parameter into page scope.

Thursday, January 14, 2010

How to handle Clob type in iBatis

1. Create a type handler:

package com.demo.sqlmap.typehandler;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.sql.Blob;
import java.sql.SQLException;
import java.text.DateFormat;
import java.util.Date;

import com.demo.domain.BlobBean;
import com.ibatis.sqlmap.client.extensions.ParameterSetter;
import com.ibatis.sqlmap.client.extensions.ResultGetter;
import com.ibatis.sqlmap.client.extensions.TypeHandlerCallback;


public class BlobTypeHandlerCallback implements TypeHandlerCallback {

private static final int BUFFER_SIZE = 3000;

/**
* @throws
* @see com.ibatis.sqlmap.client.extensions.TypeHandlerCallback#getResult(com.ibatis.sqlmap.client.extensions.ResultGetter)
*/
public Object getResult(ResultGetter getter) throws SQLException {
Blob blob = null;
String fileName = null;
InputStream inStream = null;
FileOutputStream outStream = null;
try {
blob = getter.getBlob();
File blobFile= File.createTempFile("mytmp", ".tmp", getTmpFileDirectory());
outStream = new FileOutputStream(blobFile);
inStream = blob.getBinaryStream();

int length = -1;
byte[] buffer = new byte[BUFFER_SIZE];

// Write to file
while ((length = inStream.read(buffer)) != -1) {
outStream.write(buffer, 0, length);
outStream.flush();
}
if (inStream != null)
inStream.close();
if (outStream != null)
outStream.close();

return new BlobBean(new FileInputStream(blobFile));
}

catch (Exception ex) {
throw new SQLException("Unable to export to file: " + fileName);
} finally {
inStream = null;
outStream = null;
}

}

/**
* @see com.ibatis.sqlmap.client.extensions.TypeHandlerCallback#setParameter(com.ibatis.sqlmap.client.extensions.ParameterSetter,
* java.lang.Object)
*/
public void setParameter(ParameterSetter setter, Object parameter) throws SQLException {
try {
if (parameter != null && parameter instanceof ChobBlob) {
InputStream is = ((BlobBean) parameter).getInputStream();
File file = ((BlobBean) parameter).getUploadedFile();
if (is != null)
setter.setBinaryStream(is, (int) file.length());
}
} catch (Exception ex) {
ex.printStackTrace();
throw new SQLException("Error in passing the inputstream " + ex.getMessage());
}
}

/**
* @see com.ibatis.sqlmap.client.extensions.TypeHandlerCallback#valueOf(java.lang.String)
*/
public Object valueOf(String s) {
return s;

}

/**
* Generate a random FileName
*/
public static synchronized final String constructFileName() {
Date date = new Date();
return "BLOB_T" + date.getTime() + "T-"+DateFormat.getTimeInstance().format(date).replace(":", "-")
+ Math.random();
}

/**
* Method to get tmp file Directory.
*
* @return
*/
protected File getTmpFileDirectory() {
String tempDir = System.getProperty("java.io.tmpdir");
File fileUploadDir = new File(tempDir + File.separator + "fileupload");
if (!fileUploadDir.exists())
fileUploadDir.mkdirs();
return fileUploadDir;
}

}

2. Create a Blob Class to hold the binary data:
package com.demo.domain;


import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class BlobBean{

/** Reference to the underlying Input stream. */
private InputStream inputStream;

/** Reference to the file */
private File uploadedFile;

/**
* @return the uploadedFile
*/
public File getUploadedFile() {
return uploadedFile;
}

/**
* @param uploadedFile
* the uploadedFile to set
*/
public void setUploadedFile(File uploadedFile) {
this.uploadedFile = uploadedFile;
}

/** No Args Constructor. */
public BlobBean() {

}

/**
* Constructor.
*
* @param inputStream
*/
public BlobBean(InputStream inputStream) {
this.inputStream = inputStream;
}

/**
* Constructor. Initialize inputStream instance variable from the given
* Path.
*
* @param inputStream
*/
public BlobBean(String path) throws IOException {
File f = new File(path);
initalize(f);

}

/**
* Constructor. Initialize inputStream instance variable from the given
* Path.
*
* @param inputStream
*/
public BlobBean(File file) throws IOException {
initalize(file);

}

/**
* Initlalize file to contents
*
* @param f
* @throws IOException
*/
private void initalize(File f) throws IOException {
this.uploadedFile = f;
InputStream is = null;
is = new FileInputStream(f);
this.inputStream = is;
}

/**
* @return the inputStream
*/
public final InputStream getInputStream() {
return inputStream;
}

/**
* @param inputStream
* the inputStream to set
*/
public final void setInputStream(final InputStream inputStream) {
this.inputStream = inputStream;
}
}

3. Create a Bean to hold the binary data:

package com.demo.domain;

import java.util.Date;

import com.demo.domain.BlobBean;

public class FileUpload {

private Long id = ApprovableExtendedBusinessObject.UNSAVED_VALUE;

private BlobBean binaryData;

private Date fileUploadDate;

/**
* @return the fileUploadDate
*/
public Date getFileUploadDate() {
return fileUploadDate;
}


/**
* @param fileUploadDate the fileUploadDate to set
*/
public void setFileUploadDate(Date fileUploadDate) {
this.fileUploadDate = fileUploadDate;
}

/**
* @return the id
*/
public Long getId() {
return id;
}

/**
* @param id
* the id to set
*/
public void setId(Long id) {
this.id = id;
}

/**
* @return the binaryData
*/
public BlobBean getBinaryData() {
return binaryData;
}

/**
* @param binaryData
* the binaryData to set
*/
public void setBinaryData(BlobBean binaryData) {
this.binaryData = binaryData;
}
}

4. Create a DAO implementation class to deal with database


package com.demo.fileupload.dao.impl;


import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;

import com.demo.domain.FileUpload;
import com.demo.fileupload.dao.FileUploadDao;

// Note FileUploadDao must be defined with the necessary methods

public class FileUploadDaoImpl extends SqlMapClientDaoSupport implements FileUploadDao {

public FileUpload download(Long id) throws PersistenceLayerException {
FileUpload fileUpload = (FileUpload) getSqlMapClientTemplate().queryForObject(
"commons.fileupload.download", id.longValue());
return fileUpload;

}

public Long upload(FileUpload fileUpload) throws PersistenceLayerException {
getSqlMapClientTemplate().insert("commons.fileupload.upload", fileUpload);
return fileUpload.getId();

}
}

5. Create a SQL-MAP file

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd">

<sqlMap namespace="commons.fileupload">

<typeAlias alias="blobTypeHandlerCallback" type="com.demo.sqlmap.typehandler.BlobTypeHandlerCallback"/>

<resultMap class="com.demo.domain.FileUpload" id="FileUploadMap">
<result property="id" column="ID"/>
<result property="binaryData" column="FILECONTENT"
typeHandler="blobTypeHandlerCallback"/>
<result property="fileUploadDate" column="FILEUPLOADDATE"/>
</resultMap>

<insert id="upload" parameterClass="com.demo.domain.FileUpload">
<![CDATA[
insert into FILEUPLOAD (ID, FILECONTENT, FILEUPLOADDATE)
values(#id#, #binaryData,handler=blobTypeHandlerCallback#,sysdate)
]]>
</insert>

<select id="download" resultMap="FileUploadMap">
<![CDATA[
select ID, FILECONTENT, FILEUPLOADDATE
from FILEUPLOAD
where ID = #id#
]]>
</select>

</sqlMap>


6. Table Structure
Column Name ID Pk Null? Data Type

ID 1 1 N NUMBER (19)
FILECONTENT 2 Y BLOB
FILEUPLOADDATE3 Y TIMESTAMP(6)