Sunday, December 13, 2009

Google Docs for Xanukah חנוכה

I am reading that Dave Girouard, the president of Google’s enterprise division, besides admitting that Google Docs is not mature enough to completely replace Microsoft Office, (and therefore, in my presumption, Open Office also) he says that within a year, we won't need Microsoft Office anymore if we used Google Docs.

I would like to believe that will come true. All I want for Xmas/Xanukah is my Google Docs, my Google Docs.

I am writing Xanukah חנוכה instead of the accepted Chanukah to emphasize that ח is pronounced Xa, rather than Cha, like you were swallowing while pronouncing the Spanish X in Mexico (mehiko). Like the artist's surname van Gogh, where most pronounce it van goe/gog/gof, though varn xox should be closer to what he had preferred.

I had been writing web applications to broadcast enterprise information through tables and charts for many years.

I have an empathic ear to Girouard because I have seen the cost of Office licensing being over-frequently wasted by managers, clerks, secretaries and even fellow-programmers who would use Excel merely for writing notes. Worse scenarios are when they ask for web apps to create Excel versions of the dynamically generated web pages, not because they could or would write VB script to further enhance the charts but because they had been too used to looking at reports through Excel. The exception to my amazement at this phenomenon, are the few who actually used Excel or Presentation for the purpose of creating management presentations or for arithmetic/mathematical purposes.

But then, I want to be cautious with my enthusiasm because currently using Google Docs is a rather inconvenient affair.

Google has a love affair with tags and uses tags to replace folders. Google seems to project a very strong opinion about their opinionated opinion about the advantage of tags over folders and seems to work silently and saliently to educate users to transform our folder-based perspective to a tag-based life-style.

I love folders and I just don't know how to further let Google know it so that they would stop shoving their taginization down my folderated throat. As evidenced by gmail. I am telling myself that if I find the time, I would write Java GAE interface to gmail that transforms the tags in my email to folders. Instead of counting sheep to sleep, I am thinking of the proper tag convention that would register a hierarchical folder tree for that yet-to-be-written application.

According to my topological perception, a folder structure is a subset of tag structure. Depending on implementation preference, one could be the topological inversion of the other. Google's current single dimensional tag architecture means that they could only properly simulate one level of folders.

In Google Docs, my feeling is that they are using tags to masquerade as folders. Using tags to masquerade as folders has the advantage of placing an item in more than one folder simply because you could apply multiple tags to an item. But, if I designed a way to tag a tag, that is placing a tag as a member of another tag, I could have a hierarchy of tags/folders.

So, my wish for Xanukah 2010 is Google Docs with proper folder behaviour, since currently, when you attempt to create a new document at the current folder, the new document gets created at the root. Then you would have to move the document back to where you actually wanted it created.

Next, the current GData API for a Java application to access documents in Google Docs should be made less clunky. Using GData API, you could create tables in a spreadsheet. The incovenience I face is that I am unable (either due to my stupidity or GData short-comings) to create tables that expand dynamically. Once created, it seems that I cannot change the sizes of the tables except by deleting the table. Or if I did try to respecify the size of the table, I get thrown a horrigible exception. On the whole, GData API's approach to Google Docs needs to be more programmer friendly. Without supporting web programmers like me, who could automate manipulation of Excel tables, who now need a friendlier API to manipulate Google Docs, Google is overlooking the influence of web programmers who helped sustain popularity of Microsoft Office.

Last but not the exhaustive last of the list, I have a lofty perception that there are no organisational silos in Google and yet Google Sites refuse to work properly with Google Docs. Google Sites pages allow me to embed Google Docs documents. If I had ten worksheets in a spreadsheet, frequently I only wish to publish just, perhaps, six of them because the other four are unintelligible mess of intermediate references I do not wish the reader of a report to see. But, Google Sites would not allow me to publish the worksheets selectively.

Therefore, another of my 2010 Xanukah wish is that the Google Sites team stop barricading themselves but work closely with the Google Docs team.

Mr Girouard should take note that, not only does Google Docs need to mature, the relationship between his Google Docs team and his Google Sites team and his Google App Engine team needs to mature and be strengthened. Otherwise, he would scantly find the invaluable support from web programmers to make his vision come true.

Monday, October 19, 2009

Have you ever considered Linux?

To cut the story short, I actually have been spending the last two weeks on 64 bit Ubuntu Linux.

It was fast. So fast. There was no lag on Eclipse mouse and key strokes as experienced on Vista. GWT compile was somewhat faster. I also feel GAE jetty response is faster. The Gnome desktop was great, though I am reading that KDE might be a better choice, aesthetically. And most of all, unlike Vista, the screen does not traumatize you blanking out for a few seconds each time it requested superuser privileges. What were the Vista designers thinking about? I am always wanting to ask any Vista insider - what the heck were you thinking or smokin when you introduced the pre-permission blank screen?

The installation was also less tedious and quicker than installing a Windows operating system. I used to worry that with the amount of features and infrastructure Microsoft provides that Linux had no means of being a viable or practical useable office networked deployment. After really using Linux, I am starting to worry for Microsoft because my twenty years of experience in IT for office and factory automation is telling me that Linux deployment is more supportable and office-sustainable and would be cheaper to maintain than a deployment based on Microsoft Windows. My concern now is how to keep a lid on Linux and continue keeping financial decision makers hoodwinked so that corporations continue to be addicted to Microsoft and so that Microsoft would not become another, now defunct, Digital Equipment Corporation. A financially viable Microsoft is good for the world - if not for the world, at least for this country.

I chose Ubuntu over Fedora because, well ... Dell chose it. Therefore, while I am more informed on Ubuntu now due to my focused attention on it, I can safely profess I have had insufficient exposure to Fedora to compare Washington apples with California apples.

Due to my prior exposure to Solaris and VMS, I have a strong attachment to unified system and library management. A concept that Microsoft propagates too, but which you could easily circumvent to install an application which replicates instances of libraries that are already installed on the machine multiple times in multiple locations by other applications. There are Java applications that force you to reinstall a whole JDK on their installation directories.

However, Ubuntu through Synaptic Package Manager and its Debian-based software repository system almost always force applications to be installed in a coordinated non-replicated manner, or otherwise make it really really really inconvenient and unworthwhile for the user and application not to. Which is good because, while my Vista installation minus non-Microsoft software is a bloated 60 GB, my Ubuntu installation with lots of stuffs (various JDK, Eclipse, Tomcat, Open Office, etc, etc) installed is only a miserly measly 5.9 GB.

Ubuntu is good for saving disk space.

However, a former colleague of mine believes in free-standing applications software libertarianism. He believes - the OS should not constrain us from using our own instances of libraries, our own versions of an application so that the application we produced could be packaged within a portable directory that could be singly moved by a USB flash stick to be run on any system. He believes that the advantage is that we would have the freedom not to infect a system if our application requires the use of an alternative version of a resource. He believes that and had successfully persuaded management that software-installation libertarianism is not only in the spirit of agile development, but the only spirit of agile software development!!!

I wish to say emphatically and empathetically that his view-point and those who subscribe to the attitude of free-standing applications software libertarianism is dead point-blank wrong. Worse still, I have had so many freakn years working in both agile cycles, extreme engineering as well as the dreadful full cycle waterfalls, that I can say that software-installation libertarianism is barbaric and has nothing to do with agile development. Under such an environment, it was frequently difficult to track which customer was using which combination of stuffs. Frequently, such an environment even allows inconsistent different releases of the same version. So, we had to manage and track all the different combinations of packaging containing whole copies of source codes down to the libraries and open-source ware marked by customer and package datetime. So, this is agile?! This strategy was supposed to make it simple and idiot-friendly so that the field engineer did not have to mess around with installation procedures. But then the field engineer had to manage the multiple packages that are being installed, no not installed but dumped is a better word, at various machines of the same customer site.

Under Synaptic and Debian management, all a developer has to do is to create alternative versions of resources and install them through debi. Every variation is tracked. Software wise, some people are Libertarian Democrats, but I am a Socialist Republican. I believe that utilisation of the environment and infrastructure should be coordinated, conserved and not replicated in a wasteful manner so that real Capitalism, truly free enterprise and actual freedom could flourish adaptably, cheaply and flexibly on the surface of the ocean of community coordinated socialism.

Coordinated system installation is good for those practicing agile engineering. Those who don't believe this are only looking towards short-term gains ignoring the certainty of long-term horrors. Those of you Scrum practitioners who propagate the idea that Scrum permits opportunistic discipline and that initial outlay and efforts into designing sustainability of the software is a waste of time, I think you are scum to agile development efforts - i.e. you are Scrum scum and the environment you propagate is Scrum scum slum.

Monday, October 12, 2009

Hitch Hiking to 64 bit Windows 7?

I shall then bit-torrent an ISO of 64 bit Vista.

Though I did, but why should I, because everytime I went to any Microsoft upgrade web site, it redirects me to Windows 7 pages saying be patient and wait for Windows 7 release by the end of October. Microsoft realises how crappy Vista is.

Microsoft emailed me some Windows 7 beta product keys some months ago when its availability was first announced but I had to download the ISO from bit-torrent because Microsoft's servers were swamped.

Too bad, the product keys were not accepted my 64 bit Windows 7 beta installation, and I know why - my keys were for 32 bit.

