Getting to know CouchDB – 2/x

Last time around, we were able to store the OSGi log messages into a CouchDB. Now I want to tap into the _changes API that CouchDB offers. The options are simple, connect to the ‘_changes’ document in a CouchDB database and you will be presented with a log of all changes that have occurred on the database.

http://localhost:5984/db/_changes

{"results":[
{"seq":3,"id":"_design/app","changes":[{"rev":"2-0dc1002d841221e8d8d7f325b87ffd67"}]},
{"seq":196,"id":"994cf6817a74882cecda6425e8001a96","changes":[{"rev":"193-083ec5c1e1359789eb2cf09c46097fee"}]}
,
"last_seq":196}

For each document in the database only the last change is presented. This could result in quite a lot of information. It is therefore also possible to fetch changes while applying a server-side filter. For this to work, you first need to define a filter in a design document. Mine looks like this:

function(doc, req) {
    if (doc.type == "EVENT") { return true; }
    return false;
}

and is stored (using couchapp) in a design document called ‘app’. The name of the filter is ‘events’. The filters’ meaning should obvious: pass through all documents for which the function returns ‘true’. The proper URL for accessing the changes will now be:

http://localhost:5984/db/_changes?filter=app/events

{"results":[
{"seq":196,"id":"994cf6817a74882cecda6425e8001a96","changes":[{"rev":"193-083ec5c1e1359789eb2cf09c46097fee"}]}
],
"last_seq":196}

The “last_seq” part can be used for bookkeeping: If you plan to make  multiple calls to the _changes feed (say every hour) then it is nice to be able to skip the ones you already saw during a previous call. So, the second time you call the _changes feed, you can skip all previous changes by employing the following URL:

http://localhost:5984/db/_changes?filter=app/events&since=196

{"results":[

],
"last_seq":196}

Obviously, no update has occurred since we accessed the _changes feed for the first time. If, however we now add a new document to the database (with doc.type == “EVENT”) and call the _changes feed again:

http://localhost:5984/db/_changes?filter=app/events&since=196

{"results":[
{"seq":197,"id":"f0a4a559fac65ab3cca87baf1c014fa7","changes":[{"rev":"1-c8dfffec4e08ca8db2b95f30613e213d"}]}
],
"last_seq":197}

Also, a call to “http://localhost:5984/db” will result in a JSON object, where “update_seq” provides the current update sequence. This comes in handy if you’re really not interested in previous changes:

http://localhost:5984/db

{"db_name":"db","doc_count":4,"doc_del_count":0,"update_seq":196,
"purge_seq":0,"compact_running":false,"disk_size":1871961,
"instance_start_time":"1282049630257719","disk_format_version":5,
"committed_update_seq":196}

This is all great functionality if your time granularity is in the order of hours or days. But hardly optimal if you want to be notified immediately of changes to the database. Fortunately, by supplying “feed=continuous” to the URL, CouchDB will keep your socket connection open and supply the changes as soon as they become available. Each change is represented by a well-formatted JSON line. This breaks from the previous examples, where the complete response consisted of well-formatted JSON, so beware!

http://localhost:5984/db/_changes?filter=app/events&since=196&feed=continuous

{"seq":197,"id":"f0a4a559fac65ab3cca87baf1c014fa7","changes":[{"rev":"1-c8dfffec4e08ca8db2b95f30613e213d"}]}
...
...
{"last_seq":197}

Eventually, if no changes have been sent for 60 secs, the socket connection closes. Before it does so, it spits out the last_seq, again for bookkeeping purposes.

I was wondering if it would be possible to create a simple iPhone/iPad application that is able to report specific events on a MapView using the _changes feed from CouchDB. All one then has to do as iPhone/ iPad application is connect to the continuous feed, parse the JSON data and display the events on your MKMapView. Server-side, all one has to do is insert/ update documents in the database. How easy!

So I started off by connecting to the _changes feed using an asynchronous NSURLConnection, expecting that its delegate would receive connection:didReceiveData: calls on each change. Unfortunately, this did not work: The NSURLConnection employs buffering internally that cannot be circumvented. Thus only after about 5 or 6 updates the delegate received some data. This is definitely not good enough. Some searching pointed me to the CFSocket/NSStream class. This class fortunately employs some more basic (read: unbuffered) socket handling, allowing me to receive data from the socket as soon as it becomes available!

    //open the socket
    CFReadStreamRef readStream;
    CFWriteStreamRef writeStream;
    CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)[theURL host], [[theURL port] intValue], &readStream, &writeStream);

    inputStream = (NSInputStream *)readStream;
    outputStream = (NSOutputStream *)writeStream;

    [inputStream setDelegate: self];
    [outputStream setDelegate :self];
    [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [inputStream open];
    [outputStream open];    

The containing class is set as delegate for both the NSInputStream and NSOutputStream. This causes the following method being called, based on events that occur on the streams:

/* stream eventing */
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {

    switch(eventCode) {
        case NSStreamEventOpenCompleted:
            [self connection: nil didReceiveResponse: nil];
			break;

		case NSStreamEventErrorOccurred:
            [self connection: nil didFailWithError: [stream streamError]];
			break;

		case NSStreamEventEndEncountered:
            [stream close];
            [stream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            [stream release];
            inputStream = nil;
            outputStream = nil;
            [self connectionDidFinishLoading: nil];
			break;            

        case NSStreamEventHasSpaceAvailable:
        {
            if (stream == outputStream) {
                [self connection: nil willSendRequest: [NSURLRequest requestWithURL: theURL] redirectResponse: nil];

                NSString *str = [NSString stringWithFormat: @"GET %@?%@ HTTP/1.0\r\n\r\n", [theURL path], [theURL query]];
                const uint8_t *rawstring = (const uint8_t *)[str UTF8String];
                [outputStream write:rawstring maxLength: [str length]];
                [outputStream close];
            }
        }
            break;
		case NSStreamEventHasBytesAvailable:
        {
			if (stream == inputStream)
			{
				uint8_t buffer[1024];
				int len;
				while ([inputStream hasBytesAvailable])
				{
					len = [inputStream read: buffer maxLength: sizeof(buffer)];
					if (len > 0)
					{
						NSData *theData = [[NSData alloc] initWithBytes: buffer length:len];
                        [self connection: nil didReceiveData: theData];
					}
				}
			}
        }
            break;
    }
}

As you can see, this method kind of delegates the occurring events to calls to the NSURLConnectionDelegate (which the containing class also implements, due to my initial effort to read the changes feed using a normal NSURLConnection).

Then, the connection:didReceiveData method handles the actual changes:

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    NSString *str = [[NSString alloc] initWithData:data encoding: NSUTF8StringEncoding];

    NSArray *ary = [str componentsSeparatedByString:@"\n"];
    for (NSString *line in ary) {
        if ([line length] > 0 && [line characterAtIndex: 0] == '{') {
            id json = [line JSONValue];

            NSDictionary *dict = (NSDictionary*)json;
            NSObject *seq = [dict objectForKey: @"seq"];

            if (seq && delegate) {
                [delegate changeReceived: dict];
            }
            NSObject *last_seq = [dict objectForKey: @"last_seq"];
            if (last_seq && delegate) {
                int last = [((NSNumber*)last_seq) intValue];
                [delegate lastSequence: last];
            }
        }
    }

}

This method converts the JSON data to a NSDictionary and forwards these changes to a (self-defined) @protocol called ChangesDelegate:

@protocol ChangesDelegate

@optional

-(void) changeReceived:(NSDictionary*) dict;
-(void) lastSequence:(int) last;
-(void) changesComplete:(NSError*)error;

@end

The implementation that performs the actual calls to CouchDB can be created using:

    m_changes = [[Changes alloc] initWithHost: @"localhost" database: @"db" andFilter: @"app/events"];
    m_changes.delegate = self;

    m_lastSeq = [m_changes last_seq];

Since the calling class also implements the ChangesDelegate @protocol, it will receive the changes events. I am currently using it to display MKAnnotations onto a MKMapView and it works like a charm!

Thank you CouchDB for making life easy!

p.s. I’ve made the Changes class available through github: changesfeed_xcode. Enjoy!

, , ,

Nog geen reacties

Getting to know CouchDB 1/x

Some time ago, I started looking at CouchDB. Getting to know technologies is IMO always best performed by thinking up some kind of project. So first, I started thinking of what to do with it. Now that the 1.0.0 has been released I thought it would be good to (finally) blog about my findings so far.

The project I came up with is the following: A simple (OSGi) log listener that stores its log messages into a CouchDB database.

At Luminis we use OSGi a lot. It is a highly modular framework (written in Java) that allows you to combine several modules (called ‘bundles’) that each expose or make use of functionality provided by other bundles. Careful combination of several bundles will result (almost like ‘emerging behavior’) in a complete application that suits your needs. The functionality provided by a particular bundle is best exposed through interfaces, enabling you to switch implementations without breaking the contract with other bundles that use the exposed functionality.

One of the compendium services that are available is the LogService. It allows any service to log the things it considers of any importance. It is then up to the LogService implementation where these log statements end up. Logging is usually sent to standard out or a file, which is fine in most cases. Sometimes however, logging onto the device itself and retrieving the log file for inspection is not an easy task. Take for example an Android device. Thanks to Aaron Miller’s effort, we are now able to run CouchDB on Android. Android apps (EZDroid apps) will now be able to store their logging data in this local instance. This data can then be easily replicated to another instance for inspection.

Also,  for limited devices (where there’s e.g. limited storage available) logging to a file is simply not an option.

Therefore I thought of the following scenarios where

  • CouchDB is installed locally on the device/ server. Access to CouchDB is then guaranteed and no logging is missed. A drawback might be that the OSGi application would require a local installation of CouchDB (for those who consider that a drawback!).
  • CouchDB is installed on a remote instance. Access to the CouchDB instance might be interrupted due to network instability. Then, some log messages might get lost. Since most applications require a working internet connection,  I think we could live with this.

The target of the project would be to store a JSON representation of the actually logged messages into CouchDB. This can easily be accomplished by using a LogListener.

In both cases, the OSGi LogListener that ‘lives’ inside the OSGi application, receives all LogEntries, that contain the messages that are being sent to the LogService (and some meta-data). All it then has to do is convert it to JSON and create a new document in some database at the CouchDB server. If one ever wanted to inspect the log messages, a single call to the CouchDB server would initiate a replication of the database to your local CouchDB instance. Then, you could peruse the log messages offline at your leisure.

Installation and the basic usage of CouchDB is not covered here, there are excellent descriptions already available on the WikiHalorgium’s GitHub and the O’Reilly Free Book.

To test the setup described above, I created such a LogListener implementation. I use json-simple to convert the LogEntry into JSON and end up with a JSON Object such as the following:

{
'message': 'This is a test message',
'time': 1269783246909,
'level': 'LOG_DEBUG',
'serviceReference': {},
'bundle': {
   'id': 5,
    'lastModified': 1269783246510,
    'location': 'file:bundle/net.luminis.log.couchdb-1.0.0.jar',
    'symbolicName': 'net.luminis.log.couchdb'
    }
}

A unique serverId/ instanceId could also be added to be able to distinguish between server instances if you decide to send the logging to a central server.

This, I POST to the configured server. By not submitting an ‘_id’ in the JSON string, CouchDB will make one up for me. The HTTP (1.0) POST itself is done (thus keeping it lightweight) opening a raw socket to the couchdb server:

POST /db HTTP/1.0
Content-Length: xxx
Content-Type: application/json

{ ... the data here ... }

The response is also a valid JSON response which can be inspected for success (along with the HTTP response code, of course).

In my current implementation, I can choose between two modes; either each message is sent to the couchdb instance on at a time, or I send all messages in bulk mode every x seconds. The latter is probably the best for remote couchdb instances.

Nog geen reacties

PhoneGap, een alternatief voor native mobiele applicaties

PhoneGap, een alternatief voor native mobiele applicaties

PhoneGap is een interessante open source alternatief voor het schrijven van native applicaties voor elk (mobiel) platform dat er is. In het kort komt het erop neer dat PhoneGap zorgt dat je een HTML applicatie met javascript.  De specifiek API, zoals location, contact, e.d. worden afgeschermd door een standaard API van PhoneGap.

iPhone

Voor de iPhone kan de HTML applicatie gewoon worden aangeboden via de appstore. Dit is dan ook direct de truc waardoor er voldoende rechten zijn om de hardware aan te spreken. Er zijn al vele applicatie geplaatst in de appstore (zie een selectie in www.phonegap.com/apps).  Er is tevens een getting started en er zijn  extra plugins beschikbaar

Ondersteunde platformen

Naast iPhone wordt zowel Android, Blackberry, Symbian, Palm, N900 en Windows Mobile. Ook Windows Mobile 7 is zodra dit uitkomt eenvoudig te ondersteunen en ze zullen ook geen blokkade opwerpen in het voordeel van silverlight. Interesante gedachte is natuurlijk ook de iets minder mobiele system met Linux, Windows MacOS hebben ook allemaal een browser.

IPHONE ANDROID BLACKBERRY SYMBIAN PALM
GEO LOCATION
VIBRATION
ACCELEROMETER OS 4.7
SOUND
CONTACT SUPPORT N/A

Voor meer informatie zie www.phonegap.com

, , , , , ,

Nog geen reacties

Being a .NET developer in a Mac OSX world: storing null values in a database

In this post I want to shine a light on a different aspect of developing on one OS to deliver on a different OS: different implementations of the .NET framework can have different behaviour. What runs on one, might crash on the other. That happened to me when accessing my SQL Server database using ADO.NET.

Storing data using plain ADO.NET

Ok, you might argue that there is no need to talk about plain ADO.NET, since nobody in his right mind is actually doing that anymore. Of course we -developers- have evolved and use document-databases like CouchDB and Raven DB or ORMs like NHibernate and Entity Framewok.

But every now and then you need code like the code below. In my case because we were building a demo and needed to be done quickly. Which we were not, because of the problems I ran into when trying to store null values in the database.

Book book = new Book {
	Id = Guid.NewGuid(),
	ISBN = "123-456-222",
	Title = "Through the looking glass"
};
 
using (SqlConnection connection = new SqlConnection ("some connections string")) {
	connection.Open ();
	using (SqlCommand cmd = connection.CreateCommand ()) {
		cmd.CommandText = @"INSERT INTO Book ([Id], [ISBN], [Title], [Publisher], [SuggestedPrice])
		       VALUES (@Id, @ISBN, @Title, @Publisher, @SuggestedPrice)";
 
		cmd.Parameters.AddWithValue ("@Id", book.Id);
		cmd.Parameters.AddWithValue ("@ISBN", book.ISBN);
		cmd.Parameters.AddWithValue ("@Title", book.Title);
		cmd.Parameters.AddWithValue ("@Publisher", book.Publisher);
		cmd.Parameters.AddWithValue ("@SuggestedPrice", book.RetailPrice);
 
		var rowsAffected = cmd.ExecuteNonQuery();
		if (rowsAffected == 0)
		{
			Console.WriteLine("No rows inserted!");
		}
	}
}

The sql to create the table is like this:

CREATE TABLE Book (
	Id			uniqueidentifier	NOT NULL,
	ISBN			varchar(255)		NOT NULL,
	Title			varchar	(128)	NOT NULL,
	Publisher		varchar	(128)	NULL,
	SuggestedPrice	money 			NULL
) ON [PRIMARY]

Finally the Book class is this:

class Book
{
	public Guid Id {
		get;
		set;
	}
 
	public string ISBN {
		get;
		set;
	}
 
	public string Title {
		get;
		set;
	}
 
	public string Publisher {
		get;
		set;
	}
 
	public decimal? RetailPrice {
		get;
		set;
	}
}
}

