一、应用场景
系统初始化的时候
如果没有创建olap数据源需要先创建olap数据源
否则直接获取所有的数据源存放在全局变量datasources里面以便于后续步骤中获取plap-connections
二、代码详细解析
1、olap数据源对象结构
(1) SaikuDatasource - org.saiku.datasources.datasource.SaikuDatasource
public SaikuDatasource( String name, Type type, Properties properties ) {
this.name = name;//数据源名称
this.type = type;//数据源类型
this.properties = properties;//数据源属性
}
public enum Type {
OLAP
}
(2) DataSource - org.saiku.datasources.datasource.SaikuDatasource.DataSource
public DataSource(SaikuDatasource datasource) {
this.type = datasource.getType().toString();
this.name = datasource.getName();
this.driver = datasource.getProperties().getProperty("driver");
this.location = datasource.getProperties().getProperty("location");
this.username = datasource.getProperties().getProperty("username");
this.password = datasource.getProperties().getProperty("password");
this.id = datasource.getProperties().getProperty("id");
this.encryptpassword =datasource.getProperties().getProperty("encrypt.password");
this.securityenabled =datasource.getProperties().getProperty("security.enabled");
this.securitytype = datasource.getProperties().getProperty("security.type");
this.securitymapping =datasource.getProperties().getProperty("security.mapping");
this.advanced = datasource.getProperties().getProperty("advanced");
}
2、新增OLAP数据源
(1)判断是否需要新增此OLAP数据源的代码如下:
代码结构
|-Database.loadLegacyDatasources()
|- LegacyImporterImpl.importDatasources()
详细代码LegacyImporterImpl.importDatasources()
关键代码:
1) 获取数据源配置文件所在文件夹
String repoURL = "";
FileSystemManager fileSystemManager = VFS.getManager();
fileObject fileObject = fileSystemManager.resolveFile("res:saiku-datasources");
repoURL = fileObject.getURL();
2)遍历该文件夹下所有文件
File[] files = new File(repoURL.getFile()).listFiles();
3)获取OLAP数据源的配置构造saiku-ds对象并判断是否存在,不存在才添加
for (File file : files) {
Properties props = new Properties();
props.load(new FileInputStream(file));
稍微处理下props的location属性之后创建saikuDs
SaikuDatasource ds = new SaikuDatasource(name, t, props);
//获取已加入JCR的ds
List<DataSource> dsList = irm.getAllDataSources();
//比对待添加的OLAP_DS和已存在的OLAP_DS的名字,如果不存在,才添加
boolean isExists = false;
for (DataSource dataSource : dsList) {
if(dataSource.getName().equals(ds.getName())){
isExists = true;
break;
}
}
if(!isExists){
dsm.addDatasource(ds);
}
}
(2)新增数据源具体步骤
第一步将ds加入JCR节点
第二步将ds加入全局datasources
RepositoryDatasourceManager.addDatasource(SaikuDatasource datasource)
//源代码 private Map<String, SaikuDatasource> datasources = Collections.synchronizedMap(new HashMap<String, SaikuDatasource>());
IRepositoryManager irm = JackRabbitRepositoryManager.getJackRabbitRepositoryManager(configurationpath, datadir, repopassword,oldpassword); public SaikuDatasource addDatasource(SaikuDatasource datasource){ DataSource ds = new DataSource(datasource); irm.saveDataSource(ds, "/datasources/" + ds.getName() + ".sds", "fixme"); datasources.put(datasource.getName(), datasource); return datasource; }
(3)详解第一步:将ds加入JCR节点
JackRabbitRepositoryManager.saveDataSource(DataSource ds, String path, String user) //源代码 public void saveDataSource(DataSource ds, String path, String user) throws RepositoryException { //定义字节输出流 ByteArrayOutputStream baos = new ByteArrayOutputStream(); //将DataSource对象转换成XML文件,存入baos中 try { JAXBContext jaxbContext = JAXBContext.newInstance(DataSource.class); Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); jaxbMarshaller.marshal(ds, baos); } catch (JAXBException e) { log.error("Could not read XML", e); } //获取文件名 int pos = path.lastIndexOf("/"); String filename = "./" + path.substring(pos + 1, path.length());//结果为./schema名 //获取数据源根节点/datadatasources Node n = getFolder(path.substring(0, pos)); //在根节点下添加文件节点resNode: path = /datadatasources/filename //指定node名字为filename,类型为file,属性为olap_ds,以便后续查询olap数据源能查询到 Node resNode = n.addNode(filename, "nt:file"); resNode.addMixin("nt:olapdatasource"); //在新创建的resNode节点下添加文件内容节点contentNode:
//path = /datadatasources/filename/jcr:content //设置该内容节点的内容为转换的XML的内容 Node contentNode = resNode.addNode("jcr:content", "nt:resource"); contentNode.setProperty("jcr:data", baos.toString()); //至此,数据源属性节点和配置内容节点就加入到JCR结构中了 //最后,别忘了保存新增的节点 resNode.getSession().save(); }
3、获取所有OLAP数据源
(1) 初始化内容仓库管理器
private String configurationXml = projectPath + "saiku-repository/configuration.xml"; private String datadir = projectPath + "saiku-repository/data"; private String repopassword = "sa!kuanalyt!cs"; private String oldpassword = ""; IRepositoryManager irm = JackRabbitRepositoryManager.getJackRabbitRepositoryManager(configurationpath, datadir, repopassword,oldpassword);
(2) 初始化JCR基本结构
irm.start(userService); 关键代码: 1)获得内容根节点 //根据configurationXml文件配置在datadir路径下创建JCR文件夹基本结构 //相当于创建MyRepo RepositoryConfig config = RepositoryConfig.create(configurationXml, datadir); //根据JCR文件夹基本结构生成repository对象 repository = RepositoryImpl.create(config); //获取操作JCR的权限[也叫Ticket] session = repository.login( new SimpleCredentials("admin", password.toCharArray())); //根据session获取JCR的根节点 JackrabbitSession js = (JackrabbitSession) session; session = js; root = session.getRootNode(); root.getSession().save(); 2)为workspace注册Node的类型。四种类型:File/Folder/Schema/DataSource createFiles(); createFolders(); createSchemas(); createDataSources(); //创建的大致步骤 NodeTypeManager manager = session.getWorkspace().getNodeTypeManager();//相同的代码 NodeTypeTemplate ntt = manager.createNodeTypeTemplate();//相同的代码 ntt.setName("nt:saikufiles");//依次nt:saikufiles/nt:saikufolders/nt:mondrianschema/nt:olapdatasource String[] str = new String[]{"nt:file"};//依次nt:saikufiles/nt:folder/nt:file/nt:file ntt.setDeclaredSuperTypeNames(str); ntt.setMixin(true); //创建pdt对象 name有几个值就创建几个 //File 创建五个:name分别为owner/type/roles/users/jcr:data //Folder 创建四个:name分别为owner/type/roles/users //Schema 创建四个:name分别为owner/schemaname/cubenames/jcr:data ///DataSource 创建三个:name分别为owner/enabled/jcr:data PropertyDefinitionTemplate pdt = manager.createPropertyDefinitionTemplate();//相同的代码 pdt.setName("owner"); pdt.setRequiredType(PropertyType.STRING);//相同的代码 ntt.getPropertyDefinitionTemplates().add(创建pdt对象);//有几个pdt就添加几次 manager.registerNodeType(ntt, false);//注册新建的节点类型//相同的代码 3)为workspace注册命名空间 createNamespace(); NamespaceRegistry ns = session.getWorkspace().getNamespaceRegistry(); if (!Arrays.asList(ns.getPrefixes()).contains("home")) { ns.registerNamespace("home", "http://www.meteorite.bi/namespaces/home"); } 4)构建repository结构 在root节点下新增如下文件夹节点结构,并赋予一定的ACL权限<略>
结构: /homes /datasources /etc /etc/legacyreports /etc/theme /etc/theme/legacyreports Node n = JcrUtils.getOrAddFolder(root, "homes"); n.addMixin("nt:saikufolders"); n = JcrUtils.getOrAddFolder(root, "datasources"); n.addMixin("nt:saikufolders"); n = JcrUtils.getOrAddFolder(root, "etc"); n.addMixin("nt:saikufolders"); n = JcrUtils.getOrAddFolder(n, "legacyreports"); n.addMixin("nt:saikufolders"); n = JcrUtils.getOrAddFolder(root, "etc/theme"); n.addMixin("nt:saikufolders"); n = JcrUtils.getOrAddFolder(n, "legacyreports"); n.addMixin("nt:saikufolders"); session.save();
(3) 获取JCR结构中存在的数据源
List<DataSource> dslist = irm.getAllDataSources(); 关键代码: 1)获取MDX查询管理器 QueryManager qm = session.getWorkspace().getQueryManager(); 2)查询执行属性的数据,获得所有类型为Cube数据源的节点 //创建Cube数据源时dsNode.addMixin("nt:olapdatasource"); String sql = "SELECT * FROM [nt:olapdatasource]"; Query query = qm.createQuery(sql, Query.JCR_SQL2); QueryResult res = query.execute(); NodeIterator node = res.getNodes(); 3)遍历NodeIterator,解析获取每一个node的属性构造Datasource对象 Node n = node.nextNode();//结果为:node_path = /datadatasources/filename 4)获取cube数据源的schema配置 String schemaContent = n.getNodes("jcr:content").nextNode().getProperty("jcr:data").getString(); 5)将XML文件内容数据流转换为DataSource对象 Unmarshaller jaxbMarshaller = jaxbContext != null ? jaxbContext.createUnmarshaller() : null; JAXBContext jaxbContext = JAXBContext.newInstance(DataSource.class); InputStream stream = new ByteArrayInputStream(schemaContent.getBytes()); DataSource d = (DataSource) (jaxbMarshaller != null ? jaxbMarshaller.unmarshal(stream) : null); 6)设置数据源的路径 d.setPath(n.getPath()); 7)遍历完所有olapds_node以后,返回dsList
(4) 根据dsList拼凑saikuDsList
for (DataSource file : dslist) { Properties props = new Properties(); 根据file构建props SaikuDatasource.Type t = SaikuDatasource.Type.valueOf(file.getType().toUpperCase());//OLAP SaikuDatasource ds = new SaikuDatasource(file.getName(),t,props); datasources.put(file.getName(), ds);//将saikuDs加入到全局变量datasources中 }