Oct
29
2009
20

Tutorial: GWT, Maven and Eclipse with M2Eclipse

This tutorial shows how to develop Rich Internet applications with the Google Web Toolkit (GWT) using a state of the art Software  Development Environment, especially Maven integrated in Eclipse through m2eclipse (There is another plugin IAM, but in this tutorial we will use M2Eclipse). We will set up the environment, create a web application that is using Google Maps and debug it. This tutorial is the Maven version of this one using Cypal Studio.

Preliminaries

First we have to download Java and Eclipse. We will not download the Google Web Toolkit, Cypal Studio or the Google Maps library for GWT like in my last tutorial.

  1. Download and install the Java SE Development Kit
    You need the JDK to run Eclipse, the GWT Hosted Mode-Browser and the GWT-Compiler. On MacOS the JDK is installed by default, for other operating systems you can download the JDK from Sun.
  2. Download and unzip the Eclipse IDE for Java EE Developers
    Download Eclipse for EE Developers. You can unzip Eclipse to whereever you like, for example into the folder applications or programs.
  3. Sign up for a Google Maps Api-Key (optional, only necessary for production use)
    This step is optional for development on your local computer (localhost). You can sign up for a key here.

Setup the eclipse workspace and configure plugins

Configure the eclipse workspace and project. This section contains only the configuration of eclipse, no source code that you would check in for example into svn.

  1. Eclipse Workspace
    Open Eclipse and choose a directory as workspace (project configuration and source code will/can be stored here).
    eclipse-galileo-select-workspace

    When Eclipse has started, you will see the welcome screen:
    eclipse-galileo-welcome
    Close the Welcome screen with the arrow on the right side and the workspace is displayed:
    eclipse-galileo-workspace
  2. Add the m2eclipse plugin (Integration of Maven into Eclipse)
    Open Help/Install New Software… and click Add on the upper right side:
    eclipse-galileo-install-new-software
    Enter M2Eclipse as name, http://m2eclipse.sonatype.org/update/ as Location and click OK:
    eclipse-galileo-new-software-add-site
    Select the items shown and click Next:
    eclipse-galileo-install-software-available-software
    Review the details and click Next:
    eclipse-galileo-install-software-review-details
    Accept the license and click Finish:
    eclipse-galileo-install-software-review-license
    Wait until the download has finished and the installation is complete and restart Eclipse (click yes).

Your first GWT application with Maven and Eclipse

Now we will create a simple GWT application based on an archetype.

  1. Create a Maven project
    Select File/New/Other… , select Maven project and click Next:
    eclipse-galileo-new-project-maven
    Click Next:
    eclipse-galileo-new-maven-project-name-and-location
    Select the gwt-maven-plugin archetype from org.codehaus.mojo and click Next:
    eclipse-galileo-new-maven-project-archetype
    Enter Maven details for this project and click Finish:
    eclipse-galileo-new-maven-project-archetype-parameters
    Your workspace will look like this:
    eclipse-galileo-workspace-with-project
  2. Edit the pom.xml
    This is the Project Object Model – maven project configuration file. Change the version of GWT to 1.7.o
    <gwt.version>1.7.0</gwt.version>

    Add the following dependency to the dependencies:

    <dependency>
     <groupId>com.google.gwt.google-apis</groupId>
     <artifactId>gwt-maps</artifactId>
     <scope>provided</scope>
     <version>1.0.4</version>
     </dependency>

    Add the following line direct below the gwt.version-tag within the properties:

    <runTarget>com.claudiushauptmann.gwt.maven.sample.Application/Application.html</runTarget>

    Change the plugin version to 1.1:

    <plugin>
     <groupId>org.codehaus.mojo</groupId>
     <artifactId>gwt-maven-plugin</artifactId>
     <version>1.1</version>
     <executions>
     <execution>
     <goals>
     <goal>compile</goal>
     <goal>generateAsync</goal>
     <goal>test</goal>
     </goals>
     </execution>
     </executions>
     </plugin>
  3. Edit the Application.gwt.xml
    This is the gwt module descriptor. We have to tell it, that we are using the Google Maps library (Yes, we have to do this twice. One time for Java and on time for GWT, because GWT should not use all Java libraries). Add the following lines:

    <script src="http://maps.google.com/maps?gwt=1&amp;file=api&amp;v=2" />
     <inherits name="com.google.gwt.maps.GoogleMaps">
  4. Edit the entrypoint (Application.java)
    This is the code that will be executed when the site is openend:

    package com.claudiushauptmann.gwt.maven.sample.client;
    
    import com.google.gwt.core.client.EntryPoint;
    import com.google.gwt.maps.client.MapWidget;
    import com.google.gwt.maps.client.control.MapTypeControl;
    import com.google.gwt.maps.client.control.SmallMapControl;
    import com.google.gwt.maps.client.event.MapClickHandler;
    import com.google.gwt.maps.client.geom.LatLng;
    import com.google.gwt.maps.client.overlay.Marker;
    import com.google.gwt.maps.client.overlay.Overlay;
    import com.google.gwt.user.client.ui.RootPanel;
    
    /**
     * Entry point classes define <code>onModuleLoad()</code>.
     */
    public class Application implements EntryPoint {
    
     /**
     * This is the entry point method.
     */
     public void onModuleLoad() {
     MapWidget mapWiget = new MapWidget(LatLng.newInstance(48.136559,
     11.576318), 13);
     mapWiget.setSize("500px", "300px");
    
     mapWiget.addControl(new SmallMapControl());
     mapWiget.addControl(new MapTypeControl());
    
     mapWiget.addMapClickHandler(new MapClickHandler() {
     public void onClick(MapClickEvent e) {
     MapWidget sender = e.getSender();
     Overlay overlay = e.getOverlay();
     LatLng point = e.getLatLng();
    
     if (overlay != null && overlay instanceof Marker) {
     sender.removeOverlay(overlay);
     } else {
     sender.addOverlay(new Marker(point));
     }
     }
     });
    
     RootPanel.get().add(mapWiget);</pre>
    }
    <pre>}