The reason to use SqlXXXX objects in stead of programming against interfaces like IDbConnection and IDbCommand is that I know I have a SQL Server database and will not change that in the course of this project and the fact that I have this nice simple syntax for setting parameters on the Command object:

cmd.Parameters.AddWithValue ("@Title", book.Title);

The AddWithValue-method is not on the IDbCommand interface, but is available as a public method on the SqlCommand class.

The book object comes from somewhere outside of this piece of code normally, and I cannot make any assumptions on the properties that are filled or not. For example the RetailPrice property is a nullable decimal, so it might therefore be null. No problem, since the database column SuggestedPrice is also nullable.

No problem? No problem in Mono. Run this code in MonoDevelop and store a book with a null value for the retaill-price and the publisher. Sweet.

A problem on Windows

Copy this code (or the compiled assemblies) to your Windows VM and run it there. You get an exception:
SqlException
Why is that? Why would .NET complain about the Publisher parameter, suggesting it is not there? It contains a null value, right, but the parameter itself is there anyway.

So the message itself is confusing. It took me quite some time (and the use of the great SqlProfiler from AnjLab) to find out that the problem was in the null values. That must have happened to other people before. So Google to the rescue? Even that took some time before I found a thread on a PC Review forum from 2005 that suggested to go through all the parameters in your command to see if they are null or not and then set them to DBNull.

