Chitika

Thursday, September 30, 2004

database commit in Toplink

I don't know how the other O/R mapping technology, such as JDO or Hibernate, commits the changes into the database, but Toplink has an interesting behaviour when using the transaction from EJB container.

First, Toplink will remember all database updates (insert, update, and/or delete) being performed within a single transaction. Then, only after the method in which the transaction started exits, and when the EJB Container is about to close the transaction, Toplink will try to generate the SQL statements required to perform the above actions. Toplink then executes these SQL statements, in an order specific to Toplink's dependency algorithm which might differ from the order in which we instruct them to (within our code).

If and only if the database accepts all these changes, then Toplink updates its caches, and return the control back to the EJB Container which will successfully close down the transaction and return back the needed values to the client. If, for example, there's a database exception thrown during the commit phase, the catch block or any other code within our EJB code will not be invoked. Instead, the code of the EJB client will be the one who is supposed to handle the database-related exception.


Why? Because the exception were thrown after the EJB method completes, but before the EJB Container returns the control back to the EJB client. This is troublesome sometimes.


Well, I haven't learned much about Toplink nor any other O/R mapping technology, but is this the ideal approach?

I hardly believe it.. :D

Links:

Links:
Hibernate in Action
More Hibernate books
More JDO books


Wednesday, September 29, 2004

.NET vs. IBM WebSphere

Recently The Middleware Company releases a report based on a study which Microsoft sponsored to compare .NET against IBM WebSphere in a number of dimensions including developer productivity, manageability, reliability and application performance. The report shows not only the results but also shows the steps and processes prior to the conclusion.

You can find the report here.

You can also find what the Java community has to say about this.

My personal opinion is, never to based on any conclusion made by other parties, if they're not based on hard facts and good reasonings, especially if they're too high-level. I haven't got a chance to read through the report, but I hope I can find something to learn there.. :D

Further Reading:
Enterprise Java Programming with IBM WebSphere Second Edition

Tuesday, September 28, 2004

singleton anti-pattern

At first, Singleton was introduce in GOF legendary book as one of the creational design pattern. Singleton design pattern helps to ensure that there will only be one instance of the Singleton class, for each JVM. While the Singleton pattern may be useful for certain types of classes, e.g. constant classes, class loaders, etc., it may not be appropriate for other type of classes.

But now, it's suggested that the usage of this class should be limited to those certain types of classes, because the Singleton pattern makes it almost impossible for the class (and possibly all other classes which depend on it) to be testable. It's very hard to subclass, or to create a mock object for a Singleton class.

It's interesting to keep adapting to implement Test-Driven Development.. :D

Further Reading:
Refactoring: Improving the Design of Existing Code
Design Patterns
Head First Design Patterns

Monday, September 27, 2004

using HTML in Swing components

I was going through the Sun tutorial on Swing this weekend. It's my second time since three years ago, when I use Swing last time. Many have changed since then, in fact the tutorial even states that there will be many enhancements in future versions, such as in JDK 5.0.

One of the few things that interest me is the ability to use HTML text formatting in Swing components. Here's an example:

button = new JButton(
  "<html><b><u>T</u>wo</b><br>lines</html>");

The text on this button will be displayed in two lines, where the first line consists of a 'T' which is bold & underlined, and 'wo' which is bold. You can even play with color, for example:

String color = null;
if (value <= 32) color = "blue";
else if (value <= 80) color = "green";
else color = "red";

StringBuffer sb = new StringBuffer ();
sb.append ("<html><font color=");
sb.append (color);
sb.append ('>');
sb.append (value);
sb.append ("</font></html>");

button.setText (sb.toString());

This will make our Swing application looks even more intuitive.

However, since HTML rendering involves many classes, it may be best to paint the HTML in a background thread prior to showing it.

Currently, the Swing components that supports HTML rendering are JButton, JLabel, JMenuItem, JMenu, JRadioButtonMenuItem, JCheckBoxMenuItem, JTabbedPane, JToolTip, JToggleButton, JCheckBox and JRadioButton.

I guess I'll be making intuitive suggestions if I were to create any Swing application in the future.. :D

Further Reading:
Swing Second Edition
Java Swing Second Edition

Friday, September 24, 2004

Ant mapper datatype

Reading Java Development with Ant
Chapter 3 - Understanding Ant datatypes and properties

