An open API service indexing awesome lists of open source software.

https://github.com/pf4j/pf4j-update

Update mechanism for PF4J
https://github.com/pf4j/pf4j-update

java modularity pf4j plugins update

Last synced: 9 months ago
JSON representation

Update mechanism for PF4J

Awesome Lists containing this project

README

          

PF4J - Update
=====================
[![Travis CI Build Status](https://travis-ci.org/pf4j/pf4j-update.png)](https://travis-ci.org/pf4j/pf4j-update)
[![Maven Central](http://img.shields.io/maven-central/v/org.pf4j/pf4j-update.svg)](http://search.maven.org/#search|ga|1|pf4j-update)

The goal of this project is to supply an update mechanism for [PF4J](https://github.com/pf4j/pf4j).
It's an open source (Apache license) lightweight (around 15KB) extension for PF4J, with minimal dependencies (only pf4j and gson).

Components
-------------------
- **UpdateManager** allows you to inspect the repositories (local, remote) for updates, available (new) plugins. Also this class allows you to install available plugins, update or uninstall existing plugins.
- **UpdateRepository** defines a local/remote repository (pluggable)
- **PluginInfo** defines the plugin information for each repository's plugin
- **PluginRelease** defines a plugin release
- **FileDownloader** defines a pluggable way of downloading from a repository
- **FileVerifier** defines a pluggable way of verifying downloaded files, e.g. checksum verification

Using Maven
-------------------
In your pom.xml you must define the dependencies to PF4J artifacts with:

```xml

org.pf4j
pf4j-update
${pf4j-update.version}

```

where ${pf4j-update.version} is the last pf4j-update version.

You may want to check for the latest released version using [Maven Search](http://search.maven.org/#search%7Cga%7C1%7Cpf4j-update)

How to use
-------------------
It's very simple to add pf4j-update in your application.
The whole code of below snippet is available on [Github](https://github.com/pf4j/pf4j-update/blob/master/src/test/java/org/pf4j/update/util/TestApplication.java).

```java
public static void main(String[] args) {
...

// create plugin manager
PluginManager pluginManager = new DefaultPluginManager();
pluginManager.loadPlugins();

// create update manager
UpdateManager updateManager = new UpdateManager(pluginManager);

// >> keep system up-to-date <<
boolean systemUpToDate = true;

// check for updates
if (updateManager.hasUpdates()) {
List updates = updateManager.getUpdates();
log.debug("Found {} updates", updates.size());
for (PluginInfo plugin : updates) {
log.debug("Found update for plugin '{}'", plugin.id);
PluginInfo.PluginRelease lastRelease = updateManager.getLastPluginRelease(plugin.id);
String lastVersion = lastRelease.version;
String installedVersion = pluginManager.getPlugin(plugin.id).getDescriptor().getVersion();
log.debug("Update plugin '{}' from version {} to version {}", plugin.id, installedVersion, lastVersion);
boolean updated = updateManager.updatePlugin(plugin.id, lastVersion);
if (updated) {
log.debug("Updated plugin '{}'", plugin.id);
} else {
log.error("Cannot update plugin '{}'", plugin.id);
systemUpToDate = false;
}
}
} else {
log.debug("No updates found");
}

// check for available (new) plugins
if (updateManager.hasAvailablePlugins()) {
List availablePlugins = updateManager.getAvailablePlugins();
log.debug("Found {} available plugins", availablePlugins.size());
for (PluginInfo plugin : availablePlugins) {
log.debug("Found available plugin '{}'", plugin.id);
PluginInfo.PluginRelease lastRelease = updateManager.getLastPluginRelease(plugin.id);
String lastVersion = lastRelease.version;
log.debug("Install plugin '{}' with version {}", plugin.id, lastVersion);
boolean installed = updateManager.installPlugin(plugin.id, lastVersion);
if (installed) {
log.debug("Installed plugin '{}'", plugin.id);
} else {
log.error("Cannot install plugin '{}'", plugin.id);
systemUpToDate = false;
}
}
} else {
log.debug("No available plugins found");
}

if (systemUpToDate) {
log.debug("System up-to-date");
}

...
}
```

The library has very few components. The main component is the **UpdateManager**.
This class contains methods for repositories inspection
```java
public List getAvailablePlugins();
public boolean hasAvailablePlugins();
public List getUpdates();
public boolean hasUpdates();
public List getPlugins();
public List getRepositories();
```
and methods for plugin handling
```java
public boolean installPlugin(String url);
public boolean updatePlugin(String id, String url);
public boolean uninstallPlugin(String id);
```

UpdateManager can work with multiple repositories (local and remote).
All repositories are either defined in a `repositories.json` file or
provided in UpdateManager's constructor.

Below I defined two repository: localhost and folder.
```json
[
{
"id": "localhost",
"url": "http://localhost:8081/"
},
{
"id": "folder",
"url": "file:/home/decebal/work/pf4j-update/downloads/"
}
]
```

Each repository has a unique id and a URL.

In the root of this project you have a `repositories.json` file used by
the test applications.

For more information please see the test sources (UpdateTest, ...).
It's a good idea to run these tests and to see the results.

Customization
-------------
The project is made for customization and extension to your own needs. Here are some
examples:

### Tailor repository loading
First you can supply to `UpdateManager` your custom location and name
of `repositories.json` if you want it to live somewhere else.

If you need even more control, `UpdateManager` accepts repositories in
constructor and through setters.
Implement your own `UpdateRepository`, `FileDownloader` and `FileVerifier`s
to handle your own custom repsitory structures, authentication, checksum
verifications etc.

### Subclass UpdateManager
For full control, subclass `UpdateManager` and override relevant methods.

Repository structure
-------------------
Each repository exposes multiple plugins using a `plugins.json` file.
Below I registered two plugins: _welcome-plugin_ and _hello-plugin_.

```json
[
{
"id": "welcome-plugin",
"description": "Welcome plugin",
"releases": [
{
"version": "0.8.0",
"date": "Jun 5, 2014 9:00:35 PM",
"url": "pf4j-demo-plugin1/0.8.0/pf4j-demo-plugin1-0.8.0.zip"
},
{
"version": "0.9.0",
"date": "Jun 25, 2014 9:58:35 PM",
"url": "pf4j-demo-plugin1/0.9.0/pf4j-demo-plugin1-0.9.0.zip"
}
]
},
{
"id": "hello-plugin",
"description": "Hello plugin",
"releases": [
{
"version": "0.8.0",
"date": "Jun 5, 2014 9:12:35 PM",
"url": "pf4j-demo-plugin2/0.8.0/pf4j-demo-plugin2-0.8.0.zip"
},
{
"version": "0.9.0",
"date": "Jun 25, 2014 9:58:35 PM",
"url": "pf4j-demo-plugin2/0.9.0/pf4j-demo-plugin2-0.9.0.zip"
}
]
}
]
```

### plugins.json
**Fields per plugin**

|Property |Format |Description |
|------------|-------------|-----------------------------------|
|id |string |Unique id, mandatory |
|name |string |Display name (short) |
|description |string |Describe your plugin |
|provider |string |Name of plugin provider |
|releases |List |List of releases (minimum one) |

**Fields per release**

|Property |Format |Description |
|------------|-------------|-----------------------------------|
|version |X.Y.Z |Version of release ([SemVer](http://semver.org/) format) |
|date |date |Release date, ISO8601 or `yyyy-MM-dd` format |
|requires |Expression |[SemVer expression](https://github.com/zafarkhaja/jsemver#semver-expressions-api-ranges), e.g. ">=2.0.0" |
|url |URL-string |Link to zip, either absolute or relative URL |
|sha512sum |<sha512-digest>
*or* <hash-file URL>
*or* ".sha512" |String with SHA-512 HEX digest of file content
URL to file with SHA-512 string
Fetch SHA-512 file next to plugin, with `.sha512` file suffix |

*New properties may appear in the future.*

The last (current) release of the plugin is calculated taking into account
by the _version_ property. In our example, the last release for each
plugin is the release with version _0.9.0_.

We encourage using `yyyy-MM-dd` format for release date. Localized US format
as in the examples above will also work. If the date is not parsable, it
will be set to epoch (1970-01-01) and print a warning in logs.

**NOTE**: The `requires` property was a simple X.Y.Z string in versions
up to 0.3.0, interpreted as `>=X.Y.Z`. You may want to update your old
`plugins.json` files to the new syntax.

### Example for 'hello-plugin' (plugin2):
URL from `repositories.json`: `http://localhost:8081/`
Relative URL in `plugins.json`: `pf4j-demo-plugin2/0.8.0/pf4j-demo-plugin2-0.8.0.zip`
Resulting `UpdateRepository.PluginRelease.url`: `http://localhost:8081/pf4j-demo-plugin2/0.8.0/pf4j-demo-plugin2-0.8.0.zip`

In the _downloads_ folder of the project you have a repository (plugins.json and artifacts - plugins archives) used by the test applications.
The structure of the repository is:

- plugin1
- 0.8.0
- plugin1.zip
- 0.9.0
- plugin1.zip
- plugin2
- 0.8.0
- plugin2.zip
- 0.9.0
- plugin2.zip
- plugins.json

For each plugin you have a folder (plugin1, plugin2) that contains subfolder for each version (0.8.0, 0.9.0).
In each version folder you have the plugin archive (.zip) according to PF4J specification.

Mailing list
--------------
Much of the conversation between developers and users is managed through [mailing list](http://groups.google.com/group/pf4j).

Versioning
------------
This project will be maintained under the Semantic Versioning guidelines as much as possible.

Releases will be numbered with the follow format:

`..`

And constructed with the following guidelines:

* Breaking backward compatibility bumps the major
* New additions without breaking backward compatibility bumps the minor
* Bug fixes and misc changes bump the patch

For more information on SemVer, please visit http://semver.org/.