The platform independent version

Are you kidding me? Every time and everywhere I have a Command object and add Parameters to it, I must go through all the parameters like this?

foreach (SqlParameter parameter in cmd.Parameters)
{
    if (parameter.Value == null)
    {
        parameter.Value = DBNull.Value;
    }
}

And that has been like that since .NET 2.0? No improvements in the last 5 years? Probably, the reason you haven’t bumped into this problem lately, is that you have been using NHibernate (I did) and that solved it for you. I haven’t tried it with Entity Framework yet, but I guess that would solve it too.

I really think Mono does a better job here. When I set a parameter on a DbCommand object to null, I expect that object to translate that null value to something that the database understands. As is does for any other value.

Download the code

P.S. At one time in the process of finding a solution , I got so frustrated with Microsoft .NET and Visual Studio 2008 (since that somehow stopped building properly) that I decided to run Mono on Windows too. It took me 5 minutes to download and install Mono on my VM, then 5 more minutes to discover the existence of XPS (the Mono web-server) and I had my webservice running! Unfortunately, that was not an option for our production server, but to me it proved that the guys at Mono do a really good job.

, ,

Nog geen reacties

Who writes my user stories

The user story is one of the useful initiatives that came out of the Agile movement. It expresses a very specific user need. Usually it’s written in just a few sentences in the language of the users. So any user and developer should be able to read a user story and immediately understand it.

