Monday, June 28, 2004

Twitchy, bitchy bad day.

NARGH! Waking up to an ugly rainy Waterloo day, and then things just got worse. I shall allow my foul mood to commence for 30 more minutes and then finish it with the day.

With apologies to softeng.net, Shit that pisses me off:
(a) Colin: Don't leave CDs that you want to send to Jennifer at Chan's place. Actually, that'd be fine, but don't leave them at Elena's place.
(b) Chan: Answer your phone.
(c) Chan: Get your voicemail activated.
(d) MSN: Don't refuse to log in / get my contacts / change my name.
(e) Chan: Rape the Rogers connection a bit less, please. Not cool when I have a shitload of lag just so you can download shitty quality DivX's of movies -- movies which, in some cases, we have fucking DVDs of in three different towns in Ontario.
(e) Denver, Hobo: Check your email accounts.
(f) Liberal Party of Canada: Don't come so perilously close to winning a majority government.
(g) Cocoon: Don't have retarded null pointers that occur for no fucking reason. 2 hours of my life to fix something that someone should have noticed by now...

That is all.

One bonus to today: I used my aforementioned rejection letter from CIBC to get myself on the voter's list, since it worked as proof of residence in my riding. Spiff.

Thursday, June 24, 2004

Yay!

Also, a long, loud yay for July 16th through 19th.

Cocoon's authentication framework

Welp, I decided to stop beating around the bush and take a shot at figuring out how the hell to do authentication in Cocoon.

As it turns out, it's yet another beautifully designed system that just needs documentation. OBVIOUSLY, if you want to access context data from FlowScript, you'll execute cocoon.session.getAttribute("org.apache.cocoon.webapps.authentication.components.DefaultAuthenticationManager/UserStatus").getHandler("loginhandler").getContext().getContextInfo(). I'm shamed to say this wasn't the first thing to pop into my mind.

Other than that, the architecture for protecting documents seems really neat and flexible. With minimal effort, I should be able to (a) authenticate across three different data sources and (b) generate customized output based on which class of user is logged in. Quite spiffy.


Wednesday, June 16, 2004

FOP PDFs with Internet Explorer

Welp, the webapp trundles steadily along towards being completed. *tear* They grow up so fast...

Notes: Apparently IE5.x and the Acrobat Reader plug-in and up are absolute idiots when it comes to downloading PDFs. It's quite possible for IE to try to open up to 3 concurrent requests to the server for a PDF file -- or for it to not request a Cocoon/FOP generated PDF as a PDF.

The solution? Serialize the PDF inside Cocoon, write it to a file, and then redirect the user to that file. The <xmap:serialize type="fo2pdf"/> directive will only reliably work for IE for small PDFs. Sad, no?

I still need to finish populating my PDF with user data -- but I've already populated the first 5 pages (of ~11 or so), so I feel like I'm pretty much on easy street with regard to that.

After PDF population, we worry about authentications and permissions, which could be a bit more interesting...

Rhino, you kill me.

So the hacked up Rhino included in Cocoon doesn't allow you to access the variable `this' inside of an eval() command.

Therefore, one has to do var me = this; and then refer to me, not this. Kind of a silly eccentricity, no? And sadly, this = this; isn't a valid assignment -- that'd be a beautiful kludge, though.

(Sidenote: In IE, aCertainDiv.innerHTML += ""; fixes a layout bug. God, I love software.)

Tuesday, June 08, 2004

Client-side repeaters

So I've cobbled together some ugly code that I'm pretty sure will die horribly in a non-IE browser. . . (note to self: fix that.)

Ignoring that, it's really neat! It allows for client-size resizing of repeaters - no server trip. The sneaky way I manage this is I mandate the following structure:

TABLE
  THEAD
    TR
       TH Column 1 /TH
       TH Column 2 /TH
       TH Column 3 /TH
     /TR
   /THEAD
   TBODY
     TR
       TD
         TABLE
           --- repeater layout goes here
         /TABLE
       /TD
     /TR
   /TBODY
/TABLE


An n + 1th column is automagically created in the table with add row / delete row buttons. When you press it, it triggers a JavaScript event which detects what table the event came from, finds its parent table, inserts / deletes an appropriate row and then recreates a data entry form using the source as a template strand. See, BIO 139 *did* have a purpose for me!

Anyway, it's quite nice and allows for keeping things client-side, even for really complex repeaters (think, for example, Part 4 of Form 89.)

Sunday, June 06, 2004

Cocoon Forms

Wow. That's all there is to say.

I'm prototyping a rather lengthy and complex form using Cocoon Forms (née Woody), and it's pretty darned slick.

I haven't set up the bindings yet or dealt with any of the server side issues, but I'm amazed at how rapidly I can get the form up. Also, I'm able to get a pretty nice look-and-feel using just the default stylesheets. It's neat how CForms handles the drudgery for you, so you can spend your time on custom code to make the form really effective.

