Status of Gobject Introspection for Java-GNOME

With the wide adoption of GObject Introspection (GIR for short), and to overcome the limitations (such as being static,  needing manual update of defs files leading to error-prone and out-of-date code generation) the current defs file based parser started to work on GIR based one to replace (or at least accompany it) it. Back in May.

I had 2 paths in the beginning. Parsing the .gir XML files and using girepository API. I initially started with the former but decided with the latter forseeing that XML parsing would be too fragile for changes and too hacky to code (well I ended up having some hacky code with the latter as well :( but anyway)

In the current state it works OK for most cases. Still have false generated code both arising from not fully parsing GTypeInfo to string (which I filed bug #628812 for direct inclusion) , missing (or at least I think) functions (Bug #630062), missing coverage (not yet parsing vfuncs which are mapped to signals in java-gnome) and faulty/missing gir data.

So the future is GIR, but still both the bindings developers (us), API developers and GIR developers should improve the current status for robust bindings. Follow up for the progress.

Further addition: It was revealed that API provided function to parse parameterized G(S)List types.

Announcing GMSO 2

Years later discontinuing GMSO , a GNOME application to query inklevels of various printers, I started rewriting it in Java using Java-Gnome and JNI to interface with native libraries. The project’s home page is hosted at Google (http:/mso.googlecode.com) and the source branches are hosted at Launchpad.

The project currently consists of 3 components

  • JInkLevel: Java bindings for libinklevel.
  • LibMso: JNI library to detect printers attached to the system. It uses libhd (part of hwinfo by SuSE)
  • GMSO 2: The main application

See the homepage for screenshots, downloads and javadoc of the libraries. The source code be browsed at Launchpad. Looking for the future I may be adding additional GUI’s based on the libraries (Java Swing, SWT, QT ….)

Looking for contributors for my incomplete Java-Gnome Bazaar branches

I’ll be unavailable for a period of time, so my Java-Gnome development will halt during that period. As a result I’m looking for contributors to continue my incomplete branches.

Vte: http://research.operationaldynamics.com/bzr/java-gnome/hackers/serkan/vte/
VTE library provides a terminal widget which powers Gnome Terminal and other GTK+ terminal emulators. The purpose of this branch to add coverage of VTE API.

Sexy: http://research.operationaldynamics.com/bzr/java-gnome/hackers/serkan/sexy/
Libsexy provides additional widgets for GTK+. The purpose of this branch to add coverage of widgets provided by Libsexy.

Gerrorcode: http://research.operationaldynamics.com/bzr/java-gnome/hackers/serkan/gerrorcode/
Current implementation of GlibException doesn’t capture error code and error domain associated with a GError. The purpose of this branch is to add necessary native and Java bits to provide those these two properties.

Linkbutton: http://research.operationaldynamics.com/bzr/java-gnome/hackers/serkan/linkbutton/
LinkButton is a widget providing an HTML anchor like link. The purpose of this branch is to cover LinkButton.

And thanks in advance to people who take over the development of the branches. And special thanks to Andrew Cowie who helped throughout my Java-Gnome development.

Writing a Last.FM REST client with Jersey and Java-Gnome

This tutorial will start with a sample top artists (i.e favorite artists) file from http://ws.audioscrobbler.com/2.0/?method=user.gettopartists&user=Firari&api_key=b25b959554ed76058ac220b7b2e0a026. It will follow several steps to write a dynamic client GTK UI for the topartists service. Project depends on java-gnome (4.0.12+), jsr311-api (aka jax-rs), jersey-core and jersey-client libraries. Note that there’s a Java library for accessing Last.FM web services available at http://www.u-mass.de/lastfm Project files can be downloaded as a tarball.

Step 1: Generating XML schema from the sample XML

I downloaded a sample file from the the given URL. I used Trang to reverse engineer the XSD from XML. The command line tool just takes 2 arguments, the input xml and the output xsd files. Here’s the generated XSD file.

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
  <xs:element name="lfm">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="topartists"/>
      </xs:sequence>
      <xs:attribute name="status" use="required" type="xs:NCName"/>
    </xs:complexType>
  </xs:element>
  <xs:element name="topartists">
    <xs:complexType>
      <xs:sequence>
        <xs:element maxOccurs="unbounded" ref="artist"/>
      </xs:sequence>
      <xs:attribute name="type" use="required" type="xs:NCName"/>
      <xs:attribute name="user" use="required" type="xs:NCName"/>
    </xs:complexType>
  </xs:element>
  <xs:element name="artist">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="name"/>
        <xs:element ref="playcount"/>
        <xs:element ref="mbid"/>
        <xs:element ref="url"/>
        <xs:element ref="streamable"/>
        <xs:element maxOccurs="unbounded" ref="image"/>
      </xs:sequence>
      <xs:attribute name="rank" use="required" type="xs:integer"/>
    </xs:complexType>
  </xs:element>
  <xs:element name="name" type="xs:string"/>
  <xs:element name="playcount" type="xs:integer"/>
  <xs:element name="mbid" type="xs:string"/>
  <xs:element name="url" type="xs:anyURI"/>
  <xs:element name="streamable" type="xs:integer"/>
  <xs:element name="image">
    <xs:complexType>
      <xs:simpleContent>
        <xs:extension base="xs:anyURI">
          <xs:attribute name="size" use="required" type="xs:NCName"/>
        </xs:extension>
      </xs:simpleContent>
    </xs:complexType>
  </xs:element>
</xs:schema>

Step 2: Generating data classes for mapping the xml

xjc (JAXB Binding Compiler) is used to generate the classes in generated package. Jersey can utilize JAXB to map the result XML to data classes.

Step 3: Writing code to query Last.FM web service

public static Lfm queryTopArtists(String userName) {
	final Client client;
	final WebResource webResource;
	final MultivaluedMap queryParams;
	final Lfm result;

	client = Client.create();
	webResource = client.resource("http://ws.audioscrobbler.com/2.0");
	queryParams = new MultivaluedMapImpl();
	queryParams.add("method", "user.gettopartists");
	queryParams.add("user", userName);
	queryParams.add("api_key", "b25b959554ed76058ac220b7b2e0a026");
	result = webResource.queryParams(queryParams).get(Lfm.class);
	return result;
}

Here we’re building the HTTP request along with the parameters in the query string. And finally we’re calling the service and mapping the result to Lfm class which corresponds to XML’s root element lfm.

Step 4: The GTK+ GUI

Here were initializing the table and its data model.


/*
 * Initialize the table with its DataColumn's.
 */
model = new ListStore(new DataColumn[] { rank = new DataColumnString(),
		artistImage = new DataColumnPixbuf(),
		artist = new DataColumnString(),
		playCount = new DataColumnString(),
		percent = new DataColumnInteger() });
view = new TreeView(model);

Here we’re creating the view columns and binding their properties to data model. Note that were’re binding 2 properties of the CellRendererProgress to different columns in the data model.

/*
 * Create TreeViewColumns and bind the DataColumn's to their properties.
 */
vertical = view.appendColumn();
vertical.setTitle("Rank");
rendererText = new CellRendererText(vertical);
rendererText.setText(rank);

vertical = view.appendColumn();
rendererPixbuf = new CellRendererPixbuf(vertical);
rendererPixbuf.setPixbuf(artistImage);

vertical = view.appendColumn();
vertical.setTitle("Artist");
rendererText = new CellRendererText(vertical);
rendererText.setText(artist);

vertical = view.appendColumn();
vertical.setTitle("# of times played");
rendererProgress = new CellRendererProgress(vertical);
/*
 * It's nice that in GTK+ we can bind multiple DataColumn's to
 * properties of a single TreeViewColumn.
 */
rendererProgress.setText(playCount);
rendererProgress.setValue(percent);

Here we’re querying the service (i.e calling the utility method we wrote) and populating the table. The image data will be fetched asynchroniously by AsyncImageLoader which is a subclass of Thread (Its code wil follow)

/*
 * Query Last.FM user.gettopartists method JAX-RS handles the Webservice
 * call and JAXB handles the unmarshalling of the XML response.
 */
result = LastFMUtil.queryTopArtists("Firari");

/*
 * Add the properties of Artist items as TreeView rows.
 */
if (result.getStatus().equals("ok")) {
	final List<Artist> topArtists = result.getTopartists().getArtist();
	/*
	 * Determining maximum playcount from top of the list.
	 * It will be used to calculate the percentage of the ProgressBar's.
	 */
	maxPlayCount = topArtists.get(0).getPlaycount().floatValue();
	for (final Artist artistItem : topArtists) {
		final TreeIter row = model.appendRow();
		model.setValue(row, rank, artistItem.getRank().toString());
		/*
		 * Asynchronously load the image data and set it as the image
		 * column. The first image URL is the "small" one.
		 */
		new AsyncImageLoader(model, row, artistImage, artistItem.getImage().get(0).getValue()).start();
		model.setValue(row, artist, artistItem.getName());
		model.setValue(row, playCount, artistItem.getPlaycount().toString());
		model.setValue(row, percent, Math.round(artistItem.getPlaycount().intValue() / maxPlayCount * 100));
	}
}

Here’s the code for AsyncImageLoader.

class AsyncImageLoader extends Thread {
	private ListStore model;
	private TreeIter row;
	private DataColumnPixbuf artistImage;
	private String url;

	public AsyncImageLoader(ListStore model, TreeIter row,
			DataColumnPixbuf artistImage, String url) {
		super();
		this.model = model;
		this.row = row;
		this.artistImage = artistImage;
		this.url = url;
	}

	@Override
	public void run() {
		try {
			/*
			 * Fetch the image data and set it as the image column of the
			 * specified row.
			 */
			URL artistImageURL = new URL(url);
			URLConnection artistImageConnection = artistImageURL
					.openConnection();
			DataInputStream in = new DataInputStream(artistImageConnection
					.getInputStream());
			byte[] artistImageData = new byte[artistImageConnection
					.getContentLength()];
			in.readFully(artistImageData);
			/*
			 * The image will have 32 pixels height.
			 */
			model.setValue(row, artistImage, new Pixbuf(artistImageData, -1,
					32, true));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

Here’s a screenshot of the running application.

TopArtists

The image will have 32 pixels height.

Introducing spellchecking support for TextView widget in Java-gnome

I was working on spellcheckers in Linux for quite a long time. My interest comes from another project that I’m involved in,  Zemberek, a Turkish NLP library which also includes a spellchecker. For Linux part, I was involved in developing its DBus interface as well as porting Enchant plugin to this new interface. I’m also maintaining Gentoo ebuilds for Zemberek packages and helping with Enchant package.

As a result, I gained experience with spellcheckers. At first, I started investigating GtkSpell to add bindings for Java, but I was unable to created usable .defs file from the headers. And after investigating Python bindings and seeing that it was hand-written, I examined another possibility, LibSexy. I started implementing LibSexy Java bindings which is still not complete. And main motivation was SexySpellEntry included in the library. I unfortunately hit a bug with text segmentation with it along with another bug causing a critical error (which ends up in an unchecked Exception in Java) which occurs in GtkSpell as well. (See Gentoo bugs #270179 and #270177) Anyway, later on Andrew helped to start-up the GtkSpell coverage with hand-crafted .defs file.

After a few weeks of development spelling branch is now merged to mainline which will make its way into 4.0.12 release. During the development I discovered that GtkSpell has a fallback mechanism for language of the spellchecker. The order is

  • lang peremeter passed to functions
  • LANG environment variable
  • English if none of the above is set.

Announcing Libnotify Java bindings

After 2 ½ months of work libnotify branch finally made its way to mainline. It’s my biggest contribution to Java-Gnome project. Again thanks to Andrew, Guillaume and Vrexio for their help and aid in the development and the testing. It will close a more than 3 year old ticket reported to Galago Project.

Bleeding-edge testers may grab the mainline branch and others may wait until next version (4.0.12) is released.

Libnotify Java bindings – Adding actions

Java-Gnome bindings doesn’t support callbacks at the moment. It can generate code for signals only. To add action callbacks, I reimplemented it as action signal. Here’s an example code to show how to add signals:

notification.addAction("a", "Action 1.a", new Notification.Action() {

    public void onAction(Notification source, String action) {
        System.out.println("1.a");
    }

});

The implementation currently has one drawback. Signals are not disconnected properly. This causes two issues. One, signals aren’t disconnected if actions are removed with clearActions(). Two, if actions with same actionIDs are added signals for all are triggered. Andrew will be adding support for signal disconnection to java-gnome and I’ll be using it in libnotify branch.

Follow

Get every new post delivered to your Inbox.

Join 534 other followers