2013-11-09 4 views
0

Я пытаюсь создать пакет OSGi, который является графическим интерфейсом, написанным на JavaFX. Моя установка выглядит следующим образом:Как конвертировать MigLayout для JavaFX в пакет 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) 

Я следовал инструкциям по JavaFX Maven Plugin to put the JavaFX runtime on the classpath. Я использую apache felix в качестве контейнера OSGi. Все это вместе работает довольно хорошо. (IE: Я могу создать графический интерфейс JavaFX в качестве пакета OSGi, и он работает!)

Проблема, которая у меня есть с библиотекой MigLayout для JavaFX. Я использую эти зависимости:

<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> 

Я попытался решить эту проблему с помощью wrapcommand on Peter Kriens' bnd tool изменять банку файлы MigLayout таким образом они будут включать в себя необходимые OSGi метаданных в файле манифеста.

Команды:

// 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-JavaFX-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 не устраняет проблему. Я получаю ту же ошибку.

Я не знаю, что еще попробовать, поэтому я могу использовать библиотеку MigLayout внутри контейнера OSGi.

Что мне нужно для этого, я могу использовать MigLayout внутри контейнера OSGi?

EDIT

Вот код, который загружает FXML. Это написано в Scala.

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 
    } 
} 

EDIT 2

Я изменил код, который загружает FXML в соответствии с предложением tomsontom, чтобы установить загрузчик класса. Вот обновленный код:

фрагмент из 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

Я изменил OP, чтобы включать в себя сгенерированный файл MANIFEST.MF для обоих зависимостей MigLayout после использования Bnd утилиты командной строки.

EDIT 4

client.jar MANIFEST.MF (Обратите внимание, мой пакет действительно xxclient, а не просто клиентом. Но я раздели хх от имени пакета для SO. То есть причина для межстрочного интервала расхождения в этом 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

Я создал project on GitHub, который вы можете скачать, чтобы увидеть проблему. Как и в данный момент, этот проект должен запускаться сразу после проверки, если вы следуете инструкциям в файле README.txt.

Если вы хотите увидеть проблему, с которой я столкнулся с библиотекой MigLayout, отредактируйте файл client/src/main/resources/fxml/login.fxml, раскомментировав импорт для MigPane. Переконструируйте проект, скопируйте вновь созданный клиент-1.0.0-SNAPSHOT.jar в каталог app/bundle/, очистите каталог felix-cache с помощью $ rm -rf app/felix-cache/, а затем перезапустите пусковую установку felix из каталога app с помощью команды $ java -jar bin/felix.jar.

ответ

0

Вам также необходимо иметь соответствующие инструкции Import-Package в вашем пакете пользовательского интерфейса. Самый простой способ создать их - использовать maven bundle plugin в папке вашего пакета пользовательского интерфейса.

Wether вы используете плагин bundle, чтобы проверить полученный Manifest, чтобы убедиться, что все несущественные заявления Import-Package присутствуют.

+0

Да, я должен был включить это в OP. У меня есть операторы импорта в наборе клиентов. Я смущен, почему он не работает. – axiopisty

+0

Единственная другая идея заключается в том, что, возможно, в ядре midlayout нет оператора Import-Package, и исключение возникает в основном классе miglayout, который, конечно же, использует свой собственный загрузчик классов. –

+0

Разве это не приведет к появлению другого сообщения об ошибке, что-то о том, что невозможно связать связки вместе? – axiopisty

1

Я на 99% уверен в fxml, ваша проблема в том, что вы не установили правильный загрузчик классов. Пожалуйста, введите код загрузки fxml

+1

Хорошо, я видел, как вы обновились, и вам нужно вызвать setClassloader на экземпляр fxmlloader. Если вы думаете об этом, ваш код должен завершиться неудачей в OSGi, потому что FXMLLoader находится в extclassloader, который, естественно, не знает о migpane в вашем пакете OSGi. – tomsontom

+0

Какой загрузчик классов я могу передать setClassloader? Откуда она взялась из пакета OSGi? – axiopisty

+1

Тот, у кого есть код загрузки, должен иметь зависимость от migpane, а затем передать его. Вам нужно подумать, как бы настроить свой пакет, если вы реализуете материал в файле fxml в классе java, поэтому вы также должны импортировать весь пакет javafx! GetClassloader() – tomsontom