Package com.esri.gpt.control.publication

Source Code of com.esri.gpt.control.publication.ResourceReader

/* See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* Esri Inc. licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.esri.gpt.control.publication;
import com.esri.gpt.framework.http.HttpClientRequest;
import com.esri.gpt.framework.util.Val;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.XML;

/**
* Reads the XML content associated with a resource. The source for the resource can be an XML file,
* an XML HTTP response file, or an ArcGIS JSON response.
*/
public class ResourceReader {
 
  /** class variables ========================================================= */
 
  /** The Logger. */
  private static Logger LOGGER = Logger.getLogger(ResourceReader.class.getName());
 
  /** instance variables ====================================================== */
  private ArrayList<String> agsServiceUrls = new ArrayList<String>();
  private boolean           autoRecurse = true;
  private String            baseUrl = "";
  private String            systemId = "";
  private boolean           wasJson = false;
 
  /** Default constructor. */
  public ResourceReader() {}
 
  /** properties ============================================================== */
 
  /**
   * Gets a list of ArcGIS server service URLs associated with the last
   * ArcGIS server or folder read.
   * @return the list of urls
   */
  public List<String> getAgsServiceUrls() {
    return this.agsServiceUrls;
  }
 
  /** methods ================================================================= */
 
  /**
   * Reads a JSON response from an ArcGIS server Rest end-point.
   * <br/>The supplied rest URL will be appended with "f=json" if required.
   * @param restUrl the rest URL to the ArcGIS service
   * @return a JSON object representing the response
   * @throws MalformedURLException if the URL is invalid
   * @throws IOException if the communication fails
   * @throws JSONException if a non-empty response could not be
   *         loaded as a JSON onject
   */
  private JSONObject readAgsJson(String restUrl)
    throws MalformedURLException, IOException, JSONException {
    if (!restUrl.toLowerCase().startsWith("http")) return null;
     
    // ensure that we are asking for a JSON response
    if ((restUrl.toLowerCase().indexOf("f=json") == -1) &&
        (restUrl.toLowerCase().indexOf("f=pjson") == -1)) {
      if (restUrl.indexOf("?") == -1) {
        restUrl += "?f=json";
      } else {
        restUrl += "&f=json";
      }
    }
    LOGGER.finer("Attempting to read ArcGIS Server JSON response for:\n"+restUrl);
   
    HttpClientRequest client = HttpClientRequest.newRequest();
    client.setUrl(restUrl);
    String sResponse = Val.chkStr(client.readResponseAsCharacters());
   
    // attempt to create a JSON object from the response
    if (sResponse.length() > 0) {
      JSONObject jso = new JSONObject(sResponse);
      this.wasJson = true;
      return jso;
    }
    return null;
  }
   
  /**
   * Reads a JSON response from an ArcGIS server Rest end-point and converts it to an
   * XML string.
   * @param url the rest URL to the ArcGIS service
   * @return the rest response as an XML String
   * @throws MalformedURLException if the URL is invalid
   * @throws IOException if the communication fails
   * @throws JSONException if a non-empty response could not be
   *         loaded as a JSON onject or conversion to XML fails
   * @throws TransformerFactoryConfigurationError configuration related exception
   * @throws TransformerException transformation related exception
   */
  private String readAgsXml(String url)
    throws MalformedURLException, IOException, JSONException,
           TransformerFactoryConfigurationError, TransformerException {
    String xml = "";
    JSONObject jso = readAgsJson(url);
    if (jso != null) {
      try {
        JSONObject jsoError = jso.getJSONObject("error");
        if (jsoError != null) {
          throw new IOException(jsoError.toString());
        }
      } catch (JSONException e) {}

      if (autoRecurse) {
        parseAgsTree(jso);
        for (String service: this.agsServiceUrls) System.err.println(service);
      }
      xml = toAgsXml(jso);
      LOGGER.finer("ArcGIS Rest/JSON to XML\n"+xml);
    }
    return xml;
  }
 
