CityDoctor ADE Interface

From SIMSTADT
Jump to: navigation, search

The City Doctor ADE Service Provider Interface enables City Doctor to create, read, and write data according to an arbitrary ADE schema definition. To put it another way, this interface lets City Doctor load and write ADE-enriched CityGML files or streams. This is also true for all systems which rely on City Doctor, like SimStadt.

Contents

[edit] Quickstart for SimStadt Developers

Figure 1: The big picture.

If you want to introduce or change classes which are generated from the Energy ADE schema definition via JAXB, then you usually have to perform the following steps.

  1. Checkout or update the Energy ADE schema definition. It is stored in our SVN repository under http://localhost:1080/svn/EnergyADE/trunk/ as an eclipse project.
  2. Change energy.xsd and citydoctor-binding.xjb according to your needs.
  3. You will find an ANT build file called generate.xml in the Energy ADE project. Run it in order to generate Java classes from the schema definition.
  4. Checkout or update the Energy ADE Plugin project. It is stored under http://localhost:1080/svn/kepler/EnergyADEPlugin
  5. Copy the newly generated Energy ADE specific files over to the Energy ADE Plugin.
  6. Adjust the extension handlers and the mapping of the Energy ADE Plugin. Read the documentation in this article to learn how.
  7. Export the Energy ADE Plugin as a JAR. Make sure that you include the META-INF folder in your JAR.
  8. Deploy your JAR onto SimStadt's class path. SimStadt doesn't include the EnergyADEPlugin as a eclipse project directly. Currently, the JAR is placed in SimStadtRepository/lib. Just override it. From this point on, your changed classes of the Energy ADE Plugin are available within the SimStadt platform.
  9. Adjust all depending SimStadt classes.
  10. Adjust all test cases.
  11. Commit all changes of all projects into our SVN repository.

If you encounter a problem, please read the documentation below.

[edit] Some Facts about Application Domain Extensions

There are two ways to extend CityGML. Firstly, ADEs can introduce completly new feature types by sub-typing the abstract type core:_CityObject or one of its sub-types. Secondly, existing feature types can be extended by hooks. This can be done by substituting placeholder elements of the existing features types. In general, a placeholder looks like this ns:_GenericApplicationPropertyOf<feature> where <feature> is the name of the extended feature. For instance, the type AbstractBuilding can be extended by substition of the hook bldg:_GenericApplicationPropertyOfAbstractBuilding. Have a look at the CityGML documentation for more details on this topic.

[edit] Some Facts about the Internal Data Structure of the City Doctor

Figure 2: Part of City Doctor's internal data structure

The internal data structure of the City Doctor can represent a fixed number of CityGML features. These features are Building, BuildingPart and BoundarySurface. For each feature, City Doctor provides a separate Java class of the same name. All three features are sub-classes of the abstract class CityObject. In this article, these classes are called native classes, because they have been developed by the City Doctor team and they have to be distinguished from classes of the underlying citygml4j library.

City Doctor's internal data structure builds upon the free citygml4j library. The library contains a data structure that has been directly derived from the CityGML schema. Every feature that is defined by the CityGML schema is mapped to a corresponding Java class. The directly derived Java classes did not satisfy all requirements of the City Doctor, so that the above mentioned native classes Building, BuildingPart, and BoundarySurface are added to the internal data structure of the City Doctor. All instances of the three native classes are associated with their citygml4j counterparts. Every Building and BuildingPart points at its underlying citygml AbstractBuilding. Instances of BoundarySurface point at instances of AbstractBoundarySurface. The citygml4j library also contains helper classes which enable the programmer to parse, marshal, and unmarshal CityGML features.

Naturally, all three native Java classes Building, BuildingPart and BoundarySurface have a fixed number of members. Programmers can access all the standard CityGML attributes of the represented features, but it is not possible for the City Doctor to make unknown arbitrary application domain extensions visible and accessable by itself. As a programmer, you have to introduce new ADEs to the City Doctor.

Though all native classes of the City Doctor are fixed, all of them are extensible. If you want to make new application domain extensions visible for the City Doctor, you have to implement City Doctors Extension interface. This interface will be described in one of the next sections.

[edit] The Extension Interface

Figure 3: All flat elements of simple types should be mapped to the same Java class. Every new complex type should be mapped to it's own separate Java class.

The three supported feature types of the City Doctor are extensible through implementations of the abstract class Extension. Instances of Extension can be referenced by any CityObject, because every CityObject keeps a dictionary of extensions and provides a set of accessors to that dictionary. Implementations of the Extension interface have members which correspond to arbitrary application domain extensions.

Every implementation of Extension corresponds to at least one hook of the new ADE. It is totally up to the programmer how he wants to map the hooks to the implementations. Anyways, I suggest the following mapping rules:

  • Create one implementation of Extension for each new complex type. The name of the implementation should match the name of its corresponding complex type.
  • Create one implementation of Extension for all new elements of simple types. Summarize all these flat attributes in one class per feature type.

