Package com.esri.gpt.catalog.schema.indexable

Source Code of com.esri.gpt.catalog.schema.indexable.IndexableProperty

/* 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.catalog.schema.indexable;
import com.esri.gpt.catalog.discovery.Discoverable;
import com.esri.gpt.catalog.discovery.PropertyMeaning;
import com.esri.gpt.catalog.discovery.PropertyValueType;
import com.esri.gpt.catalog.schema.CfgContext;
import com.esri.gpt.catalog.schema.EsriTags;
import com.esri.gpt.catalog.schema.Schema;
import com.esri.gpt.catalog.search.ResourceIdentifier;
import com.esri.gpt.framework.geometry.Envelope;
import com.esri.gpt.framework.util.Val;
import com.esri.gpt.framework.xml.DomUtil;

import java.util.ArrayList;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
* An indexable property associated with a metadata schema.
*/
public class IndexableProperty {
 
  /** instance variables ====================================================== */
  private List<IndexableProperty> children;
  private List<String>            evaluatedValues;
  private String                  meaningName;
  private String                  xpathExpression;
  private String                  xpathType;
 
  /** constructors ============================================================ */
 
  /** Default constructor. */
  public IndexableProperty() {}
 
  /**
   * Construct by duplicating an existing object.
   * @param objectToDuplicate the object to duplicate
   */
  public IndexableProperty(IndexableProperty objectToDuplicate) {
    if (objectToDuplicate == null) {
    } else {
      this.setMeaningName(objectToDuplicate.getMeaningName());
      this.setXPathExpression(objectToDuplicate.getXPathExpression());
      this.setXPathType(objectToDuplicate.getXPathType());
      if (objectToDuplicate.getChildren() != null) {
        if (this.getChildren() == null) {
          this.setChildren(new ArrayList<IndexableProperty>());
        }
        for (IndexableProperty child: objectToDuplicate.getChildren()) {
          this.getChildren().add(new IndexableProperty(child));
        }
      }
    }
  }
 
  /** properties ============================================================== */
 
  /**
   * Gets the child properties.
   * @return the child properties
   */
  public List<IndexableProperty> getChildren() {
    return this.children;
  }
 
  /**
   * Sets the child properties.
   * @param children the child properties
   */
  public void setChildren(List<IndexableProperty> children) {
    this.children = children;
  }
 
  /**
   * Gets the first evaluated value.
   * @return the first evaluated value (can be null)
   */
  public String getEvaluatedValue() {
    if (this.getEvaluatedValues() != null) {
      for (String value: this.getEvaluatedValues()) {
        value = Val.chkStr(value);
        if (value.length() > 0) {
          return value;
        }
      }
    }
    return null;
  }
 
  /**
   * Gets the evaluated values.
   * @return the evaluated values
   */
  public List<String> getEvaluatedValues() {
    return this.evaluatedValues;
  }
  /**
   * Sets the evaluated values.
   * @param values the evaluated values
   */
  public void setEvaluatedValues(List<String> values) {
    this.evaluatedValues = values;
  }
 
  /**
   * Gets the meaning name.
   * @return the meaning name
   */
  public String getMeaningName() {
    return this.meaningName;
  }
  /**
   * Sets the meaning name.
   * @param name the meaning name
   */
  public void setMeaningName(String name) {
    this.meaningName = name;
  }
 
