XML読込みを整理

XML読込みを整理してみる。ResourceBundle使用の恩恵があるはず。


/**
 * XML 解析インターフェース.
 *
 * AbstractXmlHandler の createParser メソッドで、XMLファイル baseName と
 * AbstractXmlHandler 継承したインスタンスを生成して作成される。
 *
 * XmlParser xmlparser = AbstractXmlHandler.createParser(baseName,handler);
 */


public interface XmlParser<T>{
   /**
    * AbstractXmlHandler継承インスタンスが AbstractXmlHandler抽象メソッドである
    * public abstract T result() throws Exception;
    * が返す任意のオブジェクトを返す。
    *
    * @return T AbstractXmlHandler継承インスタンスが返す任意オブジェクト
    */

   public T parse() throws Exception;
}
--------------------------------------
import org.xml.sax.helpers.DefaultHandler;
/**
 * XML解析ハンドラ抽象クラス.
 * 実装クラスで、org.xml.sax.helpers.DefaultHandler のメソッドをオーバライドして
 * XML解析の結果を result() で、返すように実装すること。
 */

public abstract class AbstractXmlHandler<T> extends DefaultHandler{
   public abstract T result() throws Exception;

   /**
    * XmlParser インスタンス生成.
    * 3つの引数を持つ同じメソッド、createParser の3番目に、
    * ResourceBundle.Control.TTL_DONT_CACHE を与えて実行するのと同じ効果があります。
    * @param <T> result()が返す任意オブジェクトタイプ
    * @param baseName XMLファイル ".xml" を除いた名称
    * @param handler AbstractXmlHandler継承インスタンス
    * @return XmlParserインスタンス
    */

   public final static <T> XmlParser createParser(String baseName,AbstractXmlHandler<T> handler){
      return new XmlParserImpl<T>(baseName,handler);
   }


   /**
    * XmlParser インスタンス生成(XML読込キャッシュ制御).
    * ResourceBundle.Control の下でロードされたリソースバンドルの有効期間 (TTL) 値を指定する
    * ことを可能にしたインスタンス生成です。
    * 第3引数に、
    * ResourceBundle.Control.TTL_DONT_CACHE    :キャッシュをしない
    * ResourceBundle.TTL_NO_EXPIRATION_CONTROL :有効期限なしのキャッシュをする。
    * あるいは、値 0 は、ResourceBundle.Control#getTimeToLive の戻り値=0と同じ意味を持ち、
    * キャッシュ有効期限をミリ秒で与えます。
    * @param <T> result()が返す任意オブジェクトタイプ
    * @param baseName XMLファイル ".xml" を除いた名称
    * @param handler AbstractXmlHandler継承インスタンス
    * @param cacheTime ResourceBundle.Control の下でロードされたリソースバンドルの有効期間 (TTL) 値、ミリ秒
    * @return XmlParserインスタンス
    */

   public final static <T> XmlParser createParser(String baseName,AbstractXmlHandler<T> handler,long cacheTime){
      return new XmlParserImpl<T>(baseName,handler,cacheTime);
   }

}
--------------------------------------
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import java.util.ResourceBundle;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
/**
 * XmlParser 実装クラス.
 * 解析対象 XMLファイル baseName と、AbstractXmlHandler インスタンスコンストラクタで受け取る。
 */

final class XmlParserImpl<T> implements XmlParser{
   private String baseName;
   AbstractXmlHandler<T> handler;
   long cacheTime;

   protected XmlParserImpl(String baseName,AbstractXmlHandler<T> handler){
      this.baseName = baseName;
      this.handler = handler;
      this.cacheTime = ResourceBundle.Control.TTL_DONT_CACHE;
   }
   protected XmlParserImpl(String baseName,AbstractXmlHandler<T> handler,long cacheTime){
      this.baseName = baseName;
      this.handler = handler;
      this.cacheTime = cacheTime;
   }

   @Override
   public T parse() throws Exception{
      ResourceBundle.getBundle(this.baseName
         ,new ResourceBundle.Control(){
            @Override
            public List<String> getFormats(String _baseName){
               if (_baseName==null) throw new NullPointerException();
               return Arrays.asList("xml");
            }
            @Override
            public ResourceBundle newBundle(String _baseName,Locale locale,String format,ClassLoader loader,@SuppressWarnings("unused") boolean reload)
            throws IllegalAccessException,InstantiationException,IOException{
               if (_baseName == null || locale == null || format == null || loader == null)
                  throw new NullPointerException();
               if (format.equals("xml")){
                  String bundleName = toBundleName(_baseName, locale);
                  String resourceName = toResourceName(bundleName,format);
                  InputStream stream = loader.getResourceAsStream(resourceName);
                  if (stream != null){
                     _XMLparse xmlParse = new _XMLparse(stream);
                     try{
                     xmlParse.parse();
                     }catch(Exception e){
                        throw new IOException(e);
                     }
                     stream.close();
                  }
               }
               return new _DummyBundle();
            }
            @Override
            public long getTimeToLive(String _baseName,Locale _locale){
               if (_baseName==null || _locale==null){
                  throw new NullPointerException();
               }
               return XmlParserImpl.this.cacheTime;
            }

         }
      );
      return this.handler.result();
   }
   class _XMLparse {
      private InputStream steam;
      _XMLparse(InputStream stream){
         this.steam = stream;
      }
      void parse() throws Exception{
         SAXParserFactory factory = SAXParserFactory.newInstance();
         SAXParser saxParser = factory.newSAXParser();
         saxParser.parse(this.steam,XmlParserImpl.this.handler);
      }
   }
   class _DummyBundle extends ResourceBundle {
      private Properties props;
      _DummyBundle(){
         this.props = new Properties();
      }
      @Override
      protected Object handleGetObject(String key) {
         return this.props.getProperty(key);
      }
      @Override
      public Enumeration<String> getKeys() {
         return null;
      }
   }
}