Essentially, all models are wrong, but some are useful.
Before talking about the internals of the NetBeans APIs and learning the basics of NetBeans UI design, we'll need to define some basic stuff about our "Twitter Search Application": we'll have to define a client-side data model with some entities. Let's do that quickly.
Building a client-side application requires you to model data, of course. This client-side data model may be different from any server-side data model you may have. On the client-side you can mix data from different server-side data models, for instance.
For our Twitter-search application we'll define a quick & dirty model with the following entities:
- Tweet
A Tweet will hold information related to, well, a tweet. This includes different attributes such as an URL, the text in the tweet, a timestamp and the author of the tweet.
- TweetAuthor
All the information about the author of a Tweet will be kept in a "TweetAuthor" entity, so that we can add atributes to the entity later on (such as the Twitter URL of the author, an image, or whatever).
- Query
A Query will hold information about the query we'll be doing to the Twitter Search API. At the moment we'll encapsulate a simple "search term" inside this entity. In the future we may want to extend this entity with logical operators (AND, OR, NOT, etc.). But let's keep things simple first.
The relationships between these entities are as follows: a Query has a list of Tweets (the results of the query) and each Tweet has a TweetAuthor. Figure Entities and DAOs explains graphically these relationships.
We'll keep all these entities in a Java package called, say, "net.antonioshome.nbtweeting.entities". The entities will be plain old Java objects, this is, "Java Beans" with an empty constructor and getters and setters. Something like this:
package net.antonioshome.nbtweeting.entities; public class Query { private String keyword; private List<Tweet> tweets; public Query() { tweets = new ArrayList<Tweet>(); } public List<Tweet> getTweets() { return tweets; } public void setKeyword( String keyword ) { this.keyword = keyword; } public String getKeyword() { return this.keyword; }
Note that if you're building a database application, these entities may or may not reflect the internals of your database model. In my experience is better not to bring the database structure to the client-side model. You'll be suffering if you do: it is better to have a separate model, even though you have to rewrite some plain Java objects. Anyway this discussion does not belong to these notes, so let's keep going quickly. Next section, please!
We will also need some basic Data Access Objects which will be responsible for searching using the Twitter Search API.
The "TwitterSearchDAO", for instance, will receive a "Query" object and will talk to Twitter to receive some, say, XML. It will then parse this XML and build some "Tweet" and "TweetAuthor" entities, and will update the list of Tweets in the Query entity. The source code could look something like this:
package net.antonioshome.nbtweeting.dao; public class TwitterSearchDAO { public List<Tweet> search( String keyword ) throws Exception { // Talk to Twitter, parse XML // Create a list of Tweet and return it ...
If you're building a two-tier database application then this "dao" package will usually have SQL or JPA related queries. If you're building a three-tier web-service based application then these "DAOs" will be responsible for fetching stuff from remote web services. Note that, as I explained above, these DAOs return client-side entities, and not database entities.
If you're building a database application you may want to add a light transaction-aware layer in between the rest of your client-side application and the DAOs. This "transaction-aware" layer may combine different DAOs in a single client-side transaction. If you build a 3-tiered application then this layer belongs to the server side, of course. Oh, well, I'm talking off-topic again. Let's keep going!
One of the most imporant and powerful idioms in the NetBeans Platform is that you can add capabilities to existing objects dynamically. You do this by using the NetBeans Lookup Library.
You can, for instance, add the "Saveable" capability to an object at runtime, to indicate that the object can be saved. Once the object is saved you can remove that ability from the object.
Some other capabilities could be, for instance: the "Closeable" capability (for objects that can be closed, such as forms, projects or files). The "Openable" capability (for objects that can be opened by the user). Or the "Reloadable" capability (for objects that can be reloaded by the user).
Let's see briefly what we need to make our entities "capability enabled".
Let's add an ability to one of our entities, just to learn how to do that. Which one? Mmmm... What about a "Reloadable" ability to the "Query" entity? So that we can refresh the list of Tweets in the Query? Yep. Let's do that.
We start by defining our ability using a plain Java interface. We could also use a plain Java class, or an abstrac class. But I prefer interfaces:
/** * Reloadable is an ability contained in objects that can be reloaded. */ public interface Reloadable { /** * Invoke this method to reload the entity. * @throws Exception if the entity cannot be reloaded. */ public void reload() throws Exception; }
Let's modify the "Query" entity so that it can hold "abilities". We do this by marking the entity as "Lookup.Provider", and by creating a "Lookup" object with all the abilities in our entity. In our case we add an implementation of the "Reloadable" ability that uses the "TwitterSearchDAO" to fetch a new list of Tweets; like so:
public final class Query implements Lookup.Provider { private String keyword; private List<Tweet> tweets; private Lookup lookup; private InstanceContent instanceContent; public Query() { this.tweets = new ArrayList<Tweet>(); this.instanceContent = new InstanceContent(); this.lookup = new AbstractLookup( instanceContent ); this.instanceContent.add( new Reloadable() { public void reload() throws Exception { TwitterSearchDAO dao = new TwitterSearchDAO(); tweets.clear(); tweets.addAll( dao.search( keyword ) ); } } ); } public Lookup getLookup() { return lookup; } ... // Rest of getters and setters
Let me explain briefly the code above:
We start by implementing the Lookup.Provider interface, indicating that this class has extended abilities. | |
Since we're implementing the "Lookup.Provider" interface we must have a "getLookup" method, that is implemented here by returning the "lookup" instance variable. | |
We use an InstanceContent object, responsible for holding all the abilities of our objects. | |
We create an AbstractLookup, a special kind of Lookup, that wraps the InstanceContent object we defined above. | |
Finally we "add" an implementation of the "Reloadable" ability to the instance content of our Query entity. The implementation of this "Reloadable" ability just calls the TwitterSearchDAO and updates the list of Tweets in our Query. |
This is the NetBeans-way to dynamically add abilities to objects: observe that the "Query" entity does not implement the "Reloadable" ability directly. We add the "Reloadable" ability to the "Query" lookup, instead, so that we can add and remove that ability at runtime. This common NetBeans idiom is extremely powerful [1]
Another common idiom in NetBeans Platform programming consists on how to see if an object has a given ability. You do this by "looking-up" the ability in the object's "lookup", like so:
Query query = ... // any object implementing the Lookup.Provider interface // Get the "lookup" of the object, and lookup for the "Reloadable" ability... Reloadable reloadable = query.getLookup().lookup( Reloadable.class ); // If the reloadable ability exists then reload the object... if ( reloadable != null ) { try { reloadable.reload(); } catch( Exception e ) { ... } }
This is a very common idiom in the NetBeans Platform, and you'll be seeing it all around the code. Get used to it.
We've defined a set of entities such as Tweet, TweetAuthor and Query, that we'll be using in our client-side application. These are our own entities, and have nothing to do with whatever entities Twitter is using internally. We don't mind that.
We've also encapsulated all business logic (in our case a simple query to the Twitter Search API) inside a DAO.
Finally we've quickly seen how to add abilities to our entities by using the NetBeans Lookup Library. We know how to add an ability to an object, and how to search the abilities of any object.
[1] Many programming languages, such as Javascript or Lua, make it possible for you to add dynamic behaviour to objects at runtime. The NetBeans Lookup Library makes it possible to use this feature in Java applications.
blog comments powered by Disqus