2013-11-09 3 views
0

JavaFX로 작성된 GUI 인 OSGi 번들을 만들려고합니다. 다음과 같이 내 설정은 다음과 같습니다 JavaFX 용 MigLayout을 OSGi 번들로 변환하여 OSGi 컨테이너에서 작동하는 방법은 무엇입니까?

OS name: "linux", version: "3.8.0-25-generic", arch: "amd64", family: "unix" 
Java version: 1.7.0_45, vendor: Oracle Corporation 
Apache Maven 3.1.1 (0728685237757ffbf44136acec0402957f723d9a; 2013-09-17 10:22:22-0500) 

내가 자바 FX 메이븐 플러그인 to put the JavaFX runtime on the classpath에서 제공하는 지침을 따랐다. 아파치 펠릭스를 OSGi 컨테이너로 사용하고 있습니다. 이 모든 것이 함께하면 멋지게 작동합니다. (IE : JavaFX GUI를 OSGi 번들로 만들 수 있습니다.)

문제점은 JavaFX 용 MigLayout 라이브러리에있는 문제입니다. 나는이 종속성을 사용하고 있습니다 :

<dependency> 
    <groupId>com.miglayout</groupId> 
    <artifactId>miglayout-core</artifactId> 
    <version>4.2</version> 
</dependency> 
<dependency> 
    <groupId>com.miglayout</groupId> 
    <artifactId>miglayout-javafx</artifactId> 
    <version>4.2</version> 
</dependency> 

이들 중 어느 쪽이은 OSGi 번들, 그리고 그들에게 의존 구체적으로, 응용 프로그램에서 발생하는 런타임 오류를 일으키는 : 여기

javafx.fxml.LoadException: java.lang.ClassNotFoundException: org.tbee.javafx.scene.layout.fxml.MigPane from bundle 7 (client) 
    at javafx.fxml.FXMLLoader.importClass(FXMLLoader.java:2489) 
    at javafx.fxml.FXMLLoader.processImport(FXMLLoader.java:2333) 
    at javafx.fxml.FXMLLoader.processProcessingInstruction(FXMLLoader.java:2301) 
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2154) 
    at client.Gui.start(Gui.scala:22) 
    at com.sun.javafx.application.LauncherImpl$5.run(LauncherImpl.java:319) 
    at com.sun.javafx.application.PlatformImpl$5.run(PlatformImpl.java:216) 
    at com.sun.javafx.application.PlatformImpl$4$1.run(PlatformImpl.java:179) 
    at com.sun.javafx.application.PlatformImpl$4$1.run(PlatformImpl.java:176) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at com.sun.javafx.application.PlatformImpl$4.run(PlatformImpl.java:176) 
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:76) 
    at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method) 
    at com.sun.glass.ui.gtk.GtkApplication$3$1.run(GtkApplication.java:89) 
    at java.lang.Thread.run(Thread.java:744) 
Caused by: java.lang.ClassNotFoundException: org.tbee.javafx.scene.layout.fxml.MigPane from bundle 7 (client) 
    at akka.osgi.impl.BundleDelegatingClassLoader.loadClass(BundleDelegatingClassLoader.scala:49) 
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358) 
    at javafx.fxml.FXMLLoader.loadTypeForPackage(FXMLLoader.java:2557) 
    at javafx.fxml.FXMLLoader.loadType(FXMLLoader.java:2546) 
    at javafx.fxml.FXMLLoader.importClass(FXMLLoader.java:2487) 
    ... 14 more 
Caused by: java.lang.ClassNotFoundException: org.tbee.javafx.scene.layout.fxml.MigPane not found by com.typesafe.akka.osgi [1] 
    at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1532) 
    at org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:75) 
    at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1955) 
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358) 
    at akka.osgi.impl.BundleDelegatingClassLoader.loadClass(BundleDelegatingClassLoader.scala:46) 
    ... 18 more 

는 샘플입니다 내가로드하기 위해 노력하고있어 fxml 파일, login.fxml :

