Tuesday, October 6, 2009

Continuous Integration

I've worked in environments with continuous integration for nine years. I introduced the concept at 2 of the 4 companies I worked at over that time. Hopefully everyone developing in an environment supported by continuous integration already takes build pass/fail seriously. If not, I suggest a moment of personal reflection upon your projects continuous integration server. I suggest that everyone might look at the health across multiple projects and multiple builds to assess how well they are doing to keep the projects green. What is your rough estimate of build success on the builds that your commits triggered? In Team City, find the “My Changes” tab at the top. Expand all three (at least I have three) sections. In CruiseControl, hmmm? I'm not sure anymore.

I am not trying to incite any sort of competition over who can reach 100% triggered build success. I only suggest that we might think about our personal goals. We might challenge ourselves to never cause a build failure. To aspire to 100% success is wrong. There are going to be a few "oops". There are going to be some environment problems.

Project management should always be looking at the percentage of failed builds. Also looking at the volume of commits and the size of commits. Particularly just prior to a release. Continuous integration is a great tool like any other -- the value derived is based on how it is used.

Wednesday, September 30, 2009

Mixing JSP 2.0 with GWT

I've just overcome a pesky litle problem between JSP 2.0 and GWT. I have my JSPs in xml format: <jsp:root ...>. You are likely aware that this is a bit aggressive about removing whitespace from the resulting html. This includes the transformation of empty body tags into bodyless tags. Ergo this
<div id="footer"></div>
becomes this
<div id="footer"/>

Now that second one was confusing firefox on my linux workstation. Likely on your platform as well. This is just like the old days when we fought with <script src="thefile.js" /> tags to make sure they keep their separate closing tag.

The solution is just to drop a comment into the previously empty body
<div id="footer"><![CDATA[<!-- -->]]></div>

Thank you Ramon, for pointing me down the path. It's been a long time away from servlet code. It should not have taken me as long as it did to remember this problem.

Sunday, September 6, 2009

Android Book Mobile (1 week later)

It's been a great first week for ABM on the market. Over 1,400 downloads and still carrying a 4 star rating! Here is a screen shot of the Android Market -- Developer Console. It shows all the applications you have published with their current stats.

One statistic that would be great if I knew how often people are using it. If I had my own server-side to the application I could gather that statistic myself. But alas, the data being stored at books.google.com, and the reviews coming from goodreads.com, I don't know how much they are using it. I fully expect someone will tell me their phone ran out of memory trying to load their full library.

Saturday, August 29, 2009

Android Book Mobile

I entered my Android application into the Android Developer Challenge II. You can read more about what "Book Mobile" does and my thoughts behind the name over at the product website.
  • I've integrated the Google book api into Android.
  • I use the GoodReads api to get reviews for books.
  • I integrated with zxing for barcode scanning to read ISBNs.
  • Because of this missing feature in Android I had to draft my own login dialog for users to enter their google account credentials.
Now for the frustrating part. How they setup the registration/entry process to the ADC means if I want my application available on the market, I have to repackage. This means changing the AndroidManifest.xml and refactoring all the code to have a new package structure. That doesn't seem so bad, right?

Thursday, August 27, 2009

Launch Explorer.exe from Cygwin

Working in cygwin, I often need an explorer window to my current directory or a sub-directory there of. I called this script expl.sh.
#!/bin/bash
export p=`pwd`
export pc=`cygpath -w $p/$1`
explorer.exe /root,$pc &
Once you have this the directory on your path where you keep your scripts: perhaps ~/scripts:
expl.sh
expl.sh some/sub/directory

Monday, August 24, 2009

Google App Engine and GWT

Well, I started poking around with Goole app engine in Eclipse. By default they want to use GWT. fine. Someone once said, "when drinking the tainted cool-aid you might as well eat the cookie too." (if no one said it then I just did)