Building the project

The build will be run automatically when debugging the project.

  1. Select your project in the Project Explorer.
  2. Click Run/Run As/Maven install.

Debugging the project

Of course, you can use a plugin like Cypal Studio or the Google plugin for Eclipse. This is a way that works stable on Mac, Linux and Windows.

  1. Select your project in the Project Explorer.
  2. Select Run/Run As/Maven build…
  3. Type gwt:debug as goal, give your launch configuration a name and click Run:
    eclipse-galileo-maven-gwt-launch-configuration
  4. Select your project in the Project Explorer.
  5. Select Run/Debug configurations.
  6. Select Remote Java Application in the list on the left side and click the new launch configuration symbol on the upper left side and click Debug:
    eclipse-galileo-gwt-launch-configuration
  7. The hosted mode browser will open and every time you click on the map a marker will appear:
    GWT-hosted-mode
    GWT-hosted-mode-browser

Thank you for reading my tutorial! Please leave a comment and/or make a link from your web site.

Feb
22
2009
4

Hibernate Spatial and Envers – Geospatial revisions

Especially in social software, where almost everybody can edit the contents like in Wikipedia, it is important to store the history of the data. OpenStreetMap is also working on a concept of changesets. Some time ago, I was looking for such functionality that can be used in conjunction with the Java Persistence API (JPA) and automatically logs changes. Perhaps you already noticed the Blog of Adam Warksi at my blogroll, who is the founder of the Envers project.

The Envers project aims to enable easy versioning of persistent classes. All that you have to do is annotate your persistent class or some of its properties, that you want to version, with @Audited. For each versioned entity, a table will be created, which will hold the history of changes made to the entity. You can then retrieve and query historical data without much effort. Similarly to Subversion, the library has a concept of revisions. Basically, one transaction is one revision (unless the transaction didn’t modify any versioned entities). As the revisions are global, having a revision number, you can query for various entities at that revision, retrieving a (partial) view of the database at that revision. You can find a revision number having a date, and the other way round, you can get the date at which a revision was commited. [Envers project]

Envers works on top of / integrates into hibernate, which is an implementation of the JPA specification integrated in the JBoss Application Server and since october 2008, envers is an official hibernate module.

My first attempts getting envers work, were very disappointing, since I got many exceptions, after I added envers to a well working project. Yesterday, I made a new attempt and downloaded snapshot versions of hibernate (until now, there is no official release of hibernate, which contains envers) from the MavenSnapshotReporitory. My code was working fine and envers created a new revision for my data for every commit. Really nice! Great job, Adam!

