Friday, May 29, 2009

Back to Portlet Puzzles

The learning curve for OpenLayers and WCS was temporarily set aside again as I found that I needed to spend more time negotiating the curves in the portlet learning road.

I had the basics down well enough a few months ago when I had managed to develop the application with the SOAP Service Client Portlets. But I had been learning as I went along and I knew that the way I did things in the earlier portlets was different from what I later decided was the right way to do it. And there had been no real in-depth testing done on any of the portlets.

I set out to document a series of test cases that would make it possible for another person to do the testing. It was difficult enough to start something from scratch and decide what format to use and how detailed to make the instructions. Then as I came up with explanations and procedures I realized that there were things that I myself didn't understand very well on how they worked. Some test cases that I hadn't thought of before showed errors in my original logic. And there were cases where I had chosen to use shortcuts and display less than what was actually available as data from the service. I knew I had to spend some time refactoring the code.

Of course, whenever you start to make changes in your code it always turns out to take longer than what you planned. And when it comes to portlets there are many parts of development that I still don't understand. But after this week's efforts I can say that I finally have a better understanding of the portlet lifecycle and how to properly use the various classes and objects that are needed for portlets like the SOAP Service Client Portlets, which are primarily used to gather form data from the user and return data results for display.

I had used a lot of examples over the past year to further my learning. Some examples came from sources that were being used to illustrate the new features of JSR 286. I probably shouldn't have started with those before I had a really good understanding of JSR 168. That caused confusion by making things more complicated than the simple cases I was trying to solve.

Not until this week did I understand when I should be using getParameter/setParameter as opposed to getAttribute/setAttribute. It was a real revelation to realize that setting render parameters was all that I needed to do in order for the values obtained from the service calls in the processAction method to be available to the doView method. And that what was available in the doView would also be available in the view jsp--there wasn't a need to get the parameters in both places. "getPortletContext().getRequestDispatcher.include(request,response)" had never dawned on me that "include" meant everything was shared between the two.

It took a lot of trial and error and null pointer exceptions but where I ended up getting a lot of extra mileage was once I figured out how to use the setRenderParameters and getParameterMap to pass a whole series of data values. This made possible a total revamping of the Multi-Point GeoidHeight portlet. Whereas before I only displayed a comma-separated list of the answers, I can now display all the information in a nice table form, including original inputs, inputs converted to decimal degrees, the heights and any error messages that are returned. I vaguely remember one of the other portlets I did where I knew this was a feature I needed to incorporate but didn't want to take the time then to figure it out. There's a still a bit of cleanup on Multi-Point GeoidHeight and then I'll be continuing with the other SOAP Service Client Portlets to see what needs fixing/enhancing.

Thursday, May 14, 2009

OpenLayers again

Leaving aside all that I still need to learn about how to download data from a WCS call, I thought that a good place to start would be to make sure I knew how to use an OpenLayers map that would allow a user to draw a bounding box rectangle and then have the javascript capture the BBOX coordinates. I could see such functionality in action on a couple of sites and thought it would be fairly straightforward.

It was almost a full day's work to find an example. I get frustrated paging through all the http://www.openlayers.org/dev/examples/. A lot of them don't work or, if they do work, it's not clear what you have to do to get them to work and what it is that you are supposed to see when you use them. The list changes rapidly and when I'm looking for something in particular I start at the top of the list and work my way down and usually run out of time or patience before I get to the bottom. This time I decided to start at the bottom of the list.

As well as looking at the examples on the OpenLayers site, I thought I would try some Google queries, too. That turned up some interesting information, but nothing that was what I was specifically looking for. In this particular instance those searches, combined with the decision to start at the bottom of the OpenLayers list, caused me to lose a lot of time. I finally found what I was looking for near the top of the list of OpenLayers examples. I shouldn't look at it as lost time, I suppose, because I learned new things along the way.

