openmeetings-install分析(九)——Admin类询问阶段processInstall分析(2)

2021SC@SDUSC


在上篇文章中,我们从Admin类询问阶段processInstall方法入手,分析到了ConnectionPropertiesPatcher类的patch方法、patch方法中的getConnectionProperties方法、getConnectionProperties方法中的Arr类;从Admin类跨越到了同包下的ConnectionPropertiesPatcher类,不过也都处在我的分析任务内,所以直接就一并对他们进行详细分析了。

在这篇文章中,我们将继续对上篇文章中未分析完的方法进行详细分析。

getConnectionProperties

    // ConnectionPropertiesPatcher.java
	public static ConnectionProperties getConnectionProperties(File conf) throws Exception {
	    // 新建一个ConnectionProperties对象
		ConnectionProperties props = new ConnectionProperties();
		// 通过传入的File实例获取Document实例
		Document doc = getDocument(conf);
		Attr attr = getConnectionProperties(doc);
		String[] tokens = attr.getValue().split(",");
		loadProperties(tokens, props);
		return props;
	}

在上篇文章中,我们知道Attr attr = getConnectionProperties(doc)方法会根据获得的Document实例从当前元素中获取到了节点的value属性,赋给Attr的实例对象attr。

接下来我们分析loadProperties(tokens, props);这段代码

    // ConnectionPropertiesPatcher.java
	private static void loadProperties(String[] tokens, ConnectionProperties connectionProperties) {
	    //ConnectionProperties来自openmeetings-util
		String prop;
		//遍历每个token,token即为获取到的节点属性
		for (int i = 0; i < tokens.length; ++i) {
			prop = getPropFromPersistence(tokens, i, DRIVER_PREFIX);
			if (prop != null) {
				connectionProperties.setDriver(prop);
			}

			prop = getPropFromPersistence(tokens, i, USER_PREFIX);
			if (prop != null) {
				connectionProperties.setLogin(prop);
			}

			prop = getPropFromPersistence(tokens, i, PASS_PREFIX);
			if (prop != null) {
				connectionProperties.setPassword(prop);
			}

			prop = getPropFromPersistence(tokens, i, URL_PREFIX);
			if (prop != null) {
				try {
					//will try to "guess" dbType
					String[] parts = prop.split(":");
					connectionProperties.setDbType("sqlserver".equals(parts[1]) ? DbType.mssql : DbType.valueOf(parts[1]));
				} catch (Exception e) {
					//ignore
				}
				connectionProperties.setURL(prop);
			}
		}
	}

看到prop = getPropFromPersistence(tokens, i, DRIVER_PREFIX);这行代码,我们来分析一下getPropFromPersistence方法

    //ConnectionPropertiesPatcher.java
	protected static String getPropFromPersistence(String[] tokens, int idx, String name){
		String prop = tokens[idx].trim();
		//startsWith() 方法用于检测字符串是否以指定的前缀开始。
		if (prop.startsWith(name)) {
			// From "Username=root" getting only "root"
			// substring() 方法返回字符串的子字符串。
			// indexOf(int ch): 返回指定字符在字符串中第一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1。
			// 在这里,返回“=”第一次出现的索引,并+1,作为返回子字符串的开始索引
			return prop.substring(prop.indexOf('=') + 1);
		}
		return null;
	}

所以loadProperties方法的作用就是加载属性。遍历属性列表,依次取出一些目标属性对应的值,赋给prop。prop若不为空,则将对应的值设置为connectionProperties的驱动。

这样getConnectionProperties就结束了。可以回顾一下这个方法做了什么:首先新建了ConnectionProperties对象,然后通过传入的File实例获取Document实例,接着根据该Document实例获取属性数组,对属性数组进行解析,分别加载进对应的connectionProperties驱动。

Patch

    // ConnectionPropertiesPatcher.java
	public static ConnectionProperties patch(String dbType, String host, String port, String db, String user, String pass) throws Exception {
		ConnectionProperties props = getConnectionProperties(OmFileHelper.getPersistence(dbType));
		props.setLogin(user);
		props.setPassword(pass);
		ConnectionPropertiesPatcher patcher = getPatcher(props);
		props.setURL(patcher.getUrl(props.getURL(), host, port, db));
		patch(props);
		return props;
	}

