Thursday, October 24, 2013

Java: Iterator

The Iterator interface is a member of the  Java Collections Framework.

Important notes about Iterator:

  • We can iterate in only one direction.
  • Iteration can be done only once. If you reach the end of the collection its done. If we need to iterate again we should get a new Iterator.
  • We cannot add or remove elements to the underlying collection when we are using an iterator except by calling the Iterator's remove() method.


Here is the Iterator interface documentation.

ITERATOR WITHOUT GENERICS USING FOR-LOOP

import java.util.ArrayList;
import java.util.Iterator;

public class ExampleIterator {

  public static void main(String args[]){
    List brands = new ArrayList();
    brands.add("Honda");
    brands.add("Nissan");
    brands.add("Toyota");

    for (Iterator iter = brands.iterator(); iter.hasNext();) {
    String brand = (String)iter.next();
      System.out.println(brand);
    } 
  }

}

Note: Without generics, Iterator returns an Object so you need to typecast it.


ITERATOR WITH GENERICS USING FOR-LOOP

public class ExampleIterator {

  public static void main(String args[]){
    List<String> brands = new ArrayList<String>();
    brands.add("Honda");
    brands.add("Nissan");
    brands.add("Toyota");

    for (Iterator<String> iter = brands.iterator(); iter.hasNext();){
    String brand = iter.next();      
      System.out.println(brand);
    }
  }

}


ITERATOR WITHOUT GENERICS USING WHILE-LOOP

import java.util.ArrayList;
import java.util.Iterator;

public class ExampleIterator {

  public static void main(String args[]){
    List brands = new ArrayList();
    brands.add("Honda");
    brands.add("Nissan");
    brands.add("Toyota");

    Iterator iter = brands.iterator();

    while(iter.hasNext()) {
      String brand = (String)iter.next();
      System.out.println(brand);
    }
  }

}


ITERATOR WITH GENERICS USING WHILE-LOOP

import java.util.ArrayList;

public class ExampleIterator {

  public static void main(String args[]){
    List<String> brands = new ArrayList<String>();
    brands.add("Honda");
    brands.add("Nissan");
    brands.add("Toyota");

    Iterator<String> iter = brands.iterator();

    while (iter.hasNext()){
      String brand = iter.next();
      System.out.println(brand);
    }
  }

}


ITERATE USING FOR-EACH OF GENERICS
(No explicit reference to the Iterator object)

import java.util.ArrayList;

public class ExampleIterator {

  public static void main(String args[]){
    List<String> brands = new ArrayList<String>();
    brands.add("Honda");
    brands.add("Nissan");
    brands.add("Toyota");

    for(String brand : brands) {
      System.out.println(brand);
    }
  }

}



Tuesday, October 15, 2013

Java: Best way to use the equals() method

The equals() method compares values for equality. Since this method is defined in the Object class, which is the root of the class hierarchy, it's automatically defined for every class such as the String class.

The best way to use the  .equals() method when comparing values of String objects is to write it as:

"Hello World".equals(fooBar);
"".equals(fooBar);

rather than:

fooBar.equals("Hello World");
fooBar.equals("");


Both sets of examples will compile but the first set guarantees that a NullPointerException is never thrown when you perform the comparison. The second set may risk throwing a  NullPointerException if the object fooBar happens to be null.

Thursday, October 10, 2013

Websphere Application Server: Use a cleanup batch file instead of coding in debug mode

Typically, we run our application servers in debug mode when we code so it picks up our changes on java files without the need to restart the server before we run our applications. However, early on at some point the Websphere Application Server (WAS) stops picking up our changes even  in debug mode.

A better alternative to running in debug mode (and the method I much prefer) is starting the application server  through a normal start and using a batch file to clean up the WAS temporary files.

I just run the batch file below to clean up  the application server's temporary files every time I make changes to java and jspf files. You should also clear your browser's cache and reload the application on your browser. No need to restart the application server.

Here is the code for the batch file:

@echo off
set WCT_WASPROFILE=D:\IBM\WCToolkitEE60\wasprofile
REM Delete WebSphere Commerce Developer Temp Files
set DIR=%WCT_WASPROFILE%\temp\localhost\server1\WC\Stores.war
set DIR2=%WCT_WASPROFILE%\wstemp
set FILE=%WCT_WASPROFILE%\javacore.*.txt
set FILE2=%WCT_WASPROFILE%\heapdump.*.phd
set FILE3=%WCT_WASPROFILE%\logs\server1\*.*