User stories gained popularity after realizing that developers had to start working with users throughout the project to understand their needs. It certainly works better than letting a developer discuss the needs with a user, which tends to end after a few minutes in a “Yes, I get it! No worries, know what you need”, followed by a near endless code-and-fix cycles.

So user stories are great, but who writes them? Hmmm, users probably. After all it’s their story. Question is “can users write user stories”? The answer is simple: it depends….

Certainly some users can write user stories. Sysadmins can, helpdesk and application support too. But the “real” users, can they write user stories? I don’t know about that. When you leave the writing of user stories in the hands of the users that can write user stories you may end up with “unbalanced systems” like the ones in the famous what-if-airplanes picture. After all, you don’t build a system just to do application support or system admin (unless that is your business). You build systems to increase “business value” or whatever greater purpose and for that you need the “real” users.

what_if_airplanes

As stated before: “any user and developer should be able to read a user story and immediately understand it”. If it is that simple, it cannot be too hard to learn how to write a user story.

A user story consists of two parts:

-Just a few lines of text that describe the problem;

-A Test that serves as an example and that can be used to determine when a story is complete.

A simple template for this can be found here: cukes.info

All very simple, and I bet it is possible to make a training course with exercises were the stories and their tests just drip of the table….

Unfortunately, most systems we build nowadays are not that simple. Recently I explained user stories to a group of barristers who were asked to describe their new system. After the theoretical part it was time for some their first user story. Not some lab example a real life one.

