/* 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.schema.CfgContext; import com.esri.gpt.catalog.schema.NamespaceContextImpl; import com.esri.gpt.catalog.schema.Namespaces; import com.esri.gpt.catalog.schema.Schema; import com.esri.gpt.framework.util.Val; import com.esri.gpt.framework.xml.DomUtil; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; /** * A collection of indexable properties associated with a metadata schema. */ public class Indexables { /** class variables ========================================================= */ /** Logger */ private static Logger LOGGER = Logger.getLogger(Indexables.class.getName()); /** instance variables ====================================================== */ private IndexableContext indexableContext; private Namespaces namespaces; private List<IndexableProperty> properties; private List<Indexables> siblings; /** constructors ============================================================ */ /** Default constructor. */ public Indexables() {} /** * Construct by duplicating an existing object. * @param objectToDuplicate the object to duplicate */ public Indexables(Indexables objectToDuplicate) { if (objectToDuplicate == null) { } else { if (objectToDuplicate.getNamespaces() != null) { this.setNamespaces(new Namespaces(objectToDuplicate.getNamespaces())); } if (objectToDuplicate.getProperties() != null) { if (this.getProperties() == null) { this.setProperties(new ArrayList<IndexableProperty>()); } for (IndexableProperty property: objectToDuplicate.getProperties()) { this.getProperties().add(new IndexableProperty(property)); } } if (objectToDuplicate.getSiblings() != null) { if (this.getSiblings() == null) { this.setSiblings(new ArrayList<Indexables>()); } for (Indexables sibling: objectToDuplicate.getSiblings()) { this.getSiblings().add(new Indexables(sibling)); } } } } /** properties ============================================================== */ /** * Gets the indexable context. * @return the indexable context */ public IndexableContext getIndexableContext() { return this.indexableContext; } /** * Sets the indexable context. * @param context the indexable context */ public void setIndexableContext(IndexableContext context) { this.indexableContext = context; } /** * Gets the namespaces for XPath evaluation. * @return the namespaces */ public Namespaces getNamespaces() { return this.namespaces; } /** * Sets the namespaces for XPath evaluation. * @param namespaces the namespaces */ public void setNamespaces(Namespaces namespaces) { this.namespaces = namespaces; } /** * Gets the child properties. * @return the child properties */ public List<IndexableProperty> getProperties() { return this.properties; } /** * Sets the child properties. * @param properties the child properties */ public void setProperties(List<IndexableProperty> properties) { this.properties = properties; } /** * Gets the list of associated siblings. * @return the siblings */ public List<Indexables> getSiblings() { return this.siblings; } /** * Sets the list of associated siblings. * @param siblings the siblings */ public void setSiblings(List<Indexables> siblings) { this.siblings = siblings; } /** methods ================================================================= */ /** * Adds a sibling. * @param sibling the sibling to add */ public void addSibling(Indexables sibling) { if (sibling != null) { if (this.getSiblings() == null) { this.setSiblings(new ArrayList<Indexables>()); } this.getSiblings().add(sibling); } } /** * Configures the object based upon a node loaded from a * schema configuration XML. * <p/> * The following attributes are configured: * <br/>fileName * <p/> * The following child nodes are configured: * <br/>namespace 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) { // loop through the child nodes 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()); // configure namespaces if (nodeName.equalsIgnoreCase("namespace")) { if (this.getNamespaces() == null) { this.setNamespaces(new Namespaces()); } this.getNamespaces().add(context.getFactory().newNamespace(context,nd)); // configure properties } else if (nodeName.equalsIgnoreCase("property")) { if (this.getProperties() == null) { this.setProperties(new ArrayList<IndexableProperty>()); } IndexableProperty property = new IndexableProperty(); property.configure(context,nd,nd.getAttributes()); this.getProperties().add(property); } } } String fileName = Val.chkStr(DomUtil.getAttributeValue(attributes,"fileName")); if (fileName.length() > 0) { String err = "Unable to load indexables: "+fileName; try { Document dom = DomUtil.makeDomFromResourcePath(fileName,false); NodeList nli = dom.getElementsByTagName("indexables"); if ((nli == null) || (nli.getLength() == 0)) { LOGGER.log(Level.CONFIG,"No <indexables> elements were found in: "+fileName); } else { for (int i=0;i<nli.getLength();i++) { Node nd = nli.item(i); Indexables idxables = new Indexables(); idxables.configure(context,nd,nd.getAttributes()); if (idxables.hasPropertiesOrSiblings()) { this.addSibling(idxables); } } } } catch (ParserConfigurationException e) { LOGGER.log(Level.SEVERE,err,e); } catch (SAXException e) { LOGGER.log(Level.SEVERE,err,e); } catch (IOException e) { LOGGER.log(Level.SEVERE,err,e); } } } /** * Evaluates indexable properties based upon the supplied metadata document. * @param schema the schema being evaluated * @param dom the metadata document * @param context the active indexable context * @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, XPath xpath) throws XPathExpressionException { // determine the local XPath XPath localXPath = xpath; if (this.getNamespaces() != null) { NamespaceContextImpl ns = new NamespaceContextImpl(this.getNamespaces()); localXPath = XPathFactory.newInstance().newXPath(); localXPath.setNamespaceContext(ns); } // evaluate and resolve properties if (this.getProperties() != null) { for (IndexableProperty property: this.getProperties()) { property.evaluate(schema,context,dom,null,localXPath); } for (IndexableProperty property: this.getProperties()) { property.resolve(schema,context,null); } } // evaluate siblings if (this.getSiblings() != null) { for (Indexables sibling: this.getSiblings()) { sibling.evaluate(schema,context,dom,xpath); } } } /** * Determines if properties of siblings have been configured for this set. * @return <code>true</code> if properties of siblings have been configured */ public boolean hasPropertiesOrSiblings() { if ((this.getProperties() != null) && (this.getProperties().size() > 0)) { return true; } else if ((this.getSiblings() != null) && (this.getSiblings().size() > 0)) { return true; } else { return false; } } }