In our uDig plug-ins for the Anaconda Workbench, we use Styled Layer Descriptors (SLD) for the map styles.
One of the features we are currently working on is the direction attributes for one-way streets. Of course you want to visualize them on the map, but SLD does not directly support arrow decorations for lines.
I asked for advice on the uDig mailing list and got the answer in no time. You can either use an arrow character from a suitable font in a Text Symbolizer, or a clever combination of Line Symbolizers with different styles of dashed lines to emulate arrows.
Using an SLD snippet from the Geoserver blog, I got the following result:
[Sorry, screenshot deleted to avoid potential licence issues.]
07 April 2009
02 April 2009
Getting Started with OSGi Declarative Services
OSGi Declarative Services have been on my mental agenda for a while, and now I've started using them. I'm not going to write yet another tutorial on the subject, but there are some bits and pieces I could not find anywhere else that may be worth mentioning.
To get an overview of Declarative Services, have a look at Neil Bartlett's tutorial on EclipseZone, or at his more recent EclipseCon presentation. The former is based on Eclipse 3.2.2, the latter on the latest Eclipse 3.5 milestones, so there are some differences to the current release Eclipse 3.4.2. In particular, Eclipse 3.5 supports a newer version of the Declarative Services Specification (1.1 vs. 1.0 in Eclipse 3.4).
All of the following refers to Eclipse 3.4.2. For using Declarative Services with Equinox, you need the following bundles:
Follow the tutorials to implement a simple example. If you cannot figure out why your component does not start, enable console logging for the Service Component Runtime in your OSGi launcher by setting the following system properties.
Add a header
Do not forget to specify the correct XML namespace
Seeing that Eclipse 3.4 has no graphical editors for the component descriptors, it is useful to install the Eclipse XML editor features and to work with XML validation on the component descriptors.
If your bundle contains more than one component, you can have one XML document per component and list them all in the manifest header, or you can have a single XML document containing all component descriptions, which is what I prefer.
To enable XML validation on a multi-component descriptor, write your own XML schema where the root element contains a sequence of 1..n component descriptors.
Here is an XML schema for this purpose:
Using this schema, a component descriptor for two components might look like this:
To get an overview of Declarative Services, have a look at Neil Bartlett's tutorial on EclipseZone, or at his more recent EclipseCon presentation. The former is based on Eclipse 3.2.2, the latter on the latest Eclipse 3.5 milestones, so there are some differences to the current release Eclipse 3.4.2. In particular, Eclipse 3.5 supports a newer version of the Declarative Services Specification (1.1 vs. 1.0 in Eclipse 3.4).
All of the following refers to Eclipse 3.4.2. For using Declarative Services with Equinox, you need the following bundles:
- org.eclipse.osgi
- org.eclipse.osgi.services
- org.eclipse.equinox.ds
- org.eclipse.equinox.util
Follow the tutorials to implement a simple example. If you cannot figure out why your component does not start, enable console logging for the Service Component Runtime in your OSGi launcher by setting the following system properties.
- equinox.ds.debug=true
- equinox.ds.print=true
Add a header
Service-Component: OSGI-INF/components.xml
to your manifest. (Choose any other filename if you like.)Do not forget to specify the correct XML namespace
http://www.osgi.org/xmlns/scr/v1.0.0
in your XML documents, or else your component definitions will not be recognized.Seeing that Eclipse 3.4 has no graphical editors for the component descriptors, it is useful to install the Eclipse XML editor features and to work with XML validation on the component descriptors.
If your bundle contains more than one component, you can have one XML document per component and list them all in the manifest header, or you can have a single XML document containing all component descriptions, which is what I prefer.
To enable XML validation on a multi-component descriptor, write your own XML schema where the root element contains a sequence of 1..n component descriptors.
Here is an XML schema for this purpose:
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:scr="http://www.osgi.org/xmlns/scr/v1.0.0"
targetNamespace="http://www.harmanbecker.com/anaconda/components"
xmlns:tns="http://www.example.org/components"
elementFormDefault="qualified">
<import namespace="http://www.osgi.org/xmlns/scr/v1.0.0"/>
<element name="components">
<complexType>
<sequence>
<element ref="scr:component" maxOccurs="unbounded"/>
</sequence>
</complexType>
</element>
</schema>
Using this schema, a component descriptor for two components might look like this:
<?xml version="1.0" encoding="UTF-8"?>
<c:components xmlns:scr="http://www.osgi.org/xmlns/scr/v1.0.0"
xmlns:c="http://www.harmanbecker.com/anaconda/components">
<scr:component name="foo">
<implementation class="com.acme.foo.FooImpl"/>
<service>
<provide interface="com.acme.foo.Foo"/>
</service>
</scr:component>
<scr:component name="bar">
<implementation class="com.acme.foo.BarImpl"/>
<service>
<provide interface="com.acme.bar.Bar"/>
</service>
</scr:component>
</c:components>
Labels:
Declarative Services,
Eclipse,
Equinox,
OSGi
01 April 2009
JDBC Drivers in OSGi
How do you create a JDBC connection for a given JDBC URL in an OSGi application? In particular, how do you avoid an explicit dependency of your application code on a given driver?
In a plain old classpath context, you would invoke
The trouble is, even if your driver does provide the
I'm working with a variant of the Zentus driver for SQLite, which I've modified slightly to build an OSGi bundle under Java 1.6. I added the service metadata, and indeed my application code now works without loading the driver via
There are the following issues:
The third point means that
Here is an outline of a partial solution:
If you do not need to support legacy code, do not bother using DriverManager and the Service Provider mechanism. After all, this is just a poor man's service registry, and you are much better off using the OSGi Service Registry.
I'll give an example in one of my next posts.
In a plain old classpath context, you would invoke
DriverManager.getConnection()
, maybe after loading the driver class using Class.forName()
, if your driver does not support the Service Provider mechanism which is mandatory for JDBC 4.0.The trouble is, even if your driver does provide the
META-INF/services
metadata, this does not work in OSGi, since DriverManager creates a number of class loader problems by using Class.forName()
internally.I'm working with a variant of the Zentus driver for SQLite, which I've modified slightly to build an OSGi bundle under Java 1.6. I added the service metadata, and indeed my application code now works without loading the driver via
Class.forName()
- as long as the code is running outside of OSGi.There are the following issues:
- The context class loader of the current thread is used to scan for
META-INF/services
resources and to load the referenced classes. This happens during initialization of DriverManager, so it will not catch resources from bundles which are not visible to the current context. - Additional drivers can register with DriverManager, they should do so in static initalization code, so that the driver gets registered when someone calls
Class.forName("my.own.Driver")
. DriverManager.getConnection()
iterates over the registered drivers until it finds one that can process the given URL. Unfortunately, it does a fatal double check to see if the class of that driver is the same that would be obtained by the caller. This amounts to callingClass.forName("some.matching.Driver", ccl)
where ccl is the caller's class loader.
DriverManager.setLogStream(System.out)
.)The third point means that
DriverManager.getConnection()
will always fail if the driver class is not visible to your bundle, so there really is no way to avoid a dependency.Here is an outline of a partial solution:
- Create an OSGi bundle for each JDBC driver you want to use. Add a bundle activator that calls
Class.forName("some.jdbc.Driver")
. This will register the driver with DriverManager when the bundle is started. - For each bundle that needs to create connections using
DriverManager.getConnection()
, add optional dependencies on the JDBC drivers packages for all drivers that you are planning to use.
If you do not need to support legacy code, do not bother using DriverManager and the Service Provider mechanism. After all, this is just a poor man's service registry, and you are much better off using the OSGi Service Registry.
I'll give an example in one of my next posts.
Subscribe to:
Posts (Atom)