Sunday, June 21, 2009

Writing Javascript in (somewhat like) OO style

Javascript is nowhere near OO. But that doesnt mean we cant write it in a manner that is similar to OO.

For example, we can write :




Evolution of a Programmer

I've just installed StumbleUpon on my firefox, and I was presented by this 'favourite' that I bookmarked a while ago.
Worrying that it will be taken off from the site, I'm copying the page here..
The original article is at:

http://www.ariel.com.au/jokes/The_Evolution_of_a_Programmer.html

Have fun!

The Evolution of a Programmer
High School/Jr.High


10 PRINT "HELLO WORLD"
20 END


First year in College

program Hello(input, output)
begin
writeln('Hello World')
end.

Senior year in College

(defun hello
(print
(cons 'Hello (list 'World))))

New professional

#include
void main(void)
{
char *message[] = {"Hello ", "World"};
int i;

for(i = 0; i < 2; ++i)
printf("%s", message[i]);
printf("\n");
}

Seasoned professional

#include
#include

class string
{
private:
int size;
char *ptr;

string() : size(0), ptr(new char[1]) { ptr[0] = 0; }

string(const string &s) : size(s.size)
{
ptr = new char[size + 1];
strcpy(ptr, s.ptr);
}

~string()
{
delete [] ptr;
}

friend ostream &operator <<(ostream &, const string &);
string &operator=(const char *);
};

ostream &operator<<(ostream &stream, const string &s)
{
return(stream << s.ptr);
}

string &string::operator=(const char *chrs)
{
if (this != &chrs)
{
delete [] ptr;
size = strlen(chrs);
ptr = new char[size + 1];
strcpy(ptr, chrs);
}
return(*this);
}

int main()
{
string str;

str = "Hello World";
cout << str << endl;

return(0);
}

Master Programmer

[
uuid(2573F8F4-CFEE-101A-9A9F-00AA00342820)
]
library LHello
{
// bring in the master library
importlib("actimp.tlb");
importlib("actexp.tlb");

// bring in my interfaces
#include "pshlo.idl"

[
uuid(2573F8F5-CFEE-101A-9A9F-00AA00342820)
]
cotype THello
{
interface IHello;
interface IPersistFile;
};
};

[
exe,
uuid(2573F890-CFEE-101A-9A9F-00AA00342820)
]
module CHelloLib
{

// some code related header files
importheader();
importheader();
importheader();
importheader("pshlo.h");
importheader("shlo.hxx");
importheader("mycls.hxx");

// needed typelibs
importlib("actimp.tlb");
importlib("actexp.tlb");
importlib("thlo.tlb");

[
uuid(2573F891-CFEE-101A-9A9F-00AA00342820),
aggregatable
]
coclass CHello
{
cotype THello;
};
};


#include "ipfix.hxx"

extern HANDLE hEvent;

class CHello : public CHelloBase
{
public:
IPFIX(CLSID_CHello);

CHello(IUnknown *pUnk);
~CHello();

HRESULT __stdcall PrintSz(LPWSTR pwszString);

private:
static int cObjRef;
};


#include
#include
#include
#include
#include "thlo.h"
#include "pshlo.h"
#include "shlo.hxx"
#include "mycls.hxx"

int CHello::cObjRef = 0;

CHello::CHello(IUnknown *pUnk) : CHelloBase(pUnk)
{
cObjRef++;
return;
}

