/*
* Copyright 2001-2008 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
* $Id: Xml2Datasources.java 3918 2008-04-14 17:35:35Z gbevin $
*/
package com.uwyn.rife.database;
import com.uwyn.rife.config.Config;
import com.uwyn.rife.xml.Xml2Data;
import com.uwyn.rife.xml.exceptions.XmlErrorException;
import java.util.HashMap;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import org.xml.sax.Attributes;
/**
* This class parses an XML file to create a set of {@link Datasource}
* objects.
* <p>An example of the parsable datasource file:
* <pre><datasources>
* <datasource name="postgres">
* <driver>org.postgresql.Driver</driver>
* <url>jdbc:postgres://localhost/database</url>
* <user>username</user>
* <password>password</user>
* <poolsize>5</poolsize>
* </datasource>
*</datasources></pre>
* <p>An explaination of terms:
* <ul>
* <li>datasource name: used to uniquely identify the datasource
* <li>driver: the classname of the driver to use to connect
* <li>url: the connection url used to connect
* <li>user: the username needed for authentication
* <li>password: the password needed for authentication
* <li>poolsize: the number of connections to always keep connected
* </ul>
* Multiple datasource definitions are supported and can be used at anytime.
*
* @author JR Boyens (jboyens[remove] at uwyn dot com)
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @version $Revision: 3918 $
* @since 1.0
*/
public class Xml2Datasources extends Xml2Data
{
private Datasource mDatasource = null;
private HashMap<String, Datasource> mDatasources = null;
private String mNameAttribute = null;
private StringBuilder mCharacterData = null;
/**
* Return the created datasources.
*
* @return the datasources created after parsing
* @since 1.0
*/
public HashMap<String, Datasource> getDatasources()
{
return mDatasources;
}
/**
* Clears the information in this datasource.
*
* @since 1.0
*/
protected void clear()
{
mDatasource = null;
mDatasources = new HashMap<String, Datasource>();
mNameAttribute = null;
mCharacterData = null;
}
/**
* Called when the beginng of the document to be parsed is found
*
* @since 1.0
*/
public void startDocument()
{
clear();
}
/**
* Called when the start tag of an XML element is encountered
*
* @param namespaceURI the URI of the namespace of the start tag
* @param localName the local name of the starting element
* @param qName the qualified name of the starting element
* @param atts the attributes of the starting element
* @since 1.0
*/
public void startElement(String namespaceURI, String localName, String qName, Attributes atts)
{
if (qName.equals("datasource"))
{
mNameAttribute = atts.getValue("name");
mDatasource = new Datasource();
}
else if (qName.equals("driver") ||
qName.equals("url") ||
qName.equals("user") ||
qName.equals("password") ||
qName.equals("poolsize") ||
qName.equals("jndi"))
{
mCharacterData = new StringBuilder();
}
else if (qName.equals("config"))
{
if (mCharacterData != null &&
Config.hasRepInstance())
{
mCharacterData.append(Config.getRepInstance().getString(atts.getValue("param"), ""));
}
}
else if (qName.equals("datasources"))
{
// do nothing
}
else
{
throw new XmlErrorException("Unsupport element name '"+qName+"'.");
}
}
/**
* Called when the end tag of an XML element is encountered
*
* @param namespaceURI the URI of the namespace of the ending element
* @param localName the local name of the ending element
* @param qName the qualified name of the ending element
* @since 1.0
*/
public void endElement(String namespaceURI, String localName, String qName)
{
if (qName.equals("datasource"))
{
mDatasources.put(mNameAttribute, mDatasource);
}
else if (qName.equals("driver"))
{
mDatasource.setDriver(mCharacterData.toString());
}
else if (qName.equals("url"))
{
mDatasource.setUrl(mCharacterData.toString());
}
else if (qName.equals("user"))
{
mDatasource.setUser(mCharacterData.toString());
}
else if (qName.equals("password"))
{
mDatasource.setPassword(mCharacterData.toString());
}
else if (qName.equals("jndi"))
{
Context ctx;
try
{
ctx = new InitialContext();
Object ds = ctx.lookup(mCharacterData.toString());
if (null == ds)
{
throw new XmlErrorException("The '"+mCharacterData.toString()+"' JNDI entry returned 'null'.");
}
if (!(ds instanceof DataSource))
{
throw new XmlErrorException("The '"+mCharacterData.toString()+"' JNDI entry isn't a DataSource.");
}
mDatasource.setDataSource((DataSource)ds);
}
catch (NamingException e)
{
throw new XmlErrorException("Unexpected error while looking up the '"+mCharacterData.toString()+"' JNDI entry.", e);
}
}
else if (qName.equals("poolsize"))
{
try
{
mDatasource.setPoolsize(Integer.parseInt(mCharacterData.toString()));
}
catch (NumberFormatException e)
{
throw new XmlErrorException("The value of the poolsize isn't an integer.", e);
}
}
}
/**
* Called when text data is encountered, usually between tags.
*
* @param ch a character array of the encountered text content
* @param start the index in the array at which the content starts
* @param length the length of the data stored in the character array
* @since 1.0
*/
public void characters(char[] ch, int start, int length)
{
if (length > 0)
{
mCharacterData.append(String.copyValueOf(ch, start, length));
}
}
}