// // Copyright (c)1998-2011 Pearson Education, Inc. or its affiliate(s). // All rights reserved. // package openadk.library.tools.cfg; import java.io.*; import java.util.List; import java.util.Properties; import java.util.Vector; import openadk.library.*; import openadk.library.tools.mapping.ADKMappingException; import openadk.library.tools.mapping.Mappings; import openadk.util.XMLUtils; import org.apache.xml.serialize.OutputFormat; import org.apache.xml.serialize.XMLSerializer; import org.w3c.dom.Document; import org.w3c.dom.Node; /** * Implements an XML-based configuration file for agents.<p> * * To read the configuration file into memory, call the <code>read</code> * method and specify whether to validate the XML document against a DTD. The * methods of the AgentConfig class do not perform validation of required * elements and attributes or their values, so it is recommended that you * validate against a DTD. A default DTD is located in the <code>docs</code> * directory. * <p> * * <b>Applying the Configuration</b> * * Once the configuration file is parsed, you can inspect the elements and * attributes by calling the various methods of this class. Or, you can call * the <code>apply</code> method prior to agent initialization to automatically * apply the configuration settings to your agent as follows: * <p> * * <ul> * <li> * The root <code><agent></code> attributes are inspected to set * the SourceId and default SIF Version for the agent. * </li> * <li> * For each <code><property></code> element, the associated * property is set in the agent's AgentProperties object. * </li> * <li> * The agent's transports are configured according to the properties * of the <code><transport></code> elements * <li> * A zone is created for each <code><zone></code> element * </li> * </ul> * * Most agents will extend or modify this class to add additional configuration * settings specific to the agent. The source code can be found in the ADK's * <code>extras</code> directory.<p> * * <b>Properties</b> * * Agent and Zone properties can be defined at three levels:<p> * * <ul> * <li> * <code><property></code> elements of the root <code><agent></code> * node are intended to serve as global defaults. When then applyProperties * method is called, these property values are assigned to the Agent's * AgentProperties object. * </li> * <li> * <code><property></code> elements of a zone <code><template></code> * are inherited by zones that reference that template. When the applyZones * method is called, these property values are assigned to the Zone's * AgentProperties object unless specifically overridden by <code><property></code> * elements defined by each <code><zone></code> * </li> * <li> * <code><property></code> elements of a <code><zone></code> * are specific to that zone and override any property defined in the * template referenced by the zone * </li> * </ul> * * <b>Updating the Configuration Programmatically</b> * * The elements and attributes of the configuration file are represented as DOM * Nodes that can be programmatically updated using the standard DOM interface. * Use the convenience methods getZoneNode, getZoneTemplateNode, getTransportNode, * and so on to obtain a reference to a DOM Node instance for a group of * configuration settings. The <code>getProperty</code> and <code>setProperty</code> * methods can also be used to manipulate the <code><property></code> * children of an element. Static helper routines from the * openadk.util.XMLUtils class may also be used to get and set * element attributes and text values. * <p> * * Call the <code>save</code> method to write the configuration to a file. * * @author Edustructures LLC * @version ADK 1.0 */ public class AgentConfig { /** Namespaces feature id (http://xml.org/sax/features/namespaces). */ protected static final String NAMESPACES_FEATURE_ID = "http://xml.org/sax/features/namespaces"; /** Validation feature id (http://xml.org/sax/features/validation). */ protected static final String VALIDATION_FEATURE_ID = "http://xml.org/sax/features/validation"; /** Schema validation feature id (http://apache.org/xml/features/validation/schema). */ protected static final String SCHEMA_VALIDATION_FEATURE_ID = "http://apache.org/xml/features/validation/schema"; /** Schema full checking feature id (http://apache.org/xml/features/validation/schema-full-checking). */ protected static final String SCHEMA_FULL_CHECKING_FEATURE_ID = "http://apache.org/xml/features/validation/schema-full-checking"; /** Xerces input buffer size (default is 2K) **/ protected static final String XERCES_BUFFERSIZE_PROP_ID = "http://apache.org/xml/properties/input-buffer-size"; /** * The configuration file * @see #read */ private File fSrc; /** * The DOM document produced by reading the configuration file * @see #read */ private Document fDoc; /** * The root <code><mappings></code> object defines rules for mapping * application database fields to SIF Data Object elements and attributes. * Refer to the Mappings class for details. */ private Mappings fMappings; private String CRLF = "\r\n"; /** * Constructor */ public AgentConfig() { } /** * Read a configuration file into memory.<p> * * @param file The path to the configuration file * @param validate true to validate the configuration file * * @return A DOM Document encapsulating the configuration file. This * object may also be obtained by calling <code>getDocument</code> * @exception IOException thrown if an error occurs reading the file * @exception ADKException thrown if the ADK is not initialized * @exception ADKMappingException thrown if an error occurs parsing any * <code><mappings></code> elements * @exception ADKConfigException thrown if the configuration file fails * to parse or is not valid when validation is turned on * * @see #getDocument */ public Document read( String file, boolean validate ) throws IOException, ADKConfigException, ADKMappingException, ADKException { if( !ADK.isInitialized() ) throw new ADKException( "ADK is not initialized",null ); String fileName = JUnitHelper.fixPathSeparator(file); fSrc = new File(fileName); if( fSrc.isDirectory() ) throw new IllegalArgumentException("The configuration file \""+file+"\" is a directory"); if( !fSrc.exists() ) throw new FileNotFoundException(fileName); try { // Use the Xerces parser org.apache.xerces.parsers.DOMParser parser = new org.apache.xerces.parsers.DOMParser(); // Turn validation on if requested parser.setFeature( VALIDATION_FEATURE_ID, validate ); // Parse into a DOM Document parser.parse( fSrc.toURI().toString() ); fDoc = parser.getDocument(); } catch( Exception ex ) { throw new ADKConfigException( ex.toString() ); } // Build the Mappings object fMappings = new Mappings(); fMappings.populate( fDoc, getRootNode() ); return fDoc; } /** * Saves the XML document back to the file from which it was read.<p> * @exception IOException thrown if an error occurs writing the document */ public void save() throws IOException, ADKConfigException { FileOutputStream out = null; try { out = new FileOutputStream( fSrc ); save( out ); } finally { if( out != null ) out.close(); } } /** * Saves the XML document to the specified output stream.<p> * @param out The OutputStream to which the XML document is written * @exception IOException thrown if an error occurs writing the document */ public void save( OutputStream out ) throws IOException, ADKConfigException { Document doc = getDocument(); XMLSerializer serializer = getSerializer( doc ); serializer.setOutputByteStream( out ); serializer.serialize(doc); } private XMLSerializer getSerializer( Document doc ) { OutputFormat format = new OutputFormat(doc); format.setLineWidth(65); format.setIndenting(true); format.setIndent(4); format.setLineSeparator(CRLF); XMLSerializer serializer = new XMLSerializer( format ); return serializer; } /** * Saves the XML document to the specified Writer.<p> * @param out The Writer to which the XML document is written * @exception IOException thrown if an error occurs writing the document */ public void save( BufferedWriter out ) throws IOException, ADKConfigException { Document doc = getDocument(); XMLSerializer serializer = getSerializer( doc ); serializer.setOutputCharStream( out ); serializer.serialize(doc); } /** * Determines if the configuration file has been loaded * @return true if the <code>read</code> method has been successfully called */ public boolean isLoaded() { return fDoc != null; } /** * Applies the settings in the configuration to the Agent. This method * should be called at most once during agent startup, usually from * <coce>Agent.initialize</code><p> * * <ul> * <li> * For each <code><property></code> element, the associated * property is set in the agent properties. * </li> * <li> * A Zone instance is created for each <code><zone></code> * element. Any <code><property></code> elements defined for * the zone are set in the zone's AgentProperties object. An array * of all zones created is returned. The caller can then join those * zones to topics. * </li> * </ul> * * @param agent The Agent to apply the configuration settings to * * @param overwrite When true, properties defined in the configuration file * replace properties of the same name that are already defined in the * agent properties */ public Zone[] apply( Agent agent, boolean overwrite ) throws ADKException, ADKConfigException { applyProperties(agent,overwrite); applyTransports(agent,overwrite); agent.setConfigurationSource( this ); return applyZones(agent); } /** * Applies <code><property></code> elements to the Agent * * @param agent The Agent to apply properties to * @param overwrite When true, properties defined in the configuration file * replace properties of the same name that are already defined in the * agent properties */ public void applyProperties( Agent agent, boolean overwrite ) throws ADKException, ADKConfigException { // Set the agent's ID if specified in the configuration String sourceId = getSourceId(); if( sourceId != null ) agent.setId(sourceId); // Apply root-level properties to the agent's AgentProperties getAgentProperties( agent.getProperties() ); } /** * Applies <code><transport></code> elements to the Agent.<p> * * This method selects the <code><transport></code> child of the root * <code><agent></code> with the <i>enabled</i> attribute set to true. * More than one transport may be enabled; if more than one is enabled the first * definition that is enabled is considered the agent's default transport protocol. The * <code><property></code> elements are then assigned to the agent's * default transport properties for this protocol. * <p> * * @param agent The Agent to apply the transport properties to * @param overwrite When true, properties defined in the configuration file * replace properties of the same name that are already defined in the * agent's default transport properties * @throws ADKException * @throws ADKConfigException */ public void applyTransports( Agent agent, boolean overwrite ) throws ADKException, ADKConfigException { // // Enumerate all <transport> elements of the root; ignore elements // where the 'enabled' attribute is set to false // List<Node> v = XMLUtils.getElementsByTagName( getRootNode(), "transport", false ); for( int i = 0; i < v.size(); i++ ) { Node n = v.get(i); String proto = XMLUtils.getAttribute( n, "protocol" ); // Get default properties for this transport protocol TransportProperties tp = agent.getDefaultTransportProperties( proto ); if( tp == null ) throw new ADKConfigException( "Transport protocol not supported: " + proto ); // Set the agent to use this transport protocol by default String enabled = XMLUtils.getAttribute( n, "enabled" ); boolean isEnabled = enabled != null && ( enabled.equalsIgnoreCase("true") || enabled.equalsIgnoreCase("yes") ); if( isEnabled ) { String prev = agent.getProperties().getProperty( AgentProperties.PROP_MESSAGING_TRANSPORT ); if( prev == null ) { if( ( ADK.debug & ADK.DBG_PROPERTIES ) != 0 ) { Agent.getLog().debug( "Configuration file selecting " + proto.toUpperCase() + " as the default transport protocol" ); } agent.getProperties().setTransportProtocol( proto ); } } tp.setEnabled( isEnabled ); // // Enumerate all <property> elements of this <transport> ... // List<Node> props = XMLUtils.getElementsByTagName( n, "property", false ); for( int p = 0; p < props.size(); p++ ) { Node prop = props.get(p); String nam = (String)XMLUtils.getAttribute( prop,"name" ); String val = (String)XMLUtils.getAttribute( prop, "value" ); if( tp.containsKey( nam ) ) { if( overwrite ) { if( ( ADK.debug & ADK.DBG_PROPERTIES ) != 0 ) Agent.getLog().debug( "Configuration file overwriting " + proto.toUpperCase() + " transport property: " + nam + " = " + val ); tp.setProperty(nam,val); } } else { if( ( ADK.debug & ADK.DBG_PROPERTIES ) != 0 ) Agent.getLog().debug( "Setting " + proto.toUpperCase() + " transport property from configuration file: " + nam + " = " + val ); tp.setProperty(nam,val); } } } } /** * Applies <code><zone></code> elements to create new Zone instances. * The caller is responsible for setting up topics, connecting to zones, * and joining zones to topics. */ public Zone[] applyZones( Agent agent ) throws ADKException, ADKConfigException { ZoneFactory zf = agent.getZoneFactory(); Node[] zones = getZoneNodes(); for( int i = 0; i < zones.length; i++ ) { // Get any properties defined for this zone. Zone properties // should inherit from the agent's AgentProperties object, so // pass that object as the parent AgentProperties props = new AgentProperties( agent.getProperties() ); getZoneProperties(props,zones[i]); String zoneId = XMLUtils.getAttribute(zones[i],"id"); if( zoneId == null || zoneId.trim().length() == 0 ) throw new ADKConfigException( "<zone> cannot have an empty id attribute"); String zoneUrl = XMLUtils.getAttribute(zones[i],"url"); if( zoneUrl == null || zoneUrl.trim().length() == 0 ) throw new ADKConfigException( "<zone> cannot have an empty url attribute"); // Ask ZoneFactory to create a Zone instance zf.getInstance( zoneId, zoneUrl, props ); } return agent.getZoneFactory().getAllZones(); } /** * Gets the DOM document<p> * @return The loaded configuration file */ public Document getDocument() { return fDoc; } /** * Adds a new zone * @param zoneId The zone ID * @param zoneUrl The zone URL * @param templateId The ID of the zone template */ public Node addZone( String zoneId, String zoneUrl, String templateId ) throws ADKConfigException { if( zoneId == null || zoneId.trim().length() == 0 ) throw new ADKConfigException( "Zone ID cannot be blank" ); Node zone = getZoneNode( zoneId ); if( zone != null ) throw new ADKConfigException( "Zone already defined" ); // Create a new <zone> element zone = getDocument().createElement( "zone" ); getRootNode().appendChild( zone ); XMLUtils.setAttribute( zone, "id", zoneId ); if( zoneUrl != null ) XMLUtils.setAttribute( zone, "url", zoneUrl ); XMLUtils.setAttribute( zone, "template", templateId == null ? "Default" : templateId ); return zone; } /** * Deletes a zone * @param zoneId The zone ID */ public void deleteZone( String zoneId ) { if( zoneId == null ) return; Node zone = getZoneNode( zoneId ); if( zone != null ) zone.getParentNode().removeChild(zone); } /** * Gets the version of SIF that should be used by the agent * @return A SIFVersion object for the value of the <code>sifVersion</code> * attribute specified by the <code><agent></code> element, or * the ADK's default SIFVersion if this attribute was not set */ public SIFVersion getVersion() { Node agent = getRootNode(); if( agent != null ) { String version = XMLUtils.getAttribute(agent,"sifVersion"); if( version != null ) return SIFVersion.parse(version); } return SIFVersion.LATEST; } /** * Gets the Mappings object * @return The <code><agent></code> node if defined */ public Mappings getMappings() { return fMappings; } /** * Gets the root <code><agent></code> element * @return The root node */ public Node getRootNode() { try { return (Node)XMLUtils.getElementsByTagName( getDocument(), "agent", false ).get( 0 ); } catch( Throwable thr ) { return null; } } /** * Gets the SourceId that should be used by the agent */ public String getSourceId() { Node agent = getRootNode(); return agent != null ? XMLUtils.getAttribute(agent,"id") : null; } /** * Populates an AgentProperties object with all <code><property></code> * values defined for the root <code><agent></code> element. * * Properties defined at the root level are applied to the AgentProperties * object of the Agent class. These serve as global defaults to all zones. * Use the getTemplateProperties method to obtain properties for a zone * template, which apply to all zones that reference that template, or the * getZoneProperties method to obtain properties specific to a zone. * <p> * * @return An AgentProperties object populated with all <code><property></code> * values defined for the root <code><agent></code> element */ public void getAgentProperties( AgentProperties props ) { populateProperties( props, getRootNode() ); } /** * Gets all <code><property></code> values defined for the root * <code><agent></code> node. */ public Node[] getAgentPropertyNodes() { return getPropertyNodes( getRootNode() ); } /** * Sets the value of a <code><property></code> child of the root * <code><agent></code> node. If a <code><property></code> * element already exists, its value is updated; otherwise a new element is * appended to the root <code><agent></code> node.<p> * * @param property The name of the property * @param value The property value */ public void setAgentProperty( String property, String value ) { setProperty( getRootNode(), property, value ); } /** * Populates a Properties object with all <code><property></code> * values defined by a <code><zone></code> node as well as all * properties defined by the referenced zone template. Properties defined * by the <code><zone></code> override properties defined by the * template. */ public void getZoneProperties( Properties props, String zone ) { getZoneProperties( props, getZoneNode( zone ) ); } /** * Populates a Properties object with all <code><property></code> * values defined by a <code><zone></code> node as well as all * properties defined by the referenced zone template. Properties defined * by the <code><zone></code> override properties defined by the * template. */ public void getZoneProperties( Properties props, Node zone ) { populateProperties( props, zone ); String template = XMLUtils.getAttribute( zone, "template" ); if( template != null ) { getZoneTemplateProperties( props, template ); } } /** * Gets all <code><property></code> values defined for a * <code><zone></code> node. */ public Node[] getZonePropertyNodes( String zoneId ) { return getPropertyNodes( getZoneNode( zoneId ) ); } /** * Gets all <code><property></code> values defined for a * <code><zone></code> node. */ public Node[] getZonePropertyNodes( Node zone ) { return getPropertyNodes( zone ); } /** * Sets the value of a <code><property></code> child of the specified * <code><zone></code> node. If a <code><property></code> child * already exists with the same name, its value is updated; otherwise a new * element is appended to the <code><zone></code> node.<p> * * @param zoneId The zone ID * @param property The name of the property * @param value The property value */ public void setZoneProperty( String zoneId, String property, String value ) { Node zone = getZoneNode( zoneId ); if( zone != null ) setProperty( zone, property, value ); } /** * Gets the value of a <code><property></code> child of the specified * <code><zone></code> node. * * @param zoneId The zone ID * @param property The name of the property * @param defaultValue The value that will be returned if the property is * not defined */ public String getZoneProperty( String zoneId, String property, String defaultValue ) { Node n = getZoneNode( zoneId ); if( n != null ) return getProperty( n, property, defaultValue ); return defaultValue; } /** * Sets the value of a <code><zone></code> node attribute. * * @param zone The zone ID * @param attr The name of the attribute * @param value The attribute value */ public void setZoneAttribute( String zoneId, String attr, String value ) { Node zone = getZoneNode( zoneId ); if( zone != null ) XMLUtils.setAttribute( zone, attr, value ); } /** * Gets the value of a <code><zone></code> node attribute. * * @param zone The zone ID * @param attr The name of the attribute * @param defaultValue The value that will be returned if the attribute is * not defined */ public String getZoneAttribute( String zoneId, String attr, String defaultValue ) { String s = null; Node zone = getZoneNode( zoneId ); if( zone != null ) s = XMLUtils.getAttribute( zone, attr ); return s == null ? defaultValue : s; } /** * Populates a Properties object with all <code><property></code> * values defined for a <code><template></code> node. */ public void getZoneTemplateProperties( Properties props, String template ) { populateProperties( props, getZoneTemplateNode( template ) ); } /** * Populates a Properties object with all <code><property></code> * values defined for a <code><template></code> node. */ public void getZoneTemplateProperties( Properties props, Node template ) { populateProperties( props, template ); } /** * Gets a zone template property.<p> * @param templateId The ID of the <code><template></code> * @param property The name of the <code><property></code> * @param defValue The default value to return if the property is not defined */ public String getZoneTemplateProperty( String templateId, String property, String defValue ) { Node n = getZoneTemplateNode( templateId ); if( n != null ) return getProperty( n, property, defValue ); return defValue; } /** * Gets a zone template property node.<p> * @param templateId The ID of the <code><template></code> * @param property The name of the <code><property></code> * @return the DOM Node if found */ public Node getZoneTemplatePropertyNode( String templateId, String property ) { Node n = getZoneTemplateNode( templateId ); if( n != null ) return getPropertyNode( n, property ); return null; } /** * Gets all <code><property></code> values defined for a <code><zone></code> node. */ public Node[] getZoneTemplatePropertyNodes( String templateId ) { Node[] templates = getZoneTemplates( false ); for( int i = 0; i < templates.length; i++ ) { String id = XMLUtils.getAttribute( templates[i], "id" ); if( id != null && id.equals( templateId ) ) { return getPropertyNodes( templates[i] ); } } return null; } /** * Gets all <code><property></code> values defined for a <code><zone></code> node. */ public Node[] getZoneTemplatePropertyNodes( Node template ) { return getPropertyNodes( template ); } /** * Sets the value of a <code><property></code> child of the specified * <code><zone></code> node. If a <code><property></code> child * already exists with the same name, its value is updated; otherwise a new * element is appended to the <code><template></code> node.<p> * * @param template The zone template ID * @param property The name of the property * @param value The property value */ public void setZoneTemplateProperty( String template, String property, String value ) { Node temp = getZoneTemplateNode( template ); if( temp == null ) temp = addZoneTemplateNode( template ); setProperty( temp, property, value ); } /** * Deletes a property.<p> * @param property The name of the <code><property></code> */ public void deleteProperty( String property ) { Node prn = getPropertyNode( getRootNode(), property ); if( prn != null ) prn.getParentNode().removeChild( prn ); } /** * Deletes a zone property.<p> * @param zoneId The ID of the <code><zone></code> * @param property The name of the <code><property></code> */ public void deleteZoneProperty( String zoneId, String property ) { Node n = getZoneNode( zoneId ); if( n != null ) { Node prn = getPropertyNode( n, property ); if( prn != null ) prn.getParentNode().removeChild( prn ); } } /** * Deletes a zone template property.<p> * @param templateId The ID of the <code><template></code> * @param property The name of the <code><property></code> */ public void deleteZoneTemplateProperty( String templateId, String property ) { Node n = getZoneTemplateNode( templateId ); if( n != null ) { Node prn = getPropertyNode( n, property ); if( prn != null ) prn.getParentNode().removeChild( prn ); } } /** * Populates a Properties object with all <code><property></code> * values defined as children of the specified node. Properties that already * exist in the Properties object are not overwritten by properties defined * by the node. */ public void populateProperties( Properties props, Node node ) { populateProperties( props, node, false ); } /** * Populates a Properties object with all <code><property></code> * values defined as children of the specified node. Properties that already * exist in the Properties object are optionally overwritten with properties * defined by the node. * * @param props The Properties object to populate * @param node The Node to search for child <code><property></code> elements * @param replace true to replace the values of properties already defined * in the <code>props</code> object */ public void populateProperties( Properties props, Node node, boolean replace ) { if( node != null ) { List<Node> v = XMLUtils.getElementsByTagName( node, "property", true ); for( int i = 0; i < v.size(); i++ ) { Node n = v.get(i); String nam = XMLUtils.getAttribute(n,"name"); String val = XMLUtils.getAttribute(n,"value"); if( nam != null && val != null && ( replace || !props.containsKey( nam ) ) ) props.put(nam,val); } } } /** * Sets the value of a <code><property></code> child of the specified * node. If a <code><property></code> element already exists, its value * is updated; otherwise a new element is appended to the node.<p> * * @param node The parent node of the property * @param property The name of the property * @param value The property value */ public void setProperty( Node node, String property, String value ) { Node propN = null; List<Node> v = XMLUtils.getElementsByTagName( node, "property", false ); for( int i = 0; i < v.size(); i++ ) { String name = XMLUtils.getAttribute( v.get(i),"name" ); if( name.equals(property) ) { propN = v.get(i); break; } } if( propN == null ) { propN = getDocument().createElement("property"); node.appendChild( propN ); } XMLUtils.setAttribute( propN, "name", property ); XMLUtils.setAttribute( propN, "value", value ); } public void setProperty( Node node, String element, String property, String value ) { Node _ele = null; Node _prop = null; // Find/create container node... List<Node> v = XMLUtils.getElementsByTagName( node, element, false ); if( v.size() == 0 ) { _ele = node.getOwnerDocument().createElement( element ); node.appendChild( _ele ); } // Find existing <property> node if any for( int i = 0; i < v.size() && _prop == null; i++ ) { _ele = v.get(i); List<Node> v2 = XMLUtils.getElementsByTagName( _ele, "property", false ); for( int p = 0; p < v2.size() && _prop == null; p++ ) { Node n = v2.get(p); String nam = XMLUtils.getAttribute(n,"name"); if( nam != null && nam.equals(property) ) _prop = n; } } // Create <property> node if none found above if( _prop == null ) { _prop = _ele.getOwnerDocument().createElement( "property" ); XMLUtils.setAttribute( _prop, "name", property ); _ele.appendChild( _prop ); } if( _prop != null ) XMLUtils.setAttribute( _prop, "value", value ); } /** * Gets the value of a <code><property></code> element defined by a node. * * @param node The parent node to search * @param property The name of the property * @param defaultValue The value to return if the property is not found * * @return The property value */ public String getProperty( Node node, String property, String defaultValue ) { String val = null; List<Node> v = XMLUtils.getElementsByTagName( node, "property", true ); for( int i = 0; i < v.size(); i++ ) { Node ch = v.get(i); if( XMLUtils.getAttribute( ch, "name" ).equals( property ) ) { val = XMLUtils.getAttribute( ch, "value" ); break; } } return val == null ? defaultValue : val; } /** * Gets a <code><property></code> DOM Node * * @param node The parent node to search * @param property The name of the property * * @return The DOM Node if the property is found, otherwise <code>null</code> */ public Node getPropertyNode( Node node, String property ) { Node n = null; List<Node> v = XMLUtils.getElementsByTagName( node, "property", true ); for( int i = 0; i < v.size(); i++ ) { Node ch = (Node)v.get(i); if( XMLUtils.getAttribute( ch, "name" ).equals( property ) ) { n = ch; break; } } return n; } /** * A convenience function to get the value of a <code><property></code> * defined by the first child element of the specified node that has a * matching tag name. This routine is often used to obtain properties that * are organized into named groups (e.g. <code><database-settings></code>, * <code><transport-settings></code>, etc.)<p> * * For example, to lookup a property named "user" of a top-level * <code><database-settings></code> element,<p> * * <code>getProperty( getRootNode(), "database-settings", "user", "sa" );</code> * <p> * * @param node The parent node to search * @param element The tag name of the element to search for (it must be a * non-repeating child of the parent node) * @param property The name of the property * @param defaultValue The value to return if the property is not found * * @return The property value */ public String getProperty( Node node, String element, String property, String defaultValue ) { List<Node> v = XMLUtils.getElementsByTagName( node, element, true ); if( v.size() == 0 ) return defaultValue; String val = null; for( int i = 0; i < v.size() && val == null; i++ ) { Node ch = v.get(i); List<Node> v2 = XMLUtils.getElementsByTagName( ch, "property", true ); for( int p = 0; p < v2.size() && val == null; p++ ) { Node n = v2.get(p); String nam = XMLUtils.getAttribute(n,"name"); if( nam != null && nam.equals(property) ) val = XMLUtils.getAttribute(n,"value"); } } return val == null ? defaultValue : val; } /** * Gets all <code><property></code> child nodes of an element */ public Node[] getPropertyNodes( Node node ) { List<Node> v = XMLUtils.getElementsByTagName( node, "property", false ); Node[] arr = new Node[v.size()]; v.toArray(arr); return arr; } /** * Gets an array of all zones defined by the configuration file<p> * @return An array of DOM Nodes representing the <code><zone></code> elements * defined by the configuration file */ public Node[] getZoneNodes() { List<Node> v = XMLUtils.getElementsByTagName( getRootNode(), "zone", false ); Node[] n = new Node[ v == null ? 0 : v.size() ]; v.toArray( n ); return n; } /** * Gets the <code><zone></code> element with the specified ID */ public Node getZoneNode( String zoneId ) { return XMLUtils.getElementByAttr( getRootNode(), "zone", "id", zoneId ); } /** * Gets an array of all zones templates.<p> * @return An array of DOM Nodes comprised of <code><template></code> * elements defined as children of the root <code><agent></code> node */ public Node[] getZoneTemplates( boolean filtered ) { List<Node> v = XMLUtils.getElementsByTagName( getRootNode(), "template", filtered ); Node[] n = new Node[ v == null ? 0 : v.size() ]; v.toArray( n ); return n; } /** * Gets a zone template by ID.<p> * @param templateId The ID of the template to return * @return The DOM Node encapsulating the <code><template></code> * element with the specified ID */ public Node getZoneTemplateNode( String templateId ) { return XMLUtils.getElementByAttr( getRootNode(), "template", "id", templateId ); } /** * Add a <template> node for the specified zone template. * @return The newly created node, or if a zone template node already * exists with this templateId, a reference to it is returned */ public Node addZoneTemplateNode( String templateId ) { Node n = getZoneTemplateNode( templateId ); if( n == null ) { // Create and append a new template node Node root = getRootNode(); n = root.getOwnerDocument().createElement( "template" ); XMLUtils.setAttribute( n, "id", templateId ); root.appendChild( n ); } return n; } /** * Gets a <transport> node.<p> * @param protocol The protocol type (e.g. "http", "https", etc.) * @return The DOM Node encapsulating the <code><transport></code> element */ public Node getTransportNode( String protocol ) { return XMLUtils.getElementByAttr( getRootNode(), "transport", "protocol", protocol ); } /** * Add a <transport> node for the specified transport protocol. * @return The newly created node, or if a transport node already exists * for this protocol, a reference to it is returned */ public Node addTransportNode( String protocol ) { Node n = getTransportNode( protocol ); if( n == null ) { // Create and append a new protocol node Node root = getRootNode(); n = root.getOwnerDocument().createElement( "transport" ); XMLUtils.setAttribute( n, "protocol", protocol ); root.appendChild( n ); } return n; } }