In any case, using a combination of ideas from custom-control.html and custom-control-point.html (that one doesn't even display the map when you look at it on the OpenLayers site) I created a BBOX1.html with the basic functionality that I wanted. The user can use the shift-click (and where is this documented in OpenLayers?) to draw a bounding box. When the mouse is released the BBOX coordinates display in the area below the map. Not very useful, in and of itself, but it's a big step because now I can capture those coordinates and use them when I'm to the point of building the URL to make the WCS call.

But today we have a new problem. A common approach in the OpenLayers examples, and the one being used in BBOX1.html, is to create an init() function that does the work of creating the map object with the base layers and controls and events that then gets called from onload() in the body tag. That's all well and good for a normal web page, but it doesn't work in the portlet world, which is where I'm playing.

Since portlets are fragments of HTML markup you cannot use the head, title, or body tags. Those tags are under the control of the portlet container. Whenever I use javascript in a portlet I have to make sure that the code is all within the body tag, because that is the only place you can put HTML in a portlet. When I get an OpenLayers example to work I take the code in the init() function and put it all within the body tag, instead of a separate function. I've always wondered if there'd be a situation where that would mess things up.

I made a BBOX2.html file with the init() function removed and all the code put inside the body tag. Unless I'm overlooking an obvious mistake, there are no other differences between the two HTML files. But now when I load the BBOX2.html file in Firefox I get a script error that points me to a line of code that's within the OpenLayers.js file. The code is referring to an element.style object and the error states that "element has no properties." It's next to impossible to follow any flow of code within OpenLayers.js because there's no formatting in the file. And I certainly wouldn't want to make changes to that file. So why does Firefox complain that the element has no properties just because the code is taken out of the head tag and put in the body tag? It makes no sense. Welcome to my OpenLayers world.

Monday, May 11, 2009

From SOAP Service Client Portlets to WCS Map Portlet

I've set aside the SOAP Service Client Portlets for now in favor of investigating the next task on the list. The goal is to build a map portlet that allows a user to select map layers from a WMS, draw a bounding box on the map, and download data from a WCS call. WMS and WCS are Open Geospatial Consortium (OGC) specs for Web Map Service and Web Coverage Service, respectively. And "map portlet" in this project that I'm a part of means having to struggle with my old friend, the OpenLayers JavaScript library.

Months past I struggled with OpenLayers when I was trying to build a Web Feature Service (WFS) client. I got the minimal test case working before I got dragged into other things. Wouldn't you know it, though, there's a whole new set of things to understand about WCS. I'd worked some with WMS and had the basic idea of that one, but I hadn't really paid any attention to WCS. I tried to get back into the mode of those two things by starting with some sample data sets. Surely there had to be some WMS and WCS sample data somewhere out on the Web.

What a tangled mess it is in the world of GIS data. Some things, including the Scott Davis "GIS for Web Developers", are excellent resources to a certain level but just when you need the key thing of "where is some data I can use in an OpenLayers call" you find out that the information is no longer current. Or the supposed map server is down. Or there is some layer that GAIA actually finds, but then it won't show anything because the zoom is wrong or some other inexplicable error.

I've learned way more in three days at this than I think my head can handle. I went back to playing around some more with GeoServer 1.7.0 that I had installed once before. That was explained well in the Scott Davis' book and provided a lot of insight. But it was an older version and talked about the Mapbuilder client, which is now replaced by an OpenLayers client. I hope I don't have to go to the extent of having my own functional OGC server just to get some sample WCS data to play with.

Some developers on my team have done work in this area and I was pointed to a couple of sample OpenLayers calls. But the only way to get the calls to actually return the data is to have a CAC-enabled workstation, which my laptop is not. Going back and forth between my laptop and a machine on another network where I can use the CAC helped me to make some headway. I hope to get either a CAC reader on my laptop or to find some WWW WCS data that I can use.

And, of course, there's a hassle everytime I have to add something to my basic OpenLayers map. I wasn't able to find the syntax error in the WCS call until a developer on my team said he used Firebug and it returned an exception saying the a map.setCenter call was needed. I never saw that when I was using Firebug--don't know why it didn't show up for me.

Unfortunately, when I go back and forth with the 2 systems I run into the problem that the CAC-enabled system does not have Firefox installed and security restraints prevent the installation of any software on that machine. Hence, using Firebug for debugging on my laptop is helpful but then IE7 on the other machine doesn't always agree with Firefox as to what is allowable JavaScript code. I was pointed to Visual Web Developer to debug IE issues. Something else I'll need to learn. Good thing I'm not opposed to learning new stuff. It never ends in this job.

Wednesday, May 6, 2009

Scaled Back Geographic Translator Service

I had to scale back quite a bit from what the sample web client offers for Geographic Translator Service but I think I finally got it all working as a portlet. At least the concept is there now and someone could expand the 5 possible coordinate systems the portlet offers back to the 36 offered by the service if it proves to be a useful portlet.

I had to learn some things about CSS in order to get a dynamic display of the proper input fields needed for whichever coordinate system the user selects from the pulldown. I ended up going back to the method of using separate divs for each group of form fields AND putting a form in each div. That last part is the key concept I missed when I tried doing it that way the first time.

Copying sample code from the Internet when you don't really understand something has its own hazards. In this case, I was copying the example that gave me the clue about the form within the div but it had a lot of extra CSS attributes that the other example didn't have. And my knowledge of CSS is very limited. I can say, though, that after the struggles to get it to work I know more now about CSS than when I started. In particular, the difference between "display" and "visibility" and why to use one rather than the other.

The really amusing CSS goof resulted because the example I started with used absolute positioning, which I didn't know enough about to change. When I thought everything was ready to test out I was about to give up in despair again when I used the pulldown with the onClick and I still didn't see the divs get changed to display the fields of the form. I tried pulling all the code out of the JSP and putting it into a separate HTML file. When I did it that way it would work.

So what was preventing the divs from displaying when the code was part of the portlet?
Suddenly, during one of the display attempts my eyes were drawn to the top of the portal page. I haven't been seeing the top of the portal page for awhile because as the list of finished portlets grows the one I'm currently working on gets pushed to the bottom of the page. But there up at the top, overlaid on the Geoid Height portlet, was the missing div! I thought at first it was an issue with not having used portlet namespace tags and was ready to go back and add all that nonsense like I had to do for the OpenLayers map portlet. But it turned out the problem was with the absolute positioning within the style attribute. Once I removed all of that and let it use the default (position within the normal flow of the page) the problem went away.

There were still other problems to solve, including how to get the correct default values to display for each of the div sets. I think it was during these struggles that I finally had to cut back on all the parameters and quit trying to reuse the same names within each set. I know it's not very efficient to have different variable names for each of the coordinate value fields. There's probably some way to make use of arrays and if this portlet is to grow back up to the scale of offering 36 different coordinate systems that could probably be solved. But for now I think it's OK and it gives the basic sense of what the portlet is doing.

As usual, I've run out of steam when I think of what's left to do for giving it a thorough testing. The challenge I will deal with next is to remove from the project the extra portlet that I had created when I first started Geographic Translator and thought I was going to need a portlet that would allow the user to look up the meaning of the RESTful interface cryptic parameter strings. A couple of weeks ago I had made the mistake of creating a test portlet in the project that I later wanted to delete. Trying to delete and clean up completely what gets created when a portlet is added to the project turned out to be a non-trivial task. I learned from that experience to create a test portlet within a separate test project where I could delete the whole project when the test was done. But now that there's an unneeded portlet in this project I get to go through the "delete and clean" exercise again. There should be an easier way.

Saturday, May 2, 2009

Getting Nowhere Fast

I seem to be getting nowhere fast with the Geographic Translator Web Service client. Once everything was fixed to account for the fact that the services WSDL URL had changed, I realized that the confusing instructions on how to pass parameters to the translator service that I had spent days trying to understand was not meant to be the way to call the service. The posted client and instructions I had been looking at were created to provide a method of testing the RESTful interface to the web service.

As part of the new server that went online to host the SOAP services, the developer posted a sample client for the Geographic Translator Service that was a more familiar way to collect input from the user. Each piece of the input was its own textbox or pulldown menu, instead of several cryptic strings of coded letters and numbers separated by an exclamation point. I had wondered why the data would be input that way only to then have to be parsed apart in order to set up the individual parameter fields in the web service call. Being able to see this version of a web client in action really helped clarify what was going on with the service.

But changing that horse in midstream led to a new difficulty. When a user selects which one of the 36 coordinate systems that will be used as the input system for the transformation, that changes the number and type of parameters that must be entered to represent the coordinate. The HTML page needs to change dynamically to present the user with the correct entry fields after the coordinate system selection is made.

I thought that I had come up with a solution by making use of div tags and some Javascript that would display or not display the appropriate div after the user selected the coordinate system from a pulldown. To get a feel for how it would work I started small by limiting the possible coordinate systems to just 5 of the 36. It took awhile to get the divs set up the way that looked best and, even then, I was stumped on how to get any of them, except the first, to change style when displayed to align the input parameters to the right.

Getting the alignment to look nice turned out to be the least of my problems. It was when I decided they looked good enough and went to the next step of actually submitting the data that I could see it wouldn't work. I had wanted to use the same names for the input fields in each of the divs and only have one form. But after several fruitless attempts to try to get the right data to be passed in to the right fields after the coordinate system was changed I decided that it could not be done that way. After the submission of the form it appears that the server does not make a distinction between parameters that are named the same thing but are in different divs within the same form.

The only way I could think to do it next, was to start all over with a redesign where I would have a separate JSP page for each of the different coordinate systems. It was tedious work starting over and copying and pasting to make the set of JSP pages. And not the best solution because I could see there was a lot of duplicate code. But at least I was getting the right data in when I ran through the first test. It was when I selected the pulldown to choose a different coordinate system that I realized the fallacy of my thinking. I had a JSP page ready and waiting to display for that next coordinate system but what was going to trigger the display of that page? A Javascript function that was called by an onClick in the select tag had enabled the display of the div in the method I had used before. But now without the Javascript there was nothing to dynamically change the HTML and nothing to rerender the portlet so that the doView would get called to display the proper JSP page.

What to try next? I wonder if I could make use of what's there and just figure out a way to fit in a renderURL call because that would call the doView method. Would I put a link somewhere for the user to click, sort of like when I had the "Back" functionality in one of the portlets? Or should I start over and make a beginning page where the user first selects the coordinate system as a link that loads the correct JSP page?

While looking for some more ideas on the Internet I stumbled on an example that has dynamic HTML to hide and show a div like what I had earlier. I wish I had seen this example instead of the one I followed. This one has a form within each of the divs. I bet mine would have worked if I had done it that way instead of trying to just have a single form and use the divs to separate out the parameter fields. Usually when I try something and it doesn't work I make a copy of it, just in case. But, wouldn't you know, this time I did not save any of what I had when I was trying to use the Javascript with the div tags. Enough for one day. Maybe my thoughts will fall into place and give me the proper solution the next time that I look at it.