The uDIg Catalog is used to mange and interact with spatial services and resources.
The style of programming used for the uDig Catalog is similar to that of the Eclipse IDE (where concepts such as Project / IResource / IFile are defined).
 |
Since uDig does not depend on the Eclipse IDE (we have no need of a compile / build cycle) we provide are making use of our own interfaces ICatalog, IService and IGeoResource covered on this page. By making use of our own API we also have been able to address a number of concerns specific to spatial data; almost all our data is so big, or remote, or both that latency is an issue. It is very important to us that you know when you are making use of spatial data that make take some time to process, or has the possibility of an I/O error. |
CatalogPlugin
The CatalogPlugin provides the following services:
- The concept of Handles to actual Resources
- Discovery of additional resources using Search facilities
- Programmatic Management of spatial resources
The CatalogPlugin supports several formats right out of the box and is easily extended for custom content.
You can retrieve the single instance of CatalogPlugin using getDefault():
CatalogPlugin activator = CatalogPlugin.getDefault();
You can add a listener to watch for catalog events:
CatalogPlugin.getDefault().addListener( listener );
CatalogPlugin.getDefault().removeListener( listener );
For more information please check out the next section on 3 Tracking Changes.
The CatalogPlugin keeps a list of known catalogs, including the local catalog and remote web catalogs.
CatalogPlugin.getCatalogs();
Most of the time you will spend interacting with the LocalCatalog manage live connections to services:
CatalogPlugin.getDefault().getLocalCatalog();
There is also a service factory used to create services to add to the local catalog:
IServiceFactory serviceFactory = CatalogPlugin.getDefault().getServiceFactory();
List<IService> created = serviceFactory.createService( file.toURL() );
There are several more examples of using the ServiceFactory below.
The CatalogPlugin is the "Activator" or "Plugin" class for net.refractions.udig.catalog - as such it extends AbstractUIPlugin for the following.
- getDialogSettings() - used to hold persistent state data for wizards and plug-ins
- getImageRegistry() - images that are shared for frequently used within the plug-in
- getPreferenceStore() - used to hold persistent user or internal settings
By convention all Plugins contain a static ID field used to identify the plug-in OSGi bundle, or Platform methods.
Bundle bundle = Platform.getBundle( CatalogPlugin.ID );
The ID is also useful when reporting problems:
IStatus status = new Status(IStatus.ERROR, CatalogPlugin.ID, "error message");
CatalogPlugin.getDefault().getLog().log( status );
ICatalog
ICatalog is the interface used to represent a generic "catalog" of spatial resources and services, you can think of it as being similar to a web search engine.
The following ICatalog methods are used when working with remote services:
- getInfo( IProgressMonitor ) - description of the catalog
- find( URL, IProgressMonitor ) - retrieve a list of services (or resources) for the provided URL, including all known alternatives.
- search( String, Envelope, IProgressMonitor ) - used to query the catalog using a text pattern and bounding box
Please keep in mind that the catalog tracks a great deal of information about your services and resources; the reason find returns a list (rather than just a single entry) is the same information may be available from a number of sources. Having a range of alternatives available is useful in a world where external servers are sometimes down for maintenance.
The CatalogPlugin keeps track of all the catalogs (local and remote) that can be used to find spatial content.
List<IResolve> found = new ArrayList<IResolve>();
for( ICatalog catalog : CatalogPlugin.getCatalogs() ){
try {
found.addAll( catalog.search( pattern, bbox, process ) );
}
catch( IOException problem ){
catalog.getLog(
new Status( IStatus.WARNING, CatalogPlugin.ID, IStatus.OK, "Failed to search with:"+pattern, t)
);
}
}
The above example makes use of CatalogPlugin, any problems are reported using the CatalogPlugin ID to the logging system. We will cover some of the other uses of ICatalog below.
Local Catalog
The local catalog (implemented by the CatalogImpl class) is responsible for managing a list of all the services known to the uDig application. The local catalog is also responsible for tracking which Services are in use and tracking any life cycle changes (some services such as Databases are expensive to connect to and care must be taken to clean up after their use).
The following ICatalog methods are used when working with a local catalog
- add( IService ) - add a service to the catalog
- remove( IService ) - used to communicate when a service is removed (such as a file being deleted from disk)
- replace( URL, IService ) - used to communicate when a service changes location (such as a file moving on disk)
- createTemporaryResource( Object ) - used to create a temporary resources, usually by using a FeatureType
- getTemporaryDescriptorClasses() - list of classes for which a temporary resource can be created
The following ICatalog methods are safe to call from a user interface (ie are non blocking):
- getById( Class, URL, ProgressMonitor ) - used to look up an exact match
- addCatalogListener( IResolveChangeListener ) - watch the catalog for changes
- removeCatalogListener( IResolveChangeListener ) - stop watching the catalog for changes
The CatalogPlugin is mostly used to access a single Local Catalog used to manage live connections to your databases, external services and local files. The local catalog is used to track all "active" data connections; even if you find information in a remote catalog, it will be added to the local catalog as you start to use it.
To find an existing service in the catalog:
ICatalog catalog = CatalogPlugin.getDefault().getLocalCatalog();
IService shapefile = catalog.getById( IService.class, url, progressmonitor );
To find an existing georesource in the catalog:
ICatalog catalog = CatalogPlugin.getDefault().getLocalCatalog();
IGeoResource shapefile = catalog.getById( IGeoResource.class, url, progressmonitor );
To add a service to the catalog we need to use the ServiceFactory to create the IService; and then ICatalog.add( service ) to place
each service into the ctalog.
To use ServiceFactory to connect to a service based on a simple URL.
File file = new File( "C:\data\cities.shp" );
URL url = file.toURL();
IServiceFactory serviceFactory = CatalogPlugin.getDefault().getServiceFactory();
for( IService service : serviceFactory.createService( url ) ){
try {
IServiceInfo info = service.getInfo( null );
CatalogPlugin.getDefault().getLocalCatalog().add( service );
}
catch (IOException couldNotConnect ){
}
}
You can also use connection parameters to be a bit more specific about servic:
Map<String,Serializable> params = new HashMap<String,Serializable>();
params.put("ur", url );
params.put("create spatial index", Boolean.true );
IServiceFactory serviceFactory = CatalogPlugin.getDefault().getServiceFactory();
for( IService service : serviceFactory.createService( params ) ){
try {
IServiceInfo info = service.getInfo( null ); CatalogPlugin.getDefault().getLocalCatalog().add( service );
}
catch (IOException couldNotConnect ){
}
}
To use ServiceFactory to connect to a more interesting service such as PostGIS.
Map<String,Serializable> params = new HashMap<String,Serializable>();
params.put("dbtype", "postgis"); params.put("host", "www.refractions.net"); params.put("port", new Integer(5432)); params.put("database", "demo-bc"); params.put("user", "demo"); params.put("passwd", "demo");
IServiceFactory serviceFactory = CatalogPlugin.getDefault().getServiceFactory();
for( IService service : serviceFactory.createService( params ) ){
try {
IServiceInfo info = service.getInfo( null ); CatalogPlugin.getDefault().getLocalCatalog().add( service );
}
catch (IOException couldNotConnect ){
}
}
Or a Web Feature Server:
URL url = new URL("http:);
Map<String,Serializable> params = new HashMap<String,Serializable>();
params.put( WFSDataStoreFactory.URL.key, url );
params.put( WFSDataStoreFactory.LENIENT.key, true );
params.put( WFSDataStoreFactory.TRY_GZIP.key, true );
for( IService service : serviceFactory.createService( params ) ){
try {
IServiceInfo info = service.getInfo( null ); CatalogPlugin.getDefault().getLocalCatalog().add( service );
}
catch (IOException couldNotConnect ){
}
}
To determine the connection parameters for many common servers review the GeoTools User Guide.
IService
The CatalogPlugin uses the interface IService to model a local or remote service.
Here are some examples to get us started:
- A remote Database
- A local File on disk
- A Web Feature Server
- An "internal" service such as the MapGraphics included with uDig
The identifier of a service is available - so you can find the service again at another time.
URL id = service.getIdentifier();
The connection parameters are available; you can store these parameters if you would like to connect to the service again at a later time.
Map<String,Serializable> params = service.getConnectionParams()
For a Map the connection parameters are stored (so as a Map loads we will ensure each required service is available in the local catalog). The catalog will also store these connection parameters between runs so it can connect to the service again.
You can figure out which catalog the service belongs to:
ICatalog catalog = service.parent( new NullProgressMonitor() );
This method actually needs to connect to the service so a ProgressMonitor is used (allowing the user to cancel).
To retrieve information about a service including its title, description and icon you can ask for the ServiceInfo object:
IServiceInfo info = service.getInfo( new NullProgressMonitor());
String title = info.getTitle();
String description = info.getDescription();
You can check if a service is connected:
Status status = service.getStatus();
A service contains children.
for( IResolve child : service.members(new NullProgressMonitor())){
}
These children are often IGeoResources representing spatial data; but they may also be folders or processes depending on the service.
If you are only interested in spatial data there is a specific method that will list only the GeoResources with useful data.
for( IGeoResource georesource : service.resources(new NullProgressMonitor()) ){
}
Service Specific Examples
To access a shapefile:
if( service.canResolve( ShapefileDataStore.class )){
ShapefileDataStore shapefile = service.resolve( ShapefileDataStore.class, new NullProgressMonitor() );
}
To access a WebMapServer:
if( service.canResolve( WebMapServer.class )){
WebMapServer wms = service.resolve( WebMapServer.class, new NullProgressMonitor() );
...
}
To access PostGIS data store:
if( service.canResolve( PostgisDataStore.class )){
PostgisDataStore database = service.resolve( PostgisDataStore.class, new NullProgressMonitor() );
...
}
To work with PostGIS jdbc connection:
if( service.canResolve( Connection.class )){
Connection connection = service.resolve( Connection.class, new NullProgressMonitor() );
try {
... issue jdbc commands...
}
finally {
connection.close();
}
}
To access a WebMapServer:
if( service.canResolve( WebMapServer.class )){
WebMapServer wms = service.resolve( WebMapServer.class, new NullProgressMonitor() );
...
}
IGeoResource
One of the most useful things stored in a catalog is actual spatial data. The IGeoResource interface represents real information, the kind you can display on screen or perform analysis on.
Here are a few examples to get us started with:
- A Table or View in a database
- A FeatureCollection made available through a Web Feature Server (WFS)
- A Web Map Server (WMS) Layer
- The contents of a shapefile
- A GridCoverage contained in an ArcGrid file
The IGeoResource implementation does not place any restrictions on the interface used to interact with the external resource. That said here are our top contenders for most popular interface:
From GeoTools:
- org.geotools.data.FeatureSource used to represent Feature information available in a File, Database or Web Feature Server
- org.geotools.data.FeatureStore used to represent Feature information that allows modification.
- org.geotools.data.ows.Layer represents a externalized rendering service advertised by a WMS
- org.geotools.coverage.io.AbstractGridCoverageReader represents raster information such as GeoTIFF or ArcGRID content
From Java:
- java.sql.Connection a JDBC connection used to directly communicate with a database
Please see the Advanced section for details on making your own content available: CAD file formats, feature content from other toolkits, and dynamically generated content are all exciting possibilities.
IGeoResource API Overview
- getInfo( IProgressMonitor ) access to a GeoResourceInfo describing this resource
- service( IPorgressMonitor ) the service providing this resource
- getIdentifier() identifier used to locate the resource in the catalog
- dispose( IProgressMonitor )
IGeoResource instances can formed into a tree:
- members( IProgressMonitor ) - used to treat IGeoResource like a folder that contains more content
- parent( IProgressMonitor ) - the parent containing this IGeoResource
Use of IGeoResourceInfo
IResolve
CatalogPlugin uses the model of a "handle" to allow access to spatial resources.
The concept of a resource handle is represented as the IResolve class:
- acts as a Proxy for remote content, you can ask a few basic questions (say askign for the bounds) without having to connect to the real remote service
- acts as an "Adapter" for interacting with data, you can turn your IResolve into the object you really want, behind the scenes the catalog will make the connection and return you the class used to interact with data.
- acts as an "Extensible Interface", you can make up your own data access APIs and teach the catalog how to make use of them
Here are the core responsibilities of IResolve interface:
- IResolve.getIdentifier() is a unique URL used to identify this resource in the catalog
- IResolve.canResolve( Class type ) is a non blocking check to see if a type of resource is available for the handle
- IResolve.resolve( Class type, IProgressMonitor monitor ) will acquire the requested resource
IResolve handles can form a tree using the following methods:
- members( IResolve parent, IProgressMonitor )
- parent( IProgressMonitor )
Finally, just because a handle exists does not mean the real resource resources exists or is working. A service may be down, or a shapefile may not be created yet.
Here is how to check on the status of a IResolve:
- IResolve.getStatus(), one of CONNECTED, NOTCONNECTED or BROKEN
Note: Methods that are blocking make use of a IProgressMonitor, and throw an IOException in the event of a problem. This allows for both feedback during the operation, and strongly indicates to calling code that blocking input/output will occur.
Let's quickly work with an example (to make this real)
Use of canResolve and resolve methods
public count shapes( File shapefile ){
CatalogPlugin catalog = CatalogPlugin.getDefault();
IServiceFactory factory = catalog.getServiceFactory();
for( IResolve resolve : factory.acquire( shapefile.toUrl() ) ){
if( resolve.canResolve( DataStore.class ) ){
DataStore shape = resolve.resolve( DataStore.class );
String typeName = shape.getTypeNames()[0];
return shape.getFeatureSource( typeName ).count();
}
}
return 0;
}
 | Comparison with IResource
The IResolve interface follows the same design as the normal Eclipse IResource class.
IResolve offers the following advantages over normal Eclipse IResource:
- IResolve explicitly represents a handle for a remote resource
- IResolve blocking behavior is explicit at the API level, anything that takes an IProgressMonitor or throws an IOException is blocking
- IResolve is available for RCP applications, normal IResource is part of the Eclipse IDE and cannot be used in a RCP application
- IResolve uses Java 5 enums, type narrowing and Templates for a simplified API
|
Extending Catalog Plugin (Advanced)
To extend catalog for additional formats you will need to make an implementation of IService, IGeoResource and a WizardPage for your new content.
- ServiceExtention: allow the catalog to work with new kinds of Services
- ICatalog: teach the CatalogPlugin about new kinds of remote catalogs
- temporaryResource: create new temporary resources
- resolvers: teach the existing IResolve Implementations (like ShpGeoResource) about your application needs
- friendly: build up assocations between services that are designed to work together
We are going to launch right into technical details here (this is the advanced section). If you require additional background information please consider the following references:
Common mistakes:
- If you are used to making your own Eclipse plugins you may accidently depend on IResource, it will not be available at runtime since it is part of the Eclipse IDE.
- 2 Eclipse House Rules: You may only depend on public API packages (example net.refractions.udig.catalog). This is less of a problem since we are able to properly restrict packages in Eclipse 3.3.
Resolution Manager
Just because the core uDig team knows how to do a few tricks with Shapefiles, and turn them into a FeatureSource does not mean you are left out of the game. You can teach the uDig catalog system new tricks, making uDig classes aware of your applications needs at runtime.

The ResolutionManager processes an extention point binding IResolve to new classes, you can use this facility to integrate your own functionality with the uDig application.
Eclipse IDE Integration
When making your own instance of IResolve you can also implement IAdaptable (we ensured that no method names would conflict). Implementing IAdaptable, and providing an adapter for IResource allows for seamless integration with the Eclipse IDE.
This is out of scope for our current development effort - however the implementation is straight forward and would allow integration of the GISPlatform with the wider Eclipse community. The Eclipse workbench already checks for the classes supporting IAdaptable, and will automatically integrate any class that responds to isAdaptable( IResource.class ).