Creating a custom function tool class


Summary
This topic is for developers who extend the ArcGIS geoprocessing framework by building custom geoprocessing function tools. The three essential tasks in creating a custom geoprocessing function tool are creating a custom function factory Java class, creating a custom function tool Java class, and deploying the Java classes to ArcGIS. This topic describes how to create a custom function tool class by extending the BaseGeoprocessingTool class.

In this topic


About creating a custom function tool class

A function tool defines the input and output parameters of the tool and the tool's geographic information system (GIS) operation. To create a custom function tool, you need to create a Java class that extends the BaseGeoprocessingTool abstract class and override its methods to suit your custom function tool. These steps to override the  are explained in the following subsections.

Define tool, display, and function names

To define the tool name of your custom tool, you need to override the getName() method. The tool name appears when executing the tool at the command line and in scripting. The name must be unique to each toolbox and cannot contain spaces. 
You can also define a user-friendly display name to identify the custom tool in ArcToolbox by overriding the getDisplayName() method. The display name can also be localized.
You also need to override the getFullName() method to specify the full name of the tool. Unlike the tool name and display name, the full name of the tool is not a string variable; it is a FunctionName object. The getFullName() method must return a FunctionName object created by its custom function factory. A FunctionName object is a utility object created by the tool's function factory to manage the tool. The properties of a FunctionName object include the tool's name, its description, and a reference to the function factory.
For more information about the FunctionName object, see Creating a custom function factory class.  
The following code snippet shows how to implement the methods described here:
[Java]
class GPCalculateArea extends BaseGeoprocessingTool{

    private String toolName = "JavaCalculateArea";
    private String displayName = "Java Calculate Area";

    /**
     * This is the name of the function tool. 
     * The tool name appears when executing the tool at the command line and in scripting. 
     * The tool name should be unique to each toolbox and must not contain spaces.
     */
    public String getName()throws IOException, AutomationException{

        return toolName;
    }
    /**
     * This is the display name of the function tool. 
     * The user interface uses this property to display the name of the tool in 
     * ArcToolbox. The display name is a user-friendly description of the function tool. 
     * The display name can be localized. 
     */
    public String getDisplayName()throws IOException, AutomationException{
        return displayName;
    }
    /**
     * This is the FunctionName object of the geoprocessing function tool. 
     * The FunctionName object is created and returned by the function factory. A function factory must 
     * be created before implementing this method.
     */
    public IName getFullName()throws IOException, AutomationException{

        return (IName)new CustomFunctionFactory().getFunctionName(toolName);
    }

    //Implement other methods.
}
Create the function factory class before you create the function tool class.

Define parameters

Tool parameters are the data on which the tool operates during its execution. A tool parameter can be an input or output parameter. An input parameter is the data on which the tool is executed and an output parameter stores the result from the tool's execution. There can be any number of input and output parameters for a tool. However, a function tool must define at least one input and one output parameter.
 
Custom tool parameters are provided to the geoprocessing framework by the getParameterInfo() method. The getParameterInfo() method returns an array of parameters for the tool. Each tool parameter in the parameter array is represented by a GPParameter object. The state of the tool parameters is defined by the properties of the GPParameter object. The following illustration shows part of the Add Field tool dialog box and how a tool's dialog is created using an array of GPParameter objects:
 
 
 
To define the parameter of your custom tool, override the getParameterInfo() method. The method implementation must create a GPParameter object for each input as well as output parameters required for the tool. The initial state of the GPParameter object's properties must also be set. Essential properties that must be set initially are described in the following table:
Property
Method
Description
Notes
Name
The name of the parameter, for example, in_featureclass.
A name must not contain spaces and must be unique within a function. A parameter name can be hard-coded within the function since it is never changed once the function is distributed to the user. You can reference parameters by name in the code. For this reason, do not put the name in a resource file (as is common with DisplayName) since it may be inadvertently localized, which could break your code. The rules for naming parameters are as follows:
  • An input parameter starts with in_, followed by a reference to its data type (for example, in_features or in_table).
  • An output parameter starts with out_, followed by a reference to its data type (for example, out_feature_class or out_view).
