Hierarchical Configurations

  在进行ONOS源码学习的时候,经常会看到使用这个类进行对定义好的配置文件进行操作。所有今天就认真来了解以下这个类,方便日后继续使用。

XMLConfiguration的介绍

在Configuration这个接口中大部分的方式是来处理获得的属性的数据类型,这些方法把一个指向属性的key作为他的入参。通过key获得属性的值。
获得属性的方法都是以get开头。后面是数据的类型。例如getString(),将返回String类型。getInt(),将返回int类型。
addProperty(),添加一个新的属性到配置,如果这个属性已经存在,那么这个属性将变成多值属性,并且在多值中增加一个新的。
clearProperty(),从配置中移除特定的属性
setProperty(),覆盖特定的属性
clear()擦除所有的属性。


在现实中的很多配置数据都是分层或者是树状结构的。要处理这样的类可以使用HierarchicalConfiguration接口。这个接口由BaseHierarchicalConfiguration实现,同时还调用了很多apache中别的配置类。
一个突出的例子就是采用XML形式的结构化配置源文件。使用XMLConfiguration进行配置资源的读和写,并使用HierarchicalConfiguration进行一些查询等进行一步的操作。

Accessing properties in hierarchical configurations
一开始先以一个简单的XML文件为例子,展示如何访问属性。(下面的例子名字为gui.xml)

<?
xml version = "1.0" encoding = "ISO-8859-1" ?>
< gui-definition >
 
< colors >
   
< background > #808080 </ background >
   
< text > #000000 </ text >
   
< header > #008000 </ header >
   
< link normal = "#000080" visited = "#800080" />
   
< default > ${colors.header} </ default >
 
</ colors >
 
< rowsPerPage > 15 </ rowsPerPage >
 
< buttons >
   
< name > OK </ name >
   
< name > Cancel </ name >
   
< name > Help </ name >
 
</ buttons >
 
< numberFormat pattern = "###,###.##" />
</ gui-definition >

为了要获得文件里面的信息必须使用XMLConfiguration进行加载。像其他基于文件的配置类一样,FileBasedConfigurationBuilder用于读取源文件,流程如下:
Parameters params = new Parameters();
FileBasedConfigurationBuilder<XMLConfiguration> builder =
   
new FileBasedConfigurationBuilder<XMLConfiguration>(XMLConfiguration.class)
   
.configure(params.xml()
       
.setFileName("gui.xml"));
try
{
   
XMLConfiguration config = builder.getConfiguration();
   
...
}
catch(ConfigurationException cex)
{
   
// loading of the configuration file failed
}
在ONOS中,采用如下的方法进行源文件的读取。
 XMLConfiguration cfg = new XMLConfiguration();
  try {
  cfg.load(getClass().getResourceAsStream("controllers.xml"));
  return cfg;
  } catch (ConfigurationException e) {
  throw new IllegalArgumentException("Cannot load xml from Stream", e);
  }
如果没有异常抛出,那么在XML文件中定义的变量就可以在Configuration中读取到了。
String backColor = config.getString("colors.background");
String textColor = config.getString("colors.text");
String linkNormal = config.getString("colors.link[@normal]");
String defColor = config.getString("colors.default");
int rowsPerPage = config.getInt("rowsPerPage");
List<Object> buttons = config.getList("buttons.name");
看第四行可以知道,XMLconfiguration是支持值插的。他可以引用另一个color
最后一行,因为buttons的name有多个值,所以他返回的是一个list。
在进行SET的时候,允许设置在一条语句中完成,<numberFormat>中定义分割符。
  <buttons>
   
<name>OK, Cancel, Help</name>
 
</buttons>
  <numberFormat pattern="###\,###.##"/>
Complex hierarchical structure
加载一个数据库的schema,文件如下:
<?xml version="1.0" encoding="ISO-8859-1" ?>

<database>
 
<tables>
   
<table tableType="system">
     
<name>users</name>
     
<fields>
       
<field>
         
<name>uid</name>
         
<type>long</type>
       
</field>
       
<field>
         
<name>uname</name>
         
<type>java.lang.String</type>
       
