glassfish.org は消滅したので DTD が読み込めなくなったのですケド


f:id:Naotsugu:20180220123849p:plain

TL;DR

Java EE の Oracle から Eclipse Foundation への移管に伴い以下のような DTD の URL は今や存在しないので XML 操作時には注意

http://glassfish.org/dtds/glassfish-resources_1_5.dtd

とあるプロジェクトで

久しぶりの改修。 Gradle スクリプトがエラーで止まる。

Glassfish の初期設定を Gradle スクリプトで実施していた。

こんな感じでリソースを読み込み、

def resource = new XmlParser(false, true)
  .parse(new File("${rootProject.projectDir}/・・/glassfish-resources.xml"))

リソースファイルでJDBCの設定などを環境に応じて加工して、Glassfish の CLI(add-resources) 経由で設定登録する箇所。

こんな例外出た

Caused by: java.net.ConnectException: Connection timed out: connect
        at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:647)
        at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startEntity(XMLEntityManager.java:1304)
        at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startDTDEntity(XMLEntityManager.java:1270)
        at com.sun.org.apache.xerces.internal.impl.XMLDTDScannerImpl.setInputSource(XMLDTDScannerImpl.java:264)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$DTDDriver.dispatch(XMLDocumentScannerImpl.java:1161)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$DTDDriver.next(XMLDocumentScannerImpl.java:1045)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:959)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:602)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:505)
        at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:841)
        at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:770)
        at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
        at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213)
        at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:643)
        at build_2i32as3kviieftkrs11cr0k82d$_run_closure5_closure10_closure11.doCall(C:\Users\User\necap\Tricolor\tool\build.gradle:48)
        at build_2i32as3kviieftkrs11cr0k82d$_run_closure5_closure10_closure11.doCall(C:\Users\User\necap\Tricolor\tool\build.gradle)
        at org.gradle.api.internal.CompositeDynamicObject.invokeMethod(CompositeDynamicObject.java:156)
        at org.gradle.api.tasks.JavaExec_Decorated.invokeMethod(Unknown Source)
        at build_2i32as3kviieftkrs11cr0k82d$_run_closure5.doCall(C:\Users\User\necap\Tricolor\tool\build.gradle:80)
        at org.gradle.api.internal.ClosureBackedAction.execute(ClosureBackedAction.java:58)
        at org.gradle.util.ConfigureUtil.configure(ConfigureUtil.java:130)
        at org.gradle.util.ConfigureUtil.configure(ConfigureUtil.java:110)
        at org.gradle.api.internal.AbstractTask.configure(AbstractTask.java:439)
        at org.gradle.api.internal.project.AbstractProject.task(AbstractProject.java:958)
        at org.gradle.api.internal.BeanDynamicObject$MetaClassAdapter.invokeMethod(BeanDynamicObject.java:246)
        at org.gradle.api.internal.BeanDynamicObject.invokeMethod(BeanDynamicObject.java:134)
        at org.gradle.api.internal.CompositeDynamicObject.invokeMethod(CompositeDynamicObject.java:147)
        at org.gradle.groovy.scripts.BasicScript.methodMissing(BasicScript.java:79)
        at build_2i32as3kviieftkrs11cr0k82d.run(C:\Users\User\necap\Tricolor\tool\build.gradle:36)
        at org.gradle.groovy.scripts.internal.DefaultScriptRunnerFactory$ScriptRunnerImpl.run(DefaultScriptRunnerFactory.java:52)

何が起きているのか

XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:647)

該当箇所はココの最後のトコ

    public String setupCurrentEntity(boolean reference, String name, XMLInputSource xmlInputSource,
            boolean literal, boolean isExternal)
            throws IOException, XNIException {
        // get information

        final String publicId = xmlInputSource.getPublicId();
        String literalSystemId = xmlInputSource.getSystemId();
        String baseSystemId = xmlInputSource.getBaseSystemId();
        String encoding = xmlInputSource.getEncoding();
        final boolean encodingExternallySpecified = (encoding != null);
        Boolean isBigEndian = null;

        // create reader
        InputStream stream = null;
        Reader reader = xmlInputSource.getCharacterStream();

        // First chance checking strict URI
        String expandedSystemId = expandSystemId(literalSystemId, baseSystemId, fStrictURI);
        if (baseSystemId == null) {
            baseSystemId = expandedSystemId;
        }
        if (reader == null) {
            stream = xmlInputSource.getByteStream();
            if (stream == null) {
                URL location = new URL(expandedSystemId);
                URLConnection connect = location.openConnection();
                if (!(connect instanceof HttpURLConnection)) {
                    stream = connect.getInputStream();
                }
                else {
                    boolean followRedirects = true;

                    // setup URLConnection if we have an HTTPInputSource
                    if (xmlInputSource instanceof HTTPInputSource) {
                        final HttpURLConnection urlConnection = (HttpURLConnection) connect;
                        final HTTPInputSource httpInputSource = (HTTPInputSource) xmlInputSource;

                        // set request properties
                        Iterator<Map.Entry<String, String>> propIter = httpInputSource.getHTTPRequestProperties();
                        while (propIter.hasNext()) {
                            Map.Entry<String, String> entry = propIter.next();
                            urlConnection.setRequestProperty(entry.getKey(), entry.getValue());
                        }

                        // set preference for redirection
                        followRedirects = httpInputSource.getFollowHTTPRedirects();
                        if (!followRedirects) {
                            setInstanceFollowRedirects(urlConnection, followRedirects);
                        }
                    }

                    stream = connect.getInputStream();

glassfish-resources.xml の DTD 定義は以下のようになってる。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC 
  "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN" 
  "http://glassfish.org/dtds/glassfish-resources_1_5.dtd">
<resources>

    <jdbc-connection-pool ・・・>
    ・・・
    </jdbc-connection-pool>

ご存じのように、Java EE は Oracle から Eclipse Foundation へ移管 され、glassfish.org も今や存在しない。

glassfish.org 消滅にともない Connection timed out

XmlParser(false, true) の第一引数をfalseでXMLドキュメントの検証をしない設定にしてるけど、DTDは取得しにいくみたいね。

移行先が見つからないので、Payara のリポジトリに入っているものを指定するか、

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC 
  "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN" 
  "https://raw.githubusercontent.com/payara/Payara/master/appserver/connectors/descriptors/src/main/resources/glassfish/lib/dtds/glassfish-resources_1_5.dtd">
<resources>

    <jdbc-connection-pool ・・・>
    ・・・
    </jdbc-connection-pool>

消したり、

<?xml version="1.0" encoding="UTF-8"?>
<resources>

    <jdbc-connection-pool ・・・>
    ・・・
    </jdbc-connection-pool>

ローカルに用意したり

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC 
  "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN" 
  "file:/path-to-resources/glassfish-resources_1_5.dtd">
<resources>

    <jdbc-connection-pool ・・・>
    ・・・
    </jdbc-connection-pool>

って感じかな。

まとめ

glassfish-resources_1_5.dtd の正式な移行先URLは不明

移行するなら旧URL残してリダイレクトにしてほしいんですケド



Java Ee 8 Application Development

Java Ee 8 Application Development