Friday, September 5, 2008

Launching Browser from External Application

I have a standalone java/swing application, from which I want to launch a browser. There are various methods by which you can do so, but every time this java app calls Runtime.exec to launch, it creates a new browser window (unless the user has set browser such that for new urls, it opens in same window/tab).

My objective is to launch the browser such that, if I want to target a specific browser window, it does that, or if I want to open a new window, it does that too.

And, it should work with both IE and Firefox. Let's not talk about the Google's baby yet.

Now, to target a specific browser window, javascript's window.open is the best choice. However, I can't execute javascript from my java app, I need to have it executed in the browser. What I can do is -

1. Launch the browser from java app, to go to a intermediate URL (servlet/jsp), passing in the window name and the real target URL. This servlet/jsp will inject some javascript code in it to execute on load.
2. This javascript will call window.open function, passing in the target URL and the window name.
3. The target URL will be opened in the new window, or if a window with that name already exists, it will load that target URL page in that window.
4. Use the same javascript code to close this particular window which was originally launched by the java app.

This way, we have the target URL loaded into a named window.

The javascript code snippet is:

var winA=window.open(targetUrl, winName);
window.opener='x'; // this is for IE only
if(winA != window) window.close();

And this works perfectly in IE. However, I have various problems with firefox 2/3.

Allow Javascript to Close Windows in Firefox

Starting from firefox 2, it is not allowed to close a browser window, if that window was not opened by a script. In our case, since the original window was opened by java application, window.close() gives us the error - scripts can not close window not opened by script. The easy workaround for this is to change the firefox config, however, it depends on your specific solution, if you can ask your users to make this config change. I haven't explored the possibility of programatically checking/changing/prompting the users for this change.

Anyway, the change is this - type about:config in firefox address bar. This will give you a bunch of config options. Filter on dom.allow. You should see a config:
dom.allow_scripts_to_close_windows
The default is false, toggle it to true.

Now, you can close browser windows/tabs in firefox using javascript, even if the window/tab was not opened by javascript.

The Same Origin Policy

So far so good. The next problem I have is - getting handle of an already opened window.

You would think that when you use window.open("http://www.google.com", "googleWin"); it will open a window with the name googleWin. This is only partially true. It will open a window, with the URL www.google.com loaded, however, it will not set the name of the window to "googleWin", unless you executed the javascript to load window somewhere from http://www.google.com/....../.

This is a little known security feature of firefox, which I guess is dated back to Netscape days, called Same Origin Policy. According to Mozilla documentation,

The same origin policy prevents document or script loaded from one origin from getting or setting properties of a document from a different origin. Mozilla considers two pages to have the same origin if the protocol, port (if given), and host are the same for both pages.

There's one exception to this rule, where you can allow domain changes upto some extent, for example from http://store.company.com/... to http://company.com/...

Mozilla documentation is here:

http://www.mozilla.org/projects/security/components/same-origin.html

So, if you host the servlet/jsp which opens named window in the same server/protocol/port as the to be opened pages, you will be able to get handle to windows by name.

Monday, September 1, 2008

Square Architecture - Square Any Number Easy Way

While nothing interesting going on in the software world, I got to play with some Math tricks, and got interested in ancient Indian math called Vedic Mathematics. While learning some of it, I thought of writing about this particular method-

Finding Square of Any Number using Vedic Math

The formula is called Dwandwa-yoga (Duplex combination process). Let's see how it works.
Duplex (D) of a number is found as follows, examples later will make it more clear.
For Duplex, in the number sequence we have to find square of, we take twice the product of the outermost pair, and then add twice the product of the next outermost pair, and so on until no pair is left.
When there are odd number of digits in the original sequence there is one digit left by itself in the middle, then this enters as its square.

So, if the number is:

a then D -> a2
ab then D -> 2(axb)
abc then D -> 2(axc) +b2
abcd then D -> 2(axd) + 2(bxc)
abcde then D -> 2(axe) + 2(bxd)+c2
...and so on.

So, finding duplex is so easy, and after that, it is just addition, so very simple.
Before that, note that if we are given an n digit number to square, we will prepend that number with n-1 zeros.

So, let's try this. Find square of 52. It is a two digit number, so, add 2-1=1 zero in the front.

052
Now, let's find the Duplex:

For 2, D= 22 = 4
For 52, D=2(5x2) = 20
For 052,D=2(0x2)+52 = 25

So, simple, now, just add the numbers we got:

04
20
25
_______
2704

Let's try one more example: 1092
A three digit number, so we have to add 3-1=2 zeros before it.

00109
Duplex:
For 9, D=92 = 81
For 09, D= 2(0x9) = 0
For 109, D=2(1x9)+02 = 18
For 0109, D=2(0x9)+2(1x0) = 0
For 00109, D=2(0x9)+2(0x0)+12 = 1

Here we go:
81
00
18
00
01
__________
011881

Indeed, that's the answer.

Let's do an easy one: 152
015
For 5, D = 52 = 25
For 15, D= 2(1x5) = 10
For 015, D=2(0x5)+12 = 1
And,
25
10
01
________
0225 is the answer.

Now, that brings me to a special case, for even easier calculation.
The special case is - the numbers which are ending with 5. Say, the number is of the form a5. The square of that number will be = a(a+1)|52.

So, for 152, the result will be 1(1+1) | 52
i.e. 2 | 25 or 225.

Similarly, 952 will be 9(9+1) | 25
i.e. 9025.


Now, that is superfast, I am sure in some cases it is even faster than doing it on calculator.