Category: Software

Simple Google Maps routeplanner

By Rob, July 1, 2011 5:56 pm

Last week I was googling for a simple implementation of a routeplanner based on Google maps. Weirdly enough I didn’t find a total solution or older ones based on the maps v2 API. So I decided to have a look at the API and In 15 minutes I had a working routeplanner. Which might explain why I found that less examples on the internet :) . But for all other people who need a quick solution, I thought sharing would be good.

It’s a very plain example based on the Google Maps v3 and a bit of jQuery but that can easily be avoided.

First the necessary html:


<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" type="text/javascript"></script>

<style>
  #map_canvas {
    height:500px;
    width:600px;
 }
 #directions {
   width:600px;
 }
</style>

<div id="map_canvas"></div>
<h2>Plan your trip</h2>
<form id="routeform">
  City or zipcode:
  <input type="text" name="routefrom" id="routefrom"/>
  <input type="submit" value="calculate"/>
</form>
<div id="directions"></div>

And the Javascript:

$(document).ready(function()
{
  initialize();

  $('#routeform').submit(function(e)
  {
    calcRoute();
    return false;
  });

});

var directionDisplay;
var directionsService = new google.maps.DirectionsService();
var map;
var home = new google.maps.LatLng(52.0951, 5.109);

function initialize()
{
  directionsDisplay = new google.maps.DirectionsRenderer();

  var myOptions =
  {
    zoom:8,
    mapTypeId: google.maps.MapTypeId.ROADMAP,
    center: home
  }
  map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
  directionsDisplay.setMap(map);
  directionsDisplay.setPanel(document.getElementById("directions"));

  var myLatLng = new google.maps.LatLng(52.0951, 5.109);
  var beachMarker = new google.maps.Marker
  ({
      position: myLatLng,
      map: map
  });
}

function calcRoute()
{
  var start = document.getElementById("routefrom").value;

  var request =
  {
    origin:start,
    destination:home,
    travelMode: google.maps.DirectionsTravelMode.DRIVING
  };
  directionsService.route(request, function(response, status)
  {
    if (status == google.maps.DirectionsStatus.OK)
    {
      directionsDisplay.setDirections(response);
    }
  });
}

Which results in:






Plan your trip

City or zipcode:





Cached credentials in http basic authentication

By Rob, June 11, 2011 11:50 am

After some radio silence, it’s time for a short post. Being busy with Duchenne Heroes last year and some weeks of snowboarding I’m posting a new blog about Java’s AuthCache to avoid breaking other people’s head as it broke mine.

Two weeks ago I was working on a connection with a common webservice which authentication was based on plain http basic authentication. I used CXF as a client library to handle the plumbing for me, the basic code looked like this:

JaxWsProxyFactoryBean clientFactory = new JaxWsProxyFactoryBean();
clientFactory.setAddress("http://webservice.url.com");
clientFactory.setServiceClass(MyLocalInterface.class);
clientFactory.setUsername("rob");
clientFactory.setPassword("secret");
fundaSoap = clientFactory.create(MyLocalInterface.class);

From the start this worked great and simple, till the moment that I set up another connection based on the same url but other credentials…… That’s where the problem began. Connection nr 2 was now messed up with the credentials of connection nr 1 and as I never heard of this behavior, I refused to believe it either. But after diving into server logs, I couldn’t deny it anymore. My client code was screwed up. After some googling I found the problem, the JDK is caching credentials based on the url and port of your http request. And resetting that cache by calling the Authenticator class doesn’t help you due to this bug:

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6626700

So there’s just one way to avoid this bug and that’s fooling the JDK that you’ve used the credentials before:

AuthCacheValue.setAuthCache(new AuthCache()
{
  @Override
  public void remove(String arg0, AuthCacheValue arg1) { }

  @Override
  public void put(String arg0, AuthCacheValue arg1) { }

  @Override
  public AuthCacheValue get(String arg0, String arg1)
  {
    return null;
  }
});

I hope my post will help other people with the same kind of issues as this took me some time to figure out what was happening and I don’t want that somebody else spoils his or her time on this.

Apart from this post, I’m really happy with the CXF library (based on the old XFire project) and I’ll try to publish more on that later.

Finally did my SCJP6 exam!

By Rob, May 11, 2010 7:42 pm

Long time no blog, the explanation is here.

After three years of having the good intention, I finally motivated myself to take the SCJP exam. From the moment I started working after my study, I told myself many times that I should for some Java certification. Just to prove that I understand what I’m doing. So I started reading in the SCJP 5 study guide (the Sierra and Bates book), and started several times…..

A lot of information was pretty interesting but on the other hand I couldn’t really motivate myself to learn on exotic facts which I never use in practice. Due that fact, I quit learning on SCJP5. Last year I finally picked it up again by buying the Java 6 version of the Sierra and Bates book. Again fighting with the same contradicting facts of useful and useless knowledge but now determined to finish it!