Barrister: how do we start?

Me: just go over the things you do during the day and see where your new system system comes in

Barrister: I visit people with a legal document, hand it over, explain the implications and sometimes I give them advice or propose a solution. Then I make notes on their file. That’s it.

Me: Hmmm, that is too simple, there must be more…..

The discussion continued for quite some time and finally we found that the user story was about efficiency. In the morning they receive a pile of documents for that day, they order them by address, program their navigation system and they make their visits.

Or the cukes.info template:

In order to make as many visits as possible during a day

As a barrister

I want to receive an daily workload optimized for traveling time and in such a way that I spend the least possible time in programming my navigation system.

Barrister: not in a million years I would have come up with this user story! And how do I write a test for this? Is the navigation system part of the whole system? And what if there are traffic jams or rush hours should that be in there too? And what about different makes of navigation systems?

My conclusion: help your users in writing user stories and certainly help them in writing test scenario’s.

Nog geen reacties

Being a .NET developer in a Mac OSX world: connecting Mono to SQL Server

How did I get here?

I’m a long time Windows developer. Started with VB3 en FoxPro and such, and couldn’t imagine needing another plaform. Like the Mac that my geeky artistic brother-in-law loved so much. Windows was cool and I knew all about it and the Mac was for people that didn’t know how to use a PC.

The dawn of a new era

Then I came with my current employer and they provided a mobile phone and a laptop of course (like all companies in Dutch IT do). But this was about an iPhone and a MacBook Pro.
I decided to leave OSX on the machine, although I could have erased the disk and installed Windows Something, it’s got an Intel processor after all.
But leaving OSX on it, meant I had to install VMWare and run Windows and Visual Studio and such within that. And even though my machine is pretty fast, you notice the performance hit.

I kept trying, and started to like OSX and the applications on it. But what I liked most of all: hardly any updates and no reboots. I shut down my machine once a week or once every two weeks because I feel it’s something I should do. But I don’t have to: OSX keeps on running. Just close the lid, simply know that everything is suspended and know that everything will run as before when you open the lid the next day.

Amazing! I would shut down my Windows machine every night, just to make sure I had a stable system the next morning. My wife still has a Windows machine and to ensure that she makes backups every day, we configured the backup software to run “on system shutdown”. Because that is what you do every day, as a Windows user.

And then there was Mono

I’ve written about the Mono project before, albeit in the context of MonoTouch and iPhone development. Mono brings .NET to a lot of platforms, including Mac OSX. And it is really good. The Mono team is really close behind the Microsoft team in porting new API’s and Framework versions. .NET 4.0 is recently available on Windows, but Mono is already compatible.
And the amazing thing is that you can take your Windows assemblies and use them straight away on OSX! That might not be very imported for assemblies that you have the sources for, but it is very convenient for third party libraries you use, like log4net (although that has a Mono version) and Rhino Mocks.
And one of the best things the Mono team delivers is MonoDevelop: an excellent IDE for .NET development that will feel really comfortable when you come from Visual Studio.

Being a .NET developer, not necessarily a Windows developer

I still like the .NET framework, but I no longer feel that automatically implies I am a Windows developer. There are so many good tools that allow you to do everything on the Mac that you are normally doing on Windows. So I decided that in the new project I recently started (in which we will deliver on Windows) I will try to go as far as possible to develop my code on Mac OSX.
I will blog about my experiences in a series of posts. This first one is about connecting to SQL Server.

I can’t do without SQL Server

We will deliver our project an a SQL Server database, so it makes sense to use that during development also. It’s not that you have to, there are other options. If you have something like a nice Data Access Layer, you can run any SQLLite or MySql database and easily move to SQL Server later.
There also is a file-based no-install version of SQL Server these days that might run on Mono. Haven’t tried it yet, but could be promising.
But if you need SQL Server, you can still work in MonoDevelop in your comfortable Mac environment.

