I managed to get a number of problems solved this weekend, mostly dealing with the factory model application. My number one priority was to create a search facility for the factory web application. I am still using apache Solr as a webservice for the search.
Last Wednesday I tried to create a Vaadin addon that would use a Solr backend to create a search widget. This was my first real addon, and perhaps I should have tried something simpler as a first attempt. I did get a lot of experience in debugging the addons. The basic addon project template wants to use Jetty as the web server for the server side code, which sort of disrupts the normal flow. In order to run the addon in the GWT shell, you first have to deploy it. I'm not sure what that buys me, as normally I would use the GWT shell's built-in Tomcat server. Perhaps at some point I will switch the configuration back to using the built-in Tomcat, but for now I just left it as it is, trying not to change too much in the project it setup for me.
The Vaadin addon was based on GWT's SearchBox and SearchOracle, which I have used successfully in the past for this kind of search. The SearchOracle has callbacks that are invoked whenever a key is pressed in the search box to provide a list of matches that is refined as the user types. It uses the Solr webapp directly via GWT's requestBuilder utility class. The only issue was that the request always returned a status of 0 rather than a status of 200 or some other normal HTTP code. Googling that situation only lead to sites that indicate that status 0 is a reasonable code only if the protocol is something other than http or https. I could see the query in the Solr log, so I was certain that 1) the request was http 2) the request was making it to the server and 3) the server was returning 200. My working theory is that Vaadin somehow messes with the workings of the requestBuilder, which relys on ajax calls to fulfill the request. I posted a question on the Vaadin forum but have yet to receive a response. A new theory that I'm just now realizing is that SOP (same origin policy) is interfering, since the Solr service is running on a different port than the Vaadin test server. I will follow up on that after I post.
Taking a different approach on Saturday, I tried creating a search widget using standard Vaadin components, and having the search running on the server side. The disadvantage of that is that there is an extra http call introduced per keystroke. Since Vaadin doesn't have anything similar to the SearchBox/SearchOracle, I would have to create a composite widget that would combine a text field and a list box. The only hard part is that I need the list box to pop up as soon as the user started typing, and disappear when the user selected something. I toggled the visible flag to make it appear/disappear, but it would displace the rest of the form, and I needed it to pop up over the rest of the form. Vaadin doesn't seem to provide a simple pop up, only one that's formatted as a window, with a title bar and other unwanted formatting. To do what I wanted and work within the Vaadin framework, I need to use CSS.
It was time to bite the bullet and introduce 'themes' to my application. Themes is the Vaadin way of adding CSS and images to a webapp. If you don't have a theme, a standard one is used without any intervention. Adding a theme requires that you pull the standard theme out of the Vaadin jar, and put it into your project, so that your new theme can derive from the standard theme. Then you set your application to use the theme with the setTheme method.
Themes go in a specific folder 'VAADIN/themes' and contain at least one stylesheet 'styles.css' (don't forget to make it plural, I had some trouble when Vaadin couldn't find it because it was named style.css). To add styles to a component you use the addStyleName method which will add your style to the list of styles. I created styles for the composite box, the text field, the list and a button. I also tried to include a label for the text field. That was one of my first issues, Vaadin always puts labels above the text field, and I wanted it next to the field. Using the Chrome developers tools I was able to inspect the DOM and found that Vaadin wraps almost everything in <div> tags, which stack by default. After being unable to figure out how to get the label in a <span> tag, I discovered that CSS now can override the <div> tag's stacking behavior with the 'inline' display attribute. When they still stacked after setting the tags to be inline, I realized that the enclosing space wasn't large enough, so I had to set that. Then on to trying to get the pop up list to not effect the rest of the form. That is done by setting the positioning to be absolute, and positioning it relative to the enclosing box. After a few hours of trial and error, I finally managed to get something halfway presentable.
Now I can go on a tangent about what a mess the state of CSS is in. If there's a reason that good web programmers are in such demand, it's because of the steep learning curve to overcome in using HTML and CSS to create decent web pages. The WYSIWIG designers produce horrendous code that is all but in-decipherable and almost completely unmaintainable, so unless you're working on a one-off project, steer clear. The reason is it's incredibly difficult to translate a reasonable graphical layout to consistent CSS/HTML, while overcoming all the browser quirks. It still requires the time of a skilled web programmer to create a rational structure that can be understood and maintained. So I continue to increase my skills in CSS because there's no way out of it. Even with GWT or Vaadin, there's no good way to program yourself out of dealing with CSS.
Saturday I finished getting the search box to display a basic query, and left it at that. There still was a process issue, my stack now has all these components, web services, database, Solr search service. I need some way of coordinating all those components. Additionally, the Solr search service wasn't configured correctly, so it was only returning a subset of items.
This morning, I focused on those two issues. First of all the Solr search service. A wide open search was only returning a small subset of what it was supposed to. Looking at the subset, I could tell that they were only indexing stockrooms and shops, which are both derived from 'internal organization'. That happened to be the last entity described in the DataImportHandler database config xml. The problem was that it was using the id field as a unique key across all types. At least with the MySQL implementation, and the standard DDL generated by JPA, the id was not unique across types, so the part table had id's 1, 2, 3... and the internalorganization table had id's 1, 2, 3... as well. I had to create a key that was unique across the whole database. The solution was to create a special field in the select: "concat(id,'-type') idtype" substituting the actual type for type in '-type'. That created a field called idtype which I could use for all entities.
The second issue I solved was one of process. I needed a process that would encapsulate creating the database, loading data, deploying the webservice API and the seach service. I have been evolving my thinking on Maven as a build tool. While it still is the only tool I would consider for putting together 'things', it is sorely deficient on encapsulating 'actions'. Each POM is focused on creating a 'thing'. When you need it to perform some action that is above an beyond what is needed for creating a thing, you are cutting against the grain. So I'm back to my old friend Ant to perform the actions that I need done once all my artifacts are created. I had an Ant script that I used to startup the search service, that seemed like a good place to start. There are a set of Maven Ant tasks that allow you to use artifacts in a Maven repository in a fileset and a classpath. I used both, as I used the classpath generated by my ERPLoader module to run the database loader step, and I used the fileset of the ERPWebservice module to copy the war file to the Solr instance of Jetty. Now my process was performed with a single ant build.
As my thinking has evolved with Maven, I have been looking at other build tools, most notably Buildr. There has been a lot of enthusiasm with Buildr, especially it's simplicity compared with Ant and Maven. But I have a real problem with having to learn yet another expression language (Ruby) just to do what I'm already comfortable with. I suppose it makes sense for a Ruby programmer to use Buildr, especially for simple cases. However, in addition to the problem I have with it being in Ruby, there are two other issues that that make me favor Maven in most cases and Ant in the remaining cases. Firstly, Ruby may be simpler for people to read, but it's not simpler for computers. Secondly, (and Ant suffers from this too) it is procedural, rather than descriptive, so it's much harder for third party products to infer anything from them. These two things mean that all the Maven adaptive applications such as Netbeans and Hudson, are less able to adapt to Buildr builds and Ant builds. Things such as dependency maintenance are a breeze using Netbeans, using point-and-click tools to find and configure my dependencies. In this respect, Ant and Buildr are too flexible for their own good, while Maven with it's admittedly rigid structure shines. I think the trick to using Maven and not falling into the hole of mile long pom files, is to separate out actions that are intended to build artifacts with actions that are intended to use artifacts. Use Maven to build artifacts, but use Ant or some other scripting language when you're in use mode, since the act of building tends to be pretty straight forward, but the act of using is much more open-ended, and requires a lot more flexibility.
No comments:
Post a Comment