/* * eXist Open Source Native XML Database * * Copyright (C) 2001-06 Wolfgang M. Meier wolfgang@exist-db.org * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id$ */ package org.exist.client; import org.exist.collections.CollectionConfiguration; import org.exist.collections.CollectionConfigurationManager; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import org.xmldb.api.base.Collection; import org.xmldb.api.base.Resource; import org.xmldb.api.base.XMLDBException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import java.io.IOException; import java.util.ArrayList; import java.util.Enumeration; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Properties; import java.util.Set; /** * Class to represent a collection.xconf which holds the configuration data for a collection * * @author Adam Retter <adam.retter@devon.gov.uk> * @serial 2006-08-25 * @version 1.2 */ public class CollectionXConf { public final static String TYPE_QNAME = "qname"; public final static String TYPE_PATH = "path"; public final static String ACTION_INCLUDE = "include"; public final static String ACTION_EXCLUDE = "exclude"; private InteractiveClient client = null; //the client private String path = null; //path of the collection.xconf file Collection collection = null; //the configuration collection Resource resConfig = null; //the collection.xconf resource private LinkedHashMap customNamespaces = null; //custom namespaces private FullTextIndex fulltextIndex = null; //fulltext index model private RangeIndex[] rangeIndexes = null; //range indexes model private Trigger[] triggers = null; //triggers model private boolean hasChanged = false; //indicates if changes have been made to the current collection configuration /** * Constructor * * @param CollectionName The path of the collection to retreive the collection.xconf for * @param client The interactive client */ CollectionXConf(String CollectionName, InteractiveClient client) throws XMLDBException { this.client = client; //get configuration collection for the named collection //TODO : use XmldbURIs path = CollectionConfigurationManager.CONFIG_COLLECTION + CollectionName; collection = client.getCollection(path); if(collection == null) //if no config collection for this collection exists, just return return; //get the resource from the db String[] resources = collection.listResources(); for (int i = 0; i < resources.length; i++) { if (resources[i].endsWith(CollectionConfiguration.COLLECTION_CONFIG_SUFFIX)) { resConfig = collection.getResource(resources[i]); break; } } if(resConfig == null) //if, no config file exists for that collection return; //Parse the configuration file into a DOM DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); Document docConfig = null; try { DocumentBuilder builder = factory.newDocumentBuilder(); docConfig = builder.parse( new java.io.ByteArrayInputStream(resConfig.getContent().toString().getBytes()) ); } catch(ParserConfigurationException pce) { //TODO: do something here, throw xmldbexception? } catch(SAXException se) { //TODO: do something here, throw xmldbexception? } catch(IOException ioe) { //TODO: do something here, throw xmldbexception? } //Get the root of the collection.xconf Element xconf = docConfig.getDocumentElement(); //Read any custom namespaces from xconf customNamespaces = getCustomNamespaces(xconf); //Read FullText Index from xconf fulltextIndex = getFullTextIndex(xconf); //Read Range Indexes from xconf rangeIndexes = getRangeIndexes(xconf); //read Triggers from xconf triggers = getTriggers(xconf); } /** * Indicates whether the fulltext index defaults to indexing all nodes * * @return true indicates all nodes are indexed, false indicates no nodes are indexed by default */ public boolean getFullTextIndexDefaultAll() { return fulltextIndex != null ? fulltextIndex.getDefaultAll() : false; } /** * Set whether all nodes should be indexed into the fulltext index * * @param defaultAll true indicates all nodes should be indexed, false indicates no nodes should be indexed by default */ public void setFullTextIndexDefaultAll(boolean defaultAll) { hasChanged = true; if(fulltextIndex == null) { fulltextIndex = new FullTextIndex(true, false, false, null); } else { fulltextIndex.setDefaultAll(defaultAll); } } /** * Indicates whether the fulltext index indexes attributes * * @return true indicates attributes are indexed, false indicates attributes are not indexed */ public boolean getFullTextIndexAttributes() { return fulltextIndex != null ? fulltextIndex.getAttributes() : false; } /** * Set whether attributes should be indexed into the fulltext index * * @param attributes true indicates attributes should be indexed, false indicates attributes should not be indexed */ public void setFullTextIndexAttributes(boolean attributes) { hasChanged = true; if(fulltextIndex == null) { fulltextIndex = new FullTextIndex(false, true, false, null); } else { fulltextIndex.setAttributes(attributes); } } /** * Indicates whether the fulltext index indexes alphanumeric values * * @return true indicates alphanumeric values are indexed, false indicates alphanumeric values are not indexed */ public boolean getFullTextIndexAlphanum() { return fulltextIndex != null ? fulltextIndex.getAlphanum() : false; } /** * Set whether alphanumeric values should be indexed into the fulltext index * * @param alphanum true indicates alphanumeric values should be indexed, false indicates alphanumeric values should not be indexed */ public void setFullTextIndexAlphanum(boolean alphanum) { hasChanged = true; if(fulltextIndex == null) { fulltextIndex = new FullTextIndex(false, false, true, null); } else { fulltextIndex.setAlphanum(alphanum); } } /** * Returns a full text index path * * @param index The numeric index of the fulltext index path to retreive * * @return The XPath */ public String getFullTextIndexPath(int index) { return fulltextIndex.getPath(index); } public String getFullTextIndexType(int index) { return fulltextIndex.getType(index); } /** * Returns a full text index path action * * @param index The numeric index of the fulltext index path action to retreive * * @return The Action, either "include" or "exclude" */ public String getFullTextIndexPathAction(int index) { return fulltextIndex.getAction(index); } /** * Returns the number of full text index paths defined * * @return The number of paths */ public int getFullTextPathCount() { if(fulltextIndex != null) { return fulltextIndex.getLength(); } else { return 0; } } /** * Add a path to the full text index * * @param XPath The XPath to index * @param action The action to take on the path, either "include" or "exclude" */ public void addFullTextIndex(String type, String XPath, String action) { hasChanged = true; if(fulltextIndex == null) { fulltextIndex = new FullTextIndex(false, false, false, null); } fulltextIndex.addIndex(type, XPath, action); } /** * Update the details of a full text index path * * @param index The numeric index of the path to update * @param XPath The new XPath, or null to just set the action * @param action The new action, either "include" or "exclude", or null to just set the XPath */ public void updateFullTextIndex(int index, String type, String XPath, String action) { hasChanged = true; if (type != null) fulltextIndex.setType(index, type); if(XPath != null) fulltextIndex.setPath(index, XPath); if(action != null) fulltextIndex.setAction(index, action); } /** * Delete a path from the full text index * * @param index The numeric index of the path to delete */ public void deleteFullTextIndex(int index) { hasChanged = true; fulltextIndex.deleteIndex(index); } /** * Returns an array of the Range Indexes * * @return Array of Range Indexes */ public RangeIndex[] getRangeIndexes() { return rangeIndexes; } /** * Returns n specific Range Index * * @param index The numeric index of the Range Index to return * * @return The Range Index */ public RangeIndex getRangeIndex(int index) { return rangeIndexes[index]; } /** * Returns the number of Range Indexes defined * * @return The number of Range indexes */ public int getRangeIndexCount() { if(rangeIndexes != null) { return rangeIndexes.length; } else { return 0; } } /** * Delete a Range Index * * @param index The numeric index of the Range Index to delete */ public void deleteRangeIndex(int index) { //can only remove an index which is in the array if(index < rangeIndexes.length) { hasChanged = true; //if its the last item in the array just null the array if(rangeIndexes.length == 1) { rangeIndexes = null; } else { //else remove the item at index from the array RangeIndex newRangeIndexes[] = new RangeIndex[rangeIndexes.length - 1]; int x = 0; for(int i = 0; i < rangeIndexes.length; i++) { if(i != index) { newRangeIndexes[x] = rangeIndexes[i]; x++; } } rangeIndexes = newRangeIndexes; } } } /** * Update the details of a Range Index * * @param index The numeric index of the range index to update * @param XPath The new XPath, or null to just set the type * @param xsType The new type of the path, a valid xs:type, or just null to set the path */ public void updateRangeIndex(int index, String type, String XPath, String xsType) { hasChanged = true; if (type != null) rangeIndexes[index].setType(type); if(XPath != null) rangeIndexes[index].setXPath(XPath); if(xsType != null) rangeIndexes[index].setxsType(xsType); } /** * Add a Range Index * * @param XPath The XPath to index * @param xsType The type of the path, a valid xs:type */ public void addRangeIndex(String type, String XPath, String xsType) { hasChanged = true; if(rangeIndexes == null) { rangeIndexes = new RangeIndex[1]; rangeIndexes[0] = new RangeIndex(type, XPath, xsType); } else { RangeIndex newRangeIndexes[] = new RangeIndex[rangeIndexes.length + 1]; System.arraycopy(rangeIndexes, 0, newRangeIndexes, 0, rangeIndexes.length); newRangeIndexes[rangeIndexes.length] = new RangeIndex(type, XPath, xsType); rangeIndexes = newRangeIndexes; } } /** * Returns an array of Triggers * * @return Array of Range Indexes */ public Trigger[] getTriggers() { return triggers; } /** * Returns n specific Trigger * * @param index The numeric index of the Trigger to return * * @return The Trigger */ public Trigger getTrigger(int index) { return triggers[index]; } /** * Returns the number of Triggers defined * * @return The number of Triggers */ public int getTriggerCount() { if(triggers != null) { return triggers.length; } else { return 0; } } /** * Delete a Trigger * * @param index The numeric index of the Trigger to delete */ public void deleteTrigger(int index) { //can only remove an index which is in the array if(index < triggers.length) { hasChanged = true; //if its the last item in the array just null the array if(triggers.length == 1) { triggers = null; } else { //else remove the item at index from the array Trigger newTriggers[] = new Trigger[triggers.length - 1]; int x = 0; for(int i = 0; i < triggers.length; i++) { if(i != index) { newTriggers[x] = triggers[i]; x++; } } triggers = newTriggers; } } } /** * Update the details of a Trigger * * @param index The numeric index of the range index to update * @param triggerClass The name of the new class for the trigger * */ public void updateTrigger(int index, String triggerClass, boolean STORE_DOCUMENT_EVENT, boolean UPDATE_DOCUMENT_EVENT, boolean REMOVE_DOCUMENT_EVENT, boolean CREATE_COLLECTION_EVENT, boolean RENAME_COLLECTION_EVENT, boolean DELETE_COLLECTION_EVENT, Properties parameters) { //TODO: finish this!!! - need to add code for parameters hasChanged = true; if(triggerClass != null) triggers[index].setTriggerClass(triggerClass); triggers[index].setStoreDocumentEvent(STORE_DOCUMENT_EVENT); triggers[index].setUpdateDocumentEvent(UPDATE_DOCUMENT_EVENT); triggers[index].setRemoveDocumentEvent(REMOVE_DOCUMENT_EVENT); triggers[index].setCreateCollectionEvent(CREATE_COLLECTION_EVENT); triggers[index].setRenameCollectionEvent(RENAME_COLLECTION_EVENT); triggers[index].setDeleteCollectionEvent(DELETE_COLLECTION_EVENT); } /** * Add a Trigger * * @param triggerClass The class for the Trigger * */ public void addTrigger(String triggerClass, boolean STORE_DOCUMENT_EVENT, boolean UPDATE_DOCUMENT_EVENT, boolean REMOVE_DOCUMENT_EVENT, boolean CREATE_COLLECTION_EVENT, boolean RENAME_COLLECTION_EVENT, boolean DELETE_COLLECTION_EVENT, Properties parameters) { //TODO: finish this!!! seee updateTrigger hasChanged = true; if(triggers == null) { triggers = new Trigger[1]; triggers[0] = new Trigger(triggerClass, STORE_DOCUMENT_EVENT, UPDATE_DOCUMENT_EVENT, REMOVE_DOCUMENT_EVENT, CREATE_COLLECTION_EVENT, RENAME_COLLECTION_EVENT, DELETE_COLLECTION_EVENT, parameters); } else { Trigger newTriggers[] = new Trigger[triggers.length + 1]; System.arraycopy(triggers, 0, newTriggers, 0, triggers.length); newTriggers[triggers.length] = new Trigger(triggerClass, STORE_DOCUMENT_EVENT, UPDATE_DOCUMENT_EVENT, REMOVE_DOCUMENT_EVENT, CREATE_COLLECTION_EVENT, RENAME_COLLECTION_EVENT, DELETE_COLLECTION_EVENT, parameters); triggers = newTriggers; } } //given the root element of collection.xconf it will return the fulltext index private LinkedHashMap getCustomNamespaces(Element xconf) { NamedNodeMap attrs = xconf.getAttributes(); //there will always be one attribute - the default namespace if(attrs.getLength() > 1) { LinkedHashMap namespaces = new LinkedHashMap(); for(int i = 0; i < attrs.getLength(); i++) { Node a = attrs.item(i); if(a.getNodeName().startsWith("xmlns:")) { String namespaceLocalName = a.getNodeName().substring(a.getNodeName().indexOf(":")+1); namespaces.put(namespaceLocalName, a.getNodeValue()); } } return namespaces; } return null; } //given the root element of collection.xconf it will return the fulltext index private FullTextIndex getFullTextIndex(Element xconf) { NodeList nlFullTextIndex = xconf.getElementsByTagName("fulltext"); if(nlFullTextIndex.getLength() > 0) { boolean defaultAll = true; boolean attributes = false; boolean alphanum = false; FullTextIndexPath[] paths = null; Element elemFullTextIndex = (Element)nlFullTextIndex.item(0); defaultAll = elemFullTextIndex.getAttribute("default").equals("all"); attributes = elemFullTextIndex.getAttribute("attributes").equals("true"); alphanum = elemFullTextIndex.getAttribute("alphanum").equals("true"); NodeList nlInclude = elemFullTextIndex.getElementsByTagName("include"); NodeList nlExclude = elemFullTextIndex.getElementsByTagName("exclude"); NodeList nlQName = elemFullTextIndex.getElementsByTagName("create"); int iPaths = nlInclude.getLength() + nlExclude.getLength() + nlQName.getLength(); int pos = 0; if(iPaths > 0 ) { paths = new FullTextIndexPath[iPaths]; if(nlInclude.getLength() > 0) { for(int i = 0; i < nlInclude.getLength(); i++) { paths[pos++] = new FullTextIndexPath(TYPE_PATH, ((Element)nlInclude.item(i)).getAttribute("path"), ACTION_INCLUDE); } } if(nlExclude.getLength() > 0) { for(int i = 0; i < nlExclude.getLength(); i++) { paths[pos++] = new FullTextIndexPath(TYPE_PATH, ((Element)nlExclude.item(i)).getAttribute("path"), ACTION_EXCLUDE); } } if (nlQName.getLength() > 0) { for (int i = 0; i < nlQName.getLength(); i++) { paths[pos++] = new FullTextIndexPath(TYPE_QNAME, ((Element)nlQName.item(i)).getAttribute("qname"), ACTION_EXCLUDE); } } } return new FullTextIndex(defaultAll, attributes, alphanum, paths); } return null; } //given the root element of collection.xconf it will return an array of range indexes private RangeIndex[] getRangeIndexes(Element xconf) { NodeList nlRangeIndexes = xconf.getElementsByTagName("create"); if(nlRangeIndexes.getLength() > 0) { List rl = new ArrayList(); for(int i = 0; i < nlRangeIndexes.getLength(); i++) { Element rangeIndex = (Element)nlRangeIndexes.item(i); if (rangeIndex.hasAttribute("type")) { if (rangeIndex.hasAttribute("qname")) rl.add(new RangeIndex(TYPE_QNAME, rangeIndex.getAttribute("qname"), rangeIndex.getAttribute("type"))); else rl.add(new RangeIndex(TYPE_PATH, rangeIndex.getAttribute("path"), rangeIndex.getAttribute("type"))); } } RangeIndex[] rangeIndexes = new RangeIndex[rl.size()]; rangeIndexes = (RangeIndex[]) rl.toArray(rangeIndexes); return rangeIndexes; } return null; } //given the root element of collection.xconf it will return an array of triggers private Trigger[] getTriggers(Element xconf) { NodeList nlTriggers = xconf.getElementsByTagName("trigger"); if(nlTriggers.getLength() > 0) { Trigger[] triggers = new Trigger[nlTriggers.getLength()]; for(int i = 0; i < nlTriggers.getLength(); i++) { Element trigger = (Element)nlTriggers.item(i); Properties parameters = new Properties(); NodeList nlTriggerParameters = trigger.getElementsByTagName("parameter"); if(nlTriggerParameters.getLength() > 0) { for(int x = 0; x < nlTriggerParameters.getLength(); x++) { Element parameter = (Element)nlTriggerParameters.item(x); parameters.setProperty(parameter.getAttribute("name"), parameter.getAttribute("value")); } } //create the trigger triggers[i] = new Trigger(trigger.getAttribute("class"), trigger.getAttribute("event"), parameters); } return triggers; } return null; } //has the collection.xconf been modified? /** * Indicates whether the collection configuration has changed * * @return true if the configuration has changed, false otherwise */ public boolean hasChanged() { return hasChanged; } //produces a string of XML describing the collection.xconf private String toXMLString() { StringBuilder xconf = new StringBuilder(); xconf.append("<collection xmlns=\"http://exist-db.org/collection-config/1.0\""); if(customNamespaces != null) { Set namespaceKeys = customNamespaces.keySet(); Iterator itKeys = namespaceKeys.iterator(); while(itKeys.hasNext()) { xconf.append(" "); String namespaceLocalName = (String)itKeys.next(); String namespaceURL = (String)customNamespaces.get(namespaceLocalName); xconf.append("xmlns:" + namespaceLocalName + "=\"" + namespaceURL + "\""); } } xconf.append(">"); xconf.append(System.getProperty("line.separator")); //index if(fulltextIndex != null || rangeIndexes != null) { xconf.append('\t'); xconf.append("<index>"); xconf.append(System.getProperty("line.separator")); //fulltext indexes if(fulltextIndex != null) { xconf.append("\t\t"); xconf.append(fulltextIndex.toXMLString()); xconf.append(System.getProperty("line.separator")); } //range indexes if(rangeIndexes != null) { for(int r = 0; r < rangeIndexes.length; r ++) { xconf.append("\t\t\t"); xconf.append(rangeIndexes[r].toXMLString()); xconf.append(System.getProperty("line.separator")); } } xconf.append('\t'); xconf.append("</index>"); xconf.append(System.getProperty("line.separator")); } //triggers if(triggers != null) { xconf.append('\t'); xconf.append("<triggers>"); for(int t = 0; t < triggers.length; t ++) { xconf.append("\t\t\t"); xconf.append(triggers[t].toXMLString()); xconf.append(System.getProperty("line.separator")); } xconf.append('\t'); xconf.append("</triggers>"); xconf.append(System.getProperty("line.separator")); } xconf.append("</collection>"); return xconf.toString(); } /** * Saves the collection configuation back to the collection.xconf * * @return true if the save succeeds, false otherwise */ public boolean Save() { try { //is there an existing config file? if(resConfig == null) { //no //is there an existing configuration collection? if(collection == null) { //no client.process("mkcol " + path); collection = client.getCollection(path); } resConfig = collection.createResource(CollectionConfigurationManager.COLLECTION_CONFIG_FILENAME, "XMLResource"); } //set the content of the collection.xconf resConfig.setContent(toXMLString()); //store the collection.xconf collection.storeResource(resConfig); } catch(XMLDBException xmldbe) { return false; } return true; } //represents a path in the fulltext index in the collection.xconf protected class FullTextIndexPath { private String type = TYPE_QNAME; private String path = null; private String action = ACTION_INCLUDE; FullTextIndexPath(String type, String path, String action) { this.type = type; this.path = path; this.action = action; } public String getXPath() { return path; } public String getAction() { return action; } public String getType() { return type; } public void setPath(String xpath) { this.path = xpath; } public void setType(String type) { this.type = type; } public void setAction(String action) { this.action = action; } } /** * Represents the Full Text Index in the collection.xconf */ protected class FullTextIndex { boolean defaultAll = true; boolean attributes = false; boolean alphanum = false; FullTextIndexPath[] xpaths = null; /** * Constructor * * @param defaultAll Should the fulltext index default to indexing all nodes * @param attributes Should attributes be indexed into the fulltext index * @param alphanum Should alphanumeric values be indexed into the fulltext index * @param xpaths Explicit fulltext index paths to include or exclude, null if there are no explicit paths */ FullTextIndex(boolean defaultAll, boolean attributes, boolean alphanum, FullTextIndexPath[] xpaths) { this.defaultAll = defaultAll; this.attributes = attributes; this.alphanum = alphanum; this.xpaths = xpaths; } public boolean getDefaultAll() { return defaultAll; } public void setDefaultAll(boolean defaultAll) { this.defaultAll = defaultAll; } public boolean getAttributes() { return attributes; } public void setAttributes(boolean attributes) { this.attributes = attributes; } public boolean getAlphanum() { return alphanum; } public void setAlphanum(boolean alphanum) { this.alphanum = alphanum; } public String getPath(int index) { return xpaths[index].getXPath(); } public String getAction(int index) { return xpaths[index].getAction(); } public int getLength() { return xpaths != null ? xpaths.length : 0; } public void setType(int index, String type) { xpaths[index].setType(type); } public String getType(int index) { return xpaths[index].getType(); } public void setPath(int index, String XPath) { xpaths[index].setPath(XPath); } public void setAction(int index, String action) { xpaths[index].setAction(action); } public void addIndex(String type, String XPath, String action) { if(xpaths == null) { xpaths = new FullTextIndexPath[1]; xpaths[0] = new FullTextIndexPath(type, XPath, action); } else { FullTextIndexPath newxpaths[] = new FullTextIndexPath[xpaths.length + 1]; System.arraycopy(xpaths, 0, newxpaths, 0, xpaths.length); newxpaths[xpaths.length] = new FullTextIndexPath(type, XPath, action); xpaths = newxpaths; } } public void deleteIndex(int index) { //can only remove an index which is in the array if(index < xpaths.length) { //if its the last item in the array just null the array if(xpaths.length == 1) { xpaths = null; } else { //else remove the item at index from the array FullTextIndexPath newxpaths[] = new FullTextIndexPath[xpaths.length - 1]; int x = 0; for(int i = 0; i < xpaths.length; i++) { if(i != index) { newxpaths[x] = xpaths[i]; x++; } } xpaths = newxpaths; } } } //produces a collection.xconf suitable string of XML describing the fulltext index protected String toXMLString() { StringBuilder fulltext = new StringBuilder(); fulltext.append("<fulltext default=\""); fulltext.append(defaultAll ? "all" : "none"); fulltext.append("\" attributes=\""); fulltext.append(attributes); fulltext.append("\" alphanum=\""); fulltext.append(alphanum); fulltext.append("\">"); fulltext.append(System.getProperty("line.separator")); // Patch 1694080 prevents NPE if (xpaths != null ) { for(int i = 0; i < xpaths.length; i++) { fulltext.append('\t'); fulltext.append("<"); if (TYPE_PATH.equals(xpaths[i].getType())) { fulltext.append(xpaths[i].getAction()); fulltext.append(" path=\""); fulltext.append(xpaths[i].getXPath()); } else { fulltext.append("create qname=\""); fulltext.append(xpaths[i].getXPath()); } fulltext.append("\"/>"); fulltext.append(System.getProperty("line.separator")); } } fulltext.append("</fulltext>"); return fulltext.toString(); } } /** * Represents a Range Index in the collection.xconf */ protected class RangeIndex { private String type = TYPE_QNAME; private String XPath = null; private String xsType = null; /** * Constructor * * @param XPath The XPath to create a range index on * @param xsType The data type pointed to by the XPath as an xs:type */ RangeIndex(String type, String XPath, String xsType) { this.type = type; this.XPath = XPath; this.xsType = xsType; } public String getXPath() { return(XPath); } public String getxsType() { return(xsType); } public String getType() { return type; } public void setXPath(String XPath) { this.XPath = XPath; } public void setxsType(String xsType) { this.xsType = xsType; } public void setType(String type) { this.type = type; } //produces a collection.xconf suitable string of XML describing the range index protected String toXMLString() { StringBuilder range = new StringBuilder(); if (TYPE_PATH.equals(type)) range.append("<create path=\""); else range.append("<create qname=\""); range.append(XPath); range.append("\" type=\""); range.append(xsType); range.append("\"/>"); return range.toString(); } } /** * Represents a Trigger in the collection.xconf */ protected class Trigger { private String triggerClass = null; private boolean STORE_DOCUMENT_EVENT = false; private boolean UPDATE_DOCUMENT_EVENT = false; private boolean REMOVE_DOCUMENT_EVENT = false; private boolean CREATE_COLLECTION_EVENT = false; private boolean RENAME_COLLECTION_EVENT = false; private boolean DELETE_COLLECTION_EVENT = false; private Properties parameters = null; /** * Constructor * * @param triggerClass The fully qualified java class name of the trigger * @param STORE_DOCUMENT_EVENT true indicates that the trigger should receive the Store Document Event * @param UPDATE_DOCUMENT_EVENT true indicates that the trigger should receive the Update Document Event * @param REMOVE_DOCUMENT_EVENT true indicates that the trigger should receive the Remove Document Event * @param CREATE_COLLECTION_EVENT true indicates that the trigger should receive the Create Collection Event * @param RENAME_COLLECTION_EVENT true indicates that the trigger should receive the Rename Collection Event * @param DELETE_COLLECTION_EVENT true indicates that the trigger should receive the Delete Collection Event * @param parameters Properties describing any name=value parameters for the trigger */ Trigger(String triggerClass, boolean STORE_DOCUMENT_EVENT, boolean UPDATE_DOCUMENT_EVENT, boolean REMOVE_DOCUMENT_EVENT, boolean CREATE_COLLECTION_EVENT, boolean RENAME_COLLECTION_EVENT, boolean DELETE_COLLECTION_EVENT, Properties parameters) { //set properties this.triggerClass = triggerClass; this.STORE_DOCUMENT_EVENT = STORE_DOCUMENT_EVENT; this.UPDATE_DOCUMENT_EVENT = UPDATE_DOCUMENT_EVENT; this.REMOVE_DOCUMENT_EVENT = REMOVE_DOCUMENT_EVENT; this.CREATE_COLLECTION_EVENT = CREATE_COLLECTION_EVENT; this.RENAME_COLLECTION_EVENT = RENAME_COLLECTION_EVENT; this.DELETE_COLLECTION_EVENT = DELETE_COLLECTION_EVENT; this.parameters = parameters; } Trigger(String triggerClass, String triggerEvents, Properties parameters) { this.triggerClass = triggerClass; if(triggerEvents.indexOf("store") > -1) STORE_DOCUMENT_EVENT = true; if(triggerEvents.indexOf("update") > -1) UPDATE_DOCUMENT_EVENT = true; if(triggerEvents.indexOf("remove") > -1) REMOVE_DOCUMENT_EVENT = true; if(triggerEvents.indexOf("create") > -1) CREATE_COLLECTION_EVENT = true; if(triggerEvents.indexOf("rename") > -1) RENAME_COLLECTION_EVENT = true; if(triggerEvents.indexOf("delete") > -1) DELETE_COLLECTION_EVENT = true; this.parameters = parameters; } public String getTriggerClass() { return triggerClass; } public void setTriggerClass(String triggerClass) { this.triggerClass = triggerClass; } public boolean getStoreDocumentEvent() { return STORE_DOCUMENT_EVENT; } public void setStoreDocumentEvent(boolean store) { STORE_DOCUMENT_EVENT = store; } public boolean getUpdateDocumentEvent() { return UPDATE_DOCUMENT_EVENT; } public void setUpdateDocumentEvent(boolean update) { UPDATE_DOCUMENT_EVENT = update; } public boolean getRemoveDocumentEvent() { return REMOVE_DOCUMENT_EVENT; } public void setRemoveDocumentEvent(boolean remove) { REMOVE_DOCUMENT_EVENT = remove; } public boolean getCreateCollectionEvent() { return CREATE_COLLECTION_EVENT; } public void setCreateCollectionEvent(boolean create) { CREATE_COLLECTION_EVENT = create; } public boolean getRenameCollectionEvent() { return RENAME_COLLECTION_EVENT; } public void setRenameCollectionEvent(boolean rename) { RENAME_COLLECTION_EVENT = rename; } public boolean getDeleteCollectionEvent() { return DELETE_COLLECTION_EVENT; } public void setDeleteCollectionEvent(boolean delete) { DELETE_COLLECTION_EVENT = delete; } //produces a collection.xconf suitable string of XML describing the trigger protected String toXMLString() { StringBuilder trigger = new StringBuilder(); if(!triggerClass.equals("")) { trigger.append("<trigger class=\""); trigger.append(triggerClass); trigger.append("\" event=\""); //events if(STORE_DOCUMENT_EVENT) trigger.append("store,"); if(UPDATE_DOCUMENT_EVENT) trigger.append("update,"); if(REMOVE_DOCUMENT_EVENT) trigger.append("remove,"); if(CREATE_COLLECTION_EVENT) trigger.append("create,"); if(RENAME_COLLECTION_EVENT) trigger.append("rename,"); if(DELETE_COLLECTION_EVENT) trigger.append("delete,"); //remove possible trailing comma in events attribute if(trigger.charAt(trigger.length() -1 ) == ',') { trigger.deleteCharAt(trigger.length() - 1); } trigger.append("\">"); //parameters if any if(parameters != null) { if(parameters.size() > 0) { Enumeration pKeys = parameters.keys(); while(pKeys.hasMoreElements()) { String name = (String)pKeys.nextElement(); String value = parameters.getProperty(name); trigger.append("<parameter name=\""); trigger.append(name); trigger.append("\" value=\""); trigger.append(value); trigger.append("\"/>"); } } } trigger.append("</trigger>"); } return trigger.toString(); } } }