It is cumbersome to maintain a proper mapping between schema types and Java classes, but citygml4j comes to the rescue. It provides a parser that compiles a XML schema definition to corresponding Java classes. The parser is called ade-xjc and is available at GitHub. It compiles all the newly defined complex types of a schema to distinct Java classes. Instances of elements can be obtained by factory methods of the generated class ObjectFactory. After the code generation is finished, most of the work is done.

If you have trouble compiling your XML schema please ensure that

  • you are using the newest version of the ade-xjc parser and
  • adjusted the schema locations of existing import elements in your schema to the schema files shipped with the ade-xjc parser.
  • Sometimes there might be name clash. Often this is caused by elements with the same name. The first element name begins with a capital letter and the second element name begins with a lower case letter. Resolve this issue with a binding file or adjust the schema.
Figure 4: Usage of the ade-xjc parser.

Once the ade-xjc parser did its magic, there are still some things to do in order to implement the Extension interface. The programmer has to complete the class definition by appending implements Extension to the class definition of every generated Java class. Additionally, the methods getNamespaceURI() and getLocaleName() have to be implemented. The namespace URI of an extension is the same as of the ADE schema definition. A local name is only sensible for Java classes which have been compiled from complex XML types. The programmer should use the name of the complex type as the local name. In case of wrapper class for all the flat elements of a schema, the programmer should return an empty string as the local name.

The namespace and the local name of an extension will be combined to the qualified name of the extension. This will be done automatically by the method getQualifiedName(). The qualified name will be used as a key by the extension dictionary of the extended city object in order to identify the particular extension instance. This is imported during the instantiation, marshalling and unmarshalling of the extension instances.

[edit] The Extension Handler

The purpose of the so called extension handlers is to marshal and to unmarshal ADE-specific data. Marshalling and unmarshalling happens when a CityGML file is written or loaded through the citygml4j library. The citygml4j library performs this tasks only for standard CityGML feature types and attributes and the extension handler does it for all the remaining ADE-specific feature types and attributes. There should be only one extension handler for each particular ADE.

Figure 5: Every non-standard data item (here: generic application properties) will be encoded as a DOM tree and wrapped in an ADEComponent object. The marshallers and unmarshallers of an extension handler will traverse such DOM trees and process all the relevant and recognized tree nodes.

But how does this marshalling and unmarshalling work? Lets have a closer look to the unmarshalling process. Firstly, the citygml4j library will instantiate all the standard CityGML features and map them to their corresponding Java counterparts. Secondly, the citygml4j library will parse every non-standard data item like ADE-specific features and attributes as instances of ADEComponent. ADEComponents are wrappers for DOM-trees. Every DOM-tree represents the ADE-XML of the input file structure almost literally, because citygml4j does not know how to map these extra data. You can see the instances of ADEComponents as the conterparts of Extension instances. Figure 5 shows how citygml4j handles such situations. This is where our extension handlers with their unmarshallers come into play. Our unmarshaller methods should traverse the list of of ADEComponent instances of a given citygml4j feature and search for data that can be read and mapped. The marshalling process works the other way around. The extension handler's marshaller methods will traverse the City Doctor features and search for Extension instances which can be read and mapped to ADEComponents.

The abstract class ExtensionHandler declares several methods which have to be implemented. Again, the namespace of the ADE schema has to be used to implement handlesNamespaceURI(). It tells any caller the namespace of the ADE that can be handled. The method getADEPackage() is used by the marshaller methods to find the implemented extension classes. It returns the package name which holds all of the extension implementations.

Depending on the extended CityGML features, the programmer has to implement at lease one marshaller and unmarshaller method. A marshaller method takes a City Doctor feature as an argument and returns a list of ADEComponent instances.

  • public abstract ArrayList<ADEComponent> marshal(Building building)
  • public abstract ArrayList<ADEComponent> marshal(BuildingPart buildingPart)
  • public abstract ArrayList<ADEComponent> marshal(BoundarySurface boundarySurface)

Unmarshaller methods take a citygml4j feature instance, loop over all ADEComponent instances associated with that feature, and return a list of Extension instances:

  • public abstract ArrayList<Extension> unmarshal(Building building);
  • public abstract ArrayList<Extension> unmarshal(BuildingPart bulidingPart);
  • public abstract ArrayList<Extension> unmarshal(RoofSurface boundarySurface);
  • public abstract ArrayList<Extension> unmarshal(WallSurface boundarySurface);
  • public abstract ArrayList<Extension> unmarshal(GroundSurface boundarySurface);
  • public abstract ArrayList<Extension> unmarshal(ClosureSurface boundarySurface);
  • public abstract ArrayList<Extension> unmarshal(OuterFloorSurface boundarySurface);
  • public abstract ArrayList<Extension> unmarshal(OuterCeilingSurface boundarySurface);

You will notice that there are less marshallers than unmarshallers. This is because City Doctor doesn't distinguish between the different boundary surface types on class level like CityGML. City Doctor distinguishes the different types of boundary surfaces in its BoundarySurface class by associating a certain enumeration.

[edit] The Extension Registry

