naobe @ ウィキ

Digester

最終更新:

Bot(ページ名リンク)

- view
管理者のみ編集可
OpenSourceに戻る


Tomat6内臓のDigesterについて記述する。以下は、上記リンクの要約

初めに

 DigesterはXMLに従ってJavaオブジェクトツリーを作成する。もともとstrutsのXML設定ファイルを処理するために作られたが、汎用的であるため、commonsプロジェクトに移管した。
 使用するにあたって、要素のマッチングパターンが充足した時に起動する処理ルールによって操作されるスタックをDigesterは外部にさらす。
 スタックに関連する操作は以下。意味は一般的なスタックと同じ。
  • clear()
  • peek()
  • pop()
  • push()

代表的なデザインパターンは、XMLの特別な要素が始まったときに、ルールがオブジェクトを作成しスタックにpushすること。要素が終了した時にスタックからpopする。

設定プロパティ



オブジェクトスタック


エレメントマッチングパターン


プロセスルール


ロギング



使用例

Tomcat6 server.xml

Tomcat6のorg.apache.catalina.startup.Catalina
server.xmlをパースしている。
 public class Catalina extends Embedded {
 
 load()
   Digester digester = createStartDigester();
   
   InputSource inputSource = null;
   InputStream inputStream = null;
   File file = null;
   try {
     file = configFile();                                                  //server.xml
     inputStream = new FileInputStream(file);
     inputSource = new InputSource("file://" + file.getAbsolutePath());
     catch (Exception e) {
       ;
     }
   try {
     inputSource.setByteStream(inputStream);
     digester.push(this);                                                   //自分をスタックにpush
     digester.parse(inputSource);                                           //server.xmlをparse
     inputStream.close();
   } catch (Exception e) {
     log.warn("Catalina.start using "
     + getConfigFile() + ": " , e);
     return;
   }
 
 // 親の親であるStandardServiceのメソッド
 public void setServer(Server server) {
   this.server = server;
 }
 
 
 createStartDigester()
   Digester digester = new Digester();
   digester.setValidating(false);
   digester.setRulesValidation(true);
   HashMap<Class, List<String>> fakeAttributes = new HashMap<Class, List<String>>();
   ArrayList<String> attrs = new ArrayList<String>();
   attrs.add("className");
   fakeAttributes.put(Object.class, attrs);
   digester.setFakeAttributes(fakeAttributes);
   digester.setClassLoader(StandardServer.class.getClassLoader());
   
   // Configure the actions we will be using
   digester.addObjectCreate("Server",			// server.xmlの<Server>要素を見つけたらorg.apache.catalina.core.StandardServerを作成し、スタックに積む
    "org.apache.catalina.core.StandardServer",
    "className");
   digester.addSetProperties("Server");
   digester.addSetNext("Server",				//上から2番目のスタック(Catalinaオブジェクト)のsetServerメソッドを実行。引数の型はServer。引数の値はStandardServer。
     "setServer",
     "org.apache.catalina.Server");
   
   digester.addObjectCreate("Server/GlobalNamingResources",   //server.xmlの<Server><GlobalNamingResources>の要素を見つけたらorg.apache.catalina.deploy.NamingResourcesを作成しスタックに積む。
      "org.apache.catalina.deploy.NamingResources");
   digester.addSetProperties("Server/GlobalNamingResources");
   digester.addSetNext("Server/GlobalNamingResources",     // 上から2番目のスタック(StandardServer)のsetGlobalNamingResourcesメソッドを実行
     "setGlobalNamingResources",
     "org.apache.catalina.deploy.NamingResources");
   
   digester.addObjectCreate("Server/Listener",          // server.xmlの<Server><Listener>要素を見つけたら、要素classNameのクラスを作成する。
      null, // MUST be specified in the element
      "className");
   digester.addSetProperties("Server/Listener");
   digester.addSetNext("Server/Listener",
     "addLifecycleListener",
     "org.apache.catalina.LifecycleListener");
   
   digester.addObjectCreate("Server/Service",
     "org.apache.catalina.core.StandardService",
     "className");
   digester.addSetProperties("Server/Service");
   digester.addSetNext("Server/Service",
     "addService",
     "org.apache.catalina.Service");
   
   digester.addObjectCreate("Server/Service/Listener",
      null, // MUST be specified in the element
     "className");
   digester.addSetProperties("Server/Service/Listener");
   digester.addSetNext("Server/Service/Listener",
     "addLifecycleListener",
     "org.apache.catalina.LifecycleListener");
   
   //Executor
   digester.addObjectCreate("Server/Service/Executor",
     "org.apache.catalina.core.StandardThreadExecutor",
     "className");
   digester.addSetProperties("Server/Service/Executor");
   
   digester.addSetNext("Server/Service/Executor",
     "addExecutor",
     "org.apache.catalina.Executor");
   
   		
   digester.addRule("Server/Service/Connector",
      new ConnectorCreateRule());
  	digester.addRule("Server/Service/Connector", 
    new SetAllPropertiesRule(new String[]{"executor"}));
   	digester.addSetNext("Server/Service/Connector",
     "addConnector",
     "org.apache.catalina.connector.Connector");
   		
   		
  	digester.addObjectCreate("Server/Service/Connector/Listener",
      null, // MUST be specified in the element
     "className");
  	digester.addSetProperties("Server/Service/Connector/Listener");
  	digester.addSetNext("Server/Service/Connector/Listener",
     "addLifecycleListener",
     "org.apache.catalina.LifecycleListener");
   
   // Add RuleSets for nested elements
   digester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/"));
   digester.addRuleSet(new EngineRuleSet("Server/Service/"));
   digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));
   digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));
   digester.addRuleSet(ClusterRuleSetFactory.getClusterRuleSet("Server/Service/Engine/Host/Cluster/  ")  );
   digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/"));
   
   // When the 'engine' is found, set the parentClassLoader.
   digester.addRule("Server/Service/Engine",
      new SetParentClassLoaderRule(parentClassLoader));
   digester.addRuleSet(ClusterRuleSetFactory.getClusterRuleSet("Server/Service/Engine/Cluster/"));
   
   long t2=System.currentTimeMillis();
   if (log.isDebugEnabled())
     log.debug("Digester for server.xml created " + ( t2-t1 ));
   return (digester);
   

