Wednesday, July 27, 2011

Geo-location based content (content development)

In this part of the coverage of Hippo CMS Google Maps plugin I will show how to use the plugin when designing content types using Hippo CMS.

Btw, If something is not clear the source code also contains a demo project with a document that is already geo-tagged.


Dependency


First of all, in order to use the plugin we need to have the dependency added to your cms project pom:

    
        org.onehippo.plugins
        google-maps-plugin
        1.0
    
Keep in mind to use the latest available version (which is 1.0 at the time of writing).
In order for the plugin artefact to be resolved you can either build it and put it in your repository or fork the project and add it directly to your reactor pom as a module.


Document type


Once the dependency is added the plugin is ready to be used with Hippo CMS. The plugin offers custom compound type called 'Location'. The Location component can be added to the desired document type by selecting Location compound type on the Compound Field panel in the document type editor:


Upon selecting the Location component it will be added to the document type:


The rendering is done by the plugin itself while the structure is kept in the compound type. The location component contains some of the default values, such as latitudelongitude and zoom level.
When the document type is updated with the Location component it is possible to tag documents of that type with GPS coordinates.



Geo-tagging the documents



When opening document for editing the location component will be rendered by the plugin in the same fashion as shown above. Except that the data that is stored in the Latitude, Longitude and Zoom fields will be stored with the document.

The following is typical scenario how a document can be tagged with gps-location:

Let's say we want to tag current document with the location of Amsterdam. For that we could of course lookup the GPS coordinates of the city and manually put those values into the location fields.
Another possibility is to use the Search field which is only used for searching and does not store any values with the document. The plugin tries to find possible matches with as you type:


Once the desired match is selected the map automatically jumps to that place. All is left to do is to choose the right zoom level and click on the map to place a marker:


When the marker is being placed its' coordinates together with the current zoom level are recorded in the location fields:


That's it - the document is tagged! Upon saving (and closing) the document all stored location values (together with a static piece of map) will be displayed along with the rest of the document content:



In the next article I will show how to use that information on your website.

Saturday, July 23, 2011

Geo-location based content (Intro)

The deeper we go into the mobile age the more location based services surround us. Content management systems also have to keep up. In the end - location based-content always follows the location based services.
Being open source enthusiast I am using Hippo CMS for one of my hobby projects where I need to have the ability to tag content with GPS coordinates so that I could use, for example Google Maps, to show how the content is related to a certain place.

While it's certainly easy to assign a couple of meta-data fields to an article it is far from easy to find the desired coordinates and then manually enter add to the content considering you may have thousands of articles! The problem  is  was that those are exactly the requirements I needed! Coming from this an idea for an interactive CMS plugin that would make the editors' live easier was born!

First things first - I was looking for something that might already exist. Unfortunately, I couldn't find anything that was operational.
Eventually - after several evenings of coding and troubleshooting -  the initial version of the Hippo CMS Google Maps plug-in was ready and hosted on github.

In the next blog post I will show how to use the plugin on website (where the content is published) and on the CMS front-end (as content developer and author).

Thursday, January 6, 2011

Easy unit testing for Android

Testing and Mocking

Everyone who is, like me, 'spoiled'  by mocking frameworks like Mockito, EasyMock, etc know the pain of trying to write compact and readable unit tests for Android. Of course there is JUnit built-in support in Android that offers the whole battery of base classes in order to perform integration testing. And, surely, there is a number of base mock classes that are supposed to allow proper unit testing. However when it comes to writing the tests those mock classes are not really 'nice' mocks. They are not really that 'nice' because they do stuff like:

/**
 * A mock {@link android.content.Context} class.  All methods are non-functional and throw 
 * {@link java.lang.UnsupportedOperationException}.  You can use this to inject other dependencies,
 * mocks, or monitors into the classes you are testing.
 */
public class MockContext extends Context {

    @Override
    public AssetManager getAssets() {
        throw new UnsupportedOperationException();
    }

    @Override
    public Resources getResources() {
        throw new UnsupportedOperationException();
    }
...

}