<?xml version="1.0" encoding="UTF-8"?> 
<?import javafx.scene.layout.StackPane?> 
<?import javafx.scene.control.Button?> 
<?import org.tbee.javafx.scene.layout.fxml.MigPane?> 
<StackPane xmlns:fx="http://javafx.com/fxml" fx:controller="client.view.LoginView" fx:id="pane"> 
    <children> 
    <Button text="Login" fx:id="loginButton" onAction="#login"/> 
    </children> 
</StackPane> 

이 내가 OSGi 컨테이너의 외부에서이 응용 프로그램을 실행하면, 페이지가로드 미세 유의하시기 바랍니다. 그러나 OSGi 컨테이너 내부에서는 앞서 언급 한 스택 추적으로 실패합니다. 또한 MigPane에 대한 가져 오기를 주석 처리하면 OSGi 컨테이너 내부에서도 잘로드됩니다. 그래서 아래의 예는 OSGi 컨테이너 내부에서 잘 작동 :

<?xml version="1.0" encoding="UTF-8"?> 
<?import javafx.scene.layout.StackPane?> 
<?import javafx.scene.control.Button?> 
<!--<?import org.tbee.javafx.scene.layout.fxml.MigPane?>--> 
<StackPane xmlns:fx="http://javafx.com/fxml" fx:controller="client.view.LoginView" fx:id="pane"> 
    <children> 
    <Button text="Login" fx:id="loginButton" onAction="#login"/> 
    </children> 
</StackPane> 

나는 그들이 매니페스트 파일에 필요한은 OSGi 메타 데이터를 포함 할 수 있도록 MigLayout jar 파일을 변경하는 wrapcommand on Peter Kriens' bnd tool를 사용하여이 문제를 해결하기 위해 노력했다.

명령 :

// The original jar (the one specified in the aforementioned maven 
// dependency - which is not an OSGi bundle) is contained in the 
// wrap subdirectory. 
$ java -jar bnd-2.1.0.jar wrap miglayout-core-4.2.jar wrap/miglayout-core-4.2.jar 
$ java -jar bnd-2.1.0.jar wrap miglayout-javafx-4.2.jar wrap/miglayout-javafx-4.2.jar 

miglayout 코어-4.2.jar의 MANIFEST.MF :

Manifest-Version: 1.0 
Archiver-Version: Plexus Archiver 
Bnd-LastModified: 1384015623755 
Build-Jdk: 1.6.0_29 
Built-By: Mike 
Bundle-ManifestVersion: 2 
Bundle-Name: miglayout.core 
Bundle-SymbolicName: miglayout.core 
Bundle-Version: 0 
Created-By: 1.7.0_45 (Oracle Corporation) 
Export-Package: net.miginfocom.layout 
Originally-Created-By: Apache Maven 
Tool: Bnd-2.1.0.20130426-122245 

miglayout - 자바 FX-4.2.jar MANIFEST.MF :

Manifest-Version: 1.0 
Archiver-Version: Plexus Archiver 
Bnd-LastModified: 1384015600603 
Build-Jdk: 1.6.0_29 
Built-By: Mike 
Bundle-ManifestVersion: 2 
Bundle-Name: miglayout.javafx 
Bundle-SymbolicName: miglayout.javafx 
Bundle-Version: 0 
Created-By: 1.7.0_45 (Oracle Corporation) 
Export-Package: org.tbee.javafx.scene.layout;uses:="javafx.scene,javafx. 
scene.layout,net.miginfocom.layout",org.tbee.javafx.scene.layout.fxml;u 
ses:="javafx.beans,javafx.scene,net.miginfocom.layout,org.tbee.javafx.s 
cene.layout" 
Import-Package: javafx.beans;resolution:=optional,javafx.collections;res 
olution:=optional,javafx.geometry;resolution:=optional,javafx.scene;res 
olution:=optional,javafx.scene.control;resolution:=optional,javafx.scen 
e.layout;resolution:=optional,javafx.scene.paint;resolution:=optional,j 
avafx.scene.shape;resolution:=optional,javafx.stage;resolution:=optiona 
l,net.miginfocom.layout;resolution:=optional 
Originally-Created-By: Apache Maven 
Tool: Bnd-2.1.0.20130426-122245 

그러나 결과 "번들"을 OSGi 컨테이너에 넣어도 문제가 해결되지 않습니다. 같은 오류가 발생합니다.