  /**
   * Fully reads the characters from an input stream.
   * @param stream the input stream
   * @param charset the encoding of the input stream
   * @return the characters read
   * @throws IOException if an exception occurs
   */
  private String readCharacters(InputStream stream, String charset)
    throws IOException {
    StringBuffer sb = new StringBuffer();
    BufferedReader br = null;
    InputStreamReader ir = null;
    try {
      if ((charset == null) || (charset.trim().length() == 0)) charset = "UTF-8";
      char cbuf[] = new char[2048];
      int n = 0;
      int nLen = cbuf.length;
      ir = new InputStreamReader(stream,charset);
      br = new BufferedReader(ir);
      while ((n = br.read(cbuf,0,nLen)) > 0) sb.append(cbuf,0,n);
    } finally {
      try {if (br != null) br.close();} catch (Exception ef) {}
      try {if (ir != null) ir.close();} catch (Exception ef) {}
    }
    return sb.toString();
  }
 
  /**
   * Reads the XML content behind a file or URL.
   * <br/>If the content returns is ArcGIS/JSON, the JSON object is converted to XML.
   * @param systemId the system id of the source (file path or URL)
   * @return the associated XML
   * @throws Exception if an exception occurs
   */
  public String readXml(String systemId) throws Exception {
   
    // initialize
    String xml = "";
    this.systemId = Val.chkStr(systemId);
    this.baseUrl = "";
    this.agsServiceUrls = new ArrayList<String>();
    boolean isHttp = false;
    try {
      URL url = new URL(systemId);
      String tmp = url.getProtocol();
      isHttp = (tmp != null) && (tmp.equals("http") || tmp.equals("https"));
    } catch (MalformedURLException e) {
      isHttp = false;
    }
    if (isHttp) {
      this.baseUrl = this.systemId;
      int nIdx = this.baseUrl.indexOf("?");
      if (nIdx != -1) this.baseUrl = this.baseUrl.substring(0,nIdx);
     
      // guess which to try first
      boolean tryAgsFirst = false;
      if (this.baseUrl.length() > 0) {
        String lc = this.systemId.toLowerCase();
        if (lc.indexOf("/rest/") != -1) {
          if (lc.indexOf("service=") == -1) tryAgsFirst = true;
        }
      }
     
      // execute
      HttpClientRequest client = HttpClientRequest.newRequest();
      client.setUrl(this.systemId);
      if (tryAgsFirst) {
        try {
          xml = this.readAgsXml(this.systemId);
        } catch (Exception e) {
          if (this.wasJson) {
            throw e;
          } else {
            String result = client.readResponseAsCharacters();
            StringReader reader = new StringReader(result);
            StringWriter writer = new StringWriter();
            transform(new StreamSource(reader),new StreamResult(writer));
            xml = Val.chkStr(writer.toString());
          }
        }
       
      } else {
        try {
          String result = client.readResponseAsCharacters();
          StringReader reader = new StringReader(result);
          StringWriter writer = new StringWriter();
          transform(new StreamSource(reader),new StreamResult(writer));
          xml = Val.chkStr(writer.toString());
        } catch (TransformerException te) {
          try {
            xml = this.readAgsXml(this.systemId);
          } catch (MalformedURLException mue) {
            throw te;
          } catch (JSONException e) {
            throw te;
          }
        }
      }
     
    } else {
     
      // read the contexts of a file path     
      StringWriter writer = new StringWriter();
      transform(new StreamSource(this.systemId),new StreamResult(writer)) ;
      xml = Val.chkStr(writer.toString());
    }
   
    return xml;
  }
 
