Package com.esri.gpt.server.csw.provider

Source Code of com.esri.gpt.server.csw.provider.GetRecordsProvider

/* 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.server.csw.provider;
import com.esri.gpt.framework.util.Val;
import com.esri.gpt.framework.xml.DomUtil;
import com.esri.gpt.server.csw.provider.components.CswConstants;
import com.esri.gpt.server.csw.provider.components.CswNamespaces;
import com.esri.gpt.server.csw.provider.components.ICqlParser;
import com.esri.gpt.server.csw.provider.components.IFilterParser;
import com.esri.gpt.server.csw.provider.components.IOperationProvider;
import com.esri.gpt.server.csw.provider.components.IProviderFactory;
import com.esri.gpt.server.csw.provider.components.IQueryEvaluator;
import com.esri.gpt.server.csw.provider.components.IResponseGenerator;
import com.esri.gpt.server.csw.provider.components.ISortByParser;
import com.esri.gpt.server.csw.provider.components.ISupportedValues;
import com.esri.gpt.server.csw.provider.components.OperationContext;
import com.esri.gpt.server.csw.provider.components.OwsException;
import com.esri.gpt.server.csw.provider.components.ParseHelper;
import com.esri.gpt.server.csw.provider.components.QueryOptions;
import com.esri.gpt.server.csw.provider.components.ServiceProperties;
import com.esri.gpt.server.csw.provider.components.SupportedValues;
import com.esri.gpt.server.csw.provider.components.ValidationHelper;

import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
* Provides the CSW GetRecords operation.
*/
public class GetRecordsProvider implements IOperationProvider {
   
  /** class variables ========================================================= */
 
  /** The Logger. */
  private static Logger LOGGER = Logger.getLogger(GetRecordsProvider.class.getName());
   
  /** constructors ============================================================ */
 
  /** Default constructor */
  public GetRecordsProvider() {
    super();
  }

  /** methods ================================================================= */
 
  /**
   * Builds an ogc:Filter node from HTTP GET parameters.
   * @param namespace the namespace parameter values
   * @param constraintFilter the constraint parameter value
   * @throws Exception if a processing exception occurs
   */
  protected Node buildFilterNode(String[] namespace, String constraintFilter) throws Exception {
   
    // TODO GetRecordsDomBuilder had a different pattern??
   
    // parse namespaces
    // pattern: namespace=xmlns(ogc=http://www.opengis.net/ogc),xmlns(gml=http://www.opengis.net/gml)...
    StringBuilder nsBuffer = new StringBuilder();
    boolean hasCswUri = false;
    boolean hasCswPfx = false;
    String cswPfx = "";
    if (namespace != null) {
      for (String ns: namespace) {
        ns = Val.chkStr(ns);
        String nsPfx = null;
        String nsUri = null;
       
        if (ns.toLowerCase().startsWith("xmlns(")) {
          ns = ns.substring(6);
          if (ns.toLowerCase().endsWith(")")) {
            ns = ns.substring(0,ns.length() - 1);
          }
          ns = Val.chkStr(ns);
          if (ns.length() > 0) {
            String[] pair = ns.split("=");
            if (pair.length == 1) {
              nsUri = Val.chkStr(pair[0]);
            } else if (pair.length == 2) {
              nsPfx = Val.chkStr(pair[0]);
              nsUri = Val.chkStr(pair[1]);
            }
          }
        }
        if ((nsUri == null) || (nsUri.length() == 0)) {
          String msg = "The namespace must follow the following pattern:";
          msg += " xmlns(pfx1=uri1),xmlns(pfx2=uri2),...";
          throw new OwsException(OwsException.OWSCODE_InvalidParameterValue,"namespace",msg);
        } else {
          if (nsUri.equals("http://www.opengis.net/cat/csw/")) {
            hasCswUri = true;
            if ((nsPfx != null) && (nsPfx.length() > 0)) {
              hasCswPfx = true;
              cswPfx = nsPfx;
            }
          }
          nsUri = Val.escapeXml(nsUri);
          if ((nsPfx == null) || (nsPfx.length() == 0)) {
            nsBuffer.append(" xmlns=\"").append(nsUri).append("\"");
          } else {
            nsBuffer.append(" xmlns:").append(nsPfx).append("=\"").append(nsUri).append("\"");
          }
        }
      }
    }  
   
    // use ogc as the default namespace if no namespace parameter was supplied
    if (nsBuffer.length() == 0) {
      nsBuffer.append(" xmlns=\"http://www.opengis.net/ogc\"");
    }
   
    // build the constraint XML
    StringBuilder sbXml = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
    if (hasCswUri && hasCswPfx) {
      cswPfx = cswPfx+":";
    } else if (hasCswUri) {
      cswPfx = "";
    } else {
      cswPfx = "csw:";
      nsBuffer.append(" xmlns:csw=\"http://www.opengis.net/cat/csw/2.0.2\"");
    }
    sbXml.append("\r\n<").append(cswPfx).append("Constraint");
    if (nsBuffer.length() > 0) {
      sbXml.append(" ").append(nsBuffer);
    }
    sbXml.append(">");
    sbXml.append("\r\n").append(constraintFilter);
    sbXml.append("\r\n</").append(cswPfx).append("Constraint>");
   
    // make the dom, find the ogc:Filter node
    try {
      Document dom = DomUtil.makeDomFromString(sbXml.toString(),true);
      CswNamespaces ns = new CswNamespaces();
      XPath xpath = XPathFactory.newInstance().newXPath();
      xpath.setNamespaceContext(ns.makeNamespaceContext());
     
      Node ndFilter = null;
      Node ndConstraint = (Node)xpath.evaluate("csw:Constraint",dom,XPathConstants.NODE);
      if (ndConstraint != null) {
        ndFilter = (Node)xpath.evaluate("ogc:Filter",ndConstraint,XPathConstants.NODE);;
      }
      if (ndFilter == null) {
        String msg = "The supplied constraint was not a valid ogc:Filter.";
        throw new OwsException(OwsException.OWSCODE_NoApplicableCode,"constraint",msg);
      } else {
        return ndFilter;
      }
     
    } catch (SAXException e) {
      String msg = "The supplied namespace/constraint pairs were not well-formed xml: ";
      msg += " "+e.toString();
      throw new OwsException(OwsException.OWSCODE_NoApplicableCode,"constraint",msg);
    }
   
  }
 