I’ll give a short summary of how I studied. Started with reading the book and making notes for every chapter. After each chapter, I made the test questions and reviewed them. I added the best practices to the notes and learned from my mistakes which were for 50% just silly and stupid ones. After finishing the book, I never opened it again. From that moment I started practicing by just writing several small test applications to get a feeling with several subjects. And doing different mock tests. I would like to mention and recommend the examlab software from Devaka Cooray, it’s free and is really approaching the real exam.

So that’s it for now. I’m currently working on bookmarkeable ajax urls and back button support for ajax urls in php based on CodeIgniter and JQuery. I’ll definitely post my solution here once it’s a bit finished. And not unimportant, I’m about to leave for a trip to India (for work), maybe I’ll write something about that as well.

Oh but now the most important, the result of my exam:

PASSED with a 85% score!!!

What’s next:

  • Training and collecting for our goal this year
  • Then thinking about another certification
  • Drinking a beer to celebrate my score :)

Tips:

  • Be very secure!! Most of my mistakes were not noticing minor, non-head braking things.
  • Read a good book, make notes, re-read those notes several times
  • Practice as much as you can on mock tests (for example examlab.tk)
  • Visit the Javaranch SCJP forum, contains a lot of useful information
  • Have fun!

Filtering your duplicate feedbackmessages in Wicket

By Rob, February 6, 2010 12:11 pm

Last week I noticed that in some of my webapps written in Wicket, messages appear multiple times in a FeedbackPanel (Wicket component). That happens since multiple parts of the same page do different kind of validation which might occur in the same error/warning messages. Not a big problem but duplicate messages look a bit weird to your visitor. It’s easy to fix and probably no rocket science to you but I post it anyway :) .

The solution contains two parts, a custom FeedbackPanel and an implementation of the IFeedbackMessageFilter.

Custom FeedbackPanel:

private class UniqueMessagesFeedbackPanel extends FeedbackPanel
  {
    private UniqueMessageFilter filter = new UniqueMessageFilter();

    @Override
    protected void onBeforeRender()
    {
      super.onBeforeRender();
      // clear old messages
      filter.clearMessages();
    }

    public UniqueMessagesFeedbackPanel(String id)
    {
      super(id);
      setFilter(filter);
    }
  }

And the filter class:

public class UniqueMessageFilter implements IFeedbackMessageFilter
  {
    List<FeedbackMessage> messages = new ArrayList<FeedbackMessage>();

    public void clearMessages()
    {
      messages.clear();
    }

    @Override
    public boolean accept(FeedbackMessage currentMessage)
    {
      // too bad that FeedbackMessage doesnt have an equals implementation
      for(FeedbackMessage message: messages)
        if(message.getMessage().toString().equals(currentMessage.getMessage().toString()))
          return false;
      messages.add(currentMessage);
      return true;
    }
  }

I'm looking for a a more beautiful way to cleanup the messages but it seems impossible since the FeedbackMessage class does not implement an own equals version. And if it was implemented, it propably checks on too much properties, like the component which throws the message and that still results in duplicate messages.

Context based urls with Apache Wicket

By Rob, January 2, 2010 5:47 pm

It’s been a while that I wrote something technical on my blog. The last ones were mainly about biking which is taking a lot of my spare time these days. I haven’t blogged about Wicket before but that doesn’t mean that I use it a lot. For the last 2 years, I’m using it at my work at Maxxton for developing rich content websites. In one of the usecases a month ago, we needed something for storing parameters in the urls which would never get lost after clicking around. After a little googling on the web, I found an example on the Wicket wiki which allowed you to add the locale in the url. I’ve re-used that example and made it a bit more generic by allowing key-value pairs instead of one hardcoded string.

The used keys are defined by a simple enum:


private enum Param {
LANGUAGE("lan"), THEME("theme");

private final String value;

Param(String value) {
this.value = value;
}

public String getValue() {
return value;
}
};

In this example I used two different params which can be used in combination with eachother or separated. I won’t add all the Java code in long listings over here because of the amount of code but you can download my Eclipse project at the end of this blogpost.

There are actually two important spots, a custom RequestCodingStrategy and the registration of that class in the WebApplication. But before I show that code, let’s give some examples of the urls which will be created/working:

  • http://localhost:8080/urlexample/theme/red/lan/nl/home
  • http://localhost:8080/urlexample/lan/nl/home
  • http://localhost:8080/urlexample/theme/red/home
  • http://localhost:8080/urlexample/home

All of these urls are pointing to the homepage mounted at “home”. The bold parts are the key-value pairs which are read in our RequestCodingStrategy and stored in the session for later use. The beauty of this solution is that every generated url, will still contain these values. So in my example, I created a link to another page called “end” and that url will be something like http://localhost:8080/urlexample/theme/red/lan/nl/end.

So how does that look like, lets start with the 2 overridden methods in my WebApplication:


@Override
protected IRequestCycleProcessor newRequestCycleProcessor() {
return new WebRequestCycleProcessor() {
@Override
protected IRequestCodingStrategy newRequestCodingStrategy() {
return new ParamUrlCodingStrategy(super
.newRequestCodingStrategy());
}
};
}