commons-digester3-3.2のexample

AddressBook.xml
<?xml version='1.0'?>
<!--
 Licensed to the [[Apache]] Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
 this work for additional information regarding copyright ownership.
 The ASF licenses this file to You under the Apache License, Version 2.0
 (the "License"); you may not use this file except in compliance with
 the License.  You may obtain a copy of the License at
  
      http://www.apache.org/licenses/LICENSE-2.0
  
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
-->
<address-book>
  <person id="1" category="acquaintance">
    <name>Gonzo</name>
    <email type="business">gonzo@muppets.com</email>
    <address>
      <type>home</type>
      <street>123 Maine Ave.</street>
      <city>Las Vegas</city>
      <state>NV</state>
      <zip>01234</zip>
      <country>USA</country>
    </address>
    <address>
      <type>business</type>
      <street>234 Maple Dr.</street>
      <city>Los Angeles</city>
      <state>CA</state>
      <zip>98765</zip>
      <country>USA</country>
    </address>
  </person>

  <person id="2" category="rolemodel">
    <name>Kermit</name>
    <email type="business">kermit@muppets.com</email>
    <email type="home">kermie@acme.com</email>
    <address>
      <type>business</type>
      <street>987 Brown Rd</street>
      <city>Las Cruces</city>
      <state>NM</state>
      <zip>75321</zip>
      <country>USA</country>
    </address>
  </person>

</address-book>

AddressbookParser.java
package suna.digester.addressbook;

import java.io.File;
import java.io.IOException;

import org.apache.commons.digester3.Digester;
import org.xml.sax.SAXException;

public class AddressbookParser {