  /**
   * Recursively parses an ArcGIS service tree.
   * <br/>Located services are appended to the "agsServicePaths" list.
   * @param jsoParent the JSON parent object (the server or a folder)
   */
  private void parseAgsTree(JSONObject jsoParent) {
   
    // parse folders if present
    ArrayList<String> folders = new ArrayList<String>();
    try {
      JSONArray jsoFolders = jsoParent.getJSONArray("folders");
      if (jsoFolders != null) {
        for (int i=0;i<jsoFolders.length();i++) {
          String name = Val.chkStr(jsoFolders.getString(i));
          if (name.length() > 0) {
            folders.add(this.baseUrl+"/"+name);
          }
        }
      }
    } catch (JSONException e) {
      LOGGER.finest("No ArcGIS folders: "+e.toString());
    }
   
    // parse services if present
    try {
      JSONArray jsoServices = jsoParent.getJSONArray("services");
      if (jsoServices != null) {
        for (int i=0;i<jsoServices.length();i++) {
          JSONObject service = jsoServices.getJSONObject(i);
          if (service != null) {
            String name = Val.chkStr(service.getString("name"));
            String type = Val.chkStr(service.getString("type"));
           
            // for some reason, service names within a folder are partial paths
            // e.g baseurl = http://server.arcgisonline.com/ArcGIS/rest/services/Elevation
            // name = Elevation/ESRI_Elevation_World
            if (name.lastIndexOf("/") != -1) {
              if (this.baseUrl.lastIndexOf("/") != -1) {
                String folder = this.baseUrl.substring(this.baseUrl.lastIndexOf("/")+1);
                if (name.startsWith(folder+"/")) {
                  name = name.substring(name.lastIndexOf("/")+1);
                }
              }
            }
           
            if ((name.length() > 0) && (type.length() > 0)) {
              this.agsServiceUrls.add(this.baseUrl+"/"+name+"/"+type);
            }
          }
        }
      }
    } catch (JSONException e) {
      LOGGER.finest("No ArcGIS services: "+e.toString());
    }
   
    // recurse folders
    for (String folder: folders) {
      try {
        JSONObject jsoFolder = readAgsJson(folder);
        if (jsoFolder != null) {
          parseAgsTree(jsoFolder);
        }
      } catch (MalformedURLException e) {
        LOGGER.finer("Error reading folder: "+folder+", urlerr="+e.toString());
      } catch (IOException e) {
        LOGGER.finer("Error reading folder: "+folder+", ioerr="+e.toString());
      } catch (JSONException e) {
        LOGGER.finer("Error reading folder: "+folder+", jsonerr="+e.toString());
      }
    }
       
  }
 
  /**
   * Create an XML string from an ArcGIS Rest response.
   * <br/>The XML string is wrappoed in a parent tag <ags-rest>.
   * @param jso the JSON object representing the response
   * @return the XML String
   * @throws JSONException if the JDON object cannot be converted to an XML
   * @throws TransformerFactoryConfigurationError configuration related exception
   * @throws TransformerException transformation related exception
   */
  private String toAgsXml(JSONObject jso)
    throws JSONException, TransformerFactoryConfigurationError, TransformerException {
    String xml = XML.toString(jso,"ags-rest");
    StreamSource source = new StreamSource(new StringReader(xml));
    StringWriter writer = new StringWriter();
    StreamResult result = new StreamResult(writer);
    Transformer transformer = TransformerFactory.newInstance().newTransformer();
    transformer.setOutputProperty(OutputKeys.ENCODING,"UTF-8");
    transformer.setOutputProperty(OutputKeys.INDENT,"yes");
    transformer.transform(source,result);
    return Val.chkStr(writer.toString());
  }
 
  /**
   * Executes a transformation.
   * <br/>The output encoding is set to UTF-8
   * <br/>The indent is set to "yes"
   * @param source the transformation source
   * @param result the transformation result
   * @throws TransformerException if an exception occurs
   */
  private void transform(javax.xml.transform.Source source,
                         javax.xml.transform.Result result)
    throws TransformerException {
    Transformer transformer = TransformerFactory.newInstance().newTransformer() ;
    transformer.setOutputProperty(OutputKeys.ENCODING,"UTF-8");
    transformer.setOutputProperty(OutputKeys.INDENT,"yes");
    transformer.transform(source,result);
  }
 
}
TOP

Related Classes of com.esri.gpt.control.publication.ResourceReader

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.