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");
...
     










































  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值