GWT Talk at the Boulder Denver New Tech Meetup tonight

I presented on the Google Web Toolkit at the Boulder Denver New Tech Meetup tonight (presentation and useful links). It was a rush, as presentations always are. However, the adrenaline was compounded by two factors: the length of the presentation and the composition of the audience.

To present something as large in scope as GWT in 5 minutes was difficult. Though I’d been to 3 previous meetups, I didn’t have a good feel for the technical knowledge of the audience, so I aimed to keep the presentation high level. (The audience, on this particular night, was about 50/50 split between coders and non coders, as determined by a show of hands. However, almost everyone knew the acronym AJAX and what it meant.) This lack of knowledge compounded the difficulty, but I still feel I got across some of the benefits of GWT.

I’ll be writing more about what I learned about GWT in preparing for this, but I wanted to answer 3 questions posed to me that I didn’t have off the cuff answers for tonight.

1. Who is using GWT?

I looked and couldn’t find a good list. This list is the best I could do, along with this GWT Groups post. I find it rather astonishing that there’s not a better list out there, as the above list was missing some big ones (Timepedia’s Chronoscope, the Lombardi Blueprint system) as well as my own client: Colorado HomeFinder.

2. How much time does the compilation process add?

I guessed on this tonight but guessed too high. I said it was on the order of 30 seconds to a minute. On my laptop (2 cpu/2 ghz/2 gb of ram box) GWT compilation takes ~7 seconds to build incrementally (from ant, which appears to add ~2 seconds to all of these numbers) and ~21 seconds to build after all classes and artifacts have been deleted. This is for 7400 lines of code.

3. How does GWT compare to other frameworks like Dojo and YUI?

I punted on this one when perhaps I should not have. From what I can tell, GWT attacks adding dynamic behavior to web pages in a fundamentally different way. Dojo and YUI (from what I know of them) are about adding behavior to existing widgets on a page. GWT is about adding objects to a page, which may or may not be attached to existing widgets. I’ll not say more, as I don’t have the experience with other toolkits to speak authoritatively.

Also, here’s an AJAX toolkit comparison that I found.

Technorati Tags: ,


BatchUpdateException using Hibernate and MySQL5

I ran into a crazy error last week. One of my clients was upgrading from MySQL4 to MySQL5. The application in question was using Hibernate 3.2. Here’s the table structure, and the hibernate bean definition. See if you can spot the issue:

mysql> desc stat;
+--------------+-------------+------+-----+---------------------+-------+
| Field        | Type        | Null | Key | Default             | Extra |
+--------------+-------------+------+-----+---------------------+-------+
| stat_date    | date        |      | PRI | 0000-00-00          |       |
| stat_type    | varchar(50) |      | PRI |                     |       |
| stat_count   | int(11)     | YES  |     | NULL                |       |
| last_updated | datetime    |      |     | 0000-00-00 00:00:00 |       |
+--------------+-------------+------+-----+---------------------+-------+
4 rows in set (0.00 sec)

<class name="com.foo.common.data.Statistic" table="stat" lazy="false">
<cache usage="read-write"/>
<composite-id name="statisticId" class="com.foo.common.data.StatisticId">
<key-property name="date" type="java.util.Date" column="stat_date"/>
<key-property name="type" column="stat_type"/>
</composite-id>
<property name="count" column="stat_count"/>
<property name="lastUpdated" type="java.util.Date" column="last_updated" />
</class>

The exception stack trace I was seeing was something like this:

2007-12-31 14:15:09,888 ERROR [Thread-14] def.AbstractFlushingEventListener (AbstractFlushingEventListener.java:301)

- Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:249)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:235)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:139)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
....
Caused by: java.sql.BatchUpdateException: Duplicate key or integrity constraint
violation message from server: "Duplicate entry '2007-12-31-stattype' for key 1"
at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1492)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeBatch(NewProxyPreparedStatement.java:1723)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:242)
... 57 more

I ended up turning on the mysql logging (the log setting in the my.ini file, which logs all sql statements mysql makes) to see what was happening.

Basically, I was looking to see if an entry in the stat table existed; if it did, increment and update, if it did not, insert. And the insert was always happening, so the entry was not found--it did exist because mysql threw the 'integrity constraint' exception.

The cause of the issue was the date type of stat_date and the fact that I incorrectly mapped it to java.util.Date. It really should have been mapped to java.sql.Date. How this worked in mysql4 is beyond me, but it did. Changing the hibernate dialect to mysql5 had no impact.

Technorati Tags: ,


The ant jar task and duplicate files can cause bizarre behavior and missing/incorrect files when unzipping

