📄 abstractjdbcusersrepository.java
字号:
/*********************************************************************** * Copyright (c) 2000-2004 The Apache Software Foundation. * * All rights reserved. * * ------------------------------------------------------------------- * * Licensed under the Apache License, Version 2.0 (the "License"); you * * may not use this file except in compliance with the License. You * * may obtain a copy of the License at: * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software * * distributed under the License is distributed on an "AS IS" BASIS, * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * * implied. See the License for the specific language governing * * permissions and limitations under the License. * ***********************************************************************/package org.apache.james.userrepository;import org.apache.avalon.cornerstone.services.datasource.DataSourceSelector;import org.apache.avalon.excalibur.datasource.DataSourceComponent;import org.apache.avalon.framework.CascadingRuntimeException;import org.apache.avalon.framework.activity.Initializable;import org.apache.avalon.framework.component.Component;import org.apache.avalon.framework.component.ComponentException;import org.apache.avalon.framework.component.ComponentManager;import org.apache.avalon.framework.component.Composable;import org.apache.avalon.framework.configuration.Configurable;import org.apache.avalon.framework.configuration.Configuration;import org.apache.avalon.framework.configuration.ConfigurationException;import org.apache.avalon.framework.context.Context;import org.apache.avalon.framework.context.ContextException;import org.apache.avalon.framework.context.Contextualizable;import org.apache.james.context.AvalonContextUtilities;import org.apache.james.services.User;import org.apache.james.util.JDBCUtil;import org.apache.james.util.SqlResources;import java.io.File;import java.sql.*;import java.util.*;/** * An abstract base class for creating UserRepository implementations * which use a database for persistence. * * To implement a new UserRepository using by extending this class, * you need to implement the 3 abstract methods defined below, * and define the required SQL statements in an SQLResources * file. * * The SQL statements used by this implementation are: * <TABLE> * <TH><TD><B>Required</B></TD></TH> * <TR><TD>select</TD><TD>Select all users.</TD></TR> * <TR><TD>insert</TD><TD>Insert a user.</TD></TR> * <TR><TD>update</TD><TD>Update a user.</TD></TR> * <TR><TD>delete</TD><TD>Delete a user by name.</TD></TR> * <TR><TD>createTable</TD><TD>Create the users table.</TD></TR> * <TH><TD><B>Optional</B></TD></TH> * <TR><TD>selectByLowercaseName</TD><TD>Select a user by name (case-insensitive lowercase).</TD></TR> * </TABLE> * */public abstract class AbstractJdbcUsersRepository extends AbstractUsersRepository implements Contextualizable, Composable, Configurable, Initializable{ /** * The Avalon context used by the instance */ protected Context context; protected Map m_sqlParameters; private String m_sqlFileName; private String m_datasourceName; private DataSourceSelector m_datasources; private DataSourceComponent m_datasource; // Fetches all Users from the db. private String m_getUsersSql; // This fetch a user by name, ensuring case-insensitive matching. private String m_userByNameCaseInsensitiveSql; // Insert, update and delete sql statements are not guaranteed // to be case-insensitive; this is handled in code. private String m_insertUserSql; private String m_updateUserSql; private String m_deleteUserSql; // Creates a single table with "username" the Primary Key. private String m_createUserTableSql; // The JDBCUtil helper class private JDBCUtil theJDBCUtil; /** * @see org.apache.avalon.framework.context.Contextualizable#contextualize(Context) */ public void contextualize(final Context context) throws ContextException { this.context = context; } /** * @see org.apache.avalon.framework.component.Composable#compose(ComponentManager) */ public void compose( final ComponentManager componentManager ) throws ComponentException { StringBuffer logBuffer = null; if (getLogger().isDebugEnabled()) { logBuffer = new StringBuffer(64) .append(this.getClass().getName()) .append(".compose()"); getLogger().debug( logBuffer.toString() ); } m_datasources = (DataSourceSelector)componentManager.lookup( DataSourceSelector.ROLE ); } /** * Configures the UserRepository for JDBC access.<br> * <br> * Requires a configuration element in the .conf.xml file of the form:<br> * <br> * <pre> * <repository name="LocalUsers" * class="org.apache.james.userrepository.JamesUsersJdbcRepository"> * <!-- Name of the datasource to use --> * <data-source>MailDb</data-source> * <!-- File to load the SQL definitions from --> * <sqlFile>dist/conf/sqlResources.xml</sqlFile> * <!-- replacement parameters for the sql file --> * <sqlParameters table="JamesUsers"/> * </repository> * </pre> */ public void configure(Configuration configuration) throws ConfigurationException { StringBuffer logBuffer = null; if (getLogger().isDebugEnabled()) { logBuffer = new StringBuffer(64) .append(this.getClass().getName()) .append(".configure()"); getLogger().debug( logBuffer.toString() ); } // Parse the DestinationURL for the name of the datasource, // the table to use, and the (optional) repository Key. String destUrl = configuration.getAttribute("destinationURL"); // normalise the destination, to simplify processing. if ( ! destUrl.endsWith("/") ) { destUrl += "/"; } // Split on "/", starting after "db://" List urlParams = new ArrayList(); int start = 5; int end = destUrl.indexOf('/', start); while ( end > -1 ) { urlParams.add(destUrl.substring(start, end)); start = end + 1; end = destUrl.indexOf('/', start); } // Build SqlParameters and get datasource name from URL parameters m_sqlParameters = new HashMap(); switch ( urlParams.size() ) { case 3: m_sqlParameters.put("key", urlParams.get(2)); case 2: m_sqlParameters.put("table", urlParams.get(1)); case 1: m_datasourceName = (String)urlParams.get(0); break; default: throw new ConfigurationException ("Malformed destinationURL - " + "Must be of the format \"db://<data-source>[/<table>[/<key>]]\"."); } if (getLogger().isDebugEnabled()) { logBuffer = new StringBuffer(128) .append("Parsed URL: table = '") .append(m_sqlParameters.get("table")) .append("', key = '") .append(m_sqlParameters.get("key")) .append("'"); getLogger().debug(logBuffer.toString()); } // Get the SQL file location m_sqlFileName = configuration.getChild("sqlFile", true).getValue(); if (!m_sqlFileName.startsWith("file://")) { throw new ConfigurationException ("Malformed sqlFile - Must be of the format \"file://<filename>\"."); } // Get other sql parameters from the configuration object, // if any. Configuration sqlParamsConfig = configuration.getChild("sqlParameters"); String[] paramNames = sqlParamsConfig.getAttributeNames(); for (int i = 0; i < paramNames.length; i++ ) { String paramName = paramNames[i]; String paramValue = sqlParamsConfig.getAttribute(paramName); m_sqlParameters.put(paramName, paramValue); } } /** * <p>Initialises the JDBC repository.</p> * <p>1) Tests the connection to the database.</p> * <p>2) Loads SQL strings from the SQL definition file, * choosing the appropriate SQL for this connection, * and performing parameter substitution,</p> * <p>3) Initialises the database with the required tables, if necessary.</p> * * @throws Exception if an error occurs */ public void initialize() throws Exception { StringBuffer logBuffer = null; if (getLogger().isDebugEnabled()) { logBuffer = new StringBuffer(128) .append(this.getClass().getName()) .append(".initialize()"); getLogger().debug( logBuffer.toString() ); } theJDBCUtil = new JDBCUtil() { protected void delegatedLog(String logString) { AbstractJdbcUsersRepository.this.getLogger().warn("AbstractJdbcUsersRepository: " + logString); } }; // Get the data-source required. m_datasource = (DataSourceComponent)m_datasources.select(m_datasourceName); // Test the connection to the database, by getting the DatabaseMetaData. Connection conn = openConnection(); try{ DatabaseMetaData dbMetaData = conn.getMetaData(); File sqlFile = null; try { sqlFile = AvalonContextUtilities.getFile(context, m_sqlFileName); } catch (Exception e) { getLogger().fatalError(e.getMessage(), e); throw e; } if (getLogger().isDebugEnabled()) { logBuffer = new StringBuffer(256) .append("Reading SQL resources from file: ") .append(sqlFile.getAbsolutePath()) .append(", section ") .append(this.getClass().getName()) .append("."); getLogger().debug(logBuffer.toString()); } SqlResources sqlStatements = new SqlResources(); sqlStatements.init(sqlFile, this.getClass().getName(), conn, m_sqlParameters); // Create the SQL Strings to use for this table. // Fetches all Users from the db. m_getUsersSql = sqlStatements.getSqlString("select", true); // Get a user by lowercase name. (optional) // If not provided, the entire list is iterated to find a user. m_userByNameCaseInsensitiveSql = sqlStatements.getSqlString("selectByLowercaseName"); // Insert, update and delete are not guaranteed to be case-insensitive // Will always be called with correct case in username.. m_insertUserSql = sqlStatements.getSqlString("insert", true); m_updateUserSql = sqlStatements.getSqlString("update", true); m_deleteUserSql = sqlStatements.getSqlString("delete", true); // Creates a single table with "username" the Primary Key. m_createUserTableSql = sqlStatements.getSqlString("createTable", true); // Check if the required table exists. If not, create it. // The table name is defined in the SqlResources. String tableName = sqlStatements.getSqlString("tableName", true); // Need to ask in the case that identifiers are stored, ask the DatabaseMetaInfo. // NB this should work, but some drivers (eg mm MySQL) // don't return the right details, hence the hackery below. /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -