Local query by attribute

Download Sample Viewer

Description

This sample demonstrates performing an attribute query, adding the results to the map and a table, and zooming to the result. All operations are performed on a local map service running on the Local Server. The application uses 2 queries - one to get all the State names, and another to get all the attributes of a State. Additionally, this application also has a button, which when clicked will focus on the US extent.

Code snippet


    QueryParameters query = new QueryParameters();
    query.setOutFields(new String[] {"*"});
    query.setWhere("STATE_NAME='" + newStateName + "'");
    try {
        QueryTask task = new QueryTask(URL_LOCAL_MAP_SERVICE + "/" + STATES_LAYER_INDEX);
        FeatureResult queryResult = task.execute(query);
        // do something with query result
    } catch (Exception ex) {
        // handle exception
    }
  

Sample Code

/* Copyright 2014 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 com.esri.client.samples.search;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.util.Iterator;
import java.util.Map;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;
import javax.swing.table.DefaultTableModel;

import com.esri.client.local.ArcGISLocalDynamicMapServiceLayer;
import com.esri.core.geometry.Geometry;
import com.esri.core.geometry.GeometryEngine;
import com.esri.core.map.Feature;
import com.esri.core.map.FeatureResult;
import com.esri.core.map.Graphic;
import com.esri.core.symbol.SimpleFillSymbol;
import com.esri.core.symbol.SimpleLineSymbol;
import com.esri.core.tasks.query.QueryParameters;
import com.esri.core.tasks.query.QueryTask;
import com.esri.map.GraphicsLayer;
import com.esri.map.JMap;
import com.esri.map.LayerInfo;
import com.esri.map.LayerInitializeCompleteEvent;
import com.esri.map.LayerInitializeCompleteListener;
import com.esri.map.LayerList;
import com.esri.map.MapEvent;
import com.esri.map.MapEventListenerAdapter;
import com.esri.runtime.ArcGISRuntime;

/**
 * This sample demonstrates performing an attribute query, adding the results to the map and a
 * table, and zooming to the result. All operations are performed on a local map service 
 * running on the Local Server.
 * <p>
 * The application uses 2 queries - one to get all the State names, and another to get all the 
 * attributes of a State. Additionally, this application also has a button, which when clicked 
 * will focus on the US extent.
 */
public class LocalQueryAttributeApp {

  // symbology
  final static SimpleFillSymbol SYM_STATE = new SimpleFillSymbol(
      new Color(128, 128, 128, 200), new SimpleLineSymbol(Color.WHITE, 1));

  // main content
  private JComponent contentPane;
  private JMap map;
  private GraphicsLayer graphicsLayer;

  // this URL points to the map service that is created for the local MPK file.
  // this URL is dynamically generated after the local server is started.
  private String URL_LOCAL_MAP_SERVICE = "";
  // a map consists of layers. this index points to the the states layer.
  // the states layer can be accessed with URL of format
  // (local map service URL) + "/" + (layer index or layer name)
  private final int STATES_LAYER_INDEX = 2;

  // constants
  private final String INVALID_ITEM_STATES_LIST = "Select State...";
  private static String FSP = System.getProperty("file.separator");
  private static final double BUFFER_DISTANCE = 500000; // 500 km

  // ------------------------------------------------------------------------
  // Constructors
  // ------------------------------------------------------------------------
  public LocalQueryAttributeApp() {
  }

  // ------------------------------------------------------------------------
  // Core functionality
  // ------------------------------------------------------------------------
  /**
   * This method:
   * <ul>
   * <li> Queries to get the information of a state.
   * <li> Zooms the map to the state.
   * <li> Highlights the state by adding it to the graphics layer.
   * </ul>
   * @param jMap map.
   * @param newStateName The state name which will be used to query, zoom, and highlight.
   * @param tblModelStateInfo Result of the query for the input state.
   */
  private void onStateNameChanged(
      final JMap jMap,
      String newStateName,
      DefaultTableModel tblModelStateInfo) {

    // return if state name is not valid
    if (newStateName == null ||
        newStateName.isEmpty() ||
        newStateName.equals(INVALID_ITEM_STATES_LIST)) {
      return;
    }

    // initialize the result - add the column headers if not already present,
    // and clear existing rows.
    if (tblModelStateInfo.getColumnCount() == 0) {
      tblModelStateInfo.addColumn("No.");
      tblModelStateInfo.addColumn("Name");
      tblModelStateInfo.addColumn("Value");
    }
    tblModelStateInfo.setRowCount(0);

    // -----------------------------------------------------------------------------------------
    // Query to get attributes of a state
    // -----------------------------------------------------------------------------------------
    // create query parameters
    QueryParameters query = new QueryParameters();
    // specify * to fetch all attributes, otherwise only the fields used in the
    // where clause are fetched.
    query.setOutFields(new String[] {"*"});
    // get information of the input state only.
    query.setWhere("STATE_NAME='" + newStateName + "'");

    Feature selectedState = null;

    try {
      // create and execute the query task
      // the states layer can be accessed with URL of format
      // (local map service URL) + "/" + (layer index or layer name)
      QueryTask task = new QueryTask(URL_LOCAL_MAP_SERVICE + "/" + STATES_LAYER_INDEX);
      FeatureResult queryResult = task.execute(query);

      // query result should have 1 record per state
      if (queryResult.featureCount() != 1) {
        System.out.println("Error! There should be exactly 1 record per state.");
        return;
      }
      selectedState = (Feature) queryResult.iterator().next();

      // get all attributes of the state and add them as rows to the table
      int attrIndex = 1;
      for (Map.Entry<String, Object> attr : selectedState.getAttributes().entrySet()) {
        tblModelStateInfo.addRow(new Object[] {Integer.valueOf(attrIndex++), attr.getKey(), attr.getValue()});
      }

    } catch (Exception ex) {
      ex.printStackTrace();
    }

    if (selectedState != null) {
      // -----------------------------------------------------------------------------------------
      // Zoom to selected state, with neighbouring states within extent zoomed to
      // -----------------------------------------------------------------------------------------
      // calculate a buffer around the state geometry
      Geometry geometryForZoom = GeometryEngine.buffer(
          selectedState.getGeometry(), map.getSpatialReference(), BUFFER_DISTANCE, map.getSpatialReference().getUnit());
      // zoom to this buffered geometry
      jMap.zoomTo(geometryForZoom);

      // -----------------------------------------------------------------------------------------
      // Highlight the selected state on the graphics layer
      // -----------------------------------------------------------------------------------------
      // remove previously highlighted state and highlight the current one
      graphicsLayer.removeAll();
      graphicsLayer.addGraphic(new Graphic(selectedState.getGeometry(), SYM_STATE));
    }
  }