After 3 weeks of fighting it, I think Cocoon and I are getting along now!

Saturday, June 05, 2004

Leveraging storing objects in a database

So, since I now have this handy way to magically pull objects from the database, I've started reconsidering how I'm designing what I'll call my "entrance" points. e.g. to edit client 10, the old fashion was to go to http://purplefurfle/lawoffice/admin/addClient/10. Under the new system, you go to http://purplefurfle/lawoffice/clients/10.edit() -- this seems like an insignificant difference, until you realize that 'clients/10' maps a portion of the URL to an object stored in the database. The system deserializes the object stored at that reference and then calls its "edit" method. The "edit" method then uses Cocoon's standard pipelines to interact with the user. So what have we gained here? We have a greater sense of object-oriented programming -- the logic for editing clients is now stored in the ClientJSBean object itself, rather than some random JavaScript file, and have separated two concerns: manipulating the data and accessing it in the backend.

I was feeling quite smug, until I realized there were some major issues with this. For example, let's say client 6 has a file associated with him. Call it file 3. How do I invoke methods on file 3? You see, at present, 'clients/10' identifies the resource labelled '10' in the collection labelled 'clients'. The file objects are stuffed away somewhere deep inside the '10' resource's XML structure. So we can invoke methods on the client object, since he's at the root of the XML structure, but invokng methods on his contained items is much more difficult. -- sure, we can deserialize the client himself, which will then deserialize his related children, pull the child out in some convoluted fashion, and invoke methods on that, but then how does he know where to store himself?

We could perhaps make the Serializer store arrays as subcollections, and items in arrays as resources within those subcollections.

A downside of this, is we lose part of the structure that storing data in an XML file gives us, namely the natural ordering of elements. An XML file is easily ordered from the top down, but an entire collection tree traversal? I could settle on doing pre/post/in-order traversals, but I'll still need to pick a standard for ordering resources within a collection. No matter how you cut it, I lose some ordering capabilities. Mildly annoying.

An upside of this is that if we made the (Des|S)erializer smart enough, we could allow for granular locking of resources, and minimize database transaction activity.

Blargh, this will take some time to implement... Ah well, it will be a very nice foundation to work with when it's all done.




Thursday, June 03, 2004

XML/JS Binding

So, given that I've now totally moved to an XML/JSBean binding, the question becomes: did I really just want an object relational bridge?

I would say no -- I don't want a relational data store, after all. The goal was to stor e the user's data in a standard form which is easily accessible. -- yes, sure, SQL's a standard. But the 73 cross-referenced tables any given application generates sure as hell aren't.

By storing the data as XML, it's moderately easy for the user (or at the very least, a programmer hired by the user) to understand the structure quickly, and then use existing tools such as the DOM, SAX or even XSLT to operate on it. Storing it in an RDBMS would not get you this. :>

However, another concern is that at the moment, my data is pretty simplistic. If it gets more complicated -- which it won't, unless the application itself gains a larger scope -- I may well be in a situation where a relational database would give me enormous speed gains. Then again, my application is likely a low-use one, so this is a bit of a mitigating factor.

I'm also a bit concerned about scalability, even of simple databases with only a couple collections that aren't even cross-referenced. And transactions. I wonder if there are NXDs with support for transactions, or if I'll have to cobble in my own locking system - doesn't even need to be too granular at the moment. Ah, questions, questions.

Xindice / JavaScript bean binding

There's been a bit of a drought here, so I thought I would post. Ran into a bit of a roadblock design-wise -- I needed to settle on a way to do persistence of data. Hacking together Xindice update scripts / parse scripts for each and every bit of info you want to store is definitely not cool.

So what I ended up writing was a polymorphism-aware Javascript/XML binding serializer/deserializer. I can now just write Serializer.store(jsBean, "clients/123") to save data and jsBean = Deserialize.get("clients/123") to retrieve the data as an object of the correct type. No more ugly XUpdate/JXTemplateTransformed kludges. It generates XML that is *very* human readable/XPath-able, but is not a perfect rendition of the input data. For example, sparse arrays are not supported, so I need to treat arrays a bit more like vectors than arrays.

Pretty spiffy.

I'm really enjoying the quality of the SSJS integration with *everything* in Cocoon.

Also, the British Columbia Land Title Office handily replied to me saying, "Well, gee, yes, we *do* expect you to use Adobe Acrobat 6.0 and our own form templates." On the bright side, this is easy for me to do -- Adobe's FDF Toolkit has servlet integration, but how stupid is it that what should be a public service is committing to one vendor's proprietary, expensive standards?

Weooweoo. Anyway, off to fix the things that broke in the serializer changeover!

This page is powered by Blogger. Isn't yours?