Implementing persistence for a custom feature renderer


Summary Understanding persistence in the ArcGIS framework helps you implement correct persistence behavior in extension classes. This topic explains persistence in ArcGIS and how to implement persistence for extension classes that extend the functionalities of the ArcGIS framework. It also describes version compatibility and how to implement version compatibility in extension classes.

In this topic


About persistence

The process where information indicates the current state of an object written to a persistent storage medium, such as a file on disk is called persistence. Persistence is used in ArcGIS to save the current state of a map document (.mxd) or a template (.mxt). The state of the map document is often altered when you interact with ArcGIS through its user interfaces (UIs), and application programming interfaces (APIs). When you close the map document, the state of the map document is terminated. The persistence model in ArcGIS allows you to preserve the state of the map document in a physical storage (.mxd or .mxt file) when the document is saved and restored as persisted, and when the document is reopened.
In ArcGIS, the state of the map document is the cumulative state of several ArcObjects. These ArcObjects currently running in a map document or template are persisted to streams in a compound file when the document is saved. In ArcMap, when Save is clicked, the ArcGIS persistence framework creates streams as required and associates them with the existing .mxd file (if the document has previously been saved), then requests the document to persist itself to these streams.
If there are changes to the normal template or map template, this process is repeated for the appropriate .mxt file. When the file reopens, the map document is re-created from the persisted state in the file. The following are the notable areas that are persisted as the state of a map document:
  • In a map collection, each map persists the ArcObjects corresponding to its layers, symbology, graphics, current extent, spatial reference, and so on. This can also include custom layers, renderers, symbols, elements, or other map items.
  • Page layout, map frames, map surrounds, and layout of items can also include custom map surrounds or frames.
  • Visible table of contents (TOC) views can also include a custom TOC view.
  • Visible toolbars, their members and position (if floating) can include standard and custom toolbars, and commands and UIControls.
  • List of styles referenced by the StyleGallery and items stored in a style by using persistence, can include a custom StyleGalleryItem or StyleGalleryClass. 

Persistence in extension classes

ArcGIS Java extensions are created using Java ArcObjects APIs to extend the functionalities of ArcGIS. For example, a custom feature renderer extension class is developed to extend the rendering capability of ArcGIS and can be applied to a layer in a map document. When this type of .mxd document is saved, the state of the custom feature renderer instance must be persisted to the map document. 
If the extension instances referenced by the map document is expected to support persistence and did not, the save will not be complete. The map document might become unusable or when reopened, the state of the map document might not be restored as expected. Hence, it is essential to implement appropriate persistence behavior for extension classes that you develop, when you extend ArcGIS.

Persistence behavior implementation

To persist the extension instances created in ArcGIS, extension classes must implement the java.io.Externalizable interface and its writeExternal() and readExternal() methods. The implementation of the writeExternal() method must persist the object state to the stream and the implementation of the readExternal() method must rehydrate the object. 
When implementing persistence behavior, an extension class can choose to persist all its properties or specific properties. Java primitive property types, Plain Old Java Objects (POJOs), or ArcObjects that extends the java.io.Externalizable class can be persisted to the stream.  
In the example of an custom feature renderer extension class(PointDispersalRenderer), it is expected to implement persistence. The following code example shows the persistence behavior implemented by the custom feature renderer (see the following information in the code example):
  • The custom feature renderer extension class implements the java.io.Externalizable interface to support persistence.
  • The dispersalRatio property of the PointDispersalRenderer is identified as its persisted property, which is of the Java double primitive type. 
  • The Externalizable.writeExternal() method implementation persists the dispersalRatio property to the stream.
  • The Externalizable.readExternal() method implementation retrieves the dispersalRatio property. When the map document opens, the custom feature renderer object is rehydrated by retrieving the stored properties and the framework renders the layer appropriately.
[Java]
@ArcGISExtension public class PointDispersalRenderer implements IFeatureRenderer,
    java.io.Externalizable{

    double dispersalRatio;

    //Write the variables.
    public void writeExternal(ObjectOutput out)throws IOException{
        //Write the dispersal ratio value to persistent storage to preserve the state.
        out.writeDouble(this.dispersalRatio);
    }

    //Read the variables. 
    public void readExternal(ObjectInput in)throws IOException,
        ClassNotFoundException{
        //Read the dispersal ratio from the persistent storage and rehydrate the object.
        this.dispersalRatio = in.readDouble();
    }
}

Version compatibility

