FileDocCategorySizeDatePackage
SqlResources.javaAPI DocApache James 2.3.114751Fri Jan 12 12:56:34 GMT 2007org.apache.james.util

SqlResources

public class SqlResources extends Object
Provides a set of SQL String resources (eg SQL Strings) to use for a database connection. This class allows SQL strings to be customised to particular database products, by detecting product information from the jdbc DatabaseMetaData object.

Fields Summary
private Map
m_sql
A map of statement types to SQL statements
private Map
m_dbOptions
A map of engine specific options
private static Map
stringTable
A set of all used String values
private org.apache.oro.text.perl.Perl5Util
m_perl5Util
A Perl5 regexp matching helper class
Constructors Summary
Methods Summary
public java.lang.StringgetDbOption(java.lang.String name)
Returns the dbOption string value set for the specified dbOption name.

param
name the name of the dbOption required.
return
the requested dbOption value

        return (String)m_dbOptions.get(name);
    
public java.lang.StringgetSqlString(java.lang.String name)
Returns a named SQL string for the specified connection, replacing parameters with the values set.

param
name the name of the SQL resource required.
return
the requested resource

        return (String)m_sql.get(name);
    
public java.lang.StringgetSqlString(java.lang.String name, boolean required)
Returns a named SQL string for the specified connection, replacing parameters with the values set.

param
name the name of the SQL resource required.
param
required true if the resource is required
return
the requested resource
throws
ConfigurationException if a required resource cannot be found.

        String sql = getSqlString(name);

        if (sql == null && required) {
            StringBuffer exceptionBuffer =
                new StringBuffer(64)
                        .append("Required SQL resource: '")
                        .append(name)
                        .append("' was not found.");
            throw new RuntimeException(exceptionBuffer.toString());
        }
        return sql;
    
public voidinit(java.io.File sqlFile, java.lang.String sqlDefsSection, java.sql.Connection conn, java.util.Map configParameters)
Configures a DbResources object to provide SQL statements from a file. SQL statements returned may be specific to the particular type and version of the connected database, as well as the database driver. Parameters encoded as $(parameter} in the input file are replace by values from the parameters Map, if the named parameter exists. Parameter values may also be specified in the resourceSection element.

param
sqlFile the input file containing the string definitions
param
sqlDefsSection the xml element containing the strings to be used
param
conn the Jdbc DatabaseMetaData, taken from a database connection
param
configParameters a map of parameters (name-value string pairs) which are replaced where found in the input strings


                                                                                                                                                                   
         
                        
         
    
        // Parse the sqlFile as an XML document.
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document sqlDoc = builder.parse(sqlFile);

        // First process the database matcher, to determine the
        //  sql statements to use.
        Element dbMatcherElement = 
            (Element)(sqlDoc.getElementsByTagName("dbMatchers").item(0));
        String dbProduct = null;
        if ( dbMatcherElement != null ) {
            dbProduct = matchDbConnection(conn, dbMatcherElement);
            m_perl5Util = null;     // release the PERL matcher!
        }

        // Now get the options valid for the database product used.
        Element dbOptionsElement = 
            (Element)(sqlDoc.getElementsByTagName("dbOptions").item(0));
        if ( dbOptionsElement != null ) {
            // First populate the map with default values 
            populateDbOptions("", dbOptionsElement, m_dbOptions);
            // Now update the map with specific product values
            if ( dbProduct != null ) {
                populateDbOptions(dbProduct, dbOptionsElement, m_dbOptions);
            }
        }

        
        // Now get the section defining sql for the repository required.
        NodeList sections = sqlDoc.getElementsByTagName("sqlDefs");
        int sectionsCount = sections.getLength();
        Element sectionElement = null;
        boolean found = false;
        for (int i = 0; i < sectionsCount; i++ ) {
            sectionElement = (Element)(sections.item(i));
            String sectionName = sectionElement.getAttribute("name");
            if ( sectionName != null && sectionName.equals(sqlDefsSection) ) {
                found = true;
                break;
            }

        }
        if ( !found ) {
            StringBuffer exceptionBuffer =
                new StringBuffer(64)
                        .append("Error loading sql definition file. ")
                        .append("The element named \'")
                        .append(sqlDefsSection)
                        .append("\' does not exist.");
            throw new RuntimeException(exceptionBuffer.toString());
        }

        // Get parameters defined within the file as defaults,
        // and use supplied parameters as overrides.
        Map parameters = new HashMap();
        // First read from the <params> element, if it exists.
        Element parametersElement = 
            (Element)(sectionElement.getElementsByTagName("parameters").item(0));
        if ( parametersElement != null ) {
            NamedNodeMap params = parametersElement.getAttributes();
            int paramCount = params.getLength();
            for (int i = 0; i < paramCount; i++ ) {
                Attr param = (Attr)params.item(i);
                String paramName = param.getName();
                String paramValue = param.getValue();
                parameters.put(paramName, paramValue);
            }
        }
        // Then copy in the parameters supplied with the call.
        parameters.putAll(configParameters);

        // 2 maps - one for storing default statements,
        // the other for statements with a "db" attribute matching this 
        // connection.
        Map defaultSqlStatements = new HashMap();
        Map dbProductSqlStatements = new HashMap();

        // Process each sql statement, replacing string parameters,
        // and adding to the appropriate map..
        NodeList sqlDefs = sectionElement.getElementsByTagName("sql");
        int sqlCount = sqlDefs.getLength();
        for ( int i = 0; i < sqlCount; i++ ) {
            // See if this needs to be processed (is default or product specific)
            Element sqlElement = (Element)(sqlDefs.item(i));
            String sqlDb = sqlElement.getAttribute("db");
            Map sqlMap;
            if ( sqlDb.equals("")) {
                // default
                sqlMap = defaultSqlStatements;
            }
            else if (sqlDb.equals(dbProduct) ) {
                // Specific to this product
                sqlMap = dbProductSqlStatements;
            }
            else {
                // for a different product
                continue;
            }

            // Get the key and value for this SQL statement.
            String sqlKey = sqlElement.getAttribute("name");
            if ( sqlKey == null ) {
                // ignore statements without a "name" attribute.
                continue;
            }
            String sqlString = sqlElement.getFirstChild().getNodeValue();

            // Do parameter replacements for this sql string.
            Iterator paramNames = parameters.keySet().iterator();
            while ( paramNames.hasNext() ) {
                String paramName = (String)paramNames.next();
                String paramValue = (String)parameters.get(paramName);

                StringBuffer replaceBuffer =
                    new StringBuffer(64)
                            .append("${")
                            .append(paramName)
                            .append("}");
                sqlString = substituteSubString(sqlString, replaceBuffer.toString(), paramValue);
            }

            // See if we already have registered a string of this value
            String shared = (String) stringTable.get(sqlString);
            // If not, register it -- we will use it next time
            if (shared == null) {
                stringTable.put(sqlString, sqlString);
            } else {
                sqlString = shared;
            }

            // Add to the sqlMap - either the "default" or the "product" map
            sqlMap.put(sqlKey, sqlString);
        }

        // Copy in default strings, then overwrite product-specific ones.
        m_sql.putAll(defaultSqlStatements);
        m_sql.putAll(dbProductSqlStatements);
    