DisplayName
The geoprocessing UI uses the display name to display the parameter name in the tool dialog box, for example, Input Features.
This can be localized as needed.
Direction
An enumeration that distinguishes between the input and output parameters. The enumerated values are esriGPParameterDirectionInput (for the input parameter) and esriGPParameterDirectionOutput (for the output parameter).
A geoprocessing tool must have at least one parameter defined as output. At a minimum, your function tool must output a Boolean value to communicate success or failure.
ParameterType
An enumeration that indicates to the geoprocessing framework the importance of the parameter for the successful execution of the tool. The parameter types are as follows:
  • esriGPParameterTypeRequired—Required for successful execution.
  • esriGPParameterTypeOptional—Not required for successful execution.
  • esriGPParameterTypeDerived—Does not require input from the user. The necessary info can be derived from other parameters.
esriGPParameterTypeDerived applies only to output parameters and does not appear in the tool dialog box or in the command line. 
DataType
In geoprocessing, the data type of a tool parameter is identified by a GPDatatype object. A GPDatatype object defines the type of data that is acceptable for the parameter. Examples of GPDataType objects include the following:
  • GPStringType
  • GPLongType
  • GPFeatureLayerType
  • GPRasterDataType
Assigning a GPDatatype object enables the geoprocessing framework to create an appropriate UI dialog in the tool dialog box that does not accept parameters of any other data type. A GPDatatype object also enables the framework to validate the parameter input entered by the user and raise appropriate warnings and errors.
All implementing classes of IGPDataType are considered GPDataType objects.
 
For more information on data types, see Geoprocessing tool parameter data types.
 
For a complete list of GPDataTypeArcObjects, see IGPDataType.
Value
Assigns a GPValue object for a parameter. For each geoprocessing parameter data type, there is a corresponding value object. For example, if the data type is GPFeatureLayerType, the value object for the parameter is GPFeatureLayer.
All implementing classes of IGPValue are considered GPValue objects.
 
For a complete list of GPValue objects, see IGPValue.
Enabled
Controls whether the parameter is enabled or disabled on the UI dialog.
The following code snippet shows how to create input and output parameters for a custom function tool in the getParameterInfo() method as previously discussed. The tool described in the code snippet adds a new field to the polygon feature class and assigns the corresponding area of the polygon as its value.
The following parameters are defined in the getParameterInfo() method of the tool's Java class:
[Java]
// Returns an array of parameters for execution of the tool.
public IArray getParameterInfo()throws IOException, AutomationException{
    //Create an array for parameter objects.
    IArray parameters = new Array();
    GPParameter inputParameter = new GPParameter();

    //Define parameter 1 (the input feature class)
    inputParameter.setName("in_features");
    inputParameter.setDisplayName("Input Features");
    //The parameter is defined as an input parameter. 
    inputParameter.setDirection
        (esriGPParameterDirection.esriGPParameterDirectionInput);
    //The parameter is required for execution of the tool.
    inputParameter.setParameterType(esriGPParameterType.esriGPParameterTypeRequired);
    //Define the data type and value for the parameter.
    inputParameter.setDataTypeByRef(new GPFeatureLayerType());
    inputParameter.setValueByRef(new GPFeatureLayer());

    //Add parameter 1 to the array.
    parameters.add(inputParameter);

    //Define parameter 2 (the field name parameter).

    inputParameter = new GPParameter();
    inputParameter.setName("in_fieldName");
    inputParameter.setDisplayName("Area Field Name");
    //The parameter is defined as an input parameter.
    inputParameter.setDirection
        (esriGPParameterDirection.esriGPParameterDirectionInput);
    //The parameter is required for execution of the tool.
    inputParameter.setParameterType(esriGPParameterType.esriGPParameterTypeRequired);
    //Define the data type of the parameter.
    inputParameter.setDataTypeByRef(new GPStringType());
    // Define the value of the parameter. 
    IGPString gpStringValue = new GPString();
    inputParameter.setValueByRef((IGPValue)gpStringValue);

    //Add parameter 2 to the array.
    parameters.add(inputParameter);

    //Define parameter 3 (the output feature class).

    IGPParameterEdit outputParameter = new GPParameter();
    outputParameter.setName("out_features");
    outputParameter.setDisplayName("Output FeatureClass");
    //The parameter is defined as an output parameter.
    outputParameter.setDirection
        (esriGPParameterDirection.esriGPParameterDirectionOutput);
    //The parameter type is defined as derived, since the input feature class will be modified, and a
    // new feature class will not be created. 
    //When defined as derived, the parameter does not appear in the tool dialog box.
    outputParameter.setParameterType(esriGPParameterType.esriGPParameterTypeDerived);
    //The parameter data type and value are defined.
    outputParameter.setDataTypeByRef(new GPFeatureLayerType());
    outputParameter.setValueByRef(new GPFeatureLayer());

    //Add parameter 3 to the array.
    parameters.add(outputParameter);

    //Return the parameter array.
    return parameters;
}
The code snippet above creates a tool dialog box as shown in the following screen shot (in this case, the Calculate Area tool). The green dots indicate the parameters are required for operation of the tool.
The derived output parameter is not shown.
The recommended order of precedence for parameters in the array is those that are required are first, those that are optional are last. Within each parameter type (required or optional), input parameters are listed before output parameters. In the command line and scripting, required parameters are automatically shown in angle brackets (<>), while optional parameters are shown in curly brackets ({}). In the tool dialog box, required parameters that are not filled in are shown with a green dot.
Two additional methods of the GPParameter object are shown in the following table: 
 Property