  /**
   * Executes a query to get the list of states at the start.
   * @param statesList A combo box to which the list of states will be added.
   */
  private void populateStatesList(JComboBox<String> statesList) {
    // create a query that gets all states name.
    QueryParameters query = new QueryParameters();
    // specify STATE_NAME as the attribute to be fetched.
    query.setOutFields(new String[] {"STATE_NAME"});
    // the geometry of the state is not required here. this will reduce the amount of data
    // retrieved from the server.
    query.setReturnGeometry(false);
    // select all records.
    query.setWhere("1=1");

    try {
      // execute the query.
      // the states layer can be accessed with URL of format
      // (local map service URL) + "/" + (layer index or layer name)
      QueryTask task = new QueryTask(URL_LOCAL_MAP_SERVICE + "/" + STATES_LAYER_INDEX);
      FeatureResult queryResult = task.execute(query);

      // add the query result to the list.
      Iterator<Object> it = queryResult.iterator();
      while (it.hasNext()) {
        Object o = it.next();
        if (o instanceof Feature) {
          Feature feature = (Feature) o;
          if (String.class.isInstance(feature.getAttributeValue("STATE_NAME"))) {
            String stateName = (String) feature.getAttributeValue("STATE_NAME");
            if (stateName != null && stateName.length() > 0) {
              statesList.addItem((String)feature.getAttributeValue("STATE_NAME"));
            }
          }
        }
      }
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }

  // ------------------------------------------------------------------------
  // Static methods
  // ------------------------------------------------------------------------
  /**
   * Starting point of this application.
   * @param args arguments to this application.
   */
  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
      @Override
      public void run() {
        try {

          // instance of this application
          LocalQueryAttributeApp queryAttributeApp = new LocalQueryAttributeApp();

          // create the UI, including the map, for the application.
          JFrame appWindow = queryAttributeApp.createWindow();
          appWindow.add(queryAttributeApp.createUI());
          appWindow.setVisible(true);
        } catch (Exception e) {
          // on any error, display the stack trace.
          e.printStackTrace();
        }
      }
    });
  }

  // ------------------------------------------------------------------------
  // Public methods
  // ------------------------------------------------------------------------

  /**
   * Creates and displays the UI, including the map, for this application.
   */
  public JComponent createUI() throws Exception {
    // application content
    contentPane = createContentPane();

    // drop-down list for the states
    JComboBox<String> cbxStatesList = new JComboBox<>();
    cbxStatesList.addItem(INVALID_ITEM_STATES_LIST);
    cbxStatesList.setMaximumSize(new Dimension(250, 30));

    // map
    map = createMap(cbxStatesList);

    // button - when clicked, focus on the U.S. extent
    JButton btnShowUS = new JButton("Zoom to U.S.");
    btnShowUS.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        map.setExtent(map.getFullExtent());
      }
    });
    btnShowUS.setAlignmentX(Component.CENTER_ALIGNMENT);

    // label for the states list
    JTextArea lblStatesList = new JTextArea(" Query all attributes of a State. ");
    lblStatesList.setMaximumSize(new Dimension(250, 30));
    lblStatesList.setForeground(Color.WHITE);
    lblStatesList.setBackground(Color.BLACK);
    lblStatesList.setEditable(false);

    // scrollable-table to display a state's information
    final DefaultTableModel tblModelStateInfo = new DefaultTableModel();
    JTable stateInfoTable = new JTable(tblModelStateInfo);
    stateInfoTable.setEnabled(false);
    JScrollPane tblStateInfoScrollable = new JScrollPane(stateInfoTable);

    // add a hook for the action to be taken when selected state changes
    cbxStatesList.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        String selected = (String)((JComboBox<String>) e.getSource()).getSelectedItem();
        // execute when button is pressed.
        onStateNameChanged(map, selected, tblModelStateInfo);
      }
    });

    // group the above UI items into a panel
    final JPanel controlPanel = new JPanel();
    BoxLayout boxLayout = new BoxLayout(controlPanel, BoxLayout.Y_AXIS);
    controlPanel.setLayout(boxLayout);
    controlPanel.setLocation(10, 10);
    controlPanel.setSize(250, 250);
    controlPanel.setBackground(new Color(0, 0, 0, 100));
    controlPanel.setDoubleBuffered(true);
    controlPanel.setBorder(new LineBorder(Color.BLACK, 2, false));

    controlPanel.add(btnShowUS);
    controlPanel.add(lblStatesList);
    controlPanel.add(cbxStatesList);
    controlPanel.add(tblStateInfoScrollable);

    // add the panel to the main window
    contentPane.add(controlPanel);

    contentPane.add(map);

    return contentPane;
  }

  // ------------------------------------------------------------------------
  // Private methods
  // ------------------------------------------------------------------------
  /**
   * Creates a window.
   * @return a window.
   */
  private JFrame createWindow() {
    JFrame window = new JFrame("Local Query Attribute Application");
    window.setBounds(100, 100, 1000, 700);
    window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    window.getContentPane().setLayout(new BorderLayout(0, 0));
    window.addWindowListener(new WindowAdapter() {
      @Override
      public void windowClosing(WindowEvent windowEvent) {
        super.windowClosing(windowEvent);
        map.dispose();
      }
    });
    return window;
  }

  /**
   * Creates a content pane.
   * @return a content pane.
   */
  private static JLayeredPane createContentPane() {
    JLayeredPane contentPane = new JLayeredPane();
    contentPane.setBounds(100, 100, 1000, 700);
    contentPane.setLayout(new BorderLayout(0, 0));
    contentPane.setVisible(true);
    return contentPane;
  }

  /**
   * Creates a map.
   * @return a map.
   */
  private JMap createMap(final JComboBox<String> cbxStatesList) throws Exception {
    final JMap jMap = new JMap();
    // -----------------------------------------------------------------------------------------
    // Base Layer - with US topology, focused on U.S by default
    // -----------------------------------------------------------------------------------------
    final ArcGISLocalDynamicMapServiceLayer baseLayer =
        new ArcGISLocalDynamicMapServiceLayer(
            getPathSampleData() + "mpks" + FSP + "USCitiesStates_Lambert_Conformal_Conic.mpk");

    baseLayer
        .addLayerInitializeCompleteListener(new LayerInitializeCompleteListener() {

          @Override
          public void layerInitializeComplete(LayerInitializeCompleteEvent e) {
            if (e.getID() == LayerInitializeCompleteEvent.LOCALLAYERCREATE_ERROR) {
              String errMsg = "Failed to initialize due to "
                  + baseLayer.getInitializationError();
              JOptionPane.showMessageDialog(jMap, wrap(errMsg), "",
                  JOptionPane.ERROR_MESSAGE);
            }

          }
        });
    
    jMap.setExtent(jMap.getFullExtent());

    jMap.addMapEventListener(new MapEventListenerAdapter() {
      @Override
      public void mapReady(final MapEvent arg0) {
        SwingUtilities.invokeLater(new Runnable() {
          @Override
          public void run() {
            URL_LOCAL_MAP_SERVICE = baseLayer.getUrl();
            // to avoid clutter, display only the states layer
            for (LayerInfo layer : baseLayer.getLayersList()) {
              if (layer.getId() != STATES_LAYER_INDEX) {
                layer.setVisible(false);
              }
            }
            // initialize the drop-down with the list of states
            populateStatesList(cbxStatesList);
          }
        });
      }
    });
    LayerList layers = jMap.getLayers();
    layers.add(baseLayer);
    
    // -----------------------------------------------------------------------------------------
    // Graphics Layer - to highlight a selected feature
    // -----------------------------------------------------------------------------------------
    graphicsLayer = new GraphicsLayer();
    layers.add(graphicsLayer);

    return jMap;
  }

  private String getPathSampleData() {
    String dataPath = null;
    String javaPath = ArcGISRuntime.getInstallDirectory();
    if (javaPath != null) {
      if (!(javaPath.endsWith("/") || javaPath.endsWith("\\"))){
        javaPath += FSP;
      }
      dataPath = javaPath + "sdk" + FSP + "samples" + FSP + "data" + FSP;
    }
    File dataFile = new File(dataPath);
    if (!dataFile.exists()) { 
      dataPath = ".." + FSP + "data" + FSP;
    }
    return dataPath;
  }
  
  private String wrap(String str) {
    // create a HTML string that wraps text when longer
    return "<html><p style='width:200px;'>" + str + "</html>";
  }
}
Feedback on this topic?