Showing posts with label Connection Framework. Show all posts
Showing posts with label Connection Framework. Show all posts

Thursday, August 28, 2008

Creating the SQLite Connection Profile UI bits

Hi there!

So now we're almost to our first functional version of a SQLite connection profile in DTP. We have a driver-wrapper plug-in, a driver definition, an overridden catalog loader, and a connection profile with its associated connection and connection factory classes. What's next? Why, adding the UI so you can create the profile, of course!

With versions of DTP prior to Ganymede, this was a more difficult, but not horrible task. In Ganymede, we've reduced the amount of work to adding three extension points and writing four key classes in a org.eclipse.datatools.enablement.sqlite.ui plug-in (basically just extending these classes a tad, so little real work involved):
  • A connection profile wizard extension that uses the org.eclipse.datatools.connectivity.connectionProfile extension and uses the newWizard node so we can define our wizard
  • A property page extension (org.eclipse.ui.propertyPages) to define a property page so we can edit our SQLite conneciton profile instances
  • A driver UI contributor extension (org.eclipse.datatools.connectivity.ui.driverUIContributor) to create a reusable UI component that gathers the information we need for our SQLite connections
  • A connection profile wizard class that extends the org.eclipse.datatools.connectivity.ui.wizards.ExtensibleNewConnectionProfileWizard class
  • A connection profile wizard page that extends org.eclipse.datatools.connectivity.ui.wizards.ExtensibleProfileDetailsWizardPage
  • A connection profile property page that extends org.eclipse.datatools.connectivity.ui.wizards.ExtensibleProfileDetailsPropertyPage
  • And a driver UI component that is used on the wizard and property pages that implements org.eclipse.datatools.connectivity.ui.wizards.IDriverUIContributor
It may look daunting, but really it boils down to a few extension points, a few extended classes, and an instance of poor man's inheritance (copying a class from another project).

So let's get started!

Wednesday, August 20, 2008

Creating an Actual SQLite Connection Profile (minus the UI)

Hi there!

So now we have the majority of our work done. We have a driver-wrapper plug-in, a driver definition, and an overridden catalog loader. What's next? Wrapping the functionality in a nice, easy to use connection profile!

Note: Previous articles in this series cover the following topics: Catalog Loaders, Driver Templates, and the Driver Framework.

Many moons ago, we talked at a high level about the driver template & driver definition frameworks. It's now time to talk briefly about the connection profile framework.

It all boils down to this... A connection profile manages a connection to something. Right now in DTP we connect to JDBC databases and file systems for the most part. But the Sybase WorkSpace product also uses DTP to connect to application servers, LDAP, UDDI repositories, and much more. So it's not limited in any way.

With that in mind, a JDBC database connection profile, such as the one we want to create for SQLite, just needs to manage a JDBC connection under the covers. We'll add a layer on top of that to attach the SQL Model to the connection so we can display the database specifics in the Data Source Explorer tree.

In the DTP Ganymede (1.6) release, we've really simplified creating a new connection profile if it's associated with a db definition vendor/version and a driver template. So we'll take advantage of that for SQLite.

To create a connection profile, we will go to the org.eclipse.datatools.enablement.sqlite plug-in project and create a couple of classes and two extension points. These steps are kind of chicken & egg - the order isn't really important so long as you get them all done.

Step 1: Create a new connection factory and connection class for SQLite. These are the actual raw connections that our SQLite connection profile will manage for us.

The connection class is pretty easy. We're just going to extend the Generic JDBC JDBCConnection class for SQLite so we have our own specialized version of it.

That code looks like this:
package org.eclipse.datatools.enablement.sqlite.connection;

import org.eclipse.datatools.connectivity.IConnectionProfile;
import org.eclipse.datatools.connectivity.db.generic.JDBCConnection;

public class SQLITEJDBCConnection extends JDBCConnection {

/**
* @param profile
* @param factoryClass
*/
public SQLITEJDBCConnection(IConnectionProfile profile,
Class factoryClass) {
super(profile, factoryClass);
}
}

The connection factory requires a little more work, but not much more:
package org.eclipse.datatools.enablement.sqlite.connection;

import org.eclipse.datatools.connectivity.IConnection;
import org.eclipse.datatools.connectivity.IConnectionProfile;
import org.eclipse.datatools.connectivity.db.generic.JDBCConnectionFactory;

