Im-a build me some Spring samples (Part 1: petcare) #fail

Just more examples of commonplace Eclipse/Java things that drive me nuts. I should say up front that the version of Eclipse I’m using is actually SpringSource Tool Suite (STS) version 2.3.2.RELEASE, running on the 1.6.0_20 64-bit Sun HotSpot JVM on Fedora 13.

There’s a trove of Spring sample projects over at https://src.springframework.org/svn/spring-samples/ – very helpful. So I had Eclipse check some out and import them as projects. Funny thing, there seem to be a lot of complaints about XML. I’m getting a little more savvy, let’s see if I can resolve these.

Pet Care

spring-petcare-3.0.xsd

From petcare’s servlet-context.xml, we get the good old “Referenced file contains errors (http://www.springframework.org/schema/petcare/spring-petcare-3.0.xsd).” OK – I’m pretty familiar with that. If you try to go to the URL given, SpringSource’s server redirects you to the home page. Seems the “petcare” schema just didn’t quite make the list with the rest of the framework – I can understand that. But what URL should we use instead?

Well, not surprisingly, the petcare projects contains its own XSD; it’s in /src/main/resources/org/springframework/samples/petcare/util/config/ – so how do I use that as the URL? Well, one way is to use the svn tree from the website; then the schemaLocation is https://src.springframework.org/svn/spring-samples/petcare/trunk/src/main/resources/org/springframework/samples/petcare/util/config/spring-petcare-3.0.xsd. Would have been nice if the project just did that, wouldn’t it? I would think that, distrusting SpringSource not to move/change it again, you could refer to it relative to src/main/resources/META-INF/spring/appServlet/servlet-context.xml as ../../../org/springframework/samples/petcare/util/config/spring-petcare-3.0.xsd (feeling the pain yet?) or copy it to the same directory and just refer to it as spring-petcare-3.0.xsd – but neither of these seems to work on deploy, while the web URL does. There’s a file META-INF/spring/spring.schemas that appears to be intended to specify where to look in the project for the schema, but I’m not sure how it’s supposed to be referred to in Eclipse to make this work.

Here’s a really great error Eclipse has on one of the XML elements that refers to the schema: “- schema_reference.4: Failed to read schema document ‘spring-petcare-3.0.xsd’, because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.” So which is it? Good grief. Would it really be hard to make messages like this actually useful? This is so frustrating.

Amazingly enough, if you try to deploy and you haven’t cleaned this up, Tomcat goes and tries to download the XSD as well and fails if it comes out wrong. So there you have it: your ability to deploy seems to depend on whether the right web sites are up at the right time. I imagine there’s a Tomcat or context.xml setting to disable this behavior.

Spring NamespaceHandler for petcare:resources

OK. So now I’m pointing at the right XSD, but I still have problems with servlet-context.xml. Actually it’s only a warning, but: “Unable to locate Spring NamespaceHandler for element ‘petcare:resources’ of schema namespace ‘http://www.springframework.org/schema/petcare'&#8221; – again with the “Unable to locate” business. That crap sure gets old. Why don’t you give me some kind of clue? Where did you look, where should I look? Actually I think I understand this and it’s trying to say there’s no “resources” element defined in the XSD. But there certainly is, so I don’t really know what this is on about. It seems to work anyway on deploy so I’ll ignore for now.

root-context.xml: Build path is incomplete

On to root-context.xml, another Spring bean file. This has three errors listed. The first two are really confusing: Next to line 22 which looks like this:

<!-- Embedded H2 Database -->

I have the error “Build path is incomplete. Cannot find class file for org.springframework.samples.petcare.users.PetcareAuthenticationFailureHandler”. Next to line 24 which looks like this:

<jdbc:script location="classpath:schema.sql" />

I have the error “Build path is incomplete. Cannot find class file for org.springframework.samples.petcare.users.PetcareUserService”. WTF? Actually Eclipse helpfully gave me a clue below on line 56, which looks like this:

<import resource="security.xml" />

This has the warning “Validation warning occured in imported configuration file ‘src/main/resources/META-INF/spring/security.xml'”. Yes, as it turns out that file has errors on lines 22 and 24, where  they make a lot more sense. But they’re not reported in security.xml; they’re reported against irrelevant lines in root-context.xml, which just includes it. Truly mind-boggling.

Now from this, plus the “Build path is incomplete. Cannot find class file for org.springframework.samples.petcare.util.templating.DefaultStringTemplateFactory” on line 29, I gather the build path is incomplete. But all those files look to be provided by this project and the build paths seem to be set up fine. So what the heck is going on?

At this point I checked my system and noticed that after installing some unrelated things, Fedora has chosen java-1.5.0-gcj as my compiler. I don’t think Eclipse is using this, and theoretically it shouldn’t matter anyway, but I shut down Eclipse, reconfigure alternatives so the Sun JDK is again providing the default javac, restart Eclipse, and clean the project. Somewhere in there, the complaints went away.

page.jsp Type mismatch

Now I’m left with just one actual error in src/main/webapp/WEB-INF/layouts/page.jsp. Only, when I open that file, Eclipse doesn’t list any errors. I have to go down to the “Markers” tab to find it:

page.jsp line 62 Type mismatch: cannot convert from boolean to String

Line 62 is a completely innocuous HTML div. Eclipse is just bonkers. I delete the marker and now my petcare project is free of red Xes. I deploy and it works. That might be enough for some people… but now, what about all those warnings?

Unresolvable warnings

Our old friend servlet-context.xml still has a warning next to <petcare:resources> that says “Unable to locate Spring NamespaceHandler for element ‘petcare:resources’ of schema namespace ‘http://www.springframework.org/schema/petcare'&#8221;. I feel I’ve been as clear as possible about the petcare schema so I really don’t know what more there is to say. So let’s leave that (or delete it).

Under src/main/resources, log4j.xml complains “The file cannot be validated as the XML Schema “/home/luke/Documents/workspace-sts-2.3.2.RELEASE/petcare/src/main/java/log4j.dtd (No such file or directory)” that is specified as describing the syntax of the file cannot be located.” This seems to be universally ignored – as I recall, I saw some bogus explanation as to why it was bad to specify a URL for this DTD. You would think Eclipse could just supply the DTD itself, or find it somewhere in the log4j JAR in my Maven dependencies. I don’t have a clue what to do about this so I leave it.

The final warnings are in src/main/webapp/WEB-INF/views/appointments/calendar.jsp, where Eclipse is complaining about data-* attributes on some HTML tags. As I recall these attribute “extensions” are part of the HTML standard so I don’t know why Eclipse is complaining. No way to shut it up without disabling validation entirely, so again let’s leave it. And that’s it for petcare.

Memory (classloader) leak

BTW, petcare has a big fat memory leak in it somewhere, because after you’ve re-deployed a few times, you get a PermGen error. Nice going. I can use this to hone my memory-leak-debugging skills soon.

#uberconf groovy intro

So, groovy is basically doing ruby in java. What’s incredibly clever, aside from supporting both syntaxes and a little bit more, is translating that into something that works on the JVM. That would be kind of pointless if you were just doing groovy – why not just use ruby? – but it becomes pointful when you can integrate with whatever other Java frameworks and resources you are working with; under the covers groovy is dealing in Java objects so the translation is pretty seamless.

Or so I’m guessing, just from a quick intro. It’s pretty cool. A lifesaver if you’re stuck using the JVM!

Learning about HotSpot options; also Java = pain

While researching a customer problem yesterday I became wildly more educated about Java garbage collection than ever before. I finally know what all the talk of “generations” is about.

Also it confirms my contention that Java programmers enjoy pain. I worked with Perl for over a decade and never once had to deal with a garbage collection problem. Memory leaks, yes, but those are pretty simple in Perl – look for circular references and remove or weaken them. I’m sure things get more complicated if you’re multithreading Perl, but that’s just the thing; multithreading is still unusual in the Perl world, while it’s ubiquitous in Java. Sure, multithreading can really improve your performance, but is it really appropriate to ask every Java programmer to have to deal with the complexity it entails? I think for most projects it would be a hell of a lot cheaper to just add on a few more servers.

Anyway, to record some of the links with really interesting JVM info:

Who would believe there’d ever be such a long document about nothing but Java garbage collection? You can pick between three major collection algorithms, each with extra options of course (what goes for one generation doesn’t for another!). And as a Java programmer, you pretty much have to know this stuff, if for no other reason than because you’ll run into cryptic error messages during development. Ever run out of PermGen space while developing a webapp? What the hell does that even mean? It only makes sense once you know a fair amount about HotSpot garbage collection. Until then you just know to reload the container whenever it shows up.

I will say this for Java memory management however: it’s very cool that it handles collecting objects with circular references (which is good because they appear to be rampant). That really makes a programmer’s job easier. And it’s also cool that you have the option to collect garbage concurrently with program execution rather than having to pause everything while it’s running – although this leads to even more complexity! – and is likely the source of my customer’s problem.

Java parameterization

I understand a little about generics and the need to parameterize when you use actual instances of Array and such. I wasn’t familiar with the need to parameterize Class or ArrayAdapter. I’m working with Java 6 here so I may be in uncharted (or at least unsupported) waters.

The fun started when I decided to subclass ArrayAdapter so that I could hand it an array of classes (Activity classes, in fact – then when one is selected, just startActivity on it) and have the adapter construct a ListView from them (all I have to do is override getView).

    private class ClassesAdapter extends ArrayAdapter {

Whoops! Evidently (Eclipse informs me) ArrayAdapter is a raw type and needs to be parameterized. I didn’t even know it would be necessary to deal with that in a subclass. Obviously I need to go back and read about generics again. But wait, I know what kind of array I’m handing in, so I can actually parameterize this extension (and the constructor too). And I even know what kind of Class I’ll be handing in – have to parameterize Class too.

  private class ClassesAdapter extends ArrayAdapter<Class<Activity>> {
      public ClassesAdapter(Context context, int viewId, Class<Activity>[] objects) {

Fine. Now the fun continues when I actually try to create the array of Class objects.

        Class[] classes = new Class[] {Drawables.class};

Nope! Complaints about raw type, unchecked conversion.

        Class<Activity>[] classes = new Class<Activity>[] {Drawables.class};
        Class[] classes = new Class<Activity>[] {Drawables.class};

No – these add an actual error – type mismatch!

        Class<Activity>[] classes = new Class[] {Drawables.class};

This still complains, but only about unchecked conversion. OK, probably I don’t really understand what I’m doing parameterizing a Class, but it does at least work, and produces the fewest warnings. I’ll have to hit up Google at some point.

Saving and displaying dates in a list with Android

Trying to clean up some bits that I’ve left sort of hazy. Now it’s time to wrestle with – how do I really get working dates between Java and sqlite and the user? Really two issues: how do I store it in the DB, and how do I get it from the DB and display to the user?

This is always a tad tricky with any DB. In some ways it seems sqlite treats dates like strings; and you can just stuff anything in that column, without it being valid in any sense, and sqlite accepts it without complaint. But it’s useful to notice that if you insert (or select) datetime() it puts it in the useful “YYYY-MM-DD HH:MM:SS” format (useful because at least they compare/sort properly). So I can format times that way to store them – only issue is GMT vs local time.

For displaying to the user, Android has some time formatting functions, but I’m having a heck of a time figuring them out, not being used to the Java idiom I guess. Looks like this blog post has some good pointers. The other tricky point is that I’m currently just handing off the database cursor to be displayed in a ListItem – not sure how to reformat things in between. I tried creating a custom view extending TextView just for the log output (consulting docs here). I’m not sure where I went wrong, but Android simply did not want to use that view; the view builder in ADT had an error about <init> not being defined, and I don’t remember what error I got when trying to run the app. So I asked on IRC and was advised to extend the Adapter instead. Here’s what I ended up with:

public static final String db_DATE_FORMAT = “yyyy-MM-dd HH:mm:ss”;
public static final DateFormat dbDateFormat = new SimpleDateFormat(db_DATE_FORMAT);

@Override
public void setViewText(TextView v, String text) {
if(v.getId() == R.id.ilr_itemLog && text != null && text.length() > 0) {
// try to reformat date text as a local date
try {
Date d = C.dbDateFormat.parse(text.toString());
text = d.toLocaleString();
} catch (ParseException e) {
Log.d(TAG, “Date parsing failed for ” + text);
}
}
super.setViewText(v, text);
}

This seems to work fine. But the real test is later when I let the user modify the log time; we’ll see.

context menus and transmitting state to a dialog

I basically have the same problem as reported here: putting a button or other focus-receiving object on a ListView blocks it from receiving item selections because those need to be focus-receiving too. Tricky. I guess that makes sense, though, how would you navigate without a touch-screen? So I guess it’ll be context menus for my “log it now” function although there could be ways around it on a touch screen.

Next problem: I’m using a context menu and one of the functions is to delete. Before deleting something the user accidentally touched, I want to show a dialog, then delete it if they confirm. Problem: there doesn’t seem to be any way to hold on to the item in question while the dialog is shown, except for using a class member (which seems really messy).

public boolean onContextItemSelected(MenuItem item) {
    Log.d(TAG, "onContextItemSelected");
    switch(item.getItemId()) {
    case R.id.ilc_menu_delete:
        showDialog(DELETE_DIALOG);
        return true;
    }
    return super.onContextItemSelected(item);
}

You can’t pass any information to showDialog; the dialog is actually shown via a separate callback. In fact, it’s worse than that – I don’t even have information when the context menu is clicked, or when it’s created from the list item!

OK – checked the docs; you can get the item that was selected, it’s just rather convoluted:

  AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
  // now info.id is the rowid given by the adapter for the item

But I’d still have to stash that ID somewhere while the dialog is shown. So for now I’m putting it in a member for the transition. Once the dialog is created, the ID can be captured in a listener. That works OK. The indirection for requesting a dialog versus showing it is a bit puzzling.


I gather that the reason for the indirection is so the Activity can “manage” the dialog. And looking a little more closely at the docs here, capturing the ID in a listener at dialog creation time won’t work either, because the dialog is re-used; when I want to delete a different item, the dialog still has a listener that deletes the first item. OK, I could use onPrepareDialog to set a new listener each time it’s displayed; but come to think of it, should the listener be responsible for performing the actual delete? The dialog is just supplying a yes/no. I’d like my activity to just display the dialog directly and use the response to determine whether to do the delete. But now I’m off the recommended path, so treading lightly.
Minor point: dialogs have a “setOnDismissListener” setter, but the AlertDialog.Builder (at least in 1.6) doesn’t have this setter – if you want to use it, have to set it after creating the dialog (which kind of defeats the purpose of using the builder).

In the end, I went with a straightforward dialog creation call from the context menu event:

private void showDeleteDialog(final long itemId) {
	Log.d(TAG, "showDeleteDialog");
	Dialog d = new AlertDialog.Builder(this)
	.setTitle(R.string.ilc_dialog_delete_title)
	.setMessage(R.string.ilc_dialog_delete_msg)
	.setNegativeButton(R.string.ilc_dialog_cancel_button, null)
	.setPositiveButton(R.string.ilc_dialog_delete_button, new OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				Log.d(TAG, "DeleteDialog onClick " + itemId);
				mDba.deleteItem(itemId);
				fillItemList();
			}
		})
	.create();
	d.setOwnerActivity(this); // why can't the builder do this?
	d.show();

}

I was trying to go the standard dialog management route and creating an inner class to handle the state, and that became unwieldy; this is much better. It does create an anonymous inner class, but in this case it’s really the right thing to do.

private void showDeleteDialog(final long itemId) {
Log.d(TAG, “showDeleteDialog”);
Dialog d = new AlertDialog.Builder(this)
.setTitle(R.string.ilc_dialog_delete_title)
.setMessage(R.string.ilc_dialog_delete_msg)
.setNegativeButton(R.string.ilc_dialog_cancel_button, null)
.setPositiveButton(R.string.ilc_dialog_delete_button, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Log.d(TAG, “DeleteDialog onClick ” + itemId);
mDba.deleteItem(itemId);
fillItemList();
}
})
.create();
d.setOwnerActivity(this); // why can’t the builder do this?
d.show();}

