Wednesday, November 29, 2006

Sunday, November 05, 2006

the web sucks

As a developer who really likes to get stuff done (in terms of business goals), I really detest writing the "client" side of webapps. Some work I did recently to help a struts application deal with the problems of duplicate submissions, back button issues, have really set me off, ready to go back to swing, or GWT, or... We (programmers) are just writing way too much plumbing to deliver basic web applications. I know this is probably old news for some of you, but embarassingly, most of the applications I have worked on to date, have simply ignored the problems. Here's my quick research, and what you can do about it.

1. Goal #1: Prevent duplicate submissions.

Note although the stated goal is to prevent duplicates, it is really more like saying "make sure the user reloads the screen before they submit". In other words, make sure they run the Http Get request before the POST of the form. Your business logic should kick in at some point in the process, but I digress.

How to fix: Put something in the emitted web (GET)page that when the form loads, it is a hidden field. Store this emitted token on the server side. Later, when the user submits the form
check that the token being submitted matches what exists on the server side.
If you are using Struts: use isValidToken(request) when the post comes in, and use
resetToken(request);
saveToken(request);
When the form is displayed.

Get fancy: you might be able to put this in a filter if you are crafty. However, if you have server side servlet.getDispatcher().forward type of code, or forward to another action in struts, you may run into trouble. This is because a servlet forward is not another request from the browser, hence subsequent chained actions may be checking tokens when they don't need to.

Problem #2
Back /forward navigation -
To me, if you have form posts, you ought to be able to simply disable back/forward in the browser, as it is meant for the "page" paradigm, viewing books and the like. In fact, some browsers(I think opera) you can't completely kill cache. Caching in any GUI intensive web app is a nightmare, simply because your server side state doesn't match what the user sees.

Anyway, seems like the best way to make this work, is a combination of tools.
1. When a form posts executes, do NOT display a page after doing the post, but instead, send a redirect to fetch a new page- presumably the "result" of their post.
See here for a decent explaination:
here and here

The impact of this appoach (in struts) seems that
a. any messages sent to the user on success, will need to be stuck in the session, and not request
b. if you have are using struts validation, and you have an error, your form will need to be in the session, as your form validation failure was a POST too, so that, too, should use a redirect.

So much for session persistence, given our new bloated session sizes. Good thing I think its overrated anyway.

If you do the above steps, you'll still have an issue: the browser will be caching perhaps when you choose back/forward. So, In order to disable that in struts, you just add some stuff to the controller xml file in the struts-config, eg:



Note: if you are on struts V1.28 or below, this WONT work on Firefox, as they need something in the http header called: no-store. Older versions of struts won't set this header.

If you would like to see your http headers BTW, check out the firefox extension, which helpeed me track this down.

http://livehttpheaders.mozdev.org/

Hopefully I'll get a chance to play with Seam or WebFlow one of these days, which take care of a lot of this junk for us.

windows disk space and other thoughts

My hard disk was down to 3 gigs last night, so I thought I would try and figure out where my space was going. Of course there are a lot of places to look, but heres what I found, that claimed 3 gigs of space.
It appears windows has a "system restore" feature for windows itself. Since it doesn't actually help with your installed apps being broken, I took the chance, and turned it off via the "System" control panel.
Disk space savings: 3gig!
After turning System restore off (and clearing the disk space), you can turn it back on, and create a restore point manually. (instructions)
I handle my own backups, such that if my windows gets whacked, then I would do a full restore of my drive. Here's a free and easy way to backup:
  1. Buy an external firewire or USB 2.0 drive
  2. Download driveimage xml
  3. Backup your stuff!
  4. If you want the ability to boot off of something else (like CD), get a copy of BartPE builder.
  5. This allows you to boot off of the CD drive (check your BIOS), and use your backup to replace your "c" drive.
  6. When you create your BartPE boot disk, put driveimage xml on the disk. See these instructions.
Then, I realized I could also save some disk IO by turning off Content Indexing. This appears to make little difference in my searches, as I typically search within a directory or two anyway.
My computer- properties of disk (c:) - "allow indexing" checkbox.

Saturday, November 04, 2006

java thought

I like conceptual what they are suggesting in this article.
http://nutrun.com/weblog/structures-in-java/

Tuesday, October 24, 2006

more on aspects

I did more experimentation with aspectj today. I really dig the idea, but I'm hesitant to recommend something where there is a large compilation time impact, or runtime impact. Yesterday I used the eclipse dev tools for aspectJ. Pretty neat, but the additional compile time seems a bit heavy. So, I moved to try the LTW- the weaver piece, that allows you to add advice to classes as the classloader loads them. Theres lots of docs on this on the web, but here's some notes that might help.

1. Seems if you're using the eclipse aspectJ tools, having a seperate project for the aspects is the best way to set things up. Then, when you change the aspects, just export the jar into your web-app\lib directory.

2. You'll need to customize the aop.xml file some. Heres mine. Basically you make a directory in your "jar" project called META-INF, and create a file called aop.xml. The aspect j weaver will read this, and now what aspects to "weave" in. Mine is later in this document.