  /**
   * Builds an ogc:SortBy node from HTTP GET parameters.
   * @param sortBy the sortBy parameter values
   * @throws Exception if a processing exception occurs
   */
  protected Node buildSortByNode(String[] sortBy) throws Exception {
   
    // parse sort by parameters
    // pattern: sortby=property1:A,property2:D...
   
    if (sortBy != null) {
      StringBuilder sbXml = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
      sbXml.append("\r\n<ogc:SortBy xmlns:ogc=\"http://www.opengis.net/ogc\">");
      boolean hadProperty = false;
      for (String param: sortBy) {
        param = Val.chkStr(param);
        String name = null;
        String dir = null;
        if (param.toLowerCase().endsWith(":a")) {
          name = Val.chkStr(param.substring(0,param.length() - 2));
          dir= "ASC";
        } else if (param.toLowerCase().endsWith(":d")) {
          name = Val.chkStr(param.substring(0,param.length() - 2));
          dir = "DESC";
        } else {
          name = Val.chkStr(param);
        }
        if ((name == null) || (name.length() == 0)) {
          // we'll ignore this condition without an exception
        } else {
          hadProperty = true;
          sbXml.append("\r\n<ogc:SortProperty>");
          sbXml.append("\r\n<ogc:PropertyName>").append(Val.escapeXml(name)).append("</ogc:PropertyName>");
          if (dir != null) {
            sbXml.append("\r\n<ogc:SortOrder>").append(Val.escapeXml(dir)).append("</ogc:SortOrder>");
          }
          sbXml.append("\r\n</ogc:SortProperty>");
        }
      }
      sbXml.append("\r\n</ogc:SortBy>");
      if (hadProperty) {
        Document dom = DomUtil.makeDomFromString(sbXml.toString(),true);
        NodeList nl = dom.getChildNodes();
        for (int i=0; i<nl.getLength(); i++) {
          if (nl.item(i).getNodeType() == Node.ELEMENT_NODE){
            return nl.item(i);
          }
        }
      }
    }
    return null;
  }
 
