Creating a Java ArcGIS Server Object Extension to access metadata through a mapservice

So with this cool Server Extension technology being possible with ArcGIS server java ed. 9.3.1 and me finally having time to have a play with it I decided on doing something useful; getting at the metadata of the data within a mapservice.

We have all of our data stored in SDE and most of it has a metadata document alongside in the database which can be edited and viewed using ArcCatalog or extensions such as Geosticker, there is however no standard functionality in eg. the SOAP or REST toolkits to read or query this document. We were already working around  this by using a servlet that was using some “regular” Java ADF code to retrieve this document, but this seems like an unnatural way because it would require setting up an extra DCOM connection from the servlet through the SOM to retrieve the feature class. Now we have extended the MapService to do this by adding a getMetadata(layerName .. layerID) method and associated SOAP handlers (extending REST handlers is not yet supported in the API).

First things first though, I don’t like the way the server logging works, so I’ll create an abstract class that provides a logging facility that’s similar to common Java logging. It provides a log(LoggingLevels, LoggingCodes, String) method that takes Enumeration values for level and code and a string for the message instead of numbers and a string thereby improving the readability of the code. The utility implements the IServerObjectExtension interface but is not annotated with the @ArcGISExtension because it’s abstract.

public abstract class LoggingUtil implements IServerObjectExtension, Serializable {
   private ILog2 serverLog;
   public void init(IServerObjectHelper soh) throws IOException, AutomationException {
        this.serverLog = ServerUtilities.getServerLogger();
   }
   public void shutdown() throws IOException, AutomationException {
        this.serverLog = null;
   }
   protected void log(LoggingLevels level, LoggingCodes code, String msg) {
        try {
            this.serverLog.addMessage(level.level(), code.code(), msg);
        } catch (AutomationException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

public enum LoggingLevels {
    ERROR(1), WARNING(2), NORMAL(3), DETAILED(4), DEBUG(5);
    private final int level;
    LoggingLevels(int level) {
        this.level = level;
    }
    public int level() {
        return this.level;
    }
}

LoggingCodes is very similar to LoggingLevels and it will now be clear that I’m logging a debug or an error statement:

 log(DEBUG, INIT, "Init facility."); 

and all I need to do is extend LoggingUtil.
Next up the definition of the extension:

@ArcGISExtension public interface MetadataAvailable extends InfoAvailable {
   String getMetadata(String layerName) throws AutomationException, IOException;
   String getMetadataByID(int layerId) throws AutomationException, IOException;
}

Now I wanted to have

@ArcGISExtension public interface MetadataAvailable extends InfoAvailable {
   String getMetadata(String layerName) throws AutomationException, IOException;
   String getMetadata(int layerId) throws AutomationException, IOException;
}

but there’s a problem with that (see below). The actual work is done using the following method:

 public String getMetadataByID(int layerId) throws AutomationException, IOException {
        ILayer layer = this.mapServer.getLayer("", layerId);
        FeatureLayer fLayer = (FeatureLayer) layer;
        FeatureClassName featureClassName = (FeatureClassName) fLayer.getDataSourceName();
        if (featureClassName.getMetadata() == null) {
            return "";
        }
        IXmlPropertySet2 pPropertySet = (IXmlPropertySet2) featureClassName.getMetadata();
        return pPropertySet.getXml("");
    }

This will only work for FeatureLayers, but it’s a start, there’s a handleStringRequest(String capabilities, String request) that will handle the SOAP (de)serialisation sow we can use a lightweight protocol to retrieve the metadata document from the database. A quick class diagram shows the whole picture.

Metadata class diagram

Metadata server extension class diagram

Please see the attached file for all the code.

TO DO: zip & upload and link source code

Some things I ran in to while cooking this up.

Method Overloading is broken

This must be some sort of DCOM bridg effect; a java.lang.ClassCastException is thrown when I use the following interface definition:

import com.esri.arcgis.interop.AutomationException;
import com.esri.arcgis.interop.extn.ArcGISExtension;
@ArcGISExtension public interface MetadataAvailable extends InfoAvailable {
   String getMetadataByID(int layerId) throws AutomationException, IOException;
   String getMetadata(String layerName) throws AutomationException, IOException;
   // adding this gives a classcast exception:
   String getMetadata(Integer layerId) throws AutomationException, IOException;
}

The exception is thrown when casting from IServerObjectExtensionProxy to MetadataAvailable (line 5 below), when the overloaded method String getMetadata(Integer layerId) is removed (line 6 above) everything works fine. I could live with that, but I really don’t think I should have to when I’m programming in Java I want to be able to use a basic language feature like this. (This issue has been logged under as bug NIM051760 [Java SOE(s) should support method overloading] in bugs online).

mapServer = (MapServer) serverContext.getServerObject();
// Access the soe through the IServerObjectExtensionManager
IServerObjectExtensionManager extnMgr = mapServer;
IServerObjectExtension  soe = extnMgr.findExtensionByTypeName(soeName);
MetadataAvailable t = (MetadataAvailable) soe;
String s0 = t.getMetadata(0);

Eclipse wizards don’t work in up2date versions

A minor, but disppointing issue really, but the, wizards only work with older (3.4) versions of Eclipse and not the current Galileo / 3.5 release. This apparently won’t change when SP1 for 9.3.1 is released this month but will when 9.4 comes out some time next year. So if you’re getting started with this you will probably want (need) to have a previous generation of Eclipse available.

Advertisements

4 Responses to “Creating a Java ArcGIS Server Object Extension to access metadata through a mapservice”


  1. 1 Mannus Etten Thursday 21 January 2010 at 12:49

    Interesting article. What is the role of the GPE inside the organisation and this server extension?

    • 2 Mark Prins Thursday 21 January 2010 at 13:50

      GPE is not a server extension, it is a product extension existing of a number of web applications such as the geoportal and programs such as the harvester tools. GPE will run just fine without any ArcGIS server. Using this SOE a map service will be able to provide the original metadata for the datasources directly; this can afaik not be accomplished with GPE without first creating metadata for the service and creating links to metadata for the various datasources.

  2. 3 sebastian Thursday 16 September 2010 at 20:09

    Hola, con un compañero estamos tratando de crear una geoprocessing tool in Eclipse IDE. Probamos con los eclipse desde el 3.4 al 3.6 pero no logramos que en el menu “File->new->other”, dentro de esri templates nos aparezca “ArcGis Extensions” para poder elegir Geoprocessing. Pueden Ayudarnos? Tenemos instalado el “ArcGis Engine “(Developer Kit) 9.3 “


  1. 1 Tweets that mention Creating a Java ArcGIS Server Object Extension to access metadata through a mapservice « GISpunt -- Topsy.com Trackback on Wednesday 25 November 2009 at 13:04
Comments are currently closed.



Join 58 other followers

GISpunt logo

GISpunt logo (small)

tweets


%d bloggers like this: