In the previous module we have seen how to build and deploy the MapFishSample application. More generally we have seen how to use Buildout to build and deploy MapFish applications.
In this module we will study MapFishSample. We’ll see how MapFishSample is structured, and how its connections to external components, such as MapServer and MapFish Print, are organized.
MapFishSample is a MapFish application, i.e. an application created with the mapfish template, it is therefore structured like any MapFish application.
At the root of MapFishSample we find these files and directories:
These files include the configuration of MapFishSample itself. development.ini is to be used with the Paste HTTP Server during development, while production.ini is to be used with modwsgi, in production.
Both files are generated by Buildout (the template part) from their .ini counterpart. They are generated at deployment time because they include parameters, e.g. the database connection parameters, that are specific to the execution environment.
This directory includes the MapFish Print configuration, i.e. the YAML config file. It could also include images, and PDF files, that are to be bundled in the MapFish Print webapp.
The c2c.recipe.jarfile is responsible for bundling the YAML file and the resource files into the MapFish Print webapp.
Task #1
Open apache/mapserver.conf.in and apache/mapserver.conf, and note how the mapfile is made available to MapServer.
The actual code of MapFishSample is located in the mapfishsample directory. This directory includes several sub-directories, the most important ones are:
This directory includes the controllers of the application. Controllers are written in Python. They contain the code that receive HTTP requests, take appropriate action, and send HTTP responses.
The two main controllers in MapFishSample are entry.py and pois.py.
entry.py defines the entry point of the application, it receives the very first request when the browser loads http://mapfish/.
pois.py implements the MapFish web service for the poi_osm table. This is the web service used for the Query and Editing functionalities.
This directory includes HTTP templates (as a matter of fact it also includes JavaScript templates). The Mako template engine is used for the processing of templates.
The main template is index.html, which is the HTML page displayed when http://mapfish/ is opened in the browser. This template is rendered when the index action of the entry.py controller is invoked.
This directly includes the static content of MapFishSample, i.e. the JavaScript code, CSS, images, etc.
The JavaScript code of the application, which controls the browser UI, is located in the app/lib/App directory.
The JavaScript toolkits - OpenLayers, ExtJS, and GeoExt - are located in the lib directory.
Task #2
Open http://mapfish/?debug=true in the browser. Open FireBug with F12 and go to the Net tab. Reload the page. The loading of the page should take longer than previously. And more JavaScript files should be downloaded. Setting debug in the URL indeed results in individually loading every JavaScript file composing the application. When debug is not set the app.js built file is loaded.
Open mapfishsample/controllers/entry.py and mapfishample/templates/index.html in the editor, and understand how this mechanism works (Hint: look up c.debug).
As mentioned in the previous section the application-specific code is located in the mapfishsample/public/app/lib/App directory.
The entry point of the JavaScript application is defined in the main.js file. This file defines the function called when the HTML page is loaded in the browser. This function starts by setting global variables, and then creates the map in the page.
The map-related code is in the Map.js file. The App.Map function defined in this file basically creates the map, the layers, and the toolbar that contains the buttons to enable/disable the Query, Editing, Search and Printing functionalities. The toolbar-related code is itself located in the App.Tools function of the Tools.js file.
Task #3
Open Tools.js in the editor. Take a look at the code, paying attention to the functions belonging to the App namespace, and attempt to open the relevant JavaScript files as you go through the code.
Hint: also pay attention to the @include directives at the heads of files.
Task #4
In this task you’re going to modify the JavaScript code of the application.
Start by opening http://mapfish/ in the browser. Active the Search functionality, select “Fastfood” in the “Type” select, and hit “Search”. In the popup use the left and right arrows to browse through the results, and observe that the map isn’t recentered when a result is selected. You’re going to change that!
Open Search.js in the editor, and look up the featureselected listener. At the end of the function add the following code:
var ll = new OpenLayers.LonLat(
feature.geometry.x, feature.geometry.y);
mapPanel.map.setCenter(ll);
Reload the page in the browser, and check if the behavior has changed. It shouldn’t have, because the JavaScript hasn’t been rebuilt. If you open http://mapfish/?debug=true you should get the expected behavior though.
To build the JavaScript code again, execute this command line at the root of MapFishSample:
$ ./buildout/bin/buildout -c buildout_mine.cfg install jsbuild
The install argument allows targeting a specific part of the Buildout configuration. In that case only the jsbuild part is executed.
Now http://mapfish/ should behave as expected. Verify that.
MapFishSample relies on MapServer for the display of POIs on the map. WMS is used for that (WMS request example). MapServer is an external component of MapFishSample, it needs to be installed on the system for MapFishSample to work properly.
Linking MapFishSample and MapServer together is done through multiple things:
Task #5
In this task you’re going to modify the mapfile and see what must be done to make your modification effective.
Edit mapserver/mapfishsample.map.in, look up the sustenance layer (this is the POI layer), and change the value of its LABELITEM property from "name" to "type".
You have modified a .in file so the template part of Buildout must be executed again:
$ ./buildout/bin/buildout -c buildout_mine.cfg install template
You may have noticed when looking at apache/mapserver.conf that the FastCGI interface is used for MapServer. FastCGI is preferred to CGI because it leads to better performance, especially when MapServer reads data from PostgreSQL/PostGIS. One consequence of that is that Apache needs to be reloaded for changes to the mapfile to be effective:
$ sudo /etc/init.d/apache reload
Reload http://mapfish/ in the browser. The label under a POI symbol should now be the type of the POI, instead of its name. Verify that.
MapFishSample relies on MapFish Print for the Print functionality. Here again MapFish Print is an external component of MapFishSample.
In contrast to MapServer, MapFish Print is downloaded and installed by MapFishSample’s Buildout process. But MapFishSample requires that Apache Tomcat is up and running on the system.
The following describes how MapFishSample and MapFish Print are linked together:
At any time one can use the following command to redeploy the MapFish Print webapp into Tomcat:
$ ./buildout/bin/buildout -c buildout_mine.cfg install deploy-print
Task #6
In a similar way to Task #5 you’re going to change the MapFish Print configuration in this task, and make your change effective.
Edit print/config.yaml.in and make some changes of your choice (change the map size for example).
Now re-generate print/config.yaml from print/config.yaml.in, and re-build and re-deploy the MapFish Print webapp using:
$ /buildout/bin/buildout -c buildout_mine.cfg install template deploy-print
Reload http://mapfish/ in the browser, print a map, and check that you get what you expect.
In its current form MapFishSample doesn’t use TileCache (mostly because MapFishSample uses an OSM layer as the map baselayer). But TileCache is set up in MapFishSample, so using TileCache in the future will be straightfoward.
First of all TileCache is configured as a dependency of MapFishSample. Dependencies are expressed through the install_requires variable in setup.py. Because of this dependency TileCache was installed in the Python environment when Buildout was run for the first time.
MapFishSample also includes a controller for TileCache. See mapfishsample/controller/tilecache.py. This controller is a wrapper for TileCache. Embedding TileCache within the application greatly simplifies the installation and deployment of TileCache. It also makes it possible to secure TileCache web services using Pylons-compatible security frameworks such as repoze.who. We will talk about again that in the next module.
Task #7
In this task you’re going to modify MapFishSample to go through TileCache instead of accessing MapServer directly.
The first thing to do is configure TileCache, i.e. define the TileCache layer and its connection to MapServer.
Edit tilecache/tilecache.cfg.in and replace its content by this:
[cache]
type = Disk
base = /var/sig/tilecache/mapfishsample-${instanceid}_tilecache
[DEFAULT]
type = WMSLayer
url = ${vars:mapserv_url}
srs = EPSG:900913
maxResolution = 156543.0339
levels = 18
bbox = -20037508.339200001,-20037508.339200001,20037508.339200001,20037508.339200001
extension = png
[sustenance]
With this content a TileCache layer named sustenance is defined. This layer is mapped to the MapServer layer of the same name.
To generate tilecache/tilecache.cfg execute the [template] Buildout part:
$ ./buildout/bin/buildout -c buildout_mine.cfg install template
You now need to change the JavaScript code so it accesses TileCache instead of MapServer for the POI WMS layer. For that edit mapfishsample/public/app/lib/App/Map.js, look up the POIS layer, change its url from App.mapservURL to App.tilecacheURL, and its singleTile option from true to false. The definition of the WMS layer should now look like this:
poisLayer = new OpenLayers.Layer.WMS(
'POIS',
App.tilecacheURL,
{
layers: ['sustenance'],
transparent: true
},
{
singleTile: false
}
);
Build the JavaScript code again, by executing the [jsbuild] Buildout part:
$ ./buildout/bin/buildout -c buildout_mine.cfg install jsbuild
Reload http://mapfish/ in the browser. The POIs layer should still be displayed.
If you create a new POI using the Editing functionalilty you’ll observe that the new object won’t appear in the WMS layer. This is a cached layer!
This section has shown how MapFishSample, and any MapFish application, can embed TileCache. It is interesting to note that any MapFish application can wrap any application implementing the WSGI interface. For example, embedding MapProxy, an alternative to TileCache, should be equally feasible.