Length Calculator Server Object Extension
arcgissamples\soe\LengthCalculatorSOE.java
/* Copyright 2010 ESRI
* 
* All rights reserved under the copyright laws of the United States
* and applicable international laws, treaties, and conventions.
* 
* You may freely redistribute and use this sample code, with or
* without modification, provided you include the original copyright
* notice and use restrictions.
* 
* See the use restrictions.
* 
*/
package arcgissamples.soe;

import java.io.IOException;

import com.esri.arcgis.carto.Map;
import com.esri.arcgis.carto.MapServer;
import com.esri.arcgis.geodatabase.*;
import com.esri.arcgis.geometry.Polyline;
import com.esri.arcgis.interop.AutomationException;
import com.esri.arcgis.interop.extn.ArcGISExtension;
import com.esri.arcgis.interop.extn.ServerObjectExtProperties;
import com.esri.arcgis.server.IServerObjectExtension;
import com.esri.arcgis.server.IServerObjectHelper;
import com.esri.arcgis.system.*;

@ArcGISExtension
@ServerObjectExtProperties(
      displayName = "Length Calculator SOE",
      description = "Calculates length of all polyline features in Streets layer.",
      supportsMSD = true
  )
public class LengthCalculatorSOE implements IServerObjectExtension, ICalculateLength {

  private static final long serialVersionUID = 1L;
  private IServerObjectHelper soHelper;
  private ILog serverLog;
  MapServer mapServer = null;

  /****************************************************************************************************************************
   * IServerObjectExtension methods: This is a mandatory interface that must be
   * supported by all SOEs. This interface is used by the Server Object to
   * manage the lifetime of the SOE and includes two methods: init() and
   * shutdown(). The Server Object cocreates the SOE and calls the init() method
   * handing it a back reference to the Server Object via the Server Object
   * Helper argument. The Server Object Helper implements a weak reference on
   * the Server Object. The extension can keep a strong reference on the Server
   * Object Helper (for example, in a member variable) but should not keep a
   * strong reference on the Server Object. The log entries are merely
   * informative and completely optional.
   ****************************************************************************************************************************/
  /**
   * init() is called once, when the instance of the SOE is created.
   */
  public void init(IServerObjectHelper soh) throws IOException, AutomationException {
    /*
     * An SOE should get the Server Object from the Server Object Helper in
     * order to make any method calls on the Server Object and release the
     * reference after making the method calls.
     */
    this.soHelper = soh;
    this.serverLog = ServerUtilities.getServerLogger();

    // get handle to map
    mapServer = (MapServer) soHelper.getServerObject();
  }

  /**
   * shutdown() is called once when the Server Object's context is being shut
   * down and is about to go away.
   */
  public void shutdown() throws IOException, AutomationException {
    /*
     * The SOE should release its reference on the Server Object Helper.
     */
    this.mapServer = null;
    this.soHelper = null;
    this.serverLog = null;
  }

  /****************************************************************************************************************************
   * ICalculateLength method: This is a custom interface. It exposes 1 method:
   * calculateLength()
   ****************************************************************************************************************************/
  /**
   * Calculates length of all polylines
   */
  public double calculateLength() throws Exception {
    
    // Get index of layer containing all locations
    Map map = (Map) this.mapServer.getMap("Layers");
    FeatureClass streetsFC = new FeatureClass(this.mapServer.getDataSource(this.mapServer.getDefaultMapName(), getLayerIndex(map, "Streets")));

    // count num of features
    int numFeatures = streetsFC.featureCount(null);
    IFeatureCursor featureCursor = streetsFC.search(null, true);

    // calculate length of each feature and add up
    double totalLength = 0.0;
    for (int i = 0; i < numFeatures; i++) {
      IFeature feature = featureCursor.nextFeature();
      Polyline polyline = (Polyline) feature.getShape();
      totalLength += polyline.getLength();
    }

    return totalLength;
  }

  /************************************************************************
   * Util methods
   ************************************************************************/
  /**
   * Retrieves ID of a layer in MapEJB based on its name
   * 
   * @param mapServer
   * @param layerName
   * @return
   */
  private int getLayerIndex(Map map, String layerName) throws IOException, AutomationException {
    int layerID = -1;

    for (int i = 0; i < map.getLayerCount(); i++) {
      String name = map.getLayer(i).getName();
      if (layerName.equalsIgnoreCase(name)) {
        layerID = i;
        break;
      }
    }

    if (layerID < 0) {
      serverLog.addMessage(4, 8000, "Could not find layer " + layerName + " in " + map.getName());
      throw new RuntimeException("Could not find layer " + layerName + " in " + map.getName());
    }

    return layerID;
  }
}