The extension registry is a static Java class, where extension handlers can be registered at runtime. Registering an extension handler means to enable City Doctor to read and write a particular ADE. You can register as many extension handlers as you want. The extension registry class maintains a list of the registered extension handlers. Extension handlers can also be unregistered from the extension registry at runtime.

The extension registry will be called when a CityGML file is loaded and saved by City Doctor. If City Doctors loads a file, its citygml4j backed parser only unmarshalls the standard CityGML parts of the file and instantiates the citygml4j features. These citygml4j features will then be wrapped by instances of the native City Doctor features. As soon as this standard loading procedure is finished, City Doctor calls the extension registrie's unmarshal() methods with the loaded citygml4j feature instances. Afterwards, the extension registry delegates the loaded features to the actual extension handlers with their unmarshallers. The unmarshaller then read the ADE-specific data from the citygml4j features and instantiate corresponding Extension instances. The corresponding Extension instances will be returned to the extension registry and the parser which will add the extensions to the loaded native City Doctor features.

[edit] City Doctor's Service Provider Interface

Figure 6: The service provider interface of the City Doctor.
Figure 7: Sequence of the unmarshalling of two different extensions which have been attached to a single building. The parser instantiates the citygml4j city model and passes it to the building walker. Basically, the building walker visits all building instances of the loaded city model (simplified in this diagram) and passes each building to the extension registry. The extension registry will then trigger all registered extension handlers to search and unmarshal relevant extensions.

Anybody can introduce new ADEs and extensions to the City Doctor. The code base of City Doctor's data structure isn't supposed to change often. However, in order to introduce new ADEs you have to implement the two abstract classes Extension and ExtensionHandler. So, how could you extend City Doctor? This can be done by implementing City Doctor's Service Provider Interface (SPI).

A SPI is an interface or abstract class whose implementations are loaded and instantiated at runtime. It's a well documented standard mechanism of the Java platform. The implementation of a SPI can be seen as a plug-in. In case of the City Doctor, the abstract class ExtensionHandler is the SPI. The City Doctor plug-in loading mechanism is straight forward and easy to understand. It has been implemented in the Java class CityGMLParserImpl.

Implement your concrete ExtensionHandler and your Extensions, wrap them in a JAR and put the JAR onto the class path of City Doctor or into one of your Java installation's extension folders. City Doctor will look into your JAR, instantiate the containing plugins and register all found extensions at the extensions registry everytime when you open and load a CityGML file. Once all found extension handlers are registered in the extension registry, the CityGML parser will pass all loaded buildings, building parts and boundary surfaces to the extension registry. The extension registry in turn delegates the loaded feature objects to the actual extension handlers. The extensions handler will then load extensions of the features object if extensions exist.

[edit] Things which cannot be done

Currently, the City Doctor ADE interface cannot be used to introduce new algorithms to the City Doctor. If you want to perfom some action on the new data structures which you just defined, then only a City Doctor developer can help you. A future version of the City Doctor ADE interface could enable third parties to provide new algorithms (like tests) by adding new method definitions to the service provider interface ExtensionHandler.

[edit] Tutorial: Writing a City Doctor Plug-in

[edit] What is a City Doctor plug-in and what does it do?

A plug-in enables City Doctor to load and store attributes which are defined by an application domain extension (ADE). ADEs extend existing features of the CityGML standard or introduce new ones and can be written by anybody. City Doctor itself is unable to load and store ADE-specific data items, because its internal data structure cannot map arbitrary feature types and new attributes. A plug-in provides additional and suitable Java classes which represtent the additional ADE-specific data structures.

Every City Doctor plug-in is also the implementation of City Doctor's Service Provider Interface (SPI). This means that you have to implement the abstract class called ExtensionHandler. Furthermore, you have to provide implementations of the abstract class Extension in order to make your ADE visible to City Doctor.

[edit] Supported CityGML features

City Doctor works on the CityGML features AbstractBuilding, Building, BuildingPart, BoundarySurface and its subtypes. Hence, ADEs of these feature types can be made available within the City Doctor application. Since AbstractBuilding is a sub-type of Site and CityObject, all extensions of these base types will be visible to City Doctor as well. The same is true for the base types of BoundarySurface. Currently, it is impossible to make newly introduced feature types available which are unrelated to any of the supported feature types. For instance, a new feature any:Fortification that directly extends gml:AbstractFeature and isn’t associated with any of the supported features cannot be made available through a plug-in.

[edit] How to write and deploy a plug-in?

The next few sections and paragraphs will show you how to build a City Doctor plug-in step-by-step.

  1. We will start with the definition of a simple ADE. The result will be your ADE-XML schema definition.
  2. All new types and attributes of your schema have to be mapped to corresponding Java classes. The mapping materializes as implementations of the abstract class Extension. This step is half-automated and includes some fancy Java code generation.
  3. You have to describe how to unmarshal your ADE elements to the corresponding Java objects.
  4. You have to describe how to marshal your Java objects to the corresponding ADE elements.
  5. Package your code in a JAR. The JAR will be your actual plug-in.
  6. Deploy your plug-in.

[edit] Your Schema (1)