As you can see it throws exceptions on every invocation, which means that if you want to use it you have to extend it. Problem is that it almost never limited by overriding just one method. And because your test cases are probably different the re-use of the extended MockContext is pretty limited and, again, if you try to create a re-usable MockContext the amount of effort will be somewhat close to re-writing the platform classes! So to go on with it you might start creating a number of subclasses of MockContext's to serve your particular needs. By the way, this is exactly what all the built-in subclasses of the MockContext do - even though they are a part of the public API if you have a closer look at them you might notice those are written for some particular cases to test the Android platform itself! But even those are not generic enough as you can see in this example:

RenamingDelegatingContext targetContextWrapper = new RenamingDelegatingContext(
                new MockContext2(), // The context that most methods are delegated to
                getContext(), // The context that file methods are delegated to
                filenamePrefix);

As you can see all sorts of compositions, extensions happen a lot.

Mockito to the rescue?

"Use a mocking framework" - many will probably think. Well, it's not as simple. The problem is that Dalvik VM is not really a Java VM. And most known pure-java mocking frameworks wont work out of the box, e.g. http://code.google.com/p/mockito/issues/detail?id=57
Some mocking frameworks require interfaces, which Android isn't really full of (for good reasons given the circumstances). Some mocking frameworks can do more than others and some have more or less ease of use.
Besides, if you base your classes on Android base TestCases it will run only on the emulator which isn't fast enough for unit testing.

So use the standard Java VM?

Right, the mocking frameworks will shine again! Not as simple again, you would need to mock every single call to classes contained in the Android platform (many of which are static!) which is probably even worse than just extending Android built-in mock classes.
Well, some (even people at Google) try to do it, but when I tried to repeat it with the real code I just gave up on the amount of work needed to be done just to perform simple testing.

Stumbled upon


And then I stumbled upon Robolectric. Robolectric is capable of either creating 'nice' stubs that don't throw RuntimeException("Stub!") (which is what happens if you use classes from distributable android.jar) or delegating calls to the classes in the Android platform. Basically, you can run unit tests outside the emulator in super-fast Java VM with all the mocking frameworks you like!

This allowed me to use my favorite Mockito without the need of having a separate test project, I simply employed maven!

There are plenty of articles on the Internet on how to mavenize android projects. My setup isn't much different from those so I will just focus on further customization. Quickly, I enabled dependencies to run Robolectric and Mockito in the test phase:


        
            com.pivotallabs
            robolectric
            0.9.5
            test
        
        
            junit
            junit
            4.8.2
            test
        
        
            org.mockito
            mockito-all
            1.8.5
            test
        
        
            com.google.android
            android-test
            test
            2.2.1
        
        
            com.google.android
            android
            2.2.1
            provided
        
    

If you notice I use a version of JUnit somewhat newer than the one bundled with Android SDK.
When we want to write a test case we annotate it with the Robolectric runner which does all the magic of running the unit test code on regular JVM:

@RunWith(RobolectricTestRunner.class)
public class HudsonViewProcessorUnitTest {

Creating Mockito mocks then is nothing but the usual:

@Before
    public void setUp() {
        contextMock = mock(Context.class);
        parserMock = mock(ViewJsonParser.class);
        hudsonStatusDaoMock = mock(HudsonStatusDAO.class);
        hudsonJobDaoMock = mock(HudsonJobDAO.class);
    }

Note, that I create a mock of the regular Context class in Android. And since Mockito creates 'nice' mocks by default in my particular case I didn't have to stub much of it!

Creating a test case is also very straight forward:

@Test
    public void testSimple() throws BuildParsingFailedException {
        HudsonViewProcessor hudsonViewProcessor = new HudsonViewProcessor(contextMock, defaultStatusBean, true);
        injectMocks(hudsonViewProcessor);
        List<HudsonJobBean> hudsonJobs = createHudsonJobs(WIDGET_ID, "blue", "yellow", "red");

        when(parserMock.parseHudsonJobs()).thenReturn(hudsonJobs);

        ...
    }

You might notice I don't use dependency injection which is, again, not supported by Android by-default. So I pass dependencies either via constructor or via setter methods (I have used both ways in this example) which allows me to reduce discomfort of not having dependency injection and still having the code testable.

My next stop would be to have a look at RoboGuice and see if dependency injection is usable and fast enough on Android after JIT was introduced.

The combination of the two frameworks Rolectric and Mockito made unit testing on Android fun again!
Published with Blogger-droid v1.6.5