├── .gitignore ├── README.md ├── build.sh ├── jar-run.sh ├── run.sh └── src ├── carprov.dashboard.api ├── carprov │ └── dashboard │ │ └── api │ │ ├── App.java │ │ └── ImageHelper.java └── module-info.java ├── carprov.dashboard.jfx ├── carprov │ └── dashboard │ │ └── jfx │ │ ├── ConfigurationApp.java │ │ └── Dashboard.java ├── config.png ├── home.png └── module-info.java ├── carprov.music ├── carprov │ └── music │ │ └── MusicApp.java ├── forward.png ├── module-info.java ├── music.png ├── play.png ├── prev.png ├── stop.png └── wave.gif ├── carprov.navigation ├── carprov │ └── navigation │ │ └── NavigationApp.java ├── map.png ├── maps.png └── module-info.java └── carprov.phone ├── carprov └── phone │ └── PhoneApp.java ├── module-info.java ├── number-pad.png └── phone.png /.gitignore: -------------------------------------------------------------------------------- 1 | /mods 2 | /image 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # carprov-jigsaw 2 | Port of the OSGi carprov example (https://github.com/sandermak/carprov) using the JDK9 early access build with Jigsaw 3 | Read http://branchandbound.net/blog/java/2015/10/osgi-to-jigsaw/ for a more thorough walkthrough of the code. 4 | 5 | The `run.sh` script builds the modules and runs them from the 'exploded' module format. 6 | 7 | The `jar-run.sh` script builds modular jars and runs the application from these jars. 8 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | rm -rf mods 2 | mkdir mods 3 | 4 | # Copy resources 5 | cd src 6 | rsync -R $(find . -name *.png -o -name *.gif) ../mods 7 | cd - 8 | 9 | # Compile modules 10 | javac -modulesourcepath src -d mods $(find src -name '*.java') -------------------------------------------------------------------------------- /jar-run.sh: -------------------------------------------------------------------------------- 1 | ./build.sh 2 | mkdir mods/jarred 3 | jar --create --file mods/jarred/carprov.dashboard.api@1.0.jar --module-version=1.0 -C mods/carprov.dashboard.api . 4 | jar --create --file mods/jarred/carprov.music@1.0.jar --module-version=1.0 -C mods/carprov.music . 5 | jar --create --file mods/jarred/carprov.phone@1.0.jar --module-version=1.0 -C mods/carprov.phone . 6 | jar --create --file mods/jarred/carprov.navigation@1.0.jar --module-version=1.0 -C mods/carprov.navigation . 7 | jar --create --file mods/jarred/carprov.dashboard.jfx@1.0.jar --module-version=1.0 --main-class=carprov.dashboard.jfx.Dashboard -C mods/carprov.dashboard.jfx . 8 | java -mp mods/jarred -m carprov.dashboard.jfx 9 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | ./build.sh 2 | java -mp mods -m carprov.dashboard.jfx/carprov.dashboard.jfx.Dashboard -------------------------------------------------------------------------------- /src/carprov.dashboard.api/carprov/dashboard/api/App.java: -------------------------------------------------------------------------------- 1 | package carprov.dashboard.api; 2 | 3 | import javafx.scene.Node; 4 | 5 | public interface App { 6 | 7 | String getAppName(); 8 | 9 | int getPreferredPosition(); 10 | 11 | Node getDashboardIcon(); 12 | 13 | Node getMainApp(); 14 | 15 | } -------------------------------------------------------------------------------- /src/carprov.dashboard.api/carprov/dashboard/api/ImageHelper.java: -------------------------------------------------------------------------------- 1 | package carprov.dashboard.api; 2 | 3 | import java.io.InputStream; 4 | import javafx.scene.image.Image; 5 | import javafx.scene.image.ImageView; 6 | 7 | public class ImageHelper { 8 | 9 | public static ImageView getImage(InputStream stream) { 10 | Image image = new Image(stream); 11 | ImageView view = new ImageView(image); 12 | view.setPreserveRatio(true); 13 | return view; 14 | } 15 | 16 | } -------------------------------------------------------------------------------- /src/carprov.dashboard.api/module-info.java: -------------------------------------------------------------------------------- 1 | module carprov.dashboard.api { 2 | exports carprov.dashboard.api; 3 | requires public javafx.graphics; 4 | } -------------------------------------------------------------------------------- /src/carprov.dashboard.jfx/carprov/dashboard/jfx/ConfigurationApp.java: -------------------------------------------------------------------------------- 1 | package carprov.dashboard.jfx; 2 | 3 | import javafx.geometry.Orientation; 4 | import javafx.geometry.Pos; 5 | import javafx.scene.Node; 6 | import javafx.scene.layout.FlowPane; 7 | import javafx.scene.paint.Color; 8 | import javafx.scene.text.Font; 9 | import javafx.scene.text.Text; 10 | 11 | import carprov.dashboard.api.App; 12 | import carprov.dashboard.api.ImageHelper; 13 | 14 | import java.lang.reflect.Layer; 15 | import java.lang.reflect.Module; 16 | 17 | public class ConfigurationApp implements App { 18 | 19 | @Override 20 | public String getAppName() { 21 | return "Config"; 22 | } 23 | 24 | @Override 25 | public int getPreferredPosition() { 26 | return 100; 27 | } 28 | 29 | @Override 30 | public Node getDashboardIcon() { 31 | return ImageHelper.getImage(getClass().getResourceAsStream("/config.png")); 32 | } 33 | 34 | @Override 35 | public Node getMainApp() { 36 | FlowPane flowPane = new FlowPane(Orientation.VERTICAL); 37 | flowPane.setAlignment(Pos.CENTER); 38 | 39 | Layer layer = Layer.boot(); 40 | for (Module m: layer.modules()) { 41 | if(m.getName().startsWith("carprov")) { 42 | flowPane.getChildren().add(getModuleDescription(m)); 43 | } 44 | } 45 | 46 | return flowPane; 47 | } 48 | 49 | private Node getModuleDescription(Module m) { 50 | Text text = new Text(m.getName() + ": " + m.getDescriptor().version().map(Object::toString).orElse("no version specified")); 51 | text.setFont(new Font("Open Sans", 18)); 52 | text.setFill(Color.AZURE); 53 | return text; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/carprov.dashboard.jfx/carprov/dashboard/jfx/Dashboard.java: -------------------------------------------------------------------------------- 1 | package carprov.dashboard.jfx; 2 | 3 | import carprov.dashboard.api.App; 4 | import carprov.dashboard.api.ImageHelper; 5 | 6 | import java.util.ServiceLoader; 7 | 8 | import javafx.application.Platform; 9 | import javafx.embed.swing.JFXPanel; 10 | import javafx.geometry.Insets; 11 | import javafx.geometry.Orientation; 12 | import javafx.scene.Node; 13 | import javafx.scene.Scene; 14 | import javafx.scene.image.Image; 15 | import javafx.scene.image.ImageView; 16 | import javafx.scene.layout.BorderPane; 17 | import javafx.scene.layout.FlowPane; 18 | import javafx.scene.layout.StackPane; 19 | import javafx.scene.paint.Color; 20 | import javafx.scene.text.Font; 21 | import javafx.scene.text.Text; 22 | import javafx.stage.Stage; 23 | 24 | public class Dashboard { 25 | 26 | private static final String DASHBOARD_TITLE = "Ace Car Entertainment"; 27 | 28 | private static Text titleText; 29 | private static BorderPane mainView; 30 | private static FlowPane dashboardIcons; 31 | 32 | public static void main(String[] args) { 33 | // Workaround to trigger toolkit init because 34 | // we are not using JavaFX's Application class 35 | new JFXPanel(); 36 | Platform.runLater(() -> createUI()); 37 | } 38 | 39 | public static void createUI() { 40 | mainView = new BorderPane(); 41 | mainView.setPadding(new Insets(20)); 42 | Scene scene = new Scene(mainView, 600, 400); 43 | mainView.setStyle("-fx-background-color: #444444;"); 44 | mainView.setTop(getTopBar()); 45 | 46 | dashboardIcons = new FlowPane(); 47 | dashboardIcons.setVgap(25); 48 | dashboardIcons.setHgap(25); 49 | dashboardIcons.setPadding(new Insets(20)); 50 | dashboardIcons.setOrientation(Orientation.HORIZONTAL); 51 | 52 | Stage primaryStage = new Stage(); 53 | Iterable apps = ServiceLoader.load(App.class); 54 | 55 | for(App app: apps) { 56 | renderDashboardIcon(app); 57 | } 58 | 59 | startDashboard(); 60 | primaryStage.setScene(scene); 61 | primaryStage.show(); 62 | } 63 | 64 | private static void renderDashboardIcon(App app) { 65 | Node dashboardIcon = app.getDashboardIcon(); 66 | dashboardIcons.getChildren().add(dashboardIcon); 67 | dashboardIcon.setOnMouseClicked(event -> startApp(app)); 68 | } 69 | 70 | private static void startApp(App app) { 71 | titleText.setText(DASHBOARD_TITLE + " > " + app.getAppName()); 72 | Node mainApp = app.getMainApp(); 73 | mainView.setCenter(mainApp); 74 | } 75 | 76 | private static void startDashboard() { 77 | titleText.setText(DASHBOARD_TITLE); 78 | mainView.setCenter(dashboardIcons); 79 | } 80 | 81 | private static Node getTopBar() { 82 | ImageView homeImg = ImageHelper.getImage(Dashboard.class.getResourceAsStream("/home.png")); 83 | homeImg.setFitHeight(40); 84 | homeImg.setOnMouseClicked(event -> startDashboard()); 85 | 86 | 87 | titleText = new Text(DASHBOARD_TITLE); 88 | titleText.setFont(new Font("Open Sans", 22)); 89 | titleText.setFill(Color.AZURE); 90 | 91 | BorderPane pane = new BorderPane(); 92 | pane.setPadding(new Insets(10)); 93 | pane.setStyle("-fx-background-color: #222222;"); 94 | pane.setLeft(titleText); 95 | pane.setRight(homeImg); 96 | return pane; 97 | } 98 | } -------------------------------------------------------------------------------- /src/carprov.dashboard.jfx/config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandermak/carprov-jigsaw/28500273eeca69ded5952b6d662c35958d23c4ef/src/carprov.dashboard.jfx/config.png -------------------------------------------------------------------------------- /src/carprov.dashboard.jfx/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandermak/carprov-jigsaw/28500273eeca69ded5952b6d662c35958d23c4ef/src/carprov.dashboard.jfx/home.png -------------------------------------------------------------------------------- /src/carprov.dashboard.jfx/module-info.java: -------------------------------------------------------------------------------- 1 | module carprov.dashboard.jfx { 2 | requires carprov.dashboard.api; 3 | requires javafx.base; 4 | requires javafx.controls; 5 | requires javafx.swing; 6 | 7 | uses carprov.dashboard.api.App; 8 | provides carprov.dashboard.api.App with carprov.dashboard.jfx.ConfigurationApp; 9 | } -------------------------------------------------------------------------------- /src/carprov.music/carprov/music/MusicApp.java: -------------------------------------------------------------------------------- 1 | package carprov.music; 2 | 3 | import javafx.geometry.Insets; 4 | import javafx.geometry.Pos; 5 | import javafx.scene.Node; 6 | import javafx.scene.effect.ColorInput; 7 | import javafx.scene.image.ImageView; 8 | import javafx.scene.layout.HBox; 9 | import javafx.scene.layout.StackPane; 10 | import javafx.scene.paint.Color; 11 | 12 | import carprov.dashboard.api.App; 13 | import carprov.dashboard.api.ImageHelper; 14 | 15 | public class MusicApp implements App { 16 | 17 | @Override 18 | public String getAppName() { 19 | return "Music"; 20 | } 21 | 22 | @Override 23 | public int getPreferredPosition() { 24 | return 5; 25 | } 26 | 27 | @Override 28 | public Node getDashboardIcon() { 29 | return ImageHelper.getImage(getClass().getResourceAsStream("/music.png")); 30 | } 31 | 32 | @Override 33 | public Node getMainApp() { 34 | ImageView background = ImageHelper.getImage(getClass().getResourceAsStream("/wave.gif")); 35 | ColorInput blackout = new ColorInput(); 36 | blackout.setPaint(Color.BLACK); 37 | background.setEffect(blackout); 38 | StackPane stackPane = new StackPane(background); 39 | 40 | ImageView playButton = ImageHelper.getImage(getClass().getResourceAsStream("/play.png")); 41 | playButton.setOnMouseClicked((evt) -> background.setEffect(null)); 42 | ImageView stopButton = ImageHelper.getImage(getClass().getResourceAsStream("/stop.png")); 43 | stopButton.setOnMouseClicked((evt) -> background.setEffect(blackout)); 44 | HBox buttons = new HBox( 45 | ImageHelper.getImage(getClass().getResourceAsStream("/prev.png")), 46 | playButton, 47 | stopButton, 48 | ImageHelper.getImage(getClass().getResourceAsStream("/forward.png")) 49 | ); 50 | StackPane.setMargin(buttons, new Insets(30, 0, 0, 70)); 51 | StackPane.setAlignment(buttons, Pos.TOP_CENTER); 52 | stackPane.getChildren().add(buttons); 53 | return stackPane; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/carprov.music/forward.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandermak/carprov-jigsaw/28500273eeca69ded5952b6d662c35958d23c4ef/src/carprov.music/forward.png -------------------------------------------------------------------------------- /src/carprov.music/module-info.java: -------------------------------------------------------------------------------- 1 | module carprov.music { 2 | requires carprov.dashboard.api; 3 | 4 | provides carprov.dashboard.api.App with carprov.music.MusicApp; 5 | } -------------------------------------------------------------------------------- /src/carprov.music/music.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandermak/carprov-jigsaw/28500273eeca69ded5952b6d662c35958d23c4ef/src/carprov.music/music.png -------------------------------------------------------------------------------- /src/carprov.music/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandermak/carprov-jigsaw/28500273eeca69ded5952b6d662c35958d23c4ef/src/carprov.music/play.png -------------------------------------------------------------------------------- /src/carprov.music/prev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandermak/carprov-jigsaw/28500273eeca69ded5952b6d662c35958d23c4ef/src/carprov.music/prev.png -------------------------------------------------------------------------------- /src/carprov.music/stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandermak/carprov-jigsaw/28500273eeca69ded5952b6d662c35958d23c4ef/src/carprov.music/stop.png -------------------------------------------------------------------------------- /src/carprov.music/wave.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandermak/carprov-jigsaw/28500273eeca69ded5952b6d662c35958d23c4ef/src/carprov.music/wave.gif -------------------------------------------------------------------------------- /src/carprov.navigation/carprov/navigation/NavigationApp.java: -------------------------------------------------------------------------------- 1 | package carprov.navigation; 2 | 3 | import javafx.geometry.Insets; 4 | import javafx.scene.Node; 5 | import javafx.scene.control.TextField; 6 | import javafx.scene.image.Image; 7 | import javafx.scene.layout.Background; 8 | import javafx.scene.layout.BackgroundFill; 9 | import javafx.scene.layout.BackgroundImage; 10 | import javafx.scene.layout.BackgroundPosition; 11 | import javafx.scene.layout.BackgroundRepeat; 12 | import javafx.scene.layout.BackgroundSize; 13 | import javafx.scene.layout.CornerRadii; 14 | import javafx.scene.layout.FlowPane; 15 | import javafx.scene.layout.VBox; 16 | import javafx.scene.paint.Color; 17 | import javafx.scene.text.Font; 18 | import javafx.scene.text.Text; 19 | 20 | import carprov.dashboard.api.App; 21 | import carprov.dashboard.api.ImageHelper; 22 | 23 | public class NavigationApp implements App { 24 | 25 | @Override 26 | public String getAppName() { 27 | return "Navigation"; 28 | } 29 | 30 | @Override 31 | public int getPreferredPosition() { 32 | return 10; 33 | } 34 | 35 | @Override 36 | public Node getDashboardIcon() { 37 | return ImageHelper.getImage(getClass().getResourceAsStream("/maps.png")); 38 | } 39 | 40 | @Override 41 | public Node getMainApp() { 42 | Text text = new Text("Destination: "); 43 | text.setFont(new Font("Open Sans", 18)); 44 | text.setFill(Color.AZURE); 45 | VBox box = new VBox(text); 46 | box.setPadding(new Insets(2)); 47 | box.setBackground(new Background(new BackgroundFill(Color.web("#444444"), new CornerRadii(3), Insets.EMPTY))); 48 | TextField dest = new TextField("J-Fall 2015!"); 49 | FlowPane flowPane = new FlowPane(box, dest); 50 | flowPane.setPadding(new Insets(30)); 51 | Image image = ImageHelper.getImage(getClass().getResourceAsStream("/map.png")).getImage(); 52 | flowPane.setBackground( 53 | new Background( 54 | new BackgroundImage(image, BackgroundRepeat.NO_REPEAT, BackgroundRepeat.NO_REPEAT, BackgroundPosition.CENTER, 55 | new BackgroundSize(100, 100,true, true, false, true)))); 56 | 57 | return flowPane; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/carprov.navigation/map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandermak/carprov-jigsaw/28500273eeca69ded5952b6d662c35958d23c4ef/src/carprov.navigation/map.png -------------------------------------------------------------------------------- /src/carprov.navigation/maps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandermak/carprov-jigsaw/28500273eeca69ded5952b6d662c35958d23c4ef/src/carprov.navigation/maps.png -------------------------------------------------------------------------------- /src/carprov.navigation/module-info.java: -------------------------------------------------------------------------------- 1 | module carprov.navigation { 2 | requires carprov.dashboard.api; 3 | requires javafx.controls; 4 | 5 | provides carprov.dashboard.api.App with carprov.navigation.NavigationApp; 6 | } -------------------------------------------------------------------------------- /src/carprov.phone/carprov/phone/PhoneApp.java: -------------------------------------------------------------------------------- 1 | package carprov.phone; 2 | 3 | import java.util.concurrent.atomic.AtomicReference; 4 | 5 | import javafx.geometry.Insets; 6 | import javafx.geometry.Pos; 7 | import javafx.scene.Node; 8 | import javafx.scene.control.TextField; 9 | import javafx.scene.image.Image; 10 | import javafx.scene.image.ImageView; 11 | import javafx.scene.layout.BorderPane; 12 | import javafx.scene.text.Font; 13 | import javafx.scene.text.Text; 14 | 15 | 16 | import carprov.dashboard.api.App; 17 | import carprov.dashboard.api.ImageHelper; 18 | 19 | public class PhoneApp implements App { 20 | 21 | 22 | private AtomicReference mainApp = new AtomicReference<>(); 23 | 24 | public PhoneApp() { 25 | mainApp.set(getMainAppNode()); 26 | } 27 | 28 | @Override 29 | public String getAppName() { 30 | return "Phone"; 31 | } 32 | 33 | @Override 34 | public int getPreferredPosition() { 35 | return 20; 36 | } 37 | 38 | @Override 39 | public Node getDashboardIcon() { 40 | return ImageHelper.getImage(getClass().getResourceAsStream("/phone.png")); 41 | } 42 | 43 | @Override 44 | public Node getMainApp() { 45 | return mainApp.get(); 46 | } 47 | 48 | public Node getMainAppNode() { 49 | BorderPane pane = new BorderPane(); 50 | pane.setPadding(new Insets(20)); 51 | ImageView numberPadImg = ImageHelper.getImage(getClass().getResourceAsStream("/number-pad.png")); 52 | numberPadImg.setFitHeight(100); 53 | BorderPane.setAlignment(numberPadImg, Pos.CENTER); 54 | pane.setLeft(numberPadImg); 55 | TextField phone = new TextField(); 56 | phone.setFont(new Font(20)); 57 | phone.setMaxWidth(200); 58 | pane.setCenter(phone); 59 | return pane; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/carprov.phone/module-info.java: -------------------------------------------------------------------------------- 1 | module carprov.phone { 2 | requires carprov.dashboard.api; 3 | requires javafx.controls; 4 | 5 | provides carprov.dashboard.api.App with carprov.phone.PhoneApp; 6 | } -------------------------------------------------------------------------------- /src/carprov.phone/number-pad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandermak/carprov-jigsaw/28500273eeca69ded5952b6d662c35958d23c4ef/src/carprov.phone/number-pad.png -------------------------------------------------------------------------------- /src/carprov.phone/phone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandermak/carprov-jigsaw/28500273eeca69ded5952b6d662c35958d23c4ef/src/carprov.phone/phone.png --------------------------------------------------------------------------------