I just ran into some bizarre behavior. I’m building a web application on Windows XPSP2, using Ant 1.6.1. The application worked fine. Then, I added one more copy instruction, to move a GWT component I’d just added to the appropriate place in the war file. Suddenly, the application ceased to work.

After a few hours of tracking down the issue, I found that it didn’t matter whether it was the new GWT component or an old one; it didn’t matter whether the copy went to the same directory or a new one–simply adding the new set of files caused the issue. Then I noticed that the unzipped version of the application differed. In particular, the configuration files differed. That explained why the application wasn’t working–it wasn’t configured correctly.

But, why were the configuration files different?

I examined the generated jar file. When I unjarred it, the configuration files were correct. I was using the jar command, whereas the ant script was using unzip. I made sure the jar file was copied correctly. I made sure the old directory was deleted, and that the ant unzip task would overwrite existing files. Still, no fix–I was seeing the incorrect configuration files.

Then, this part of the jar task documentation jumped out at me:

Please note that the zip format allows multiple files of the same fully-qualified name to exist within a single archive. This has been documented as causing various problems for unsuspecting users. If you wish to avoid this behavior you must set the duplicate attribute to a value other than its default, “add”.

The other possible values for the duplicate attribute to the jar task listed are “fail” and “preserve”. It doesn’t explain what the other options actually do; “fail” causes the jar task to fail when duplicate files are encountered. This seems to be sane default behavior, and I’m not sure why it’s not the case. “preserve” seems to preserve the first file added, and doesn’t add duplicates, but doesn’t tell you that duplicates exist.

Update, 2:09:   “preserve” does tell you that duplicates exist, in this form: WEB-INF/web.xml already added, skipping

I had, for a variety of reasons, a jar task that was adding two sets of the configuration files, with the same names and paths, to the war file. Something about adding a few extra files seemed to flip a switch, and change existing behavior. Whereas before, the unzip task picked the correct configuration file, now the unzip task picked the incorrect file. I don’t know more than that, because I didn’t dig down into the source.

The answer is to move the correct files to the top of the jar task, and change the “duplicate” attribute to be “preserve”.

I hope this post saves someone a few hours of banging their head.

Technorati Tags: , , ,


GWT impressions

After about a year of working with GWT, it seems to me like there are two places where it is really useful as a technology:

  1. Quickly building relatively sophisticated user interfaces for entire web based applications. An intranet ‘client-server’ type application, like a timesheet, would be a perfect fit. If you use Java on the server side, domain objects can even be shared.
  2. Building small widgets that have anything beyond the simplest logic. This is the best way to integrate GWT into an existing application–add small bits of functionality that improve the user experience. You can use GWT to manage, reuse and package this logic.

However, what GWT is best for is not the limiting factor for GWT; rather, if you aren’t a Java developer, GWT just doesn’t make sense. (I’m ignoring the fact that if a user doesn’t have JavaScript enabled, GWT doesn’t make sense, since this is a failing of almost all the Web 2.0 rich user interface toolkits).

For me, being a Java developer and a fan of Eclipse, GWT is a natural fit for a number of reasons. The Java object serialization support, the use of an IDE to code Javascript, the JRE emulation, and the event driven user interface model all make it extremely comfortable to develop in the language. If you’re already coding the server side in Java, GWT is one less language to learn (until you need to do something that isn’t provided for in the emulation libraries, or you need to use a Java 1.5 feature, or a bug leaks up through the abstraction; of course, these problems will never happen).

While I don’t have deep knowledge with other toolkits (I’ve worked slightly with the Yahoo! User Inteface Library and have toyed with Dojo), it seems to me that many many folks can get by using them; there’s no tie to Java.

If someone was going to ask me whether or not they should use GWT, I’d boil it down to the following questions:

  1. Are your developers familiar with Java? (If ‘no’, don’t use GWT.)
  2. Are your developers familiar with JavaScript? (If ‘yes’, consider not using GWT.)
  3. Are you integrating with an existing app? (If ‘yes’, GWT might be a good fit.)
  4. If so, are you planning to ‘web 2.0’-ify the existing application, or add widgets to enhance existing functionality? (If planning to ‘web 2.0’-ify existing functionality, don’t use GWT.)

On a final note, I don’t want to bag on GWT too much. GWT has improved tremendously over the past year or so, and I’m very glad to have used it. I think it’s quite cool tech, and I think it has really improved the user experience on my client’s site.

Thank you, Google, for releasing GWT and making it available for me to use.


Connecting PHP and Java

Have you ever had a project written primarily in PHP, but there were some java systems that you wanted to connect to? Perhaps there was a third party library or a java API that you really want (or are required) to use, but PHP had been chosen for other reasons.