But what about Hibernate Spatial (like in my post about storing map data) and Envers? Do they cooperate? I was dying to write a little test, whether that works. First I, created a class, that stores markers, that have got an id, a caption and a location:

package com.claudiushauptmann.test;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

import org.hibernate.annotations.Type;
import org.hibernate.envers.Audited;

import com.vividsolutions.jts.geom.Point;

@Entity
@Audited
public class Marker implements Serializable {

    @Id
    @GeneratedValue
    private int id;

    @Type(type="org.hibernatespatial.GeometryUserType")
    private Point location; 

    private String caption;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public Point getLocation() {
        return location;
    }

    public void setLocation(Point location) {
        this.location = location;
    }

    public String getCaption() {
        return caption;
    }

    public void setCaption(String caption) {
        this.caption = caption;
    }
}

Second, I created two tables, one for the current data and one for the history:

CREATE TABLE marker
(
  id integer NOT NULL,
  "location" geometry NOT NULL,
  caption text NOT NULL,
  CONSTRAINT "PK_marker" PRIMARY KEY (id)
)
WITH (OIDS=FALSE);
CREATE TABLE marker_aud
(
  id integer NOT NULL,
  "location" geometry NOT NULL,
  caption text NOT NULL,
  rev integer NOT NULL,
  revtype integer NOT NULL
)
WITH (OIDS=FALSE);

Third, there must be a table, that contains meta data about the revisions. This is the minimum of the columns:

CREATE TABLE revinfo
(
  rev integer NOT NULL,
  revtstmp bigint NOT NULL,
  CONSTRAINT "PK_REVINFO" PRIMARY KEY (rev)
)
WITH (OIDS=FALSE);

Don’t forget to add enlist envers in your persistence.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
    <persistence-unit name="test">
        <jta-data-source>java:/test</jta-data-source>
        <properties>
            <property name="hibernate.dialect" value="org.hibernatespatial.postgis.PostgisDialect" />
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.ejb.event.post-insert" value="org.hibernate.envers.event.AuditEventListener" />
            <property name="hibernate.ejb.event.post-update" value="org.hibernate.envers.event.AuditEventListener" />
            <property name="hibernate.ejb.event.post-delete" value="org.hibernate.envers.event.AuditEventListener" />
            <property name="hibernate.ejb.event.pre-collection-update" value="org.hibernate.envers.event.AuditEventListener" />
            <property name="hibernate.ejb.event.pre-collection-remove" value="org.hibernate.envers.event.AuditEventListener" />
            <property name="hibernate.ejb.event.post-collection-recreate" value="org.hibernate.envers.event.AuditEventListener" />
            <property name="org.jboss.envers.warnOnUnsupportedTypes" value="true" />      
        </properties>
    </persistence-unit>
</persistence>

This is working very well! For every commit, a new revision is created in the table revinfo and the new version of the marker is stored into the table marker_aud and the data within the table marker was updated.

Of course, we do not only need to store the history, but also a way to retrieve past data. There is a pretty nice quickstart tutorial about envers, which describes, how to get the data out of the history with the VersionsReader.

Feb
16
2009
0

Using OpenStreetMap data in your own applications

OpenStreetMap is a collaborative project to create a free editable map of the world. The maps are created using data from portable GPS devices, aerial photography and other free sources [Wikipedia]. OpenStreetMap data can be used freely under the terms of the Creative Commons Attribution-ShareAlike 2.0 license [OpenStreetMap]. Thus it can be used e.g. in your own applications, mobile devices or web pages, for productive use or testing purposes (This abstract makes no claim to be complete, please read the license before using the data).

The database model is documented here. OpenStreetMap provides two ways for programmatical use/access. First, snapshots and diffs that can be imported in your own database and be used for replication (The files are here). Second, an API (implemented as a REST webservice). This link queries a mountain peak in bavaria, for example (Look at the source code, if the browser displays a blank page). If you are just interested in looking up some points of interest from time to time and internet access is available, using the API is a good idea. Otherwise an export or  replication (full or partial) of the database is the better solution, particularly if you want to run intensive geospatial computings on the data.