Lets assume you’ve written an ADE. Your ADE can be used to store radiation exposures of sites and buildings that are located in an area around a collapsed nuclear site like in Fukushima. Additionally, your ADE enables you to store the distance of every neighboring site to the collapsed nuclear site and you can describe a teardown and disposal plan along with the costs for each building. Lets call the XML schema file exposure-ade.xsd and it could look like this:

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://anydomain.de/ade/exposure" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:core="http://www.opengis.net/citygml/1.0"
    targetNamespace="http://anydomain.de/ade/exposure" 
    elementFormDefault="qualified" 
    attributeFormDefault="unqualified" 
    version="0.3">
  <xsd:import namespace="http://www.opengis.net/citygml/1.0" schemaLocation="./schemas/CityGML/1.0.0/cityGMLBase.xsd" />
  <xsd:element name="radiationExposure" type="xsd:double" substitutionGroup="core:_GenericApplicationPropertyOfSite" />
  <xsd:element name="distanceToSiteOfAccident" type="xsd:int" substitutionGroup="core:_GenericApplicationPropertyOfSite" />
  <xsd:element name="teardownAndDisposalPlan" type="TeardownAndDisposalPlan" substitutionGroup="core:_GenericApplicationPropertyOfSite" />
  <xsd:complexType name="TeardownAndDisposalPlan">
    <xsd:sequence minOccurs="0">
      <xsd:element name="planDescription" type="xsd:string" minOccurs="0" maxOccurs="1" />
      <xsd:element name="costs" type="xsd:double" minOccurs="0" maxOccurs="1" />
    </xsd:sequence>
  </xsd:complexType>
</xsd:schema>

The schema consists of some new elements of the type Site. Site is a base-type of AbstractBuilding. This ADE lets you store data about the exposure of the site and the radiation exposure and the distance to the collapsed structure as flat extensions of the type Site. The extensions are called flat, because they are of simple types. If there is a plan to tear down and dispose the site, you can store a description and the costs of such a plan. For this reason the new complex type TeardownAndDisposalPlan has been introduced. It is associated with the type Site by a new element. The complex type itself consists of the two flat elements planDescription and costs. This Exposure ADE should be visible to City Doctor when this tutorial is finished.

[edit] Understand Your Mapping (2a)

Figure 8: Best mapping strategy for your ADE schema

Now with our schema definition at hand, we want to build Java classes which represent our new attributes and types within City Doctor. The relation between the new XML elements and the corresponding Java classes is called mapping. This section teaches you the theory behind the mapping and in section (2b) we will build the actual mapping.

There are many ways to map ADEs to Java classes and it is up to you how you do it, but I strongly recommend the following mapping strategy:

  • Create one implementation of the abstract class Extension for each new complex type. The name of the implementation should match the name of its corresponding complex type.
  • Create one implementation of Extension for all new elements of simple types. Summarize all these flat attributes in one class per extended feature type. You can name it after the extended feature type like <Feature name>Extension. For instance, BuildingExtension or BoundarySurfaceExtension.

In case of your Exposure ADE, by following the presented mapping strategy you will end up with two new implementations of the abstract class Extension. The first implementation summarizes the two flat extensions radiationExposure (Double) and distanceToSiteOfAccident (Integer) of Site. This implementation will be called SiteExtension. The second implementation represents the complex type TeardownAndDisposalPlan and will have two members planDescription (String) and costs (Double). It will be called TeardownAndDisposalPlan.

[edit] Realize Your Mapping (2b)

Ok, let's build the Java classes for your ADE schema. Fortunately, most of the work will be done for you by a neat little piece of software. It is called ade-xjc and it is a parser. The ade-xjc parser is part of the citygml4j distribution and generates Java classes from arbitrary ADE schema definition files. The generated Java classes can be marshalled to XML and XML can be unmarshalled to the generated Java classes with the help of the citygml4j library.

ade-xjc itself is a Java program and a console application. Search it at Github or download a (old?) version here: File:Ade-xjc.zip. The software comes with a folder called schemas which contains all the GML and CityGML schema definitions needed to generate your code.

Now we will generate some code. Save the application ade-xjc.jar along with its schema folder and your exposure-ade.xsd in a (temporary) folder. Then fire up your console and enter

java -jar ade-xjc.jar -package exposure.ade -output src exposure-ade.xsd

This will generate three Java files ObjectFactory.java, package-info.java and TeardownAndDisposalPlan.java in the src destination folder. TeardownAndDisposalPlan.java is nearly your wanted representation of the new ADE type with the same name. There are only few additions necessary.

Open TeardownAndDisposalPlan.java and append "extends Extension" to the class definition. This forces you to implement the two abstract methods getNamespaceURI() and getLocalName(). The method getNamespaceURI() returns the namespace of your ADE which is http://anydomain.de/ade/exposure (). The method getLocalName() should return the name of the XML element which accociates the extended feature type Site with your new entity and that is "teardownAndDisposalPlan". Now, the class should look like this:

package exposure.ade;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;
import de.hft.stuttgart.citydoctor.datastructure.Extension;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "TeardownAndDisposalPlan", propOrder = {
    "planDescription",
    "costs"
})
public class TeardownAndDisposalPlan extends Extension {