Is it true that from Windows 7 onwards, Microsoft will no longer allow interchangeability of licence between 32 and 64 bit?

In the rather appropriately titled PC World article http://www.pcworld.com/article/173678/article.html?tk=nl_bex_h_news, they have an even more appropriate picture of Gv'nor Arhnold Swashbuckler:

Hasta la Vista, baby!


I am thinking of buying an early edition of Windows 7 by going through OEM resellers.

Anyway, Windows 7 is fast, really fast on desktop interactions. Generally, technogeeks are relating Vista to Windows 98. Why did they even bother with releasing Windows 98. However in general also, technogeeks are saying Vista ain't as bad as W98. I disagree because it's like saying the 2008 economic meltdown was not as bad as the 1932 crash. Humanity in 2008 simply has more features and amenities to distract us from the the meltdown that is just as bad as 1932.

I am echoing what every geek is saying today ~ Why did they bother with Vista at all?

Microsoft had even once tried to force big institutional and commercial concerns to drop XP and quickly adopt Vista. To which the big customers must have threatened en masse direction towards Linux. Otherwise, why had Microsoft taken an abrupt jerk back away from that decision?

The verdict due to the jury of my multiple senses is that persistently loyal, compulsive users of Microsoft technologies should quickly throw the leaky junk life-boat overboard and migrate to Windows 7 as soon as their financial resources permit.

Hitch Hiking to 64 bit Vista

In those days, even people who didn't pay much attention to Queen knew their two most popular pieces - We will rock you and We are the herose. No, three, including Bohemian Rhapsody. Did I spell that wrongly? Alright, We are the heroes.

I never knew they were categorised as heavy metal rock. As a kid I thought they sounded rather classical and operatic. They are nowhere jock-shocking as ACDC, Black Sabbath or Alice Cooper. Using midi software to reassign tracks to strings and winds, you might think they sound pretty classical, right?

Who on earth flagged this (I want to break free) video as inappropriate so that you needed to confirm you're 18 before allowed to watch it? Is men dressing as women in a video inappropriate? No sexual explicitness and even some traditional ballet routines are more sexually suggestive. Perhaps, we should go around youtube flagging every ballet video as inappropriate. I recall, some fifteen years ago, a certain school district, I can't recall which, considered banning the Bible because of its sexual explicitness.

So, after two weeks of consideration, I decided it is pointless to upgrade to 64 bit Vista. The myth was you should not run 64 bit Vista because it requires all drivers to be signed. There is a registry flag to set, which would allow the installation of unsigned drivers.

I went to Microsoft upgrade web site whose previous pages boast they could ship us the 64 bit Vista DVD for our current product keys, where I keyed in my Vista product keys, one for a Toshiba laptop and the other for Gateway. The web site responded that those are OEM keys and I should contact the respective OEMs. Okay.

I called Toshiba and they said it's your fault for not specifying 64 bit Vista when you bought the laptop. Now you have to purchase a new licence with a DVD that has both 32 and 64 bit installations and perhaps sell your current licence (I presume to some uninformed/unsuspecting buyer). I told them, to no avail of any sympathy, that I believe my licence is valid for 64 bit installations too - so just sell me the (danged) 64 bit DVD without a new licence, just as Microsoft would.

Should I call Gateway if they have a similar response? Would an American company have better response than a Japanese one? Toshiba, as a Japanese company, is surprisingly actually more disappointing than Gateway in my previous experience. I had an acquaintance who was rather frustrated and smashed his Vaio to the wall because Sony wanted him to ship it all the way to Singapore for repairs. Do you know that Singapore is diametrically the other side of the planet from Boston? A little bit less, give or take.

Hitch Hiking to 64 bit

I am regretting that when I purchased this 64 bit dual core machine two and a half years ago, I did not specify 64 bit Vista. A 32 bit system is constrained arithmetically to an address space of 232 = 4 294 967 295, which we geekily call 4GB (4000 MB). That is, both the virtual memory of a process and the real memory of my 64 bit system is limited by its 32 bit OS to addressing on 4GB.

Of that 4GB, Windows architecture limits us to using only half of the max virtual memory for our processes, reserving the other 2GB for kernel virtual space. That is not a problem really, because the max size of any one of my processes (due to Eclipse or Netbeans) is only 1GB. The real problem is the RAM available for use, which brings us back to reminisce on the 640KB limit on a 1MB address space. IBM and Microsoft was using the upper memory space for device addresses.

I should remember the exciting IBM PC days when I was still writing Cobol and C on IBM mainframes and DEC miniframes. Those days, 45 MIPS by IBM's newly released Sierras were considered such a breakthrough.

So, a normal off-the-shelf non-server non-specialty 32 bit Vista is actually limited by Microsoft to using 3.12 GB RAM? That makes it really difficult for me as my superficially multitasking habit of normally having two Eclipse instances, a Chrome browser full of tabs of javadocs, a Firefox window to GMail and my various blogs, plus an IE window to my various Google Apps accounts. In addition, I normally switch between doing Java and C#, and so I have to turn on Visual Studio. But I cannot close my Eclipse windows or the browsers displaying the Javadocs because they are a cursor for me to quickly switch back to Java when I'd had enough of .NET.

Moreover, unlike Eclipse or Netbeans, A Visual Studio instance does not allow more than one solution open. I need to refer to my previous solutions,and therefore, I would need to open another two instances of Visual Studio. And then I need to open another set of browser tabs and this time Safari to search for C#/C++ answers and then I would be able to find a few .NET solutions for which I would have to yet open another Visual Studio instance to try them. And worse of all, the Visual Studio help browser is more clunky than the IDE itself and of course, I need the help browser open too.

Then recently, I had been trying out some animation software like Alice and a couple others. To run Alice or JavaFx, I needed to close all my other windows.

In short, I need lots of windows and processes running to function efficiently. Eclipse and Netbeans simply struggled along so I started having only one Eclipse instance without Visual Studio, vice versa. Closing windows is slowing me down not just because of the process startup latency of the system, but my mental switchover latency because I cannot remember which Javadoc page I had been on and which pile of Java classes I was working on.

I even go as far as terminating the processes due to the icons on the taskbar. All those little icons are slowing me down. Google Desktop and Taskbar is slowing me down. The evidence is, those little icons on the taskbar adds in a delay by holding my keyboard and mouse at ransom for three minutes everytime I reboot the system.

Why do I allow those icons to be installed in the first place? What a good question. Adobe insists on doing it, otherwise I won't have access to Flash and PDF. No Flash, no Youtube, which is unacceptable. Open Office insists on doing it. Real player insists on doing it. MSN Live insists on it, etc, etc. So I would use Windows Defender to disable those icons and associated services. But, for some reasons, Windows Defender greys out the disable button for some of these taskbar icons. I am itching to know how much those companies pay Microsoft to disable the disable button for their parasitic taskbar iconised background noise from being disabled through Windows Defender. Okay, I won't be defeated by these parasitic icons. I search the Windows Registry for them or disable their services through the Control Panel.

This is wasting my time. I need a solution to better my situation. I am going 64 bit.

Saturday, August 22, 2009

Using memcache for Session Beans in GAE

Continued from Why Use JSP for GWT RPC Server-side Service


Note: the statement "JSP session beans are not supported in GAE" is outdated. Nonetheless, the examples on using memcache still holds. Session beans can be enabled in the appengine-web.xml:

<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app
  xmlns="http://appengine.google.com/ns/1.0">
  <application>syntercourse</application>
  <version>1</version>
  <sessions-enabled>true</sessions-enabled>
  <precompilation-enabled>true</precompilation-enabled>
</appengine-web-app>

[outdate info]
JSP session beans are not supported in GAE. The jsp:usebean tag has no effect of value in a JSP running in GAE. As session control is not implemented in GAE, we would need to exploit persistence features of GAE to implement it. A strategy would need to be employed to put and get session beans. The tactic described here uses memcache, which is implemented by GAE as standard Java caching API (import javax.cache.*).
[/oudated info]

GAE memcache is not actually session cache by itself because the stored blobs do not actually expire. We have to deliberately set an expiry time.

SessionSilo, below, can be used as a template for implementing session persistence of beans. Please refer to synthful project in Google Code for its complete source code. Here is the outline of the strategy.
  1. At start of session initialise persistence cache.
  2. Set an expiry time for the cache.
  3. At the first JSP response within a session, declare the bean.
  4. At every start of JSP response, get the session bean from persistence cache.
  5. At end of JSP response, if the bean had updates, put the bean into persistence cache, overwriting its old blob stored in the cache.

package com.blessedgeek.gwt.gdata.server;

....
public class SessionSilo
{
  ....

/** * Create new instance of static cache, beanCache. * GAE memcache is configurable thro certain reserved keys. * A reserved key and its value can be injected into the * cache thro a hashmap. * If a config hashmap is not injected into the cache, * the cache would take on default values. * */ static public void initBeanCache(){ if (beanCache!=null) return; Map cfgMap = new HashMap(); cfgMap.put(GCacheFactory.EXPIRATION_DELTA, 900); try{ CacheFactory cacheFactory = CacheManager.getInstance().getCacheFactory(); beanCache = cacheFactory.createCache(cfgMap); } catch (CacheException e){} }
/** * Call this at start of a JSP to get the session bean * If bean does not exist, create and put it in the cache. */ static public MrBean initSessionBean(String sessId){ MrBean mrBean = getBean(sessId); if (mrBean==null){ mrBean = new MrBean(); mrBean.sessionId = sessId; putBean(sessId, mrBean); } return mrBean; }
/** * Call this at the end of a JSP. * If any routine updates the bean, * those routines would need to set updated flag to true. * If updated is true, then put the bean back into cache * to over-write its existing blob in the cache. * * @param mrBean */ static public void storeSessionBean(MrBean mrBean){ if(mrBean.isUpdated()) putBean(mrBean.sessionId, mrBean); }
static Cache beanCache; }

