<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Nicolas ColomerNicolas Colomer</title>
	<atom:link href="http://www.ncolomer.net/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.ncolomer.net</link>
	<description>From lorem to ipsum</description>
	<lastBuildDate>Wed, 11 Jul 2012 22:29:26 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Comet/WebSocket? Introducing the Atmosphere framework</title>
		<link>http://www.ncolomer.net/2012/03/cometwebsocket-introducing-the-atmosphere-framework/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=cometwebsocket-introducing-the-atmosphere-framework</link>
		<comments>http://www.ncolomer.net/2012/03/cometwebsocket-introducing-the-atmosphere-framework/#comments</comments>
		<pubDate>Wed, 28 Mar 2012 07:09:54 +0000</pubDate>
		<dc:creator>Nicolas Colomer</dc:creator>
				<category><![CDATA[Geomatics]]></category>
		<category><![CDATA[How to]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[atmosphere]]></category>
		<category><![CDATA[comet]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[jee]]></category>
		<category><![CDATA[jersey]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[push]]></category>
		<category><![CDATA[realtime]]></category>
		<category><![CDATA[webpush]]></category>
		<category><![CDATA[websocket]]></category>

		<guid isPermaLink="false">http://www.colomern.net/?p=352</guid>
		<description><![CDATA[Pushing messages to connected clients has always been a need on the web, growing with the apparition of new Rich Internet Applications, like realtime feeds (Gmail, news, market quotes), social feeds (The Twitter, Facebook and consort) and many other providing realtime collaboration, monitoring and &#8230;<p class="read-more"><a href="http://www.ncolomer.net/2012/03/cometwebsocket-introducing-the-atmosphere-framework/">Read more &#187;</a></p>]]></description>
				<content:encoded><![CDATA[<p><img class="alignleft  wp-image-382" title="MapPush" src="http://www.colomern.net/wp-content/uploads/2012/02/Capture-d’écran-2012-02-25-à-19.00.34.png" alt="" width="165" height="150" />Pushing messages to connected clients has always been a need on the web, growing with the apparition of new Rich Internet Applications, like <strong>realtime feeds</strong> (Gmail, news, market quotes), <strong>social feeds</strong> (The Twitter, Facebook and consort) and many other providing <strong>realtime collaboration</strong>, <strong>monitoring</strong> and <strong>control</strong> like new Internet of Things applications (<a href="http://www.flightradar24.com/">FlightRadar24</a>, Arduino <a href="http://kevinrohling.wordpress.com/2011/09/14/world-domination-using-arduinos-and-websockets/">#1</a>, <a href="http://laclefyoshi.blogspot.com/2010/12/controlling-arduino-with-ipod-touch.html">#2</a>).</p>
<p><a href="http://en.wikipedia.org/wiki/Comet_(programming)">Comet</a> technics (ie. polling, long-polling, streaming) and more recently, the <a href="http://en.wikipedia.org/wiki/WebSocket">WebSocket</a> protocol, have made possible various webpush applications.</p>
<p>Today, when you want to enable realtime push on your own Java-based webapp, you have several solutions:</p>
<ul>
<li>Use an <strong>externalized system</strong> that will handle that for you (like <a href="http://pusher.com/">Pusher</a>), avoiding you the providing of any additional server</li>
<li>Use a <strong>commercial solution</strong> (like <a href="http://kaazing.com/">Kaazing</a> or <a href="http://www.pushtechnology.com/">Diffusion</a>), generally implementing a Message Broker underneath, with both embedded and standalone server</li>
<li>Use a <strong>container-</strong><strong>specific api</strong> (like <a href="http://docs.codehaus.org/display/JETTY/Continuations">Jetty Continuation</a>, Tomcat&#8217;s <a href="http://tomcat.apache.org/tomcat-6.0-doc/aio.html">CometProcessor</a>, <a href="http://grizzly.java.net/nonav/docs/docbkx2.2/html/grizzly-docs.html">Grizzly CometHandler</a> or <a href="http://docs.jboss.org/netty/3.2/xref/org/jboss/netty/example/http/websocket/package-summary.html">Netty WebSocket</a>), but your application will be strongly coupled with it</li>
<li>Or use one of the few <strong>Open Source frameworks</strong> available (like <a href="https://github.com/atmosphere/atmosphere">Atmosphere</a>, <a href="http://cometd.org/">cometD</a> or <a href="http://jwebsocket.org/">JWebSocket</a>)</li>
</ul>
<p>In this article, I will focus on <strong>Atmosphere</strong>. After a brief presentation of the framework, I will demonstrate how easy it is to make push-capable applications, whatever the container you use and the nature of your clients.</p>
<p>Before we start, you can take a look at the following video, that demonstrates what I achieved thanks to the Atmosphere framework (more details below, of course):</p>
<p style="text-align: center;"><iframe src="http://www.youtube.com/embed/1Abv88t5igc" frameborder="0" width="420" height="315"></iframe><br />
<a href="http://youtu.be/1Abv88t5igc">http://youtu.be/1Abv88t5igc</a></p>
<p><span id="more-352"></span></p>
<h1>What is Atmosphere ?</h1>
<p>Atmosphere is a <strong>Java OpenSource framework</strong> led by Jean-Francois Arcand. Started around 2009, it evolved significantly and powers today websites like <a href="http://www.smartmoney.com/">smartmoney.com</a>. The project is very active (daily commits, lively mailing list, 300 Github followers). Currently in version 0.9, Atmosphere is close to the major 1.0 release planned for May.</p>
<p>One of the strength of the framework is that it is <strong>container agnostic</strong>: you can deploy an Atmosphere application in Jetty, Tomcat, JBoss, Grizzly,&#8230; Indeed, Atmosphere will seamlessly use specific compatibility modules and enable WebSocket depending on the detected container. The user does not need to learn container-specific Comet or WebSocket implementations anymore, only the way Atmosphere runs.</p>
<p>Atmosphere takes advantage of <strong>asynchronous I/O</strong> assuming the container supports it (e.g. Tomcat APR Connector). Indeed, as realtime connections are all maintained server side (either with WebSocket or Comet), clients are permanently connected. If you don&#8217;t use advanced mechanisms, available threads in connection pool can run out very quickly. Here comes async I/O, that breaks the 1 client / 1 thread paradigm and allows one server to handle numerous connected clients asynchronously. Of course, if your container can&#8217;t run async I/O, Atmosphere will fallback with common blocking thread per request.</p>
<p>Atmosphere can run in two modes: <strong>embedded</strong> or <strong>standalone</strong>. The first one is the classic approach and the one you generally choose when you start from scratch. The second one, called <a href="https://github.com/Atmosphere/nettosphere/blob/master/README.md">Nettosphere</a>, relies on the combination of the <a href="http://www.jboss.org/netty">Netty</a> container and the Atmosphere framework, allowing you to extend your existing Java webapp with realtime push capabilities in a non-intrusive<span style="color: #000000;"> way. Moreover, Nettosphere fits well when you need to do integration test on your realtime resources as you can instantiate it programmatically on demand, similarly to the <a href="http://jersey.java.net/nonav/documentation/latest/test-framework.html"><span style="color: #000000;">Jersey-test-framework</span></a>.</span></p>
<p><span style="color: #000000;">Usually, when you want to achieve standard <strong>comet</strong> (long-polling, streaming) communication, you don&#8217;t have to worry about the underneath container: they are compatible with Atmosphere. About <strong>WebSocket</strong> nonetheless, the compatibility will depend on the version of the WebSocket specification implemented by the container running Atmosphere. To this day, Jetty, Grizzly, Netty and even <a href="https://issues.apache.org/bugzilla/show_bug.cgi?id=51181" target="_blank"><span style="color: #000000;">Tomcat</span></a> are some WebSocket-capable containers.</span></p>
<p>A variety of <strong>modules and plugins</strong> are bundled with the framework, letting the user benefit from Atmosphere in various way: you are able to write Atmosphere applications in Java, Scala, JRuby and Groovy, and use other frameworks such as Jersey, GWT, Spring or JSF.</p>
<p>Another interesting thing: Atmosphere was built to scale thanks to <strong>clustering plugins</strong>. These plugins actually wrap a clustering layer implementation among JMS, Redis, XMPP or Hazelcast to name a few&#8230;  So if one server is not enough, you have tools to scale-out as needed.</p>
<p>Among all Atmosphere&#8217;s components, we find the <strong>jQuery plugin</strong>: this Javascript API connects your web pages to your server and offers methods to exchange realtime data. It can detect client&#8217;s capabilities and switch between protocols as necessary via a fallback mechanism. Therefore, the same user experience can be offered from IE6 to Chrome18.</p>
<p>From now on, we will focus on the Jersey&#8217;s Atmosphere extension, very convenient as it largely reduces lines to code thanks to JAX-RS implementation (annotations, json mapping, etc&#8230;).</p>
<h1>Grab your keyboard, launch your Eclipse!</h1>
<p>To demonstrate the use of Atmosphere, I chose to build an application that draws realtime events on a map: user can generate events by clicking on the map, and server can generate random events. A generated event (by either client or server) is delivered to each connected clients.</p>
<p>Thus, this application &#8211; called MapPush (I was not able to find anything more explicit!) &#8211; is composed of:</p>
<ul>
<li>The <strong>client</strong>, a simple HTML page that uses Javascript/jQuery to process logic</li>
<li>The <strong>server</strong>, a JEE webapp backed by Atmosphere and Jersey frameworks</li>
</ul>
<p><em>Note: the application is <em>hosted on <strong>Github</strong> at the address <a href="http://github.com/ncolomer/MapPush/">http://github.com/ncolomer/MapPush</a></em>. All the snippets below are extracted from this project. Feel free to browse the source code or clone the project!</em></p>
<h2>Project bootstrap</h2>
<p>In Eclipse, create a Maven project with a &#8220;webapp&#8221; archetype. As Atmosphere is available on Sonatype repositories (<a href="https://oss.sonatype.org/content/repositories/snapshots/org/atmosphere/">snapshots</a>, <a href="https://oss.sonatype.org/content/repositories/releases/org/atmosphere/">releases</a>), you can simply add the following to your <code>pom.xml</code> :</p>
<pre class="brush: xml; gutter: true; first-line: 1">&lt;!-- Sonatype repositories --&gt;
&lt;repositories&gt;
	&lt;repository&gt;
		&lt;id&gt;Sonatype snapshots&lt;/id&gt;
		&lt;url&gt;https://oss.sonatype.org/content/repositories/snapshots&lt;/url&gt;
	&lt;/repository&gt;
	&lt;repository&gt;
		&lt;id&gt;Sonatype releases&lt;/id&gt;
		&lt;url&gt;https://oss.sonatype.org/content/repositories/releases&lt;/url&gt;
	&lt;/repository&gt;
&lt;/repositories&gt;

&lt;!-- Dependencies --&gt;
&lt;dependencies&gt;
	&lt;!-- Atmosphere --&gt;
	&lt;dependency&gt;
		&lt;!-- Atmosphere&#039;s Comet Portable Runtime (CPR) --&gt;
		&lt;groupId&gt;org.atmosphere&lt;/groupId&gt;
		&lt;artifactId&gt;atmosphere-runtime&lt;/artifactId&gt;
		&lt;version&gt;0.9.7&lt;/version&gt;
	&lt;/dependency&gt;
	&lt;dependency&gt;
		&lt;!-- Atmosphere&#039;s Jersey module --&gt;
		&lt;!-- Transitivity will pull all necessary dependencies --&gt;
		&lt;!-- ie. Jersey 1.10 core, server, etc... --&gt;
		&lt;groupId&gt;org.atmosphere&lt;/groupId&gt;
		&lt;artifactId&gt;atmosphere-jersey&lt;/artifactId&gt;
		&lt;version&gt;0.9.7&lt;/version&gt;
	&lt;/dependency&gt;
	&lt;dependency&gt;
		&lt;!-- Atmosphere&#039;s jQuery plugin --&gt;
		&lt;groupId&gt;org.atmosphere&lt;/groupId&gt;
		&lt;artifactId&gt;atmosphere-jquery&lt;/artifactId&gt;
		&lt;version&gt;0.9.7&lt;/version&gt;
		&lt;type&gt;war&lt;/type&gt;
	&lt;/dependency&gt;
	&lt;!-- Jersey&#039;s JSON mapper --&gt;
	&lt;dependency&gt;
		&lt;groupId&gt;com.sun.jersey&lt;/groupId&gt;
		&lt;artifactId&gt;jersey-json&lt;/artifactId&gt;
		&lt;version&gt;1.10&lt;/version&gt;
	&lt;/dependency&gt;
&lt;/dependencies&gt;</pre>
<p>To start the framework we need a servlet, and not any&#8230; an AtmosphereServlet! In case the Atmosphere&#8217;s Jersey module is detected at load time, the framework will wrap around the Jersey Servlet (ContainerServlet) to load our resources and extend it with Atmosphere capabilities (IoC, annotations, etc&#8230;). Therefore, Jersey&#8217;s init-params are still available.</p>
<p>Open the <code>web.xml</code> file of your project and paste the following snippet:</p>
<pre class="brush: xml; gutter: true; first-line: 1">&lt;!-- Atmosphere --&gt;
&lt;servlet&gt;
    &lt;description&gt;AtmosphereServlet&lt;/description&gt;
    &lt;servlet-name&gt;AtmosphereServlet&lt;/servlet-name&gt;
    &lt;servlet-class&gt;org.atmosphere.cpr.AtmosphereServlet&lt;/servlet-class&gt;
    &lt;init-param&gt;
        &lt;!-- Jersey base package of your resources --&gt;
        &lt;param-name&gt;com.sun.jersey.config.property.packages&lt;/param-name&gt;
        &lt;param-value&gt;org.mappush.resource&lt;/param-value&gt;
    &lt;/init-param&gt;
    &lt;init-param&gt;
        &lt;!-- Enable Jersey&#039;s JSON mapping feature --&gt;
        &lt;param-name&gt;com.sun.jersey.api.json.POJOMappingFeature&lt;/param-name&gt;
        &lt;param-value&gt;true&lt;/param-value&gt;
    &lt;/init-param&gt;
    &lt;load-on-startup&gt;0&lt;/load-on-startup&gt;
&lt;/servlet&gt;
&lt;servlet-mapping&gt;
    &lt;servlet-name&gt;AtmosphereServlet&lt;/servlet-name&gt;
    &lt;url-pattern&gt;/api/*&lt;/url-pattern&gt;
&lt;/servlet-mapping&gt;</pre>
<p>We are now ready to code both client and server application.</p>
<h2>The server</h2>
<p>If you have already used the official JAX-RS implementation, Jersey, you won&#8217;t be disapointed. For others, you&#8217;ll find out that programming Atmosphere push APIs is really&#8230; dead simple!</p>
<p>Among the essential pieces of Atmosphere, one is called <strong><a href="http://atmosphere.github.com/atmosphere/apidocs/org/atmosphere/cpr/Broadcaster.html">Broadcaster</a></strong>. This is the object that manages connected clients and delivers broadcasted messages to them. A connected client is seen as an <strong><a href="http://atmosphere.github.com/atmosphere/apidocs/org/atmosphere/cpr/AtmosphereResource.html">AtmosphereResource</a> </strong>by the framework.</p>
<p>In the push communication lifecycle, we can define three steps:</p>
<ul>
<li>the client sends a request, that is suspended (in case of comet) or upgraded (in case of websocket) by the server.</li>
<li>then, server and client can exchange data : server generally broadcasts/pushes data to clients, and in case of a duplex protocol like WebSocket, client can send data back to it.</li>
<li>finally, either one closes the connection.</li>
</ul>
<p>Atmosphere offers two convenient ways to handle this lifecycle: you can choose between <strong>annotation</strong> or <strong>programmatic API</strong> (or even a combination of both), the last one allowing more customization from my point of view.</p>
<ul>
<li>To suspend a request, use the <a href="http://atmosphere.github.com/atmosphere/apidocs/org/atmosphere/annotation/Suspend.html">@Suspend</a> annotation, or simply return a <strong><a href="http://atmosphere.github.com/atmosphere/apidocs/org/atmosphere/jersey/SuspendResponse.html">SuspendResponse</a></strong></li>
<li>To broadcast data, use the  <a href="http://atmosphere.github.com/atmosphere/apidocs/org/atmosphere/annotation/Broadcast.html">@Broadcast</a> annotation and simply return a <strong><a href="http://atmosphere.github.com/atmosphere/apidocs/org/atmosphere/jersey/Broadcastable.html">Broadcastable</a></strong>. For a more specific use of broadcast mechanism, you are able to manually deal with the <strong><a href="http://atmosphere.github.com/atmosphere/apidocs/org/atmosphere/cpr/Broadcaster.html">Broadcaster</a></strong> and its <em>broadcast(&#8230;)</em> methods to push messages to all, a subset or a particular <strong><a href="http://atmosphere.github.com/atmosphere/apidocs/org/atmosphere/cpr/AtmosphereResource.html">AtmosphereResource</a></strong>.</li>
</ul>
<p><span style="line-height: 18px;">Here is an exemple of Atmosphere resource using the main concepts we have described above:</span></p>
<pre class="brush: java; gutter: true; first-line: 1; highlight: [26,45,46,64]">@Path(&quot;/&quot;)
@Singleton
public class EventResource {

	private final Logger logger = LoggerFactory.getLogger(EventResource.class);

	private EventListener listener;
	private EventGenerator generator;

	private @Context BroadcasterFactory bf;

	/**
	 * Programmatic way to get a Broadcaster instance
	 * @return the MapPush Broadcaster
	 */
	private Broadcaster getBroadcaster() {
		return bf.lookup(DefaultBroadcaster.class, &quot;MapPush&quot;, true);
    }

	/**
	 * The @PostConstruct annotation makes this method executed by the
	 * container after this resource is instanciated. It is one way
	 * to initialize the Broadcaster (e.g. by adding some Filters)
	 */
	@PostConstruct
	public void init() {
		logger.info(&quot;Initializing EventResource&quot;);
		BroadcasterConfig config = getBroadcaster().getBroadcasterConfig();
		config.addFilter(new BoundsFilter());
		listener = new EventListener();
		generator = new EventGenerator(getBroadcaster(), 100);
	}

	/**
	 * When the client connects to this URI, the response is suspended or
	 * upgraded if both client and server arc WebSocket capable. A Broadcaster
	 * is affected to deliver future messages and manage the
	 * communication lifecycle.
	 * @param res the AtmosphereResource (injected by the container)
	 * @param bounds the bounds (extracted from header and deserialized)
	 * @return a SuspendResponse
	 */
	@GET
	@Produces(MediaType.APPLICATION_JSON)
	public SuspendResponse&lt;String&gt; connect(@Context AtmosphereResource res,
			@HeaderParam(&quot;X-Map-Bounds&quot;) Bounds bounds) {
		if (bounds != null) res.getRequest().setAttribute(&quot;bounds&quot;, bounds);
		return new SuspendResponse.SuspendResponseBuilder&lt;String&gt;()
				.broadcaster(getBroadcaster())
				.outputComments(true)
				.addListener(listener)
				.build();
	}

	/**
	 * This URI allows a client to send a new Event that will be broadcaster
	 * to all other connected clients.
	 * @param event the Event (deserialized from JSON by Jersey)
	 * @return a Response
	 */
	@POST
	@Path(&quot;event&quot;)
	@Consumes(MediaType.APPLICATION_JSON)
	public Response broadcastEvent(Event event) {
		logger.info(&quot;New event: {}&quot;, event);
		getBroadcaster().broadcast(event);
		return Response.ok().build();
	}

	// ...

}</pre>
<h3 class="brush: java; gutter: true; first-line: 1">Listen for client messages</h3>
<p class="brush: java; gutter: true; first-line: 1">In case of a duplex protocol, we said a client can send data back to the server using the connection. But how do we handle such messages? Atmosphere provides a <strong>listener mechanism</strong>, implementable via interfaces such as the <a href="http://atmosphere.github.com/atmosphere/apidocs/org/atmosphere/cpr/AtmosphereResourceEventListener.html">AtmosphereResourceEventListener</a> or its WebSocket specialization, the <a href="http://atmosphere.github.com/atmosphere/apidocs/org/atmosphere/websocket/WebSocketEventListener.html">WebSocketEventListener</a>. The WebSocket interface exposes useful methods like <code>onConnect</code>, <code>onHandshake</code>, <code>onDisconnect</code>, or <code>onMessage</code>. Listeners are declared when the client connects (ie. when suspending a response).</p>
<pre class="brush: java; gutter: true; first-line: 1">public class EventListener extends WebSocketEventListenerAdapter {

	private final Logger logger = LoggerFactory.getLogger(EventListener.class);

	@Override
	public void onMessage(WebSocketEvent event) {
		Bounds bounds = JsonUtils.fromJson(event.message(), Bounds.class);
		if (bounds == null) return;
		logger.info(&quot;New bounds {} for resource {}&quot;,
				event.message(), event.webSocket().resource().hashCode());
		AtmosphereRequest req = event.webSocket().resource().getRequest();
		req.setAttribute(&quot;bounds&quot;, bounds);
	}

}</pre>
<h3 class="brush: java; gutter: true; first-line: 1">Filter your broadcasted messages</h3>
<p class="brush: java; gutter: true; first-line: 1">You may also have observed the <code>init()</code> method&#8230; but what is done inside exactly ?</p>
<p>A possibility offered by the framework is the ability to include logic before delivering message to each connected client. We can achieve that thanks to the <a href="http://atmosphere.github.com/atmosphere/apidocs/org/atmosphere/cpr/BroadcastFilter.html">BroadcastFilter</a> interface and its specialization, the <a href="http://atmosphere.github.com/atmosphere/apidocs/org/atmosphere/cpr/PerRequestBroadcastFilter.html">PerRequestBroadcastFilter</a> interface. The first interface allows to execute logic once (common to all clients) whereas the second one can apply to each client according to their associated context (session data, first connection headers, etc&#8230;).</p>
<p>Each BroadcastFilter can <code>CONTINUE</code> or <code>ABORT</code> a broadcast. While the broadcast is not aborted, the filter chain is executed in order (BroadcastFilters first, PerRequestBroadcastFilters then) and finally delivered (or not) to each client. The following snippet is an example of PerRequestBroadcastFilter implementation:</p>
<pre class="brush: java; gutter: true; first-line: 1">public class BoundsFilter implements PerRequestBroadcastFilter {

    private final Logger logger = LoggerFactory.getLogger(BoundsFilter.class);

    @Override
    public BroadcastAction filter(Object originalMessage, Object message) {
        return new BroadcastAction(ACTION.CONTINUE, originalMessage);
    }

    @Override
    public BroadcastAction filter(AtmosphereResource res,
            Object originalMessage, Object message) {
        logger.info(&quot;BoundsFilter triggered for AtmosphereResource {} &quot;+
				&quot;with message {}&quot;, res.hashCode(), message);
        Event event = (Event) message;
        try {
            Bounds bounds = (Bounds) res.getRequest().getAttribute(&quot;bounds&quot;);
            if (bounds == null) throw new NoBoundsException(&quot;no bounds&quot;);
            if (bounds.contains(event)) {
                String json = JsonUtils.toJson(event); // Manual serialization
                return new BroadcastAction(ACTION.CONTINUE, json);
            } else {
                return new BroadcastAction(ACTION.ABORT, message);
            }
        } catch (NoBoundsException e) {
            logger.info(&quot;Applying default action CONTINUE, cause: {}&quot;,
					e.getMessage());
            String json = JsonUtils.toJson(event); // Manual serialization
            return new BroadcastAction(ACTION.CONTINUE, json);
        } catch (Exception e) {
            logger.info(&quot;Filter BoundsFilter aborted, cause: {}&quot;,
					e.getMessage());
            return new BroadcastAction(ACTION.ABORT, message);
        }
    }

}</pre>
<h2>The client</h2>
<p><span style="color: #000000;">Now that all is ready server side, we are able to connect our clients to the realtime endpoint. If you plan to use WebSocket, several clients are compatible with Atmosphere. Let&#8217;s focus on Java and Javascript ones:</span></p>
<ul>
<li><span style="color: #000000;">In java, you find several projects like <a href="https://github.com/TooTallNate/Java-WebSocket"><span style="color: #000000;">Java-WebSocket</span></a> or <a href="https://github.com/sonatype/async-http-client"><span style="color: #000000;">async-http-client</span></a>. Some webapp containers also provide a WebSocket client implementation (e.g. <a href="http://download.eclipse.org/jetty/stable-7/apidocs/org/eclipse/jetty/websocket/package-summary.html"><span style="color: #000000;">Jetty</span></a>)</span></li>
<li><span style="color: #000000;">In Javascript, most of recent browsers implement the <a href="http://dev.w3.org/html5/websockets/"><span style="color: #000000;">WebSocket</span></a> interface. But, in case the browser is not compatible with WebSocket, this API can&#8217;t fallback into another protocol. Here comes the jQuery Atmosphere Plugin and its fallback mechanism.</span></li>
</ul>
<p><span style="color: #000000;">In our case, you probably guessed, we&#8217;ll use the Atmosphere jQuery plugin. Please note that due to the jQuery dependency, we have to import the jQuery library in addition to the Atmosphere plugin.</span></p>
<p>Once done, connect to the server is no more complicated than the following <code>connect()</code> javascript routine:</p>
<pre class="brush: javascript; gutter: true; first-line: 1; highlight: [4,28]">var endpoint;
function connect() {

    var callback = function callback(response) {
        // Websocket events.
        if (response.state == &quot;opening&quot;) {
            console.log(&quot;Connected to realtime endpoint&quot;);
        } else if (response.state == &quot;closed&quot;) {
            console.log(&quot;Disconnected from realtime endpoint&quot;);
        } else if (response.transport != &#039;polling&#039; &amp;&amp;
                response.state == &#039;messageReceived&#039;) {
            if (response.status == 200) {
                var data = response.responseBody;
                if (data.length &gt; 0) {
                    statsAgent.notify();
                    console.log(&quot;Message Received: &quot; + data +
                            &quot; &amp; detected transport is &quot; + response.transport);
                    var json = JSON.parse(data);
                    mapsAgent.drawEvent(json);
                }
            }
        }
    };

    var bounds = mapsAgent.getBounds();
    var header = bounds.southLat + &quot;,&quot; + bounds.northLat +
            &quot;,&quot; + bounds.westLng + &quot;,&quot; + bounds.eastLng;
    endpoint = $.atmosphere.subscribe(url, callback, {
        transport: &#039;websocket&#039;,
		/* available transports: websocket, jsonp, long-polling,
			polling, streaming */
        attachHeadersAsQueryString: true,
        headers: {&quot;X-Map-Bounds&quot;: header}
    });
}</pre>
<p>You can see that we attach headers when connecting. They are used here to transmit some client context when connecting (actually, the current bounds of t<span style="color: #000000;">he map). As the WebSocket handshake doesn&#8217;t allow the client to pass any headers, they have to be serialized in the query string, justifying the </span><code>attachHeadersAsQueryString: true</code> entry. On the server side, the query string will be translated to headers so application wise, you don&#8217;t have to care about the difference.</p>
<p>To process message pushed from the server, we can add a callback. It will be triggered on each received message, passing a response (Javascript object) containing values as <code>status</code>, <code>state</code>, <code>transport</code> etc&#8230;</p>
<p>The <code>endpoint</code> variable &#8211; that stores the connection &#8211; was made global to be used when you want to disconnect the client from the realtime endpoint or push data to the server. The following snippet shows you the two corresponding javascript routines.</p>
<pre class="brush: javascript; gutter: true; first-line: 1; highlight: [1,6]">function disconnect() {
	$.atmosphere.unsubscribe();
	endpoint = null;
}

function update(bounds) {
	console.log(&quot;### Map bounds changed:&quot;, JSON.stringify(bounds));
	if (!endpoint) return;
	endpoint.push(JSON.stringify(bounds));
}</pre>
<h2>Testing your WebSocket resources</h2>
<p>In addition to regular browser testing, you can easily try your realtime URIs with a shell and <a href="http://curl.haxx.se/docs/manpage.html">cURL</a>:</p>
<pre class="brush: bash; gutter: true; first-line: 1">curl -v -N -XGET http://localhost:8080/MapPush/api</pre>
<ul>
<li><code>-v/--verbose</code>: Make the operation more talkative</li>
<li><code>-N/--no-buffer</code>: Disable buffering of the output stream</li>
<li><code>-X/--request &lt;command&gt;</code>: Specify request command to use</li>
</ul>
<p>With the second option, you will be able to observe all data sent by the server. Nonetheless, note that you&#8217;ll not be able to send data back to it.</p>
<p>cURL also allows you to send headers with the request:</p>
<pre class="brush: bash; gutter: true; first-line: 1">boundsHeader=&#039;48.0,49.0,2.0,3.0&#039;
curl -v -N -XGET http://localhost:8080/MapPush/api -H &quot;X-MAP-BOUNDS: $boundsHeader&quot;</pre>
<ul>
<li><code>-H/--header &lt;line&gt;</code>: Custom header to pass to server</li>
</ul>
<p>You can also go deeper and analyse WebSocket frames with tools such as <a href="http://ngrep.sourceforge.net/">ngrep</a> or <a href="http://www.wireshark.org/">Wireshark</a>: these are a bit more complex tools but it may become very useful in some situations!</p>
<h1>Conclusion</h1>
<p><span style="color: #000000;">Atmophere provides a powerful ecosystem that simplifies the creation of push applications and makes easy full-duplex communication between a server and any kind of client. Its intensive use of async I/O and its ready-to-use clustering plugins give it both performance and scalability. Moreover, the project is under Open source Apache license, the community is growing quickly and the last 0.9 version is stabilizing fast.</span></p>
<p><span style="color: #000000;">In short, the Atmosphere framework has a bright future :)</span></p>
<h1 class="brush: bash; gutter: true; first-line: 1">Additional Resources</h1>
<ul>
<li>Atmosphere project is hosted on <a href="https://github.com/Atmosphere/atmosphere">GitHub</a>:
<ul>
<li>Download the Atmosphere&#8217;s <a href="https://github.com/Atmosphere/atmosphere/raw/master/docs/atmosphere_whitepaper.pdf">whitepaper</a></li>
<li>Take a look at the <a href="https://github.com/Atmosphere/atmosphere/tree/master/samples">samples</a></li>
<li>Browse the <a href="http://atmosphere.github.com/atmosphere/apidocs/">Javadoc</a></li>
</ul>
</li>
<li>The community is reachable via Atmosphere&#8217;s <a href="http://groups.google.com/group/atmosphere-framework">Google Group</a></li>
<li>You can also follow Atmosphere via Jean-Francois Arcand&#8217;s <a href="http://jfarcand.wordpress.com/">blog</a> and <a href="http://twitter.com/atmo_framework">Twitter</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.ncolomer.net/2012/03/cometwebsocket-introducing-the-atmosphere-framework/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>Domain name migration</title>
		<link>http://www.ncolomer.net/2012/03/domain-name-migration/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=domain-name-migration</link>
		<comments>http://www.ncolomer.net/2012/03/domain-name-migration/#comments</comments>
		<pubDate>Sun, 18 Mar 2012 21:41:08 +0000</pubDate>
		<dc:creator>Nicolas Colomer</dc:creator>
				<category><![CDATA[DevOps]]></category>
		<category><![CDATA[How to]]></category>
		<category><![CDATA[domain name]]></category>
		<category><![CDATA[htaccess]]></category>
		<category><![CDATA[migration]]></category>
		<category><![CDATA[robot]]></category>
		<category><![CDATA[seo]]></category>

		<guid isPermaLink="false">http://www.ncolomer.net/?p=466</guid>
		<description><![CDATA[I just migrated my website (the one you&#8217;re reading actually!) from www.colomern.net to the new URL www.ncolomer.net. Normally, you should have felt no difference thanks to some tips gleaned here and there on the web. My first approach was to put a custom index.php file on &#8230;<p class="read-more"><a href="http://www.ncolomer.net/2012/03/domain-name-migration/">Read more &#187;</a></p>]]></description>
				<content:encoded><![CDATA[<p>I just migrated my website (the one you&#8217;re reading actually!) from <span style="font-size: xx-small;">www.colomern.net</span> to the new URL <a href="http://www.ncolomer.net/">www.ncolomer.net</a>. Normally, you should have felt no difference thanks to some tips gleaned here and there on the web.</p>
<p>My first approach was to put a custom <code>index.php</code> file on the old domain that permanently redirects all root requests to my new domain:</p>
<pre class="brush: php; gutter: true; first-line: 1">&lt;?php
// Permanent redirection
header(&quot;HTTP/1.1 301 Moved Permanently&quot;);
header(&quot;Location: http://www.ncolomer.net/&quot;);
exit();
?&gt;</pre>
<p>But what about the old URLs that map my blog articles, the one that was indexed by Google? In a such situation, the best way to do the least possible harm (ie. do not lost SEO robots) is to redirect all old URLs to my new domain. This can be done using a simple <code>.htaccess</code> containing the following:</p>
<pre class="brush: text; gutter: true; first-line: 1">RewriteEngine on
RedirectMatch 301 ^(.*)$ http://www.ncolomer.net$1</pre>
<p class="brush: text; gutter: true; first-line: 1">Thus, all requests on <a href="http://www.colomern.net/2011/03/bonjour-tout-le-monde/"><strong>colomern.net</strong>/2011/03/bonjour-tout-le-monde</a> for instance will instantly be redirected (<a href="http://en.wikipedia.org/wiki/HTTP_301">301 Moved Permanently</a>) to <a href="http://www.ncolomer.net/2011/03/bonjour-tout-le-monde/"><strong>ncolomer.net</strong>/2011/03/bonjour-tout-le-monde</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ncolomer.net/2012/03/domain-name-migration/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Set up a Ubuntu as a home/web server</title>
		<link>http://www.ncolomer.net/2011/09/set-up-a-ubuntu-as-a-homeweb-server/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=set-up-a-ubuntu-as-a-homeweb-server</link>
		<comments>http://www.ncolomer.net/2011/09/set-up-a-ubuntu-as-a-homeweb-server/#comments</comments>
		<pubDate>Sun, 04 Sep 2011 15:54:05 +0000</pubDate>
		<dc:creator>Nicolas Colomer</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://www.colomern.net/?p=361</guid>
		<description><![CDATA[I recently added a page to my Wiki: it presents some procedures on how install and setup a Ubuntu distribution as a home and web server. Tested and approved on my own network! The wiki page is available here. Edit: &#8230;<p class="read-more"><a href="http://www.ncolomer.net/2011/09/set-up-a-ubuntu-as-a-homeweb-server/">Read more &#187;</a></p>]]></description>
				<content:encoded><![CDATA[<p>I recently added a page to my Wiki: it presents some procedures on how install and setup a Ubuntu distribution as a home and web server. Tested and approved on my own network!</p>
<p>The wiki page is available <a title="Ubuntu as home server" href="http://www.ncolomer.net/wiki/index.php?title=Ubuntu_as_home_server" target="_blank">here</a>.</p>
<p><em>Edit: I added some <a href="http://www.ncolomer.net/wiki/index.php?title=Ubuntu_as_home_server#Manage_disks">tips</a> to optimize Ubuntu when running on a SSD</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ncolomer.net/2011/09/set-up-a-ubuntu-as-a-homeweb-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>More fun with Redis</title>
		<link>http://www.ncolomer.net/2011/07/more-fun-with-redis/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=more-fun-with-redis</link>
		<comments>http://www.ncolomer.net/2011/07/more-fun-with-redis/#comments</comments>
		<pubDate>Wed, 27 Jul 2011 09:47:57 +0000</pubDate>
		<dc:creator>Nicolas Colomer</dc:creator>
				<category><![CDATA[How to]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Storage]]></category>
		<category><![CDATA[jedis]]></category>
		<category><![CDATA[memcache]]></category>
		<category><![CDATA[nosql]]></category>
		<category><![CDATA[phone number]]></category>
		<category><![CDATA[redis]]></category>
		<category><![CDATA[set]]></category>
		<category><![CDATA[slot management]]></category>
		<category><![CDATA[sorted set]]></category>
		<category><![CDATA[transaction]]></category>

		<guid isPermaLink="false">http://www.colomern.net/?p=269</guid>
		<description><![CDATA[In my precedent blog post, we introduced the way to install and start playing with Redis. Now, I propose you to go further, with a more advanced use case. In my personnal project development (f.ollow.us), I faced a new problem: How &#8230;<p class="read-more"><a href="http://www.ncolomer.net/2011/07/more-fun-with-redis/">Read more &#187;</a></p>]]></description>
				<content:encoded><![CDATA[<div>
<p><a href="http://www.colomern.net/wp-content/uploads/2011/07/Capture-d’écran-2011-07-26-à-15.02.18-e1311685712218.png"><img class="alignleft size-full wp-image-283" title="Capture d’écran 2011-07-26 à 15.02.18" src="http://www.colomern.net/wp-content/uploads/2011/07/Capture-d’écran-2011-07-26-à-15.02.18-e1311685712218.png" alt="" width="150" height="47" /></a>In my precedent blog <a href="http://www.colomern.net/2011/07/time-to-redis/">post</a>, we introduced the way to install and start playing with Redis. Now, I propose you to go further, with a more advanced use case. In my personnal project development (<a title="Follow us" href="http://f.ollow.us" target="_blank">f.ollow.us</a>), I faced a new problem:</p>
<p>How can we manage efficiently a fixed number of &#8220;slots&#8221; that have a TTL (i.e. Time To Live) and can be held (i.e. be available or not) in a high concurrency context? Don&#8217;t look further, Redis is the solution!</p>
<p><span id="more-269"></span></p>
<h1>The problem</h1>
<p>To be more explicit about what we try to solve here, i&#8217;ll give you another example. This one involves phone operators. You are aware that they dispose of a (large) range of phone number that can be used or vacant. Sometimes, customers break their contract and their phone number becomes available after a while. Sometimes, new customers subscribe a phone plan and they are given a random phone number. It&#8217;s exactly the same problem here.</p>
<p>Actually, we have to answer at least four constraints:</p>
<ul>
<li>Know if a phone number is available or not</li>
<li>Retrieve an available phone number (preferably, the oldest one)</li>
<li>Ask for them transactionally (race condition support)</li>
<li>Expire phone numbers with time (they become available)</li>
</ul>
<p>What about the Redis TTL feature you&#8217;ll say, does it solve the problem? I think the response is no. Ho yeah, we can probably imagine a solution, in which you select all used slots (not expired, existing in the db), store them in a set, and finally make a <a href="http://en.wikipedia.org/wiki/Difference_(set_theory)#Relative_complement">difference</a> with another set that contains all known slots&#8230; but these operations take time, CPU and memory.</p>
<p>Why bother when the solution is so close? The Redis &#8220;sorted set&#8221; data type is our solution.</p>
<h1>The solution</h1>
<h2>What is a Sorted Set?</h2>
<p>Accordingly to the official <a title="Redis" href="http://redis.io" target="_blank">redis.io</a> website, sorted sets are &#8220;non repeating collections of Strings&#8221;. In reality, this simple definition hides the most advanced Redis data type. Sorted sets are advanced Redis sets, that associate each element with a score. This score permits elements to be taken permanently in order (and not ordered afterwards), resulting great performances when accessing to the set entries.</p>
<p>Redis offers useful commands to access such data sets by score (<a title="Zscore" href="http://redis.io/commands/zscore">ZSCORE</a>) or by rank (<a title="Zrank" href="http://redis.io/commands/zrank">ZRANK</a>), or select only a range of them (once again) by score (<a title="Zrangebyscore" href="http://redis.io/commands/zrangebyscore">ZRANGEBYSCORE</a>) or by rank (<a title="Zrange" href="http://redis.io/commands/zrange">ZRANGE</a>). For the three last commands, time complexity is equivalent to O(log(N)), with N the number of elements in the sorted set: no longer doubt about performances! To get a full list of Sorted sets dedicated commands, you can have a see to this <a title="Sorted set" href="http://redis.io/commands#sorted_set">web page</a>.</p>
<p>We don&#8217;t need more to achieve our task!</p>
<h2>Code it with Java</h2>
<p>The code you&#8217;ll find below is <strong>a</strong> Java implementation of what we need to solve the &#8220;slot management&#8221; problem. It boils down to a simple class named <em>PhoneNumberManager</em>, which contains some static methods.</p>
<p>To converse with a Redis instance, I used the Jedis API (the Java Redis client). Jedis instances are retrieved from the RedisManager described in my precedent <a href="http://www.colomern.net/2011/07/time-to-redis/">post</a> about Redis.</p>
<p>First, we have to populate the sorted set with all phone numbers that we wish to use. These numbers are stored as simple strings. Each element is associated with the default 0 score. This initialization is done by using the <em>init</em>() method.</p>
<p>Once initialized, we can retrieve available phone numbers with the method <em>getAvailableSlot</em>(). A retrieved phone number have to be held or released via respective methods <em>hold</em>() and <em>release</em>().</p>
<p>There are also three more useful methods:</p>
<ul>
<li><em>getSize</em>() returns the current number of elements in the sorted set</li>
<li><em>getExpirationTimestamp</em>() returns the expiration timestamp for a given phone number</li>
<li><em>isAvailable</em>() checks the availability of a phone number</li>
</ul>
<p>Each of these methods are atomic (unique read/write atomic access to Redis) except the <em>getAvailableSlot</em>() method, which use <a title="Redis transactions" href="http://redis.io/topics/transactions">transaction mechanism</a> (<a title="WATCH" href="http://redis.io/commands/watch">WATCH</a>, <a title="MULTI" href="http://redis.io/commands/multi">MULTI</a>, <a title="EXEC" href="http://redis.io/commands/exec">EXEC</a>) to support race condition on giving available phone number.</p>
<p>I think it&#8217;s time to paste some Java code&#8230;</p>
<pre class="brush: java; gutter: true; first-line: 1">import java.util.Date;
import java.util.Set;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Response;
import redis.clients.jedis.Transaction;

/**
 * This class manage all available phone numbers via static methods.
 * It uses Jedis instances from a JedisPool.
 */
public class PhoneNumberManager {

	/**
	 * This method populates the &quot;numbers&quot; sorted set.
	 * @param number The number of slots to allocate
	 */
	public static void init(int number) {
		Jedis jedis = RedisManager.getJedis();
		// Delete the key if exists
		jedis.del(&quot;numbers&quot;);
		// Populate the sorted set
		int number = Integer.parseInt(&quot;600000000&quot;);
		for (int i = 0; i &lt; 10; i++) {
			jedis.zadd(&quot;numbers&quot;, i, &quot;+33&quot; + Integer.toString(number++));
		}
		RedisManager.returnJedis(jedis);
	}

	/**
	 * Returns the number of phone number.
	 * @return the number of phone number
	 */
	public static long getSize() {
		Jedis jedis = RedisManager.getJedis();
		Long card = jedis.zcard(&quot;numbers&quot;);
		RedisManager.returnJedis(jedis);
		return card;
	}

	/**
	 * This methods searches for an available phone number.
	 * The operation is atomic: The phone number (if found) is owned
	 * only by the claimant.
	 * You can release the phone number by using {@link #release()}.
	 * You can hold the phone number by using {@link #hold()}.
	 * @return A free phone number
	 * @throws Exception If no one is available
	 */
	public static String getAvailableSlot() throws Exception {
		Jedis jedis = RedisManager.getJedis();
		// Start watching the sorted set (preventing any modification)
		jedis.watch(&quot;numbers&quot;);
		try {
			String number = null;
			// Try to get an available phone number
			Set&lt;String&gt; availableNumber = jedis.zrangeByScore(&quot;numbers&quot;,
					Double.NEGATIVE_INFINITY, new Date().getTime(), 0, 1);
			if (!availableNumber.isEmpty()) {
				number = availableNumber.iterator().next();
				// Start transaction to remove the phone number from list
				Transaction t = jedis.multi();
				Response&lt;Long&gt; poped = t.zrem(&quot;numbers&quot;, number);
				t.exec();
				if (poped.get() != 1)
					throw new Exception(&quot;Problem getting available&quot; +
						&quot; phone number, please retry&quot;);
				else return number;
			} else {
				throw new Exception(&quot;No phone number available&quot;);
			}
		} catch (Exception e) {
			throw e;
		} finally {
			jedis.unwatch();
			RedisManager.returnJedis(jedis);
		}
	}

	/**
	 * This method holds a phone number for a given time.
	 * @param number The phone number to hold
	 */
	public static void hold(String number) {
		long timestamp = (long)(new Date().getTime()*1E-3 + duration);
		Jedis jedis = RedisManager.getJedis();
		jedis.zadd(&quot;numbers&quot;, timestamp, number);
		RedisManager.returnJedis(jedis);
	}

	/**
	 * This method release a given phone number.
	 * @param number The phone number to release
	 */
	public static void release(String number) {
		Jedis jedis = RedisManager.getJedis();
		jedis.zadd(&quot;numbers&quot;, 0, number);
		RedisManager.returnJedis(jedis);
	}

	/**
	 * This method returns the expiration timestamp of a phone number
	 * @param number The phone number
	 * @return The phone number expiration timestamp, null if not found
	 */
	public static Long getExpirationTimestamp(String number) {
		Jedis jedis = RedisManager.getJedis();
		Double score = jedis.zscore(&quot;numbers&quot;, number);
		RedisManager.returnJedis(jedis);
		return score.longValue();
	}

	/**
	 * This method checks the availability of a phone number.
	 * @param number The phone number
	 * @return false if slot does not exist or already expired,
	 * true otherwise
	 */
	public static boolean isAvailable(String number) {
		Long timestamp = getExpirationTimestamp(number);
		if (timestamp == null) return false;
		if (timestamp &lt;= (long)(new Date().getTime()*1E-3)) return false;
		return true;
	}

}</pre>
<p>&nbsp;</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.ncolomer.net/2011/07/more-fun-with-redis/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Time to Redis!</title>
		<link>http://www.ncolomer.net/2011/07/time-to-redis/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=time-to-redis</link>
		<comments>http://www.ncolomer.net/2011/07/time-to-redis/#comments</comments>
		<pubDate>Tue, 12 Jul 2011 12:05:12 +0000</pubDate>
		<dc:creator>Nicolas Colomer</dc:creator>
				<category><![CDATA[How to]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Storage]]></category>
		<category><![CDATA[expire]]></category>
		<category><![CDATA[key]]></category>
		<category><![CDATA[memcache]]></category>
		<category><![CDATA[nosql]]></category>
		<category><![CDATA[pool]]></category>
		<category><![CDATA[redis api]]></category>
		<category><![CDATA[token]]></category>
		<category><![CDATA[transaction]]></category>
		<category><![CDATA[ttl]]></category>
		<category><![CDATA[value]]></category>

		<guid isPermaLink="false">http://www.colomern.net/blog/?p=101</guid>
		<description><![CDATA[Redis is a &#8211; take a deep breath - nosql key-value in-memory storage system, also called memcache. It is written in ANSI C and works in most POSIX operating systems. Its features are numerous: high perf, on disk persistence, replication, pub/sub and &#8230;<p class="read-more"><a href="http://www.ncolomer.net/2011/07/time-to-redis/">Read more &#187;</a></p>]]></description>
				<content:encoded><![CDATA[<p><img class="alignleft" title="Redis" src="http://www.h-online.com/imgs/43/6/3/4/1/4/8/redis_logo200-659049d37f1fb3ad.png" alt="" width="160" height="51" />Redis is a &#8211; take a deep breath - <em>nosql key-value in-memory</em> storage system, also called memcache. It is written in ANSI C and works in most POSIX operating systems. Its features are numerous: high perf, on disk persistence, replication, pub/sub and TTL (i.e. Time To Live) to name a few.</p>
<p>The community around Redis is very active, resulting a lot of client for many languages: Java, Node, Ruby, PHP, etc. On this post, after a brief &#8220;How to set up Redis&#8221;, I will focus on one of the most active Java API, Jedis.</p>
<p><span id="more-101"></span></p>
<h1>First steps with Redis</h1>
<p>To familiarize with, as first approach, you can try the excellent online interactive <a title="Redis online interactive tutorial" href="http://try.redis-db.com/">tutorial</a>.</p>
<p>Once you are ready to go further, simply run these commands on a shell to install Redis:</p>
<pre class="brush: shell; gutter: false; first-line: 1">wget http://redis.googlecode.com/files/redis-2.2.11.tar.gz
tar xzf redis-2.2.11.tar.gz
cd redis-2.2.11
make</pre>
<p>Then, you can execute the Redis server with:</p>
<pre class="brush: shell; gutter: false; first-line: 1">src/redis-server</pre>
<p>And finally, interact with it by running the Redis client:</p>
<pre class="brush: shell; gutter: false; first-line: 1">src/redis-cli</pre>
<p>Throughout your tests, you will probably generate a lot of keys. Here is a useful Redis command to delete all keys, once.</p>
<pre class="brush: shell; gutter: false; first-line: 1">flushdb</pre>
<h1>Jedis, the Java Redis API</h1>
<p>The Jedis API is an open project hosted on <a title="Jedis Java client" href="https://github.com/xetorthio/jedis">Github</a>. It supports most of Redis features, including <em>connection handling &amp; pooling</em>, <em>transactions</em>, <em>pipelining</em> or <em>publish/subscribe</em>. Please refer to the <em>Related links</em> part below to get some pointers about Jedis.</p>
<p>Jedis contributors done things well. They created a class that enable the API to work in a multithreaded environment. Here is a quotation from their wiki page.</p>
<blockquote><p>A single Jedis instance is not threadsafe! To avoid these problems, you should use <strong>JedisPool</strong>, which is a threadsafe pool of network connections. You can use the pool to reliably create several Jedis instances, given you return the Jedis instance to the pool when done.</p>
<p>You can store the pool somewhere statically, it is thread-safe.</p></blockquote>
<p>No sooner said than done! We can write a simple RedisManager to handle our pool of jedis instances. Here is a way to do so:</p>
<pre class="brush: java; gutter: true; first-line: 1">import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class RedisManager {
	private static final RedisManager instance = new RedisManager();
	private static JedisPool pool;
	private RedisManager() {}
    public final static RedisManager getInstance() {
        return instance;
    }
	public void connect() {
		// Create and set a JedisPoolConfig
		JedisPoolConfig poolConfig = new JedisPoolConfig();
		// Maximum active connections to Redis instance
		poolConfig.setMaxActive(10);
		// Tests whether connection is dead when connection
		// retrieval method is called
		poolConfig.setTestOnBorrow(true);
		/* Some extra configuration */
		// Tests whether connection is dead when returning a
		// connection to the pool
		poolConfig.setTestOnReturn(true);
		// Number of connections to Redis that just sit there
		// and do nothing
		poolConfig.setMaxIdle(5);
		// Minimum number of idle connections to Redis
		// These can be seen as always open and ready to serve
		poolConfig.setMinIdle(1);
		// Tests whether connections are dead during idle periods
		poolConfig.setTestWhileIdle(true);
		// Maximum number of connections to test in each idle check
		poolConfig.setNumTestsPerEvictionRun(10);
		// Idle connection checking period
		poolConfig.setTimeBetweenEvictionRunsMillis(60000);
		// Create the jedisPool
		pool = new JedisPool(poolConfig, &quot;localhost&quot;, 6379);
	}
	public void release() {
		pool.destroy();
	}
	public Jedis getJedis() {
		return pool.getResource();
	}
	public void returnJedis(Jedis jedis) {
		pool.returnResource(jedis);
	}
}</pre>
<p class="brush: java; gutter: true; first-line: 1">Note that JedisPool class depends on the Apache commons-pool library. You can download this lib from the <a title="Apache commons-pool" href="http://commons.apache.org/pool/" target="_blank">main page</a> of the project.</p>
<h1>The token problem</h1>
<p>This problem is about transaction. Redis offers some native atomic functions like <a title="INCR" href="http://redis.io/commands/incr" target="_blank">INCR</a> or <a title="DECR" href="http://redis.io/commands/decr" target="_blank">DECR</a>, but also a transactional mechanism, also called &#8220;check-and-set&#8221;. This is what we will use below.</p>
<p>The problem I had is quite simple: I have to set keys that expire (TTL). Some Threads scan asynchronously for expired keys. If a thread detects that a key is absent, it executes some http requests which is time expensive (and a blocking io). We have to avoid that two or more threads executes the same request!</p>
<p>This problem can be solved by using a <strong>token</strong>. This is how I made it work:</p>
<ul>
<li>The thread test the presence of a key. If the key exists, it ignores it and search for another key. This test has to be atomic.</li>
<li>If the key does not exist, the thread set a provisional value for this key that does not expire: It the the token. Other threads that will ask for this key in the future will show that it is already set (or in progress).</li>
<li>After the execution, the worker thread, that get responses to requests (or not), set the final value, that expire after a fixed time.</li>
</ul>
<p>Here is the code:</p>
<pre class="brush: java; gutter: true; first-line: 1">	// Get Jedis instance from pool
	Jedis jedis = redisManager.getJedis();
	jedis.watch(&quot;key:&quot;+myKey);
	String value = jedis.get(&quot;key:&quot;+myKey);
	if (type == null) {
		// No value for the key, we set the token atomically
		Transaction t = jedis.multi();
		Response&lt;String&gt; response = t.set(&quot;key:&quot;+myKey, &quot;Searching&quot;);
		t.exec();
		if (response != null) {
			// The key was correctly set
			// You can do stuff here...
			// And finally update the key
			jedis.setex(&quot;key:&quot;+myKey, TIMEOUT, myValue);
		}
	}
	// Return the jedis instance to the pool
	jedis.unwatch();
	redisManager.returnJedis(jedis);</pre>
<h1>Related links</h1>
<ul>
<li>To learn more on how Redis handles transactions, you can read the official related <a title="Transactions in Redis" href="http://redis.io/topics/transactions" target="_blank">topic</a></li>
<li>The page presenting all available <a title="Redis client API" href="http://redis.io/clients" target="_blank">client APIs</a></li>
<li>Some extra links about Jedis:
<ul>
<li>The <a title="Jedis downloads" href="https://github.com/xetorthio/jedis/downloads" target="_blank">download</a> page, where you can get latest Jars</li>
<li>The <a title="Jedis wiki page" href="https://github.com/xetorthio/jedis/wiki" target="_blank">wiki</a> page, where concept and usage are explained</li>
<li>Some extra <a title="Jedis documentation" href="http://redis.io/documentation" target="_blank">documentation</a></li>
</ul>
</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.ncolomer.net/2011/07/time-to-redis/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Replace a Time Capsule disk</title>
		<link>http://www.ncolomer.net/2011/06/replace-a-time-capsule-disk/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=replace-a-time-capsule-disk</link>
		<comments>http://www.ncolomer.net/2011/06/replace-a-time-capsule-disk/#comments</comments>
		<pubDate>Fri, 24 Jun 2011 10:23:16 +0000</pubDate>
		<dc:creator>Nicolas Colomer</dc:creator>
				<category><![CDATA[Hardware]]></category>
		<category><![CDATA[How to]]></category>
		<category><![CDATA[backup]]></category>
		<category><![CDATA[disk]]></category>
		<category><![CDATA[frequency]]></category>
		<category><![CDATA[partition]]></category>
		<category><![CDATA[replace disk]]></category>
		<category><![CDATA[storage]]></category>
		<category><![CDATA[time capsule]]></category>
		<category><![CDATA[time machine]]></category>

		<guid isPermaLink="false">http://www.colomern.net/blog/?p=130</guid>
		<description><![CDATA[The price of HDD declined significantly last years. Today, you can afford a 2TB one for less than $100. Why not take this opportunity to increase the capacity of your Time Capsule? For that matter, prefer a silent and energy &#8230;<p class="read-more"><a href="http://www.ncolomer.net/2011/06/replace-a-time-capsule-disk/">Read more &#187;</a></p>]]></description>
				<content:encoded><![CDATA[<p><img class="alignleft" title="The Time Capsule" src="http://cache.gawkerassets.com/assets/images/4/2008/01/Time_Capsule_Front_Back.jpg" alt="" width="120" />The price of HDD declined significantly last years. Today, you can afford a 2TB one for less than $100. Why not take this opportunity to increase the capacity of your Time Capsule?</p>
<p>For that matter, prefer a silent and energy efficient HDD (e.g. &#8220;green&#8221; products from Seagate, Samsung or Western Digital). These HDD rotate more often at 5400 rpm. That&#8217;s enough to do daily backups (not so IO intensive).</p>
<p>Here is a step by step procedure to change your Time Capsule disk in no more than 15 minutes!</p>
<p><span id="more-130"></span></p>
<h1>Changing the disk</h1>
<p>Please note that all data on your old drive will be lost. You&#8217;ll have to reconfigure your Mac&#8217;s Time Machine once you finished, and start a full backup.</p>
<p>Here is the underside of my Time Capsule <img src='http://www.ncolomer.net/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p><a href="http://www.colomern.net/wp-content/uploads/2011/06/TC_01.jpg"><img class="aligncenter size-medium wp-image-150" title="TC_01" src="http://www.colomern.net/wp-content/uploads/2011/06/TC_01-300x224.jpg" alt="" width="300" height="224" /></a>Remove the rubber. Don&#8217;t be afraid, it is just stuck, you&#8217;ll be able to stuck it again at the end. Once done, you should see something like that.</p>
<p><a href="http://www.colomern.net/wp-content/uploads/2011/06/TC_02.jpg"><img class="aligncenter size-medium wp-image-151" title="TC_02" src="http://www.colomern.net/wp-content/uploads/2011/06/TC_02-300x224.jpg" alt="" width="300" height="224" /></a>Unscrew all the visible screws (ten that fix the hull and four that fix the HDD) and lift the metal part. Be careful, a fan is attached to the part you are removing. If you don&#8217;t want to unplug the fan, place the metal part as in the following image.</p>
<p><a href="http://www.colomern.net/wp-content/uploads/2011/06/TC_03.jpg"><img class="aligncenter size-medium wp-image-152" title="TC_03" src="http://www.colomern.net/wp-content/uploads/2011/06/TC_03-300x224.jpg" alt="" width="300" height="224" /></a>Unstuck the little temperature sensor from the disk surface (the solid foam square). Unplug the disk SATA and power connectors.</p>
<p><a href="http://www.colomern.net/wp-content/uploads/2011/06/TC_04.jpg"><img class="aligncenter size-medium wp-image-153" title="TC_04" src="http://www.colomern.net/wp-content/uploads/2011/06/TC_04-300x224.jpg" alt="" width="300" height="224" /></a>You are now up to extract the disk carefully.</p>
<p><a href="http://www.colomern.net/wp-content/uploads/2011/06/TC_05.jpg"><img class="aligncenter size-medium wp-image-154" title="TC_05" src="http://www.colomern.net/wp-content/uploads/2011/06/TC_05-300x224.jpg" alt="" width="300" height="224" /></a>Finally, plug and place the new disk in the same way than the old one. Stuck the temperature sensor, replace the metal part and screw it. Power your Time Capsule. The status light should blink in orange and, after a while, be fixed green.</p>
<p>Use the Apple Airport utility to configure your Time Capsule if necessary (disk tab once connected).</p>
<h1>About disk partitioning</h1>
<p>It may be useful when you want to share data on your network (public file depot) and use Time Machine backups. Partioning disk seems to be feasible, although more binding. I have not experienced myself (the adapter is missing), but some people already achieved this. You need:</p>
<ul>
<li>An USB to SATA adapter, recycled from an USB SATA disk drive or easily foundable on eBay.</li>
<li>A Mac to format your disk with Mac OS partition table and type. I tried with Ubuntu, without success.</li>
</ul>
<ol>
<li>Connect your disk to your adapter and plug the USB cable on your Mac.</li>
<li>Open the MacOS Disk Utility or spotlight it. You should see your USB hard drive on the left panel. Select it.</li>
<li>Click to the Partition tab, and create as many partition as your need in your Time Capsule.<br />
<span style="text-decoration: underline;">Note</span> that you have to choose Apple partition table to be recognized by your Time Capsule. You can use MacOS Extended (Journalized) as partition format, even though Time Capsule automatically format your partitions if it was not done or in wrong format. You can also name your partitions, they will be displayed by the Time Capsule.</li>
<li>Unmount your USB disk from your Mac, unplug your hard drive from the adapter, and plug it into the Time Capsule.</li>
<li>Once powered and connected to your network, display the Time Capsule settings via Airport Utility and go to the disk tab. You should see your partitions. You can access them with the finder by connecting to your Time Capsule.</li>
</ol>
<h1>Set the backup frequency</h1>
<p>By default, the Time Machine backup frequency is set to 3600 seconds, i.e. one hour. You can set this value by opening a terminal and execute the following bash command:</p>
<pre class="brush: bash; gutter: false; first-line: 1">sudo defaults write /System/Library/LaunchDaemons/com.apple.backupd-auto StartInterval -int 86400</pre>
<p>Here, the backup frequency is set to 86400 seconds, i.e. one day.</p>
<p>You have to restart for this change to take effect.</p>
<h1>Related links</h1>
<ul>
<li>(FR) Allain Le Gallou <a href="http://www.legallou.com/Mac/TimeCapsule/TCpartition.html">partitioning Time Capsule</a> page</li>
<li>(FR) MacBidouille <a href="http://www.macbidouille.com/articles/244/page1">change Time Capsule disk</a> page</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.ncolomer.net/2011/06/replace-a-time-capsule-disk/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Use OpenStreetMap web API</title>
		<link>http://www.ncolomer.net/2011/06/use-openstreetmap-web-api/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=use-openstreetmap-web-api</link>
		<comments>http://www.ncolomer.net/2011/06/use-openstreetmap-web-api/#comments</comments>
		<pubDate>Tue, 14 Jun 2011 13:40:50 +0000</pubDate>
		<dc:creator>Nicolas Colomer</dc:creator>
				<category><![CDATA[Geomatics]]></category>
		<category><![CDATA[How to]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[geocoding]]></category>
		<category><![CDATA[mapquest]]></category>
		<category><![CDATA[nominatim]]></category>
		<category><![CDATA[openstreetmap]]></category>
		<category><![CDATA[osm]]></category>
		<category><![CDATA[rest]]></category>
		<category><![CDATA[reverse geocoding]]></category>
		<category><![CDATA[web service]]></category>
		<category><![CDATA[xapi]]></category>
		<category><![CDATA[xml]]></category>

		<guid isPermaLink="false">http://www.colomern.net/blog/?p=50</guid>
		<description><![CDATA[OpenStreetMap (i.e. OSM) is a community which creates and provides free and open geographic data. The project started because most available maps, such as Google Maps or Bing, have legal or technical restrictions on their use: lot of content are &#8230;<p class="read-more"><a href="http://www.ncolomer.net/2011/06/use-openstreetmap-web-api/">Read more &#187;</a></p>]]></description>
				<content:encoded><![CDATA[<p><img class="alignleft" title="OpenStreetMap" src="http://www.openstreetmap.org/assets/osm_logo-caccd6371f095ca973c373b8e2014896.png" alt="" />OpenStreetMap (i.e. OSM) is a community which creates and provides free and open geographic data. The project started because most available maps, such as Google Maps or Bing, have legal or technical restrictions on their use: lot of content are not exposed due to copyrights, belonging to mapping companies (e.g. NAVTEQ or Tele Atlas) or national agencies (e.g. Ordnance Survey or IGN). To see how rich is OpenStreetMap data, you can have a preview via the <a href="http://www.itoworld.com/product/data/ito_map/main" target="_blank">ito! map</a> project.</p>
<p>The main feature of OpenStreetMap is to provide a map, as Google do. You can <a href="http://www.openstreetmap.org/" target="_blank">access</a> it on there main site or <a href="http://wiki.openstreetmap.org/wiki/Deploying_your_own_Slippy_Map" target="_blank">embed</a> it in your own website. But you can also access OSM data in other ways than viewing them in a browser&#8230;</p>
<p><span id="more-50"></span></p>
<h1>OpenStreetMap available API</h1>
<p>Indeed OpenStreetMap provides several API to create, modify and read geographic content. In addition, some API provide advanced querying features (e.g. geocoding or reverse geocoding features).</p>
<p>All the available API are listed below:</p>
<ul>
<li><a href="http://wiki.openstreetmap.org/wiki/API" target="_blank">API</a>: OpenStreetMap editing API for fetching and saving raw geodata from/to the OpenStreetMap database.</li>
<li><a href="http://wiki.openstreetmap.org/wiki/XAPI" target="_blank">Xapi</a>: OpenStreetMap extended read-only API, based on a modified version of the standard API, that provides enhanced querying capabilities, as bouding-box or X-path.</li>
<li><a href="http://wiki.openstreetmap.org/wiki/Nominatim" target="_blank">Nominatim</a>: OpenStreetMap search engine, for searching OSM data by name and address and generating synthetic addresses of returned OSM points (i.e. reverse geocoding).</li>
</ul>
<p>Xapi and Nominatim are what will interest us today. These API are used as one of the sources for the Search box on the OpenStreetMap home page, but also powers other websites like <a href="http://open.mapquest.com/" target="_blank">MapQuest</a>.</p>
<p>Because of official OpenStreetMap servers are mostly overloaded and out of date, their use are not recommended. Fortunately, other providers are available (you can see the additional link section for more information). We will focus on one of the most relevant providers: the MapQuest Open Initiative.</p>
<p>MapQuest is a mapping company based in the United States and wholly-owned by AOL. In 2010, The company announced their support for OpenStreetMap, making MapQuest the first large online mapping service to embrace OSM. They since earmarked $1 million in resources to help improve the OSM data in the United States, with the stated intention of possibly using OSM data for their maps of the U.S. in the future.</p>
<p>The <a title="MapQuest" href="http://wiki.openstreetmap.org/wiki/MapQuest" target="_blank">MapQuest Open Initiative</a> is one of the results of their support efforts. In addition to localized websites, it provides an API to read and query OSM data. These data are frequently updated from OSM (every 15 minutes for map data, every 5 minutes for search data and daily for routing data). So there is no problem to get fresh data quickly!</p>
<h1>Using OpenStreetMap API</h1>
<h2>The data model</h2>
<p>In order to use API via MapQuest, we first have to understand the data model used by OpenStreetMap. OSM data is stored as XML. Basically, it is a list of instances of 3 data primitives:</p>
<ul>
<li><a title="Nodes" href="http://wiki.openstreetmap.org/wiki/Nodes" target="_blank">Node</a>, a single geospatial point.</li>
<li><a title="Ways" href="http://wiki.openstreetmap.org/wiki/Ways">Way</a>, an ordered interconnection of at least 2 nodes that describe a linear feature (e.g. street, footpath, railway line, river, &#8230;).</li>
<li><a title="Relations" href="http://wiki.openstreetmap.org/wiki/Relations" target="_blank">Relation</a>, used to group way or node objects that are geographically related (i.e. connected or adjacent to one another).</li>
</ul>
<p>To summarize, querying the API should return all or part of the following XML schema:</p>
<pre class="brush: xml; gutter: true; first-line: 1; highlight: [8,10,14,21]">&lt;?xml version=&#039;1.0&#039; standalone=&#039;no&#039;?&gt;
&lt;osm version=&#039;0.6&#039; generator=&#039;xapi: OSM Extended API&#039;
 xmlns:xapi=&#039;http://www.informationfreeway.org/xapi/0.6&#039;
 xapi:uri=&#039;/api/0.6/*[amenity=hotel]&#039;
 xapi:planetDate=&#039;200803150826&#039;
 xapi:copyright=&#039;2008 OpenStreetMap contributors&#039;
 xapi:instance=&#039;zappy2&#039;&gt;
  &lt;node id=&#039;218963&#039; lat=&#039;52.5611324692581&#039; lon=&#039;-1.79024812573334&#039; timestamp=&#039;2006-03-22T16:47:48+00:00&#039; version=&#039;1&#039; changeset=&#039;2211&#039;&gt;
  &lt;/node&gt;
  &lt;node id=&#039;331193&#039; lat=&#039;53.7091237972264&#039; lon=&#039;-1.50282510180841&#039; timestamp=&#039;2007-03-31T00:09:22+01:00&#039; version=&#039;1&#039; changeset=&#039;2211&#039;&gt;
    &lt;tag k=&#039;amenity&#039; v=&#039;hotel&#039;/&gt;
  &lt;/node&gt;
  ...
  &lt;way id=&#039;4958218&#039; timestamp=&#039;2007-07-25T01:55:35+01:00&#039; version=&#039;1&#039; changeset=&#039;2211&#039;&gt;
    &lt;nd ref=&#039;218963&#039;/&gt;
    &lt;nd ref=&#039;331193&#039;/&gt;
    ...
    &lt;tag k=&#039;amenity&#039; v=&#039;hotel&#039;/&gt;
    &lt;tag k=&#039;building&#039; v=&#039;hotel&#039;/&gt;
  &lt;/way&gt;
  &lt;relation id=&#039;123456&#039; timestamp=&#039;2007-10-25T03:05:34Z&#039; version=&#039;32&#039; changeset=&#039;2211&#039;&gt;
    &lt;member type=&#039;node&#039; ref=&#039;331193&#039; role=&#039;&#039;/&gt;
    &lt;member type=&#039;node&#039; ref=&#039;331194&#039; role=&#039;&#039;/&gt;
    ...
    &lt;tag k=&#039;amenity&#039; v=&#039;hotel&#039;/&gt;
    &lt;tag k=&#039;operator&#039; v=&#039;Premier Inns&#039;/&gt;
    &lt;tag k=&#039;type&#039; v=&#039;operators&#039;/&gt;
  &lt;/relation&gt;
&lt;/osm&gt;</pre>
<h2>Querying the API</h2>
<p>The previous XML result can be obtained by querying Xapi. The querying engine allows the use of filters also called predicates. There are 3 types of predicates:</p>
<ul>
<li><strong>Tag</strong> predicates, to match any node that has a key with the wanted value. For instance, use the link <code>api/0.6/node[amenity=hospital]</code> to get all nodes in which tag <code>amenity</code> exists and equals <code>hospital</code></li>
<li><strong>BBox</strong> (i.e. bounding box) predicates, which limit the result to the selected bounding box region. For instance, the link <code>api/0.6/node[bbox=-6,50,2,61]</code> will return all objects localized in the region limited by the <code>[left=-6°, bottom=50°, right=2°, top=61°]</code> box.</li>
<li><strong>Child element</strong> predicates, to select objects matching X-path like conditions. For instance, the link <code>api/0.6/way/14310041</code> will return the <code>way</code> object matching <code>14310041</code> id.</li>
</ul>
<p>However, there is limitations on the use of predicates. Currently each request is limited to one tag predicate and one bbox predicate. Child element predicates are used to query a specific OSM object with a known ID.</p>
<h2>A simple example</h2>
<p>To illustrate the use of our API, imagine that we want to know the <a href="http://wiki.openstreetmap.org/wiki/Key:highway">highway type</a> (e.g. motorway, trunk, primary,&#8230;) of a road for a given position. To do so, we have to execute 2 requests:</p>
<ul>
<li>The first one is a reverse geocoding request, which will give us the street address of a location and the OSM ID of the associated way.</li>
<li>The second is a Xapi request, which will give us highway information for a give highway id, like its type.</li>
</ul>
<p>Assume that the location correspond to the following geo coordinates <code>(48.888320; 2.249920)</code>.</p>
<p>The first step can be accomplished by sending the following GET request (follow the link to see the result):</p>
<p><a href="http://open.mapquestapi.com/nominatim/v1/reverse?lat=48.888320&amp;lon=2.249920" target="_blank">http://open.mapquestapi.com/nominatim/v1/reverse?lat=48.888320&amp;lon=2.249920</a></p>
<p>In the result XML, we can see the <code>...osm_type="way" osm_id="14310041"...</code> string. We can conclude that the returned object type is <code>way</code>, and its OSM id is <code>14310041</code>.</p>
<p>These data will allow us to write and execute the second request (follow the link to see the result):</p>
<p><a href="http://open.mapquestapi.com/xapi/api/0.6/way/14310041">http://open.mapquestapi.com/xapi/api/0.6/way/14310041</a></p>
<p>Among the result&#8217;s tags, we can find the <code>&lt;tag k="highway" v="motorway"/&gt;</code> key/value tag. We finally can assert that the highway type is <code>motorway</code>!</p>
<h1>Additional links</h1>
<ul>
<li>To learn more about OpenStreetMap, you can have a see on their <a href="http://wiki.openstreetmap.org/wiki/Faq" target="_blank">FAQ</a>.</li>
<li>The community greatly highlights the ability for common user to contribute to the project (create and update geographic content). To learn more on how to contribute, you can read their <a href="http://wiki.openstreetmap.org/wiki/Beginners%27_guide">beginners&#8217; guide</a>.</li>
<li>To learn more on the MapQuest API, see their <a href="http://open.mapquestapi.com/">developer&#8217;s guide</a>.</li>
<li>To learn more on using Xapi, you can read the dedicated <a href="http://wiki.openstreetmap.org/wiki/XAPI">wiki</a> page and test it on <a href="http://open.mapquestapi.com/xapi/">MapQuest Xapi</a> page.</li>
<li>To learn more on using Nominatim, you can read the dedicated <a href="http://wiki.openstreetmap.org/wiki/Nominatim">wiki</a> page and test it on <a href="http://open.mapquestapi.com/nominatim/">MapQuest Nominatim</a> page.</li>
<li>Other geocoding web services using OpenStreetMap exist on the web. You can have a look at <a title="Géocoding mondial" href="http://services.gisgraphy.com/public/geocoding_worldwide.html">Worldwide Geocoding</a> or <a title="GeoNames" href="http://www.geonames.org/export/ws-overview.html">GeoNames</a>.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.ncolomer.net/2011/06/use-openstreetmap-web-api/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Handle Post Multipart with Java</title>
		<link>http://www.ncolomer.net/2011/03/handle-post-multipart-with-java/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=handle-post-multipart-with-java</link>
		<comments>http://www.ncolomer.net/2011/03/handle-post-multipart-with-java/#comments</comments>
		<pubDate>Sun, 13 Mar 2011 18:42:47 +0000</pubDate>
		<dc:creator>Nicolas Colomer</dc:creator>
				<category><![CDATA[How to]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[jee]]></category>
		<category><![CDATA[jsp]]></category>
		<category><![CDATA[multipart]]></category>
		<category><![CDATA[post]]></category>
		<category><![CDATA[servlet]]></category>

		<guid isPermaLink="false">http://www.colomern.net/blog/?p=36</guid>
		<description><![CDATA[Handle post multipart is quite simple with languages like PHP. But what about if you develop your forms with JEE, including Servlets &#38; JSP? Here is some procedures and advices to understand how to handle post multipart form with JEE. &#8230;<p class="read-more"><a href="http://www.ncolomer.net/2011/03/handle-post-multipart-with-java/">Read more &#187;</a></p>]]></description>
				<content:encoded><![CDATA[<p>Handle <a href="http://en.wikipedia.org/wiki/MIME#Multipart_messages">post multipart</a> is quite simple with languages like PHP. But what about if you develop your forms with JEE, including Servlets &amp; JSP?</p>
<p>Here is some procedures and advices to understand how to handle post multipart form with JEE.</p>
<p><span id="more-36"></span>The API we will use is called FileUpload from Apache commons API.</p>
<p>As usual, some web resources about this API:</p>
<ul>
<li><a href="http://commons.apache.org/fileupload/">Apache FileUpload main page</a></li>
<li>&#8230; Where you can find the <a href="http://commons.apache.org/fileupload/using.html">user guide</a></li>
<li>&#8230; And some <a href="http://commons.apache.org/fileupload/apidocs/index.html">JavaDoc</a></li>
</ul>
<p>You can download the latest version of this FileUpload API (1.2.1 &#8211; 18 January 2008) using this <a href="http://commons.apache.org/fileupload/download_fileupload.cgi">link</a>. Simply add the .jar library to your Eclipse Project to use it.</p>
<p>The first thing is to create our JSP file, which will contain our form:</p>
<pre class="brush: html; gutter: true; first-line: 1"> ...
 &lt;%= request.getAttribute(&quot;message&quot;) %&gt;
 &lt;form action=&quot;.&quot; enctype=&quot;multipart/form-data&quot; method=&quot;post&quot;&gt;
 &lt;input accept=&quot;image/*&quot; name=&quot;file&quot; type=&quot;file&quot; /&gt;
 &lt;input type=&quot;submit&quot; value=&quot;Send&quot; /&gt;
 &lt;/form&gt;
 ...</pre>
<p>Then, write the web.xml deployment descriptor as following in order to map correctly our servlet.</p>
<pre class="brush: xml; gutter: true; first-line: 1">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;web-app id=&quot;WebApp_ID&quot; version=&quot;2.4&quot;
	xmlns=&quot;http://java.sun.com/xml/ns/j2ee&quot;
	xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
	xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd&quot;&gt;
	&lt;!-- WebApp Name --&gt;
	&lt;display-name&gt;MyPostServlet&lt;/display-name&gt;
	&lt;!-- Servlet declaration --&gt;
	&lt;servlet&gt;
		&lt;servlet-name&gt;post&lt;/servlet-name&gt;
		&lt;servlet-class&gt;foo.post.Servlet&lt;/servlet-class&gt;
	&lt;/servlet&gt;
	&lt;!-- Servlet url mapping --&gt;
	&lt;servlet-mapping&gt;
		&lt;servlet-name&gt;post&lt;/servlet-name&gt;
		&lt;url-pattern&gt;/post&lt;/url-pattern&gt;
	&lt;/servlet-mapping&gt;
	&lt;!-- Default welcome page --&gt;
	&lt;welcome-file-list&gt;
		&lt;welcome-file&gt;post&lt;/welcome-file&gt;
	&lt;/welcome-file-list&gt;
&lt;/web-app&gt;</pre>
<p>We can now create our main servlet which will handle GET and POST requests:</p>
<ul>
<li>The doGet method simply dispatch to our form.jsp,</li>
<li>The doPost method parse the multipart request and then&#8230; call the doGet method.</li>
</ul>
<p>Before process the post as a multipart one, you have to test it (see line 21).</p>
<p>When you parse the multipart post request with the ServletFileUpload.parseRequest(req) method, you get a List as return (see line 37).</p>
<p>Finally, loop with an Iterator to get all the FileItem of the request (see line 43).</p>
<pre class="brush: java; gutter: true; first-line: 1; highlight: [21,37,43]">public class Servlet extends HttpServlet {

	private static final String CACHE_PATH = &quot;./temp/&quot;;
	private static final int CACHE_SIZE = 100*(int)Math.pow(10,6);
	private static final int MAX_REQUEST_SIZE = 10*(int)Math.pow(10,6);
	private static final int MAX_FILE_SIZE = 1*(int)Math.pow(10,6);

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {

		// Redirecting to the test form
		req.getRequestDispatcher(&quot;form.jsp&quot;).forward(req, resp);

	}

	@Override
	public void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {

		if (ServletFileUpload.isMultipartContent(req))
		{
			// Create a factory for disk-based file items
			DiskFileItemFactory factory = new DiskFileItemFactory();
			// Set factory constraints
			factory.setRepository(new File(CACHE_PATH));
			factory.setSizeThreshold(CACHE_SIZE);

			// Create a new file upload handler
			ServletFileUpload upload = new ServletFileUpload(factory);
			// Set overall request size constraint
			upload.setSizeMax(MAX_REQUEST_SIZE);
			upload.setFileSizeMax(MAX_FILE_SIZE);

			// Parse the request
			@SuppressWarnings(&quot;unchecked&quot;)
			List&lt;FileItem&gt; items = upload.parseRequest(req);

			// Process the uploaded items
			Iterator iter = items.iterator();
			while (iter.hasNext())
			{
				FileItem item = (FileItem) iter.next();

				if (item.isFormField())
				{
					// The FileItem is a (text) form field
					// You can save it to a database
				}
				else
				{
					// The FileItem is a file
					// You can write it on the disk
				}
			}
		}
		// Add a validation message to the request
		req.setAttribute(&quot;message&quot;,&quot;The file was uploaded&quot;);
		// Redirect as a GET request to print the form again
		doGet(req,resp);

	}

}</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.ncolomer.net/2011/03/handle-post-multipart-with-java/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Generate and use a Google Maps debug API key</title>
		<link>http://www.ncolomer.net/2011/03/generate-and-use-a-google-map-debug-api-key/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=generate-and-use-a-google-map-debug-api-key</link>
		<comments>http://www.ncolomer.net/2011/03/generate-and-use-a-google-map-debug-api-key/#comments</comments>
		<pubDate>Sun, 13 Mar 2011 16:57:45 +0000</pubDate>
		<dc:creator>Nicolas Colomer</dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[How to]]></category>
		<category><![CDATA[adk]]></category>
		<category><![CDATA[api key]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[mac]]></category>
		<category><![CDATA[maps]]></category>
		<category><![CDATA[mapview]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://www.colomern.net/blog/?p=12</guid>
		<description><![CDATA[To start using Google Maps on your Android application, you need no more than a MapView and some GeoPoint. Nevertheless, in order to show map tiles loaded and drawn on your Android application when debugging (on AVD or phone), you&#8217;ll &#8230;<p class="read-more"><a href="http://www.ncolomer.net/2011/03/generate-and-use-a-google-map-debug-api-key/">Read more &#187;</a></p>]]></description>
				<content:encoded><![CDATA[<p>To start using Google Maps on your Android application, you need no more than a <a title="MapView" href="http://code.google.com/intl/fr-FR/android/add-ons/google-apis/reference/com/google/android/maps/MapView.html">MapView</a> and some <a title="GeoPoint" href="http://code.google.com/intl/fr-FR/android/add-ons/google-apis/reference/com/google/android/maps/GeoPoint.html">GeoPoint</a>. Nevertheless, in order to show map tiles loaded and drawn on your Android application when debugging (on AVD or phone), you&#8217;ll have to obtain a Maps API Key.</p>
<p>The procedure splits in three steps:</p>
<ul>
<li>Obtain the debug certificate (official procedure <a title="Obtaining Maps API key" href="http://code.google.com/intl/fr/android/add-ons/google-apis/mapkey.html" target="_blank">here</a>)</li>
<li>Sign up for a Maps API (official procedure <a title="Sign up for Maps API key" href="http://code.google.com/intl/fr/android/maps-api-signup.html" target="_blank">here</a>)</li>
<li>Start playing with MapView !</li>
</ul>
<p><span id="more-12"></span></p>
<h1>Step one: obtain the debug certificate</h1>
<p>Each installed Android SDK have a unique debug certificate. You&#8217;ll have to get the MD5 Fingerprint of this certificate in order to pretend a Maps API key.</p>
<p>First, we have to locate the <em>debug.keystore</em> file on the computer and note down its path. This file is generally located at these following paths:</p>
<pre class="brush: bash; gutter: false; first-line: 1"># Linux / MacOS
~/.android/debug.keystore</pre>
<pre class="brush: bash; gutter: false; first-line: 1"># Windows
C:\Documents and Settings\&lt;user&gt;\.android\debug.keystore</pre>
<p>Please note that <em>.android</em> is a hidden directory in both OS.</p>
<p>Then, we must generate the MD5 Fingerprint of our debug keystore. To do so, we will use <em>keytool</em>, a tool bundled with any java JDK. You can find it in the following paths (or similar).</p>
<pre class="brush: bash; gutter: false; first-line: 1"># Linux
$JAVA_HOME/bin/keytool
# MacOS
JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home
$JAVA_HOME/bin/keytool</pre>
<pre class="brush: bash; gutter: false; first-line: 1"># Windows
C:\Program Files\Java\jdk1.6.0_23\bin\keytool.exe</pre>
<p>Open a terminal or a dos box and change the working directory to the java bin/ path seen above (the <em>keytool</em> directory). You can now launch the following command:</p>
<pre class="brush: bash; gutter: false; first-line: 1">keytool -list -alias androiddebugkey -keystore &quot;path_to_your_debug.keystore&quot; \
-storepass android -keypass android</pre>
<p>Note down the generated MD5 Fingerprint present in the result. It should look like:</p>
<pre class="brush: bash; gutter: false; first-line: 1">01:E9:C8:C0:BF:E3:4C:5F:A3:EE:28:33:BD:10:D3:19</pre>
<h1>Step two: sign up for a Maps API key</h1>
<p>We have now to register the debug certificate with the Android Maps API service.</p>
<p>Connect to the Maps <a href="http://code.google.com/intl/fr/android/maps-api-signup.html">API Signup page</a> and enter your MD5 Fingerprint. (Read and) Accept terms of use and validate the form.</p>
<p>You just obtain the key you need to load map tiles in your Android application. It should look like:</p>
<pre class="brush: bash; gutter: false; first-line: 1">16ahjArI_Z393VYwzeGYJFT62pmG3LuKgZ0jy9w</pre>
<h1>Step three: start playing with MapView !</h1>
<p>To draw a MapView in your application, simply paste the following code snippet in a XML layout. Don&#8217;t forget to write your own API key in the <em>android:apiKey</em> property.</p>
<pre class="brush: xml; gutter: true; first-line: 1">&lt;com.google.android.maps.MapView
 android:id=&quot;@+id/MyMapView&quot;
 android:layout_width=&quot;match_parent&quot;
 android:layout_height=&quot;match_parent&quot;
 android:clickable=&quot;true&quot;
 android:apiKey=&quot;16ahjArI_Z393VYwzeGYJFT62pmG3LuKgZ0jy9w&quot;
 /&gt;</pre>
<p>You&#8217;ll probably need to change the API key for a production one. Instead of putting the API key into the XML layout, prefer define a string value by editing the res/values/strings.xml as following:</p>
<pre class="brush: xml; gutter: true; first-line: 1">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;resources&gt;
	&lt;string name=&quot;apikey&quot;&gt;16ahjArI_Z393VYwzeGYJFT62pmG3LuKgZ0jy9w&lt;/string&gt;
&lt;/resources&gt;</pre>
<p>And replace the <em>android:apiKey</em> value, in a XML layout, by:</p>
<pre class="brush: xml; gutter: false; first-line: 1">android:apiKey=&quot;@string/maps_apikey&quot;</pre>
<h1>Related links</h1>
<ul>
<li>More information about Google APIs add-on <a title="Google APIs" href="http://code.google.com/android/add-ons/google-apis/reference/index.html">here</a> (and the associated <a title="Google APIs reference" href="http://code.google.com/intl/fr-FR/android/add-ons/google-apis/reference/index.html">javadoc</a> API Reference)</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.ncolomer.net/2011/03/generate-and-use-a-google-map-debug-api-key/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Hello world !</title>
		<link>http://www.ncolomer.net/2011/03/bonjour-tout-le-monde/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=bonjour-tout-le-monde</link>
		<comments>http://www.ncolomer.net/2011/03/bonjour-tout-le-monde/#comments</comments>
		<pubDate>Wed, 02 Mar 2011 10:44:56 +0000</pubDate>
		<dc:creator>Nicolas Colomer</dc:creator>
				<category><![CDATA[Everything]]></category>

		<guid isPermaLink="false">http://www.colomern.net/blog/?p=1</guid>
		<description><![CDATA[There I am, another blog on the web. But this one is mine !]]></description>
				<content:encoded><![CDATA[<p>There I am, another blog on the web. But this one is mine !</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ncolomer.net/2011/03/bonjour-tout-le-monde/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