    protected String planDescription;
    protected Double costs;

    public String getPlanDescription() {
        return planDescription;
    }

    public void setPlanDescription(String value) {
        this.planDescription = value;
    }

    public boolean isSetPlanDescription() {
        return (this.planDescription!= null);
    }

    public Double getCosts() {
        return costs;
    }

    public void setCosts(Double value) {
        this.costs = value;
    }

    public boolean isSetCosts() {
        return (this.costs!= null);
    }
	
    @Override
    public String getNamespaceURI() {
        return "http://anydomain.de/ade/exposure";
    }
	
    @Override
    public String getLocalName() {
        return "teardownAndDisposalPlan";
    }
	
}

Ok, what is missing? Right, our SiteExtension class for the flat attributes radiationExposure and distanceToSiteOfAccident is missing. The xjc-ade parser generates classes only for complex types of a XML schema definition. So we start writing our SiteExtension class like this:

package exposure.ade;

import de.hft.stuttgart.citydoctor.datastructure.Extension;

public class SiteExtension extends Extension {

    @Override
    public String getNamespaceURI() {
        return "http://anydomain.de/ade/exposure";
    }

    @Override
    public String getLocalName() {
        return "";
    }

}

We implemented the abstract class Extension the same way as we did before with TeardownAndDisposalPlan, but still something is missing. In case of TeardownAndDisposalPlan class the ade-xjc parser generated all needed class members for us. Now we have to do it on our own. We add ...

private Double radiationExposure;
private Integer distanceToSiteOfAccident;

public Double getRadiationExposure() {
    return radiationExposure;
}

public void setRadiationExposure(Double radiationExposure) {
    this.radiationExposure = radiationExposure;
}

public Integer getDistanceToSiteOfAccident() {
    return distanceToSiteOfAccident;
}

public void setDistanceToSiteOfAccident(Integer distanceToSiteOfAccident) {
    this.distanceToSiteOfAccident = distanceToSiteOfAccident;
}

We don't need to add any XML binding annotations to SiteExtension or its members, because we cannot map the class directly to any XML element. This will be done dynamically by our marshallers and unmarshallers, which we will implement next.

[edit] Unmarshal XML elements to Java objects (3)

In our case, unmarshalling is the process of deserializing XML to Java objects. It happens when we load and parse a CityGML file with the help of the citygml4j library. All the specified CityGML core elements can be unmarshalled by citygml4j, but citygml4j needs help to unmarshal our new and unknown ADE elements properly. This is where our ExtensionHandler comes into play.

ExtensionHandler is an abstract class which declares unmarshaller and marshaller methods. Let's have a look at the declared unmarshallers first. Unmarshallers take citygml4j buildings, building parts, roof surfaces, wall surfaces, ground surfaces, closure surfaces and outer floor surfaces as aruguments. These are all supported features of the City Doctor. Every unmarshaller will return a list of extensions that have been found for the given feature instance.

public abstract ArrayList<Extension> unmarshal(Building building);
public abstract ArrayList<Extension> unmarshal(BuildingPart bulidingPart);
public abstract ArrayList<Extension> unmarshal(RoofSurface boundarySurface);
public abstract ArrayList<Extension> unmarshal(WallSurface boundarySurface);
public abstract ArrayList<Extension> unmarshal(GroundSurface boundarySurface);
public abstract ArrayList<Extension> unmarshal(ClosureSurface boundarySurface);
public abstract ArrayList<Extension> unmarshal(OuterFloorSurface boundarySurface); 

Implemented unmarshallers are supposed to introspect the passed feature instance and search for ADE extensions. In order to do this, every unmarshaller has to iterate over the ADE extensions associated with the passed feature. Every citygml4j feature instance maintains a list of ADE extensions wrapped in ADEComponents. ADEComponent is the citygml4j conterpart of City Doctor's Extension, but there are several differences between those two classes, which will not be described here. Every ADEComponent can tell the XML schema namespace of its wrapped DOM element. This enables the unmarshaller to ckeck if a particular ADEComponent contains a relevant extension of the specific ADE which the unmarshaller is supposed to unmarshal. It can check the namespace of a ADEComponent with adeComponent.getNamespaceURI().

Let's write our own ExtensionHandler and its unmarshaller for citygml4j buildings. Start with a new class that extends ExtensionHandler. It should reside in the same package extension.ade as your implementations of Extension. You should get something like this ...

package exposure.ade;

import java.util.ArrayList;

import javax.xml.bind.JAXBException;

import org.xml.sax.SAXException;

import de.hft.stuttgart.citydoctor.datastructure.BoundarySurface;
import de.hft.stuttgart.citydoctor.datastructure.Extension;
import de.hft.stuttgart.citydoctor.mapper.ExtensionHandler;
import org.citygml4j.model.citygml.ade.ADEComponent;
import org.citygml4j.model.citygml.building.Building;
import org.citygml4j.model.citygml.building.BuildingPart;
import org.citygml4j.model.citygml.building.ClosureSurface;
import org.citygml4j.model.citygml.building.GroundSurface;
import org.citygml4j.model.citygml.building.OuterCeilingSurface;
import org.citygml4j.model.citygml.building.OuterFloorSurface;
import org.citygml4j.model.citygml.building.RoofSurface;
import org.citygml4j.model.citygml.building.WallSurface;

