Tomcat源码阅读四:Digester工具

来源:互联网 发布:异地备份软件 编辑:程序博客网 时间:2024/06/05 05:06
     为了不将一些tomcat配置写在代码里, tomcat使用了配置文件server.xml来记录系统配置。同时,使用开源库Digester将xml文件中的元素转换为java对象。
     配置文件中的标签 称为模式,如<?xml version="1.0" encoding="ISO-8859-1"?> 
<employee firstName="Brian" lastName="May">
   <office>
     <address streeName="Wellington Street" streetNumber="100"/>
   </office>
</employee>
DIigester解析xml时使用一种规则来约定如何解析,规则类是是Rule类的子类。以下是在解析xml文件时,digester做的一些事:
(1)digester会先遇到employee的开始标签,因此,它会检查是否有rule和模式employee相关联。 若
有,调用该rule的begin方法;
(2)然后,它会遇到office的开始标签,检查是否有rule与模式employee/office相关联,若有,调用
该rule的begin方法;
(3)接下来遇到address的开始标签,执行过程与前面相同;
(4)然后,遇到前面已经遇到的标签的结束标签,调用各自rule的end方法。
看个简单的例子:
 public static void main(String[] args) {
    String path = System.getProperty("user.dir") + File.separator  + "etc";
    File file = new File(path, "employee1.xml");
    Digester digester = new Digester();
    // add rules
    digester.addObjectCreate("employee", "ex15.pyrmont.digestertest.Employee");
    digester.addSetProperties("employee");   
    digester.addCallMethod("employee", "printName");

    try {
      Employee employee = (Employee) digester.parse(file);
      System.out.println("First name : " + employee.getFirstName());
      System.out.println("Last name : " + employee.getLastName());
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  } 
     对于要解析度目标文件,要为解析器添加Rule规则,告诉解析器当遇到规则中的几种标签元素模式时应该如何去解析,添加规则之后即可解析文件。解析器模块可以简单的分为三个子模块,Digester类、RulesBase类和Rule规则的实现类。其中Digester类是解析器类,RuleBase类并不是Rule的子类,而是一个支持类,Rule的实现类则是各种解析规则。RuleBase是Rules类的实现类,Rules是一个接口,规则了的父类Rule是一个抽象类源码注释中对Rules的定义: Public interface defining a collection of Rule instances.即Rules表示对一组Rule规则类集合的定义。
     Digester中有一个成员变量Rules rules = null;默认实现是RulesBase类。以及一个栈的实例    protected ArrayStack stack = new ArrayStack();,stack用于存放已经解析得到实例化的对象。RulesBase中有两个比较重要的成员变量属性:
               protected HashMap cache = new HashMap();
               protected ArrayList rules = new ArrayList();
cache用来存放同一种模式的Rule规则链表类,rules就是Rule规则链表。同一种模式都会使用同一个键值放到map中去,比如digester.addObjectCreate("employee", "ex15.pyrmont.digestertest.Employee");
    digester.addSetProperties("employee");    
    digester.addCallMethod("employee", "printName");
这三个规则都会使用同一个链表,键值为"employee",list中存放着三种模式。
     首先,Digester添加规则:public void addObjectCreate(String pattern, String className) {

        addRule(pattern,
                new ObjectCreateRule(className));

    }
     addRule中new一个新的规则类
  public void addRule(String pattern, Rule rule) {

        rule.setDigester(this);
        getRules().add(pattern, rule);

    }
getRules返回Digester对象的Rules实现类,默认为RulesBase,其add方法如下:
 public void add(String pattern, Rule rule) {
        // to help users who accidently add '/' to the end of their patterns
        int patternLength = pattern.length();
        if (patternLength>1 && pattern.endsWith("/")) {
            pattern = pattern.substring(0, patternLength-1);
        }        
        List list = (List) cache.get(pattern);
        if (list == null) {
            list = new ArrayList();
            cache.put(pattern, list);
        }
        list.add(rule);
        rules.add(rule);
        if (this.digester != null) {
            rule.setDigester(this.digester);
        }
        if (this.namespaceURI != null) {
            rule.setNamespaceURI(this.namespaceURI);
        }
    }
此外,这些类包含有对象引用来进行关系的关联,RulesBase和Rule中的Digester的引用则用于对象之间的关联。看下ObjectCreateRule类的实现:
     ObjectCreateRule继承自Rule类,主要有begin方法和end方法用于说明Digester解析器解析相应xml文件时要执行的操作。
  public void begin(Attributes attributes) throws Exception {

        // Identify the name of the class to instantiate
        String realClassName = className;
        if (attributeName != null) {
            String value = attributes.getValue(attributeName);
            if (value != null) {
                realClassName = value;
            }
        }
        if (digester.log.isDebugEnabled()) {
            digester.log.debug("[ObjectCreateRule]{" + digester.match +
                    "}New " + realClassName);
        }

        // Instantiate the new object and push it on the context stack
        Class clazz = digester.getClassLoader().loadClass(realClassName);
        Object instance = clazz.newInstance();
        digester.push(instance);

    }
     实例化相应的模式类,并调用digester对象的push方法push到栈。end方法则将对象从digester的栈中pop。
另外说明下,DIgester是使用了Sax进行xml文件的解析,因此Digester类中还有一些Sax的内容比如SaxFactory以praser等等。
SetPropertiesRule类:
 public void begin(Attributes attributes) throws Exception {
       
        // Populate the corresponding properties of the top object
        Object top = digester.peek();
        if (digester.log.isDebugEnabled()) {
            if (top != null) {
                digester.log.debug("[SetPropertiesRule]{" + digester.match +
                                   "} Set " + top.getClass().getName() +
                                   " properties");
            } else {
                digester.log.debug("[SetPropertiesRule]{" + digester.match +
                                   "} Set NULL properties");
            }
        }
       
        // set up variables for custom names mappings
        int attNamesLength = 0;
        if (attributeNames != null) {
            attNamesLength = attributeNames.length;
        }
        int propNamesLength = 0;
        if (propertyNames != null) {
            propNamesLength = propertyNames.length;
        }
       
        for (int i = 0; i < attributes.getLength(); i++) {
            String name = attributes.getLocalName(i);
            if ("".equals(name)) {
                name = attributes.getQName(i);
            }
            String value = attributes.getValue(i);
           
            // we'll now check for custom mappings
            for (int n = 0; n<attNamesLength; n++) {
                if (name.equals(attributeNames[n])) {
                    if (n < propNamesLength) {
                        // set this to value from list
                        name = propertyNames[n];
                   
                    } else {
                        // set name to null
                        // we'll check for this later
                        name = null;
                    }
                    break;
                }
            }
           
            if (digester.log.isDebugEnabled()) {
                digester.log.debug("[SetPropertiesRule]{" + digester.match +
                        "} Setting property '" + name + "' to '" +
                        value + "'");
            }
            IntrospectionUtils.setProperty(top, name, value);
        }

    }

0 0
原创粉丝点击