wireless doom, skin success, android device bridge

last night i put my laptop in suspend; this morning after un-suspend, wireless didn’t work for fedora. i installed a lot of updates to the OS last night so i guess one of them broke wireless. fabulous. submitting a bug. at least wired network is fine.

total success on the android g1 skins melding. basically, i created two subdirectories, one each for portrait/landscape images. then i merged the two layout files; as everything was pretty explicit in the layout files, my “parts” section consists of three parts: one shared “device” part (which is the display screen), and one part each for landscape and portrait (which just wrapped the rest of the previously separate layout files). i had to specify that the “device” part was rotated and translated for landscape – in portrait, x/y specify the upper left corner of the screen; in landscape where this is rotated, x/y refer to the lower left corner of the screen. also because for landscape the system automatically rotates the dpad effects, i had to re-rotate it to undo that (since everything is explicit and correct in the button layout) as commented in the HVGA layout. now all i need to do is send a copy to the original author and ask him to place it in the creative commons so i can rebrand it :-)

So, I thought for a quick bit of fun I’d try attaching to my phone from my computer (like you can to an emulator). Windows makes you install some USB driver and then reboot – well, the heck with rebooting. Under Ubuntu, you need to do some obscure udev voodoo to connect, but that’s OK. This is all it takes for Karmic Koala (thanks to this post):

