sipXconfig
Monday, March 28, 2005
 
reasons not to overuse XSLT
I fixed a bug.

This is why I dislike overusing XSLT. We take the data from couple of different sources, cram it into XML document and generate HTML page through XSLT transformation. There are at least two really bad things here:
  1. We are passing data between different application components as XLOBs (XML Large Objects (tm) ). I do not care about how ineffective it is, I do care about how non-transparent it is. You never know what someone decided to put into that XML and you never know who and what depends on its content.
  2. We are using XSLT to apply bussines logic. In this case to decide which components are editable and which are read only. Aa a result our UI code is hopelessly hidden in the ocean of bussiness logic writen in poorly designed and not especially convenient programming language (XSLT).
The bottom line is template based approach (JSP, Velocity, XSLT) quite often degenerates in the heavy proprietary scripring, where template stops resembling your destination document (which is the main reason to use the template after all). I think I prefer Tapestry to JSP, DOM4J/JDOM/Xstream to Velocity, Java/Python/Groovy to XSLT. Also I prefer cats.

Thursday, March 24, 2005
 
Tapestry components repositories
Since Tapestry related tools are using a lot of real world terminology it's virtually impossible to look for anything Tapestry related on google (try Tapestry, Spindle, Tassel and see what you find).

This is a list of Tapestry components repositories that I know of:

Thursday, March 17, 2005
 
Tapestry in anger: pitfall #12141
You cannot validate your page when the form tag is in an embedded component because the IValidationDelegate.hasErrors() will not process the components form elements until it's too late.

So mypage.page (pseudo code)
mycomponent
submit button [w/listener=page.doit]

mycomponent.jwc
form tag
form element w/validator defined


MyPage.java
doIt() {
IValidationDelegate delegate = (IValidationDelegate) getBeans().getBean("validator");
// INVALID: form elements in component has not asked to validate yet!
boolean save = !delegate.getHasErrors();
}

So I rewrote this so the form tag is in the page and now it works fine.

 
Tapestry: accessing validators from components
binding name="validator" expression="page.global.validXXX"

This works for accessing all global data from components, use judicisouly, as components make assumptions about page they're in

Friday, March 11, 2005
 
logging according to lazyboy
Apparently this is how one should use commons logging in sipXconfig:


// define logger as private static final field
private static final Log LOG = LogFactory.getLog(SipServiceImpl.class);

// use it
LOG.info("blah");


The output goes to server.log

Wednesday, March 09, 2005
 
Damian's flowers

 
Strategy for binding Interface implementations from Spring with Hibernate object
This is a very esoteric blog, it's more of a mental memory dump for myself incase I ever need to recall this "design pattern"

Actors:
1. Phone interface
2. Vendor's Phone interface implementation
3. PhoneData hibernate object w/access to perisent data for all phones
4. Line interface
5. Vendor's Line interface implementation
6. LineData hibernate object w/access to perisent data for all lines

Goals:
1. Let interface be service driven, easy to implement
2. Let database store simple properties and not burden implementation with menial getter and setters and allow interface and persistent objects to evolve independently of each other

Challenge:
Phones have 1-to-many relationship with lines and hibernate is great at dealing w/that however hiding data objects at least when it comes to adding and deleting lines becomes very difficult.

Knowns:
Dao needs to wrap each read/write of data objects to return interface implentations. Therefore fancy queries that return complex object graphs are not really useful.

Solution:
Given that all queries need to be "wrapped" advantage of having hibernate manage the collection is minimal. Therefore, if phone interface manages a "simple" collection, Dao can read/write collection in only a few isolated places. I say "simple" because one trick is being able to recall what lines need to be deleted. A simple Collection subclass handled this trick.

 
hibernate: deleting objects w/unsaved references
Hibernate Gotcha #104312

Error: object references an unsaved transient instance - save the transient instance before flushing

Senario: I was deleting an object that had a reference to an unsaved object. Why would i try to add a new object to an object that's about to be deleted? Improper logic, but, not exactly illegal. Now I null out the reference and it's happy.

 
DBUnit seed data, use high primary ids
Using dbunit w/postgres, or any db that uses sequence numbers, is challenging. I just spent half a day finding out why seed data should contain primary keys starting at high numbers, say 1000.

Senario:
1.) create new db
2.) insert a new row with primary key = 1 in dbunit seed file. NOTE: Dbunit does not update sequence numbers. (if this scares you, it should, almost ditched it thinking it was going to be useless, but for some reason I decided this could be worked around)
3.) write a test that adds a new object from db business layer, if this is your first unittest, it will pick primary key = 1 as well and will throw an error. You would think the error would be obvisous, but I didn't "get it" from this hibernate/spring but from lot of debugging:

org.springframework.orm.hibernate.HibernateSystemException:
a different object with the same identifier value was
already associated withthe session: 1,of class:
org.sipfoundry.sipxconfig.phone.LineMetaData; nested
exception is net.sf.hibernate.NonUniqueObjectException:
a different object with the same identifier value was
already associated with the session: 1, of class:
org.sipfoundry.sipxconfig.phone.LineMetaData
net.sf.hibernate.NonUniqueObjectException: a different
object with the same identifier value was already
associated with the session: 1, of class:
org.sipfoundry.sipxconfig.phone.LineMetaData

Saturday, March 05, 2005
 
Spring's AOP Major limitation

Apparently Spring with only affect bean classes it loaded thru it's application context files. Considering it weaves code at runtime, this makes sense. Knowing this, it can still be useful, but it's not in the same league as AspectJ.

So using Spring's AOP to dump particular Hibernate exceptions that wrap SQL exceptions in unittests won't be that straigtforward, I'd have to wrap each DAO with yet another proxy layer. It won't be long before people start talking about the "AOP Proxy Stack".


Thursday, March 03, 2005
 
Tapestry contrib:Table without paging
Turns out the default page size of the table component is 10. It is controlled by pageSize parameter. I could not locate any documentation on how to turn off paging altogether. In the code it looks like any negative value should result in rendering only one (possible long) page.

I am not sure if we should increase the default to some reasonable value (25, 50?) or just set it to -1 on the tables that we pretty much know are not going to have many entries (Gateways, Dial Plans).

I do not think there is a way to change the default globally (it's a static constant). So it looks like we are have to touch the code on all the pages...

Tuesday, March 01, 2005
 
autowire mode for spring beans and unit testing
I was playing with several ways of setting up 2 slightly different Spring application context. One for Unit testing, another for real application. I guess classical way of doing it is to split bean factory xml into 3 parts - one that is common, the second that is used in unit test only, and the third one used in application only.
However in some cases when application context for unit test can be a subset of real application context, one can use autowire trick. Setting bean autowire attribute to byType will cause Spring to locate the singletons of a given type to initialize bean properties automatically. If there is more than one candidate Spring will complain. However if there are none, no error is reported and the property remains uninitialized.
We could employ this trick by defining "application only" beans (for example beans than need JNDI) in a separate file and include this file only in real application context. Unit test application context will not find it and as a result some bean properties in common files remain unset (null). You can either mock them, or ignore the fact that they are null if they are not needed.
I have some misgivings about using autowire mode in general, but something has to be said about more concise bean definition. For example one does not have to explicitly initialize hibernate session in each DAO.


Powered by Blogger