diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..20398ae --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +.git +.gradle diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..ea9005a --- /dev/null +++ b/.drone.yml @@ -0,0 +1,29 @@ +--- +kind: pipeline +name: default +type: docker + +#platform: +# os: linux +# arch: amd64 + + +steps: + +# - name: test +# image: docker.io/bellsoft/liberica-openjdk-debian:17 +# commands: +# - ./gradlew --quiet --no-daemon test + + - name: jpackage + image: docker.io/debian:stable + environment: + AUTH_TOKEN: # Gitea access token ENV variable + from_secret: AUTH_TOKEN # Name of DroneCI secret exposed above + commands: + - apt-get update && apt-get install -y dpkg-dev rpm unzip zip curl openjdk-17-jdk + - ./gradlew --no-daemon clean build jpackage + - for file in build/jpackage/*.* ; do curl -s --user "$${AUTH_TOKEN}" --upload-file "$${file}" "https://git.data.coop/api/packages/${DRONE_REPO_OWNER}/generic/${DRONE_REPO_NAME}/${DRONE_TAG}/$(basename $file)" ; done + when: + event: + - tag diff --git a/README.md b/README.md index 9b3ccc9..56572c0 100644 --- a/README.md +++ b/README.md @@ -1,96 +1,37 @@ # mDNS Explorer -View all multicastDNS devices. +View multicastDNS services on your local network. + +![mDNS-Explorer](doc/mDNS-Explorer.png) + ## Development Java SDK version 17 (or later) is required. -## Native Images - -The native images are built with GraalVM. -Download the Gluon version of GraalVM from https://github.com/gluonhq/graal/releases/tag/gluon-22.1.0.1-Final and extract it locally. - -Point the GRAALVM_HOME environment variable to the folder: - -```export GRAALVM_HOME="/path/to/gluon-22.1.0.1``` - -With all requirements setup and on a supported platform, the general idea is to run: +Information on how to build and package jftpd: ```shell -./gradlew clean build -./gradlew nativeBuild -Ptarget=android # or -Ptarget=ios -./gradlew nativeLink -Ptarget=android -./gradlew nativePackage -Ptarget=android -./gradlew nativeInstall -Ptarget=android -./gradlew nativeRun -Ptarget=android +./gradlew build jpackage ``` -or, in one go for Android: +### Windows -```shell -./gradlew -Ptarget=android clean build nativeBuild nativeLink nativePackage nativeInstall nativeRun -``` +Download and install +- Microsoft .NET Framework 3.5 +- Wix Toolset 3.11.2 (or later) -or, in one go for iOS: -```shell -./gradlew -Ptarget=ios clean build nativeBuild nativeLink nativePackage nativeInstall nativeRun -``` ### Linux -See https://docs.gluonhq.com/#prerequisites_linux +TODO -For nativeBuild on Linux, install the following dependencies. +docker build . -f docker/Dockerfile.rpm-txt -```shell -sudo apt install libgtk-3-dev libavformat-dev libavutil-dev libavcodec-dev libasound2-dev libpango1.0-dev libxtst-dev build-essential -``` +or -#### Building for Android (on Linux) - -See https://docs.gluonhq.com/#prerequisites_android - -Install Android Studio and use sdkmanager to install the following: - -- Android SDK Platform 31 -- NDK (Side by side) - -Point the ANDROID_NDK variable to the installed NDK directory: - -``` -export ANDROID_NDK="/home/mark/Android/Sdk/ndk/25.2.9519653/" -``` - -Add the platform-tools to you PATH to use 'adb' command: - - -``` -export PATH="$PATH:/home/mark/Android/Sdk/platform-tools/" -``` - -Run the 'adb devices' and 'adb usb' to verify your Android networkService is in development mode and allows connections. +docker build . -f docker/Dockerfile.deb-txt ### MacOS -See https://docs.gluonhq.com/#platforms_macos - -Install the xcode command line tools and an iPhone emulator. - -If you have problems with *xcrun* not being able to find *iphoneos*, try: - -```shell -sudo xcode-select --switch /Applications/Xcode.app -``` - -Download and install homebrew, and install the following: - -```shell -brew install maven -brew install --HEAD libusbmuxd -brew install --HEAD libimobiledevice -``` - -#### iOS (on MacOS) - -See https://docs.gluonhq.com/#prerequisites_ios +TODO diff --git a/build.gradle b/build.gradle index 088bbbb..0e1e62b 100644 --- a/build.gradle +++ b/build.gradle @@ -1,49 +1,47 @@ -import org.apache.tools.ant.filters.ReplaceTokens - plugins { + id 'java' + id 'groovy' id 'application' id 'org.openjfx.javafxplugin' version '0.0.14' - id "com.github.johnrengelman.shadow" version "8.1.1" - id 'com.gluonhq.gluonfx-gradle-plugin' version '1.0.19' + id 'com.google.osdetector' version '1.7.3' + id 'org.beryx.jlink' version '2.26.0' } - repositories { mavenCentral() mavenLocal() - maven { - url 'https://nexus.gluonhq.com/nexus/content/repositories/releases' - } } -version = "0.0.1" -mainClassName = "biz.nellemann.mdexpl.App" -application.mainModule = "biz.nellemann.mdexpl" - tasks.withType(JavaCompile).configureEach { options.encoding = 'UTF-8' } +application { + mainModule = 'biz.nellemann.mdexpl' + mainClass = 'biz.nellemann.mdexpl.App' +} + java { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 - modularity.inferModulePath = false + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } } /* This is to be able to build with a JDK not bundled with JavaFX */ javafx { - version = '21+' + version = '17.0.8' modules = [ 'javafx.controls', 'javafx.fxml' ] // platform("linux-aarch64") } dependencies { - implementation 'com.gluonhq:charm-glisten:6.2.3' - implementation 'com.gluonhq:glisten-afterburner:2.1.0' - implementation 'org.slf4j:slf4j-api:2.0.7' // Logging API runtimeOnly 'org.slf4j:slf4j-simple:2.0.7' // Logging API + implementation 'jakarta.inject:jakarta.inject-api:2.0.1' + implementation 'jakarta.annotation:jakarta.annotation-api:2.1.1' implementation 'org.jmdns:jmdns:3.5.8' testImplementation 'org.spockframework:spock-core:2.3-groovy-3.0' @@ -54,66 +52,67 @@ test { useJUnitPlatform() } +jlink { -gluonfx { - verbose = true - target = project.hasProperty("target") ? project.getProperty("target") : 'host' - //target = 'ios' // Uncomment to enable iOS - see https://docs.gluonhq.com/#prerequisites_ios - //target = 'android' // Uncomment to enable Android - see https://docs.gluonhq.com/#prerequisites_android + forceMerge 'slf4j' - attachConfig { - version = "4.0.18" - services 'storage', 'display', 'lifecycle', 'statusbar' - } - - reflectionList = [ - "javafx.fxml.FXMLLoader", - "com.gluonhq.charm.glisten.mvc.View", - "com.gluonhq.charm.glisten.control.Icon", - "com.gluonhq.charm.glisten.control.DropdownButton", - "com.gluonhq.charm.glisten.control.BottomNavigation", - "com.gluonhq.charm.glisten.control.BottomNavigationButton", - "biz.nellemann.mdexpl.view.AboutPresenter", - "biz.nellemann.mdexpl.view.MainPresenter", "biz.nellemann.mdexpl.model.MainModel", - "biz.nellemann.mdexpl.service.DiscoveryService", + options = [ + '--strip-debug', + '--compress', '2', + '--no-header-files', + '--no-man-pages' ] - compilerArgs = [ - '-Djava.awt.headless=true' - ] + launcher { + name = 'mDNS-Explorer' + noConsole = true + } - appIdentifier = 'biz.nellemann.mdexpl' + // Only works with Java 14 (and later) + jpackage { + imageName = "mDNS-Explorer" + skipInstaller = true + installerName = "mDNS-Explorer-${osdetector.arch}" + installerOptions += [ + '--vendor', 'Nellemann Data', + '--description', 'List mDNS services on your local network.', + '--copyright', 'Mark Nellemann ', + '--app-version', project.findProperty('version') + ] + + // Requires: https://wixtoolset.org/ to create installer on Windows + if(osdetector.os == 'windows') { + installerType = 'msi' + skipInstaller = false + installerOptions += [ + '--win-per-user-install', + '--win-dir-chooser', + '--win-menu', + // '--icon', 'src/main/resources/icon.ico' + ] + } + + // Requires: xcode-select --install + if(osdetector.os == 'osx') { + installerType = 'dmg' + skipInstaller = false + installerOptions += [ + //'--icon', 'src/main/resources/icon.icns' + ] + } + + // Requires: build-rpm / rpm and dpkg-dev + if(osdetector.os == 'linux') { + skipInstaller = false + installerOptions += [ + '--linux-shortcut', + '--linux-menu-group', 'Internet', + '--linux-rpm-license-type', 'APACHE-20', + '--linux-deb-maintainer', 'mark.nellemann@gmail.com', + '--icon', 'src/main/resources/icon.png', + ] + } - release { - // Android - appLabel = "mDNS Explorer" - //versionCode = "1" - //versionName = "1.0" - //providedKeyStorePath = "" - //providedKeyStorePassword = "" - //providedKeyAlias = "" - //providedKeyAliasPassword = "" - // iOS - //bundleName = "mDNS Explorer" - //bundleVersion = "" - //bundleShortVersion = "" - //providedSigningIdentity = "" - //providedProvisioningProfile = "" - //skipSigning = true // Will not run or deploy if not signed } } - -shadowJar { - //archiveBaseName.set("vtd-poc-app") - //archiveClassifier.set('all') - archiveVersion.set("${System.env.BITBUCKET_BRANCH ?: 'dev' }") -} - -tasks.build.dependsOn tasks.shadowJar - -tasks.processResources { - filesMatching('**/configuration.properties') { - filter(ReplaceTokens, tokens: [copyright: '2023', version: System.env.BITBUCKET_BUILD_NUMBER ?: 'development' ]) - } -} diff --git a/doc/mDNS-Explorer.png b/doc/mDNS-Explorer.png new file mode 100644 index 0000000..a7ad97e Binary files /dev/null and b/doc/mDNS-Explorer.png differ diff --git a/docker/Dockerfile.deb-txt b/docker/Dockerfile.deb-txt new file mode 100644 index 0000000..02a4d86 --- /dev/null +++ b/docker/Dockerfile.deb-txt @@ -0,0 +1,12 @@ +FROM docker.io/debian:stable AS build + +RUN apt-get update && apt-get install -y unzip zip curl dpkg-dev +RUN bash -c "curl -s 'https://get.sdkman.io' | bash" +RUN bash -c "source $HOME/.sdkman/bin/sdkman-init.sh && sdk install java 17.0.8-zulu" + +COPY ./src /tmp/prj/src +COPY ./gradle /tmp/prj/gradle +COPY [ "gradlew", "build.gradle", "gradle.properties", "settings.gradle", "/tmp/prj/" ] + +WORKDIR /tmp/prj +RUN bash -c "source $HOME/.sdkman/bin/sdkman-init.sh && ./gradlew --no-daemon clean build jpackage" diff --git a/docker/Dockerfile.rpm-txt b/docker/Dockerfile.rpm-txt new file mode 100644 index 0000000..eb9213c --- /dev/null +++ b/docker/Dockerfile.rpm-txt @@ -0,0 +1,14 @@ +FROM docker.io/almalinux:8 AS build + +RUN dnf -y install unzip zip rpm-build +RUN sh -c "curl -s 'https://get.sdkman.io' | bash" +RUN sh -c "source $HOME/.sdkman/bin/sdkman-init.sh && sdk install java 17.0.8-zulu" + +COPY ./src /tmp/prj/src +COPY ./gradle /tmp/prj/gradle +COPY [ "gradlew", "build.gradle", "gradle.properties", "settings.gradle", "/tmp/prj/" ] + +WORKDIR /tmp/prj +RUN sh -c "source $HOME/.sdkman/bin/sdkman-init.sh && ./gradlew --no-daemon clean build jpackage" + +COPY --from=build build/jpackage/* build/ diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..c518c53 --- /dev/null +++ b/gradle.properties @@ -0,0 +1 @@ +version = 1.0.1 diff --git a/settings.gradle b/settings.gradle index 4aeb3ad..616f1de 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,9 +1,6 @@ pluginManagement { repositories { mavenLocal() - maven { - url "https://nexus.gluonhq.com/nexus/content/repositories/releases" - } gradlePluginPortal() } } diff --git a/src/main/java/biz/nellemann/mdexpl/App.java b/src/main/java/biz/nellemann/mdexpl/App.java index 5742834..03b466a 100644 --- a/src/main/java/biz/nellemann/mdexpl/App.java +++ b/src/main/java/biz/nellemann/mdexpl/App.java @@ -1,36 +1,50 @@ package biz.nellemann.mdexpl; -import biz.nellemann.mdexpl.view.AppViewManager; -import com.gluonhq.charm.glisten.application.AppManager; -import com.gluonhq.charm.glisten.visual.Swatch; import javafx.application.Application; +import javafx.application.Platform; +import javafx.fxml.FXMLLoader; import javafx.scene.Scene; import javafx.scene.image.Image; import javafx.stage.Stage; -import java.util.Objects; +import java.awt.Taskbar; +import java.awt.Toolkit; +import java.awt.Taskbar.Feature; +import java.io.IOException; public class App extends Application { - private final AppManager appManager = AppManager.initialize(this::postInit); - @Override - public void init() { - AppViewManager.registerViewsAndDrawer(); - } + public void start(Stage primaryStage) throws IOException { - @Override - public void start(Stage primaryStage) { - //System.setProperty(com.gluonhq.attach.util.Constants.ATTACH_DEBUG,"true"); - appManager.start(primaryStage); - } + // Make all stages close and the app exit when the primary stage is closed + Platform.setImplicitExit(true); + primaryStage.setOnCloseRequest(e -> { + System.exit(0); + }); + // Set icon on the application bar + var appIcon = new Image("/icon.png"); + primaryStage.getIcons().add(appIcon); - private void postInit(Scene scene) { - Swatch.GREEN.assignTo(scene); - //scene.getStylesheets().add(App.class.getResource("style.css").toExternalForm()); - ((Stage) scene.getWindow()).getIcons().add(new Image(Objects.requireNonNull(App.class.getResourceAsStream("/icon.png")))); + // Set icon on the taskbar/dock + if (Taskbar.isTaskbarSupported()) { + var taskbar = Taskbar.getTaskbar(); + + if (taskbar.isSupported(Feature.ICON_IMAGE)) { + final Toolkit defaultToolkit = Toolkit.getDefaultToolkit(); + var dockIcon = defaultToolkit.getImage(getClass().getResource("/icon.png")); + taskbar.setIconImage(dockIcon); + } + + } + + FXMLLoader fxmlLoader = new FXMLLoader(App.class.getResource("main.fxml")); + Scene scene = new Scene(fxmlLoader.load()); + primaryStage.setTitle("mDNS Explorer"); + primaryStage.setScene(scene); + primaryStage.show(); } diff --git a/src/main/java/biz/nellemann/mdexpl/MainPresenter.java b/src/main/java/biz/nellemann/mdexpl/MainPresenter.java new file mode 100644 index 0000000..386969b --- /dev/null +++ b/src/main/java/biz/nellemann/mdexpl/MainPresenter.java @@ -0,0 +1,51 @@ +package biz.nellemann.mdexpl; + +import biz.nellemann.mdexpl.model.NetworkService; +import biz.nellemann.mdexpl.service.DiscoveryService; +import jakarta.inject.Inject; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.fxml.FXML; +import javafx.scene.control.ListView; +import javafx.scene.control.TableView; +import javafx.scene.layout.BorderPane; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.ResourceBundle; + +public class MainPresenter { + + private static final Logger log = LoggerFactory.getLogger(MainPresenter.class); + + + + @FXML + private BorderPane view; + + @FXML + private ResourceBundle resources; + + @FXML + private ListView listView; + + @FXML + public ListView propertiesList; + + @Inject + DiscoveryService discoveryService; + + private final ObservableList devicesList = FXCollections.observableArrayList(); + + + @FXML + public void initialize() { + log.info("initialize()"); + listView.setItems(devicesList); + listView.setCellFactory(p -> new NetworkServiceCell()); + discoveryService = new DiscoveryService(devicesList); + } + + +} diff --git a/src/main/java/biz/nellemann/mdexpl/NetworkServiceCell.java b/src/main/java/biz/nellemann/mdexpl/NetworkServiceCell.java index c01398f..ba15c3f 100644 --- a/src/main/java/biz/nellemann/mdexpl/NetworkServiceCell.java +++ b/src/main/java/biz/nellemann/mdexpl/NetworkServiceCell.java @@ -1,40 +1,47 @@ package biz.nellemann.mdexpl; import biz.nellemann.mdexpl.model.NetworkService; -import com.gluonhq.attach.util.impl.ClipboardUtils; -import com.gluonhq.charm.glisten.control.CharmListCell; -import com.gluonhq.charm.glisten.control.ListTile; +import javafx.collections.FXCollections; +import javafx.scene.Node; +import javafx.scene.Scene; +import javafx.scene.control.ListCell; +import javafx.scene.control.ListView; import javafx.scene.input.ClipboardContent; +import javafx.scene.layout.HBox; import javafx.scene.shape.Rectangle; import javafx.scene.input.Clipboard; -import java.util.Optional; +public class NetworkServiceCell extends ListCell { -public class NetworkServiceCell extends CharmListCell { - - private final ListTile tile; private final Rectangle icon; private final Clipboard clipboard; private final ClipboardContent clipboardContent; + HBox hBox; public NetworkServiceCell() { clipboard = Clipboard.getSystemClipboard(); clipboardContent = new ClipboardContent(); - this.tile = new ListTile(); - //imageView = new ImageView(); - //imageView.setFitHeight(15); - //imageView.setFitWidth(25); - //tile.setPrimaryGraphic(imageView); icon = new Rectangle(); icon.setHeight(25); icon.setWidth(25); - tile.setPrimaryGraphic(icon); - tile.setOnMouseClicked(e -> { - clipboardContent.putString(itemProperty().get().getUrl()); - clipboard.setContent(clipboardContent); + this.setGraphic(icon); + + this.setOnMouseClicked(e -> { + if(itemProperty().get() != null) { + clipboardContent.putString(itemProperty().get().getUrl()); + clipboard.setContent(clipboardContent); + + Node source = (Node) e.getSource(); + Scene scene = source.getScene(); + Object node = scene.lookup("#propertiesList"); + + if(node instanceof ListView listView) { + listView.setItems(FXCollections.observableArrayList(itemProperty().get().getProperties())); + } + }; }); setText(null); } @@ -43,16 +50,14 @@ public class NetworkServiceCell extends CharmListCell { @Override public void updateItem(NetworkService item, boolean empty) { super.updateItem(item, empty); - if (item != null && !empty) { - tile.textProperty().setAll(item.getName(), - item.getApp() + " (" + item.getSubType() + ") - " + item.getUrl() - ); - icon.setFill(item.getColor()); - setGraphic(tile); - } else { + if (empty) { + setText(null); setGraphic(null); + } else { + setText(item.toString()); + icon.setFill(item.getColor()); + setGraphic(icon); } } - } diff --git a/src/main/java/biz/nellemann/mdexpl/NetworkServiceListener.java b/src/main/java/biz/nellemann/mdexpl/NetworkServiceListener.java index f817e5e..0a0e624 100644 --- a/src/main/java/biz/nellemann/mdexpl/NetworkServiceListener.java +++ b/src/main/java/biz/nellemann/mdexpl/NetworkServiceListener.java @@ -10,6 +10,7 @@ import org.slf4j.LoggerFactory; import javax.jmdns.ServiceEvent; import javax.jmdns.ServiceInfo; import javax.jmdns.ServiceListener; +import java.util.Iterator; public class NetworkServiceListener implements ServiceListener { @@ -21,7 +22,7 @@ public class NetworkServiceListener implements ServiceListener { private final Color color; public NetworkServiceListener(String service, ObservableList observableList, Color color) { - log.info("NetworkServiceListener() - type: {}", service); + log.debug("NetworkServiceListener() - type: {}", service); this.service = service; this.observableList = observableList; this.color = color; @@ -38,13 +39,13 @@ public class NetworkServiceListener implements ServiceListener { ServiceInfo serviceInfo = event.getInfo(); if (serviceInfo != null) { String name = serviceInfo.getName(); + String url = serviceInfo.getURLs()[0]; log.info("serviceRemoved() - Service: " + name); - NetworkService networkService = new NetworkService(name, service, serviceInfo.getSubtype(), serviceInfo.getApplication(), serviceInfo.getURLs()[0], color); - while (observableList.contains(networkService)) { - Platform.runLater(() -> { - observableList.remove(networkService); - }); - } + Platform.runLater( () -> { + observableList.stream().filter(e -> ( + e.getName().equals(name) && e.getUrl().equals(url) + )).forEach(observableList::remove); + }); } } @@ -56,7 +57,15 @@ public class NetworkServiceListener implements ServiceListener { String name = serviceInfo.getName(); String app = serviceInfo.getApplication(); log.info("serviceResolved() - Service: {} - {} with url {}", app, name, url); + NetworkService networkService = new NetworkService(name, service, serviceInfo.getSubtype(), app, url, color); + for (Iterator it = serviceInfo.getPropertyNames().asIterator(); it.hasNext(); ) { + String key = it.next(); + String value = serviceInfo.getPropertyString(key); + //log.info(" -> " + key + " = " + value); + networkService.addProperty(key, value); + } + Platform.runLater(() -> { if(!observableList.contains(networkService)) { observableList.add(networkService); diff --git a/src/main/java/biz/nellemann/mdexpl/model/MainModel.java b/src/main/java/biz/nellemann/mdexpl/model/MainModel.java deleted file mode 100644 index 4c96aaa..0000000 --- a/src/main/java/biz/nellemann/mdexpl/model/MainModel.java +++ /dev/null @@ -1,20 +0,0 @@ -package biz.nellemann.mdexpl.model; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.annotation.PostConstruct; -import javax.inject.Singleton; - -@Singleton -public class MainModel { - - private static final Logger log = LoggerFactory.getLogger(MainModel.class); - - - @PostConstruct - public void initialize() { - log.info("initialize()"); - } - -} diff --git a/src/main/java/biz/nellemann/mdexpl/model/NetworkService.java b/src/main/java/biz/nellemann/mdexpl/model/NetworkService.java index b148c0a..676b672 100644 --- a/src/main/java/biz/nellemann/mdexpl/model/NetworkService.java +++ b/src/main/java/biz/nellemann/mdexpl/model/NetworkService.java @@ -1,8 +1,11 @@ package biz.nellemann.mdexpl.model; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.collections.ObservableMap; import javafx.scene.paint.Color; -import java.util.Objects; +import java.util.*; public class NetworkService { @@ -12,6 +15,8 @@ public class NetworkService { private String app; private String url; private Color color; + private final ArrayList propertiesList = new ArrayList<>(); + public NetworkService(String name, String type, String subType, String app, String url, Color color) { this.name = name; @@ -71,10 +76,18 @@ public class NetworkService { this.color = color; } + public void addProperty(String key, String value) { + propertiesList.add(key + ": " + value); + } + + public ArrayList getProperties() { + return propertiesList; + } + @Override public String toString() { - return name + " (" + type + "), app=" + app + ", url=" + url; + return name + " (" + app + ") " + url; } diff --git a/src/main/java/biz/nellemann/mdexpl/service/DiscoveryService.java b/src/main/java/biz/nellemann/mdexpl/service/DiscoveryService.java index d72761d..d173b99 100644 --- a/src/main/java/biz/nellemann/mdexpl/service/DiscoveryService.java +++ b/src/main/java/biz/nellemann/mdexpl/service/DiscoveryService.java @@ -2,14 +2,12 @@ package biz.nellemann.mdexpl.service; import biz.nellemann.mdexpl.NetworkServiceListener; import biz.nellemann.mdexpl.model.NetworkService; +import jakarta.inject.Singleton; import javafx.collections.ObservableList; import javafx.scene.paint.Color; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; -import javax.inject.Singleton; import javax.jmdns.JmDNS; import java.io.IOException; import java.net.InetAddress; @@ -22,16 +20,10 @@ public class DiscoveryService { private final static Logger log = LoggerFactory.getLogger(DiscoveryService.class); - private ObservableList observableList; + private final ObservableList observableList; private JmDNS jmdns; - /*private final HashMap services = HashMap<>({ - "http", "https", "upnp", "ssh", "sip", "rdp", "ntp", "rdp", "rtsp", - "ntp", "smb", "nfs", "llrp", "ftp", "ep", "daap", "ipp", "ipps", - "googlecast", "sonos", "airplay", "smartenergy", "skype", "bittorrent" - );*/ - // From: http://www.dns-sd.org/serviceTypes.html + // https://jonathanmumm.com/tech-it/mdns-bonjour-bible-common-service-strings-for-various-vendors/ + some guesses private final Map services = new HashMap<>() {{ @@ -64,44 +56,29 @@ public class DiscoveryService { put("homekit", Color.LIGHTGREEN); put("homebridge", Color.LIGHTGREEN); + put("device-info", Color.DARKGREEN); + //put("rdlink", Color.DARKGREEN); + put("sip", Color.YELLOW); put("skype", Color.YELLOW); //put("rdlink", Color.KHAKI); }}; + public DiscoveryService(ObservableList list) { + log.info("DiscoveryService()"); + this.observableList = list; - @PostConstruct - public void initialize() { - log.info("initialize()"); try { jmdns = JmDNS.create(InetAddress.getByName("0.0.0.0"), "mdnsExplorer"); + services.forEach((item, color) -> { + String service = String.format("_%s._%s.local.", item, "tcp"); + NetworkServiceListener networkServiceListener = new NetworkServiceListener(service, observableList, color); + jmdns.addServiceListener(service, networkServiceListener); + }); } catch (IOException e) { log.error("initialize() - {}", e.getMessage()); } } - - @PreDestroy - public void destroy() { - if(jmdns != null) { - try { - jmdns.close(); - } catch (IOException e) { - log.error("destroy() - {}", e.getMessage()); - } - } - } - - - public void setObservableList(ObservableList list) { - this.observableList = list; - services.forEach((item, color) -> { - String service = String.format("_%s._%s.local.", item, "tcp"); - NetworkServiceListener networkServiceListener = new NetworkServiceListener(service, observableList, color); - jmdns.addServiceListener(service, networkServiceListener); - }); - } - - } diff --git a/src/main/java/biz/nellemann/mdexpl/view/AboutPresenter.java b/src/main/java/biz/nellemann/mdexpl/view/AboutPresenter.java deleted file mode 100644 index 2062ca9..0000000 --- a/src/main/java/biz/nellemann/mdexpl/view/AboutPresenter.java +++ /dev/null @@ -1,64 +0,0 @@ -package biz.nellemann.mdexpl.view; - -import com.gluonhq.charm.glisten.application.AppManager; -import com.gluonhq.charm.glisten.control.AppBar; -import com.gluonhq.charm.glisten.mvc.View; -import com.gluonhq.charm.glisten.visual.MaterialDesignIcon; -import javafx.fxml.FXML; -import javafx.scene.control.Label; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.inject.Inject; -import java.util.ResourceBundle; - -public class AboutPresenter { - - private static final Logger log = LoggerFactory.getLogger(AboutPresenter.class); - - - @FXML - private ResourceBundle resources; - - @FXML - View about; - - @FXML - Label labelInfoWebsite; - - @FXML - Label labelVersion; - - @Inject String appVersion; - @Inject String aboutWebsite; - - - @FXML - public void initialize() { - log.info("initialize()"); - - about.showingProperty().addListener((obs, oldValue, newValue) -> { - if (newValue) { - AppManager appManager = AppManager.getInstance(); - AppBar appBar = appManager.getAppBar(); - - appBar.setNavIcon(MaterialDesignIcon.MENU.button(e -> - appManager.getDrawer().open())); - - appBar.setTitleText("About"); - - appBar.getActionItems().add(MaterialDesignIcon.CLOSE.button(e -> { - appManager.goHome(); - })); - - } - }); - - labelVersion.setText(appVersion); - labelInfoWebsite.setText(aboutWebsite); - - } - - - -} diff --git a/src/main/java/biz/nellemann/mdexpl/view/AppViewManager.java b/src/main/java/biz/nellemann/mdexpl/view/AppViewManager.java deleted file mode 100644 index f656d26..0000000 --- a/src/main/java/biz/nellemann/mdexpl/view/AppViewManager.java +++ /dev/null @@ -1,52 +0,0 @@ -package biz.nellemann.mdexpl.view; - -import biz.nellemann.mdexpl.App; -import com.gluonhq.charm.glisten.afterburner.AppView; -import com.gluonhq.charm.glisten.afterburner.AppViewRegistry; -import com.gluonhq.charm.glisten.afterburner.Utils; -import com.gluonhq.charm.glisten.application.AppManager; -import com.gluonhq.charm.glisten.control.Avatar; -import com.gluonhq.charm.glisten.control.NavigationDrawer; -import com.gluonhq.charm.glisten.visual.MaterialDesignIcon; -import javafx.scene.image.Image; - -import java.util.Locale; -import java.util.Objects; - -import static com.gluonhq.charm.glisten.afterburner.AppView.Flag.*; - -public class AppViewManager { - - public static final AppViewRegistry REGISTRY = new AppViewRegistry(); - - // Shown in drawer - public static final AppView PRIMARY_VIEW = view("Explorer", MainPresenter.class, MaterialDesignIcon.HOME, SHOW_IN_DRAWER, HOME_VIEW, SKIP_VIEW_STACK); - public static final AppView ABOUT_VIEW = view("About", AboutPresenter.class, MaterialDesignIcon.HELP, SHOW_IN_DRAWER); - - - - private static AppView view(String title, Class presenterClass, MaterialDesignIcon menuIcon, AppView.Flag... flags ) { - return REGISTRY.createView(name(presenterClass), title, presenterClass, menuIcon, flags); - } - - private static String name(Class presenterClass) { - return presenterClass.getSimpleName().toUpperCase(Locale.ROOT).replace("PRESENTER", ""); - } - - public static void registerViewsAndDrawer() { - for (AppView view : REGISTRY.getViews()) { - view.registerView(); - } - - NavigationDrawer.Header header = new NavigationDrawer.Header("mDNS Explorer", - "Multicast DNS Explorer", - new Avatar(48, new Image(Objects.requireNonNull(App.class.getResourceAsStream("/icon.png")))) - ); - - Utils.buildDrawer(AppManager.getInstance().getDrawer(), header, REGISTRY.getViews()); - - //NavigationDrawer.Footer footer = new NavigationDrawer.Footer("Bla"); - //AppManager.getInstance().getDrawer().setFooter(footer); - } - -} diff --git a/src/main/java/biz/nellemann/mdexpl/view/MainPresenter.java b/src/main/java/biz/nellemann/mdexpl/view/MainPresenter.java deleted file mode 100644 index 7c8d6a8..0000000 --- a/src/main/java/biz/nellemann/mdexpl/view/MainPresenter.java +++ /dev/null @@ -1,77 +0,0 @@ -package biz.nellemann.mdexpl.view; - -import biz.nellemann.mdexpl.NetworkServiceCell; -import biz.nellemann.mdexpl.model.NetworkService; -import biz.nellemann.mdexpl.model.MainModel; -import biz.nellemann.mdexpl.service.DiscoveryService; -import com.gluonhq.charm.glisten.application.AppManager; -import com.gluonhq.charm.glisten.control.AppBar; -import com.gluonhq.charm.glisten.control.CharmListView; -import com.gluonhq.charm.glisten.control.LifecycleEvent; -import com.gluonhq.charm.glisten.mvc.View; -import com.gluonhq.charm.glisten.visual.MaterialDesignIcon; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.fxml.FXML; -import javafx.scene.input.MouseEvent; -import javafx.scene.input.TouchEvent; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.inject.Inject; -import java.util.ResourceBundle; - -public class MainPresenter { - - private static final Logger log = LoggerFactory.getLogger(MainPresenter.class); - - - @FXML - private View main; - - @Inject - private MainModel model; - - @Inject - private DiscoveryService discoveryService; - - @FXML - private ResourceBundle resources; - - @FXML - private CharmListView charmListView; - - private final ObservableList devicesList = FXCollections.observableArrayList(); - - - @FXML - public void initialize() { - - log.info("initialize()"); - - main.showingProperty().addListener((obs, oldValue, newValue) -> { - if (newValue) { - AppManager appManager = AppManager.getInstance(); - AppBar appBar = appManager.getAppBar(); - - appBar.setNavIcon(MaterialDesignIcon.MENU.button(e -> - appManager.getDrawer().open())); - - appBar.setTitleText("mDNS Explorer"); - } - }); - - discoveryService.setObservableList(devicesList); - charmListView.setItems(devicesList); - charmListView.setCellFactory(p -> new NetworkServiceCell()); - } - - - public void onEventShowing(LifecycleEvent lifecycleEvent) { - - } - - public void onEventHiding(LifecycleEvent lifecycleEvent) { - } - -} diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java new file mode 100644 index 0000000..753b422 --- /dev/null +++ b/src/main/java/module-info.java @@ -0,0 +1,12 @@ +module biz.nellemann.mdexpl { + requires javafx.controls; + requires javafx.fxml; + requires javax.jmdns; + requires org.slf4j; + requires jakarta.inject; + requires jakarta.annotation; + requires java.desktop; + + opens biz.nellemann.mdexpl to javafx.fxml; + exports biz.nellemann.mdexpl; +} diff --git a/src/main/resources/biz/nellemann/mdexpl/main.fxml b/src/main/resources/biz/nellemann/mdexpl/main.fxml new file mode 100644 index 0000000..933b83e --- /dev/null +++ b/src/main/resources/biz/nellemann/mdexpl/main.fxml @@ -0,0 +1,15 @@ + + + + + + + +
+ +
+ + + + +
diff --git a/src/main/resources/biz/nellemann/mdexpl/view/about.fxml b/src/main/resources/biz/nellemann/mdexpl/view/about.fxml deleted file mode 100644 index df8b47f..0000000 --- a/src/main/resources/biz/nellemann/mdexpl/view/about.fxml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/main/resources/biz/nellemann/mdexpl/view/configuration.properties b/src/main/resources/biz/nellemann/mdexpl/view/configuration.properties deleted file mode 100644 index f6c5482..0000000 --- a/src/main/resources/biz/nellemann/mdexpl/view/configuration.properties +++ /dev/null @@ -1,8 +0,0 @@ -### -# properties defined in configuration.properties per folder (component) -# can be directly injected into a presenter - -appCopyright=@copyright@ -appVersion=@version@ - -aboutWebsite=https://www.nellemann.biz diff --git a/src/main/resources/biz/nellemann/mdexpl/view/main.fxml b/src/main/resources/biz/nellemann/mdexpl/view/main.fxml deleted file mode 100644 index 31171e8..0000000 --- a/src/main/resources/biz/nellemann/mdexpl/view/main.fxml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - -
- -
- -