天天看點

saiku 中繼資料存儲分析

一、介紹

使用saiku的人一定對他的中繼資料存儲都特别感興趣,特别是有分布式管理需求的項目,更是迫切需要了解。其實它是使用Apache的開源項目Jackrabbit管理檔案的!

二、代碼跟蹤

我也是使用了一段時間,希望深入了解它的中繼資料存儲,下面是代碼跟蹤:

2.1 ajax

首先還是從ajax入手:ajax請求:/saiku/rest/saiku/admin/datasources?_=1466478165922

對應的腳本:org.saiku.web.rest.resources.AdminResource,方法如下:

@GET
    @Produces( {"application/json"})
    @Path("/datasources")
    @ReturnType("java.lang.List<SaikuDatasource>")
    public Response getAvailableDataSources()       

發現核心代碼是:datasourceService.getDatasources().values() 不過看不出來什麼,于是從代碼注入開始查起!

2.2 代碼注入

AdminResource對象注入:
    <bean id="adminBean" class="org.saiku.web.rest.resources.AdminResource">
        <property name="userService" ref="userServiceBean"/>
        <property name="datasourceService" ref="datasourceServiceBean"/>
        <property name="olapDiscoverService" ref="olapDiscoverServiceBean"/>
        <property name="repositoryDatasourceManager" ref="repositoryDsManager"/>
        <property name="logExtractor" ref="logwriterbean"/>
    </bean>
UserService對象注入:
    <bean id="userServiceBean" class="org.saiku.service.user.UserService">
        <property name="jdbcUserDAO" ref="userDAO"/>
        <property name="datasourceService" ref="datasourceServiceBean"/>
        <property name="iDatasourceManager" ref="repositoryDsManager"/>
        <property name="adminRoles">
            <list>
                <value>ROLE_ADMIN</value>
            </list>
        </property>
        <property name="sessionService" ref="sessionService"/>
    </bean>
DatasourceService對象注入:
    <bean id="datasourceServiceBean" class="org.saiku.service.datasource.DatasourceService">
        <property name="connectionManager" ref="connectionManager"/>
    </bean>      

發現部分核心代碼:

private void readObject(ObjectInputStream stream)
      throws IOException, ClassNotFoundException {
    stream.defaultReadObject();
    datasources = connectionManager.getDataSourceManager();
  }      

繼續跟蹤: 

connectionManager對象注入:
    <bean id="connectionManager" class="org.saiku.web.core.SecurityAwareConnectionManager" init-method="init"
          destroy-method="destroy" depends-on="mondrianVFS">
        <property name="dataSourceManager" ref="repositoryDsManager"/> --這是注入執行setDataSourceManager方法,傳入repositoryDsManager對象
        <property name="sessionService" ref="sessionService"/>
    </bean>
repositoryDsManager對象注入:
    <bean id="repositoryDsManager" class="org.saiku.service.datasource.RepositoryDatasourceManager" init-method="load" destroy-method="unload">
        <property name="userService" ref="userServiceBean"/>
        <property name="configurationpath" value="../../repository/configuration.xml"/>
        <property name="datadir" value="../../repository/data"/>
        <property name="foodmartdir" value="../../data"/>
        <property name="foodmartschema" value="../../data/FoodMart4.xml"/>
        <property name="foodmarturl" value="jdbc:h2:../../data/foodmart;MODE=MySQL"/>
        <property name="earthquakeDir" value="../../data"/>
        <property name="earthquakeSchema" value="../../data/Earthquakes.xml"/>
        <property name="earthquakeUrl" value="jdbc:h2:../../data/earthquakes;MODE=MySQL"/>
        <property name="repoPasswordProvider" ref ="repoPasswordProviderBean"/>
        <property name="defaultRole" value="ROLE_USER"/>
        <!-- If you change the repoPassword set this property for at least 1 restart to update the old repo password-->
        <!--<property name="oldRepoPassword" value="sa!kuanalyt!cs"/>-->
    </bean>      

擷取所有的中繼資料,就是擷取RepositoryDatasourceManager對象的datasources對象,這個對象是由下面的代碼生成的: 

public void load() {
        irm = JackRabbitRepositoryManager.getJackRabbitRepositoryManager(configurationpath, datadir, repopasswordprovider.getPassword(),
            oldpassword, defaultRole);
        try {
            irm.start(userService);
            this.saveInternalFile("/etc/.repo_version", "d20f0bea-681a-11e5-9d70-feff819cdc9f", null);
        } catch (RepositoryException e) {
            log.error("Could not start repo", e);
        }
        datasources.clear();
        try {
 
            List<DataSource> exporteddatasources = null;
            try {
                exporteddatasources = irm.getAllDataSources();
            } catch (RepositoryException e1) {
                log.error("Could not export data sources", e1);
            }
 
            if (exporteddatasources != null) {
                for (DataSource file : exporteddatasources) {
                    if (file.getName() != null && file.getType() != null) {
                        Properties props = new Properties();
                        SaikuDatasource.Type t = SaikuDatasource.Type.valueOf(file.getType().toUpperCase());
                        SaikuDatasource ds = new SaikuDatasource(file.getName(), t, props);
                        datasources.put(file.getName(), ds);
                    }
                }
            } 
        } catch (Exception e) {
            throw new SaikuServiceException(e.getMessage(), e);
        }
    }      

三、終極發現

saiku是使用JackRabbit管理樹狀中繼資料的,如果想要擴充,隻能在JackRabbit基礎上進行擴充,同志們繼續努力!      
JackRabbitIBM文檔:http://www.ibm.com/developerworks/cn/java/j-jcr/  
JackRabbit入門文檔: http://suigara.iteye.com/blog/1454765