public class SQLITEJDBCConnectionFactory extends JDBCConnectionFactory {

public SQLITEJDBCConnectionFactory() {
super();
}

public IConnection createConnection(IConnectionProfile profile) {
SQLITEJDBCConnection connection = new SQLITEJDBCConnection(profile, getClass());
connection.open();
return connection;
}
}

Basically in the connection factory, we're just creating one of our new SQLiteJDBCConnection class instances for the profile that's passed in.

Step 2: We want to add a new extension point to the plugin.xml in the org.eclipse.datatools.enablement.sqlite plug-in project: org.eclipse.datatools.connectivity.connectionProfile.
This extension point has a couple of nodes we're going to create beneath it: connectionFactory and connectionProfile.

Let's define our connectionProfile first, so we have the connection profile ID to use for the connectionFactory.



You can see from the screen that we're giving our connection profile the following properties:
  • id = org.eclipse.datatools.enablement.sqlite.connectionProfile
  • category = org.eclipse.datatools.connectivity.db.category (this ensures that our connection profile shows up under the "Databases" category in the DSE)
  • name = SQLite Connection Profile
  • icon = icons/jdbc_16.gif (you can copy this from the Generic JDBC connection profile plug-in)
  • pingFactory = org.eclipse.datatools.enablement.sqlite.connection.SQLITEJDBCConnectionFactory (our new connection factory class we created in step 1)
Then we define our connectionFactory:



Our connectionFactory extension has the following properties:
  • id = java.sql.Connection (this maps to the type of connection this connection factory/connection class maps back to -- in this case, a JDBC connection)
  • class = org.eclipse.datatools.enablement.sqlite.connection.SQLITEJDBCConnectionFactory (our connection factory class)
  • profile = org.eclipse.datatools.enablement.sqlite.connectionProfile (our SQLite connection profile ID from the connectionProfile extension)
  • name = SQLite Connection Factory
So now we have a connection profile for SQLite in DTP. Now all we need is a user interface (wizard, wizard page, property page, and driver UI) and we'll be golden!

That's what we'll cover next time.
--Fitz

Reblog this post [with Zemanta]

Tuesday, June 24, 2008

How do you add your own custom driver template? (Repost)

Hi all...

Sorry there's been a bit of a lag between articles. We've been busy trying to get Ganymede out the door and start planning for the future (maintenance releases for 1.6 plus the next major release of DTP for next June). I need to ditch my crystal ball for a magic eight ball I think. :)

Anyway... This week we're going to chat about how to create a new custom driver template.

First of all, when would you want to do this? There are a few possibilities:

  1. You're creating support for a new database type not currently covered by DTP Enablement.
  2. You want to add support for a third-party driver (such as DataDirect or jTDS) for a currently supported database.
  3. You simply want to add an alternative driver template to complement an existing driver that adds properties or changes default values for use in your application(s).
That said, let's pick #1. We can use it as an example to provide functionality through this article series and eventually add some new database support to DTP Enablement.

For this example, let's work on SQLite support.