다른 어떤 시도를해야할지 모르겠으므로 OSGi 컨테이너에서 MigLayout 라이브러리를 사용할 수 있습니다.

OSGi 컨테이너에서 MigLayout을 사용할 수 있도록하려면 어떻게해야합니까?

편집 여기

는 FXML를로드하는 코드입니다. 스칼라로 작성되었습니다.

package client 

import _root_.javafx.application.Application 
import _root_.javafx.stage.Stage 
import _root_.javafx.scene.{Parent, Scene} 
import _root_.javafx.fxml.FXMLLoader 
import client.view.{Login, Screen} 

class Gui extends Application { 
    def start(stage: Stage) { 
    val initialScreen: Screen = Login 
    stage.setTitle("GUI") 
    val loader = new FXMLLoader 
    loader.setLocation(initialScreen.url) 
    try { 
     val root: Parent = loader.load(initialScreen.inputStream).asInstanceOf[Parent] 
     val scene: Scene = new Scene(root, 800, 600) 
     scene.getStylesheets.add("/fxml/styles/styles.css") 
     stage.setScene(scene) 
     stage.show() 
    } catch { 
     case t: Throwable => t.printStackTrace() 
    } 
    } 

    override def stop() { 
    System.out.println("Stopping JavaFX Application") 
    Container.shutdown() 
    } 
} 

또한 여기에 클라이언트 용으로 정의 된 가져 오기 - 패키지가 있습니다. 빌드는 scala와 osgi 플러그인을 사용하여 실제로 수행됩니다.

빌드 스 니펫Gradle을 :

def importPackages = 
    ' akka.actor' + 
    ', akka.actor.dungeon' + 
    ', akka.event' + 
    ', akka.osgi' + 
    ', javafx.application' + 
    ', javafx.beans' + 
    ', javafx.collections' + 
    ', javafx.fxml' + 
    ', javafx.geometry' + 
    ', javafx.scene' + 
    ', javafx.scene.control' + 
    ', javafx.scene.image' + 
    ', javafx.scene.layout' + 
    ', javafx.scene.paint' + 
    ', javafx.scene.shape' + 
    ', javafx.stage' + 
    ', net.miginfocom.layout' + 
    ', org.osgi.framework' + 
    ', org.tbee.javafx.scene.layout' + 
    ', org.tbee.javafx.scene.layout.fxml' + 
    ', scala' + 
    ', scala.collection' + 
    ', scala.reflect' + 
    ', scala.runtime' 

jar { 
    manifest { 
    name = "client (OSGi bundle)" 

    instruction 'Bundle-Vendor', 'Company' 
    instruction 'Bundle-Description', 'Client (OSGi bundle)' 

    instruction 'Private-Package', 'client' 
    instruction 'Bundle-Activator', 'client.ClientActivator' 

    instruction 'Import-Package', importPackages 
    } 
} 

편집 2

나는 클래스 로더를 설정하는 tomsontom의 제안에 따라 fxml를로드하는 코드를 수정했습니다. build.gradle에서

미리보기 : 여기에 업데이트 된 코드는

def importPackages = 
    ' akka.actor' + 
    ', akka.actor.dungeon' + 
    ', akka.event' + 
    ', akka.osgi' + 
    ', javafx.application' + 
    ', javafx.beans' + 
    ', javafx.collections' + 
    ', javafx.fxml' + 
    ', javafx.geometry' + 
    ', javafx.scene' + 
    ', javafx.scene.control' + 
    ', javafx.scene.image' + 
    ', javafx.scene.layout' + 
    ', javafx.scene.paint' + 
    ', javafx.scene.shape' + 
    ', javafx.stage' + 
    ', net.miginfocom.layout' + 
    ', org.osgi.framework' + 
    ', org.tbee.javafx.scene.layout' + 
    ', org.tbee.javafx.scene.layout.fxml' + 
    ', scala' + 
    ', scala.collection' + 
    ', scala.reflect' + 
    ', scala.runtime' 

fxml 로딩 코드 : 응용 프로그램을 실행할 때 지금은 비슷하지만 다른 오류 메시지가

