I've now created a subclass of DriverDataSourceFactory called
OracleApplicationServerXMLDataSourceFactory which will initialize from the
Oracle Application Server datasources.xml JNDI definition file. (The
advantage of this over cdeploy is that authentication information can be
stored locally on each [dev/production] application server without needing
to incorporate it into the application project build stream somehow).
I have two questions:
1) Is there any interest in adding this to a cayenne contrib directory? I'm
not sure if it's relevent enough to put into the cayenne core. On the other
hand, it's an example of how to subclass DriverDataSourceFactory to read
driver information from an alternate xml format, and does have use for some
Oracle Application Server JNDI deployers.
2) I am having problems parsing a text tag in the xml file. Each datasource
element can have an optional <description> child element (and maybe other
elements) which I just need to ignore. Originally I thought I could just
ignore the information I wasn't using. When that didn't work, I tried
adding a DefaultHandler instance for children. When that failed, I created
an IgnoreNestedElementsHandler which is really just a nested DefaultHandler.
However, I get an error that the text between <description> tags is
unexpected. Removing all text between <description> and </description>
causes everything to work perfectly, but I can't really do this outside of
my own test environment. There's nothing special about the xml as far as I
can tell. I looked at the source for MapLoader which handles similar
nested text elements (for example, db-generator-type), and I see no special
treatment being done there. However, since my total SAX experience is with
modifying Cayenne code, maybe I'm missing something fundamental somewhere.
Error:
========================================================================
org.objectstyle.cayenne.ConfigurationException: [v.1.1-dev April 14 2004]
Error during Configuration initialization. [v.1.1-dev April 14 2004] Load
failures. Main configuration class:
org.objectstyle.cayenne.conf.FileConfiguration, details:
domain.node.name=OnlineBillingNode,
domain.node.datasource=/gvea/data-sources.xml:jdbc/CachedDS, reason:
DataSource load failed -
com.gvea.cayenne.OracleApplicationServerXMLDataSourceFactory$DataSourceHandler:
unexpected text "Datasource used for connection cache."
at
org.objectstyle.cayenne.conf.Configuration.initializeSharedConfiguration(Configuration.java:304)
at
com.gvea.struts.ebpp.business.batch.DemandBasedTaskScheduler.main(DemandBasedTaskScheduler.java:310)
Caused by: org.objectstyle.cayenne.ConfigurationException: [v.1.1-dev April
14 2004] Load failures. Main configuration class:
org.objectstyle.cayenne.conf.FileConfiguration, details:
domain.node.name=OnlineBillingNode,
domain.node.datasource=/gvea/data-sources.xml:jdbc/CachedDS, reason:
DataSource load failed -
com.gvea.cayenne.OracleApplicationServerXMLDataSourceFactory$DataSourceHandler:
unexpected text "Datasource used for connection cache."
at
org.objectstyle.cayenne.conf.RuntimeLoadDelegate.finishedLoading(RuntimeLoadDelegate.java:589)
at
org.objectstyle.cayenne.conf.ConfigLoader.loadDomains(ConfigLoader.java:117)
at
org.objectstyle.cayenne.conf.DefaultConfiguration.initialize(DefaultConfiguration.java:185)
at
org.objectstyle.cayenne.conf.Configuration.initializeSharedConfiguration(Configuration.java:296)
... 1 more
========================================================================
This is the raw xml being parsed.
========================================================================
<data-source location="jdbc/CachedDS"
class="oracle.jdbc.pool.OracleConnectionCacheImpl" password="xxx"
max-connect-attempts="5" wait-timeout="30" connection-retry-interval="30"
connection-driver="oracle.jdbc.driver.OracleDriver" username="xxx"
min-connections="1" max-connections="30"
url="jdbc:oracle:thin..xx:1521:xxx" inactivity-timeout="15" name="CachedDS">
<description>Datasource used for connection cache.</description>
</data-source>
========================================================================
Same thing hand-formatted.
========================================================================
<data-source
location="jdbc/CachedDS"
class="oracle.jdbc.pool.OracleConnectionCacheImpl"
password="xxx"
max-connect-attempts="5"
wait-timeout="30"
connection-retry-interval="30"
connection-driver="oracle.jdbc.driver.OracleDriver"
username="xxx"
min-connections="1"
max-connections="30"
url="jdbc:oracle:thin..xx:1521:xxx"
inactivity-timeout="15"
name="CachedDS">
<description>Datasource used for connection cache.</description>
</data-source>
========================================================================
Code:
========================================================================
package com.gvea.cayenne;
import java.io.FileInputStream;
import java.io.InputStream;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.objectstyle.cayenne.ConfigurationException;
import org.objectstyle.cayenne.conf.DriverDataSourceFactory;
import org.objectstyle.cayenne.conn.DataSourceInfo;
import org.objectstyle.cayenne.util.AbstractHandler;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
/**
* Creates DataSource objects from Oracle Application Server datasource.XML
configuration files that
* describe a JDBC driver. Wraps JDBC driver in a generic DataSource
* implementation.
*
*..uthor Mike Kienenberger
*/
public class OracleApplicationServerXMLDataSourceFactory extends
DriverDataSourceFactory {
private static Logger logObj =
Logger.getLogger(OracleApplicationServerXMLDataSourceFactory.class);
protected String jndiLocation = null;
protected int jndiDatasourcesFoundCount = 0;
/**
* Default constructor
*..hrows Exception
*/
public OracleApplicationServerXMLDataSourceFactory() throws Exception {
super();
}
/**
* Loads driver information from the file at <code>location</code>.
* Called internally from "getDataSource"
*/
protected void load(String datasourceLocation) throws Exception {
logObj.log(
logLevel,
"loading driver information from '" + datasourceLocation +
"'.");
String datasourceFileLocation = null;
int colonPos = datasourceLocation.indexOf(':');
if (-1 != colonPos)
{
datasourceFileLocation = datasourceLocation.substring(0,
colonPos);
if (colonPos+1 >= datasourceLocation.length())
{
logObj.log(
logLevel,
"Error: location '" + datasourceLocation + "' contains
no JNDI location after ':'.");
throw new ConfigurationException(
"Can't find DataSource configuration file at " +
datasourceLocation + ": location '" + datasourceLocation + "' contains no
data after ':'.");
}
jndiLocation = datasourceLocation.substring(colonPos + 1);
}
else
{
datasourceFileLocation =
"/ora/Ora10gAS/j2ee/home/config/data-sources.xml";
jndiLocation = datasourceLocation;
}
InputStream in = new FileInputStream(datasourceFileLocation);
if (in == null) {
logObj.log(
logLevel,
"Error: location '" + datasourceFileLocation + "' not
found.");
throw new ConfigurationException(
"Can't find DataSource configuration file at " +
datasourceFileLocation);
}
RootHandler handler = new RootHandler();
handler.init(logObj, logLevel, parser);
parser.setContentHandler(handler);
parser.setErrorHandler(handler);
parser.parse(new InputSource(in));
if (0 == jndiDatasourcesFoundCount)
{
logObj.log(
logLevel,
"Error: Can't find datasource definition " + jndiLocation +
" in " + datasourceFileLocation);
throw new ConfigurationException(
"Can't find datasource definition " + jndiLocation + " in "
+ datasourceFileLocation);
}
else if (1 < jndiDatasourcesFoundCount)
{
logObj.log(
logLevel,
"Error: Found " + jndiDatasourcesFoundCount + " datasource
definitions " + jndiLocation + " in " + datasourceFileLocation);
throw new ConfigurationException(
"Found " + jndiDatasourcesFoundCount + " datasource
definitions " + jndiLocation + " in " + datasourceFileLocation);
}
}
protected void incrementJndiDatasourcesFoundCount()
{
++jndiDatasourcesFoundCount;
}
// SAX handlers start below
/** Handler for the root element. Its only child must be the
"data-sources" element. */
private class RootHandler extends DefaultHandler {
private Logger logObj;
private Level logLevel;
private XMLReader parser;
public void init(Logger logObj, Level logLevel, XMLReader parser)
throws SAXException {
this.logObj = logObj;
this.logLevel = logLevel;
this.parser = parser;
}
/**
* Handles the start of a "data-sources" element. A data-sources
handler is created
* and initialized with the element name and attributes.
*
*..xception SAXException if the tag given is not
* <code>"data-sources"</code>
*/
public void startElement(
String namespaceURI,
String localName,
String qName,
Attributes atts)
throws SAXException {
if (localName.equals("data-sources")) {
new DataSourcesHandler(parser, this).init(localName,
atts, logObj, logLevel);
} else {
logObj.log(
logLevel,
"<data-sources> must be the root element. <"
+ localName
+ "> is unexpected.");
throw new SAXException(
"Config file is not of expected XML type. '"
+ localName
+ "' unexpected.");
}
}
}
/** Handler for the "data-sources" element. */
private class DataSourcesHandler extends AbstractHandler {
private Logger logObj;
private Level logLevel;
public DataSourcesHandler(XMLReader parser, ContentHandler
parentHandler) {
super(parser, parentHandler);
}
public void init(String name, Attributes attrs, Logger logObj, Level
logLevel) throws SAXException {
this.logObj = logObj;
this.logLevel = logLevel;
}
/**
* Handles the start of a data-source child element. An appropriate
handler
* is created and initialized with the element name and attributes.
*
*..xception SAXException if the tag given is not recognized.
*/
public void startElement(
String namespaceURI,
String localName,
String qName,
Attributes atts)
throws SAXException {
new DataSourceHandler(this.parser, this).init(
localName,
atts,
logObj, logLevel);
}
}
/** Handler for the "data-source" element. */
private class DataSourceHandler extends AbstractHandler {
public DataSourceHandler(XMLReader parser, ContentHandler
parentHandler) {
super(parser, parentHandler);
}
public void init(String name, Attributes attrs,
Logger logObj, Level logLevel) throws SAXException {
String location = attrs.getValue("", "location");
logObj.log(logLevel, "loading driver location " + location);
if (jndiLocation.equals(location))
{
incrementJndiDatasourcesFoundCount();
driverInfo = new DataSourceInfo();
String connectionDriver = attrs.getValue("",
"connection-driver");
logObj.log(logLevel, "loading driver class " +
connectionDriver);
driverInfo.setJdbcDriver(connectionDriver);
String username = attrs.getValue("", "username");
logObj.log(logLevel, "loading driver username " + username);
driverInfo.setUserName(username);
String password = attrs.getValue("", "password");
logObj.log(logLevel, "loading driver password " + password);
driverInfo.setPassword(password);
String url = attrs.getValue("", "url");
logObj.log(logLevel, "loading driver url " + url);
driverInfo.setDataSourceUrl(url);
String min = attrs.getValue("", "min");
logObj.log(logLevel, "loading driver min " + min);
if (min != null)
driverInfo.setMinConnections(Integer.parseInt(min));
String max = attrs.getValue("", "max");
logObj.log(logLevel, "loading driver max " + max);
if (max != null)
driverInfo.setMaxConnections(Integer.parseInt(max));
}
}
/**
* Handles the start of a child element (like "description").
Currently ignored.
*
*..xception SAXException if the tag given is not recognized.
*/
public void startElement(
String namespaceURI,
String localName,
String qName,
Attributes atts)
throws SAXException {
// ignore any children elements
new IgnoreNestedElementsHandler();
}
}
/** Handler for the "data-source" element. */
private class IgnoreNestedElementsHandler extends DefaultHandler {
public IgnoreNestedElementsHandler() {
super();
}
/**
* Handles the start of a child element (like "description").
Currently ignored.
*
*..xception SAXException if the tag given is not recognized.
*/
public void startElement(
String namespaceURI,
String localName,
String qName,
Attributes atts)
throws SAXException {
// ignore any children elements
new IgnoreNestedElementsHandler();
}
}
}
========================================================================
This archive was generated by hypermail 2.0.0 : Tue Jul 27 2004 - 19:49:03 EDT