$ sudo su -
# cat > /etc/udev/rules.d/51-android.rules
SUBSYTEM=="usb", SYSFS(idVendor)=="0bb4", SYMLINK+="android_adb", MODE="0666"
^D
# chmod a+r !$
# service udev restart

Then I connected my device and it was visible to adb right away. I got a shell on the phone. It’s not a root shell like in an emulator, so there doesn’t seem to be a lot you can do! For instance, the /data directory isn’t readable, so no scoping out databases. You can run top, dmesg, etc. from the /system/bin directory. Maybe I’ll find uses for that. I was hoping maybe there’d be some kind of bridge to open a telnet connection to the console on the device (like on emulator) but I guess that’s not available. If I think about it, makes sense, you don’t want someone’s computer to be able to do much to your phone if you just happen to connect its USB cable.

Connected eclipse to it – only one process is visible, the uploader. But I set my app to debuggable and kicked it over to the phone, and debugging worked great. That’s pretty sweet! Definitely necessary if you’re really using the device interactively. And something that would be useful even if you weren’t planning to do any development: you can do a screen capture of your device from DDMS in Eclipse!

I was thinking that part of the reason people use Java so much is the awesome remote debugging abilities. But then it occurred to me to ask whether other languages do this too. Certainly they do – no particular reason why it shouldn’t be possible. Looks like gdb can do it for the languages it supports, and there are at least some ways to do it for Perl and Ruby, though I’m not clear on whether anybody actually does that – though knowing Ruby someone has an awesome way to debug into Rails apps as they run.