Skip to content

Commit

Permalink
Merge pull request #1 from edvin/master
Browse files Browse the repository at this point in the history
pull latest
  • Loading branch information
gcstang authored Sep 28, 2016
2 parents 12cee38 + a302457 commit 535cc68
Show file tree
Hide file tree
Showing 11 changed files with 745 additions and 242 deletions.
51 changes: 49 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,57 @@
# Change Log
All notable changes to this project will be documented in this file.

## [Unreleased]
## [10.0.14-SNAPSHOT]

- `include-extensions` was consulted too early, leaving the matched files out of the manifest

## [1.0.13] - 2016-09-12

- Support for fully customizable update UI, see (https://github.com/edvin/fxlauncher-custom-ui)
- Basic Authentication support for manifest url (via https://user:pass@host/path)
- Added `--include-extensions` as a comma separated list of filename extensions to include of other resources from the build dir. By default it always includes `jar,war`.
- Fixed bug: If updating from a manifest with no timestamp (pre 1.0.11), new version was considered older, so no upgrade was performed

## [1.0.12]

### Changed

- Added `include-extensions` parameter to CreateManaifest. By default only `jar` and `war` files are included, add more extensions via this comma separated list.
- Added --accept-downgrade=<true|false> parameter to CreateManifest. Default is to not accept downgrades (server version is older than local version)
- Artifacts in subfolders gets correct path delimiter in app manifest for Windows

## [1.0.11]

### Changed

- Progress window is now closed after primaryStage is shown instead of right before app.start() is called

## [1.0.10] - 2016-05-07

### Changed

- Add optional `--cache-dir` program parameter `cacheDir` and manifest entry (https://github.com/edvin/fxlauncher/issues/9)
- Add / if missing from base url (https://github.com/edvin/fxlauncher/issues/6)

## [1.0.9] - 2016-03-14

### Added

- App manifest location can be given as command line parameter (https://github.com/edvin/fxlauncher/issues/3)

## [1.0.8] - 2016-03-02

### Added
- OS specific resources

- Support for manifest configurable parameters (https://github.com/edvin/fxlauncher/issues/2)

## [1.0.7] - 2016-02-20

### Added
- Support for platform specific resources

### Changed
- Parameters are now passed to the Application instance (https://github.com/edvin/fxlauncher/issues/1)

## [1.0.6] - 2016-02-10
- First feature complete release
44 changes: 41 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# FXLauncher

[![Maven Central](https://maven-badges.herokuapp.com/maven-central/no.tornado/fxlauncher/badge.svg)](https://search.maven.org/#search|ga|1|no.tornado.fxlauncher)
[![Apache License](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg)](http://www.apache.org/licenses/LICENSE-2.0)

Auto updating launcher for JavaFX Applications. Combined with JavaFX native packaging, you get
a native installer with automatic app updates.

Expand All @@ -12,11 +15,11 @@ You can see the launcher in action in this [Demo Application](http://fxldemo.tor

### Video demonstration

See the launcher in action in this short [screencast](https://www.youtube.com/watch?v=NCP9wjRPQ14).
See the launcher in action in this short [screencast](https://www.youtube.com/watch?v=NCP9wjRPQ14). There is also a [video](https://www.youtube.com/watch?v=-6PlFVUgntU) about customizing the update user interface.

## How does it work?

FXLauncher is a 14Kb jar that can be used to boot your application. It knows the location
FXLauncher is a 18Kb jar that can be used to boot your application. It knows the location
of your application repository where you host all the app resources.

See a manifest [example here](http://fxldemo.tornado.no/app.xml). FXLauncher will look up the
Expand All @@ -33,7 +36,15 @@ Before each run, the launcher will synchronize all resources and seamlessly laun
## How to use FXLauncher

See the QuickStart projects at the top of the README for information on integrating FXLauncher in your build system.

## Adhoc usage

FXLauncher can also be used to launch an application at an arbitrary url by specifying the `--app` parameter at startup:

```bash
java -jar fxlauncher.jar --app=http://remote/location/app.xml
```

#### Native installers

The native installer does not contain any application code, only the launcher. There is
Expand All @@ -49,6 +60,19 @@ Check out these prebuilt installers for a more complex demo application
- [Windows](http://fxsamples.tornado.no/CRMApplication-1.0.exe)
- [Linux](http://fxsamples.tornado.no/crmapplication-1.0.deb)

## Specify cache directory

By default, the artifacts are downloaded to the current working directory. This is usually fine for native installers, but if you distribute
your application via just the launcher jar, you might want to specify where the downloaded artifacts land. See the
[cache dir documentation](https://github.com/edvin/fxlauncher/wiki/Optional-Cache-Directory)for more information.

## Accept downgrades

Starting from version 1.0.12, FXLauncher will not download a remote version if the local version is newer. This is controlled
by comparing a timestamp in the manifest. Specifying `--accept-downgrades=true` as the last argument to CreateManifest will
allow you to make sure that the version you have published will always be used by your clients even if they have a newer version installed.
This option is also available in the Gradle plugin as `acceptDowngrades`.

## A slimmer alternative

It is also possible to embed the launchar jar in a native installer system like Advanced Installer - same approach as above,
Expand All @@ -58,4 +82,18 @@ Again, you are only distributing the launcher with the native installer, the res
### A note on classloaders

FXLauncher uses a custom classloader to dynamically load the synchronized resources. This classloader is
then made available to the `FXMLLoader`. You can access it via `FXMLLoader.getDefaultClassLoader()`.
then made available to the `FXMLLoader`. You can access it via `FXMLLoader.getDefaultClassLoader()`.

### Platform specific resources

FXLauncher supports filtering of resources for the running platform. Any resource
that ends with `-[mac|win|linux].jar` will only be downloaded and put on the classpath on the corresponding
platform. The manifest enforces this though the `os` attribute in `app.xml`.

### Custom UI

There are two ways to customize the appearance of the update UI. Either you can configure the
supported style properties in the manifest, or you can provide a custom implementation of the
[UIProvider](https://github.com/edvin/fxlauncher/blob/master/src/main/java/fxlauncher/UIProvider.java)
to completely customize the UI. Have a look at this [Custom UI Demo Project](https://github.com/edvin/fxlauncher-custom-ui) for
more information about customizing the updater.
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>no.tornado</groupId>
<artifactId>fxlauncher</artifactId>
<version>1.0.7</version>
<version>1.0.14-SNAPSHOT</version>
<packaging>jar</packaging>
<name>FX Launcher</name>
<description>Auto updating launcher for JavaFX Applications</description>
Expand Down Expand Up @@ -119,7 +119,7 @@
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<phase>install</phase>
<goals>
<goal>sign</goal>
</goals>
Expand Down
74 changes: 72 additions & 2 deletions src/main/java/fxlauncher/CreateManifest.java
Original file line number Diff line number Diff line change
@@ -1,35 +1,105 @@
package fxlauncher;

import com.sun.javafx.application.ParametersImpl;

import javax.xml.bind.JAXB;
import java.io.IOException;
import java.net.URI;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class CreateManifest {
private static ArrayList<String> includeExtensions = new ArrayList<>();

static {
includeExtensions.addAll(Arrays.asList("jar", "war"));
}

public static void main(String[] args) throws IOException {
URI baseURI = URI.create(args[0]);
String launchClass = args[1];
Path appPath = Paths.get(args[2]);

String cacheDir = null;
Boolean acceptDowngrade = null;
String parameters = null;

if (args.length > 3) {
// Parse named parameters
List<String> rawParams = new ArrayList<>();
rawParams.addAll(Arrays.asList(args).subList(3, args.length));
ParametersImpl params = new ParametersImpl(rawParams);
Map<String, String> named = params.getNamed();

if (named != null) {
// Configure cacheDir
if (named.containsKey("cache-dir"))
cacheDir = named.get("cache-dir");

// Configure acceptDowngrade
if (named.containsKey("accept-downgrade"))
acceptDowngrade = Boolean.valueOf(named.get("accept-downgrade"));

// Add additional files with these extensions to manifest
if (named.containsKey("include-extensions"))
includeExtensions.addAll(
Arrays.stream(named.get("include-extensions").split(","))
.filter(s -> s != null && !s.isEmpty())
.collect(Collectors.toList())
);
}

// Append the rest as manifest parameters
StringBuilder rest = new StringBuilder();
for (String raw : params.getRaw()) {
if (raw.startsWith("--cache-dir=")) continue;
if (raw.startsWith("--accept-downgrade=")) continue;
if (raw.startsWith("--include-extensions=")) continue;
if (rest.length() > 0) rest.append(" ");
rest.append(raw);
}

// Add the raw parameter string to the manifest
if (rest.length() > 0)
parameters = rest.toString();
}

FXManifest manifest = create(baseURI, launchClass, appPath);
if (cacheDir != null) manifest.cacheDir = cacheDir;
if (acceptDowngrade != null) manifest.acceptDowngrade = acceptDowngrade;
if (parameters != null) manifest.parameters = parameters;

JAXB.marshal(manifest, appPath.resolve("app.xml").toFile());
}

public static FXManifest create(URI baseURI, String launchClass, Path appPath) throws IOException {
FXManifest manifest = new FXManifest();
manifest.ts = System.currentTimeMillis();
manifest.uri = baseURI;
manifest.launchClass = launchClass;

Files.walkFileTree(appPath, new SimpleFileVisitor<Path>() {
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (!Files.isDirectory(file) && file.toString().endsWith(".jar") && !file.getFileName().toString().startsWith("fxlauncher"))
if (!Files.isDirectory(file) && shouldIncludeInManifest(file) && !file.getFileName().toString().startsWith("fxlauncher"))
manifest.files.add(new LibraryFile(appPath, file));
return FileVisitResult.CONTINUE;
}
});

return manifest;
}


private static boolean shouldIncludeInManifest(Path file) {
String filename = file.getFileName().toString();
for (String ext : includeExtensions) {
if (filename.toLowerCase().endsWith(String.format(".%s", ext.toLowerCase()))) return true;
}
return false;
}

}
42 changes: 42 additions & 0 deletions src/main/java/fxlauncher/DefaultUIProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package fxlauncher;

import javafx.geometry.Insets;
import javafx.scene.Parent;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class DefaultUIProvider implements UIProvider {
private ProgressBar progressBar;

public Parent createLoader() {
StackPane root = new StackPane(new ProgressIndicator());
root.setPrefSize(200, 80);
root.setPadding(new Insets(10));
return root;
}

public Parent createUpdater(FXManifest manifest) {
progressBar = new ProgressBar();
progressBar.setStyle(manifest.progressBarStyle);

Label label = new Label(manifest.updateText);
label.setStyle(manifest.updateLabelStyle);

VBox wrapper = new VBox(label, progressBar);
wrapper.setStyle(manifest.wrapperStyle);

return wrapper;
}

public void updateProgress(double progress) {
progressBar.setProgress(progress);
}

public void init(Stage stage) {

}
}
Loading

0 comments on commit 535cc68

Please sign in to comment.