  /**
   * Executes a parsed operation request.
   * @param context the operation context
   * @throws Exception if a processing exception occurs
   */
  public void execute(OperationContext context) throws Exception {
   
    // initialize
    LOGGER.finer("Executing csw:GetRecords request...");
    IProviderFactory factory = context.getProviderFactory();
   
    // evaluate the query
    IQueryEvaluator evaluator = factory.makeQueryEvaluator(context);
    if (evaluator == null) {
      String msg = "IProviderFactory.makeQueryEvaluator: instantiation failed.";
      LOGGER.log(Level.SEVERE,msg);
      throw new OwsException(msg);
    } else {
      evaluator.evaluateQuery(context);
    }
   
    // generate the response
    IResponseGenerator generator = factory.makeResponseGenerator(context);
    if (generator == null) {
      String msg = "IProviderFactory.makeResponseGenerator: instantiation failed.";
      LOGGER.log(Level.SEVERE,msg);
      throw new OwsException(msg);
    } else {
      generator.generateResponse(context);
    }
     
  }
 
  /**
   * Handles a URL based request (HTTP GET).
   * @param context the operation context
   * @param request the HTTP request
   * @throws Exception if a processing exception occurs
   */
  public void handleGet(OperationContext context, HttpServletRequest request)
    throws Exception {
   
    // initialize
    LOGGER.finer("Handling csw:GetRecords request URL...");
    QueryOptions qOptions = context.getRequestOptions().getQueryOptions();
    ServiceProperties svcProps = context.getServiceProperties();
    ParseHelper pHelper = new ParseHelper();
    ValidationHelper vHelper = new ValidationHelper();
    String locator;
    String[] parsed;
    ISupportedValues supported;
    IProviderFactory factory = context.getProviderFactory();
   
    CswNamespaces ns = new CswNamespaces();
    XPath xpath = XPathFactory.newInstance().newXPath();
    xpath.setNamespaceContext(ns.makeNamespaceContext());
   
    // service and version are parsed by the parent RequestHandler
   
    // TODO typeNames requestId distributedSearch hopCount responseHandler
    // TODO resultype validate is not applicable for a GET request?
   
    // output format
    locator = "outputFormat";
    parsed = pHelper.getParameterValues(request,locator);
    supported = svcProps.getSupportedValues(CswConstants.Parameter_OutputFormat);
    context.getOperationResponse().setOutputFormat(
        vHelper.validateValue(supported,locator,parsed,false));
       
    // output schema
    locator = "outputSchema";
    parsed = pHelper.getParameterValues(request,locator);
    supported = svcProps.getSupportedValues(CswConstants.Parameter_OutputSchema);
    qOptions.setOutputSchema(vHelper.validateValue(supported,locator,parsed,false));
   
    // start and max records
    parsed = pHelper.getParameterValues(request,"startPosition");
    if ((parsed != null) && (parsed.length) > 0) {
      qOptions.setStartRecord(Math.max(Val.chkInt(parsed[0],1),1));
    }
    parsed = pHelper.getParameterValues(request,"maxRecords");
    if ((parsed != null) && (parsed.length) > 0) {
      qOptions.setMaxRecords(Val.chkInt(parsed[0],10));
    }
   
    // result type
    locator = "resultType";
    parsed = pHelper.getParameterValues(request,locator);
    supported = svcProps.getSupportedValues(CswConstants.Parameter_ResultType);
    qOptions.setResultType(vHelper.validateValue(supported,locator,parsed,false));
    if (qOptions.getResultType() == null) {
      qOptions.setResultType(CswConstants.ResultType_Hits);
    }
   
    // query type names
    locator = "typeNames";
    parsed = pHelper.getParameterValues(request,locator);
    qOptions.setQueryTypeNames(vHelper.validateValues(locator,parsed,false));
   
    // response element set type
    locator = "ElementSetName";
    parsed = pHelper.getParameterValues(request,locator);
    supported = svcProps.getSupportedValues(CswConstants.Parameter_ElementSetType);
    qOptions.setElementSetType(vHelper.validateValue(supported,locator,parsed,false));
   
    // response element names
    if (qOptions.getElementSetType() == null) {
      // TODO supported ElementNames this for GetRecordById as well?
      locator = "ElementName";
      parsed = pHelper.getParameterValues(request,locator,",");
      supported = svcProps.getSupportedValues(CswConstants.Parameter_ElementName);
      qOptions.setElementNames(vHelper.validateValues(supported,locator,parsed,false));
    }
   
    // constraint language
    locator = "constraintLanguage";
    parsed = pHelper.getParameterValues(request,locator);
    supported = new SupportedValues("CQL_TEXT,FILTER",",");
    String constraintLanguage = vHelper.validateValue(supported,locator,parsed,false);
   
    // constraint version
    locator = "constraint_language_version";
    parsed = pHelper.getParameterValues(request,locator);
    String constraintVersion = vHelper.validateValue(locator,parsed,false);
    qOptions.setQueryConstraintVersion(constraintVersion);
   
    // constraint text
    locator = "constraint";
    parsed = pHelper.getParameterValues(request,locator);
    String constraint = vHelper.validateValue(locator,parsed,false);
   
    // csw:CqlText
    if ((constraintLanguage != null) && constraintLanguage.equalsIgnoreCase("CQL_TEXT")) {
      String cql = Val.chkStr(constraint);
      qOptions.setQueryConstraintCql(cql);
      ICqlParser parser = factory.makeCqlParser(context,constraintVersion);
      if (parser == null) {
        String msg = "IProviderFactory.makeCqlParser: instantiation failed.";
        throw new OwsException(OwsException.OWSCODE_NoApplicableCode,locator,msg);
      } else {
        parser.parseCql(context,cql);
      }
    }
   
    // ogc:Filter
    if ((constraintLanguage == null) || constraintLanguage.equalsIgnoreCase("FILTER")) {
      Node ndFilter = null;
      IFilterParser parser = factory.makeFilterParser(context,constraintVersion);
      if (parser == null) {
        String msg = "IProviderFactory.makeFilterParser: instantiation failed.";
        throw new OwsException(OwsException.OWSCODE_NoApplicableCode,locator,msg);
      }
      String constraintFilter = Val.chkStr(constraint);
      if (constraintFilter.length() > 0) {
        String[] namespace = pHelper.getParameterValues(request,"namespace",",");
        ndFilter = this.buildFilterNode(namespace,constraintFilter);
        parser.parseFilter(context,ndFilter,xpath);
      }
    }
   
    // ogc:SortBy
    locator = "sortBy";
    String[] sortBy = pHelper.getParameterValues(request,"sortBy",",");
    if (sortBy != null) {
      Node ndSortBy = this.buildSortByNode(sortBy);
      if (ndSortBy != null) {
        ISortByParser parser = factory.makeSortByParser(context);
        if (parser == null) {
          String msg = "IProviderFactory.makeSortByParser: instantiation failed.";
          throw new OwsException(OwsException.OWSCODE_NoApplicableCode,locator,msg);
        } else {
          parser.parseSortBy(context,ndSortBy,xpath);
        }
      }
    }
   
    // execute the request
    this.execute(context);
  }

