File: README.md

package info (click to toggle)
libpf4j-update-java 2.3.0%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 288 kB
  • sloc: java: 1,399; xml: 214; makefile: 2
file content (284 lines) | stat: -rw-r--r-- 10,720 bytes parent folder | download | duplicates (2)
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
=====================
[![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
<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   |&lt;sha512-digest&gt;<br/>*or* &lt;hash-file URL&gt;<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/.