Example of JSP using SessionSilo static methods to store and get "session" beans.
<%@
page language="java"
extends="com.blessedgeek.gwt.gdata.server.TableMgrServiceImplJspBeanable"
....
%><%
MrBean mrBean = SessionSilo.initSessionBean(session.getId());
%>

....
<%
SessionSilo.storeSessionBean(mrBean);
%>

In the TableMgr application, TableActionService.gwtrpc.jsp employs this technique.

Its subsidiary JSPs conditionally called-by-include also have to employ these series of manoeuvres because GAE does not pass bean instances across an include call: Listxxx.jsp, Loggedin.jsp.

Remember that a bean being cached must implement the java.util.serializable interface. Every member class of the bean as well as the whole depth of recursive members must also implement serializable. Otherwise, GAE will dump the response due to encountering non-serializable exception when attempting to put the bean into memcache.

If a bean has many members, it may be better to cache individual members of the bean. Why should a whole cached blob be replaced if only one tiny bit was changed for each response? Caching individual members of a bean also allows a bean to have non-serializable members that do not need persistence.

You should also read
http://code.google.com/appengine/docs/java/memcache/usingjcache.html.

Why Use JSP for GWT RPC Server-side Service

Continued from GWT RPC - How Server-side JSP Service Works


Because, you can produce json response this way.

<%@ page
contentType="text/html; charset=utf-8"
language="java"
extends="com.blessedgeek.gwt.gdata.server.TableMgrJspBeanable"
....
%>
<%
MrBean mrBean = SessionSilo.initSessionBean(session.getId());
TableEntry entry = mrBean.getTableEntry();
Data data = entry.getData();
%>{
 "id":"<%=entry.getId()%>",
 "title":"<%=entry.getTitle().getPlainText()%>",
 "summary":"<%=entry.getSummary().getPlainText()%>",
 "worksheet":"<%=entry.getWorksheet().getName()%>",
 "header":"<%=entry.getHeader().getRow()%>",
 "insertionMode":"<%=data.getInsertionMode().name()%>",
 "startRow":"<%=data.getStartIndex()%>",
 "numRows":"<%=data.getNumberOfRows()%>",
 "columns":"<%
 int i=0;
 for (Column col : data.getColumns())
 {
  %><%=i>0?";":""%><%=col.getIndex()%>:<%=col.getName()%><%
  i++;
 }%>"
}

Because, that is why programmers prefer to use PHP, Perl or Scala to produce dynamic web pages rather than using a non-JSP servlet.

Because this is ugly and unfriendly, ugly to copy n'pasting (excerpted from http://code.google.com/p/javarunaround/source/browse/trunk/src/org/oosterveld/runaround/Display.java):
if (user != null){
  if (user.is_facebook_user()){
    html += "<div id=\"header-profilepic\">";
    html += user.getProfilePic(true);
    html += "</div>\n";
  }

  html += "<div id=\"header-account\">";
  html += "<b>Welcome, " + user.getName() + "</b>";
  html += "<div class=\"account_links\">";
  html += "<a href=\"account.jsp\">Account Settings</a> | ";
  
  if (user.is_facebook_user()){
    html += "<a href=\"#\" onclick=\"FB.Connect.logout(
    function()
    {
      refresh_page();
    }
    )\">" +
    "Logout of Facebook" +
    //.'<img src="images/fbconnect_logout.png">'
    "</a>";
  }
  else{
    html += "<a href=\"logout.jsp\">Logout</a>";
  }
  html += "<br /></div>";
  html += "</div>\n";
}
else{
  html += "<div class=\"account\">";
  html += "Hello Guest | ";
  html += "<a href=\"./register.jsp\">Register for an account</a>";
  html += "</div>\n";
}

html += "</div></div>\n"; // header & header_content
html += "<div class=\"body_content\">\n";