It's interesting to see that we have these mapper datatypes in Ant. They're very powerful, yet I have not seen many of the developers use them in their build file. I strongly suggest that these mappers be acknowledged, for the efficiency of the build process itself.

These mapper data can be used with the <uptodate>, <copy>, <move> and some other tasks. A good example would be matching a glob mapper with the <uptodate> task. For example, if no production code is updated, then no compilation should be performed.

<target description="compile if src not uptodate" name="compile">
  <condition property="src.uptodate">
    <uptodate>
      <srcfiles dir="{src.dir}" includes="**/*.java">
      <mapper type="">glob" from="*.java"
        to="{build.dir}/*.class"/>
    </uptodate>
  </condition>
  <javac srcdir="{src.dir}">
        destdir="{build.dir}"
        unless="src.uptodate">
    <classpath refid="classpath.default">
  </javac>
</target>


It is a very simplified version, but the purpose is to have a conditional step in the build process, e.g. no compilation should be performed if the class file is already updated, by comparing each java source code's timestamp against the corresponding (as mapped by the glob mapper) class' timestamp.

This book offers a lot of enhancement to the way we use Ant. I hope I can get a chance to read through the rest of the book.

Further Reading:
Java Development with Ant


Thursday, September 23, 2004

Comparator and Comparable

Again, the topic on Collection usage seems overlooked by most Java developers. Sorting is something that's very common in any programming world, therefore we shouldn't bother to reinvent the wheel for such purpose. As common as it is, yet not many of us know how to do it correctly and efficiently.

In the real business world, there are many cases where we're required to perform sorting on a Collection of some user-defined objects. If the element of the Collection is a String type, or any other class which implements Comparable, then the sorting can be performed in the natural order. But sometimes, we want to perform a different criteria for sorting, or probably we want to sort a user-defined type.

Here's where Comparator comes into play. Clean and extensible.

Here's an example of a simplified user-defined type:

public class Customer {
  private String firstName;
  private String middleName;
  private String lastName;

  // setter & getter methods..
}

In the above class, the most commonly found as natural ordering would be order by lastName. This can easily be implemented using the Comparable interface, i.e.

public class Customer implements Comparable {
  // as shown previously..

  public int compareTo (Object o) {
    if (o == null || !(o instanceof Customer)) {
      throw new IllegalArgumentException ("...");
    }
    Customer c = (Customer) o;
    String cLastName = c.getLastName();

    if (lastName == null && cLastName == null) return 0;
    // assuming you want null values shown last
    if (lastName != null && cLastName == null) return -1;
    if (lastName == null && cLastName != null) return 1;
    return lastName.compareTo (cLastName);
  }
}

Sorting a List of Customer objects would be as simple as:

  Collections.sort (customerList);

But, if we want to use a different ordering, e.g. order by the first name, then we cannot use the natural ordering as defined within the Customer class. Instead, we have to define an alternative ordering, in the form of a Comparator class.

public class CustomerFirstNameComparator
implements Comparator {
  // use singleton whenever possible..

  public int compare (Object o1, Object o2) {
    if (o1 == null && o2 == null) return 0;
    // assuming you want null values shown last
    if (o1 != null && o2 == null) return -1;
    if (o1 == null && o2 != null) return 1;
    if (!(o1 instanceof Customer) ||
        !(o2 instanceof Customer)) {
      throw new IllegalArgumentException ("...");
    }

    Customer c1 = (Customer) o1;
    Customer c2 = (Customer) o2;
    String firstName1 = c1.getFirstName();
    String firstName2 = c2.getFirstName();

    if (firstName1 == null && firstName2 == null) return 0;
    // assuming you want null values shown last
    if (firstName1 != null && firstName2 == null) return -1;
    if (firstName1 == null && firstName2 != null) return 1;
    return firstName1.compareTo (firstName2);
  }
}

Sorting a List of Customer objects by their first name, would be:

  // assuming you implement singleton..
  Comparator comparator =
    CustomerFirstNameComparator.getInstance();

  Collections.sort (customerList, comparator);

Simple, clean & extensible. You can start defining more and more Comparator classes to suit your needs. As it is a Java class, you can also perform complex comparison on the objects.

Wednesday, September 22, 2004

nightly build & extreme programming

Reading Java Development with Ant
Chapter 1 - Introducing Ant