</field>
       
<field>
         
<name>firstName</name>
         
<type>java.lang.String</type>
       
</field>
       
<field>
         
<name>lastName</name>
         
<type>java.lang.String</type>
       
</field>
       
<field>
         
<name>email</name>
         
<type>java.lang.String</type>
       
</field>
     
</fields>
   
</table>
   
<table tableType="application">
     
<name>documents</name>
     
<fields>
       
<field>
         
<name>docid</name>
         
<type>long</type>
       
</field>
       
<field>
         
<name>name</name>
         
<type>java.lang.String</type>
       
</field>
       
<field>
         
<name>creationDate</name>
         
<type>java.util.Date</type>
       
</field>
       
<field>
         
<name>authorID</name>
         
<type>long</type>
       
</field>
       
<field>
         
<name>version</name>
         
<type>int</type>
       
</field>
     
</fields>
   
</table>
 
</tables>
</database>
在这个例子中,database中包含有多个table,每个table中又有多个field,他们由name和type进行区分(这个文件称之为tables.xml)。
如果要获得可能有多个值的时候,可以使用getProperty(),或者getList().如果使用getString则返回list中的一个元素
Object prop = config.getProperty("tables.table.name");
if(prop instanceof Collection)
{
       
System.out.println("Number of tables: " + ((Collection<?>) prop).size());
}
Accessing structured properties
在上一个例子中,如果使用getProperty()后要如何定位到自己想要的具体的属性呢,可以使用tables.table(0).name。

Sub Configurations
有的时候如果属性所属的层级比较下,调用那些属性就会变得不方便,这个时候可以采用HierarchicalConfiguration中的ConfigurationAt()方法。在创建他的时候,先指定父节点,此后就可以通过相对路径来获得子节点的信息。
HierarchicalConfiguration<ImmutableNode> sub = config.configurationAt("tables.table(0)");
String tableName = sub.getString("name"); // only need to provide relative path
List<Object> fieldNames = sub.getList("fields.field.name");
采用configurationAt的一个问题是,当原始的配置发生改变后,子配置里面的信息并不会发生改变,为了解决,可以在使用configurationAt时,增加一个boolean的参数,如果值为true那么返回一个特殊的配置实现(实际上是SubnodeConfiguration类的一个实例),它在与原始配置相同的数据结构上运行。 因此,对一个配置所做的更改直接反映在另一个配置上。如果像例子中,把整个子配置都删除了,那么子配置就保存原来的配置不变

// sub points to the 2nd table

HierarchicalConfiguration<ImmutableNode>sub= config.configurationAt("tables.table(1)",true);
assertEquals("documents",sub.getString("name"));结果为一直的

// Now change name in parent configuration => should be visible in sub config
config
.setProperty("tables.table(1).name","tasks");
assertEquals
("tasks",sub.getString("name"));结果为一致的,表示两边都修改成功了

// Clear the whole content of the 2nd table
config
.clearTree("tables.table(1)");
// The key used to create the sub configuration is no longer valid,
// so it is now detacted; it contains the recent data.
assertEquals("tasks",sub.getString("name"));虽然在夫配置中已经被删除了,在子配置中还是一样

例子中clearTree()就是移除子树的所有信息,类似的还有clearProperty。一旦子树被移除,子配置就与原来的配置失去了连接,就算以后那个子树又被创建,还是失去了连接。
Adding new properties
采用addProperty()。
// Warning: This might cause trouble!
config.addProperty("tables.table.fields.field.name", "size");
第一个参数是你想要添加的位置(会在其后面添加),第二个参数是你想要添加的名称。如果存在多个位置都符合第一个参数,那么选则最后一个。如果我们输入的第一个参数不存在,那么会根据第一个参数新增一条路径
如果输入
config.addProperty("tables.table(1).fields.field(-1).name", "size");
那么就会在fields里面,创建一个新的分支叫做field(用-1表示了),与其他field平行
Escaping special characters
在名字中如果含有. 那么在使用table.value这样的用法时,名字中的.就会被当成分隔符,这个可将.换成..。例如你要找table中名字叫value.name的这个标签,表示为table.value..name。但是这样还是很容易弄错,所以在命名的时候尽量少使用.进行命名。
Internal Representation
在HierarchicalConfiguration接口中含有类型参数来定义他操作节点的类型。在内部,节点构建树结构,可以在其上进行查询或者操作。这些节点不能直接进行访问,而是要用过NodeHandler进行。NodeHandler接口定义了许多方式来访问节点的属性,例如通过名称、值或者其子节点。
// config is of type BaseHierarchicalConfiguration
ImmutableNode root = config.getNodeModel().getNodeHandler().getRootNode();