ECHO.
ECHO Cleaning WAS Temp Directory:
ECHO    %DIR%
rmdir /Q /S %DIR%
ECHO.
ECHO Cleaning WSTEMP Directory:
ECHO    %DIR2%
rmdir /Q /S %DIR2%
ECHO.

ECHO Cleaning Javacore Files:
ECHO    %FILE%
DEL /Q /F %FILE%
ECHO.
ECHO Cleaning Heapdump Files:
ECHO    %FILE2%
DEL /Q /F %FILE2%
ECHO.
ECHO Cleaning Server1 Logs Files:
ECHO    %FILE3%
DEL /Q /F %FILE3%
ECHO.
ECHO Cleaning Complete...
ECHO.
PAUSE


Remember though that at some point the application server will stop picking up your changes and will need a restart. But it will be way much longer before that happens compared to when running in debug mode.

Happy coding!


Wednesday, October 9, 2013

Dojo: Using dojo.query with pseudo-selectors

Changing HTML markup programmatically is dependent on locating nodes. You may go the traditional way of  selecting HTML elements in Javascript by using the browser's native DOM API like "document.getElementsByTagName( )" and "document.getElementsByClassName( )". But your code can get long, verbose and slow.

dojo.query is a better, faster, and more compact way to do this. It can also handle sophisticated DOM element relationships.

dojo.query() returns a list of DOM nodes based on a CSS selector.

Using dojo.query with pseudo-selectors is very interesting because it's a very compact way of getting a list of DOM nodes with several attributes.

Example:
Get the input checkbox elements with its "checked" property equal to true (a checked checkbox element) contained within an unordered list with an ID of  "sidebarCategories", then put the focus on the first checked input checkbox.

var checkboxes = dojo.query("ul#sidebarCategories  input[type=checkbox]:checked");
if (checkboxes.length > 0) {
    checkboxes[0].focus();
} 

Now that code is pretty compact and clean.

Check out the dojo.query documentation for more simple and compound queries using CSS, descendant and attribute selectors.

Monday, October 7, 2013

Websphere Commerce: Controller Command Design Pattern

Commands are beans that perform business logic. Command beans follow a specific design pattern. Every command includes both an interface class (for example, CategoryDisplayCmd) and an implementation class (for example, CategoryDisplayCmdImpl). See the Websphere Commerce Command Framework and Command implementation documentation for more info.

The four main types of commands are: controller, task, view and data bean commands.

This blog post is about the controller command design pattern.

Controller Command Interface

Pattern:

public interface MyNewControllerCmd extends ControllerCommand {

   // set default command implement class
   static final String defaultCommandClassName  =  "com.ibm.commerce.sample.commands.MyNewControllerCmdImpl
}


Saturday, October 5, 2013

jQuery Plugin: modified Image Magnifier plugin for multiple images

I had a project requirement for an image magnifier for multiple images in a single page. The page will have a list of products where each product have an image magnifier as part of its listing.

I found this jQuery plugin called Easy Image Zoom among other plugins while googling for the term "image magnifier jquery".

The original jQuery plugin, demo and instructions are found on the plugin author's page.

The plugin was easy to use but only worked with just one image for each page.

So I modified the image magnifier plugin so that it will work with multiple images in one page. The plugin's javascript code with the annotated modifications is listed below. The code in blue text are the new codes and codes in red text are commented out codes.

/*
 * Easy Zoom 1.0 - jQuery plugin
 * written by Alen Grakalic
 * http://cssglobe.com/post/9711/jquery-plugin-easy-image-zoom
 *
 * Copyright (c) 2011 Alen Grakalic (http://cssglobe.com)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * Built for jQuery library
 * http://jquery.com
 *
 */

 /*

 Required markup sample

 <a href="large.jpg"><img src="small.jpg" alt=""></a>

 */