Page 15
"However, every night, one person's computer attempts to build the planet's most popular open-source Java projects from their latest source, using the latest version of Ant as the foundation. When that build breaks because of a change in Ant, the owner of that computer, Sam Ruby, lets the Ant development team know."

What is the percentage of all Java projects in this world are running their nightly builds as early as possible, as soon as the project started?

Having a nightly build, means that the project team can have a great confidence on the results (assuming that they're good), and the project team can also get their feedback immediately (if the results are not good). The nightly build has a great synergy with the continuing integration process, which in the end forces the software to start from a simple running application, and growing in small incremental steps, to always be integrated and refactored along the way, receiving feedback as early as possible, before turning into a production ready application, weeks before the deadline.

Page 16
"The idea is that change is embraced; it is planned for and expected. The software is continually refactored during development to keep it simple, clean, and agile at all times. Change occurs in small incremental steps when using XP, leaving the system ever in a production-ready state."

By doing nightly builds, I believe the whole team is used to having a positive results at all time. Even further, I believe they'll be more adaptive to changes, as they get them daily. I believe the key is to design and code as required, and never to be afraid to refactor. Again, this relates well to having a good unit test mechanism, allowing us to refactor freely, yet safely.

Page 16
"Continuous testing and integration are crucial to obtaining agility inadaptation to change."

Nightly builds, Unit tests, Continuing integration, Change Management & Refactoring...

All of them are keys to successful software development project, I believe. How many of us are courageous enough to cross the bridge to these agile/XP methodologies?

Tuesday, September 21, 2004

up and running, in no time

Reading Java Development with Ant
Chapter 1 - Introducing Ant

Page 14
"Being capable of quickly getting a new development environment up and running is a sign that your project is on the right track."

At a first glance, this may seem to be a trivial task to do. It may be a trivial task for a small scale Java project, but for a large scale J2EE project, this may very well be a non trivial task to do. Can we really perform this consistently even for a large scale J2EE project? The answer to the question remains to be seen.

It's quite a challenge for any Project Manager to make sure that the above quote does happen for his/her project. But, unless a careful planning, and continuing integration is in place, it's an impossible thing to do.

Can we really do it?
Can a new developer who joins the project which started weeks/months earlier, immediately pick up the latest development source code and environment, and set it up in his new PC/laptop, and have it clean compiled and run smoothly within an hour?

I think it's quite a big challenge..


Friday, September 17, 2004

decoupling in session facade

Some J2EE architectures involve session facade design pattern, as a way to hide the implementation from the client and as a way to minimize network roundtrips (if the session has a remote interface). Most of these architectures have either an Entity Bean, a POJO, or another Session Bean, depending on the needs & the requirements.

Most developers still get the facade concept incorrectly. Sometimes, there's hardly any difference between the reponsibilities of the session facade and the responsibilities of the underlying classes. Sometimes, both layers implement the business rules and access the DB at the same time. This may lead to a bad situation where less and less code can be reused.

Here's my opinion on the facade concept. I'm trying to decouple the DB access layer from the business rules layer as best as possible. For example, I've always tried to put the business rules in the facade, and leave the DB access to the underlying layer, may it be an Entity Bean, a POJO or another Session Beans. This would help me a lot in terms of reusability and ease me up a bit on portability.

I get to reuse the same DB access method for multiple business rules. I get the chance to refactor these common methods to be as generic as possible while still keeping the performance in check. I also get a better chance at DB access layer switching, e.g. from Session Bean (DAO) to Entity Bean or from TopLink to Hibernate, etc. Only my DB access layer needs to be modified, where my business rules layer should be less impacted by such switch.

A sample facade would be like the following:

public void deleteUser (String stUserID,
    String stLoginUserID)
throws Exception {
  // verify that all arguments are valid
  // ...

  if (stUserID.equals(stLoginUserID)) {
    // cannot delete him/herself
    throw new Exception ("...");
  }

  // delegate the process to underlying layer
  List roles = listUserRoles (stUserID);

  for (Iterator it = roles.iterator();
    it.hasNext(); ) {
    RoleVO role = (RoleVO) it.next();
    String roleName = role.getName();
    if (roleName.equals("SUPERVISOR")) {

      // delegate the process to underlying layer
      reassignMembers (stUserID);

    } else if (roleName.equals("MEMBER")) {

      // delegate the process to underlying layer
      reassignTasks (stUserID);

    } else if (roleName.equals("ADMIN")) {

      // admin users cannot be deleted,
      // they must be demoted first
      throw new Exception ("...");
    }
  }

  // delegates the process to underlying layer
  invalidateUser (stUserID);
}

As the example above shows, DB accesses to different tables in the DB is being delegated to the underlying layer, i.e. listUserRoles (String), reassignMembers (String), reassignTasks (String), and invalidateUser (String). On the other hand, the business rules, i.e. validation for self-removal, validation for admin role, and additional steps to be performed when the user is a supervisor/member, before actually invalidating the user, will stay in the facade.

This decoupling will improve readability, reusability, and at the same time will minimize the ripple effects should the underlying DB schema is changed, or the business rule is slightly modified.

I know sometimes it's hard to get the discipline..
But in the end, I think it's worth the efforts.. :D

Thursday, September 16, 2004

sample IDEA live template

Following is a sample of IDEA Live Template that I'd like to share and discuss:

/**
 * Getter method for the text version of a double field
 * named $DECAPITALIZED_FIELD_NAME$ with a precision of
 * $PRECISION$.
 */
public String get$FIELD_NAME$Text () {
  Double d$FIELD_NAME$ = get$FIELD_NAME$();
  return StringConversionUtil.doubleToString (
    d$FIELD_NAME$.doubleValue(), $PRECISION$);
}

/**
 * Setter method for the text version of a double field
 * named $FIELD_NAME$.
 */
public void set$FIELD_NAME$Text (
    String $DECAPITALIZED_FIELD_NAME$Text) {
  double d$FIELD_NAME$ =
    StringConversionUtil.stringToDouble (
      $DECAPITALIZED_FIELD_NAME$Text);
  set$FIELD_NAME$ (d$FIELD_NAME$ == 0.0 ?
    StringConversionUtil.ZERO :
    new Double (d$FIELD_NAME$));
}

The above Live Template is trying to provide additional methods in the ActionForm class to provide semi-automatic data type conversion for the ActionForm auto-population mechanics in Struts (see my previous post, limitation of ActionForm in Struts).

For every double field in the class (or its subclass), you can just type in the abbreviation, e.g. "setgetdouble", and hit the expand key, e.g. "Tab", boom!

The setter & getter method will be generated automatically. All you need to provide is just the DECAPITALIZED_FIELD_NAME & PRECISION. Following is an example of what's the generation result if the DECAPITALIZED_FIELD_NAME is 'ratio' and the PRECISION is '2':

/**
 * Getter method for the text version of a double field
 * named ratio with a precision of
 * 2.
 */
public String getRatioText () {
  Double dRatio = getRatio();
  return StringConversionUtil.doubleToString (
    dRatio.doubleValue(), 2);
}

/**
 * Setter method for the text version of a double field
 * named Ratio.
 */
public void setRatioText (
    String ratioText) {
  double dRatio =
    StringConversionUtil.stringToDouble (
      ratioText);
  setRatio (dRatio == 0.0 ?
    ScoringCommonConstants.ZERO :
    new Double (dRatio));
}

Here's what I put for the template variables:
- DECAPITALIZED_FIELD_NAME
    Expression: variableOfType("java.lang.Double")
    Default value: "aDoubleField"
- FIELD_NAME
    Expression: capitalize(DECAPITALIZED_FIELD_NAME)
    Skip if defined: Checked
- PRECISION
    Default value: "2"

The variableOfType() expression will show you a selection of all variables within the current scope whose type is the same as you specified.
The capitalize() expression will capitalize the first character of the variable's value which you specified.
The rest is quite straightforward.

What do you think? It helped me.. :D
I'll share more of my live templates next time.. :D

Wednesday, September 15, 2004

optimizing collection usage

We've been playing with Collection classes for years now. We used to play with Vector & Hashtable, before we were given ArrayList, HashMap, and the new Linked* classes. But the question still remains, have we use them properly and efficiently?

I believe that not many developers have realized this. Improper usage of Collection may cause unnecessary memory allocation & performance degradation. Especially when involving loop or recursive calls.

For example, if we're required to create an instance of Map interface which contains a single entry (key-value pair), and we know that this Map instance will never be altered, then the best way to go is by using the singletonMap() method in the Collections utility class.

Map param = Collections.singletonMap ("USER_ID", stUserID)

instead of creating the default HashMap implementation, which will automatically allocate 16 entries into the memory usage.

Map param = new HashMap ();
param.put ("USER_ID", stUserID);

By using the default HashMap implementation, we're allocating more memory than we need, and we perform tasks which we may never need. The similar method exists for List as well.

Still with the same "optimize while initializing" spirit, both HashMap and ArrayList should be instantiated efficiently, to prevent the overhead of auto-resizing implementation of both classes. For example, an ArrayList will automatically expand itself, including copying the old elements of the internal array to the newly created internal array. This cause overhead in the number of instructions that'll need to be executed as well as the extra memory to be allocated. Similar conditions apply to HashMap as well.

If we have known for sure what's the number of elements to be included within the Collection, it'd save a good number of instructions to be executed as well as unnecessary amount of memory to be allocated.

For example, to convert elements of a List from a Class type to another Class type (e.g., from Transfer Object to ActionForm), we'd known what the size is beforehand.

public static List convert (List transferObjects) {
  List result = new ArrayList (transferObjects.size() + 1);
  for (Iterator it = transferObjects.size();
       it.hasNext(); ) {
    TransferObject obj = (TransferObject) it.next ();
    ActionForm bean = ActionFormFactory.getInstance (
        "xForm");

    // assuming that there's another private method
    // dealing with the conversion for each field
    convert (obj, bean);
    result.add (bean);
  }
}

Same with a HashMap, whose default load factor is 0.75. Here's my trick:

// the number of entries known to be inserted
final int KNOWN_CAPACITY = 3;
final int INITIAL_CAPACITY =
    1 + (KNOWN_CAPACITY + 1) * 4 / 3;

Map params = new HashMap (INITIAL_CAPACITY);
params.put ("USER_ID", stUserId);
params.put ("LOGIN_ROLE", stLoginRole);
params.put ("KEYWORD", stKeyword);

Hopefully, using the above approaches, I can minimize (or prevent) the unnecessary auto-resizing & extensive memory allocation.
I think it's very easy to be done, and it has a good impact on the performance & quality of the code.
What do you think?


Tuesday, September 14, 2004

live templates in IntelliJ IDEA

Three years ago, I was not a fan of any IDE tools. My favourite Java editor was UltraEdit. I've switched to EditPlus once a while, but mostly it's UltraEdit that got me through many Java projects. Two years ago, most of the developers in my company started using IntelliJ IDEA, but I wasn't impressed enough to even give it a try.

Until last year, when I had a chance, I took a look at IntelliJ IDEA 3.0. It's quite impressive actually. One thing for sure, I really like the refactoring tools that came with it.

Recently, when I played around with the latest IntelliJ IDEA 4.5 which already includes the Inspection Gadget 2.0, I was more impressed, and making it my favourite IDE for Java. Since then, I'm trying to use more and more features in it, and try to minimize my time to develop any Java application.

With the spirit of leveraging my productivity, I'm currently testing the Live Templates in IDEA. I was hoping it could help me boost my productivity. And, apparently it did. I have been using most of the pre-constructed Live Templates (as listed in Ctrl-J). And now, I have even tried to create some Live Templates for my daily usage.

It's working great. It can be even copied and imported to my PC at home, since it's created in an XML file. This could very well be a good step to enrich my experience with IDEA.

If you had not tried it, it's highly recommended..
If you had created any user-defined live templates which can be shared, I'd really like to take a look.. :D
I'll share mine once it's not so application-specific, and more generic instead..

Friday, September 10, 2004

limitations of ActionForm in Struts

Up until now, Struts have been used quite extensively throughout the world of J2EE Web developers. I myself just try to start using them a little bit. One of the few things I've encountered is the limitations of ActionForm. One limitation I'd like to cover here is the limitation of the automatic population strategy implemented by Struts.

Struts currently allows only String and boolean to be automatically converted into the ActionForm properties. It leaves the rest of the data types for the developers to implement them. As the book Struts in Action suggested, creating helper methods might solve the problem, for example:

private double approvedMinimum;

public String getApprovedMinimumText () {
  return StringConversionUtil.doubleToString (
    approvedMinimum,
    2);
}

Assuming we had the StringConversionUtil class with this method:

public static String doubleToString (double d, int digit) {
  StringBuffer pattern = new StringBuffer ("#");
  if (digit > 0) {
    pattern.append (".");
    for (int i=0; i<=0; i++) {
      pattern.append ("0");
    }
  }
  NumberFormat nf = new DecimalFormat (pattern.toString());
  return nf.format (d);
}

This method will be used to populate the approvedMinimum, which was supposedly to be a double value. A similar method must also be created to parse the user-inputted String into a double on the way in. The same applies for other non-String, non-boolean data type, such as Calendar, etc.

Another option is to declare all properties in the ActionForm as String, as suggested by the Programming Jakarta Struts book. It claims that the ActionForm was not designed as the [m]odel holding the real data, instead it's merely a representation of the [v]iew. Hence, this approach might force us to implement the conversion manually before setting the value into the ActionForm.

I'd rather go with the first approach..

Are these the only options to go?
Are there any other options which just might be better than those books have to offer?
I sure would love to hear... :D


Thursday, September 09, 2004

bomb in jakarta

Facts:
- Exploded today, 10.15 (03:15 GMT) just outside Australian Embassy in Rasuna Said Street, Kuningan, Jakarta
- At least 9 people were killed and more than 100 people were injured
- At least 10 cars, 2 motorcycles and 2 minibuses (metromini) were destroyed
- The blast creates a crater of 30 metres by 30 metres, and 3 metres deep (which is larger than the previous Mariott bomb, which is 20 metres by 20 metres)

Worse Facts:
- I live there, 500 metres away
- I currently in the office, 10 km (6 miles) away
- I don't have any idea what might happen next

Follow ups:
- Australian PM sends 9 bomb experts & foreign minister to help investigate

Just as reminder:
December 2000 - Christian churches bombings kill 19
October 2002 - Bali attacks kill 202, 88 of them are Australian
December 2002 - Blast at McDonald's in Sulawesi kills three
August 2003 - Bomb at Marriott Hotel in Jakarta kills 13
September 2004 - Bomb outside Australian embassy in Jakarta


Wednesday, September 08, 2004

constant classes

Many approaches have been taken toward how should constant values are implemented in Java. In the early days, some developers used to put constant values in an interface, instead of a class.
For example,

public interface Constants {
  public static final Double ZERO = new Double (0.0);
}

But this practice soon becomes less popular, since the OOP experts find that most developers using the interface approach abuse that interface, thus violating what should be the concepts of interface-inheritance. Interface was designed for the main purpose of giving a certain identity or marking that the implementing classes have that ability. While on the other hand, implementing an interface containing constant values just for the sake of lazy coding might beat those initial purposes.

Hence, most developers start taking the final class approach..
For example,

public final class Constants {
  private Constants () { }
  public static final Double ZERO = new Double (0.0);
}

This approach has become more or less de facto standard for defining constant values.

As we grow more and more, code more and more, we learn that it would be better to place as many literal values as possible into constant values within a constant class. If we're talking about a small application, that shouldn't raise any eyebrow. But when we're talking about an enterprise application with more than 10,000 classes, this could trigger a possible refactoring.

AFAIK, there are two refactoring approaches when dealing with a constant class having more than 20 constant values..
We can group the related constant values into nested classes, naming them with the appropriate namespace, or we can create one or more separate (non-nested) constant class(es), assuming that the constant values can be grouped or categorized into two (or more).

I currently don't know which is best..
But I may opt to go with the combination of both approaches whenever possible..

Tuesday, September 07, 2004

gmail account

This is my first post since when? three years?..
It turned out that I wasn't into blogging 3 years ago..
I don't know about now..
At least I'm trying..

Anyway, to start off the blog habit..
Yesterday, I was looking for a gmail account, and turned out that it was only given to several people through the limited invitation..
Apparently, it's very hard to get the invitation..
I had this guy on a m-list, sharing his gmail account, so I check the FAQ there, and it explains that sometimes, on a quite-random case, Google will give a link in the Inbox, which we can use to invite other people in testing the gmail account.
Since I still don't have a gmail account, it should be obvious that the link wasn't there..
And, I can't get into the shared account since..

But my initial experience is, it was slow logging in, but it's quite fast when checking messages (unlike yahoo).. It's slow though, when refreshing the inbox..
Anyhow, I still don't have a gmail account, so I'm hoping if by any chance anyone out there reading this blog, might be kind enough to share me one, I would be very grateful.. :D

Some say also that blogging just might get you one.. :P