Inside the VM

SQL Server will run on Windows in your VM, but that will be the only thing you’ll need your VM for. SImply minimize the window after all the configuration is done and don’t think about it anymore.

Step one: opening up your Windows

You need access to your VM from your Mac, so you have to open up some things.

Go into Control Panel and choose Windows Firewall. Go to the advanced tab and add some ports. Port 1433 for SQL Server over TCP/IP and port 1434 for SQL Server over UDP. Maybe you can do without the UDP version, haven’t tried yet.

Firewall Exceptions

Step two: configure SQL Server

First, make sure the SQL browser is running.

SQL Browser

Then enable TCP/IP in the Client Protocols

Protocols

And check that the Default Port is on 1433.

Poort

In SQL Server Management Console open the properties of the server and make sure you have mixed authentication.

Mixed Authentication

Step three: connect from your code or MonoDevelop

In your connection string use the IP-address of your VMWare instance. Something like

<?xml version="1.0" encoding="utf-8"?>
<configuration>
	<connectionStrings>
		<add name="dossiers" connectionString="Server=172.16.86.128;Database=mydefaultdatabase;User ID=sa;Password=bladiebla" providerName="System.Data.SqlClient"/>
	</connectionStrings>
</configuration>

That is! You can test your connection from MonoDevelop: Go to Tools/Database/Add database connection/SQL server:
MonoDevelopDatabaseTools
Screen shot 2010-07-18 at 9.33.05 PM

, , , ,

3 reacties

Windows Phone 7 Developer Hub

Ik heb vorige week de Windows Phone 7 Developer Hub bijgewoond met de verwachting in een keer een compleet overzicht te krijgen van de nieuwe Microsoft smartphone. Ik heb niet de intentie in deze blog alles even uit te leggen, dat kan Microsoft prima zelf. Ik wil hier alleen het beeld dat ik heb gekregen schetsen vanuit het perspectief van de gebruiker, ontwikkelaar en business.

Gebruiker

Ik heb de telefoon niet zelf bedient maar heb toch een redelijke indruk gekregen. Zelf ben ik een iPhone gebruiker en zie wel wat verbeteringen en interessante ontwikkelingen

  • Het gebruik is opgezet rond hubs. Er is bijvoorbeeld een social hub, op deze hub komt alle sociale media bij elkaar en bieden ze mogelijkheden tot integratie. Er zijn dus geen aparte ingangen meer voor linked-in, contacts, facebook e.d. maar alle informatie wordt gebundeld weergegeven.
  • Drie verplichte toetsen op de telefoon waarbij naast de enige toets op de iPhone om applicaties te starten er ook een zoek toets is die de standaard zoek functionaliteit heeft maar ook kan worden gebruikt voor zoeken binnen de applicatie. Daarnaast is er de back toets hiermee kan je terug naar de applicatie die een andere heeft aangeroepen. Een typisch voorbeeld waar ik mij vaak aan heb geërgerd is: Je leest je mail daar staat een link in die je opent en vervolgens zit je in safari. De enige manier om die te verlaten is stoppen en je mail opnieuw opstarten.
  • Het metro concept van de user interface (Kort samengevat: beperkt grafisch en meer tekst) aangevuld met een panorama view en pivot view is wel een verfrissende aanpak waarbij je direct informatie ziet die je nodig hebt en niet alleen een menu.

Ontwikkelaar

Voor een .Net ontwikkelaar is er eigenlijk niets nieuws. Je kunt namelijk gewoon ontwikkelen met je opgedane kennis in XAML (WPF en Silverlight) in je vertrouwde ontwikkelomgeving. Ik wil echter wel een aantal punten benadrukken

  • Een virtuele machine met de phone OS op de ontwikkel PC dus geen emulator of simulator dus betere test omgeving
  • Naast API’s die telefoonfunctionaliteit geven zijn er ook API’s voor bijbehorende services in de cloud
  • Er is een gratis omgeving bestaande uit visual studio express voor ontwikkelaars en Blend express voor designers

Het lijkt mij een eitje om de look en feel van de quote eetgids (een iphone app gemaakt door luminis) te bouwen voor W7

Business

  • Beperkt aantal modellen en veel verplichte onderdelen zoals een grafische processor en sensoren als GPS e.d. Dit maakt de herkenbaarheid groter
  • Geen exclusieve contracten met KPN’s en de TMobile’s
  • Vergelijkbare appstore als Apple waarin een applicatie gegarandeerd binnen dagen wordt geplaatst.
  • Office applicaties en zelf een sharepoint front-end

Het evenement

Het evenement zelf was wat mij betreft teleurstellend. Op een developer event verwacht ik concrete presentaties met duidelijke concepten en voorbeelden. Helaas bleven de presentaties erg oppervlakkig ook al aangemoedigd door de vele bizarre vragen die gesteld werden. Wat mij wel duidelijk is geworden dat Microsoft serieus hun best doet om weer aansluiting te vinden of zoals ze zelf beweren een voorsprong te nemen maar dat ze nog  heel goed hun best moeten doen om alles in de winkels te krijgen voor de kerst.

