How to catch "com.esri.arcgisruntime.internal.io.handler.request.BaseRequest getInvalidApiKeyException?"

1082
2
Jump to solution
05-27-2021 03:58 PM
DonScott
New Contributor

When an API key is bad resulting in an application failing to download a base map, the runtime outputs this message to stdout, "com.esri.arcgisruntime.internal.io.handler.request.BaseRequest getInvalidApiKeyException?" How to we catch this exception so that we can inform the user that the API key is bad? Right now, it just produces an error with a INFO log statement which a user will not see. We want to catch it and display an alert box in the GUI when the key is bad.

0 Kudos
1 Solution

Accepted Solutions
MarkBaird
Esri Regular Contributor

You can identify this state in code by adding load listener to the map which is trying to use your bad API key.

I've done this very crudely in the code below:

 

      // authentication with an API key or named user is required to access basemaps and other location services
      ArcGISRuntimeEnvironment.setApiKey("bad API key");
      // create a map with the standard imagery basemap style
      ArcGISMap map = new ArcGISMap(BasemapStyle.ARCGIS_IMAGERY);

      map.addDoneLoadingListener(()-> {
        System.out.println("load status" + map.getLoadStatus());
        if (map.getLoadStatus() == LoadStatus.FAILED_TO_LOAD) {
          System.out.println("error " + map.getLoadError().getCause());
        }
      });

      // create a map view and set the map to it
      mapView = new MapView();
      mapView.setMap(map);

 

We don't throw a specific error for this condition (IOException), but the cause comes up as you spotted in the console window.

Does this help?

View solution in original post

2 Replies
MarkBaird
Esri Regular Contributor

You can identify this state in code by adding load listener to the map which is trying to use your bad API key.

I've done this very crudely in the code below:

 

      // authentication with an API key or named user is required to access basemaps and other location services
      ArcGISRuntimeEnvironment.setApiKey("bad API key");
      // create a map with the standard imagery basemap style
      ArcGISMap map = new ArcGISMap(BasemapStyle.ARCGIS_IMAGERY);

      map.addDoneLoadingListener(()-> {
        System.out.println("load status" + map.getLoadStatus());
        if (map.getLoadStatus() == LoadStatus.FAILED_TO_LOAD) {
          System.out.println("error " + map.getLoadError().getCause());
        }
      });

      // create a map view and set the map to it
      mapView = new MapView();
      mapView.setMap(map);

 

We don't throw a specific error for this condition (IOException), but the cause comes up as you spotted in the console window.

Does this help?

DonScott
New Contributor

Hi Mark,

Thank you very much for the solution. Trying to load a standard basemap as a test of the validity of the API key is a good approach. I implemented it slightly differently. We're using JavaFX and the user is interacting with the UI thread, but listener is attached to a background thread. We need feedback on the UI thread and need the test to be blocking.  Also, a bad Internet connection causes a basemap to fail to load in the same way a bad API key does and we have to be able to distinguish between the two problems. Anyway, using a variation on your idea, I came up with the code below. The method "testApiKey(String key)" runs in the foreground, is blocking (with a timeout) and returns true if the key is good and false if it is bad. The "BaseMapLoadStatus" is a helper class for debugging.

public class BaseMapLoadStatus {
    private static final Logger log = LoggerFactory.getLogger(BaseMapLoadStatus.class);

    private Timestamp timestamp = Timestamp.from(Instant.now());
    private LoadStatus loadStatus = LoadStatus.LOADING;

    public BaseMapLoadStatus(LoadStatus loadStatus) {
        this.timestamp = Timestamp.from(Instant.now());
        this.loadStatus = loadStatus;
    }

    public BaseMapLoadStatus(Timestamp timestampLoadStatus loadStatus) {
        this.timestamp = timestamp;
        this.loadStatus = loadStatus;
    }

    public String getName() {
        return loadStatus.name();
    }

    public LoadStatus getLoadStatus() {
        return loadStatus;
    }

    public Timestamp getTimestamp() {
        return timestamp;
    }
 
    public static boolean testApiKey(String keythrows InterruptedException { 
        log.info("Using API key {}"key);
        ArcGISRuntimeEnvironment.setApiKey(key);
        String sUrl = "https://basemaps-api.arcgis.com";
        final int MAX_WAIT_TIME = 2000// millisecs

        try {
            URL urlObj = new URL(sUrl);
            HttpURLConnection con = (HttpURLConnectionurlObj.openConnection();
            con.setRequestMethod("GET");
            con.setConnectTimeout(MAX_WAIT_TIME);
            con.connect();
 
            int code = con.getResponseCode();
            if (code != 200) {
                log.error("Unable to connect to ESRI basemaps API site \"{}\""sUrl);
                return false;
            }
        } catch (Exception e) {
            log.error("Exception ecountered while trying to connect to the ESRI basemaps API site \"{}\": {}"sUrle.getMessage());
            return false;
        }

        final MapView mapView = new MapView();
        final int INTERVAL = 100;
        int waitTime = 0;
        final ArcGISMap map = new ArcGISMap(BasemapStyle.ARCGIS_IMAGERY);
        final HashMap<StringBaseMapLoadStatusloadStatusMap = new HashMap<>();
        final BaseMapLoadStatus ls = new BaseMapLoadStatus(LoadStatus.NOT_LOADED);
        loadStatusMap.put(ls.getName(), ls);
        map.addLoadStatusChangedListener(e -> {
            BaseMapLoadStatus ls1 = new BaseMapLoadStatus(e.getNewLoadStatus());
            loadStatusMap.put(ls1.getName(), ls1);
        });
        mapView.setMap(map);
        log.debug("Waiting for map to load");
        while(waitTime < MAX_WAIT_TIME && !loadStatusMap.containsKey(LoadStatus.LOADED.name())) {
            Thread.sleep(100);
            waitTime += INTERVAL;
            log.debug("Waiting {} msecs"waitTime);
        }
        if (waitTime >= MAX_WAIT_TIME) {
            log.error("Loading of base map timed out. Waited {} msecs for map to load"waitTime);
            return false;
        }
        List<BaseMapLoadStatussorted = ls.sortByTimestamp(loadStatusMap);
        log.debug("Load status change of states:");
        for (BaseMapLoadStatus bmls : sorted) {
            log.debug("{} {}"bmls.getTimestamp(), bmls.getName());
        }
        return loadStatusMap.containsKey(LoadStatus.LOADED.name());
    }
 

 

0 Kudos