Because, you can use my text custom tag (http://h2g2java.blessedgeek.com/2009/07/jsp-text-custom-tag.html) to subject large blocks of unbroken text to conditional output.


Continue next Using memcache for Session Beans in GAE

GWT RPC - How Server-side JSP Service Works

Continued from Passing Parameters in GWT RPC (Server-side)


Remember that the name of any JSP that is registered as a GWT RPC service responder must end with suffix ".gwtrpc.jsp".

Here's the reason why.

A JSP is first translated into a Java source file with a _jspService method, which always begins with this block of code
public void _jspService(
HttpServletRequest request,
HttpServletResponse response)
throws java.io.IOException, ServletException {

JspFactory _jspxFactory = null;
  PageContext pageContext = null;
  HttpSession session = null;
  ServletContext application = null;
  ServletConfig config = null;
  JspWriter out = null;
  Object page = this;
  JspWriter _jspx_out = null;
  PageContext _jspx_page_context = null;

  try {
    _jspxFactory = JspFactory.getDefaultFactory();
    response.setContentType("text/html");
    pageContext =
    _jspxFactory.getPageContext(
    this, request, response,
    null, true, 8192, true);
    _jspx_page_context = pageContext;
    application = pageContext.getServletContext();
    config = pageContext.getServletConfig();
    session = pageContext.getSession();
    out = pageContext.getOut();
    _jspx_out = out;

    ....

However, the RemoteServiceServlet class, which a GWT RPC service responder servlet should extend (in order to exploit the convenience of data serialization afforded by implementng GWT RPC interfaces), uses its own output stream and ignores/discards the response output stream. That is, the JspWriter out stream is ignored/discarded. Which causes the output of a JSP extending RemoteServiceServlet to be blank, because all the content rendering of a JSP is translated into lines of ignored output stream

out.write( .... );

Therefore, we need a way to exploit the out.write lines generated by the JSP translator, by diverting out back to the response body. So we create a class JspResponseWriter, which extends JspWriter, to over-ride the write method, so that it writes to the response body.
package org.synthful.gwt.http.servlet.server;
....
public class JspResponseWriter
 extends JspWriter
{
  ....



@Override public void write(char[] cbuf, int off, int len) throws IOException{ for (int i=off; i<off+len; i++) this.Body.append(cbuf[i]); }
.... }

Alright, now we the mice have the bell, we only need find a ribbon to tie it to the neck of the pussycat. Even with a ribbon, we still need to sneak up to the cat tie the ribbon with the bell around the cat.

Okay, notice in the translated JSP Java source is the line

out = pageContext.getOut();

So we create an extension of PageContext whose getOut method would sneak our version of JspWriter to the out variable.

And, the plot thickens. Now, we have to find a way to sneak our version of PageContext into the conspiracy to defraud Google's blindfolding of the JSP out prisoner.

Notice the translated Java source has a line
pageContext = _jspxFactory.getPageContext(....);

And your premonition is correct - we have to send in a double-agent to sneak our impersonator of the JspFactory, who would help us sneak our version of PageContext into the belly of RemoteServiceServlet.

So, here's the double-agent, JspServiceBeanable, who would undertake this mission. Notice the line JspFactory.setDefaultFactory( .... ), which is how our agent sneaks our version of JspFactory, which would sneak our version of PageContext, which would sneak our version of JspWriter, which would sneak GWT server-side prisoner, the JSP rendering output, back to the response body where it rightly belongs:
package org.synthful.gwt.http.servlet.server;
...
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

abstract public class JspServiceBeanable
  extends RemoteServiceServlet
  implements HttpJspPage
{
....

protected String doJspService( HashMap<String, String> parameters){ this.parameters = new Hashtable<String, String>(parameters); JspFactory.setDefaultFactory(new JspFactoryShunt()); this.jspFactory = JspFactory.getDefaultFactory(); try{ this._jspService( this.getThreadLocalRequest(), this.getThreadLocalResponse()); } catch (Exception e){ e.printStackTrace(); } this.jspContext.popBody(); return this.jspOut.Body.toString(); }
public class JspFactoryShunt extends JspFactory { .... @Override public PageContext getPageContext( Servlet arg0, ServletRequest arg1, ServletResponse arg2, String arg3, boolean arg4, int arg5, boolean arg6) { Class cls = arg0.getClass(); this.shuntedPageContext = this.shuntedJspFactory.getPageContext( arg0, arg1, arg2, arg3, arg4, arg5, arg6); if (!cls.getName().contains("_gwtrpc_jsp")) return this.shuntedPageContext; jspContext = new PageContextShunt(this.shuntedPageContext); return jspContext; } .... }
public class PageContextShunt extends PageContext { public PageContextShunt(PageContext ctx) { this.shuntedPageContext = ctx; } .... }
}



But, but, but ...,
JspFactory.setDefaultFactory and
JspFactory.getDefaultFactory
are static methods, and affects the whole application, not just a request, so that our version of JspFactory is thrusted into the throats of even JSPs who are not involved in this conspiracy.

We need to a way for our JspFactory impersonator to differentiate between visitors and prisoners, between JSPs not part of the crime from JSPs intent on committing this fraud. Otherwise, the output of the non-complicit JSPs would not be processed as intended thro the normal response out stream.

That is where the suffix, .gwtrpc.jsp comes in. Notice the code in the JspFactoryShunt, which returns the original shunted PageContext for JSPs whose names are without .gwtrpc.jsp.

if (!cls.getName().contains("_gwtrpc_jsp"))
  return this.shuntedPageContext;




Continue next Why Use JSP for GWT RPC Server-side Service

Tuesday, August 11, 2009

Passing Parameters in GWT RPC (Server-side)

Continued from Passing Parameters in GWT RPC (Client-side)


The server-side code
The server-side servlet must extend RemoteServiceServlet, remember?
However, to allow a JSP to be the servlet servicing the RPC request, the JSP must implement the HttpJspPage interface. JspServiceBeanable, which does that, is an abstract class (provided by the courtesy of this author) to be extended by a JSP.

package org.synthful.gwt.http.servlet.server;
...
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

abstract public class JspServiceBeanable
extends RemoteServiceServlet
implements HttpJspPage
{
 ....



protected String doJspService( HashMap<String, String> parameters) { this.parameters = new Hashtable<String, String>(parameters); JspFactory.setDefaultFactory(new JspFactoryShunt()); this.jspFactory = JspFactory.getDefaultFactory(); try{ this._jspService( this.getThreadLocalRequest(), this.getThreadLocalResponse()); } catch (Exception e){ e.printStackTrace(); } this.jspContext.popBody(); return this.jspOut.Body.toString(); }
.... }


But, wait another minute. Shouldn't it also implement HashedParameterService in order to recognise the HashMap datatype being passed by the RPC requester?

Wokay dokay, here's JspServiceParametricBeanable, the abstract class to be extended by any JSP with ambitions to service an RPC request that comes with a HashMap argument. It over-rides the empty doServiceResponse method in GWT-supplied RemoteServiceServlet so that instead of ignoring the response output, it diverts RemoteServiceServlet to perform doJspService mandated by HttpJspPage interface.

package org.synthful.gwt.http.servlet.server;
import java.util.HashMap;
abstract public class JspServiceParametricBeanable
extends JspServiceBeanable
{
 public String doServiceResponse(
  HashMap<String, String> parameters){
  return this.doJspService(parameters);
 }
}


Oopsie doops, wait one more final minute. Shouldn't the JSP implement TableMgrService which the application-specific client-side in the previous page has required to define the target URL? So here's the actual abstract class to be implemented by the RPC service JSP.
package com.blessedgeek.gwt.gdata.server;
import
org.synthful.gwt.http.servlet.server.
JspServiceParametricBeanable;
import com.blessedgeek.gwt.gdata.client.TableMgrService;

abstract public class TableMgrServiceImplJspBeanable
 extends JspServiceParametricBeanable
 implements TableMgrService{}



So here's the header for TableActionService.gwtrpt.jsp as targeted by TableMgrService interface. Notice that it extends TableMgrServiceImplJspBeanable.


<%@ page
language="java"
extends="com.blessedgeek.gwt.gdata.server.
TableMgrServiceImplJspBeanable"

import="
com.blessedgeek.gwt.gdata.client.TableMgr,
com.blessedgeek.gwt.gdata.server.MrBean,
....
com.google.gdata.data.spreadsheet.Column,
com.google.gdata.data.spreadsheet.Field"%>


When using JspServiceBeanable as the means to allow JSPs to be used as GWT RPC service responders, the servicing JSP name must end with ".gwtrpc.jsp". JspServiceBeanable detects that a JSP is a GWT RPC service responder by detecting if its name ends of ".gwtrpc.jsp".


Continue next GWT RPC - How Server-side JSP Service Works

Passing Parameters in GWT RPC (Client-side)

Continued from GWT RPC


The GWT RPC tutorials provide the simple case of passing and receiving String objects. However, in most, if not all, practical cases, programmers need to pass a set of parameter-value pairs between HTTP communicants. In this case, between communicants of the communion of RPC over HTTP.

TableMgr bears in itself an example how to pass parameters over the RPC/GWT/HTTP (RPC over GWT over HTTP) communion.

For TableMgr source code, refer to
http://code.google.com/p/synthfuljava/source/browse/#svn/apps/GData Table Manager,

and for the library elements it uses, refer to
http://code.google.com/p/synthfuljava/source/browse/#svn/trunk.

Do not copy code from this page, as it would contain line-breaks and exclude lines left out for brevity that would break the code, but get them drectly from the google code project listed above.

TableMgr uses a HashMap as the datatype being passed. A HashMap is the best choice because it allows values to be mapped to parameter keys.


GWT client-side code
package org.synthful.gwt.http.servlet.client;
import java.util.HashMap;
import com.google.gwt.user.client.rpc.RemoteService;

public interface HashedParameterService
extends RemoteService
{
 String doServiceResponse(
  HashMap<String, String> input);
}

The interface HashedParameterService is a generic service declaration interface (provided by the courtesy of this author) which anyone could use, but if you use it with GWT-provided server side RemoteServiceServlet, your servlet would need to provide the method

String doServiceResponse(
 HashMap<String, String> input);


GWT applications in accessory to using this framework is restricted to having this method as the RPC procedure being called.

Or, you could copy it and rename the method to a name of your liking. However, my intention for it was not to provide a generic service declaration interface, but for a more sinister intention. It is to subvert the RemoteServiceServlet provided by GWT so that I could have JSPs, rather than plain servlets, implement it to service RPC requests. This would be explained later in the server-side part.

Wait a minute, shouldn't the service declaration interface contain the RemoteServiceRelativePath directive to tell the GWT compiler the URL that would service its RPC request? Therefore, to keep this interface generic, we introduce an extra layer of interface.
package com.blessedgeek.gwt.gdata.client;
import
org.synthful.gwt.http.servlet.client.HashedParameterService;
import
com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
@RemoteServiceRelativePath("TableActionService.gwtrpc.jsp")
public interface TableMgrService
 extends HashedParameterService
{}


TableMgrService would be the actual interface implemented by the RPC client, but the server side would still implement its super-interface HashedParameterService. The corresponding client and server sides do not actually have to implement the same interface but interfaces of the same signature.

The companion async-response request interface to that is

package org.synthful.gwt.http.servlet.client;
import java.util.HashMap;
import com.google.gwt.user.client.rpc.AsyncCallback;

/*
* @gwt.TypeArgs parameters <java.util.HashMap 
<java.lang.String,java.lang.String>>
*/
public interface HashedParameterServiceAsync
{
 void doServiceResponse(
  HashMap<String, String> parameters,
 AsyncCallback<String> callback);
}


Note that both of them declares the same HashMap<String, String> parameters argument.


Continue next Passing Parameters in GWT RPC (Server-side)

Monday, August 10, 2009

GWT RPC

Continued from TableMgr - List Spreadsheets


GWT is an ingenious way of allowing browser behaviour to be coded in Java source code, which the GWT compiler then compiles into Javascript.

GWT could allow the programmer to escape from Java into writing Javascript using the Java native method declaration. As far as GWT is concerned, Javascript is the native code of the browser - even though to the operating system, that is far from the truth.

Bear in mind not to confuse the Java source code for the browser with the Java source code running on the web application server. The Java source code for the browser is compiled into Javascript, whereas the Java source code on the server is compiled into Java bytecode. Of course, the server code need not be coded in Java, as long as it provides the GET-able URLs that a GWT client page requests.

RPC over HTTP
GWT RPC allows a page to request for content from its server using the established HTTP channel. The GWT Java source (before compilation to Javascript) mimics a remote procedure call. However, the RPC is actually translated into normal HTTP requests/responses. Perhaps, just as many protocols ride on HTTP, we could call this RPC over HTTP. XYZ over HTTP is a common strategy programmers use to allow information to mimic web pages, to circumvent restrictions placed by internet traffic policing devices on non-HTTP communication.

Second Level Domain Same Origin Policy (SLD-SOP)
Bear in mind that the standard browser restricts its pages to only be able to request for, and to include, content from within the same second-level domain (SLD) as the server that provided that page to the browser. Top level domains (and top-level and a half) are such as .com, .org, .net, .me.us or .co.uk. So, domain names such as google.com, fbi.gov, mit.edu are second level domains. While, mail.google.com would be a third-level domain. Therefore, GWT RPC would work only within the confines of an SLD.

Note that SLD-SOP also requires the port number to be the same, such that jan.synthful.com:9100 is not on the same SLD as jan.synthful.com:9101. A particular browser brand may be lax and allows different port numbers within the same SLD consideration, but that would not be compliant to standard SLD restrictions.

GWT client-side code
The Java source of the GWT client intending to conduct RPC with its server must provide its own service declaration interface,
  • which has a @RemoteServiceRelativePath directive to tell the GWT compiler the URL that would service its RPC request.
  • which declares the remote service method to tell the GWT RPC class the datatype of the request argument and the expected return datatype. Surely, you need to pass arguments when you call a procedure and expect an object to to be returned. The datatype of the argument and the return signature and all their recursive members must implement the serializable interface (of course, or expect a nonserializable run-time error when the RPC process attempts to serialize those data).
  • where the remote service method is to be invoked on the client-side GWT code to trigger the RPC.
  • where the name of remote service method corresponds to the name of the remote method/procedure that GWT RPC would pass to the server to invoke to service this call.
  • which must implement the com.google.gwt.user.client.rpc.RemoteService interface, which is an empty, marker interface.
The service declaration interface is a bridging interface between the client and the server as it is used by both the client and server sides. It is to be implemented and invoked by the GWT class used for performing the RPC on the client side as well as implemented and invoked by the servicing servlet on the server side.

The GWT client source code must also provide an async-response request interface for the GWT compiler. This interface should declare a method with two arguments
  • the serializable datatype declared in the service declaration interface, to tell the GWT compiler constructing this whole setup the datatype of the request argument and the datatype of the object to be returned by the RPC service.
  • the call-back method of the client that would asynchronously handle the server response. The call-back method must implement the com.google.gwt.user.client.rpc.AsyncCallback interface.

The server-side code
The URL on the server-side targeted by the GWT RPC client must, of course, be able to recognise the request parameters. How else would it be best but for the servlet to implement service declaration interface provided by the client. For a server that implements JEE standards - that is obvious. However, if the responder on the server is not written in Java - it would have to mimic the serialization of Java datatype declared in that interface. Since this is not a hitch hiker's guide to PHP, Python or Perl, etc, non-JEE responders are beyond the scope of discussion.

Remember that the service declaration interface defined the remote service method which your server is "supposed to" use to service the RPC request. You could write your own RPC request handler servlet by ignoring the service declaration interface as well as the remote service method name it declares but service the request any old how. Your handler servlet would still need to deserialize the RPC request parameters.

If you are coding server-side in Java, GWT provides the server-side request handler as well, RemoteServiceServlet, to
  • call the method as requested by the GWT client. The method must implement service declaration interface which you have declared for the client.
  • deserialize the data, that came with the request, back into a Java object, and pass the object to the requested method.
  • serialize the return type of the method to be sent back to the GWT client.
Which is a lot of work not to write your server side in Java.

Naturally, your handler servlet would need to be mapped to the URL on which the GWT client has sent a GET request, as registered in the @RemoteServiceRelativePath directive of service declaration interface.

To use the GWT framework, your servlet needs to extend com.google.gwt.user.server.rpc.RemoteServiceServlet.


Continue next Passing Parameters in GWT RPC (Client-side)

Wednesday, August 5, 2009

TableMgr - List Spreadsheets

Continued from Cuckooberra Login Process

The following diagram illustrates the List Worksheets action which would exemplify the rest of the information flow between browser, Cuckooberra GAE server and Google Docs GDATA service.




Continue next GWT RPC

Tuesday, August 4, 2009

Cuckooberra Login Process

Continued from TableMgr: GAE + GWT + GDATA with RPC

The following diagram documents the log-in procedure.

A one-time-use authorisation token is dispensed by Google accounts when you log in. This one-time-use token is then exchanged for a session token. When you log out of Cuckooberra, the session token is revoked. Remember that the session token actually never expires. So if you logged in to try Cuckooberra, and any interruption occurs preventing you from loggin out, there is a revoke token link at the left bottom of the page which you should click to revoke the token. Cuckooberra does not memorise the token beyond the browser session, so it would not be able to remember what token you used if you return to use it after the interruption to your browser session.

Note: "Redirect to Google Accounts" in Login.jsp is not really a HTTP redirect but a Javascript "location.replace()".




Continue next TableMgr - List Spreadsheets

TableMgr: GAE + GWT + GDATA with RPC

TableMgr is a web application hosted on Google App Engine. It is actually a port of Google's spreadsheet and table GDATA examples from being a console application to running as a GAE/GWT application.

http://cuckooberra.blessed-are-the-geek.com/.

Therefore, it is a combination of Google App Engine, Google Web Toolkit and Google Spreadsheet access through GDATA service.

It also makes use of GWT RPC to avoid the need for page refresh. I also extended the Http servlet framework that GWT RPC service uses so that I could use JSPs to respond to RPC service requests.

The code is found here:
http://code.google.com/p/synthfuljava/source/browse/#svn/apps/GData%20Table%20Manager

The library elements it uses are found among here:
http://code.google.com/p/synthfuljava/source/browse/#svn/trunk

TableMgr resides within the GAE application ID Cuckooberra. The following page documents the Cuckooberra log-in process.


Continue to Cuckooberra Login Process

Sunday, August 2, 2009

Why I love to scrum 2

Continuing from my last blog about misplaced agile efforts, I should write, for the record, that I had always enjoyed agile and scrumming process for my other jobs.

Agile development and scrumming practices are useful only when they are not constrained by formalised theories.

I used to work with a cross-location, cross-department project team which had broad support from the departments that were directly involved in making the company profitable. It is great to work for a team supported by a user-base who have the financial authority and direct motivation to make the company profitable. They don't care about information management theories or violation of theories people had learnt from MBA or MISc degrees. They just want to make sure you are helping them make money for the company. I like working for such clients. They don't have the luxury for adhering to information management theories and most of all, they have the authority and discipline to over-ride those who do.

We scrummed by email, Solaris talk and telephone and sometimes video-conf. We only got those who had the problems and solutions involved. We were careful not to waste anybody's time. We made regular enhancements and releases. We had two weeks of beta for every release in which advanced users would test the new releases. We had an effective release roll-back procedure. It was a rather large multi-national and so we had to manage with different sites having different releases. There was a corporate project manager who did his job effectively. We had fluid project milestones and a queue of feature requests and a feature priority system. The feature prioritisation process coincided with what we would today call the scrum of scrums.

Now and then, some of my Information Department colleagues would berate my team as moving targets illegitimately existing on the absence of formal procedures and that our team simply survived only because we had the profits generating people behind us.

Hello? Only because we had the money generating people behind us? Why would the money generating people be behind us, in the first place?

Ok, since we were a large multinational, we tend to have more than one solution. A competing team decided to steal me away from my first team and the relocaton benefits were wonderful. I succumbed to the offer. It was another great team.

We scrummed as often as we needed resolutions. It was more like extreme engineering.

Once, a team member noticed a persistent spike in the development Sybase server that lasted for more than ten minutes. Two members of the team traced the source to a piece of code with cross-product query. A quick scrum was called and a raise of hands was made to find out who else was writing cross-products. Immediately, we had a microproject of excising all cross-product queries from our our application. We traced all the code to one single culprit who was a contractor. I just don't understand, none of the other team members did, why would he persist in writing cross-product queries after the team had decided to ban it. Doesn't he understand what 2.5 normalisation means? We were not in the business of sticking to normalisation perfection but to ensure our application ran as fast as possible. OK, we decided not to renew his contract because he kept citing importance of normalisation theory over performance.

We had a colleague, who was not in the team, who had decided that we lacked formal discipline and decided to help us rectify that shortcoming. He wrote a Delphi application that would help us track our activities to the time spent on each module of the application to help us justify if a module was worth the effort. All we had to do was, keep his application up all the time and key in whenever we started or stopped our work on each respective module. He shared it with the division head who thought it was a great idea. It was a riot because most of us (unlike he) were multi-taskers. The project manager managed to persuade our division head that it was a bad idea, fortunately. Our colleague was extremely disappointed because we had caused his efforts to be wasted. We were using AIX workstations and he thought all we needed was the simple case of running the PC emulation window to keep his application alive. OK, he thinks we have the CPU power to spare for a PC emulation window. I had only used the PC emulation window at the end of the day to play computer pong.

I just don't understand why now and then, there are colleagues who work jealously against an agile development team.

My next pleasant experience with agile development was in Colorado as a 1099 contractor. My client and I formed an extreme programming team. It was like playing ping-pong with him, sitting in the same cubicle. He was a software product manager with no one reporting to him, except a couple of contractors like me. Moreover, the view of the Rockies were great. Once, he drove me to South Park and declared that I was in an historic town. At that time, I had not realised that South Park, Colorado was the raison d'etre for the South Park cartoon. Until he told me. I mean, how could evangelical Colorado be the origins of such an irreverent cartoon show?

Then, I decided to return to the east coast, to the dismay of my Colorado client where I worked for a privately held company. It was a wonderful development environment. My management measured me by the level of happiness of my clients. They reminded me that I was there to provide statistical solutions and warned that it was a fluid environment. Finally an IS department that understands what profitable means. I am sure, being a small company makes profit-consciousness a top priority for the IS director. What a pleasant surprise. I had great reviews. When I had to live in a neighbouring state for personal reasons, they sought to retain me to accommodate my need of having to drive 6o miles to work until I found another job.

Saturday, August 1, 2009

Why I love to scrum

Before, scrumming and agile development approach was formalised with the technical terms "Agile Engineering", my colleagues and I were already practising it.

We had regular scrumming sessions over Solaris talk and telephone conference as well as face to face informal meetings. As agile development adage goes, we made application changes precise, frequent and quick, so that users could enjoy the fruits of our modifications as soon as possible. At every release we had two weeks of beta for willing users who wanted to use the latest and greatest or for users who themselves urgently required a feature they had suggested because a disastrous process misbehaviour had slipped through their fingers which the new statistical analysis features would catch.

The management of the users were very supportive and their mandate was make my engineers, planners and designers happy. That was since twenty years ago. Yes, I have been practising scrumming and agile development for twenty years with my colleagues but we never knew that one day what we were practising would be formalised into terminologies called scrumming, extreme engineering and agile development.

In one of my former place of employment, since I normally reported to the Information Systems department, I had a problem. My administrative management would inform me that the project goals and targets that I had agreed with my manager were seldom satisfied. So, came the annual goal and target setting week.

What are my project goals and targets for this coming year, I would be asked. I would sit quiet, pondering how to transform my tasks into projects and milestones that would be acceptable to my manager. Finally, I would confess, I really don't know. What? My goal is to ensure that the users of my statistical analysis applications are happy with my work. That is not a valid goal, I would be told. OK, I proposed, how about goals like these,
  • reduce average turnaround times of tasks from two weeks to ten days
  • reduce number of misinterpreted customer requests from five to one.

Those are not project goals.

But, but, but, my clients' goals and targets keep changing. I don't know what they want next. They seldom know what they want next.

You must force your customers to accept the way the Information Department works. We have solid projects not moving targets. We should have customer contracts which we would fulfill and which the client department needs to justify through their department managers why those targets and goals need to change. You are working for the Information Department, remember? Not for Engineering, Planning, Manufacturing or Design. You must force your departmental clients to understand how information management works. If you fail to make your clients understand and comply to that, we are sorry to tell you that you have no skills in managing your customers.

OK.

But my departmental clients are in the business of making their customers happy. Moreover, I together with every employee, have been compelled by the corporate quality compliance authorities to pledge through various fanciful sloganeering that we would work our best to keep our corporation profitable by helping our colleagues ensure our external customers are satisfied.

So, why can't I have a set of stable immutable projects? That is because, I work for a corporation which has processes. Both procedural and chemical processes that need to be managed. New products and processes are constantly developed. My departmental clients cannot wait for a process to stabilise into immutable states because if we do not solve issues as soon as they arise, our external customers would take their contract elsewhere. It's a fast changing business. We have to constantly stabilise those processes by constantly discovering requirements for information that we never expected we needed last week. Therefore, my targets keep changing and therefore I cannot have long term project milestones. My milestones are one week as soon as a new issue crops up and I would need to scrum with Engineering, Manufacturing, Planning and Design to remove bottlenecks and roadblocks towards the goals of making our external customers happy.

Then after a while, my psychotic management would decide - so we need to justify your existence because they have just graduated with MBA degrees where they learnt that we need measurable benefits in what we do. If we cannot measure, we are probably doing the wrong thing.

OK, why don't you get your departmental customers tell you how much money they saved for every microproject they make you perform? We have an activity-based costing framework and we need to distribute the cost of employing you to various product lines and the cost saving differentials. So, I spent two days conjuring numbers with my clients, instead of helping them solve problems. After, just one round of cost justification exercise, my colleagues implied that I should either work on their problems or f*** off.

So, on the whole, sometimes information departments are really out of touch with their fellow colleagues on the nature of the business of the company they work for. They are so attached to their information theories and formalised information management theories that they seem to think that the whole world needs to tune their processes to be in line with computer science.

Then, one day, I started working for a company that prided itself with formalised scrumming practice.

Hey, fellow agile development enthusiasts, the day scrumming became formalised is the day of its demise. When I participate in a daily scrum, this is what I expect to happen. I want to present to my colleagues the roadblocks I am facing. Then I want to find out who has the expertise, authority or personnel connections to remove my roadblocks and I would like to find out if I am roadblock to my colleagues and what I can do about that and also if I am the solution to helping someone's roadblocks. And I expect everyone on the team to bear the same attitude. Then I expect that we humbly acknowledge we need to rearrange our fluid milestones and schedule which is subject to changes. Then I expect the product to be tested and then released to customers or customer interface who are willing to provide feedback to the product.

However, the department that I started to work for did not realise they had quite a few impediments to their successful implementation of agile development. Their daily scrum lasts an hour. People took turns to present an update of their tasks and justify their delays. And the scrum was presided over by the scrum-enthusiastic department head, no less. Alright, after those meetings, I would have to go through the actual scrumming by meeting informally with colleagues which is when I get my real scrum done.

So, the company was experiencing frequent customer returns. These are huge pieces of equipment not little tubes of IC chips. Or the service engineer would have to drive or fly a couple of thousand miles to see what the problem is with the equipment. The idea of agile engineering, I was reminded was to work on an issue, and don't try to solve the bigger picture and refrain from refactoring your code. But that advice works only after a while. With the frequency of customer returns, the only solutions was to clean up the code that I had inherited because patch after patch was making it difficult to trace problems.

The other problem was, customer interface personnel who worked with us refused to participate in scrums. In order to find out what the problem was, we needed to make changes and have her try it out. But she complained to the department head that she was confused by my frequently updating the behaviour of the application. Ok, she complains the customer is not able to use the equipment because of software problems. I am told that the formalised theory of agile development is not to make large changes. And without making large changes I cannot clean up the code. Without cleaning up the code, the patches upon patches made it impossible for me to predict if when released, would the equipment be returned. And to clean up the code I would need our gentle and lovely customer interface to understand that she would need to test them.

It is unfortunate when once useful and practical procedures are formalised into respectable MBA curriculum, they normally become the problem rather than solutions. People don't know when to deviate from the theory.

As for me, I just want to make my customers happy.

Wednesday, July 29, 2009

Teeth Whitener for 49 cts.

Rush, rush, rush. Don't forget to brush.

I read an online advertisement that says
Don't pay a fortune to whiten your teeth - the price is only $2.49 plus shipping.

I keep wondering why people never bother to use baking soda. The local store's self-branded box is simply 49 cts.

I used to brush my teeth with baking soda at night and tooth paste in the morning. The tooth paste is for the benefits of fluoride for my teeth. Then I started using fruit flavoured fluoridated mouth rinse to moist my tooth brush before dipping the brush into the baking soda.

I had kept up the practice a number of years and I guess people were noticing my teeth were whiter than the usual population's. Then one day, the dental nurse (they call them dental hygienists nowadays) finally succeeded in persuading me that my front tooth chipped when I was a kid should be mended.

So another technician from a dental consultant company had an appointment with me at the dental office. She brought with her a panel of enamel shades to attempt to match my teeth with the enamel shades they have. The consultant's technician had to choose the whitest shade they had. She said with a big smile, you have the whitest teeth in the population. It's the baking soda, I said.

I know, she said - she'd like to use it too but she did not like the taste or the grittiness.

I am a lazy teeth-brusher and it takes only 2 daily minutes of grit and baky taste to keep my teeth healthy.

You should use baking soda on your teeth before you go to sleep for the night or before any few hours when you would not be ingesting any food. Baking soda is pretty nonreactive so the brushing does not actually whiten your teeth. Baking soda does not corrode your teeth. Baking soda is insoluble in water but it needs to react with acid to whiten your teeth. And baking soda is a persistent sticker to surfaces because it takes quite a few wipes to clean a baking soda spill.

Which sets the perfect condition for using baking soda on your teeth before you go to sleep. The remnant sugars stuck between your teeth which brushing won't eliminate turns acidic (by some bacteriologic process, as we have all been told) while you sleep and the acid reacts with the stuck baking soda and voila! - that's your teeth whitener.

As I said, I used to brush my teeth with baking soda. Then one day, I got tired of the dentist reminding me my lack of discipline in flossing my teeth and that I brushed my teeth too much that my gum was receding.

I changed my habit. I stopped brushing my teeth. Actually, I do minimal brushing where flossing wouldn't reach. My dentist and his technicians were happy with the results. Reason being, I started flossing my teeth with baking soda using a toothbrush. I would press the baking soda embedded bristles between my teeth to floss them. I lied to my dentist and his technicians that my healthier gum was the result of their recommended disciplined flossing. They believed me. I hate flossing my teeth with dental floss strings - it's messy and at times bloody and mostly tedious.

At first, I went to the pharmacy section to look for hand held flossing equipment and finally decided that the good old long-bristled toothbrush was the most convenient and cheapest means of flossing my teeth. My last supply of toothbrush I bought for $10 for ten from the local Hispanic supermarket. There are still quite a lot of Hispanic food ingredients that I still cannot find in major supermarkets, not to mention cheap toothbrushes.

May be baking soda is bad for the dental health business, because on subsequent visits, there weren't much plaque for them to clean and I dropped my dental insurance altogether.

Now for the taste part, though I don't mind it. First you should try as I had - moist your tooth brush bristles with fruit flavoured fluoridated mouth rinse before dipping it into the baking soda. If not try the following.

I am planning to experiment mixing a little of my favourite fruit jams with the baking soda on the toothbrush. That would give an excellent taste while flossing my teeth and provide the necessary acid to react with the baking soda while I am asleep. Let's see, my favourites are blueberry, strawberry-raspberry, peanut butter with grape and strawberry, fruity Schnapps ...

You shouldn't brush your teeth. It's bad for the gums. You should use your toothbrush to massage and floss your teeth with baking soda. The massaging action spreads into the gum line without ruining your gums but yet prevents plaque from forming.

OK, Schnapps is not a jam and probably would not provide sufficient acid to react with the baking soda.

Tuesday, July 28, 2009

Cuckoo Berra quotes

Cuckoo Berra quotes
  1. We ain't sober till we're sober.
  2. I didn't write half the applications that I wrote.
  3. When you come to a fork(), wake it.
  4. What's the datetime()? Do you mean now()?
  5. Programming is 90% mental, the other half is philosophical.
  6. I want to thank you for making this application necessary.
  7. If you don't know what you're coding, you'll end up with something else.
  8. The application encountered the wrong error.
  9. Nobody visits that site anymore, it's too popular.
  10. Applications slow down quickly out there - on Vista.
  11. If users don't want to use the application, you can't stop them.
  12. He must have wrote that (software) before he died.
  13. If you can't copy the code, don't paste it.
  14. Think?! How the heck are you gonna think and code at the same time?
  15. There are two hours when I'm most productive, it's from nine to twelve in the morning.
  16. An integer isn't worth a char these days - on differences between c and java.
  17. You can code a lot by just typing.
  18. In design there is no difference between design and implementation, but in implementation there is.
  19. Have you seen my secs manuals? - when frantically searching through amazed female colleagues' cubicles for the $600 set of semiconductor equipment communications standard (secs) manuals.
  20. We should instead put some firm codes down and stop waltzing around that crappy matilda.
  21. Middle management sucks especially when they treat you like another set of routines to be executed.
  22. The difference between a virus and a trojan horse is a virus behaves like a virus and a trojan horse works like a trojan horse.
  23. We should all ban cell phones at work because their use is discouraging the use of blackberries.
  24. You know a project is going to be a failure when people spend time drumming up their achievements during scrumming sessions.
  25. Make no mistake, that the mistake we had made was a mistake indeed.
  26. Mission Accomplished is an attitude from people who have no idea what continuous improvement means.
  27. I am pro choice-buttons because I don't like the idea of a process aborting due to lack of options.
  28. The difference between arguments and parameters is that an argument is a functional parameter, whereas a parameter is a parametric argument.
  29. When there is too much logic involved, it can become illogical.
  30. Is this a bug or an undocumented feature?
  31. If I sat on the old gum tree, would you marry me?
  32. Tele-ban is terrorising your users by informing them their loss of privileges through the telephone.

Saturday, July 18, 2009

Referencing a Text JSP Custom Tag Defined in Another Page

You could define the contents of a Text tag in a page

RunFirst.jsp

<h2g2j:text id="sesquery" scope="session">
SELECT NAME, ADDRESS, JOBID
FROM EMPLOYEE E, JOBS J
WHERE E.EID = J.EID AND
E.STATE = '<%=state%>' AND
current_date - E.STARTDATE > <%=minExp%>
AND J.DESC = '<%=jobDesc%>'
</h2g2j:text>



You could then in other subsequent pages use that StringBuffered pool of text by referencing it:
RunNext.jsp

<h2g2j:text ref="sesquery" scope="session"/>


<%
jdbcConnection.submit(query);
%>



RunFirst.jsp must be run once before any other page that would reference the session buffered text "sesquery". The ref invocation is necessary as it is an instruction to search for the session attribute "sesquery", whose object would be hooked up with the page variable "sesquery" by the servlet container's session handler.

Therefore, if you have a few voluminous query texts that tend to be reused frequently across the pages throughout a session, you could have an initial JSP that loads those texts into session buffer once. Rather than redefining common blocks of texts at every JSP.

JSP Text Custom Tag

Which is the more proper (i.e. acceptable to Sun, now Oracle's new division)
  • JSP Text Custom Tag, or
  • Text JSP Custom Tag?
The source is at
http://code.google.com/p/synthfuljava/source/browse/#svn/trunk/jsp/org/synthful/jsp/tags/Text.

The TLD is at
http://code.google.com/p/synthfuljava/source/browse/#svn/trunk/jsp/org/resources/WEB-INF.

Anyway, this is a custom tag I wrote because during ancient times I programmed in Perl and when I moved to Java I had to do this Java

String query =
"SELECT NAME, ADDRESS, JOBID " +
"FROM EMPLOYEE E, JOBS J " +
"WHERE E.EID = J.EID AND" +
"E.STATE = '" + state + "' AND " +
"current_date - E.STARTDATE > " + minexp;


instead of, which Perl allows me,

query =
SELECT NAME, ADDRESS, JOBID
FROM EMPLOYEE E, JOBS J
WHERE E.EID = J.EID AND
E.STATE = \'$state\' AND
current_date - E.STARTDATE > $minexp
;



With the Text JSP Custom Tag, I have been doing this

<h2g2j:text id="query" scope="session">
SELECT NAME, ADDRESS, JOBID
FROM EMPLOYEE E, JOBS J
WHERE E.EID = J.EID AND
E.STATE = '<%=state%>' AND
current_date - E.STARTDATE > <%=minExp%>
</h2g2j:text>

  • The contents of the body of the tag is stored in a StringBuffer.
  • The ID="query" attribute associates the StringBuffer to Java variable "query".
  • Specifying the ID attribute clears the StringBuffer before storing the tag's contents into the StringBuffer.
  • Instead of using the ID attribute, the REF attribute should be used to invoke the tag identified by "query" without clearing the StringBuffer.

<h2g2j:text ref="query" scope="session"/>


There isn't actually much you could do reinvoking a text tag, unless you wish to append to the StringBuffer.


<h2g2j:text ref="query" scope="session">
AND J.DESC = '<%=jobDesc%>'
</h2g2j:text>



Which would be equivalent to doing

<h2g2j:text id="query" scope="session">
SELECT NAME, ADDRESS, JOBID
FROM EMPLOYEE E, JOBS J
WHERE E.EID = J.EID AND
E.STATE = '<%=state%>' AND
current_date - E.STARTDATE > <%=minExp%>
AND J.DESC = '<%=jobDesc%>'
</h2g2j:text>


Since the StringBuffer of the tag is associated with the java variable "query", you would invoke the StringBuffer with that variable:

<%
jdbcConnection.submit(query);
%>

Sunday, July 12, 2009

The Future of Personal Computing

Getting Personal
A professor from Rennsalaer Polytech (cannot recall who) once said,
The personal computer is getting too personal.

Meaning - personal computing devices (Macs included), despite all their networking features have so far been incapable of accommodating natural human mode communication and cooperation.

In the future, personal computers will be obsolete. Not because the practice and processes of computing would become obsolete but computing will be a minority requirement in the realms of machine-aided-human-activities. The near future devices will be capable of computing nonetheless but whose role involves millions of perfunctory activities and only one of which is computing.

The future is in the cloud.

A device can virtually create as many virtual CPUs as the number of tasks running on it require. Dynamically and spontaneously increasing or reducing the number of virtual machines running. Vice-versa, a virtual super-device can be created over the network, whose resources the participating devices could tap into. Devices could subscribe to clouds as we currently subscribe to Youtube, Wordpress or Tweeter - pulling in and out at will with no detriment to the subscription system.

Instead of a hard-wired super-environment, we subscribe to clouds. We will have evaporation and condensation of virtual machines and processes. That is the power and efficiency of authenticated subscription.

Before anyone spouts any anti-666 big-brother-is-watching-you tower-of-babel ridiculousness, you have to realise that cooperative activities is a requirement of human existence. There is nothing big-brother about the clouds. It's like walking into a wet market, getting noticed, getting your chores done and then walk out. Nowhere anything near 666 here (i.e., if you believe in such a thing as 666) . Do whatever you want. You don't have to visit the large cities. You don't have to live in the large cities. You could keep your machines to your own small village, subscribe among your own fellow-believers, to your own little communes and qibuts. There will be millions of clouds rather than one single tower of babel.

There will be clouds whose existence is to sanitize communication to help other clouds maintain privacy and confidentiality. Virtual clouds make multiplying a few fish into feeding five thousand possible.

Cloudification
At this moment, Google seems to be the party that is paying the most attention to the cloud. Oh no, the cloud is more than Amazon's web services or Zoho or Microsoft's miserable attempts at cloudifying themselves. And just like missing the internet boat, Microsoft will again miss the cloud because they are carrying a huge baggage that induce them to be unwilling to provide an operating system that is small and compact and that does not run Windows. Before it's too late, Microsoft needs to shift their attention away from .NET towards .CLOUD.

Have you been cloudified, yet?

Saturday, July 11, 2009

Google ChromeOS: My Wish List

Open letter to Google,
request for features of ChromeOS.

I am anticipating ChromeOS because I work mostly on the Web and on Java and therefore, I would like to throw out all the Vista baggage that is slogging down my PC. My whole professional life revolves around Google - Apps, Docs, GAE, Blogger, GData, Sites, etc.

I also write in .NET C# quite a lot but I can do that on another machine or another session of a dual boot. Perhaps, the advent of ChromeOS would make my .NET skills obsolete. I hope so.

  • I need ChromeOS to be dual-bootable between itself and Vista(or any future version of Windows). As I would need to share data between my Windows and ChromeOS sessions, I would need ChromeOS to recognise NTFS.

  • I want Google to provide me a convenient migration path from Windows to ChromeOS, so that for the initial 18 months I would be vacillating between Windows (or MacOS) and ChromeOS but thereafter, ChromeOS features should be so persuasive that I abandon Windows (or MacOS) altogether.

  • I have dual-core 64 bit Intel CPUs. Would ChromeOS be able to exploit 64 bit and give me an advantage over 32 bit machines? I hope so. Would it be able to exploit multi-CPUs? I hope so. Will it be able to exploit the power-saving variable speed of the CPUs? I hope so.

  • I use Eclipse or Netbeans. Mostly Eclipse. It must run Eclipse.

  • Of course, it would have to run the beloved Java Platform, and if it wouldn't, I would be so extremely dismayed and surprised.

  • Perhaps it could run Mono, just in case it comes in handy with .NET applications and I don't have to run off to another machine, but please, please, please, put Mono inclusion in the lowest priority because if I wanted to .NET, as I said earlier, I'll do it elsewhere. But it would not hurt if it runs Mono.

  • Should it run flash? I am sure it has to run flash because everything with a movie on the web runs on Flash, especially Youtube. And CNN, Yahoo, etc.

    As a programmer, I am hoping some other technology would be in advent to replace Flash because I find writing actionscripts really tedious and unreliable and barely debuggable. I use OpenLaszlo on Tomcat because I do not wish to afford the $10K Adobe enterprise Flash authoring system.

    JavaFX is an extreme disappointment because it runs on a JVM and therefore is about 9 or 10 times slower than Flash. Then, Silverlight runs only on .NET.

  • Perhaps, further down the milestones on the roadmap of ChromeOS, Google could come up with a JVM that violates the JVM specification by improving on the JVM virtual CPU a little bit, like their Android DVM, so that we could run JavaFX at the speed of Flash. Sun would be unhappy? Who cares about Sun? May be they should just use DVM without the Linux underneath.

    How about a multi-virtualCPU DVM, where two or more DVMs could run concurrently on the same task. A JVM/DVM is like a virtual CPU - so a multi-VMCPU VM. In fact, why don't you just base ChromeOS on your own version of DVM - where we could configure a system to create as many virtual DVMCPUs as desired and depending on loading, we could configure the system to spontaneously dynamically reduce or increase the number of DVMCPUs running on the system?

    Would Sun be unhappy? Perhaps, they would, but you don't have to talk to them now because they don't exist anymore. I have the impression that Oracle, a more business oriented and practical entity, would cooperate with you readily, especially when it helps their mostly Java-based admin utilities run faster and friendlier.

    I think you should rope in IBM to define this multi-VMCPU VM thing, because IBM is a very powerful (and enthusiastic) force in the Java world. They've had quite a few skirmishes with Sun over Java. I have been fantasizing a Java-oriented OS since the birth of Java.

    And how about a virtual coprocessing VMCPU whose instruction-set is dedicated to handling graphics IO - so that graphics IO is not bottle-necked by system processes, vice versa. Perhaps, we should call it a VVM for Video Virtual Machine.

    Also, how about a DVM optionally capable of 64 bit processing?

    With all this multi-VMCPU VM in place, nothing would prevent me from knitting a few lowly ChromeOS lap, book or palm tops together to run as a single VPS (virtual processing space) super-computer. With the appropriate permission/privilege processes in place, ChromeOS based on a renewed Java multi-virtual architecture would make this scenario possible, where a teacher in a classroom of 24 kids says, "Hey kids, I'm borrowing your JVMs over the wireless for a minute" to crunch the solution to a set of equations.

  • And people are asking why Google is trying to compete with Apple and Microsoft in the PC arena. Well, Google, you are not - because neither Apple nor Microsoft has come up with a framework that would allow me to create a supercomputer over the wireless of a classroom of 24 students and a teacher. Those two have too much baggage and Google has none. Moreover, internet-based cooperative computing is Google's expertise and Google is merely expanding their expertise to the cooperative-intranet arena where neither Apple nor Microsoft has the focus or expertise to provide for this much needed arena.
Therefore, if following my recommended road map, Google is not competing with them, Google would merely be conquering outer space where barely anyone (except for some quaint academic esoteric systems) has ever been before.

Cat Psychiatrist Needed

Maine Coon cats are the most lovable and loving of any domestic cat breeds. This morning, and on other occasions, our cat lay down in watch at the bedroom door and waited for me to wake up. I kept wondering what it wanted from me. I checked she had water and food. Then when I started making a piece of bread with strawberry jam and peanut butter for myself, she started to eat her food.

I am rather mystified and deeply impressed by this behaviour. She needed my breakfast companionship. I am thinking if there are such professions as cat psychiatrist or psychologist, who could explain our cat's mentality to me. Most times, I simply forget that she wants me there to eat with her.

By the way ...

If you have a Maine Coon cat, what would you hope to do with all the fluffy down it sheds. Do you have a depleted goose or duck down jacket and have you thought of using the Maine Coon down to replenish your depleted jacket?

Thursday, July 9, 2009

GWT: Useable Closeable Scrollable DialogBox

The GWT DialogBox is barely useable beyond demonstration-level GWT examples. It does not have a close button at the corner of its caption bar.

A usable, closeable and scrollable dialog box is available from
http://code.google.com/p/synthfuljava/ .

ScrolledDialogBox Patch
This class ScrolledDialogBox is found as
http://code.google.com/p/synthfuljava/source/browse/trunk/gwt/widgets/com/google/gwt/user/client/ui/ScrolledDialogBox.java .

Being a patch, it retains the com.google.gwt.user.client.ui namespace.

DialogBox over-rides the onBrowserEvent method and replaces it with a block of obtuse logic - to prevent the text in the caption bar from being selected while the mouse is grabbing the caption to move the DialogBox around the window. A prevention scheme that does not work very well on the hosted browser, evidently. This obtuse logic is the very reason why buttons placed on the caption bar will not react appropriately to mouse click events - consequently, you cannot hide/close the DialogBox through any button placed on the caption bar.

Therefore, either we delve into the convoluted GWT event firing scheme or invent our own mini event scheme and insert it into onBrowserEvent method of DialogBox. The scheme is defined by the interface CloserEventHandler, where only three mouse events are recognised
  • onClick - to close the dialog by clicking on the close button
  • onMouseOver - to change the colour of the close button
  • onMouseOut - to change the close button back to its original colour.
In ScrolledDialogBox.java is declared an ArrayList CloserEventHandlers. This ArrayList is to allow CloserEventHandler instances to be stacked using its add() method.

And CloserHandler embedded class implements CloserEventHandler, which is added onto the CloserEventHandlers event stack, which the new onBrowserEvent paces through to execute each registered handler.

Subclassing rather than Patching
The initial tendency to solve the problem, besides waiting for Google to release a better DialogBox (waiting and looking over the wall till your neck stretches as long as a giraffe's), is to subclass DialogBox to provide the desired effect of having a closer button at the caption bar. As in
http://code.google.com/p/synthfuljava/source/browse/trunk/gwt/widgets/org/synthful/gwt/widgets/client/ui/UnusableScrollableDialogBox.java .

However, this class has a disclaimer - it is not useable, as explained within the javadoc sections, but retained as an example why over-riding this way would not work, because DialogBox's caption acknowledges DialogBox as a parent, but DialogBox does not acknowledge its caption as a child:
  1. In DialogBox, the caption bar comprises one widget alone - an HTML widget implementing the DialogBox.Caption interface.
  2. We need to replace the caption bar with a HorizontalPanel. On the HorizontalPanel, we should place the caption widget and on the right, the closer button.
  3. We should extract the caption widget and reuse it by pulling it out of the caption bar and reinserting it as the first widget of the HorizontalPanel.
  4. However DialogBox did not add caption widget as a widget but rather by adopting (using the adopt() method) it as an element. The consequence is, caption registers DialogBox as a parent but, DialogBox does not register caption widget as a child widget.
  5. To yank caption widget out of DialogBox, we would use caption.removeParent() method. However, Widget removeParent() method first detours to let the parent check if it has the widget as a child widget - if not, the parent's failure to relate to the widget as a child causes the remove operation to abort without the widget having a chance to nullify the dead-beat parent from its private parent variable. Since a widget's parent is stored as a private variable, we muggles would not be able to access it to nullify it.
  6. Well, since the caption widget still acknowledges its dead-beat parent as a parent, the add operation would not work. That is HorizontalPanel cannot add caption widget as its child widget because add() method would first check if the widget still has a parent.
  7. Therefore the caption widget is a victim of a widget's unrequited loyalty to its dead-beat parent.

Therefore the solution is to
  • Orphan the original caption widget.
  • Instantiate an HTML widget as the new caption widget.
  • Over-ride the get/set Text, Caption & Html methods. Unfortunately, the getCaption() method is final and cannot be over-riden.
  • Instantiate a HorizontalPanel and set it as the new caption panel.
  • Add the new caption widget as first child widget of HorizontalPanel.
  • Instantiate a Button and add it to HorizontalPanel as its second widget.
  • Conjure the mini event scheme.
This exercise can be aided by merging some codes for ScrolledDialogBox into ScrollableDialogBox. At the end of the exercise, you would discover that you had replaced three quarters of the super class's code - might as well write a patch rather than a subclass.

The subclassing code is found as
http://code.google.com/p/synthfuljava/source/browse/trunk/gwt/widgets/org/synthful/gwt/widgets/client/ui/ScrollableDialogBox.java .

Disclaimer: The ScrolledDialogBox and ScrollableDialogBox classes need further refinement.
  • The position of the X button needs to be properly calculated
  • The event scheme of the X button accounts only for onClick, onMouseOver and onMouseOut.