ひよっこ。

I want to…

Posts Tagged ‘jar’

SpringBatchで実行可能なjarファイルを作ったらSAXParseExceptionではまるなど

Posted by hikaruworld : 2011 6月 25

SpringBatchを使ってバッチプログラムを書いて、実行可能なjarファイルを作り、
おもむろにjava -jarで起動したら表題のごとくSAXParseExceptionではまりました。

発生した例外のスタックトレースは以下の通り。

2011-06-25 16:21:08,829 ERROR [org.springframework.batch.core.launch.support.CommandLineJobRunner] - 
org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 5 in XML document from class path resource [launch-context.xml] is invalid; nested exception is org.xml.sax.SAXParseException: cvc-elt.1: Cannot find the declaration of element 'beans'.
        at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:396)
        ....
        ....
        (以下略)

色々ググってみたり、リファレンスを読んでいたのですが、
Springコミュニティでも話題になっている割には解決策が見つからずorz…
すると、あるブログで同様の件が発生していて、
その解決策を書いている人がいました。

根本的な原因は以下に記されていることに起因するようです。
参照されるjarファイルのMETA-INF内が参照されないというように読み取れました。

In fact, the root cause is that the META-INF directory of a can be blocked when referenced inside an EJB jar.

SAXParseExceptionが出ている直接の原因は、定義ファイルlaunch-context.xmlで指定されている
ルートタグbeanで定義されている名前空間、http://www.springframework.org/schema/beansが見つからないことです。

<beans xmlns="http://www.springframework.org/schema/beans"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
    ....

これは、xsi:schemaLocationが定義されていればSpringはクラスパス上のMETA-INF内部に定義されている
spring.handlersに書かれている名前空間から解決してくれるようですが、
上記の理由により依存ライブラリのMETA-INFが参照できず、XMLの解析に失敗してしまいます。

# ここはSpring2.0系ですが、InfoQのこの辺りの記事が参考になると思います。

具体的な回避策

先ほどのサイトに書いてあった通りです。
実行対象のjarファイル内のMETA-INF内に、XMLファイルが参照する名前空間を『全て』定義した状態の
マージしたspring.schemasとMETA-INF/spring.handlersのファイルを同梱する必要があります。
必要なxmlの名前空間定義は、各spring-xxx.jar内に含まれていますのでそれをマージします。

大体階層的にはこんな感じになります。

batch-sample.jar
├── META-INF
│   ├── INDEX.LIST
│   ├── MANIFEST.MF
│   ├── maven
│   │   └── org.springframework.samples.batch
│   │       └── spring-batch-simple
│   │           ├── pom.properties
│   │           └── pom.xml
│   ├── spring
│   │   └── module-context.xml
│   ├── spring.schemas
│   └── spring.handlers
├── batch.properties
├── empty.txt
├── launch-context.xml  

なお、自分の環境だとネットワークがつながっていなかったのですが、つながっている場合はもうちょっとわかりやすいエラーになるようです。
会わせてエラーログを張っておきます。

自分がでたエラーログ

2011-06-25 16:21:08,829 ERROR [org.springframework.batch.core.launch.support.CommandLineJobRunner] - <Job Terminated in error: Line 5 in XML document from class path resource [launch-context.xml] is invalid; nested exception is org.xml.sax.SAXParseException: cvc-elt.1: Cannot find the declaration of element 'beans'.>
org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 5 in XML document from class path resource [launch-context.xml] is invalid; nested exception is org.xml.sax.SAXParseException: cvc-elt.1: Cannot find the declaration of element 'beans'.
        at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:396)
        at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:334)
        at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:302)
        at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:143)
        at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:178)
        at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:149)
        at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:212)
        at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:126)
        at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:92)
        at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:130)
        at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:465)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:395)
        at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
        at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
        at org.springframework.batch.core.launch.support.CommandLineJobRunner.start(CommandLineJobRunner.java:272)
        at org.springframework.batch.core.launch.support.CommandLineJobRunner.main(CommandLineJobRunner.java:541)
Caused by: org.xml.sax.SAXParseException: cvc-elt.1: Cannot find the declaration of element 'beans'.
        at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:195)
        at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:131)
        at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:384)
        at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:318)
        at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.handleStartElement(XMLSchemaValidator.java:1916)
        at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.startElement(XMLSchemaValidator.java:705)
        at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:400)
        at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl$NSContentDriver.scanRootElementHook(XMLNSDocumentScannerImpl.java:626)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:3103)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:922)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:648)
        at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:140)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:511)
        at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:808)
        at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:737)
        at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:119)
        at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:235)
        at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:284)
        at org.springframework.beans.factory.xml.DefaultDocumentLoader.loadDocument(DefaultDocumentLoader.java:75)
        at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:388)
        ... 15 more

ネットワークにつながる環境の場合