public class ExposureADEHandler extends ExtensionHandler {

    @Override
    public String handlesNamespaceURI() {
        return "http://anydomain.de/ade/exposure";
    }

    @Override
    public String getADEPackage() {
        return "exposure.ade";
    }

    // ... list of marshallers ...

    @Override
    public ArrayList<Extension> unmarshal(Building building)
            throws JAXBException, SAXException {
        return null;
    }

    @Override
    public ArrayList<Extension> unmarshal(BuildingPart bulidingPart)
            throws JAXBException, SAXException {
        return null;
    }

    // ... list of unmarshallers ...

}

ExposureADEHandler should be the name of your ExtensionHandler. Like the Extensions, it has to tell the system, what XML schema namespace can be handled by it. The method getADEPackage() returns the name of your package. This is needed by the citygml4j library.

Since your Exposure ADE extends the CityGML site feature, only buildings and buildings parts are affected by this extension. This is the reason why we only have to implement the two unmarshallers listed above. Let's go on with the building unmarshaller. As described above, we will introspect the given building feature as follows ...

@Override
public ArrayList<Extension> unmarshal(Building building) throws JAXBException, SAXException {
    ArrayList<Extension> extensionList = new ArrayList<>();
    List<ADEComponent> adeComponentList = building.getGenericApplicationPropertyOfSite();
    for (ADEComponent adeComponent : adeComponentList) {
        if (adeComponent.getNamespaceURI().equals(handlesNamespaceURI())) {
            // TODO
        }
    }
    return extensionList;
}

So far, so good. We found the ADE extensions, but how do we proceed? Since we defined more than one complex type or attribute in the new Exposure ADE, there will be more than one ADEComponent that matches the filter condition above. Therefore, we have to discriminate the ADEComponents further, by testing the local name it with the method adeComponent.getLocalName(). Another thing to grasp is that you have to use a so called JAXBUnmarshaller to unmarshal the DOM element of the ADEComponent to a JAXBElement. ExtensionHandler offers a singelton instance of such a JAXBUnmarshaller with static method getJAXBUnmarshaller(). Once you know the local name of the current ADEComponent, you can cast the value of the JAXBElement to the correct target type. Eventually, you will end up with the following unmarshaller for buildings ...

@Override
public ArrayList<Extension> unmarshal(Building building)
        throws JAXBException, SAXException {
    HashSet<Extension> extensionSet = new HashSet<>();
    List<ADEComponent> adeComponentList =
    building.getGenericApplicationPropertyOfSite();
    SiteExtension siteExtension = new SiteExtension();
    for (ADEComponent adeComponent : adeComponentList) {
        if (adeComponent.getNamespaceURI().equals(handlesNamespaceURI())) {
            JAXBElement<?> element =
                    (JAXBElement<?>) getJAXBUnmarshaller().unmarshal(adeComponent.getContent());
	    if (adeComponent.getLocalName().equals("teardownAndDisposalPlan")) {
                extensionSet.add((TeardownAndDisposalPlan) element.getValue());
            } else if (adeComponent.getLocalName().equals("radiationExposure")) {
                siteExtension.setRadiationExposure((Double) element.getValue());
                extensionSet.add(siteExtension);
            } else if (adeComponent.getLocalName().equals("distanceToSiteOfAccident")) {
                siteExtension.setDistanceToSiteOfAccident((Integer) element.getValue());
                extensionSet.add(siteExtension);
            }
        }
    }
    ArrayList<Extension> extensionList = new ArrayList<Extension>(extensionSet);
    return extensionList;
}

We wrote the unmarshaller for citygml4j buildings. Now we also have to consider building parts, because building parts are subtypes of the abstract and extended type Site, too. Fortunately, we can reuse most of our code, do a little refactoring and will end up with somthing like ...

@Override
public ArrayList<Extension> unmarshal(Building building)
        throws JAXBException, SAXException {
    return unmarshalSite(building.getGenericApplicationPropertyOfSite());
}

@Override
public ArrayList<Extension> unmarshal(BuildingPart buildingPart)
        throws JAXBException, SAXException {
    return unmarshalSite(buildingPart.getGenericApplicationPropertyOfSite());
}
	
private ArrayList<Extension> unmarshalSite(List<ADEComponent> adeComponentList)
        throws JAXBException {
    HashSet<Extension> extensionSet = new HashSet<>();
    SiteExtension siteExtension = new SiteExtension();
    for (ADEComponent adeComponent : adeComponentList) {
        if (adeComponent.getNamespaceURI().equals(handlesNamespaceURI())) {
            JAXBElement<?> element = (JAXBElement<?>) getJAXBUnmarshaller().unmarshal(adeComponent.getContent());
            if (adeComponent.getLocalName().equals("teardownAndDisposalPlan")) {
                extensionSet.add((TeardownAndDisposalPlan) element.getValue());
            } else if (adeComponent.getLocalName().equals("radiationExposure")) {
                siteExtension.setRadiationExposure((Double) element.getValue());
                extensionSet.add(siteExtension);
            } else if (adeComponent.getLocalName().equals("distanceToSiteOfAccident")) {
                siteExtension.setDistanceToSiteOfAccident((Integer) element.getValue());
                extensionSet.add(siteExtension);
            }
        }
    }
    ArrayList<Extension> extensionList = new ArrayList<Extension>(extensionSet);
    return extensionList;
}

