openfire(2)数据库脚本执行
当XMPPServer启动的时候,会调用其start()方法,
??? public void start() {
??????? try {
??????????? initialize();
??????????? startDate = new Date();
??????????? // Store server info
??????????? xmppServerInfo = new XMPPServerInfoImpl(name, host, version, startDate, getConnectionManager());
??????????? // Create PluginManager now (but don't start it) so that modules may use it
??????????? File pluginDir = new File(openfireHome, "plugins");
??????????? pluginManager = new PluginManager(pluginDir);
??????????? // If the server has already been setup then we can start all the server's modules
??????????? if (!setupMode) {
??????????????? verifyDataSource();
??????????????? // First load all the modules so that modules may access other modules while
??????????????? // being initialized
??????????????? loadModules();
??????????????? // Initize all the modules
??????????????? initModules();
??????????????? // Start all the modules
??????????????? startModules();
??????????? }
??????????? // Initialize statistics
??????????? ServerTrafficCounter.initStatistics();
??????????? // Load plugins (when in setup mode only the admin console will be loaded)
??????????? pluginManager.start();
??????????? // Log that the server has been started
??????????? String startupBanner = LocaleUtils.getLocalizedString("short.title") + " " + version.getVersionString() +
??????????????????? " [" + JiveGlobals.formatDateTime(new Date()) + "]";
??????????? Log.info(startupBanner);
??????????? System.out.println(startupBanner);
??????????? started = true;
???????????
??????????? // Notify server listeners that the server has been started
??????????? for (XMPPServerListener listener : listeners) {
??????????????? listener.serverStarted();
??????????? }
??????? }
??????? catch (Exception e) {
??????????? e.printStackTrace();
??????????? Log.error(e.getMessage(), e);
??????????? System.out.println(LocaleUtils.getLocalizedString("startup.error"));
??????????? shutdownServer();
??????? }
??? }
?
start方法中干的事情太多了,这里主要介绍数据库方面,其他的暂时不做介绍。
initialize();会读取openfire.xml中的setup的值,如果为true,就不会做数据的验证操作。
openfire所有的自动化执行简表脚本都在此方法中verifyDataSource();
?
private void verifyDataSource() {
??????? Connection con = null;
??????? PreparedStatement pstmt = null;
??????? ResultSet rs = null;
??????? try {
??????????? con = DbConnectionManager.getConnection();在此做了很多的操作。
??????????? pstmt = con.prepareStatement("SELECT count(*) FROM ofID");
??????????? rs = pstmt.executeQuery();
??????????? rs.next();
??????? }
??????? catch (Exception e) {
??????????? System.err.println("Database setup or configuration error: " +
??????????????????? "Please verify your database settings and check the " +
??????????????????? "logs/error.log file for detailed error messages.");
??????????? Log.error("Database could not be accessed", e);
??????????? throw new IllegalArgumentException(e);
??????? }
??????? finally {
??????????? DbConnectionManager.closeConnection(rs, pstmt, con);
??????? }
??? }
?
DbConnectionManager.getConnection();:
在获取数据库链接的时候会做如下操作:
public static Connection getConnection() throws SQLException {
??????? if (connectionProvider == null) {
??????????? synchronized (providerLock) {
??????????????? if (connectionProvider == null) {
??????????????????? // Attempt to load the connection provider classname as
??????????????????? // a Jive property.
??????????????????? String className = JiveGlobals.getXMLProperty("connectionProvider.className");
??????????????????? if (className != null) {
??????????????????????? // Attempt to load the class.
??????????????????????? try {
??????????????????????????? Class conClass = ClassUtils.forName(className);
??????????????????????????? setConnectionProvider((ConnectionProvider)conClass.newInstance());
??????????????????????? }
??????????????????????? catch (Exception e) {
??????????????????????????? Log.warn("Failed to create the " +
??????????????????????????????????? "connection provider specified by connection" +
??????????????????????????????????? "Provider.className. Using the default pool.", e);
??????????????????????????? setConnectionProvider(new DefaultConnectionProvider());
??????????????????????? }
??????????????????? }
??????????????????? else {
??????????????????????? setConnectionProvider(new DefaultConnectionProvider());
??????????????????? }
??????????????? }
??????????? }
??????? }
??????? // TODO: May want to make these settings configurable
??????? Integer retryCnt = 0;
??????? Integer retryMax = 10;
??????? Integer retryWait = 250; // milliseconds
??????? Connection con = null;
??????? SQLException lastException = null;
??????? do {
??????????? try {
??????????? ?con = connectionProvider.getConnection();
??????????????? if (con != null) {
??????????????????? // Got one, lets hand it off.
??????????????????? // Usually profiling is not enabled. So we return a normal
??????????????????? // connection unless profiling is enabled. If yes, wrap the
??????????????????? // connection with a profiled connection.
??????????????????? if (!profilingEnabled) {
??????????????????????? return con;
??????????????????? }
??????????????????? else {
??????????????????????? return new ProfiledConnection(con);
??????????????????? }
??????????????? }
??????????? } catch (SQLException e) {
??????????? ?// TODO distinguish recoverable from non-recoverable exceptions.
??????????? ?lastException = e;
??????????? ?Log.info("Unable to get a connection from the database pool " +
??????????? ???"(attempt "+retryCnt+" out of "+retryMax+").", e);
???}
??????????? try {
??????????????? Thread.sleep(retryWait);
??????????? }
??????????? catch (Exception e) {
??????????????? // Ignored
??????????? }
??????????? retryCnt++;
??????? } while (retryCnt <= retryMax);
??????? throw new SQLException("ConnectionManager.getConnection() " +
??????????????? "failed to obtain a connection after " + retryCnt +" retries. " +
??????????????? "The exception from the last attempt is as follows: "+lastException);
??? }
?
会在数据库配置文件中读取connectionProvider的配置,如果没有,就采用默认的DefaultConnectionProvider,
?
?
public static void setConnectionProvider(ConnectionProvider provider) {
??????? synchronized (providerLock) {
??????????? if (connectionProvider != null) {
??????????????? connectionProvider.destroy();
??????????????? connectionProvider = null;
??????????? }
??????????? connectionProvider = provider;
??????????? connectionProvider.start();
??????????? // Now, get a connection to determine meta data.
??????????? Connection con = null;
??????????? try {
??????????????? con = connectionProvider.getConnection();
??????????????? setMetaData(con);
??????????????? // Check to see if the database schema needs to be upgraded.
??????????????? schemaManager.checkOpenfireSchema(con);
??????????? }
??????????? catch (Exception e) {
??????????????? Log.error(e.getMessage(), e);
??????????? }
??????????? finally {
??????????????? closeConnection(con);
??????????? }
??????? }
?
?
?
?? schemaManager.checkOpenfireSchema(con);是模板管理器,这个才是真的自动建表的管理器。
checkOpenfireSchema方法调用 private boolean checkSchema(Connection con, String schemaKey, int requiredVersion,
??????????? ResourceLoader resourceLoader) throws Exception;方法,根据版本号来确定是否需要建表,会读取相关的sql脚本。
?
?public boolean checkPluginSchema(final Plugin plugin) ,这个方法也是根据版本号来执行插件中database中sql脚本,其有一定的命名规则,插件名_数据库类型.sql。这个地方的版本号是从插件的配置文件中读取
<databaseKey>clientcontrol</databaseKey>
??? <databaseVersion>0</databaseVersion>,
这个配置的作用已在另外一篇文章中做说明了。
?
此篇文章就到此,稍后会有更多关于openfire的个人解读。
联系方式(qq):851392159
出处:http://buerkai.iteye.com
?