Friday, April 30, 2010

Will Chromium OS improve carbon emissions?

With Google’s Chromium operating system, it is a goal to not have to wait so long to have a usable machine once you power it on. In fact the goal is seven seconds from the time you push the “on” button, to being able to access the internet (which is where Google wishes all your apps to live).

Hmmm. Seven seconds to being in a usable state. Can I have all my apps and windows where I left them too? Can I run all my developer tools yet? Ok, this is going to take some time to get there. But when we do, I might actually start turning off my computer(s) and emitting less carbon.

Setting this kind of standard, making the PC more of an “appliance” in a sense, could have a small impact on carbon emissions in the world. Cool.

Hey Microsoft, where’s your HTML5 browser?

Ok, this is just a rant.

I am really getting annoyed with IE being such a “special case” to deal with. I long for the days when moving an application to the web was the ultimate cross platform solution. Mac, PC, Unix – sure, just point your web browser at it! It runs everywhere!

I’m not telling you anything you don’t already know. Yes, we are sadly returning to wasted time and energy dealing with browser variations, as we once did with PC vs. Mac apps 20 years ago. And dealing with this cross platform issue will become more and more pronounced as richer features on the client side are employed by more and more developers. These richer web apps are only going to grow; I have a new Comet application employing server push, and the client side *really* stinks, just because of IE.

So I appeal to you developers: don’t do it. Don’t include IE! Save your time and energy. Instead, write an awesome app and tell your users to install a browser that keeps up with modern specs. Ok, I know that is insane to ask some users to actually install anything on their machine – there’s no chance. (The EU was right…) But today I stumbled upon someone who told IE to jump in a lake. Clarity Accounting. Bravo, Clarity Accounting!

Hypocritical? I mean, I hate it when a website requires me to use IE for some special thing that only IE does. However, there is a difference. I do not find it terribly unreasonable to expect browsers to comply with a modern specification, like HTML5. So Microsoft, where’s your HTML5 compliant browser? Evidence would suggest that it is not even on your radar.

A year ago at Google I/O, Google really pitched hard developers about all the great rich client stuff you can accomplish in an HTML5 browser. Granted, Google is placing their bets on cloud computing, and having proper platforms to access cloud apps is critical. Thus we see Google’s hands in action with the Chrome Browser, the upcoming Chromium OS (basically everything in a browser), and Android (the other place where we interact with our online life).

So I guess Microsoft is in a real spot. Comply with HTML5 spec, and developers can create rich client apps with easy cross browser compatibility. And those open-spec savvy developers won’t necessarily be using Silverlight.  Now broad user acceptance of cloud applications could reach a tipping point more easily with a better IE.   All those people who know only IE would begin to see new rich client apps developed which run from the cloud. Perhaps that’s a threat worth dragging your feet?

Yes, I am drawing a line connecting the quality of your client experience with cloud computing. And frankly I am ignorant of how well MS Azure stands up to other cloud computing platforms; I am inferring that perhaps Microsoft execs are not ready for (or don’t know if they want to be in) the cloud biz. I just don’t see Microsoft’s rationale to drag their feet on having an HTML5 browser. Surely they have the talent to accomplish it. Or maybe that kind of talent would rather work elsewhere where doing the next obvious cool internet thing is permitted by their employer…?

End rant, back to reality. Now I have to really decide if I can really tell my users to install a better browser for my app. Damn you Microsoft.

Wednesday, April 14, 2010

Public/Private Exposure of your GeoServer

When you setup your GeoServer, you may wish to expose only a portion of it to the public. Namely, in the case of serving “tiles” for an overlay in a google map, you need to permit the public to reach the GeoWebCache, but not permit them to reach the other functionality of GeoServer.

One way to do this is by fronting your Tomcat server with an Apache server and use mod_jk to “mount” only the URLs needed to support tile serving.

The URL used by google maps to grab tiles has the format of:

var url = "http://private:8080/geoserver/gwc/service/gmaps?layers=layer_name&" +
  "zoom=" + zoom + "&x=" + coord.x + "&y=" + coord.y + "&format=image/png";