2011-06-25 16:29:11,590 INFO [org.springframework.context.support.ClassPathXmlApplicationContext] - <Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@12b7eea: startup date [Sat Jun 25 16:29:11 JST 2011]; root of context hierarchy>
2011-06-25 16:29:11,689 INFO [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] - <Loading XML bean definitions from class path resource [launch-context.xml]>
2011-06-25 16:29:13,462 INFO [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] - <Loading XML bean definitions from class path resource [META-INF/spring/module-context.xml]>
2011-06-25 16:29:14,149 ERROR [org.springframework.batch.core.launch.support.CommandLineJobRunner] - <Job Terminated in error: Configuration problem: Failed to import bean definitions from URL location [classpath:/META-INF/spring/module-context.xml]
Offending resource: class path resource [launch-context.xml]; nested exception is org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace [http://www.springframework.org/schema/batch]
Offending resource: class path resource [META-INF/spring/module-context.xml]
>
org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Failed to import bean definitions from URL location [classpath:/META-INF/spring/module-context.xml]
Offending resource: class path resource [launch-context.xml]; nested exception is org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace [http://www.springframework.org/schema/batch]
Offending resource: class path resource [META-INF/spring/module-context.xml]

        at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:68)
        at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:85)
        at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:76)
        at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.importBeanDefinitionResource(DefaultBeanDefinitionDocumentReader.java:193)
        at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseDefaultElement(DefaultBeanDefinitionDocumentReader.java:148)
        at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:133)
        at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:93)
        at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:493)
        at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:390)
        at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:334)
        at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:302)
        at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:143)
        at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:178)
        at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:149)
        at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:212)
        at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:126)
        at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:92)
        at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:130)
        at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:465)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:395)
        at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
        at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
        at org.springframework.batch.core.launch.support.CommandLineJobRunner.start(CommandLineJobRunner.java:272)
        at org.springframework.batch.core.launch.support.CommandLineJobRunner.main(CommandLineJobRunner.java:541)
Caused by: org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace [http://www.springframework.org/schema/batch]
Offending resource: class path resource [META-INF/spring/module-context.xml]

        at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:68)
        at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:85)
        at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:80)
        at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.error(BeanDefinitionParserDelegate.java:284)
        at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1332)
        at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1325)
        at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:136)
        at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:93)
        at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:493)
        at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:390)
        at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:334)
        at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:302)
        at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:143)
        at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:178)
        at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.importBeanDefinitionResource(DefaultBeanDefinitionDocumentReader.java:187)
        ... 20 more

以上です。

Posted in program | タグ: , , , , | Leave a Comment »

Air2.0(ベータ版)でネイティブプロセスでjarファイルを実行する方法(泥臭い編)

Posted by hikaruworld : 2009 12月 13

Air2.0(現時点ではβ1版)での新機能の一つとして、ネイティブプロセスを実行することができるようになっています。

詳細はこのあたりが参考になります。

  1. AIR 2.0 ではじめるコミュニケーションツール Comm On AIR 2.0

この新機能を用いてjarファイルを実行したかったのですが、
ちょっと面倒な実装になってしまったのでメモしておきます。

ちなみに環境はMacOSX(雪豹)です。
winだとjarファイルを直接渡しても実行してくれるのかなぁ(javaw -jar hoge.jar)。

結論としては、jarファイル単体実行が結局うまくいかずshのラッパーを用意しました。

  • bin/exec.jar
  • bin/wrapper.sh

という感じでアプリケーションに実行ファイルを含めておきます。

exec.jarはマニュフェストファイルが存在する実行可能jarファイルで固めてあります。
wrapper.shの中身はこんな感じです。

#!/bin/sh

# 単純にjava -jarで第一引数に実行対象のjarファイルを渡す。
# jarファイルにパスが通っている前提
$(java -jar $1)

java -jarコマンドを実行時に$1でwrapper.shに渡された
引数(これが実行対象のjarファイルになります)をそのまま指定しています。

Air2.0側では、以下のような実装を書きました。

var info:NativeProcessStartupInfo = new NativeProcessStartupInfo();
// 実行対象のファイル(ラッパー)を指定
var file:File = File.applicationDirectory.resolvePath("bin/wrapper.sh");
info.executable = file;

// wrapper.shに渡す引数を指定
var args:Vector.<String> = new Vector.<String>();
// 相対指定だとAirのランタイムからの指定になってしまうので、
// 実際にjava -jarコマンドに渡したいファイルの絶対パスを解決する。
var jarFile:File = File.applicationDirectory.resolvePath("bin/exec.jar");
args.push(jarFile.nativePath);
info.arguments = args;

// 実行
this.process = new NativeProcess();
process.start(info);

ソースコード上のコメントにもありますが、
ネイティブプロセスによって実行されたファイルのカレントディレクトリ(pwd)が、
AirのRuntimeになってしまうようで、アプリ内に存在するファイルの
絶対パスを解決して渡しているとう微妙な実装をしています。

以上。

めちゃめちゃ泥臭い実装なんですが、
よりより方法があれば誰か教えてください。

Posted in program | タグ: , , , | 1 Comment »