  /**
   * Handles an XML based request (normally HTTP POST).
   * @param context the operation context
   * @param root the root node
   * @param xpath an XPath to enable queries (properly configured with name spaces)
   * @throws Exception if a processing exception occurs
   */
  public void handleXML(OperationContext context, Node root, XPath xpath)
    throws Exception {
   
    // initialize
    LOGGER.finer("Handling csw:GetRecords request XML...");
    QueryOptions qOptions = context.getRequestOptions().getQueryOptions();
    ServiceProperties svcProps = context.getServiceProperties();
    ParseHelper pHelper = new ParseHelper();
    ValidationHelper vHelper = new ValidationHelper();
    String locator;
    String[] parsed;
    ISupportedValues supported;
    IProviderFactory factory = context.getProviderFactory();
   
    // service and version are parsed by the parent RequestHandler
   
    // TODO requestId
       
    // output format
    locator = "@outputFormat";
    parsed = pHelper.getParameterValues(root,xpath,locator);
    supported = svcProps.getSupportedValues(CswConstants.Parameter_OutputFormat);
    context.getOperationResponse().setOutputFormat(
        vHelper.validateValue(supported,locator,parsed,false));
   
    // output schema
    locator = "@outputSchema";
    parsed = pHelper.getParameterValues(root,xpath,locator);
    supported = svcProps.getSupportedValues(CswConstants.Parameter_OutputSchema);
    qOptions.setOutputSchema(vHelper.validateValue(supported,locator,parsed,false));
   
    // start and max records
    qOptions.setStartRecord(Math.max(Val.chkInt(xpath.evaluate("@startPosition",root),1),1));
    qOptions.setMaxRecords(Val.chkInt(xpath.evaluate("@maxRecords",root),10))
   
    // result type
    locator = "@resultType";
    parsed = pHelper.getParameterValues(root,xpath,locator);
    supported = svcProps.getSupportedValues(CswConstants.Parameter_ResultType);
    qOptions.setResultType(vHelper.validateValue(supported,locator,parsed,false));
    if (qOptions.getResultType() == null) {
      qOptions.setResultType(CswConstants.ResultType_Hits);
    }
   
    // find the query node
    locator = "csw:Query";
    Node ndQuery = (Node)xpath.evaluate(locator,root,XPathConstants.NODE);
    if (ndQuery != null) {
   
      // query type names
      locator = "csw:Query/@typeNames";
      parsed = pHelper.getParameterValues(root,xpath,"@typeNames");
      qOptions.setQueryTypeNames(vHelper.validateValues(locator,parsed,false));
             
      // response element set type
      locator = "csw:ElementSetName";
      parsed = pHelper.getParameterValues(ndQuery,xpath,locator);
      supported = svcProps.getSupportedValues(CswConstants.Parameter_ElementSetType);
      qOptions.setElementSetType(vHelper.validateValue(supported,locator,parsed,false));
     
      // response element set type names
      String elementSetType = qOptions.getElementSetType();
      if (elementSetType != null) {
        locator = "csw:ElementSetName/@typeNames";
        parsed = pHelper.getParameterValues(ndQuery,xpath,locator);
        qOptions.setElementSetTypeNames(vHelper.validateValues(locator,parsed,false));
      }
     
      // response element names
      if (elementSetType == null) {
        // TODO supported ElementNames
        locator = "csw:ElementName";
        parsed = pHelper.getParameterValues(ndQuery,xpath,locator);
        supported = svcProps.getSupportedValues(CswConstants.Parameter_ElementName);
        qOptions.setElementNames(vHelper.validateValues(supported,locator,parsed,false));
      }
     
      // find the constraint node
      Node ndConstraint = (Node)xpath.evaluate("csw:Constraint",ndQuery,XPathConstants.NODE);
      if (ndConstraint != null) {
       
        // constraint version
        String constraintVersion = xpath.evaluate("@version",ndConstraint);
        qOptions.setQueryConstraintVersion(constraintVersion);
   
        // csw:CqlText
        locator = "csw:CqlText";
        Node ndCql = (Node)xpath.evaluate(locator,ndConstraint,XPathConstants.NODE);
        if (ndCql != null) {
          String cql = Val.chkStr(ndCql.getTextContent());
          qOptions.setQueryConstraintCql(cql);
          ICqlParser parser = factory.makeCqlParser(context,constraintVersion);
          if (parser == null) {
            String msg = "IProviderFactory.makeCqlParser: instantiation failed.";
            throw new OwsException(OwsException.OWSCODE_NoApplicableCode,locator,msg);
          } else {
            parser.parseCql(context,cql);
          }
        } else {
       
          // ogc:Filter
          locator = "ogc:Filter";
          Node ndFilter = (Node)xpath.evaluate(locator,ndConstraint,XPathConstants.NODE);
          if (ndFilter != null) {
            IFilterParser parser = factory.makeFilterParser(context,constraintVersion);
            if (parser == null) {
              String msg = "IProviderFactory.makeFilterParser: instantiation failed.";
              throw new OwsException(OwsException.OWSCODE_NoApplicableCode,locator,msg);
            } else {
              parser.parseFilter(context,ndFilter,xpath);
            }
          } else {
            String msg = "An OGC filter for the CSW constraint is required.";
            throw new OwsException(OwsException.OWSCODE_NoApplicableCode,locator,msg);
          }
        }
      }
     
      // ogc:SortBy
      locator = "ogc:SortBy";
      Node ndSortBy = (Node)xpath.evaluate(locator,ndQuery,XPathConstants.NODE);
      if (ndSortBy != null) {
        ISortByParser parser = factory.makeSortByParser(context);
        if (parser == null) {
          String msg = "IProviderFactory.makeSortByParser: instantiation failed.";
          throw new OwsException(OwsException.OWSCODE_NoApplicableCode,locator,msg);
        } else {
          parser.parseSortBy(context,ndSortBy,xpath);
        }
      }
    }
       
    // execute the request
    this.execute(context);
  }
   
}
TOP

Related Classes of com.esri.gpt.server.csw.provider.GetRecordsProvider

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.