You can find a ton of information about SQLite on the SQLite home page (http://www.sqlite.org/). And you can grab the SQLite JDBC driver from the SQLiteJDBC page (http://www.zentus.com/sqlitejdbc/). So we'll grab the SQLite binaries for Windows (in my case) and the sqlitejdbc-v051-bin.tgz for this case. (You'll need to put the sqlitejdbc.dll in your JRE's or SDK's JRE bin directory to get this working.)

Typically the process I work through when deciding whether or not we need a custom connection profile for a given database is as follows:
  1. Can I create a new Generic JDBC driver definition that references the jar (sqlitejdbc-v051-native.jar in this case)? Yes.
  2. Can I then create a new Generic JDBC connection profile that uses my driver definition from (1) to connect to the database? Yes.
  3. Can I browse into the database to see schemas, tables, stored procedures, and the like? Unfortunately not in this case.


This means we need to go a step further and go through these stages:
  • Stage 1: Create a new Database Definition for our Database
  • Stage 2: Create a new Driver Template for our Database (and the associated UI)
  • Stage 3: Create a new Connection Profile for our Database
  • Stage 4: Create a Custom Catalog Loader for our Database
So let's start with Stage 1 and get Stage 2 started today...

For each database that is supported in DTP and presents its structure in the Data Source Explorer (DSE), we have to tell the base models what the database supports. This is represented by the Database Definition (or "DB Definition"). What data types does it handle? Does it handle aliases or triggers? What kinds of constraints?

The DB Definition file itself is simply an XMI file (an XML file that provides metadata for some other XML files). In this case, it maps back to an EMF model for the DB Definition.

I'm not going to go into the gory details here. But there's a good article on how to get started here (be sure to look at Scenario 2).

Basically we need to create an XMI file to tell DTP what basic properties this database adheres to. What data types does it support, does it have catalogs, and so on. Most of this information can be found in the database documentation.

To simplify the process a little, we have a sample Java file that can be customized to create a new XMI file. I've modified it somewhat to create the XMI file locally. And I'll post a zip with the necessary files on the DTP website so you can grab them at the end of this exercise.

Once that's created, you can create a plug-in wrapper called "org.eclipse.datatools.enablement.sqlite.dbdefinition". And in that plug-in wrapper we will use the org.eclipse.datatools.connectivity.sqm.core.databaseDefinition extension point to tell DTP about it. Basically the databaseDefinition extension point just maps the XMI file to a named vendor and a named version. That's how the underlying systems will locate it. (You'll see the terms vendor and version appear later as we define our driver template as well.)

So now we have a DB Definition and a plug-in wrapper for it. Cool. Now we can move to the first part of Stage 2: Creating a driver template.

To create a new driver template, we'll start by creating another plug-in. This plug-in will house all the non-UI bits and pieces we want for our SQLite connection profile. We'll call it "org.eclipse.datatools.enablement.sqlite".

In the manifest for our new SQLite plug-in, we will create a new org.eclipse.datatools.connectivity.driverExtension extension. This extension point is used to register driver template categories and driver templates within the DTP framework.

Remember how we were talking about vendor and version earlier? Well, now we're going to map some driver template categories to them.

First we'll create a "SQLite" category, which maps back to the vendor name we chose earlier and has org.eclipse.datatools.connectivity.db.driverCategory as a parent. All database drivers fall under this category in DTP so we can easily find them. We'll call our new category "SQLite" and give it an ID "org.eclipse.datatools.enablement.sqlite.driver.category".

Next, we'll create a "3.5.9" category, to map to the version we selected earlier (3.5.9 is the most recent version of SQLite I could find). This one will use our "SQLite" category as its parent. We'll call it "3.5.9", and give it an ID "org.eclipse.datatools.enablement.sqlite.3_5_9.category"

Lastly we'll create the driver template itself. We'll give it the name "SQLite JDBC Driver" (not very original, but easy to remember) and an ID "org.eclipse.datatools.enablement.sqlite.3_5_9.driver". We'll set it to our SQLite 3.5.9 parent category so it has some context, setting it to the category ID we made a second ago "org.eclipse.datatools.enablement.sqlite.3_5_9.category".

We know it needs a driver jar, so we'll provide a default jar name as "sqlitejdbc-v051-native.jar". If we get fancy later, we can provide some mechanisms to pre-populate the path to the local version of that jar, but for now we'll assume the user will be able to know where their jar is located and set it appropriately in the driver definition. (Yes, we'll talk about the "fancier" way to do this automatically later.)

Beyond that, we need to get a few key bits of information about the driver. Based on the documentation for SQLite, it appears that we require the following property values:
  • Driver Class: org.sqlite.JDBC
  • JDBC URL: jdbc:sqlite:test.db
Easy enough, right? Well, we also require a few other things for a standard driver definition:
  • Vendor: SQLite
  • Version: 3.5.9
  • Database name: TEST (we can extrapolate this from the sample URL)
  • User ID: (not applicable, so we just leave it blank)
With these basic bits and pieces, we have defined our driver template! Whew. Took a bit of work though, I know.

That said, we now have reusable bits we can take into the next part of this process, which is creating a connection profile that can use our new driver definition and driver template.

At this point we're just laying the ground work. You can find a zip with the plug-ins created during this exercise here.

So next time we'll look at creating a basic connection profile that can actually use these bits!

--Fitz