Method 
Description
Notes
altered
Indicates whether the parameter has been explicitly set or altered by the user.
 
Programmatically changing a value with a validation code does not change the altered state. That is, if you set a default value for a parameter programmatically, the altered state does not change.
HasBeenValidated
Indicates whether the parameter value has been modified since the last time the parameter was validated by the geoprocessing framework.
 

Define the tool operation

The geoprocessing framework invokes the BaseGeoprocessingTool.execute() method to operate the tool. You must override the execute() method to define your tool's operation. To implement the execute() method, perform the following steps:
  1. Open the datasets of the corresponding input parameters and verify all inputs are valid—Opening the input datasets means creating objects from the inputs. For example, if the input value is a path to a feature class, create an IFeatureClass object. This ensures that this data still exists and is not locked by another application. The same is true for other inputs, such as fields. 
  2. Confirm whether the Overwrite Output setting is true or false—If the tool creates output data, you must check if the OverwriteOutput property is true or false. If the setting is true, you must delete the existing output before performing the operation.
  3. Implement operation of the tool
The geoprocessing framework exposes the following objects as arguments of the execute() method for implementation:
Internally, the geoprocessing framework calls the internal validate process before performing execute(). If the validation fails, the execute() method is not invoked.
The following code snippet illustrates the execute() method of the Calculate Area tool whose GIS operation adds a new field to the polygon feature class and populates it with the area of the corresponding feature shape:
[Java]
public void execute(IArray paramvalues, ITrackCancel trackcancel,
    IGPEnvironmentManager envMgr, IGPMessages message)throws IOException,
    AutomationException{


    //Open the datasets.

    // Get the first input parameter.
    IGPParameter parameter = (IGPParameter)paramvalues.getElement(0);
    // UnPackGPValue. This ensures you get the value from either the data element or GpVariable (ModelBuilder).
    IGPValue parameterValue = this.gpUtilities.unpackGPValue(parameter);
    // Open the input dataset.
    IDataset inputDataset = this.gpUtilities.openDataset(parameterValue);
    IFeatureClass inputFeatureClass = new FeatureClass(inputDataset);

    //Check the overwrite output since you'll modify the input feature class.
    GeoProcessor geoprocessor = new GeoProcessor();
    if geoprocessor.isOverwriteOutput(){

        //Implement the tool operation.

        // 1. Add the new field.
        int indexA;
        parameter = (IGPParameter)paramvalues.getElement(1);
        String field = parameter.getValue().getAsText();
        indexA = inputFeatureClass.findField(field);
        if (indexA < 0){
            IFieldEdit fieldEdit = new Field();
            fieldEdit.setType(esriFieldType.esriFieldTypeDouble);
            fieldEdit.setName(field);
            inputFeatureClass.addField(fieldEdit);
            indexA = inputFeatureClass.findField(field);
        }

        //2. Calculate the area and populate the new field.
        IFeatureCursor updateCursor = inputFeatureClass.IFeatureClass_update(null,
            false);
        IFeature updateFeature = updateCursor.nextFeature();
        IGeometry geometry;
        IArea area;
        double dArea;
        while (updateFeature != null){
            geometry = updateFeature.getShape();
            area = (IArea)geometry;
            dArea = area.getArea();
            updateFeature.setValue(indexA, dArea);
            updateCursor.updateFeature(updateFeature);
            updateFeature.store();
            updateFeature = updateCursor.nextFeature();
        }
        //Add message
        messages.addMessage("\tArea Calculated");


    }
}