You do not have to write your own client code to access the API. JOSM, a java-based map editor for OpenStreetMap is using the web service to load the map content and store your change set. Perhaps it is a good idea to look at the source code and the api calls. I tried to check out the project via eclipse (with subclipse) and I just had to click debug as java application and it worked fine, since the required libraries are included in the svn repository. Then I could debug through the code and watch the API calls. Unfortunately there is much GUI code mixed into the logic, but the code is easy to understand.

If you want to export/replicate the data into your own data store, there is a really great java-based console application: Osmosis. It can be run within cron jobs to periodically to replicate the database. I checked out the source code, but had some troubles debugging the application, since not all libraries are included in the svn repository. It took some time to collect all necessary jar files from the web. I advise you not to grub through the code. There is a lot of functionality out of the box, which can be read here and there is an API to write your own plugins for Osmosis, that can be included in the pipelines, if you want to use your own database schema, e.g. with Hibernate Spatial like in my last post about how to store your map data on the server side. A really great feature is the option –read-change-interval, that calculates, which change sets have to be downloaded to keep your own replication of the database up to date.

Nov
16
2008
89

Tutorial: Google Maps with Java, GWT and Eclipse

The intention of this tutorial is to show how to use eclipse to develop a rich internet application with GWT that contains a Google Maps-map. The focus is less on the API provided by the Google Maps-wrapper for GWT, but how to use eclipse as a comfortable IDE. Google itself provides a very comprehensive example (source code) that demonstrates the possibilities of the wrapper.

UPDATE (01/07/09): Since there is some discussion about how to put this tutorial into action, I decided to provide a zip file containing the finished eclipse workspace of this tutorial: tutorialgwtmaps. Don’t forget to update the build path and the GWT home folder!

UPDATE 2 (01/14/09): Code Formatted.

Preliminaries
Download the required software and sign for a Google Maps API-key.

  1. Download and install the Java SE Development Kit
    You need the JDK to run Eclipse, the GWT Hosted Mode-Browser and the GWT-Compiler. On MacOS the JDK is installed by default, for other operating systems you can download the JDK from Sun.
  2. Download and unzip the Eclipse IDE for Java EE Developers
    Download Eclipse for EE Developers. You can unzip Eclipse to whereever you like, for example into the folder applications or programs.
  3. Download the Google Web Toolkit
    GWT is available at code.google.com. Download and unzip it to whereever you like.
  4. Download und install Cypal Studio for GWT
    Cypal Studio is a Eclipse plugin that integrates GWT into Eclipse the build process and the launch process. Unzip the plugin jars into <Eclipse home>/dropins/Cypal/plugins. You have to manually create the Cypal and plugins directories (installation manual).
  5. Download and unzip the Google Maps-library for GWT
    The Google Maps-library for GWT wrappes the javascript necessary to run Google Maps on your website. Download and unzip the library to whereever you like.
  6. Sign up for a Google Maps Api-Key
    This step is optional for development on your local computer (localhost). You can sign up for a key here.

Setup the eclipse workspace
Configure the eclipse workspace and project. This section contains only the configuration of eclipse, no source code that you would check in for example into svn.

  1. Eclipse Workspace
    Open Eclipse and choose a directory as workspace (project configuration and source code will/can be stored here).

    When Eclipse has started, you will see the welcome screen:

    Close the Welcome screen with the arrow on the right side and the workspace is displayed:
  2. Configuration of Cypal Studio
    Open the Preferences Dialog (Eclipse/Preferences on MacOS or Window/Preferences) and select Cypal Studio on the left side. Then Enter the folder where the Google Web Tookit is located and click OK:
  3. Create the GWT-Project
    Select File/New/Dynamic Web Project. Enter MyFirst Google Maps Application as project name and select Cypal Studio for GWT as configuration, then click Next.

    You can leave the default values on the next page and click Finish.

    You will see a new project on the left side in the project explorer:
  4. Add the Google Maps-library to the Java Build Path
    Rightclick your new project and select Properties in the popup menu, then select Java Build Path on the left side and Libraries on the top. Click Add External JARs… and add the file gwt-maps.jar located in the Google Maps for GWT-library.