Well, I develop on Ubuntu and immediately ran into an UnsatisfiedLinkError.
** Unable to load Mozilla for hosted mode **
java.lang.UnsatisfiedLinkError: /home/user/projects/gwt-linux-1.5.3
/mozilla-1.7.12/libxpcom.so: libstdc++.so.5:
Thankfully, this was the first hit on by search. Thank you

Monday, August 3, 2009

When to Refactor

It's common knowledge that you don't write code in a software project to solve future problems. Don't implement code that is not needed.

It occurred to me that the inverse is true for refactoring. I will not delay a refactor because we expect to have a requirement that will make it obsolete. You never know which features/tasks will be canceled or delayed. You should ask yourself, "How long am I willing to support this ugly code?"

Tuesday, May 12, 2009

Subversive Eclipse on Jaunty Ubuntu

I got all obsessed over the weekend. I needed stable sound from my laptop. I mean really, who can code without music!? I don't want to talk about that. I had a painful path form Hardy to Jaunty. But that's not why I'm posting.

After a complete re-install of Ubuntu I was reinstalling Eclipse and Subversive. It failed. The "SVN Connectors" drop down was empty. Turned out I fell victim to a bad link over to Polarion. That was answered over on stackoverflow. As stated in that answer, this is the right update site url to get the connectors from Polarion: http://www.polarion.org/projects/subversive/download/eclipse/2.0/update-site/


I wanted to use the javaHL connector, so I also needed this step.

  • sudo apt-get install libsvn-java
  • put "-Djava.library.path=/usr/lib/jni" in eclipse.ini


Thanks guys/gals. Hopefully I won't forget how to do this stuff. (next time an OC urge strikes to set myself back 3 days)

Sunday, March 1, 2009

J2EE Connector Architecture

J2EE Connector Architecture (JCA) is a little used aspect of J2EE that is probably now relegated to obscurity due to the popularity of web services. It is however a viable solution to many problems. You can still find it documented at sun. You can also rather nicely integrate Spring.

I put this short presentation together. Contact me if you would like the three Eclipse projects.

Tuesday, February 17, 2009

Android Custom Component Merge

I created my custom component that extends LinearLayout. In that post I show that the root element of the components XML is a <LinearLayout ...> element. That ended up getting in the way. When the LayoutInflater built the view in my Java PersonComposite extends LinearLayout the default behavior was that my java class now had one child, the LinearLayout that is the root of the XML. This meant that each use of <my.app.PersonComposite ...> in other view XML would never apply configuration to the Linearlayout that has any effect.

Wow. Even I don't understand that. Let's try this way. The LayoutInflater, actually created the following structure (details omitted for brevity):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout >
<LinearLayout >
<TextView .../>
<TextView .../>
</LinearLayout>
</LinearLayout>
So any attempts to use the component like this would never change the orientation of the two nested TextView Components because the configuration was applied to the outer LinearLayout:
<my.app.PersonComposite
android:id="@+id/person"
android:orientation="vertical"
/>
Solve this problem by using <merge> as the root element. And make sure you invoke LayoutInflater:

LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View inflatedView = inflater.inflate(R.layout.person_composite, this);
Now the person_composite.xml looks something like this:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
<TextView .../>
<TextView .../>
</merge>
You can see how this works by getting the android source from git and looking at the source code for the LayoutInflater.inflate method. then search that same source tree for an xml that uses <merge> as the root element. You'll find more than one.

Sunday, February 8, 2009

Unit Test Your Custom Parcelable

Your Android application needs to pass some custom data between processes in an Intent. You will be calling Intent.putExtra(String, Parcelable). It would be easier to test if the Parcel class where not final with only private constructors. That keeps us from testing the methods individually. We are forced to perform only round trip testing -- write our Parcelable to a Parcel, then call the creator with the same Parcel instance.

There is one important step right in the middle of the round trip. The Parcel needs to be reset to be ready for read. Think of this just like working with java.nio.ByteBuffer. With ByteBuffer, when you are done writing, you call flip. With Parcel, when you want to read -- call setDataPosition(0). Here is a sample test.