Implement parameter interaction

Parameter interaction enables you to filter or set values for a parameter based on values of other parameters entered by the user in the tool dialog box. For example, you can enable or disable specific parameters or change a parameter's default value based on user input of other parameter values. 
The following screen shots show the Add Field tool dialog box. The Add Field tool adds a new field to a feature class. Initially, the Field Length input parameter is enabled (as shown in the screen shot on the left). When the user inputs the Field Type value as Long, the Field Length input is disabled (as shown in the screenshot on the right). The Filed Length value is enabled only if the Field Type value is Text.
Parameter interaction in a tool is achieved by overriding the BaseGeoprocessingTool.updateParameters() method. The updateParameters() method is invoked by the geoprocessing framework each time a parameter value in the tool dialog box or in the command line is entered or modified. This provides an opportunity to alter the state of the parameters based on the input parameter values. 
Another example of parameter interaction is setting the default value of a parameter that has not been altered or left blank by the user based on other parameters. In the case of the GPCalculateArea function tool, the field name parameter is initially left blank. When the user enters the inputFeatureClass parameter, the GPCalculateArea tool examines the field names of the feature class entered by the user. If there is no field in the feature class named Area, the field name value is automatically set to Area.
The following code snippet shows this scenario implemented by the updateParameters() method of the GPCalculateArea tool:
[Java]
//Set the default value as Area if there is no other field named Area.
public void updateParameters(IArray paramvalues, IGPEnvironmentManager pEnvMgr){
    IGPParameter3 input_feature = (IGPParameter3)paramvalues.getElement(0);
    try{
        //Check whether the parameter has been altered by the user.
        if (input_feature.isAltered()){

            //Get the feature class value for the parameter.
            IGPValue parameterValue = this.gpUtilities.unpackGPValue(input_feature);
            IDataset inputDataset = this.gpUtilities.openDataset(parameterValue);
            IFeatureClass inputFeatureClass = new FeatureClass(inputDataset);
            int fieldno = inputFeatureClass.findField("Area");
            //Confirm there is no other field named Area.
            if (fieldno < 1){
                IGPParameterEdit3 input_fieldname = (IGPParameterEdit3)
                    paramvalues.getElement(1);
                IGPString fieldName = new GPString();
                fieldName.setValue("Area");
                //The value of the field name parameter is set as Area.
                input_fieldname.setValueByRef((IGPValue)fieldName);
            }
        }
    }
    catch (Exception e){
        System.out.println(e);
    }
}

Verify parameters and update messages