Your first Google Maps-application
This section handles the source code and configuration files. It adjusts the GWT-template to create a Google Maps-map.

  1. Create a GWT Module
    Select File/New/Other…, then Cypal Studio/GWT Module and click Next:

    Enter a package (e.g.: com.claudiushauptmann.gwt.maps.samples) and a name for the module (e.g.: MyFirstMapsModule) and click Finish.

    Your workspace will look like this with 3 new files. A Java class with the module, a wrapper-html-file and a xml-file that defines the GWT-Module:
  2. Configure your project for Google Maps
    Add <inherits name=”com.google.gwt.maps.GoogleMaps”/> and<script src=”http://maps.google.com/maps?gwt=1&amp;file=api&amp;v=2″ /> to your Module XML-file (e.g.: MyFirstMapsModule.gwt.xml). You can enter your API-Key here (optional for localhost).

    &lt;module&gt;
    
    	&lt;!-- Inherit the core Web Toolkit stuff.                  --&gt;
    	&lt;inherits name='com.google.gwt.user.User'/&gt;
    
    	&lt;inherits name=&quot;com.google.gwt.maps.GoogleMaps&quot;/&gt;
    	&lt;script src=&quot;http://maps.google.com/maps?gwt=1&amp;amp;amp;file=api&amp;amp;amp;v=2&quot; /&gt;
    
    	&lt;!-- Specify the app entry point class.                   --&gt;
    	&lt;entry-point class='com.claudiushauptmann.gwt.maps.samples.client.MyFirstMapsModule'/&gt;
    
      	&lt;inherits name=&quot;com.google.gwt.user.theme.standard.Standard&quot;/&gt;
      	&lt;!-- &lt;inherits name=&quot;com.google.gwt.user.theme.chrome.Chrome&quot;/&gt; --&gt;
      	&lt;!-- &lt;inherits name=&quot;com.google.gwt.user.theme.dark.Dark&quot;/&gt; --&gt;
    
    &lt;/module&gt;
    
  3. Add some code that inserts a MapWidget into the web page:
    package com.claudiushauptmann.gwt.maps.samples.client;
    
    import com.google.gwt.core.client.EntryPoint;
    import com.google.gwt.maps.client.MapWidget;
    import com.google.gwt.maps.client.control.MapTypeControl;
    import com.google.gwt.maps.client.control.SmallMapControl;
    import com.google.gwt.maps.client.event.MapClickHandler;
    import com.google.gwt.maps.client.geom.LatLng;
    import com.google.gwt.maps.client.overlay.Marker;
    import com.google.gwt.maps.client.overlay.Overlay;
    import com.google.gwt.user.client.ui.RootPanel;
    
    public class MyFirstMapsModule implements EntryPoint {
    
    	public void onModuleLoad() {
    		MapWidget mapWiget = new MapWidget(LatLng.newInstance(48.136559, 11.576318), 13);
    		mapWiget.setSize(&quot;500px&quot;, &quot;300px&quot;);
    
    	    mapWiget.addControl(new SmallMapControl());
    	    mapWiget.addControl(new MapTypeControl());
    
    	    mapWiget.addMapClickHandler(new MapClickHandler() {
    	      public void onClick(MapClickEvent e) {
    	        MapWidget sender = e.getSender();
    	        Overlay overlay = e.getOverlay();
    	        LatLng point = e.getLatLng();
    
    	        if (overlay != null &amp;amp;&amp;amp; overlay instanceof Marker) {
    	          sender.removeOverlay(overlay);
    	        } else {
    	          sender.addOverlay(new Marker(point));
    	        }
    	      }
    	    });
    
    	    RootPanel.get().add(mapWiget);
    	}
    }
    

The launch configuration
Now we want to run and debug our application. First we debug it in the Hosted Mode-Browser, the we compile it to javascript and open it with a standard internet browser.

  1. Create a launch configuration and start debugging
    Select Run/Debug Configurations… and create a new launch configuration with the button on the top left. Enter a name for the launch configuration and selct your project and your module, then click Apply.
  2. Debugging
    Click Debug and the Hosted Mode-browser starts:
  3. Compile and run in your Browser
    Click Compile/Browse, wait some seconds and your standard browser will open and show your application:

It would give me a great pleasure, if you wrote a short comment, whether this tutorial was helpful!

Powered by WordPress. Theme: TheBuckmaker