1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
|
PF4J - Update
=====================
[](https://travis-ci.org/pf4j/pf4j-update)
[](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
<dependency>
<groupId>org.pf4j</groupId>
<artifactId>pf4j-update</artifactId>
<version>${pf4j-update.version}</version>
</dependency>
```
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/UpdateTest.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<PluginInfo> 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<PluginInfo> 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<UpdateRepository.PluginInfo> getAvailablePlugins();
public boolean hasAvailablePlugins();
public List<UpdateRepository.PluginInfo> getUpdates();
public boolean hasUpdates();
public List<UpdateRepository.PluginInfo> getPlugins();
public List<UpdateRepository> 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><br/>*or* <hash-file URL><br/>*or* ".sha512" |String with SHA-512 HEX digest of file content<br/>URL to file with SHA-512 string<br/>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:
`<major>.<minor>.<patch>`
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/.
|