def start(stage: Stage) { 
    val initialScreen: Screen = Login 
    stage.setTitle("GUI") 
    val loader = new FXMLLoader 
    loader.setClassLoader(getClass.getClassLoader) 
    loader.setLocation(initialScreen.url) 
    try { 
     val root: Parent = loader.load(initialScreen.inputStream).asInstanceOf[Parent] 
     val scene: Scene = new Scene(root, 800, 600) 
     scene.getStylesheets.add("/fxml/styles/styles.css") 
     stage.setScene(scene) 
     stage.show() 
    } catch { 
     case t: Throwable => t.printStackTrace() 
    } 
    } 

그러나 통지 OSGi 컨테이너의 경우 :

javafx.fxml.LoadException: java.lang.ClassNotFoundException: org.tbee.javafx.scene.layout.fxml.MigPane 
    at javafx.fxml.FXMLLoader.importClass(FXMLLoader.java:2489) 
    at javafx.fxml.FXMLLoader.processImport(FXMLLoader.java:2333) 
    at javafx.fxml.FXMLLoader.processProcessingInstruction(FXMLLoader.java:2301) 
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2154) 
    at client.Gui.start(Gui.scala:23) 
    at com.sun.javafx.application.LauncherImpl$5.run(LauncherImpl.java:319) 
    at com.sun.javafx.application.PlatformImpl$5.run(PlatformImpl.java:216) 
    at com.sun.javafx.application.PlatformImpl$4$1.run(PlatformImpl.java:179) 
    at com.sun.javafx.application.PlatformImpl$4$1.run(PlatformImpl.java:176) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at com.sun.javafx.application.PlatformImpl$4.run(PlatformImpl.java:176) 
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:76) 
    at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method) 
    at com.sun.glass.ui.gtk.GtkApplication$3$1.run(GtkApplication.java:89) 
    at java.lang.Thread.run(Thread.java:744) 
Caused by: java.lang.ClassNotFoundException: org.tbee.javafx.scene.layout.fxml.MigPane 
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366) 
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354) 
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425) 
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) 
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358) 
    at org.apache.felix.framework.ExtensionManager$ExtensionManagerWiring.getClassByDelegation(ExtensionManager.java:873) 
    at org.apache.felix.framework.BundleWiringImpl.searchImports(BundleWiringImpl.java:1553) 
    at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1484) 
    at org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:75) 
    at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1955) 
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358) 
    at javafx.fxml.FXMLLoader.loadTypeForPackage(FXMLLoader.java:2557) 
    at javafx.fxml.FXMLLoader.loadType(FXMLLoader.java:2546) 
    at javafx.fxml.FXMLLoader.importClass(FXMLLoader.java:2487) 
    ... 14 more 

여전히 ClassNotFoundExcep . 그러나 이번에는 스택 트레이스에는 트레이스가 오는 번들과 관련된 것이 포함되어 있지 않습니다. 그것의 미묘한 차이, 그리고 그것이 무엇을 의미 모르겠어요. 어떤 아이디어? 3

편집은 내가 BND 명령 행 유틸리티를 사용 후 MigLayout 종속성 모두에 대해 생성 된 MANIFEST.MF 파일을 포함하도록 OP를 수정했습니다.

EDIT 4

client.jar가의 MANIFEST.MF (내 패키지가 아니라 단지 클라이언트에 비해 정말 xxclient 참고.하지만 SO의 패키지 이름에서 XX를 제거했습니다. 그 이유이다 이 MANIFEST.MF 파일의 줄 간격 불일치)에 대한 :