HRESULT __stdcall CHello::PrintSz(LPWSTR pwszString)
{
printf("%ws
", pwszString);
return(ResultFromScode(S_OK));
}


CHello::~CHello(void)
{

// when the object count goes to zero, stop the server
cObjRef--;
if( cObjRef == 0 )
PulseEvent(hEvent);

return;
}

#include
#include
#include "pshlo.h"
#include "shlo.hxx"
#include "mycls.hxx"

HANDLE hEvent;

int _cdecl main(
int argc,
char * argv[]
) {
ULONG ulRef;
DWORD dwRegistration;
CHelloCF *pCF = new CHelloCF();

hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

// Initialize the OLE libraries
CoInitializeEx(NULL, COINIT_MULTITHREADED);

CoRegisterClassObject(CLSID_CHello, pCF, CLSCTX_LOCAL_SERVER,
REGCLS_MULTIPLEUSE, &dwRegistration);

// wait on an event to stop
WaitForSingleObject(hEvent, INFINITE);

// revoke and release the class object
CoRevokeClassObject(dwRegistration);
ulRef = pCF->Release();

// Tell OLE we are going away.
CoUninitialize();

return(0); }

extern CLSID CLSID_CHello;
extern UUID LIBID_CHelloLib;

CLSID CLSID_CHello = { /* 2573F891-CFEE-101A-9A9F-00AA00342820 */
0x2573F891,
0xCFEE,
0x101A,
{ 0x9A, 0x9F, 0x00, 0xAA, 0x00, 0x34, 0x28, 0x20 }
};

UUID LIBID_CHelloLib = { /* 2573F890-CFEE-101A-9A9F-00AA00342820 */
0x2573F890,
0xCFEE,
0x101A,
{ 0x9A, 0x9F, 0x00, 0xAA, 0x00, 0x34, 0x28, 0x20 }
};

#include
#include
#include
#include
#include
#include "pshlo.h"
#include "shlo.hxx"
#include "clsid.h"

int _cdecl main(
int argc,
char * argv[]
) {
HRESULT hRslt;
IHello *pHello;
ULONG ulCnt;
IMoniker * pmk;
WCHAR wcsT[_MAX_PATH];
WCHAR wcsPath[2 * _MAX_PATH];

// get object path
wcsPath[0] = '\0';
wcsT[0] = '\0';
if( argc > 1) {
mbstowcs(wcsPath, argv[1], strlen(argv[1]) + 1);
wcsupr(wcsPath);
}
else {
fprintf(stderr, "Object path must be specified\n");
return(1);
}

// get print string
if(argc > 2)
mbstowcs(wcsT, argv[2], strlen(argv[2]) + 1);
else
wcscpy(wcsT, L"Hello World");

printf("Linking to object %ws\n", wcsPath);
printf("Text String %ws\n", wcsT);

// Initialize the OLE libraries
hRslt = CoInitializeEx(NULL, COINIT_MULTITHREADED);

if(SUCCEEDED(hRslt)) {


hRslt = CreateFileMoniker(wcsPath, &pmk);
if(SUCCEEDED(hRslt))
hRslt = BindMoniker(pmk, 0, IID_IHello, (void **)&pHello);

if(SUCCEEDED(hRslt)) {

// print a string out
pHello->PrintSz(wcsT);

Sleep(2000);
ulCnt = pHello->Release();
}
else
printf("Failure to connect, status: %lx", hRslt);

// Tell OLE we are going away.
CoUninitialize();
}

return(0);
}

Apprentice Hacker

#!/usr/local/bin/perl
$msg="Hello, world.\n";
if ($#ARGV >= 0) {
while(defined($arg=shift(@ARGV))) {
$outfilename = $arg;
open(FILE, ">" . $outfilename) || die "Can't write $arg: $!\n";
print (FILE $msg);
close(FILE) || die "Can't close $arg: $!\n";
}
} else {
print ($msg);
}
1;

Experienced Hacker

#include
#define S "Hello, World\n"
main(){exit(printf(S) == strlen(S) ? 0 : 1);}

Seasoned Hacker

% cc -o a.out ~/src/misc/hw/hw.c
% a.out

Guru Hacker

% echo "Hello, world."

New Manager

10 PRINT "HELLO WORLD"
20 END

Middle Manager

mail -s "Hello, world." bob@b12
Bob, could you please write me a program that prints "Hello, world."?
I need it by tomorrow.
^D

Senior Manager

% zmail jim
I need a "Hello, world." program by this afternoon.

Chief Executive

% letter
letter: Command not found.
% mail
To: ^X ^F ^C
% help mail
help: Command not found.
% damn!
!: Event unrecognized
% logout

Wednesday, June 17, 2009

Spring Testing & Transaction Manager

Transaction is one of the topic that always baffles me. Spring framework is supposed to take a bit of this burden away from the programmer. But a lot of time we (programmers) take this for granted, without looking into details under the hood.
I'm a classical example of this type of programmer.

I'm currently working on a project, which heavily uses Spring framework. We use spring within the application and for testing.

i.e.:
our code looks something like:


@Service
@Transactional
public class SomeServiceImpl implements SomeService{
public void someTransactionalMethod(){
...
}
}


and the spring config looks like:




xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
">
...




...



This is all fine within the code itself. The transaction manager spring bean is named 'hbTransactionManager', and we explicitly says that transactional annotation is to be managed by this transaction manager instance.

Unfortunately, sometime during the project, we added LDAP components to the project,
and no-surprise, we decided to use Spring LDAP. It happens (somehow) that we introduced Spring LDAP Transaction manager:























Note that this transaction manager uses 'transactionManager' as the bean identifier.

The code seems to be working fine for now - but I cant guarantee that anymore. Anyway, what I wanted to talk about, is the test codes.
Our base test class looks like:


@ContextConfiguration(locations = {"classpath:applicationContextTest-common.xml"})
public abstract BaseTestCase extends AbstractTransactionalJUnit4SpringContextTests{
...
}


while test cases that extends this class uses Spring LDAP's transaction manager, it is not the case with some other test cases that extends another abstract class:


@TransactionConfiguration(transactionManager = "hbTransactionManager")
public abstract BaseIntegrationTestCase extends BaseTestCase {
}


This only came to my attention in my recent attempt to write a test case that test the rollback behaviour within our codes:




public class SomeTestThatShouldFail extends BaseIntegrationTestCase{

@Autowired
private SomeService service;

@Test
public void test_something(){
..
try{
service.someTransactionalMethod(); // i expect this to fail
Assert.assertFail("Shouldnt succeed");
}catch(Exception e){
}
...
// do some verification that rollback occurs
}
}


The test case above failed. Because of the following:
1. The test case uses 'hbTransactionManager'.
2. The code uses transactional annotation, which is specified to use the same transaction manager (hbTransactionManager).
3. Since the test case start the transaction, the failed operation wont be rolled back at the end of method invocation (because the transaction wasnt started at the point of method invocation!)
4. Therefore my verification for rollback wont succeed. The rollback will be performed at the end of the test.


The fix is to change the code above to:


@TransactionConfiguration
public class SomeTestThatShouldFail extends BaseIntegrationTestCase{

@Autowired
private SomeService service;

@Test
public void test_something(){
..
try{
service.someTransactionalMethod(); // i expect this to fail
Assert.assertFail("Shouldnt succeed");
}catch(Exception e){
}
...
// do some verification that rollback occurs
}
}


This time, the test case will use the default transaction manager - which is the Spring LDAP's transaction manager. The rollback will occur at the end of the service.someTransactionMethod() invocation, because it was started there.


Lesson learnt - never take things for granted. Always look at what happens under the hood.

Tomcat + Postgresql +JNDI Datasource

JNDI datasource is probably the most convenient way to configure datasource in a J2EE environment. Here is what I have for my Tomcat server


${CATALINA_HOME}/conf/context.xml


auth="Container" type="javax.sql.DataSource"
driverClassName="org.postgresql.Driver"
url="jdbc:postgresql://localhost:5432/ramen"
username="ramen" password="ramen"/>


web.xml

xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
....


jdbc/ramenDataSource
javax.sql.DataSource
Container

....


spring configuration

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
">
...

..



Thats all :)

Monday, June 15, 2009

Maven + Cargo + Tomcat +vista = pain

I'm currently working on a project thats using Tomcat as the servlet container.
So I thought I'll use cargo plugin from Codehaus to deploy to Tomcat.
FYI, I was doing this on my desktop, which runs Vista, Sun JDK 1.6, and Maven 2.0.9

For some reason, I kept getting the following error while doing mvn cargo:deploy


java.net.HttpRetryException: cannot retry due to server authentication, in streaming mode.
...
...
org.codehaus.cargo.container.tomcat.internal.TomcatManager.invoke(TomcatManager.java:565)
..


After scratching my head for quite a while, I decided to give it a shot on my laptop, which runs Ubuntu. Sure enough, it ran without any error.

I might poke around the code a bit, to see whats happening there, and maybe submit some patch to cargo. What surprised me, is that surely someone out there has used Maven + Cargo + Tomcat + Vista, and experienced the same error. Or ignorance has become a norm? I dunno.


Ciao.

P.S.: apparently that error has to do with connection transfer in chunk mode? I have no idea.
Who cares... its 12:06 AM now, and I know that my code works in Linux.