I'll decoreate a Person object as a ParcelablePerson that implements the Parcelable interface and has the requisite public static final CREATOR. Following TDD I've only created enough of the implementation code below to make the test compile.
    public void testPersonTakesRoundTripThroughParcel() throws Exception {
Person testPerson = new Person();
ParcelablePerson testObject = new ParcelablePerson(testPerson);
Parcel parcel = Parcel.obtain();
testObject.writeToParcel(parcel, 0);
//done writing, now reset parcel for reading
parcel.setDataPosition(0);
//finish round trip
ParcelablePerson createFromParcel = ParcelablePerson.CREATOR.createFromParcel(parcel);

assertEquals(testPerson, createFromParcel.getPerson());
}
public class Person {
...
}
public class ParcelablePerson implements Parcelable {
private Person person;
public ParcelablePerson(Person person) {
this.person = person;
}

public Person getPerson() {
return person;
}

@Override
public int describeContents() {
return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
//call dest.write... methods
}

public static final Creator CREATOR = new Creator() {
@Override
public ParcelablePerson createFromParcel(Parcel source) {
return null;
}

@Override
public ParcelablePerson[] newArray(int size) {
return null;
}};
}

Thursday, January 29, 2009

Android View XML

I am thoroughly enjoying using XML to define the view characteristics of my Android application. I've written GUI code in Visual Basic, Swing, RCP, and a dab of GTK+. None of them are as easy and elegant as using XML. I applaud the Android team in using this approach.

Don't forget to apply some style to your view. Who would want to look at some boring, white standard font. Checkout the Android documentation on styles and themes.

But don't stop at using only the view components that Android supplies. Good object oriented design encompasses creating custom view components for your custom data objects. If you have a domain object called Person that needs to be displayed then you should have a custom composite view that knows exactly how a Person is displayed -- err, the attributes of the person are displayed. I learned over here that using custom view controls in the XML is as easy as defining an xml element with the name of your custom view.

I put together the below example as a guide. It is not meant to be an exemplar. Note that i have a LinearLayout that defines padding. That likely belongs in a style instead of being defined solely for THAT LinearLayout. With that warning in place, here's an exmple of a my.app.PersonComposite which is a custom class that extends LinearLayout. To use this custom view component in your XML then you would include something like the following:
<my.app.PersonComposite
android:id="@+id/person"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
So, that element will put a PersonComposite in your activity. But what does the PersonComposite look like? Well, that should be defined in xml as well. In the constructors of PersonComposite, include the following:
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View inflatedView = inflater.inflate(R.layout.person_composite, this);

In order for this to work, you'll need to have a ./res/layout/person_composite.xml. Perhaps something like this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:padding="2dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<TextView
style="@style/BigAndBlue"
android:id="@+id/personLastName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/not_given_default"
/>

<TextView
android:id="@+id/personFirstName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/not_given_default"
/>
</LinearLayout>
Note that the style attribute conspicuously lacks the android namespace. Hmm? Oh well, just watch out for that. We have to define that Style over in ./res/values/styles.xml:
<resources>
<style name="BigAndBlue">
<item name="android:textSize">12pt</item>
<item name="android:textColor">#008</item>
</style>
</resources>

Tuesday, January 13, 2009

Unit Testing Android Applications

Unit testing my Android application has put strain on my patience. All of my unit tests are not just one quick key stroke. I already posted regarding mock testing an Android project. Integration tests are another issue. These tests have to run inside the container -- the emulator or phone. I got started writing integration tests by reading this document. You'll find more Android topics discussed at his blog.

I followed Diego's steps to setup the test-specific eclipse project. Then I created an external tool configuration to launch the tests:
The "Functional Tests" run configuration changes the arguments to:
shell am instrument -w -e func true com.wilson.android.libary.test/android.test.InstrumentationTestRunner
Now each time I'm ready to run the tests I need to deploy the main project, the test project -- if they both changed. Now I can use one of the run configurations above to use "adb" to launch the tests.

Be sure to read the official documentation on running instrumentation tests, starting here.