我们从getConnectionProperties方法返回后,接下来通过setLogin、setPassword等方法设置该props的用户名和密码等属性,然后我们看一下patch(props)这个方法

    // ConnectionPropertiesPatcher.java
	public static void patch(ConnectionProperties props) throws Exception {
		ConnectionPropertiesPatcher patcher = getPatcher(props);
		Document doc = getDocument(OmFileHelper.getPersistence(props.getDbType()));
		Attr attr = getConnectionProperties(doc);
		String[] tokens = attr.getValue().split(",");
		patcher.patchAttribute(tokens);
		attr.setValue(StringUtils.join(tokens, ","));

		TransformerFactory transformerFactory = TransformerFactory.newInstance();
		Transformer transformer = transformerFactory.newTransformer();
		DOMSource source = new DOMSource(doc);
		transformer.transform(source, new StreamResult(OmFileHelper.getPersistence().getCanonicalPath())); //this constructor is used to avoid transforming path to URI
	}

前面几行代码和我们在getConnectionProperties方法(本篇文章第一部分)中分析的作用是类似的,我们主要关注下面Transformer的部分

TransformerFactory实例可用于创建Transformer和Templates对象。

Transformer这个抽象类的实例可以将源树转换为结果树。可以使用该类实例处理来自各种来源的XML,并将转换输出写入各种接收器。该类的对象不能用于并发运行的多个线程中。不同的Transformer可以由不同的线程同时使用。一个Transformer可以被多次使用。在转换中保留参数和输出属性。
transform方法
transform方法接收2个参数,一个是Source类实例,一个是Result类实例。该方法将XML源转换为结果。特定的转换行为由实例化Transformer时的TransformerFactory的设置以及对Transformer实例的任何修改决定。一个空的Source表示为一个由DocumentBuilder.newDocument()构造的空文档。转换空源的结果取决于转换行为;它并不总是一个空的结果。

在我们的代码中传入的第一个实参是DOMSource对象,DOMSource是文档对象模型(DOM)树形式的转换源树的持有者。第二个实参是StreamResult对象,StreamResult是转换结果的持有者,转换结果可以是XML、纯文本、HTML或其他形式的标记。在我们的代码中,我们使用的是StreamResult(String systemId)构造函数,用于从url中构造一个StreamResult对象。

我们分析一下OmFileHelper.getPersistence().getCanonicalPath():

OmFileHelper来自openmeeting-util;getPersistence方法最后得到的是路径为"classes/META-INF/persistence.xml"(默认路径)的File类文件;getCanonicalPath方法会返回抽象路径名的规范路径名字符串。 规范路径名是绝对路径名,并且是惟一的。规范路径名的准确定义与系统有关。如有必要,此方法首先将路径名转换成绝对路径名,这与调用 getAbsolutePath() 方法的效果一样,然后用与系统相关的方式将它映射到其惟一路径名。这通常涉及到从路径名中移除多余的名称(比如 “.” 和 “…”)、分析符号连接(对于 UNIX 平台),以及将驱动器名转换成标准大小写形式(对于 Microsoft Windows 平台)。

所以OmFileHelper.getPersistence().getCanonicalPath()这段代码最终得到的是一个规范路径名字符串,作为参数传入StreamResult构造器中,StreamResult构造器根据该url构造一个StreamResult对象,作为参数传入transform方法中。tranform方法负责将源转换为结果,保存在StreamResult中。

小小总结一下patch方法,首先获取props,设置其属性,获取该props对应的patcher,执行patch方法(另一个);patch方法从DOM中获取属性数组,解析属性并设置,接着通过transform方法将XML源转换为结果。最后返回一个已附带上属性的connectionProperties实例。

总结

本篇文章对上篇文章中未分析完的代码进行补充分析,分析了getConnectionProperties和patch两个方法。接下来的文章,就可以回到processInstall方法体内再对其他代码进行分析了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值