The php java bridge is your solution. The documentation is good, and the performance is pretty darn good (if you’re looking for benchmarks, search for ‘How fast is it?’). You can use the bridge over sockets, a xml based protocol via servlets, or over a mono application. The mailing list is active, and it looks like the primary developer actually answers questions on said list (as of May 2007).

I’ve always been a bit hesitant regarding cross language programming: “Great, now I get to debug in two languages that communicate via sockets! Yahoo!”. But for a certain set of circumstances, using this bridge can be the right answer.

Technorati Tags: , , ,



Using Excel to ease Java i18n processes

Ah, the perils of reading Bloglines before going to sleep. (I’ll just catch up on one more blog…)
I gave a BJUG talk 18 months ago about large websites and internationalization (i18n). (Links and powerpoint here.) The talk was based on my experiences of a smooth operation, created and executed by Zia Consulting.

A crucial part of this i18n process was creating and moving around Excel files containing keys and translations. In addition, there was an Access database and a VB script that converted the keys and translations to properties files. The reason to do this is that the typical Java developer wants to use ResourceBundles for i18n, which typically involves properties files. And the typical translator is much more comfortable with Excel. So, Zia built a process which bridged that gap.

It looks like someone else solved the same problem with translators and Excel files, and open sourced the solution.

Via Rickard.

Updated 2/16, fixed typo and a small formatting change.

Technorati Tags: ,


MolhadoRef: A refactoring-aware version control system

This past Thursday, I went to one of the CU Comp Sci Colloquia. The speaker was Danny Dig, and he discussed Refactoring-Aware Software Merging and Version Control for Object-Oriented Programs, in particular, MolhadoRef. Mr Dig billed this several times as the first refactoring aware source control system ‘that we are aware of’.

Being relatively new to IDEs in general and Eclipse in particular, I find that the automatic refactoring is one of the largest productivity enhancements that I’ve discovered. The ability to almost effortlessly change a variable name to more accurately reflect its purpose, and to know that such a change will propagate everywhere it is used, lets you update variable names more often. I was recently editing a piece of PHP code and one of the variables had changed slightly in purpose. I could have done a search and replace, but I wouldn’t be positive that the changes hadn’t broken something subtle. With Eclipse, there’s no such hesitation.

This is almost worth the cost of having to use the mouse and not being able to use vi keystrokes (at least, without the vi plugin). But when you throw in the other refactorings, including move method and rename method, well, refactoring becomes invaluable.

What follows are my notes from the talk.

Mr Dig discussed how refactoring is becoming more prevalent in todays development environments, and how this is challenging text based version control systems such as CVS and SVN. The main issues are that refactoring causes global changes, while version control systems excel at tracking local changes. In addition, refactoring impacts program elements, while version control systems focus on files. In short, refactorings are more likely than normal edits to create conflicts and/or merge errors–due to refactoring tools, changes are regularly no longer limited to files.

In addition, when you move members between classes, you can lose version history–the only connection back to the original location is a commit comment, which is neither dependable nor robust.

MolhadoRef aims to change this, by making the version control system become refactoring aware. Currently MolhadoRef exists in ‘research project’ form as an Eclipse plugin, and is part of Mr Dig’s PhD thesis work. (By ‘research form’, I think he means not ready for prime time. For example, in his demo, when you checked changes in, there was no support for a commit message.) There are plans to release it as an open source project, but it is currently not so available. MolhadoRef is based on Molhado, which is an SCM system with support for OO software, on the backend, and Eclipse and a refactoring engine on the front end.

Basically, MolhadoRef can handle API level merging, where ‘API level’ means any member declarations. It also supports normal text edits in the same manner as CVS or SVN. It also tracks compile time as well as runtime merge conflicts.

On checkin, it follows the following algorithm:

  1. Detect API change operations, using a 3 way comparison. They are also tracked with tools such as Catchup or RefactoringCrawler
  2. Detect and resolve conflicts. It attempts to do so in an automated fashion, but sometimes requires user input.
  3. Undo refactorings. Sometimes this is not entirely possible, but if it fails, MolhadoRef is intelligent enough to fall back to a text merge.
  4. Merge text changes. This happens on a method level, not on a file level.
  5. Replay refactorings. This can be hard, because you need to serialize what may have been two parallel series of refactorings. He went into some things I didn’t understand right here, including using graph theory to reorder the refactoring, or making a refactoring into an enhanced refactoring (which not only changes code, but future refactorings in the chain).