Manifest-Version: 1.0 
Export-Package: client;version="1.0.0.SNAPSHOT";uses:= 
"akka.actor,akka.osgi,javafx.application,javafx.stage,org.osgi.framew 
ork,scala.reflect",client.controller;version="1.0.0.S 
NAPSHOT";uses:="akka.actor,akka.event,scala,scala.reflect,scala.runti 
me",client.message;version="1.0.0.SNAPSHOT";uses:="sc 
ala,scala.collection,scala.reflect",client.model;vers 
ion="1.0.0.SNAPSHOT";uses:="scala.reflect",client.vie 
w;version="1.0.0.SNAPSHOT";uses:="scala,scala.collection,scala.reflec 
t" 
Private-Package: client 
Tool: Bnd-2.1.0.20130426-122213 
Bundle-Name: client (OSGi bundle) 
Created-By: 1.7.0_45 (Oracle Corporation) 
Bundle-Vendor: Company 
Bundle-Version: 1.0.0.SNAPSHOT 
Bnd-LastModified: 1384035615000 
Bundle-ManifestVersion: 2 
Bundle-Activator: client.ClientActivator 
Bundle-Description: Client (OSGi bundle) 
Bundle-SymbolicName: client 
Import-Package: akka.actor;version="[2.2,3)",akka.event;version="[2.2, 
3)",akka.osgi;version="[2.2,3)",javafx.application,javafx.collections 
,javafx.fxml,javafx.scene,javafx.stage,org.osgi.framework;version="[1 
.7,2)",scala;version="[2.10,3)",scala.collection;version="[2.10,3)",s 
cala.reflect;version="[2.10,3)",scala.runtime;version="[2.10,3)",net. 
miginfocom.layout,org.tbee.javafx.scene.layout.fxml,org.tbee.javafx.s 
cene.layout,javafx.scene.layout,javafx.scene.image,javafx.scene.contr 
ol,javafx.scene.shape,javafx.scene.paint,javafx.geometry,javafx.beans 
,akka.actor.dungeon;version="[2.2,3)" 

EDIT 5

나는를 생성을 다운로드하면 문제를 확인할 수 있습니다. 현재 체크인 된대로이 프로젝트는 README.txt 파일의 지침을 따르는 경우 체크 아웃 한 후 바로 실행해야합니다.

MigLayout 라이브러리에서 발생하는 문제를보고 싶다면 client/src/main/resources/fxml/login.fxml 파일을 편집하고 MigPane에 대한 가져 오기의 주석을 제거하십시오. 프로젝트를 다시 빌드하고 새로 작성한 클라이언트 1.0.0-SNAPSHOT.jar을 app/bundle/ 디렉토리로 복사하고 $ rm -rf app/felix-cache/으로 felix-cache 디렉토리를 지운 다음 $ java -jar bin/felix.jar 명령으로 app 디렉토리에서 felix 실행 프로그램을 다시 시작하십시오.

답변

0

또한 UI 번들에 해당하는 Import-Package 문이 있어야합니다. 가장 쉬운 방법은 UI 번들의 테두리에 maven bundle plugin을 사용하는 것입니다.

당신은 번들 플러그인을 사용하여 결과 매니페스트를 검사하여 모든 nevessary Import-Package 문이 있는지 확인하십시오.

+0

예, OP에 포함 시켰어야합니다. 클라이언트 번들에 import 문이 있습니다. 왜 작동하지 않는지 혼란 스럽습니다. – axiopisty

+0

유일한 다른 아이디어는 midlayout 코어에 Import-Package 문이 없으며 해당 클래스 로더를 사용하는 miglayout 핵심 클래스에서 예외가 발생한다는 것입니다. –

+0

다른 오류 메시지가 표시되지 않겠습니까? 번들을 연결할 수 없다는 것에 대한 것이 있습니까? – axiopisty

1

저는 fxml에서 99 % 확실합니다. 문제는 올바른 클래스 로더를 설정하지 않았다는 것입니다. fxml 로딩 코드를 보여주십시오.

+1

좋아, 나는 당신이 fxmlloader 인스턴스에서 setClassloader를 호출해야합니다. FXMLLoader가 자연스럽게 OSGi 번들의 migpane에 대해 알지 못하는 extclassloader에 있기 때문에 코드를 OSGi에서 실패해야합니다. – tomsontom

+0

setClassloader에 전달할 클래스 로더는 무엇입니까? OSGi 번들은 어디에서 왔습니까? – axiopisty

+1

로딩 코드를 저장하는 코드는 migpane에 종속성을 가져야하며이 코드를 전달해야합니다. 자바 클래스의 fxml 파일에 내용을 구현하면 번들을 어떻게 구성 할 것인가를 생각해야합니다. 그래서 모든 javafx 패키지를 가져와야합니다! getClass() 클래스 로더를 얻는다. getClassloader() – tomsontom

관련 문제