Extending Tomcat WebappLoader to Share Library jars

16. March, 2010

If you’re like me and use Tomcat and you want to bring down the size of your WAR, you’re faced with one issue: All your applications need to use the same libraries (since there is only a single common/lib for everyone). So you’re either stuck with an old version or you need to upgrade all your apps at the same time. I just can see the budget guys shake their heads.

The solution is a list of directories in your context.xml which contain specific versions of the libraries you need. This way, you can install all the versions you need and each app can pick and choose.

For the complete solution, see the original article: Extending Tomcat WebappLoader to Share Library jars

OSS for teh win! 🙂


Finding unindexed foreign key columns

15. December, 2009

If you’re using Oracle and you have tables with foreign keys, then you must remember to add indexes to all the columns in the referenced tables (i.e. the foreign tables). If your schema has more than two tables, it’s hard to make sure all the necessary indexes exist. Fret no more and let Oracle do (most of) the work for you:

select table_name, constraint_name,
       cname1 || nvl2(cname2,','||cname2,null) ||
       nvl2(cname3,','||cname3,null) || nvl2(cname4,','||cname4,null) ||
       nvl2(cname5,','||cname5,null) || nvl2(cname6,','||cname6,null) ||
       nvl2(cname7,','||cname7,null) || nvl2(cname8,','||cname8,null)
              columns
    from ( select b.table_name,
                  b.constraint_name,
                  max(decode( position, 1, column_name, null )) cname1,
                  max(decode( position, 2, column_name, null )) cname2,
                  max(decode( position, 3, column_name, null )) cname3,
                  max(decode( position, 4, column_name, null )) cname4,
                  max(decode( position, 5, column_name, null )) cname5,
                  max(decode( position, 6, column_name, null )) cname6,
                  max(decode( position, 7, column_name, null )) cname7,
                  max(decode( position, 8, column_name, null )) cname8,
                  count(*) col_cnt
             from (select substr(table_name,1,30) table_name,
                          substr(constraint_name,1,30) constraint_name,
                          substr(column_name,1,30) column_name,
                          position
                     from sys.user_cons_columns ) a,
                  sys.user_constraints b
            where a.constraint_name = b.constraint_name
              and b.constraint_type = 'R'
            group by b.table_name, b.constraint_name
         ) cons
   where col_cnt > ALL
           ( select count(*)
               from sys.user_ind_columns i
              where i.table_name = cons.table_name
                and i.column_name in (cname1, cname2, cname3, cname4,
                                      cname5, cname6, cname7, cname8 )
                and i.column_position <= cons.col_cnt
              group by i.index_name
           )

Isn’t it a beauty? Thanks to Tom.


Why WYSIWYG doesn’t work II

7. December, 2009

In my old post “The Space Between Two Characters“, I wrote about some flaws of WYSIWYG. Since then, I got some feedback.

The real issue behind the issues with WYSIWYG is that it doesn’t work while you edit the document. The concept is flawed, not the implementation. It is flawed because it omits some vital information that you need for editing. The information is omitted because it doesn’t make sense anymore as soon as you print the document on paper. And WYSIWYG means “if you don’t see it, you won’t get it.”

So it makes sense to omit feedback on where ranges start and end, what kind of break follows after a line, there the handles for a table are. But most WYSIWYG editors today have a “show invisible” option. Word can show you all those invisible characters so you can see “oh, this is a tab and not a space”.

For this to work, we need a tight integration between the editor model, the renderer and the view. The problem here is, as usual, performance. If you add all the hooks you need to be able to show nice visual feedback in the view, printing to a printer will be slower.

How much? Well, not much. Anymore. You’re quadcore will be 95% bored. It will need memory. How much? Well, to remember the bounding boxes for all letters rendered on the screen takes at most 4’608’000 bytes (“i”, 8px font, 30″ display with 3840×1200). That might seem like a lot but almost no PC sold next year will have less then 4GB of RAM, not even the Netbooks. My mobile phone comes with 32GB!

For printing, the values are usually much smaller. A normal page of text has around 1’500 to 2’500 characters per page and for printing, you just need to remember the current and maybe the next page (unless you need a page count but with todays CPUs, you can layout the pages twice).

So the final obstacles is code complexity. OO has helped a lot to cut down complexity in algorithms but there are problems which you can’t solve nicely with OO, for example “run this algorithm but replace line 5 with …” or “before … run …”.

AOP has come to solve this but it has failed to deliver so far. Maybe this is because point-cuts are too complicated to formulate, maybe because the debuggers can’t handle this case well, maybe because the setup is too complex or the resulting code is too fragile. Or because people are afraid of the leap of faith it takes to use it.