, ,

Nog geen reacties

FitNesse and OSGi

As a demonstrator for a customer, I recently built a set of fixtures that allow FitNesse acceptance tests to talk to an OSGi framework. This code is by no means production quality, but merely intended to show the concept and explain the challenges.

I will not explain the details of the acceptance tests here, however, if there’s one point I would like to get across, it’s your fixtures should be as narrow as possible to easily accommodate for implementation changes. Study the different UserAdmin fixtures for more details. Also, I assume some familiarity with OSGi.

FitNesse and OSGi. Why?

Of course its fun, there is some real benefit to be gained here. While the industry well understands the need for unit- and integration testing, also in a modular context, it becomes more complex to create the necessary link between business and code. Yes, using a modular architecture we can behave in a more agile fashion, but all that agility is no good if the business doesn’t hop on the train, and explain well what it needs. FitNesse allows the business to explain its goals in business-lingo, while forcing the specification to be precise enough to be executable: if a concept cannot be explained by simple scenarios, something is wrong, but that’s a different story.

The modular nature of OSGi means that behavior of an application is more emergent than deterministic, making it harder to reason about its correctness: we can prove that our code and bundles are correct (unit tests), that everything works together as it should (integration tests), and that it looks right (user interface tests). However, proving that the business rules (which may well be one of those emergent properties) are handled correctly in a given setting, is another can of worms: we need to connect our acceptance tests to the OSGi framework.

The big picture

FitNesse and OSGi - overview

The solution presented below uses a special ‘fixtures’ bundle, which can be deployed along side other bundles in your framework. This bundles exposes an interface (in our case, through an HTTPServlet), which is used by a set of connectors, which in turn are used by FitNesse.

The details

FitNesse and OSGi - detailed

The ingredients are two parts connector code, one part boiler plate, and one part genuine OSGi-aware fixtures.

The connectors

Starting at the level closest to FitNesse, we find a set of fixtures that FitNesse can use. For us, these contain merely boiler plate code.

public void removeUser(String name) throws Exception {
    doRemoteCall(buildRemoteCall("UserAdmin", name), Void.class);
}

This code instructs our RemoteInvoker to do some call to the outside world. For more details, see RemoteInvoker.java in the UserAdminRemoteFixtures project.

The fixture bundle

Moving one step closer to our service, and into the OSGi framework, we find a FixtureServlet, whose task it is to receive calls from the RemoteInvoker, and turn them into actual method calls on the fixtures.

The fixtures, then, are almost regular OSGi aware objects. I chose to use the Apache Felix Dependency Manager for the dependency management of the fixtures. So, for our UserAdmin fixture, the dependencies are

manager.add(createService()
    .setInterface(UserAdminListener.class.getName(), null)
    .setImplementation(userAdmin)
    .add(createServiceDependency()
        .setService(UserAdmin.class)
        .setRequired(true)));

Here, we state that we have some instance of a fixture userAdmin that registers itself as a UserAdminListener and needs a UserAdmin. How straightforward is that?

The final step takes us to the actual fixture,

public class UserAdminFixture implements UserAdminListener {
	private volatile UserAdmin m_userAdmin;
...
	public void addUser(String name) {
		m_usersCreatedInLastCall = 0;
		m_userAdmin.createRole(name, Role.USER);
	}
...
}

which is just another component using a the UserAdmin service.

Putting it all together

All we now need to do is deploy the fixture bundle in our project, and instruct FitNesse to use the remote connector. The zip file at the bottom of this post contains two shell scripts to do exactly that.

Future work

As I stated at the top of this story, this is by no means production quality code, but the concepts stand as they are. Given the way FitNesse works, the connectors do not need much extra work, perhaps support for collections. However, we could use

  • a way to reduce the boiler plate code,
  • a way to ensure that that both side of the fixtures use the same function naming, and
  • better integration, for instance by only firing up a framework once a FitNesse suite is started.

Let’s play with it!

I have built a zip file containing everything you need to get started, including a set of scenarios that can run with both a homebrew implementation of a User Admin, and the actual Apache Felix User Admin. A Readme gives you more information on getting it all up and running.

, , , ,

1 reactie

Building iPad applications using MonoTouch: the UISplitView

First of all, I bow deeply to the people that bring us MonoTouch. It was less than 2 days after the introduction of the iPad and the release of a beta of the iPhone/iPad SDK that a version of MonoTouch (and MonoDevelop) was available that covers the new API.

To build iPad apps, you need a couple of things that are all listed on the MonoTouch iPad page.