  /**
   * Gets the XPath expression.
   * @return the XPath expression
   */
  public String getXPathExpression() {
    return this.xpathExpression;
  }
  /**
   * Sets the XPath expression.
   * @param expression the XPath expression
   */
  public void setXPathExpression(String expression) {
    this.xpathExpression = expression;
 
 
  /**
   * Gets the XPath expression result type.
   * <br/>BOOLEAN NODE NODESET NUMBER STRING
   * @return the XPath expression result type
   */
  public String getXPathType() {
    return this.xpathType;
  }
  /**
   * Sets the XPath expression result type.
   * <br/>BOOLEAN NODE NODESET NUMBER STRING
   * @param xpathType the expression result type
   */
  public void setXPathType(String xpathType) {
    this.xpathType = xpathType;
 
 
  /** methods ================================================================= */

  /**
   * Adds an evaluated value to the collection.
   * @param context the active indexable context
   * @param meaning the associated property meaning
   * @param value the evaluated value
   */
  protected void addValue(IndexableContext context, PropertyMeaning meaning, String value) {
    value = Val.chkStr(value);
    if (value.length() > 0) {
      if (this.getEvaluatedValues() == null) {
        this.setEvaluatedValues(new ArrayList<String>());
      }
      this.getEvaluatedValues().add(value);
    }
  }
 
  /**
   * Configures the object based upon a node loaded from a
   * schema configuration XML.
   * <p/>
   * The following attributes are configured:
   * <br/>meaning xpathType xpath
   * <p/>
   * The following child nodes are configured:
   * <br/>property
   * @param context the configuration context
   * @param node the configuration node
   * @param attributes the attributes of the configuration node
   */
  public void configure(CfgContext context, Node node, NamedNodeMap attributes) {
    String mName = DomUtil.getAttributeValue(attributes,"meaning");
    if (Val.chkStr(mName).equalsIgnoreCase("anytext")) mName = "body";
    if (Val.chkStr(mName).equalsIgnoreCase("resource.type")) mName = "contentType";
    this.setMeaningName(mName);
    this.setXPathExpression(Val.chkStr(DomUtil.getAttributeValue(attributes,"xpath")));
    this.setXPathType(Val.chkStr(DomUtil.getAttributeValue(attributes,"xpathType")));
   
    // loop through the children
    NodeList nl = node.getChildNodes();
    for (int i=0;i<nl.getLength();i++) {
      Node nd = nl.item(i);
      if (nd.getNodeType() == Node.ELEMENT_NODE) {
        String nodeName = Val.chkStr(nd.getNodeName());
        if (nodeName.equalsIgnoreCase("property")) {
          if (this.getChildren() == null) {
            this.setChildren(new ArrayList<IndexableProperty>());
          }
          IndexableProperty child = new IndexableProperty();
          child.configure(context,nd,nd.getAttributes());
          this.getChildren().add(child);
        }
      }
    }
   
  }
 
  /**
   * Evaluates the property based upon the supplied metadata document.
   * @param schema the schema being evaluated
   * @param context the active indexable context
   * @param dom the metadata document
   * @param parent the metadata document node the is actively being processed (can be null)
   * @param xpath an XPath object configured with an appropriate
   *        Namespace context for the schema
   * @throws XPathExpressionException if an evaluation expression fails
   */
  public void evaluate(Schema schema,
                       IndexableContext context,
                       Document dom,
                       Node parent,
                       XPath xpath)
    throws XPathExpressionException {
   
    // initialize
    String mName = Val.chkStr(this.getMeaningName());
    String xpExpr = Val.chkStr(this.getXPathExpression());
    String xpType = Val.chkStr(this.getXPathType());
    boolean hasChildren = (this.getChildren() != null) && (this.getChildren().size() > 0);
   
    // determine the meaning
    PropertyMeaning meaning = null;
    if (mName.length() > 0) {
      meaning = context.getPropertyMeanings().get(mName);
      if (meaning == null) {
        Discoverable discoverable = context.getPropertyMeanings().getAllAliased().get(mName);
        if (discoverable != null) {
          meaning = discoverable.getMeaning();
        } else {
          // TODO warn if the meaning is null
        }
      }
    }
   
    // loop through children if no XPath expression was supplied
    if (xpExpr.length() == 0) {
      if (hasChildren) {
        for (IndexableProperty child: this.getChildren()) {
          child.evaluate(schema,context,dom,null,xpath);
        }
      }
     
    } else {
     
      // determine the starting context for the expression
      Object startItem = dom;
      if (parent != null) {
        if (!xpExpr.startsWith("/")) {
          startItem = parent;
        }
      }
     
      // determine the return type, BOOLEAN NODE NODESET NUMBER STRING
      QName returnType = null;
      if (xpType.equalsIgnoreCase("BOOLEAN")) {
        returnType = XPathConstants.BOOLEAN;
      } else if (xpType.equalsIgnoreCase("NODE")) {
        returnType = XPathConstants.NODE;
      } else if (xpType.equalsIgnoreCase("NODESET") ||
                 xpType.equalsIgnoreCase("NODELIST") ||
                 xpType.equalsIgnoreCase("LIST")) {
        returnType = XPathConstants.NODESET;
      } else if (xpType.equalsIgnoreCase("NUMBER")) {
        returnType = XPathConstants.NUMBER;
      } else if (xpType.equalsIgnoreCase("STRING")) {
        returnType = XPathConstants.STRING;
      } else {
        if (hasChildren) {
          returnType = XPathConstants.NODESET;
        } else {
          if (xpExpr.toLowerCase().endsWith("text()")) {
            returnType = XPathConstants.STRING;
          } else {
            returnType = XPathConstants.NODESET;
          }
        }
      }
     
      // evaluate the expression, process the result
      Object result = xpath.evaluate(xpExpr,startItem,returnType);
      if (result != null) {
       
        if (returnType.equals(XPathConstants.STRING)) {
          String value = (String)result;
          this.addValue(context,meaning,value);
        } else if (returnType.equals(XPathConstants.NUMBER)) {
          String value = ""+((Number)result);
          this.addValue(context,meaning,value);
        } else if (returnType.equals(XPathConstants.BOOLEAN)) {
          String value = ""+((Boolean)result);
          this.addValue(context,meaning,value);
         
        } else if (returnType.equals(XPathConstants.NODE)) {
          Node nd = (Node)result;
          String value = this.getTextContent(nd,true);
          this.addValue(context,meaning,value);
         
          if (hasChildren) {
            for (IndexableProperty child: this.getChildren()) {
              child.evaluate(schema,context,dom,nd,xpath);
            }
          }
         
        } else if (returnType.equals(XPathConstants.NODESET)) {
          NodeList nl = (NodeList)result;
          for (int i=0;i<nl.getLength();i++) {
            Node nd = nl.item(i);
            String value = this.getTextContent(nd,true);
            this.addValue(context,meaning,value);
           
            if (hasChildren) {
              for (IndexableProperty child: this.getChildren()) {
                child.evaluate(schema,context,dom,nd,xpath);
              }
            } 
          }
         
        }
      }   
    }
  }
 
  /**
   * Gets the text associated with a node.
   * @param node the subject node
   * @param first if true, get the first text node associated with an element node
   * @return the text (can be null)
   */
  protected String getTextContent(Node node, boolean first) {
    String text = null;
    if (node.getNodeType() == Node.ATTRIBUTE_NODE ) {
      text = node.getNodeValue();
    } else if (node.getNodeType() == Node.TEXT_NODE) {
      text = node.getNodeValue();
    } else if (node.getNodeType() == Node.CDATA_SECTION_NODE) {
      text = node.getNodeValue();
    } else if (node.getNodeType() == Node.ELEMENT_NODE) {
      if (first) {
        NodeList nl = node.getChildNodes();
        for (int i=0;i<nl.getLength();i++) { 
          Node nd = nl.item(i);
          if (nd.getNodeType() == Node.TEXT_NODE) {
            text = nd.getNodeValue();
          } else {
            break;
          }
        }
      } else {
        text = node.getTextContent();
      }
    }
    if (text != null) {
      text = Val.chkStr(text);
      if (text.length() == 0) {
        text = null;
      }
    }
    return text;
  }
 
  /**
   * Resolves an evaluated property.
   * @param schema the schema being evaluated
   * @param context the active indexable context
   * @param parent the parent property
   */
  public void resolve(Schema schema, IndexableContext context, IndexableProperty parent) {
   
    // initialize
    String mName = Val.chkStr(this.getMeaningName());
    boolean hasChildren = (this.getChildren() != null) && (this.getChildren().size() > 0);
    List<String> values = this.getEvaluatedValues();
   
    // determine the meaning
    PropertyMeaning meaning = null;
    if (mName.length() > 0) {
      meaning = context.getPropertyMeanings().get(mName);
      if (meaning == null) {
        Discoverable discoverable = context.getPropertyMeanings().getAllAliased().get(mName);
        if (discoverable != null) {
          meaning = discoverable.getMeaning();
        } else {
          // TODO warn if the meaning is null
        }
      }
    }
   
    // handle geometries
    if ((meaning != null) && (meaning.getValueType() != null)) {
      if (meaning.getValueType().equals(PropertyValueType.GEOMETRY)) {
        if (hasChildren) {
          hasChildren = false;
          Envelope envelope = new Envelope();
          for (IndexableProperty child: this.getChildren()) {
            String mn = Val.chkStr(child.getMeaningName());
            String ev = Val.chkStr(child.getEvaluatedValue());
            if (ev.length() > 0) {
              if (mn.equalsIgnoreCase("envelope.west")) {
                envelope.setMinX(ev);
              } else if (mn.equalsIgnoreCase("envelope.south")) {
                envelope.setMinY(ev);
              } else if (mn.equalsIgnoreCase("envelope.east")) {
                envelope.setMaxX(ev);
              } else if (mn.equalsIgnoreCase("envelope.north")) {
                envelope.setMaxY(ev);
              } else if (mn.equalsIgnoreCase("envelope.lowerCorner")) {
                String[] pt = ev.split(" ");
                if (pt.length == 2) {
                  envelope.setMinX(pt[0]);
                  envelope.setMinY(pt[1]);
                }
              } else if (mn.equalsIgnoreCase("envelope.upperCorner")) {
                String[] pt = ev.split(" ");
                if (pt.length == 2) {
                  envelope.setMaxX(pt[0]);
                  envelope.setMaxY(pt[1]);
                }
              }
            }
          }
          if (!envelope.isEmpty()) {
            context.addStoreableValue(meaning,envelope);
          }
        }
        return;
      }
    }
   
    // ArcIMS content type
    if ((meaning != null) && (values != null) && (values.size() > 0)) {
      if (Val.chkStr(meaning.getName()).equalsIgnoreCase("contentType")) {
        ArrayList<String> al = new ArrayList<String>();
        boolean changed = false;
        ResourceIdentifier ri = context.ensureResourceIdentifier();
        for (String value: values) {
          String s = Val.chkStr(ri.guessArcIMSContentTypeFromResourceType(value));
          if ((s != null) && (s.length() > 0)) {
            al.add(s);
            changed = true;
          } else {
            // TODO: allow non-enumerated values?
            al.add(value);
          }
        }
        if (changed) {
          this.setEvaluatedValues(al);
          values = this.getEvaluatedValues();
        }
      }
    }
   
    // data themes (ISO MD_TopicCategoryCode)
    if ((meaning != null) && (values != null) && (values.size() > 0)) {
      if (Val.chkStr(meaning.getName()).equalsIgnoreCase("dataTheme")) {
        ArrayList<String> al = new ArrayList<String>();
        boolean changed = false;
        for (String value: values) {
          String s = EsriTags.DATA_THEME_CODES.get(value);
          if ((s != null) && (s.length() > 0)) {
            al.add(s);
            changed = true;
          } else {
            // TODO: allow non-enumerated values?
            al.add(value);
          }
        }
        if (changed) {
          this.setEvaluatedValues(al);
          values = this.getEvaluatedValues();
        }
      }
    }
    
    // process the evaluated values
    if (this.getEvaluatedValues() != null) {
      boolean isSingleValued = false;
      if (isSingleValued) {
        String singleValue = Val.chkStr(this.getEvaluatedValue());
        if (singleValue.length() == 0) {
          this.setEvaluatedValues(null);
        } else {
          this.getEvaluatedValues().clear();
          this.addValue(context,meaning,singleValue);
        }
       
      } else {
        context.addStorableValues(meaning,this.getEvaluatedValues().toArray(new String[0]));
      }
    }
   
    // process the children
    if (hasChildren) {
      for (IndexableProperty child: this.getChildren()) {
        child.resolve(schema,context,this);
      }
    }
   
  }
 
}
TOP

Related Classes of com.esri.gpt.catalog.schema.indexable.IndexableProperty

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.