--- /dev/null
+/*\r
+ * xml resource resolver\r
+ *\r
+ * Copyright(c) 2009 olyutorskii\r
+ * $Id: XmlResourceResolver.java 888 2009-11-04 06:23:35Z olyutorskii $\r
+ */\r
+\r
+package jp.sourceforge.jindolf;\r
+\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.Reader;\r
+import java.net.URI;\r
+import java.net.URISyntaxException;\r
+import java.net.URL;\r
+import java.util.Map;\r
+import jp.sourceforge.jindolf.corelib.XmlResource;\r
+import org.w3c.dom.ls.LSInput;\r
+import org.w3c.dom.ls.LSResourceResolver;\r
+import org.xml.sax.EntityResolver;\r
+import org.xml.sax.InputSource;\r
+import org.xml.sax.SAXException;\r
+\r
+/**\r
+ * URL変換マップに従い、XML文書からの外部参照をリダイレクトする。\r
+ * 相対URIはこのクラスをベースに解決される。\r
+ * 主な用途は外部スキーマのリソース化など。\r
+ */\r
+public class XmlResourceResolver\r
+ implements LSResourceResolver,\r
+ EntityResolver{\r
+\r
+ private static final URI EMPTY_URI = URI.create("");\r
+\r
+ /**\r
+ * 絶対URIと相対URIを合成したURIを返す。\r
+ * 正規化も行われる。\r
+ * @param base 絶対URIでなければならない。nullでもよい。\r
+ * @param relative 絶対URIでもよいがその場合baseは無視される。null可。\r
+ * @return 合成結果のURLオブジェクト。必ず絶対URIになる。\r
+ * @throws java.net.URISyntaxException URIとして変。\r
+ * @throws java.lang.IllegalArgumentException 絶対URIが生成できない。\r
+ */\r
+ protected static URI buildBaseRelativeURI(String base, String relative)\r
+ throws URISyntaxException,\r
+ IllegalArgumentException {\r
+ URI baseURI = null;\r
+ if(base != null){\r
+ baseURI = new URI(base);\r
+ if( ! baseURI.isAbsolute() ) throw new IllegalArgumentException();\r
+ }\r
+\r
+ URI relativeURI = EMPTY_URI;\r
+ if(relative != null){\r
+ relativeURI = new URI(relative);\r
+ }\r
+\r
+ URI resultURI;\r
+ if(baseURI == null || relativeURI.isAbsolute()){\r
+ resultURI = relativeURI;\r
+ }else{\r
+ resultURI = baseURI.resolve(relativeURI);\r
+ }\r
+\r
+ if( ! resultURI.isAbsolute() ) throw new IllegalArgumentException();\r
+\r
+ resultURI = resultURI.normalize();\r
+\r
+ return resultURI;\r
+ }\r
+\r
+ /**\r
+ * LSInput実装を生成する。\r
+ * @return LSInput実装\r
+ */\r
+ public static LSInput createLSInput(){\r
+ LSInput input = new LSInputImpl();\r
+ return input;\r
+ }\r
+\r
+ private final Map<URI, URI> uriMap = XmlResource.RESOLVE_MAP;\r
+\r
+ /**\r
+ * コンストラクタ。\r
+ */\r
+ public XmlResourceResolver(){\r
+ super();\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * 変換後のリソースの入力ストリームを得る。\r
+ * @param originalURI オリジナルURI\r
+ * @return 入力ストリーム\r
+ * @throws java.io.IOException 入出力エラー\r
+ */\r
+ public InputStream getXMLResourceAsStream(URI originalURI)\r
+ throws IOException{\r
+ URI resourceURI = this.uriMap.get(originalURI.normalize());\r
+ URL resourceURL = resourceURI.toURL();\r
+ InputStream is = resourceURL.openStream();\r
+\r
+ return is;\r
+ }\r
+\r
+ /**\r
+ * {@inheritDoc}\r
+ * URL変換したあとの入力ソースを返す。\r
+ * @param type {@inheritDoc}\r
+ * @param namespaceURI {@inheritDoc}\r
+ * @param publicId {@inheritDoc}\r
+ * @param systemId {@inheritDoc}\r
+ * @param baseURI {@inheritDoc}\r
+ * @return {@inheritDoc}\r
+ */\r
+ public LSInput resolveResource(String type,\r
+ String namespaceURI,\r
+ String publicId,\r
+ String systemId,\r
+ String baseURI ){\r
+ if(systemId == null) return null;\r
+\r
+ URI originalURI;\r
+ try{\r
+ originalURI = buildBaseRelativeURI(baseURI, systemId);\r
+ }catch(URISyntaxException e){\r
+ return null;\r
+ }\r
+\r
+ InputStream is;\r
+ try{\r
+ is = getXMLResourceAsStream(originalURI);\r
+ }catch(IOException e){\r
+ return null;\r
+ }\r
+\r
+ LSInput input = createLSInput();\r
+ input.setBaseURI(baseURI);\r
+ input.setPublicId(publicId);\r
+ input.setSystemId(systemId);\r
+ input.setByteStream(is);\r
+\r
+ return input;\r
+ }\r
+\r
+ /**\r
+ * {@inheritDoc}\r
+ * URL変換したあとの入力ソースを返す。\r
+ * @param publicId {@inheritDoc}\r
+ * @param systemId {@inheritDoc}\r
+ * @return {@inheritDoc}\r
+ * @throws org.xml.sax.SAXException {@inheritDoc}\r
+ * @throws java.io.IOException {@inheritDoc}\r
+ */\r
+ public InputSource resolveEntity(String publicId, String systemId)\r
+ throws SAXException, IOException{\r
+ if(systemId == null) return null;\r
+\r
+ URI originalUri;\r
+ try{\r
+ originalUri = new URI(systemId);\r
+ }catch(URISyntaxException e){\r
+ return null;\r
+ }\r
+\r
+ InputStream is = getXMLResourceAsStream(originalUri);\r
+\r
+ InputSource source = new InputSource(is);\r
+ source.setPublicId(publicId);\r
+ source.setSystemId(systemId);\r
+\r
+ return source;\r
+ }\r
+\r
+ /**\r
+ * JRE1.5用LSInput実装。\r
+ * JRE1.6なら\r
+ * org.w3c.dom.ls.DOMImplementationLS#createLSInput()\r
+ * で生成可能かも。\r
+ */\r
+ public static class LSInputImpl implements LSInput{\r
+\r
+ private String baseURI = null;\r
+ private InputStream byteStream = null;\r
+ private boolean certifiedText = false;\r
+ private Reader characterStream = null;\r
+ private String encoding = null;\r
+ private String publicId = null;\r
+ private String stringData = null;\r
+ private String systemId = null;\r
+\r
+ /**\r
+ * コンストラクタ。\r
+ */\r
+ public LSInputImpl(){\r
+ super();\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * {@inheritDoc}\r
+ * @return {@inheritDoc}\r
+ */\r
+ public String getBaseURI(){\r
+ return this.baseURI;\r
+ }\r
+\r
+ /**\r
+ * {@inheritDoc}\r
+ * @param baseURI {@inheritDoc}\r
+ */\r
+ public void setBaseURI(String baseURI){\r
+ this.baseURI = baseURI;\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * {@inheritDoc}\r
+ * @return {@inheritDoc}\r
+ */\r
+ public InputStream getByteStream(){\r
+ return this.byteStream;\r
+ }\r
+\r
+ /**\r
+ * {@inheritDoc}\r
+ * @param byteStream {@inheritDoc}\r
+ */\r
+ public void setByteStream(InputStream byteStream){\r
+ this.byteStream = byteStream;\r
+ }\r
+\r
+ /**\r
+ * {@inheritDoc}\r
+ * @return {@inheritDoc}\r
+ */\r
+ public boolean getCertifiedText(){\r
+ return this.certifiedText;\r
+ }\r
+\r
+ /**\r
+ * {@inheritDoc}\r
+ * @param certifiedText {@inheritDoc}\r
+ */\r
+ public void setCertifiedText(boolean certifiedText){\r
+ this.certifiedText = certifiedText;\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * {@inheritDoc}\r
+ * @return {@inheritDoc}\r
+ */\r
+ public Reader getCharacterStream(){\r
+ return this.characterStream;\r
+ }\r
+\r
+ /**\r
+ * {@inheritDoc}\r
+ * @param characterStream {@inheritDoc}\r
+ */\r
+ public void setCharacterStream(Reader characterStream){\r
+ this.characterStream = characterStream;\r
+ }\r
+\r
+ /**\r
+ * {@inheritDoc}\r
+ * @return {@inheritDoc}\r
+ */\r
+ public String getEncoding(){\r
+ return this.encoding;\r
+ }\r
+\r
+ /**\r
+ * {@inheritDoc}\r
+ * @param encoding {@inheritDoc}\r
+ */\r
+ public void setEncoding(String encoding){\r
+ this.encoding = encoding;\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * {@inheritDoc}\r
+ * @return {@inheritDoc}\r
+ */\r
+ public String getPublicId(){\r
+ return this.publicId;\r
+ }\r
+\r
+ /**\r
+ * {@inheritDoc}\r
+ * @param publicId {@inheritDoc}\r
+ */\r
+ public void setPublicId(String publicId){\r
+ this.publicId = publicId;\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * {@inheritDoc}\r
+ * @return {@inheritDoc}\r
+ */\r
+ public String getStringData(){\r
+ return this.stringData;\r
+ }\r
+\r
+ /**\r
+ * {@inheritDoc}\r
+ * @param stringData {@inheritDoc}\r
+ */\r
+ public void setStringData(String stringData){\r
+ this.stringData = stringData;\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * {@inheritDoc}\r
+ * @return {@inheritDoc}\r
+ */\r
+ public String getSystemId(){\r
+ return this.systemId;\r
+ }\r
+\r
+ /**\r
+ * {@inheritDoc}\r
+ * @param systemId {@inheritDoc}\r
+ */\r
+ public void setSystemId(String systemId){\r
+ this.systemId = systemId;\r
+ return;\r
+ }\r
+\r
+ }\r
+\r
+ // TODO OASIS XML Catalog などと調和したい。\r
+}\r