在之前的例子中如果你需要找到特定的属性例如名字为user的表,你需要知道这个表的index才能单独获得他,但是在很多情况下你并不知道他的index是什么这个时候采用XPATH就可以很好地帮助你,采用tables/table[@name='users']/fields/name。就可以获得对应的值。具体使用方法如下:
Parameters params = new Parameters();
FileBasedConfigurationBuilder<XMLConfiguration> builder =
   
new FileBasedConfigurationBuilder<XMLConfiguration>(XMLConfiguration.class)
   
.configure(params.xml()
       
.setFileName("tables.xml")
       
.setExpressionEngine(new XPathExpressionEngine()));
XMLConfiguration config = builder.getConfiguration();

// Now we can use XPATH queries:
List<Object> fields = config.getList("tables/table[1]/fields/name");
         

XPATH不仅可以使用get方法,还可以使用addProperty来增加新的属性或者分支。
config.addProperty("tables/table[1] type", "system");
       
他会在tables/table[1]下增加一个分支叫type,值为system。type前面用空格进行分割。注意与在XPATH中,tables/table[1]必须存在,并且是唯一的。如果要增加的是属性,则
config.addProperty("tables/table[1] @type", "system");
以下是创建一个表的例子:
// Add new table "tasks" with name element and type attribute
config
.addProperty("tables table/name", "tasks");
// last() selects the last element of this name,
// which is the newest table element
config
.addProperty("tables/table[last()] @type", "system");

// Now add fields
config
.addProperty("tables/table[last()] fields/field/name", "taskid");
config
.addProperty("tables/table[last()]/fields/field[last()] type", "int");
config
.addProperty("tables/table[last()]/fields field/name", "name");
config
.addProperty("tables/table[last()]/fields field/name", "startDate");
...
     










































  
Unexpected problem occured during version sanity check Reported exception: java.lang.AbstractMethodError: org.slf4j.simple.SimpleServiceProvider.getRequesteApiVersion()Ljava/lang/String; at org.slf4j.LoggerFactory.versionSanityCheck(LoggerFactory.java:294) at org.slf4j.LoggerFactory.performInitialization(LoggerFactory.java:141) at org.slf4j.LoggerFactory.getProvider(LoggerFactory.java:418) at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:404) at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:353) at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:379) at org.example.ManagerTest.<clinit>(ManagerTest.java:18) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at org.junit.platform.commons.util.ReflectionUtils.newInstance(ReflectionUtils.java:550) at org.junit.jupiter.engine.execution.ConstructorInvocation.proceed(ConstructorInvocation.java:56) at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) at org.junit.jupiter.api.extension.InvocationInterceptor.interceptTestClassConstructor(InvocationInterceptor.java:73) at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105) at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104) at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:77) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestClassConstructor(ClassBasedTestDescriptor.java:355) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateTestClass(ClassBasedTestDescriptor.java:302) at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.instantiateTestClass(ClassTestDescriptor.java:79) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:280) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$4(ClassBasedTestDescriptor.java:272) at java.util.Optional.orElseGet(Optional.java:267) at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$5(ClassBasedTestDescriptor.java:271) at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:31) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$prepare$0(TestMethodTestDescriptor.java:102) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:101) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:66) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$2(NodeTestTask.java:123) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:123) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:90) at java.util.ArrayList.forEach(ArrayList.java:1259) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) at java.util.ArrayList.forEach(ArrayList.java:1259) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86) at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86) at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53) at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:57) at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235) at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)这怎么了
最新发布
08-05
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值