	private static final String XML_FILE = "xml/AddressBook.xml";
	
	
	public static void main(String[] args) {
		AddressbookParser parser = new AddressbookParser();
		try {
			AddressBook addressBook = parser.parse();
			dbg(addressBook.toString());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
 
	public AddressBook parse() throws IOException, SAXException {
		File file = new File(XML_FILE);
		
		Digester digester = new Digester();
		digester.setValidating(false);

		digester.addObjectCreate("address-book", "suna.digester.addressbook.AddressBook");
		digester.addObjectCreate("address-book/person", "suna.digester.addressbook.Person");
		digester.addSetProperties("address-book/person");
		digester.addSetNext("address-book/person", "addPerson");
		digester.addBeanPropertySetter("address-book/person/name", "name");
		digester.addObjectCreate("address-book/person/email", "suna.digester.addressbook.Mail");
		digester.addSetProperties("address-book/person/email");
		digester.addBeanPropertySetter("address-book/person/email", "name");
		digester.addSetNext("address-book/person/email", "setMail");
		digester.addObjectCreate("address-book/person/address", "suna.digester.addressbook.Address");
		digester.addSetNext("address-book/person/address", "addAddress");
		digester.addBeanPropertySetter("address-book/person/address/type", "type");
		digester.addBeanPropertySetter("address-book/person/address/street", "street");
		digester.addBeanPropertySetter("address-book/person/address/city", "city");
		digester.addBeanPropertySetter("address-book/person/address/state", "state");
		digester.addBeanPropertySetter("address-book/person/address/zip", "zip");
		digester.addBeanPropertySetter("address-book/person/address/country", "country");

		return digester.parse(file);
	}
 
	private static void dbg(String string) {
		System.out.println(string);
	}
}

実行結果
[
	##Person## id:1,category:acquaintance,name:Gonzo,
	mail:[##Mail## type:business,name:gonzo@muppets.com],
	[##Address## type:home,zip:01234,country:USA,state:NV,city:Las Vegas,street:123 Maine Ave.]
	[##Address## type:business,zip:98765,country:USA,state:CA,city:Los Angeles,street:234 Maple Dr.]
] 
[
	##Person## id:2,category:rolemodel,name:Kermit,
	mail:[##Mail## type:home,name:kermie@acme.com],
	[##Address## type:business,zip:75321,country:USA,state:NM,city:Las Cruces,street:987 Brown Rd]
] 

AddressBook.java
package suna.digester.addressbook;

import java.util.ArrayList;
import java.util.List;

public class AddressBook {
	private List<Person> personList = new ArrayList<Person>();

	public List<Person> getPersonList() {
		return personList;
	}

	public void addPerson(Person person) {
		personList.add(person);
	}

	@Override
	public String toString() {
		StringBuffer buf = new StringBuffer();
		for(int i = 0; i < personList.size(); i++) {
			buf.append(personList.get(i).toString());
			buf.append(" ");
		}
		return buf.toString();
	}
	
}

Person.java
package suna.digester.addressbook;

import java.util.ArrayList;
import java.util.List;

public class Person {
	private String id;
	
	private String name;
	
	private String category;
	
	private Mail mail;
	
	private List<Address> addressList = new ArrayList<Address>();

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getCategory() {
		return category;
	}
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public void setCategory(String category) {
		this.category = category;
	}

	public Mail getMail() {
		return mail;
	}

	public void setMail(Mail mail) {
		this.mail = mail;
	}

	public List<Address> getAddressList() {
		return addressList;
	}

	public void addAddress(Address address) {
		this.addressList.add(address);
	}

	@Override
	public String toString() {
		StringBuffer buf = new StringBuffer();
		String mailString = "";
		if(mail != null) {
			mailString = mail.toString();
		}
		buf.append("[##Person## ").append("id:").append(id).append(",category:")
				.append(category).append(",name:").append(name).append(",mail:")
				.append(mailString).append(",");
		for(int i = 0; i < addressList.size();i++) {
			buf.append(addressList.get(i).toString());
		}
		buf.append("]");
		return buf.toString();
	}
}

Mail.java
package suna.digester.addressbook;

public class Mail {
	
	private String type;

	private String name;
	
	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		StringBuffer buf = new StringBuffer();
		buf.append("[##Mail## ").append("type:").append(type).append(",name:").append(name).append("]");
		return buf.toString();
	}
}

Address.java
package suna.digester.addressbook;

public class Address {
	private String type;
	
	private String street;
	
	private String city;
	
	private String state;

	private String zip;
	
	private String country;

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public String getStreet() {
		return street;
	}

	public void setStreet(String street) {
		this.street = street;
	}

	public String getCity() {
		return city;
	}

public void setCity(String city) {
	this.city = city;
}

	public String getState() {
		return state;
	}

	public void setState(String state) {
		this.state = state;
	}

	public String getZip() {
		return zip;
	}

	public void setZip(String zip) {
		this.zip = zip;
	}

	public String getCountry() {
		return country;
	}

	public void setCountry(String country) {
		this.country = country;
	}

	@Override
	public String toString() {
		StringBuffer buf = new StringBuffer();
		buf.append("[##Address## ").append("type:").append(type)
				.append(",zip:").append(zip).append(",country:").append(country).append(",state:")
				.append(state).append(",city:").append(city).append(",street:").append(street).append("]");	
		return buf.toString();
	}
}


ネームスペースを意識したパース

人気記事ランキング
ウィキ募集バナー