All the GeoServer functionality exists under  /geoserver/*, so we would like to limit exposure only to /geoserver/gwc/service/gmaps/*.

(A litmus test is loading /geoserver/gwc/demo and seeing if it exists or not. We don’t want this page to load for the public.)


So how to hookup mod_jk between Apache and Tomcat? I will first assume you have a working Apache installation. I am using version 2.x. I will also presume you have a working Tomcat installation with GeoServer installed and functioning.

First, Apache must have the module loaded. (You may have to build mod_jk, which is beyond the scope of this post.) In the httpd.conf file, check for the following line, and add it if it doesn’t exist. There should be a whole list of LoadModule entries together in the httpd.conf.

LoadModule jk_module libexec/apache22/


At the end of the httpd.conf, add the following:

<IfModule jk_module>
# Where to find
# Update this path to match your conf directory location (put
# next to httpd.conf)
JkWorkersFile /your/website/path/etc/apache22/
# Where to put jk shared memory
# Update this path to match your local state directory or logs directory
JkShmFile     /your/website/path/log/mod_jk.shm
# Where to put jk logs
# Update this path to match your logs directory location (put mod_jk.log
# next to access_log)
JkLogFile     /your/website/path/log/mod_jk.log
# Set the jk log level [debug/error/info]
JkLogLevel    info
# Select the timestamp log format
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
## my mod_jk mounts, same for SSL section too
Include etc/apache22/mod_jk_mounts.conf


This sets up apache to use mod_jk and its log files. It also refers to two more important files that you must create. Those two files are mod_jk_mounts.conf and

The mod_jk_mounts.conf file is used to tell Apache what URL patterns to watch for, and if it has a match, it will delegate the work to render the page to a tomcat worker. The file looks like this:

<IfModule jk_module>
# this maps to /geoserver tile server at localhost tomcat
JkMount  /geoserver/gwc/service/gmaps* worker1


Above you see that the URL is the precise URL we need to serve our tiles, i.e. /geoserver/gwc/service/gmaps/*.  So traffic at this URL will get directed to Tomcat’s worker1, which is defined in the next file,, which looks like:

# Define workers using ajp13
# Set properties for worker1 (ajp13)


Apache and Tomcat speak a custom protocol on a custom port. This is the meaning of ajp13 and port 8009. It is also presumed that Tomcat is listening on a localhost address. If not, supply your local (and presumably private!) address above.

Now you should be able to serve tiles from the GeoWebCache via the front-end apache, but not be able to see the other GeoServer functionality.  So now you can use a public URL like this:

var url = "http://publicserver/geoserver/gwc/service/gmaps?layers=layer_name&" +
  "zoom=" + zoom + "&x=" + coord.x + "&y=" + coord.y + "&format=image/png";




It would be nice to also have a super clean URL that obscures the URL that indicates you are using GeoServer. Bu you cannot use the Apache “Alias” configuration to remap the URL because it expects the target path to be a physical path and not a virtual one. I would like to hear if anyone out there has a way to Alias mounted JK paths.

Thursday, April 8, 2010

Tile overlays with Google Maps API v3 and GeoServer

I was introduced to the Google Maps v3 API last May at Google I/O. And I am sadly just getting around to doing something with it beyond the "hello world" example given on their website.

My plan is to serve image overlay tiles from a geoserver backed by a postgresql database with postGIS. Last week I installed postGIS and setup a new database with the postGIS functions. I created a table to import a shapefile w/ supporting files. (I should post some howto details on all that...)

So to get a basic v3 maps running with image tile overlays, the key docs are at:

You can follow the example there first, and get a tiled image overlay working, showing a traffic overlay from google's server. The "tile server" URL format is formed by a function, e.g.
1: function(coord, zoom) {
2:   return "" +
3:     "zoom=" + zoom + "&x=" + coord.x +
4:     "&y=" + coord.y + "&client=google";
5: }

Now, back to the GeoServer side of things.  The key thing I needed to know was what the format of the URL should be to get a raster tile image out of the GeoWebCache. The GeoWebCache docs show the following, which is aimed at v2 google maps API.  (From

To be sure, when I installed GeoServer 2.0.1, I was under the impression that it included GeoWebCache. I could confirm when I browse to the following URL and see a GeoWebCache page.

In this screen shot you can see my indiana counties shapefile that I had imported into a postGIS table. The "spelling" of that data layer will be used in the URL that follows.

So, given the GeoWebCache docs above, and the fact that I had a different base URL, I construed that the proper URL to fetch a google maps tile would perhaps be:

Putting this URL into my web browser, I was served a single 256x256 PNG tile as desired. Success.

So below is my example of hooking up v3 google maps API to GeoWebCache tile server. This presumes you have a corresponding div tag in your html file, e.g.,

1: <div id="map_canvas" style="border: 1px #333 solid; height: 375px; width: 500px;"></div>

And the code:

1: function initialize() {
2:   var latlng = new google.maps.LatLng(39.8895, -86.1575); // Indiana
3:   var myOptions = {
4:     zoom: 6,
5:     center: latlng,
6:     mapTypeId: google.maps.MapTypeId.ROADMAP
7:   };
8:   var indianaCountiesOptions = {
9:     getTileUrl: function(coord, zoom) {
10:       return "http://myserver:8080/geoserver/gwc/service/gmaps?layers=indiana:indiana_counties&" +
11:        "zoom=" + zoom + "&x=" + coord.x + "&y=" + coord.y + "&format=image/png";
12:     },
13:     tileSize: new google.maps.Size(256, 256),
14:     isPng: true,
15:     opacity: 0.25
16:   };
18:   var customMapType = new google.maps.ImageMapType(indianaCountiesOptions);
19:   var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
20:   map.overlayMapTypes.insertAt(0, customMapType);
21: }