(function($) {

$.fn.easyZoom = function(options){

var defaults = {
id: 'easy_zoom',
parent: 'body',
append: true,
preload: 'Loading...',
error: 'There has been a problem with loading the image.'
};

var obj;
var img = new Image();
var loaded = false;
var found = true;
var timeout;
var w1,w2,w3,w4,h1,h2,h3,h4,rw,rh;
var over = false;
//new code 
var hoveredLink;

var options = $.extend(defaults, options);

this.each(function(){

obj = this;
// works only for anchors
var tagName = this.tagName.toLowerCase();
if(tagName == 'a'){
/* - commented out this code because the img var only stores the image of the last <a> link element
var href = $(this).attr('href');
img.src = href + '?' + (new Date()).getTime() + ' =' + (new Date()).getTime();
$(img).error(function(){ found = false; })
img.onload = function(){
loaded = true;
img.onload=function(){};
};
*/
$(this)
.css('cursor','crosshair')
//.click(function(e){ e.preventDefault(); })
.click(function(){ hide(); })
.mouseover(function(e){ start(e, this); })
.mouseout(function(){ hide(); })
.mousemove(function(e){ move(e); })
};

});

function start(e, imgLink){
hide();

/* begin new code */
//assign mouseovered image link to global var hoveredLink
hoveredLink = imgLink;
//load the zoom image (big image) for the mouseovered image link
var href = imgLink.href;
img = new Image();
img.onload = function(){
loaded = true;
};
img.src = href;
$(img).error(function(){ found = false; })
/* end new code */

var zoom = $('<div id="'+ options.id +'">'+ options.preload +'</div>');
if(options.append) { zoom.appendTo(options.parent) } else { zoom.prependTo(options.parent) };
$('#'+ options.id).html('').append(options.preload);
if(!found){
error();
} else {
if(loaded){
show(e);
} else {
loop(e);
};
};
};

function loop(e){
if(loaded){
show(e);
clearTimeout(timeout);
} else {
timeout = setTimeout(function(){loop(e)},200);
};
};

function show(e){
over = true;
w1 = 0; h1 = 0; w2 = 0; h2 = 0; w3 = 0; h3 = 0; w4 = 0; h4 = 0; rw = 0; rh = 0;
$(img).css({'position':'absolute','top':'0','left':'0'});
//put the big image in the popup DIV
$('#'+ options.id).html('').append(img);
/* - commented out and replaced this code because $('img', obj) wrongly gets the last small image in the page
w1 = $('img', obj).width();
h1 = $('img', obj).height();
*/

/* begin new code */
/* use children[0] to get the thumb image because firstElementChild returns null in IE10 and
firstChild returns a text node in Chrome. children is a collection of just the child nodes that are elements */
//get small image properties
w1 = $(hoveredLink.children[0]).width();
h1 = $(hoveredLink.children[0]).height();
/* end new code */

//get popup zoom DIV properties
w2 = $('#'+ options.id).width();
h2 = $('#'+ options.id).height();

//get big image properties
w3 = $(img).width();
h3 = $(img).height();

//get difference between big image properties and  DIV (of big image) properties
w4 = w3 - w2;
h4 = h3 - h2;

//get ratio of w4 and h4 against small image properties
rw = w4/w1;
rh = h4/h1;

move(e);
};

function hide(){
over = false;
/* begin new code */
loaded = false;
found = true;
/* end new code */
$('#'+ options.id).remove();
};

function error(){
$('#'+ options.id).html(options.error);
};

function move(e){
if(over){
// target image movement
//var p = $('img',obj).offset();

//replaced code above with new code below to get the correct thumb image (small image link)
/* begin new code */
/* use children[0] to get the thumb image because firstElementChild returns null in IE10 and
firstChild returns a text node in Chrome. children is a collection of just the child nodes that are elements */
var thumbImg = hoveredLink.children[0];
var p = $(thumbImg).offset(); //get the 'top' and 'left' coordinates of the small image
/* end new code */

//pageX returns the mouse position relative to the LEFT edge of the document
//pl = difference between the mouse position and LEFT coordinate of the small image
var pl = e.pageX - p.left;

//pageY returns the mouse position relative to the TOP edge of the document
//pt = difference between the mouse position and TOP coordinate of the small image
var pt = e.pageY - p.top;

//rw is the RATIO of the big image width against the width of the zoom DIV (of big image)
//xl = the new LEFT coordinate of the big image
var xl = pl*rw;

//rh is the RATIO of the big image height against the height of the zoom DIV (of big image)
//xt = the new TOP coordinate of the big image
var xt = pt*rh;

xl = (xl>w4) ? w4 : xl;
xt = (xt>h4) ? h4 : xt;

//if big image is smaller than popup DIV container, center the image in the DIV
//else, do the image magnifier scroll
if (w4 < 0 && h4 < 0) {
//top property of big image = (Div height - big image height) / 2
var topVal = (h2-h3)/2;
$(img).css({'position':'relative', 'top':topVal, 'display':'block', 'margin':'0 auto'});
} else {
//$('#'+ options.id + ' img').css({'left':xl*(-1),'top':xt*(-1)});   --> original code replaced with the one below
$(img).css({'left':xl*(-1),'top':xt*(-1)});
}
};
/* begin new code */
//check if big image was loaded (is available)
if (!loaded) {
$('#'+ options.id).html('').append("Big image is not available");
};
/* end new code */
};

};

})(jQuery);