Oracle Blog

Random NetBeans Stuff

Since I stated that yesterday's blog entry would be the final part in this series on creating context-sensitive capabilities for file-based nodes, the fact that the series continues today can only mean that... this is the epilogue! (In fact, it might be Part 1 of the epilogue.)

The reason for yet another part in this series is that loosely coupled data sources could have varying ORM tools behind them. In other words, one module could provide entity classes that use iBatis to connect to a database, while another module could provide entity classes that use JPA (or Hibernate or something else) to connect to a database.

How do we deal with this situation? Well, good thing that the interface for dealing with data is so simple:

In fact, anything at all could be handled by means of the above interface. Let's say that our generic container application should also be able to display a node representing data coming from a web service. Not a problem, our interface covers that scenario too, doesn't it?

Great, so we have a very flexible interface, which can be implemented in many different ways. The only thing we need is for the relevant database connection files of the respective ORM tool to be registered in the layer. Someone providing a module with configuration files for iBatis, for example, would have this in the layer:

"Connections" is the folder name containing the connections, below that is an identifier (here "Cruise") for distinguishing between different connections, because in the end, when the NetBeans Platform resolves all the layer files, the "Connections" folder will potentially have content like this:

So, now we have modules providing entity classes (some of which, as with JPA, have annotations, hence dependencies on EclipseLink or TopLink or something similar), while others are unannotated entity classes (such as those supported by iBatis). These modules all register their ORM configuration file, exactly as shown above.

And how are the above registrations used? That depends on the implementation of our DataServiceInterface. In the case of iBatis, the implementation of "getData" is as follows. Note the lines in bold, which shows you how the correct configuration file is found, i.e., if you want to use iBatis to get data from the "Cruise" database, all you need to do is provide the identifier "Cruise", followed by the name of the ORM, which is "iBatis" here, and "config" to specify the configuration file. As a user of iBatis in this application, you don't care at all about the implementation, you simply specify a way to find the file that you'll be using.

The module providing the class above could now be in a different module to where the connection files are found, since the class above looks in the layer for the location of the connection file.

The above file is registered in the "DataServiceProviders" layer file of the module that provides it. When the NetBeans Platform resolves all layer files, it will end up with a "DataServiceProviders" folder with this content:

Now let's call "getData" in our implementation classes! When do we do that? When we need to get data. Where do we need to do that? In the loosely coupled ChildFactory classes (see the past entries in this series for details on this). These need to look inside the layer file and find the above folders, turning them into a Lookup, by means of which the implementation can be found, where we can call the "getData", since that is defined in the interface:

Above, we specify that we want to use JPA, without caring at all about the implementation. We simply say "yes, we want to use JPA for this connection", with the file registered in the "config" attribute determining how the connection is made, as always.

What is the point of all of this? To make the application very flexible, so that contributions from the outside can be made possible. In the scenario that the IMR (Institute of Marine Research) in Norway is working with, new nodes can come from a wide variety of third parties, each providing a broad range of different (unrelated) kinds of data. In this scenario, where the application is a generic container for nodes, a very loose structure such as the above seems to be of fundamental importance.

what I don't like about this approach is the childfactory part: The childfactory is the consumer of the service. It should be transparent to the childfactory where the data comes from. The problem is this code:

It get's the data from the default lookup. Then the DataServiceInterface should decide which implementation to use, by calling:
DataServiceInterface dsi = Lookups.forPath("DataServiceProviders/Cruise").lookup(DataServiceInterface.class);

In fact it would be better to have a different interface for this, because we don't require the name parameter, also it would be easier to separate the main "Proxy" DataServiceInterface from the individual instances:

public interface NamedDataServiceInterface {

public List getData();

public void updateData();

public void saveData();

}

And as such choosing one implementation available there. I do not see why there should be multiple ones for the same db at the same time.

In \*our specific project\* there might be one reason, why there could be more than provider: We could use the central database, when connected to the internet, and a local one offline.

About

Geertjan Wielenga (@geertjanw) is a Principal Product Manager in the Oracle Developer Tools group living & working in Amsterdam. He is a Java technology enthusiast, evangelist, trainer, speaker, and writer. He blogs here daily.

The focus of this blog is mostly on NetBeans (a development tool primarily for Java programmers), with an occasional reference to NetBeans, and sometimes diverging to topics relating to NetBeans. And then there are days when NetBeans is mentioned, just for a change.