I couldn’t wait to build something that used the way bigger UI-surface that the iPad has. The first thing that attracted my attention when I fired up the Interface Builder was the UISplitViewController.
The idea behind the SplitView is that you have some navigation on the left (like a NavigationController, or just a TableViewController) and a data view on the right. That is, only when the display is in landscape mode. As soon as you turn the iPad (the iPad SImulator, of course) to portrait, the left side disappears and all the screen is available to the data view.
That behaviour is entirely taken care of by the UISplitViewController, at least if you stick to the conventions!

I decided to make a simple app with a list of places on the left side, and a map-view on the right:

LandscapePortait version of the UI

The obvious start

When you start a new iPad application from the New Project menu, you get the well-known set-up of files in your project. Double-click the MainWindow.xib to fire up Interface Builder. Then drag the Split View Controller from the Library Window and drop it below the Window object in de MainWindow:
MainWindow

As you can see, you get a lot for free, including stuff you don’t want. Now it gets less obvious. After clicking Cmd-Backspace a thousand times and positioning my cursor everywhere, I had an epiphany. Since the SplitViewController won’t work without two other controllers I had to add something new before I could remove the old!

No kidding, that was really the solution. So I added a UITableViewController, Interface Builder magically removed the default NavigationController, and I added a MKMapView to the view-controller on the right.

This is the result:

SplitView I then added outlets to the AppDelegate for the map, the tableview and the splitview:

Outlets

The less obvious code

To make the controllers react properly when the orientation of the UI changes, you need to override the ShouldAutorotateToInterfaceOrientation() method in each of your controllers. How do you do that?
The first step is to add a class to your project, make it inherit from your controller (a UITableViewController in my case) and override the ShouldAutorotateToInterfaceOrientation() method as below:

public class PlacesController : UITableViewController
{
	public PlacesController ()
	{
	}
 
	public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
	{
		return true;
	}
}

Repeat the step for the second controller:

public class Map : UIViewController
{
	public Map ()
	{
	}
 
	public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
	{
		return true;
	}
}

This should still compile. But it doesn’t work yet.

The even less obvious link from the code to the UI

The objects in the Interface Builder are standard objects. They need to be of the types that we just defined, to make the overridden methods work. See we need to make our own classes known to Interface Builder. That’s done by adding a Register-atribute and overriding the constructor with one that accepts an IntPtr.
The Map class changed in something like this:

[Register("Map")]
public class Map : UIViewController
{
	public Map ()
	{
	}
 
	public Map(IntPtr p) : base(p)
	{
	}
 
	public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
	{
		return true;
	}
}

The final step is setting the right class on the controller. Go to Interface Builder, select the UIViewController (e.g.) in the MainWindow, then go to the Inspector Window and type your classname over the default one:

Inspector

And then it works! The map will re-orientate itself when the iPad is turned, and the Table View appears and disappears.
Of course you want some location data in the table and the map to show the locations when clicked on, but that’s all in the code you can download.

Enjoy making software for a device that makes you need to rethink the way you always made software…!!!

Mmmmh. re-reading that last line, I realize it’s a little hard to read. What I meant was something like Joe Hewitt wrote.

, , , , ,

4 reacties

Presentaties AgileMDD kennissessie – 30 maart 2010

Op 30 maart organiseerde luminis samen met ArchitecIT een kennissessie over model-driven development. Aan de hand van vijf verschillende thema’s deelden sprekers van diverse organisaties hun praktijkervaringen met MDD. De volgende organisaties waren als deelnemer vertegenwoordigd: ArchitecIT, Delphino Consultancy, luminis, Ministerie van Defensie, Nedap, Nuon, PANalytical, Radboud Universiteit Nijmegen, Sogeti, Tennet en Thales.

De presentaties van deze avond zijn inmiddels online beschikbaar en kunnen hieronder worden gedownload.

agilemdd_logo


In de praktijk zijn er bij softwareontwikkeling nog veel communicatie (overdrachtsmomenten) en bestaan de meeste ontwikkeltaken uit veel handwerk. Op basis van een MDD aanpak kunnen ontwikkeltaken worden geautomatiseerd en kan de onderlinge communicatie worden verbeterd. Hierbij is het echter wel belangrijk om te weten hoe MDD het beste kan worden toegepast en wat hierbij de meest voorkomende valkuilen zijn. Vanuit onze AgileMDD filosofie moet bij model-driven development een pragmatische en doelgerichte aanpak vooral centraal staan. Zo kan de bestaande ontwikkelkracht in de organisatie slimmer worden ingezet.


Programma kennissessie 30 maart:

Wil je op de hoogte blijven van aankomende AgileMDD sessies of geïnteresseerd in advies op maat? Neem dan contact op met Inge Dokter (inge.dokter@luminis.nl) of bel 026-3653470.

Discussie resultaat vorige MDD kennissessie

, , , ,

2 reacties