private java.lang.StringmatchDbConnection(java.sql.Connection conn, org.w3c.dom.Element dbMatchersElement)
Compares the DatabaseProductName value for a jdbc Connection against a set of regular expressions defined in XML. The first successful match defines the name of the database product connected to. This value is then used to choose the specific SQL expressions to use.

param
conn the JDBC connection being tested
param
dbMatchersElement the XML element containing the database type information
return
the type of database to which James is connected

        String dbProductName = conn.getMetaData().getDatabaseProductName();
    
        NodeList dbMatchers = 
            dbMatchersElement.getElementsByTagName("dbMatcher");
        for ( int i = 0; i < dbMatchers.getLength(); i++ ) {
            // Get the values for this matcher element.
            Element dbMatcher = (Element)dbMatchers.item(i);
            String dbMatchName = dbMatcher.getAttribute("db");
            StringBuffer dbProductPatternBuffer =
                new StringBuffer(64)
                        .append("/")
                        .append(dbMatcher.getAttribute("databaseProductName"))
                        .append("/i");

            // If the connection databaseProcuctName matches the pattern,
            // use the match name from this matcher.
            if ( m_perl5Util.match(dbProductPatternBuffer.toString(), dbProductName) ) {
                return dbMatchName;
            }
        }
        return null;
    
private voidpopulateDbOptions(java.lang.String dbProduct, org.w3c.dom.Element dbOptionsElement, java.util.Map dbOptionsMap)
Gets all the name/value pair db option couples related to the dbProduct, and put them into the dbOptionsMap.

param
dbProduct the db product used
param
dbOptionsElement the XML element containing the options
param
dbOptionsMap the Map to populate

        NodeList dbOptions = 
            dbOptionsElement.getElementsByTagName("dbOption");
        for ( int i = 0; i < dbOptions.getLength(); i++ ) {
            // Get the values for this option element.
            Element dbOption = (Element)dbOptions.item(i);
            // Check is this element is pertinent to the dbProduct
            // Notice that a missing attribute returns "", good for defaults
            if (!dbProduct.equalsIgnoreCase(dbOption.getAttribute("db"))) {
                continue;
            }
            // Put into the map
            dbOptionsMap.put(dbOption.getAttribute("name"), dbOption.getAttribute("value"));
        }
    
private java.lang.StringsubstituteSubString(java.lang.String input, java.lang.String find, java.lang.String replace)
Replace substrings of one string with another string and return altered string.

param
input input string
param
find the string to replace
param
replace the string to replace with
return
the substituted string

        int find_length = find.length();
        int replace_length = replace.length();

        StringBuffer output = new StringBuffer(input);
        int index = input.indexOf(find);
        int outputOffset = 0;

        while ( index > -1 ) {
            output.replace(index + outputOffset, index + outputOffset + find_length, replace);
            outputOffset = outputOffset + (replace_length - find_length);

            index = input.indexOf(find, index + find_length);
        }

        String result = output.toString();
        return result;