Mr Dig conducted a case study and an experiment to prove the effectiveness of MolhadoRef. In the case study, he and a partner developed MolhadoRef separately for 3 weeks, and then merged the changes using both MolhadoRef and CVS. With 1267 lines of changed code, CVS had 36 conflicts, 41 compile errors, 7 runtime errors (determined by unit test coverage), and it took 105 minutes (including human time) to merge the two trees. In contrast, MolhadoRef had 1 conflict, 0 compile and runtime errors, and it took 1 minute to merge. Pretty impressive.

The experiment was to split 10 students (fairly experienced with Eclipse and java) into two groups. Each group had a common task. At the end, the changes made by each person in the first group were merged with the changes made by each person in the second group, producing 25 merge sessions. Using these episodes, using MolhadoRef led to 3.6 times fewer conflicts, 11.6 times fewer compiler errors, and 1.5 fewer runtime errors. In addition, the time to merge was 3.5 times faster with MolhadoRef.

The larger picture that Mr Dig is pursuing is to perform automated upgrades of component based applications (pdf). If you’ve ever upgraded from one version of a java web framework to another, you’ll know how painful it can be, especially if the API has changed. According to Mr Dig, 80% of the API changes in 5 projects he’s examined so far (4 open source, 1 proprietary) were due to refactorings. He told us why MolhadoRef fits into this picture, but I didn’t note it. Bummer.

He did say that both Microsoft and IBM were interested in his work. He also mentioned, I think, that Eclipse has already accepted some of his refactoring code.

/Notes

What does that mean for us developers who don’t use build version control systems? well, not much right now, but if some of the bigger providers start to use this, it means that bigger, longer lived projects can be better managed; that code history won’t be lost as often, and that merge conflicts will decrease in severity and number. I for one can’t wait for that day.

Technorati Tags: ,


Destroying robot generated Tomcat sessions

A large effort goes into creating sites that are crawlable by robots, such as Google, Yahoo! and other search engines. However, these programs can create a large number of sessions, if the site is based on servlet technology. Per the servlet spec (the 2.3 specification, page 50), if a client never joins a session, new sessions will be created for each request.

A session is considered new when it is only a prospective session and has not been established. Because HTTP is a request-response based protocol, an HTTP session is considered to be new until a client joins it. A client joins a session when session tracking information has been returned to the server indicating that a session has been established. Until the client joins a session, it cannot be assumed that the next request from the client will be recognized as part of a session.The session is considered to be new if either of the following is true:

  • The client does not yet know about the session
  • The client chooses not to join a session.

These conditions define the situation where the servlet container has no mechanism by which to associate a request with a previous request.

Since all these extra sessions take up memory, and are long lived, a client asked me to look into a way to invalidate them. (I’m not the first person to run into this problem.) The easiest way to do that was to build a filter that examined the User-Agent HTTP header; here’s a nice list of User-Agent values. If the client was any of the robots, we could safely invalidate the session. For some reason, in with Tomcat 4.1, I needed to run session.isNew(); before running session.invalidate();, otherwise the session wasn’t destroyed. The filter was placed at the end of the request chain, as outlined in this article, by calling chain.doFilter(request, response); before the invalidation filter looked at the request or response.

I haven’t seen any performance problems with creating a session and then throwing it away, probably because java is so good at garbage collecting short lived objects. If I did, conditionally disabling session participation in a JSP might be an option to pursue.


Eclipse and existing CVS modules

On a project I’m working on, we just made the move from local CVS via a windows share to remote CVS via ssh. I’m a big fan of that, because I was seeing some weird behavior from the drive, and because Eclipse doesn’t support local repositories.

The Eclipse/CVS FAQ had some good information, but I had a bit of trouble importing CVS source into a java project (which is important so you get the command line completion, etc).

The easiest way I’ve found to get things working in Eclipse with previously existing CVS modules is to do this:

  • Make sure everything is checked into CVS using command line tools.
  • Open eclipse.
  • Delete the project(s). When it prompts you “Are you sure you want to
    delete project ‘xxx’?” choose “Do not delete contents” and click “Yes”.
  • For each project:
    • On the menu, Go to File/New Project.
    • Choose “Java Project”.
    • Give the project name you’ve used for the module.
    • On the same screen, choose “Create project from existing source”. Put the path of the directory of the previously checked out file.
    • Click finish.

Eclipse is smart enough to connect to CVS by looking in the CVS subdirectories, although you may need to change your project’s CVS settings. I had to change it from the ext to the extssh connection method.

This was with Eclipse version 3.1.2 Build M20060118-1600 on Windows, with cygwin.

Technorati Tags: ,



© Moore Consulting, 2003-2020