Your unmarshallers are finished. Take a break. Afterwards, we will write our marshaller methods.

[edit] Marshal Java objects to XML elements (4)

Marshallers do the exact opposite of unmarshallers. They take City Doctor feature instances, introspect them, search for extensions and marshal all found extensions to ADEComponents. These are the declared marshallers:

public abstract ArrayList<ADEComponent> marshal(Building building);
public abstract ArrayList<ADEComponent> marshal(BuildingPart buildingPart);
public abstract ArrayList<ADEComponent> marshal(BoundarySurface boundarySurface);

You will notice that there are less marshallers than unmarshallers. This is because City Doctor doesn't distinguish between the different boundary surface types on class level like CityGML. City Doctor distinguishes the different types of boundary surfaces in its BoundarySurface class by associating a certain enumeration.

Let's have a look at a fully-fledged marshaller method ...

@Override
public ArrayList<ADEComponent> marshal(de.hft.stuttgart.citydoctor.datastructure.Building building)
        throws JAXBException, SAXException {
    ArrayList<ADEComponent> adeComponentList = new ArrayList<ADEComponent>();
    ArrayList<Extension> extensionList = building.getExtensions(handlesNamespaceURI());
    for (Extension extension : extensionList) {
        ObjectFactory objectFactory = new ObjectFactory();
        if (extension.getLocalName().equals("teardownAndDisposalPlan")) {
            // Process the teardown and disposal plan
            TeardownAndDisposalPlan teardownAndDisposalPlan = (TeardownAndDisposalPlan) extension;
            JAXBElement<TeardownAndDisposalPlan> jaxbElement =
                    objectFactory.createTeardownAndDisposalPlan(teardownAndDisposalPlan);
            Element domElement = getJAXBMarshaller().marshalDOMElement(jaxbElement, getJAXBContext());
            adeComponentList.add(new ADEComponent(domElement));
        } else if (extension.getLocalName().equals("")) {
            SiteExtension siteExtension = (SiteExtension) extension;
				
            // Process the radiation exposure
            JAXBElement<Double> reJAXBElement =
                    objectFactory.createRadiationExposure(siteExtension.getRadiationExposure());
            Element reDOMElement = getJAXBMarshaller().marshalDOMElement(reJAXBElement, getJAXBContext());
            adeComponentList.add(new ADEComponent(reDOMElement));
			
            // Process the distance to the site of accident
            JAXBElement<Integer> dJAXBElement =
                    objectFactory.createDistanceToSiteOfAccident(siteExtension.getDistanceToSiteOfAccident());
            Element dDOMElement = getJAXBMarshaller().marshalDOMElement(dJAXBElement, getJAXBContext());
            adeComponentList.add(new ADEComponent(dDOMElement));
        }
    }
    return adeComponentList;
}

Firstly, you iterate over all the extensions of the given feature. Then, query for the local name of each extension. If the local name is recognized as teardownAndDisposalPlan you will create a fresh JAXBElement and wrap the TeardownAndDisposalPlan. Afterwards, the JAXBMarshaller will be used to actually marshal the data to a DOM element. This element will then be wrapped inside a new ADEComponent instance.

This procedure differs slightly when it comes to the flat attributes radiationExposure and distanceToSiteOfAccident. SiteExtension is only a wrapper. This is the reason why it has no local name (empty string). Now you have to get the radiation exposure and the distance to the site of accident from the wrapper and marshal it individually. That's it.

Again, you have to consider the building parts. After some refactoring your code might look like this ...

@Override
public ArrayList<ADEComponent> marshal(de.hft.stuttgart.citydoctor.datastructure.Building building)
        throws JAXBException, SAXException {
    return marshalExtension(building.getExtensions(handlesNamespaceURI()));
}

@Override
public ArrayList<ADEComponent> marshal(de.hft.stuttgart.citydoctor.datastructure.BuildingPart buildingPart)
        throws JAXBException, SAXException {
    return marshalExtension(buildingPart.getExtensions(handlesNamespaceURI()));
}
	