It is critical to verify the values of the tool parameters entered by the user. The geoprocessing framework validates parameters based on data type. However, special conditions and restrictions for the parameters, if any, need to be explicitly implemented. For example, in the GPCalculateArea custom function tool, tool execution fails if the feature shape type is not polygon. The geoprocessing framework verifies that the input parameter value is a feature class; however, the feature's geometry type is not verified by the geoprocessing framework.
You can override the BaseGeoprocessingTool.updateMessages() method to examine the parameter values for special conditions and to inform the user about possible errors and warnings. When the user alters a tool's parameter value, the geoprocessing framework validates the input data and invokes the updateParameters() and updateMessages() methods. In the updateMessages() method implementation, you can verify the parameter values and update the error and warning messages as required. You can also examine and change the messages created by the geoprocessing framework regarding data validation.
The following screen shot shows an example of feature geometry type verification of the GPCalculateArea tool. The updateMessages() method is implemented to verify the feature geometry type of the feature class entered by the user and to flag appropriate error messages.
This scenario is shown in the following code snippet of the GPCalculateArea custom function tool:
[Java]
public void updateMessages(IArray paramvalues, IGPEnvironmentManager pEnvMgr,
    IGPMessages messages){

    IGPParameter3 input_feature = (IGPParameter3)paramvalues.getElement(0);

    try{
        //Check if the parameter value has been changed by the user.
        if (input_feature.isAltered()){

            //Get the feature class.
            IGPValue parameterValue = this.gpUtilities.unpackGPValue(input_feature);
            IDataset inputDataset = this.gpUtilities.openDataset(parameterValue);
            IFeatureClass inputFeatureClass = new FeatureClass(inputDataset);

            //Verify the shape type. If it's not polygon, set error message.
            if (inputFeatureClass.getShapeType() !=
                esriGeometryType.esriGeometryPolygon){
                messages.replaceError(0,
                    esriGPMessageSeverity.esriGPMessageSeverityError, 
                    "Feature Type not a polygon");
            }
        }
        catch (Exception e){
            System.out.println(e);
        }
    }
The updateParameters() and updateMessages() methods are invoked by the framework each time a user interacts with the dialog box. If you include time consuming operations in your implementation of these methods, it may affect the response time of the tool dialog.

Check for license

If the operation of your custom geoprocessing tool requires specific ArcGIS licenses, you must check the existing license level by overriding the isLicensed() method. 
The following code snippet checks the ArcView product license and informs the user of the status:
[Java]
public boolean isLicensed()throws IOException, AutomationException{

    AoInitialize aoInit = new AoInitialize();
    String licensedProductName = aoInit.getLicenseProductName
        (esriLicenseProductCode.esriLicenseProductCodeArcInfo);
    //Check the product license level.
    if (licensedProductName.equalsIgnoreCase("ArcInfo")){
        System.out.println(toolName + ": licensedProductName: " +
            licensedProductName);
        //Check out extensions here if required.
        return true;
    }
    else{
        System.out.println(toolName + ": licensedProductName: " +
            licensedProductName + " ArcInfo License level required");
        return false;
    }
    return true;
}

Populate the help panel

The geoprocessing framework allows you to provide information about the tool's operation and its parameters in the help panel of the tool dialog box. In the following screen shot, the help panel provides information about the XY Tolerance parameter of the Clip tool:
To open the help panel, click the Show Help button; to close the help panel, click the Hide Help button.
The parameter descriptions of a function tool are derived from a metadata file (in Extensible Markup Language [XML] file format) that resides in the %ArcGISHOME%/help/gp folder. In the case of a custom function tool, you need to create a metadata file in the %ArcGISHOME%/help/gp folder, and ensure that the getMetaDataFile() method provides the name of the metadata file for the tool as shown in the following code.
The metadata file name must be the custom function tool name concatenated with the name of the custom function factory.
[Java]
//Define the class variable for the tool name.
private String toolName = "JavaCalculateArea";

public String getMetadataFileName(){
    return this.getName() + ".xml";
}

public String getName()throws IOException, AutomationException{
    return toolName;
}

What's next

Once the custom function tool class and the custom function factory class are created, their corresponding Java .class files must be bundled in a Java Archive (JAR) file and deployed to ArcGIS by placing the JAR file in the <ArcGIS Install Dir>/java/lib/ext folder. After deployment, the custom geoprocessing function tool can be accessed as follows:
For more information about accessing and consuming custom geoprocessing tools in ArcToolbox and in ArcGIS Engine and ArcGIS Server applications, see the following topics:
An ArcGIS application (ArcGIS Engine, ArcMap, ArcCatalog, and ArcGIS Server) recognizes the custom geoprocessing function tool when the application is started. If the ArcGIS application is already running, then it needs to be restarted after deployment. While testing the tool, if you modify the code in the Java classes bundled in the JAR file, the JAR file must be recreated and redeployed. You also need to restart the ArcGIS application after redeployment.


See Also:

How to build custom geoprocessing tools
Creating a custom function factory class




Development licensingDeployment licensing
Engine Developer KitEngine
ServerServer
ArcGIS for Desktop BasicArcGIS for Desktop Basic
ArcGIS for Desktop StandardArcGIS for Desktop Standard
ArcGIS for Desktop AdvancedArcGIS for Desktop Advanced