openfire(2)数据库脚本执行

本文主要介绍了Openfire服务器启动时的数据库相关操作,包括通过`initialize()`检查setup状态,`verifyDataSource()`验证数据源并执行自动化脚本。在`DbConnectionManager.getConnection()`方法中,它尝试从配置或默认提供者获取数据库连接,并在连接失败时进行重试。`schemaManager.checkOpenfireSchema(con)`负责检查Openfire的数据库模式,并根据版本执行相应的SQL脚本。同时,`checkPluginSchema()`方法处理插件的数据库升级,依据命名规则执行SQL脚本。
摘要由CSDN通过智能技术生成

当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

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值