private ArrayList<ADEComponent> marshalExtension(List<Extension> extensionList) throws JAXBException {
    ArrayList<ADEComponent> adeComponentList = new ArrayList<ADEComponent>();
    for (Extension extension : extensionList) {
        ObjectFactory objectFactory = new ObjectFactory();
        if (extension.getLocalName().equals("teardownAndDisposalPlan")) {
            // Process the teardown and disposal plan
            TeardownAndDisposalPlan teardownAndDisposalPlan = (TeardownAndDisposalPlan) extension;
            JAXBElement<TeardownAndDisposalPlan> jaxbElement =
                    objectFactory.createTeardownAndDisposalPlan(teardownAndDisposalPlan);
            Element domElement = getJAXBMarshaller().marshalDOMElement(jaxbElement, getJAXBContext());
            adeComponentList.add(new ADEComponent(domElement));
        } else if (extension.getLocalName().equals("")) {
            SiteExtension siteExtension = (SiteExtension) extension;
				
            // Process the radiation exposure
            JAXBElement<Double> reJAXBElement =
            objectFactory.createRadiationExposure(siteExtension.getRadiationExposure());
            Element reDOMElement = getJAXBMarshaller().marshalDOMElement(reJAXBElement, getJAXBContext());
            adeComponentList.add(new ADEComponent(reDOMElement));
			
            // Process the distance to the site of accident
            JAXBElement<Integer> dJAXBElement =
            objectFactory.createDistanceToSiteOfAccident(siteExtension.getDistanceToSiteOfAccident());
            Element dDOMElement = getJAXBMarshaller().marshalDOMElement(dJAXBElement, getJAXBContext());
            adeComponentList.add(new ADEComponent(dDOMElement));
        }
    }
    return adeComponentList;
}

[edit] Packaging (5)

Very good! You are almost through! All the hard work is done. Now you can package your plug-in as a JAR. Afterwards, that JAR will be deployed to the City Doctor application instance. But there are some important things to do, first.

City Doctor will look into your plug-in JAR and will search for implementations of its service provider interface ExtensionHandler. It will only find your implementation, if you add a certian file into the META-INF folder of your JAR. So go ahead and create a file named after the qualified class name of the service provider interface, which is de.hft.stuttgart.citydoctor.mapper.ExtensionHandler. This file should contain only one line and that is the qualified class name of your exposure.ade.ExposureADEHandler. Put the new file in the folder <your application> -> META-INF -> services. Your project structure should look like this ...

project
|-- META-INF
|   |-- services
|       |-- de.hft.stuttgart.citydoctor.mapper.ExtensionHandler
|--src
   |-- exposure
       |-- ade
           |-- ExposureADEHandler.java
           |-- ObjectFactory.java
           |-- package-info.java
           |-- SiteExtension.java
           |-- TeardownAndDisposalPlan.java

Now, build a JAR out of your project.

[edit] Deployment (6)

Deployment is easy. Put your JAR onto City Doctor's class path or in one of Java's extension folders. City Doctor will look into your JAR every time it attempts to load a CityGML file. Now the City Doctor is able to read your ADE.

Unfortunately, you cannot verify visually, that your ADE is actually loaded from a file, but as a City Doctor developer you can set a breakpoint and look into the loaded features. Every feature has an extension dictionary, which should contain your ADE. This is one way to verify if your plug-in works. An alternative way to test the plug-in could be to let your (un)marshallers or extension constructors print something to standard out.

What now? How to improve this plug-in mechanism? There is no standard way how to introduce new algorithms to the City Doctor that could work on your ADE. Currently, you have to be a City Doctor developer to acutally use your ADE. Find a concept that lets you introduce new algorithms.

Find the fully implemented plug-in for this tutorial here: File:Plugin-Tutorial.zip. The Java sources are included in the containing JAR file.

[edit] JAXB Bindings

Sometimes it can be useful to use existing Java classes for certian XML types rather than to generate new classes. If you want to use an existing Java class for a XML type while generating parts of your plug-in with the help of the ade-xjc parser just call it this way ...

java -jar ade-xjc.jar -package exposure.ade -binding binding.xjb -output src exposure-ade.xsd

Here, the binding file tells the parser to map the Java class de.hft.stuttgart.citydoctor.datastructure.Geometry.LOD to the XML tag LevelOfDetail. Here is an example of such a binding file ...

<jaxb:bindings
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" 
        version="2.1">
    <jaxb:bindings schemaLocation="energy.xsd">
        <jaxb:bindings node="//xsd:simpleType[@name='LevelOfDetail']">
            <jaxb:typesafeEnumClass ref="de.hft.stuttgart.citydoctor.datastructure.Geometry.LOD" />
        </jaxb:bindings>
    </jaxb:bindings>
</jaxb:bindings>
If you want to reuse a class instead of an enumeration type use ...
<jaxb:class ref="eu.simstadt.ade.energy.Fuel" />

Sometimes you may want the ade-xjc parser to use generate plural method names. The following article dwells on this topic ... http://stackoverflow.com/questions/4502229/how-do-you-customize-how-jaxb-generates-plural-method-names

In essence, this is what the article tells you to do, if you want the parser to use plural ...

<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        version="2.0">
    <jaxb:bindings schemaLocation="energy.xsd">
        <jaxb:bindings node="//xsd:complexType[@name='EndUse']//xsd:element[@name='energyGenerationSystem']">
            <jaxb:property name="energyGenerationSystems"/>
        </jaxb:bindings>
    </jaxb:bindings>
</jaxb:bindings>
Personal tools
Namespaces

Variants
Actions
Navigation
Toolbox