@Override
public Session newSession(Request request, Response response) {
return new CustomSession(request);
}

The newRequestCycleProcessor() returns the custom RequestCodingStrategy instead of the default one. and the newSession() returns our custom session for storing the values. Nothing special.

Lets take a look now to our custom RequestCodingStrategy where most of the magics happens. I only show a stripped version of the one in the example project:


public class ParamUrlCodingStrategy extends RequestCodingStrategy {

public ParamUrlCodingStrategy(final IRequestCodingStrategy defaultStrategy) {
super(defaultStrategy);
}

@Override
public RequestParameters decode(final Request request) {
final String requestLanguage = getParamValue(request.getPath(),
Param.LANGUAGE);
final String requestTheme = getParamValue(request.getPath(),
Param.THEME);

// for example, use a custom session object to store your values
if (requestLanguage != null) {
((CustomSession) Session.get()).setLanguage(requestLanguage);
}
if (requestTheme != null) {
((CustomSession) Session.get()).setTheme(requestTheme);
}

String url = request.decodeURL(request.getURL());

// remove params from request
for (Param param : Param.values()) {
url = stripParamFromPath(url, param);
}
final String urlWithoutParams = url;

// use decorator for decoding
return getDecoratedStrategy().decode(new RequestDecorator(request) {
@Override
public String getURL() {
return urlWithoutParams;
}

@Override
public String getPath() {
return urlWithoutParams;
}
});
}

@Override
public CharSequence encode(final RequestCycle requestCycle,
final IRequestTarget requestTarget) {
String url = getDecoratedStrategy().encode(requestCycle, requestTarget)
.toString();

// rewrite only requests for pages &amp;amp; links
if (requestTarget instanceof IBookmarkablePageRequestTarget
|| requestTarget instanceof IPageRequestTarget) {

String theme = ((CustomSession) Session.get()).getTheme();
String language = ((CustomSession) Session.get()).getLanguage();

// language
if (language != null &amp;amp;&amp;amp; !language.isEmpty()) {
if (url.startsWith("../")) {
final int lastIndex = url.lastIndexOf("../") + 3;
final String remainingUrl = url.substring(lastIndex);
if (!remainingUrl.isEmpty()) {
url = url.substring(0, lastIndex)
+ Param.LANGUAGE.getValue() + "/" + language
+ "/" + remainingUrl;
}
}
// if starts with . -&gt; skip
else if (!url.startsWith(".")) {
url = Param.LANGUAGE.getValue() + "/" + language + "/"
+ url;
}
}
// and theme
if (theme != null &amp;amp;&amp;amp; !theme.isEmpty()) {
if (url.startsWith("../")) {
final int lastIndex = url.lastIndexOf("../") + 3;
final String remainingUrl = url.substring(lastIndex);
if (!remainingUrl.isEmpty()) {
url = url.substring(0, lastIndex)
+ Param.THEME.getValue() + "/" + theme + "/"
+ remainingUrl;
}
}
// if starts with . -&gt; skip
else if (!url.startsWith(".")) {
url = Param.THEME.getValue() + "/" + theme + "/" + url;
}
}
return url;
}
return url;
}

private String getParamValue(final String path, Param param) {
int index = path.indexOf(param.getValue());
if (index &gt;= 0) {
int indexOfNextSlash = path.indexOf("/", index
+ param.getValue().length() + 1);
String paramValue = path.substring(index
+ param.getValue().length() + 1, indexOfNextSlash);
return paramValue;
}
return null;
}

private String stripParamFromPath(final String path, Param param) {
String paramValue = getParamValue(path, param);

return path.replace(param.getValue() + "/" + paramValue + "/", "");
}

@Override
public IRequestTarget targetForRequest(
final RequestParameters requestParameters) {
// delegate call to decorated codingStrategy, but with params removed
String newPath = requestParameters.getPath();
for (Param param : Param.values()) {
newPath = stripParamFromPath(newPath, param);
}

requestParameters.setPath(newPath);
return super.targetForRequest(requestParameters);
}

@Override
public IRequestTargetUrlCodingStrategy urlCodingStrategyForPath(
final String path) {
String newPath = path;
for (Param param : Param.values()) {
newPath = stripParamFromPath(newPath, param);
}

if (newPath != null &amp;amp;&amp;amp; !newPath.isEmpty()) {
// treat this kind of situation by returning some not null
// codingStrategy,
// to let this kind of request treated by wicket
return new PassThroughUrlCodingStrategy(newPath);
}
return super.urlCodingStrategyForPath(newPath);
}

}

As you can see, the encode() and decode() methods do most of the processing. It’s actually nothing more then adding and removing/reading the parameters. The reason that I liked it, is that it’s always executed, no matter what code is used inside the pages. That’s a secure way of adding parameters and not loosing them and as a little dessert, Google likes them as well! Urls are indexed including state in Google which allows you to create language based urls for example.

So that’s it for now. The post only shows the keyfactors of my example. If you’re more interested, you should download my example project and dive into the code.

Download my example Eclipse project

Panorama Theme by Themocracy