arcgissamples\soe\JavaSimpleRESTSOE.java—ArcObjects 10.4 Help for Java | ArcGIS for Desktop
Simple REST SOE Sample
arcgissamples\soe\JavaSimpleRESTSOE.java
/* Copyright 2015 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 at <your ArcGIS install location>/DeveloperKit10.4/userestrictions.txt.
* 
*/
package arcgissamples.soe;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import com.esri.arcgis.carto.IMapLayerInfo;
import com.esri.arcgis.carto.IMapLayerInfos;
import com.esri.arcgis.carto.IMapServer3;
import com.esri.arcgis.carto.IMapServerDataAccess;
import com.esri.arcgis.carto.IMapServerInfo;
import com.esri.arcgis.geodatabase.FeatureClass;
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.server.json.JSONArray;
import com.esri.arcgis.server.json.JSONException;
import com.esri.arcgis.server.json.JSONObject;
import com.esri.arcgis.system.ILog;
import com.esri.arcgis.system.IRESTRequestHandler;
import com.esri.arcgis.system.ServerUtilities;

@ArcGISExtension
@ServerObjectExtProperties(displayName = "Java Simple REST SOE", description = "Java Simple REST SOE.", defaultSOAPCapabilities = "", allSOAPCapabilities = "", properties = "")
public class JavaSimpleRESTSOE implements IServerObjectExtension,
  IRESTRequestHandler {
    private static final long serialVersionUID = 1L;
    private IServerObjectHelper soHelper;
    private ILog serverLog;
    private IMapLayerInfos layerInfos;

    public JavaSimpleRESTSOE() throws Exception {
  super();
    }

    /****************************************************************************************************************************
     * 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();

  serverLog.addMessage(3, 200, "Beginning init in "
    + this.getClass().getName() + " SOE.");

  IMapServer3 ms = (IMapServer3) this.soHelper.getServerObject();
  IMapServerInfo mapServerInfo = ms.getServerInfo(ms.getDefaultMapName());
  this.layerInfos = mapServerInfo.getMapLayerInfos();

  serverLog.addMessage(3, 200, "Initialized " + this.getClass().getName()
    + " SOE.");
    }

    /**
     * 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.
   */
  serverLog.addMessage(3, 200, "Shutting down "
    + this.getClass().getName() + " SOE.");
  this.soHelper = null;
  this.serverLog = null;
    }

    /**
     * Returns number of layers in associate map service, based on layer type
     * provided
     * 
     * @param operationInput
     * @return
     */
    private byte[] getLayerCountByType(JSONObject operationInput, java.util.Map<String, String> responsePropertiesMap)
      throws Exception {
  String type = operationInput.getString("type");

  JSONObject json = new JSONObject();

  int count = 0;
  if (type != null && !type.isEmpty()) {
      String aoType = "";
      if (type.equalsIgnoreCase("all")) {
    count = layerInfos.getCount();
      } else if (type.equalsIgnoreCase("feature")) {
    aoType = "Feature Layer";
      } else if (type.equalsIgnoreCase("raster")) {
    aoType = "Raster Layer";
      } else if (type.equalsIgnoreCase("dataset")) {
    aoType = "Network Dataset Layer";
      }

      for (int i = 0; i < layerInfos.getCount(); i++) {
    if (layerInfos.getElement(i).getType().equalsIgnoreCase(aoType)) {
        count++;
    }
      }

      json.put("count", count);

      responsePropertiesMap.put("Content-Type", "application/json");
      
      return json.toString().getBytes();
  } else {
      throw new Exception(
        "Invalid layer type provided. Available types are: \"all\", \"feature\", \"raster\", \"dataset\".");
  }
    }

    /**
     * Returns JSON representation of root resource's description.
     * 
     * @return String JSON representation of root resource's description.
     */
    private byte[] getRootResource() throws Exception {
  JSONObject json = new JSONObject();
  json.put("name", "Java Simple REST SOE");
  json.put(
    "description",
    "Simple REST SOE with 1 sub-resource called \"layers\" and 1 operation called \"getLayerCountByType\".");
  json.put(
    "usage",
    "The \"layers\" subresource returns all layers in the map service.\n"
      + "The \"getLayerCountByType\" operation returns a count of layer of specified type. It accepts one of the following values as input: \"feature\", \"raster\", "
      + "\"dataset\", and \"all\".");
  return json.toString().getBytes("utf-8");
    }

    /**
     * Returns JSON representation of specified sub-resource.
     * 
     * @return String JSON representation of specified resource.
     */
    private byte[] getSubresourceLayers(Map<String, String> responsePropertiesMap) throws Exception {
  JSONObject json = new JSONObject();
  json.put("layers", getLayersInfoAsJSON());
  
  responsePropertiesMap.put("Content-Type", "application/json");

  return json.toString().getBytes("utf-8");
    }

    /**
     * Returns info about layers in associated map service
     * 
     * @return
     * @throws Exception
     */
    public JSONObject getLayersInfoAsJSON() throws Exception {
  JSONObject json = new JSONObject();

  int count = this.layerInfos.getCount();
  json.put("layerCount", count);
  JSONArray layerArray = new JSONArray();
  for (int i = 0; i < count; i++) {
      IMapLayerInfo layerInfo = layerInfos.getElement(i);
      JSONObject layerJSON = new JSONObject();
      layerJSON.put("name", layerInfo.getName());
      String layerType = layerInfo.getType();
      layerJSON.put("type", layerType);
      int id = layerInfo.getID();
      layerJSON.put("id", id);
      layerJSON.put("description", layerInfo.getDescription());
      if (layerInfo.isFeatureLayer()) {
    IMapServerDataAccess mapServerDataAccess = (IMapServerDataAccess) this.soHelper
      .getServerObject();
    FeatureClass fc = new FeatureClass(
      mapServerDataAccess.getDataSource("", id));
    layerJSON.put("featureCount", fc.featureCount(null));
      }

      layerArray.put(i, layerJSON);
  }
  json.put("layersInfo", layerArray);
  return json;
    }

    /**
     * Returns JSON representation of specified resource.
     * 
     * @return String JSON representation of specified resource.
     */
    private byte[] getResource(String resourceName, Map<String, String> responsePropertiesMap) throws Exception {
  if (resourceName.equalsIgnoreCase("") || resourceName.length() == 0) {
      return getRootResource();
  } else if (resourceName.equalsIgnoreCase("layers")) {
      return getSubresourceLayers(responsePropertiesMap);
  }
  
  return null;
    }

    /**
     * Invokes specified REST operation on specified REST resource
     * 
     * @param capabilitiesList
     * @param resourceName
     * @param operationName
     * @param operationInput
     * @return
     */
    private byte[] invokeRESTOperation(String capabilitiesList,
      String resourceName, String operationName, String operationInput,
      String outputFormat, String requestProperties,
      Map<String, String> responsePropertiesMap) throws Exception {
  byte[] operationOutput = null;

  JSONObject operationInputAsJSON = new JSONObject(operationInput);

  if (resourceName.isEmpty()) {
      if (operationName.equalsIgnoreCase("getLayerCountByType")) {
    operationOutput = getLayerCountByType(operationInputAsJSON, responsePropertiesMap);
      }
  } else
  // if non existent sub-resource specified, report error
  {
      this.serverLog.addMessage(1, 500, "No sub-resource by name "
        + resourceName + " found.");
      return ServerUtilities.sendError(500,
        "No sub-resource by name " + resourceName + " found.",
        new String[] { "No details specified." })
        .getBytes("utf-8");
  }

  return operationOutput;
    }

    /*************************************************************************************
     * IRESTRequestHandler methods:
     *************************************************************************************/
    /**
     * This method handles REST requests by determining whether an operation or
     * resource has been invoked and then forwards the request to appropriate
     * methods.
     */
    @Override
    public byte[] handleRESTRequest(String capabilities, String resourceName,
      String operationName, String operationInput, String outputFormat,
      String requestProperties, String[] responseProperties)
      throws IOException, AutomationException {
  /*
   * This method handles REST requests by determining whether an operation
   * or resource has been invoked and then forwards the request to
   * appropriate methods.
   */

  try {
      
      Map<String, String> responsePropertiesMap = new HashMap<String, String>();
      
      // if no operationName is specified send description of specified
      // resource
      byte[] response = null;
      if (operationName.length() == 0) {
    response = getResource(resourceName, responsePropertiesMap);
      } else
      // invoke REST operation on specified resource
      {
    response = invokeRESTOperation(capabilities, resourceName,
      operationName, operationInput, outputFormat,
      requestProperties, responsePropertiesMap);
      }
     
      //collect response properties that may have changed in subresources or operations
      JSONObject responsePropertiesJSON = new JSONObject(responsePropertiesMap);
      responseProperties[0] = responsePropertiesJSON.toString();
      
      return response;
  } catch (Exception e) {
      this.serverLog.addMessage(1, 500, e.getMessage());
      return ServerUtilities.sendError(500,
        "Exception occurred: " + e.getMessage(),
        new String[] { "No details specified." }).getBytes("utf-8");
  }
    }

    /**
     * This method returns the resource hierarchy of a REST based SOE in JSON
     * format.
     */
    public String getSchema() throws IOException, AutomationException {
  try {
      JSONObject simpleRESTSOE = ServerUtilities.createResource(
        "JavaSimpleRESTSOE", "Java Simple REST SOE", false, false);
      JSONArray _subResourcesArray = new JSONArray();
      _subResourcesArray.put(ServerUtilities.createResource("layers",
        "layers in associated map service", false, false));
      simpleRESTSOE.put("resources", _subResourcesArray);

      JSONArray _OpArray = new JSONArray();
      _OpArray.put(ServerUtilities.createOperation("getLayerCountByType",
        "type", "json", false));
      simpleRESTSOE.put("operations", _OpArray);
      return simpleRESTSOE.toString();
  } catch (JSONException e) {
      this.serverLog.addMessage(1, 500, e.getMessage());
      return ServerUtilities.sendError(500,
        "Exception occurred: " + e.getMessage(), null);
  }
    }
}