Version compatibility, introduced with ArcGIS 9.1 onwards, allows you to save (persist) map documents to previous ArcGIS versions using "save a copy" functionality in ArcMap or MapDocument.setDocumentVersion() in Java applications. See the following illustration that shows version compatibility:
At ArcGIS 9.3, you can save to ArcGIS 8.3, ArcGIS 9, or ArcGIS 9.1. ArcGIS 9.1 map documents are compatible with ArcGIS 9; therefore, there is no option to save them to ArcGIS 9. By supporting version compatibility in extension classes that you develop, you ensure your map document is compatible with other ArcGIS versions.

Version compatibility implementation

ArcGIS extension classes that support persistence must also support version compatibility. If the extension class that you develop is not supported by previous versions of ArcGIS, implement IDocumentVersionSupportGEN and provide an alternative object for rendering the map in previous versions. 
 
The extension classes that you develop to create custom geoprocessing tools, custom feature renderers, class extensions, plug-in data sources, utility objects, and server object extensions are not supported in versions before ArcGIS 9.3.1; therefore, to ensure version compatibility, the extension classes must implement IDocumentVersionSupportGen.
 
The following shows how the IDocumentVersionSupportGen interface and its methods, isSupportedAtVersion() and convertToSupportedObject(), can support version compatibility:
  • When an  extension instance that implements IDocumentVersionSupportGen is persisted to the stream, the ArcGIS framework invokes the IDocumentVersionSupportGen.isSupportedAtVersion() method to determine the ArcGIS document versions supported by the extension.
    • If isSupportedAtVersion returns true, ArcGIS appropriately handles the persistence behavior of the extension.
    • If isSupportedAtVersion returns false, ArcGIS calls the IDocumentVersionSupportGEN.convertToSupportedObject method. The method returns an alternative object that can be persisted to the specified ArcGIS document version, which is persisted instead of the extension instance. See the following illustration that shows this scenario:

The following code example shows the implementation of isSupportedAtVersion() and convertToSupportedObject() for persisting a custom feature renderer instance supported from ArcGIS 9.3.1 onwards. If the document is saved before ArcGIS 9.3.1, an alternative standard SimpleRenderer is persisted. When the map document is opened in versions before ArcGIS 9.3.1, the map layer will be rendered by the SimpleRenderer instead of the PointDispersalRenderer.
[Java]
@ArcGISExtension 
//Notice, the PointDispersalRenderer class implements IDocumentVersionSupportGen.
public class PointDispersalRenderer implements IFeatureRenderer,
    java.io.Externalizable, IDocumentVersionSupportGEN{
    //The method returns the alternative renderer if the version is not equal to ArcGIS 9.3.
    public Object convertToSupportedObject(int arg0)throws IOException,
        AutomationException{
        SimpleRenderer simpleRend = new SimpleRenderer();
        SimpleMarkerSymbol simpleMarkerSymbol = new SimpleMarkerSymbol();
        simpleMarkerSymbol.setSize(8);
        simpleMarkerSymbol.setStyle(esriSimpleMarkerStyle.esriSMSDiamond);
        simpleRend.setSymbolByRef(simpleMarkerSymbol);
        return simpleRend;

    }

    //The method verifies the supported versions.
    public boolean isSupportedAtVersion(int docVersion)throws IOException,
        AutomationException{
        /***********
        //The esriArcGISVersion enumeration does not specify an enum value for ArcGIS 9.3.1. 
        //Therefore, the code example allows persisting custom ArcObjects to ArcGIS 9.3 documents.
        // However, when opening the map document in ArcGIS 9.3, the layer will not be rendered.  
        //Therefore, it is the developer's responsibility to ensure 
        //ArcGIS 9.3.1 is installed to open map documents saved to ArcGIS 9.3.
         ****************/
        //Support all versions above or equal to ArcGIS 9.3.
        if (docVersion >= esriArcGISVersion.esriArcGISVersion93)
            return true;
        else
        //The convertToSupportedObject() method will be invoked if isSupportedAtVersion() returns false.
            return false;
    }

Points to remember

  • Every esriArcGISVersion enum value that returns false in the isSupportedAtVersion() method, must include implementation in the convertToSupportedObject() method to return an alternative object. For example, if the isSupportedAtVersion() method returns false for esriArcGISVersion92 and esriArcGISVersion93, the corresponding alternative objects must be specified for both versions in the convertToSupportedObject() method.
  • Do not return a null reference in the convertToSupportedObject() method, as ArcGIS might attempt to apply this null reference to a property, which can corrupt the saved document
  • The esriArcGISVersion enumeration does not include a specific enum value for ArcGIS 9.3.1; therefore, it is the developer's responsibility to ensure ArcGIS 9.3.1 is installed to open map documents that persisted extension instances when saved to ArcGIS 9.3.






Development licensing Deployment licensing
Engine Developer Kit Engine Runtime
Server Server
ArcView ArcView
ArcEditor ArcEditor
ArcInfo ArcInfo