![JAR search and dependency download from the Maven repository](/logo.png)
org.logicalcobwebs.proxool.configuration.XMLConfigurator Maven / Gradle / Ivy
/*
* This software is released under a licence similar to the Apache Software Licence.
* See org.logicalcobwebs.proxool.package.html for details.
* The latest version is available at http://proxool.sourceforge.net
*/
package org.logicalcobwebs.proxool.configuration;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.logicalcobwebs.proxool.ProxoolConstants;
import org.logicalcobwebs.proxool.ProxoolException;
import org.logicalcobwebs.proxool.ProxoolFacade;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
import java.util.Properties;
/**
* A SAX 2 ContentHandler that can configure Proxool from an XML source.
*
* This is just a ContentHandler, so you must associate it with a SAX parser for it to actually do anything.
* If you have JAXP available {@link JAXPConfigurator} will do this for you.
*
* Properties that you pass on to the delegate driver have to be treated specially. They
* must be contained within a <driver-properties> element.
*
* See the Proxool properties for documentation
* on the available configuration properties.
*
* Example configuration:
*
* <proxool>
* <alias>apple</alias>
* <driver-url>jdbc:hsqldb:.</driver-url>
* <driver-class>org.hsqldb.jdbcDriver</driver-class>
* <driver-properties>
* <property name="user" value="abc" />
* <property name="password" value="def" />
* </driver-properties>
* <house-keeping-sleep-time>40000</house-keeping-sleep-time>
* <house-keeping-test-sql>select CURRENT_DATE</house-keeping-test-sql>
* <maximum-connection-count>10</maximum-connection-count>
* <minimum-connection-count>3</minimum-connection-count>
* <maximum-connection-lifetime>18000000</maximum-connection-lifetime> <!-- 5 hours -->
* <simultaneous-build-throttle>5</simultaneous-build-throttle>
* <recently-started-threshold>40000</recently-started-threshold>
* <overload-without-refusal-lifetime>50000</overload-without-refusal-lifetime>
* <maximum-active-time>60000</maximum-active-time>
* <verbose>true</verbose>
* <trace>true</trace>
* <fatal-sql-exception>ORA-1234</fatal-sql-exception>
* <prototype-count>2</prototype-count>
* </proxool>
*
*
* When the parser reaches the end of the <proxool> element the pool
* is automatically registered. You can contain the <proxool> element
* in any other elements as you wish. And the <proxool> element can
* occur as many times as you wish. This allows you to use an XML file that
* configures your whole application as the source. This configurator will
* ignore everything apart from the elements contained within the <proxool>
* element.
*
* Validation
* A couple of additional steps are required if you want your SAX parser to validate your Proxool xml confguration:
*
* -
* Put your proxool configuration elements inside a root
proxool-config
element.
* The document must adhere to the Proxool dtd.
*
* -
* Add a
DOCTYPE
entry to your xml with a system id containing the absolute url to the Proxool
* dtd. The Proxool jar contains a copy of the Proxool dtd in the confguration package. You can reference that with
* a jar url like this:
* <!DOCTYPE proxool-config SYSTEM "jar:file:///C:/Proxool/lib/proxool.jar!/org/logicalcobwebs/proxool/configuration/proxool.dtd">
* -
* Configure your parser to be validating. In the {@link JAXPConfigurator} this is done by passing
true
as
* the second arghument to any of the configure
methods.
*
*
*
*This class is not thread safe.
*
* @version $Revision: 1.18 $, $Date: 2006/01/18 14:39:58 $
* @author billhorsman
* @author $Author: billhorsman $ (current maintainer)
*/
public class XMLConfigurator extends DefaultHandler {
private static final Log LOG = LogFactory.getLog(XMLConfigurator.class);
private StringBuffer content = new StringBuffer();
private String poolName;
private String driverClass;
private String driverUrl;
private Properties properties = new Properties();
private static final String PROXOOL = "proxool";
private static final String DRIVER_PROPERTIES = "driver-properties";
private static final String PROPERTY = "property";
private static final String NAME = "name";
private static final String VALUE = "value";
private boolean insideDelegateProperties;
private boolean insideProxool;
/**
* @see org.xml.sax.ContentHandler#startElement
*/
public void startElement(String uri, String lname, String qname, Attributes attributes) throws SAXException {
content.setLength(0);
if (!namespaceOk(uri)) {
return;
}
final String elementName = getElementName(uri, lname, qname);
if (elementName.equals(PROXOOL)) {
if (insideProxool) {
throw new SAXException("A <" + PROXOOL + "> element can't contain another <" + PROXOOL + "> element.");
}
insideProxool = true;
properties.clear();
driverClass = null;
driverUrl = null;
}
if (insideProxool) {
if (elementName.equals(DRIVER_PROPERTIES)) {
insideDelegateProperties = true;
} else if (insideDelegateProperties) {
if (elementName.equals(PROPERTY)) {
setDriverProperty(attributes);
}
}
}
}
/**
* @see org.xml.sax.ContentHandler#characters
*/
public void characters(char[] chars, int start, int length) throws SAXException {
if (insideProxool) {
content.append(chars, start, length);
}
}
/**
* @see org.xml.sax.ContentHandler#endElement
*/
public void endElement(String uri, String lname, String qname) throws SAXException {
if (!namespaceOk(uri)) {
return;
}
final String elementName = getElementName(uri, lname, qname);
// Are we ending a proxool configuration section?
if (elementName.equals(PROXOOL)) {
// Check that we have defined the minimum information
if (driverClass == null || driverUrl == null) {
throw new SAXException("You must define the " + ProxoolConstants.DRIVER_CLASS + " and the " + ProxoolConstants.DRIVER_URL + ".");
}
// Build the URL; optinally defining a name
StringBuffer url = new StringBuffer();
url.append("proxool");
if (poolName != null) {
url.append(ProxoolConstants.ALIAS_DELIMITER);
url.append(poolName);
}
url.append(ProxoolConstants.URL_DELIMITER);
url.append(driverClass);
url.append(ProxoolConstants.URL_DELIMITER);
url.append(driverUrl);
if (LOG.isDebugEnabled()) {
LOG.debug("Created url: " + url);
}
// Register the pool
try {
ProxoolFacade.registerConnectionPool(url.toString(), properties);
} catch (ProxoolException e) {
throw new SAXException(e);
}
// This ensures we ignore remaining XML until we come across another
// element.
insideProxool = false;
}
if (insideProxool && !elementName.equals(PROXOOL)) {
if (elementName.equals(DRIVER_PROPERTIES)) {
insideDelegateProperties = false;
} else if (!insideDelegateProperties) {
setProxoolProperty(elementName, content.toString().trim());
}
}
}
private void setProxoolProperty(String localName, String value) {
if (localName.equals(ProxoolConstants.ALIAS)) {
poolName = value;
} else if (localName.equals(ProxoolConstants.DRIVER_CLASS)) {
driverClass = value;
} else if (localName.equals(ProxoolConstants.DRIVER_URL)) {
driverUrl = value;
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("Setting property '" + ProxoolConstants.PROPERTY_PREFIX + localName + "' to value '" + value + "'.");
}
properties.put(ProxoolConstants.PROPERTY_PREFIX + localName, value);
}
}
private void setDriverProperty(Attributes attributes) throws SAXException {
final String name = attributes.getValue(NAME);
final String value = attributes.getValue(VALUE);
if (name == null || name.length() < 1 || value == null) {
throw new SAXException("Name or value attribute missing from property element."
+ "Name: '" + name + "' Value: '" + value + "'.");
}
if (LOG.isDebugEnabled()) {
if (name.toLowerCase().indexOf("password") > -1) {
LOG.debug("Adding driver property: " + name + "=" + "*******");
} else {
LOG.debug("Adding driver property: " + name + "=" + value);
}
}
properties.put(name, value);
}
/**
* @see org.xml.sax.ErrorHandler#warning(SAXParseException)
*/
public void warning(SAXParseException e) throws SAXException {
// Just debug-log the warning. We'll probably survive.
LOG.debug("The saxparser reported a warning.", e);
}
/**
* @see org.xml.sax.ErrorHandler#error(SAXParseException)
*/
public void error(SAXParseException e) throws SAXException {
// On error we rethrow the exception.
// This should cause the parser stop and an exeption be thrown back to the client.
throw e;
}
/**
* @see org.xml.sax.ErrorHandler#fatalError(SAXParseException)
*/
public void fatalError(SAXParseException e) throws SAXException {
// On fatal error we rethrow the exception.
// This should cause the parser stop and an exeption be thrown back to the client.
throw e;
}
// If no namespace use qname, else use lname.
private String getElementName(String uri, String lname, String qname) {
if (uri == null || "".equals(uri)) {
return qname;
} else {
return lname;
}
}
private boolean namespaceOk(String uri) {
return uri == null || uri.length() == 0 || uri.equals(ProxoolConstants.PROXOOL_XML_NAMESPACE_URI);
}
}