3. When you run your classes(a unit test perhaps), you'll need to add the following stuff. I was just using eclilpse, so tomcat or appserver setup would of course be different.
Notable JVM args:

-- if you want to override the default aop.xml file locations:
-Dorg.aspectj.weaver.loadtime.configuration=myclasspathplace/aop.xml;foo/bar/aop.xml

-- this will give you info as to the parsing of the aop.xml file

-Daj.weaving.verbose=true

finally, in order to do the LTW:
-javaagent:./lib/aspectjweaver.jar -Xmx256m

Note I added the JVM args as I was running out of memory. I also had some wierd errors when I first started, and had to upgrade my aspectweaver.jar, from something newer than 1.5.2. Basically a null pointer exception in the weaver...


So, here are the issues:
The weaving adds about 30 seconds of additional startup time, even with the many exclusions below. Note that my advice doesn't do a whole lot.

Unittest (200 tests) time w/out :45 seconds
With weaver was about 75 seconds
With compilation time (non LTW) about 44 seconds.

Maybe later this week I'll now tell spring about my aspects...
At the moment I'm not sold on using aspects in daily development. Maybe as part of an automated build it would be okay, but that kind of limits what I would do with them in the first place it seems.















































crazy for aspects

I stayed up too late into the evening trying to learn aspectJ. I think we should consider its use more often. It makes things like logging simple.
Note that it requires that you modify your eclipse environment to have the aspectj compiler. Or, download the eclipse tools here:
download aspectj developer tools

Then watch this quick demo:
demo of aspectj tools

What I like most about the tool, is that it shows you where your advice will be applied!

** Note, if you are using BEAWorkshop, for some strange reason BEA doesn't include the PDE plugins for eclipse, and although the tool(ajdt) will be installed, it didn't work for me, until I manually added this plugin via the eclipse software update function.

The real time consuming thing is to figure out how to define pointcuts (where your code will run), and the aspectj syntax. Hopefully my samples will make it easy.

Here's some sample aspects I wrote:

public aspect ServiceLayerAspect {
/**
* intercept executiong of methods begining w/ pkg name com.service, ending with name service
* and any method
*/
pointcut methodsEndingWithNameService():
//any pkg or subpackage of service
within(pkg.pkg.pkg..*)
// && execution(public * pkg.pkg.pkg.*.*Service.*(..))
//classname ends in Service
&& execution(public * com..*Service.*(..))
&& !execution(public * get*())
&& !execution(public void set*(..))
;

before(): methodsEndingWithNameService() {
Logger log = Logger.getLogger(thisJoinPointStaticPart.getSignature().getDeclaringType().getName());

log.debug("before service method "+thisJoinPointStaticPart.getSignature().getName());
}
}




public aspect DomainLayerBusLogicLogger {
/**
* intercept executiong of methods begining w/ pkg name com.service, ending with name service
* and any method
*/
pointcut methodsNotGetSet():
// call(public * get*(..));
// &&
within(pkg.pkg.domain..*)
&& execution(public * *(..))
&& !execution(public * get*())
&& !execution(public void set*(..))
;

before(): methodsNotGetSet() {
Logger log = Logger.getLogger(thisJoinPointStaticPart.getSignature().getDeclaringType());
log.debug("bus domin method:"+thisJoinPointStaticPart.getSignature().getName());
}
}


public aspect StrutsLoggingAspect {
/**
* find methods that return an ActionForward, and extend DispatchAction
*/
pointcut dispatchingActionForwards():
execution(public org.apache.struts.action.ActionForward
org.apache.struts.actions.DispatchAction+.*(..));

before(): dispatchingActionForwards() {
Logger log = Logger.getLogger(thisJoinPoint.getTarget().getClass());

log.debug("Web action start:"+thisJoinPointStaticPart.getSignature().getName());
}

Sunday, October 22, 2006

Hibernate inner workings 1

Although I've been Hibernating for a couple of years now, it seems there is always more to know. I'm a big fan of hibernate as its allowed me to apply what I learned long ago in all my OO classes w/ CRC cards. It really is possible to put Domain Model Programming into practice. Okay, so why am I writing about it today? Because I finally looked at the source to see how it does change detection. Any object loaded by HIbernate, is "watched" by hibernate for changes. I knew this, but didn't really know how it works. So, from my brief look at the code, heres how it goes AFAIK

  1. You load objects via load, get, query, whatever
  2. Hibernate puts these objects in its session cache (a hashmap)
  3. Hibernate uses the key of the object and the class to as the key
  4. When sess.flush is called (either explicitly or because tx is finished or a query is executed)
  5. Hibernate goes throught its identitymap of object
    1. Check out the FlushEventListener class for details
  6. The EntityEntry for the object is found
  7. Dirty check takes place against the EntityEntry. Each EntityEntry has the loadedState of an object, which appears to be an array of simple properties
  8. Update is scheduled if necessary
I initialially thought hib did all this via CGLIB. Appears I was incorrect. Also, if you think your equals methods are involved in this evaluation, that appears to not be true either.

Cheers, long live hibernate

--James