This is an automated email from the ASF dual-hosted git repository.
chrisdutz pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git
The following commit(s) were added to refs/heads/develop by this push:
new fcd2fa11a0 doc: Updated the website to correctly update the current
version and replaced the old scraper documentation with new event-pump
documentation.
fcd2fa11a0 is described below
commit fcd2fa11a0f10b067ffa3d7204be76de9533ba95
Author: Christofer Dutz <[email protected]>
AuthorDate: Thu Aug 13 10:26:41 2026 +0200
doc: Updated the website to correctly update the current version and
replaced the old scraper documentation with new event-pump documentation.
---
website/asciidoc/antora.yml | 10 +-
website/asciidoc/modules/users/nav.adoc | 2 +-
website/asciidoc/modules/users/pages/index.adoc | 2 +-
.../modules/users/pages/tools/event-pump.adoc | 271 +++++++++++++++++++++
.../modules/users/pages/tools/scraper.adoc | 237 ------------------
.../modules/users/pages/tools/testing.adoc | 3 +-
website/pom.xml | 52 ++++
7 files changed, 334 insertions(+), 243 deletions(-)
diff --git a/website/asciidoc/antora.yml b/website/asciidoc/antora.yml
index 22d4d03348..ccdd9c4f72 100644
--- a/website/asciidoc/antora.yml
+++ b/website/asciidoc/antora.yml
@@ -27,6 +27,12 @@ nav:
- modules/developers/nav.adoc
asciidoc:
attributes:
- current-last-released-version: '0.14.0-SNAPSHOT'
- current-full-version: '0.14.0'
+ # These two are kept in sync with the version of the Maven project by the
+ # "sync-antora-version" execution in website/pom.xml, which runs in the
"validate"
+ # phase of every build - don't edit them by hand, a build will overwrite
it again.
+ # They have to stay in this file (rather than being passed to Antora
globally),
+ # because the playbook builds the released branches from git alongside
this one and
+ # every branch has to keep documenting its own version.
+ current-last-released-version: '1.0.0-SNAPSHOT'
+ current-full-version: '1.0.0'
diff --git a/website/asciidoc/modules/users/nav.adoc
b/website/asciidoc/modules/users/nav.adoc
index 919658db78..72adbe74c5 100644
--- a/website/asciidoc/modules/users/nav.adoc
+++ b/website/asciidoc/modules/users/nav.adoc
@@ -79,9 +79,9 @@
** xref:tools/index.adoc[]
*** xref:tools/capture-replay.adoc[]
*** xref:tools/connection-cache.adoc[]
+*** xref:tools/event-pump.adoc[]
*** xref:tools/opm.adoc[]
*** xref:tools/plc4x-server.adoc[]
-*** xref:tools/scraper.adoc[]
*** xref:tools/testing.adoc[]
** xref:industry40.adoc[]
diff --git a/website/asciidoc/modules/users/pages/index.adoc
b/website/asciidoc/modules/users/pages/index.adoc
index 41a72917da..361a17b766 100644
--- a/website/asciidoc/modules/users/pages/index.adoc
+++ b/website/asciidoc/modules/users/pages/index.adoc
@@ -59,8 +59,8 @@ And brings stand-alone (Java) utils like:
It also provides (Java) tools for usage inside an application:
- link:tools/connection-cache.html[Connection Cache] (Connection Cache for PLC
connections)
+- link:tools/event-pump.html[Event-Pump] (Util for automating fetching PLC
data using a variety of triggers)
- link:tools/opm.html[Object PLC Mapping (OPM)] (Object PLC Mapping - Like JPA
for PLC data)
- link:tools/plc4x-server.adoc[PLC4X-Server] (A small relay server that speaks
the **PLC4X proxy protocol**.)
-- link:tools/scraper.html[Scraper] (Util for automating fetching PLC data
using a variety of triggers)
- link:tools/testing.html[Testing-Utils] (Want to build/test an application
without having a PLC? ... this is the tool for you)
diff --git a/website/asciidoc/modules/users/pages/tools/event-pump.adoc
b/website/asciidoc/modules/users/pages/tools/event-pump.adoc
new file mode 100644
index 0000000000..27dceec1a5
--- /dev/null
+++ b/website/asciidoc/modules/users/pages/tools/event-pump.adoc
@@ -0,0 +1,271 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+:imagesdir: ../../images/
+:icons: font
+
+= Event-Pump
+
+
+
+While the Apache PLC4X API gives you simple access to PLC resources, reading
the same set of values over and over again is a job the plain API leaves to
you: scheduling the reads, leasing and returning connections, deciding what to
do when the PLC stops answering, and making sure a slow response doesn't pile
up behind the next poll.
+
+The `Event-Pump` does that work for you.
+
+You describe *what* to read and *when*, and it delivers each response to a
listener.
+
+The Event-Pump replaces the `Scraper` from PLC4X 0.13 and earlier.
+If you are migrating, see <<Migrating from the Scraper>> at the end of this
page.
+
+== Getting started with the `Event-Pump`
+The Event-Pump can be found in the Maven module:
+
+[subs=attributes+]
+----
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4j-tools-event-pump</artifactId>
+ <version>{current-last-released-version}</version>
+ </dependency>
+----
+
+== Concepts
+
+The Event-Pump is built from three pieces:
+
+`TagBatch`::
+A set of tags read together from one connection, with one trigger and one
listener.
+A batch is the unit of scheduling: every tag in it is read in a single request.
+
+`Trigger`::
+Decides *when* a batch is fetched.
+The `TimerTrigger` fires at a fixed interval.
+
+`TagBatchListener`::
+Receives each `PlcReadResponse`, and any errors.
+
+`EventPump`::
+A container that owns a number of batches and starts and stops them together.
+
+== Using it from Java
+
+A batch is assembled with a builder and handed to the pump:
+
+[source,java]
+----
+PlcConnectionManager connectionManager = PlcDriverManager.getDefault();
+
+TagBatch batch = TagBatch.builder()
+ .withBatchId("boiler")
+ .withConnectionManager(connectionManager)
+ .withConnectionString("opcua:tcp://192.168.1.1:4840?request-timeout=10000")
+ .addTagAddress("temperature", "ns=2;i=1001")
+ .addTagAddress("pressure", "ns=2;i=1002")
+ .withTrigger(new TimerTrigger(5, TimeUnit.SECONDS))
+ .withListener((b, response) -> {
+ System.out.println("Temperature: " + response.getInt("temperature"));
+ System.out.println("Pressure: " + response.getInt("pressure"));
+ })
+ .build();
+
+EventPump pump = new EventPump();
+pump.addBatch(batch);
+pump.startAll();
+
+// ... later
+pump.close();
+----
+
+`EventPump` implements `AutoCloseable`, and closing it stops and closes every
batch it owns, so a try-with-resources block works too.
+
+Individual batches can be controlled by id with `startBatch(id)`,
`stopBatch(id)` and `removeBatch(id)`.
+
+The tag set of a running batch may be changed at any time with `addTag`,
`removeTag` and `clearTags`; the change takes effect on the next fetch cycle.
+
+=== Handling errors
+
+Passing a lambda as the listener only covers the success case.
+Implement the interface to see failures as well:
+
+[source,java]
+----
+batch.setListener(new TagBatch.TagBatchListener() {
+ @Override
+ public void onTagsFetched(TagBatch batch, PlcReadResponse response) {
+ // process values
+ }
+
+ @Override
+ public void onError(TagBatch batch, Throwable error) {
+ // connection lost, read failed, ...
+ }
+
+ @Override
+ public void onFetchSkipped(TagBatch batch, long lastFetchDurationMs, long
consecutiveSkips) {
+ // the PLC is slower than the configured interval
+ }
+});
+----
+
+== Configuration files
+
+Rather than assembling batches in code, a whole pump can be described in a
YAML, JSON or XML file and loaded with `EventPumpFactory`:
+
+[source,yaml]
+----
+connections:
+ - id: plc1
+ url: "opcua:tcp://192.168.1.1:4840?request-timeout=10000"
+
+batches:
+ - id: boiler
+ connectionId: plc1
+ tags:
+ temperature: "ns=2;i=1001"
+ pressure: "ns=2;i=1002"
+ trigger:
+ type: timer
+ intervalSeconds: 5
+----
+
+[source,java]
+----
+EventPump pump = EventPumpFactory.fromYaml(
+ new File("event-pump.yml"), connectionManager, listener);
+pump.startAll();
+----
+
+`EventPumpFactory` also offers `fromJson(...)` and `fromXml(...)`, and every
variant accepts an optional `ValueTransformerRegistry` as a last argument.
+
+The listener passed to the factory becomes the default listener for all
batches in the file.
+
+=== Transformations
+
+A tag may carry an expression that is applied to its value before the listener
sees it.
+Use the extended tag format to declare one:
+
+[source,yaml]
+----
+batches:
+ - id: boiler
+ connectionId: plc1
+ tags:
+ temperature:
+ address: "ns=2;i=1001"
+ transform: "value * 1.8 + 32"
+ pressure:
+ address: "ns=2;i=1002"
+ trigger:
+ type: timer
+ intervalSeconds: 5
+----
+
+In an expression, `value` refers to the tag's own value, and every other tag
in the same batch is available under its own name, so cross-tag expressions
such as `temperature + humidity` work.
+All names resolve to the values of the *current* response, before any
transformation is applied.
+
+The built-in evaluator (registered under the name `simple`) supports:
+
+* arithmetic: `+`, `-`, `*`, `/`, `%`, unary minus and parentheses
+* comparisons: `>`, `<`, `>=`, `<=`, `==`, `!=`
+* boolean logic: `&&`, `||`, `!`, and the literals `true` and `false`
+
+If an expression fails to evaluate, the error is logged and the *original*
value is passed through, so a broken expression degrades one tag rather than
failing the whole batch.
+
+Custom transformers can be registered by implementing `ValueTransformer` and
adding it to a `ValueTransformerRegistry`.
+
+The same thing is available from the builder via `addTransform(tagName,
expression)`.
+
+== Timeouts, backoff and overload
+
+Getting these right matters more than the API surface does, so it is worth
being explicit about which knob does what.
+
+=== Request timeouts belong on the connection string
+
+The Event-Pump does not impose a request timeout of its own.
+How long a read may take is the driver's decision, configured as a parameter
on the connection URL, for example:
+
+----
+opcua:tcp://192.168.1.1:4840?request-timeout=10000
+----
+
+Consult the documentation of the driver you are using for the parameter it
supports.
+
+=== The fetch watchdog
+
+As a last line of defence against a driver that never completes a read at all,
each batch bounds a single fetch cycle.
+The default is 5 minutes.
+This is deliberately far above any sensible request timeout: it is not a way
to limit how long a read may take, only a guarantee that a batch cannot be
wedged forever by a stalled request.
+
+Set it with `withFetchTimeout(long, TimeUnit)` on the builder, or
`fetchTimeoutMs` on a batch in a configuration file; a value of `0` or less
disables it.
+
+WARNING: Do not use the watchdog as a substitute for the driver's request
timeout. Setting it *below* the driver's timeout makes every slow read look
like a stalled one.
+
+=== When the PLC is unreachable
+
+After a failed fetch, a batch backs off exponentially before trying again: 1
second, then 2, 4, 8 … capped at 60 seconds.
+The first successful fetch resets it.
+This keeps a batch from hammering a device that is down, and keeps your logs
readable during an outage.
+Both ends are configurable with `withInitialBackoffMs(...)` and
`withMaxBackoffMs(...)`.
+
+=== When the PLC is slower than the interval
+
+If a trigger fires while the previous fetch is still running, the new fetch is
*skipped* rather than queued, a warning is logged, and `onFetchSkipped` is
called on the listener.
+This is the main signal that a polling interval is set too aggressively for
the device.
+
+The `TimerTrigger` schedules with a fixed delay rather than a fixed rate, so
an occasional slow cycle delays the next fetch instead of producing a burst of
catch-up reads.
+
+== Threading
+
+Each `TimerTrigger` owns a timer thread and a dispatch thread; listener code
runs on the dispatch thread, never on the timer thread.
+A listener that blocks therefore delays only its own batch.
+
+Note that this means listener callbacks for a given batch are serialized, but
callbacks for *different* batches may run concurrently — a listener shared
between batches must be thread-safe.
+
+A `Timer` may also be shared between several triggers by passing it to the
`TimerTrigger` constructor, which keeps the thread count down when you have
many batches.
+
+== Migrating from the Scraper
+
+The Scraper was removed after PLC4X 0.13.
+The concepts map over fairly directly:
+
+|===
+| Scraper | Event-Pump
+
+| `ScrapeJob`
+| `TagBatch`
+
+| `TriggeredScraperImpl`
+| `EventPump`
+
+| `ResultHandler`
+| `TagBatch.TagBatchListener`
+
+| scrape rate
+| `TimerTrigger` interval
+
+| `futureTimeOut` constructor argument
+| the driver's own `request-timeout` connection string parameter
+|===
+
+The last row is the one to pay attention to.
+The Scraper applied a single timeout of its own — 2000 ms unless you passed
something else — to every read, regardless of what the connection string said.
+The Event-Pump does not: configure the timeout on the connection URL and the
driver will honour it.
+
+== Current limitations
+
+* `SubscriptionTrigger` is a placeholder. It can be constructed, and a
configuration file may name `type: subscription`, but starting such a batch
throws `UnsupportedOperationException`. Use a `TimerTrigger` until subscription
support lands.
+* Batches read; there is no write support.
+* Leasing a connection for a fetch is a blocking call made on the batch's
dispatch thread.
diff --git a/website/asciidoc/modules/users/pages/tools/scraper.adoc
b/website/asciidoc/modules/users/pages/tools/scraper.adoc
deleted file mode 100644
index de12281abf..0000000000
--- a/website/asciidoc/modules/users/pages/tools/scraper.adoc
+++ /dev/null
@@ -1,237 +0,0 @@
-//
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You under the Apache License, Version 2.0
-// (the "License"); you may not use this file except in compliance with
-// the License. You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-:imagesdir: ../../images/
-:icons: font
-
-= Scraper
-
-
-
-While the Apache PLC4X API allows simple access to PLC resources, if you want
to continuously monitor some values and have them retrieved in a pre-defined
interval, the core PLC4X API method is a little bit uncomfortable.
-
-Especially when you have multiple batches of data you want to have refreshed
in different intervals.
-
-In this case you need to take care of the scheduling of queries, need to
manage the connection state (Check if the connection is still available and to
apply countermeasures, if there are problems)
-
-As we have encountered exactly the same problem for about every integration
module we created, the Apache PLC4X team has created a tool called the
`Scraper`.
-
-This tool automatically handles all of the tasks mentioned above.
-
-== Getting started with the `Scraper`
-The Scraper can be found in the Maven module:
-
-[subs=attributes+]
-----
- <dependency>
- <groupId>org.apache.plc4x</groupId>
- <artifactId>plc4j-scraper</artifactId>
- <version>{current-last-released-version}</version>
- </dependency>
-----
-
-In general, you need 3 parts to work with the `Scraper`:
-
-1) A `Scraper` Configuration
-2) A `Scraper` Implementation
-3) A Handler to handle the results of `Scraper` jobs
-
-In the `Scraper` Configuration you define the so-called `jobs`.
-
-=== Sources
-
-Sources define connections to PLCs using PLC4X drivers.
-
-Generally you can think of a `Source` as a PLC4X connection string, given an
alias name.
-
-=== Jobs
-
-A `Job` defines which resources (PLC Addresses) should be collected from which
`Sources` with a given `Trigger`.
-
-All resources in a job will be collected as a batch.
-
-Generally multiple types of triggers could theoretically be supported, but for
now only a time triggered job (Aka `SCHEDULED`) is actually supported.
-
-In the near future we're hoping that we will be able to support:
-- External triggers
-- Triggering collection based upon PLC-values
-
-But, as to now, this has not been implemented yet.
-
-== Configuration using the Java API
-
-The core of the Scraper configuration is the
`ScraperConfigurationTriggeredImplBuilder` class.
-Use this to build the configuration objects used to bootstrap the Scraper.
-
-----
-ScraperConfigurationTriggeredImplBuilder builder = new
ScraperConfigurationTriggeredImplBuilder();
-----
-
-As soon as you have your `builder` instance, you should add at least one
`source` to it.
-
-----
-builder.addSource({connectionName}, {plc4xConnectionString});
-----
-
-The `connectionName` will be what we use when configuring the job to reference
which source it should use to collect.
-
-In order to configure a `job` we have to get an instance of a
`JobConfigurationTriggeredImplBuilder`.
-
-----
-JobConfigurationTriggeredImplBuilder jobBuilder = builder.job({jobName},
{triggerCommand});
-----
-
-This creates a new `job` with a given name which is executed based on the
information in the `triggerCommand`.
-
-As mentioned above, we currently only support a time-scheduled collection.
-
-This generally requires just one parameter: The number of `milliseconds`
between each collection.
-
-----
-(SCHEDULED,1000)
-----
-
-Above would schedule a collection every 1000ms - so once every second.
-
-Up to now this job would not be run anywhere, and it would also not collect
anything.
-So in order to have the job actually do something, we should assign it a
`source` to collect from.
-
-----
-jobBuilder.source({connectionName});
-----
-
-Here we could theoretically collect on multiple sources, by simply calling the
`source()` method multiple times.
-
-All sources would be collected at the same time, whenever the trigger tells it
to.
-
-So the last thing we need to configure our first `Scraper` job, is to add a
few fields for it to collect.
-
-----
-jobBuilder.field({fieldName}, {fieldAddress});
-----
-
-The `field` method has to be called for every field we want to add to the
current job configuration.
-It gives a PLC4X address string an easy to understand string name, just like
when using the core PLC4X API.
-
-As soon as we're done adding fields, we configure the job by calling the
`build` method.
-
-----
-jobBuilder.build();
-----
-
-This configures the finished job and attaches that to the overall `Scraper`
configuration of the scraper configuration.
-
-As soon as we're done configuring jobs, we need to create the `Scraper`
configuration by calling the `build` method on the `builder`:
-
-----
-ScraperConfigurationTriggeredImpl scraperConfig = builder.build();
-----
-
-== Running the `Scraper`
-
-In order to run the `Scraper`, the following boilerplate code is needed.
-
-----
- try {
- PlcDriverManager plcDriverManager = new PooledPlcDriverManager();
- TriggerCollector triggerCollector = new
TriggerCollectorImpl(plcDriverManager);
- TriggeredScraperImpl scraper = new
TriggeredScraperImpl(scraperConfig, (jobName, sourceName, results) -> {
-
- ...
-
- }, triggerCollector);
- scraper.start();
- triggerCollector.start();
- } catch (ScraperException e) {
- log.error("Error starting the scraper", e);
- }
-----
-
-At first a new `PooledPlcDriverManager` is created (It actually doesn't have
to be the pooled version, but we strongly suggest you use it as for some
protocols the connection process is stressfull for the connected PLC).
-
-With this `plcDriverManager` we can then create a so-called
`TriggerCollector`, which we pass in the driver manager as argument.
-
-Next comes the probably most important part: We configure the scraper, by
binding a `Scraper Configuration`, a `ResultHandler` and a `TriggerCollector`
together.
-
-After this, the scraper is ready to start, which is then done by calling
`start` on the `scraper` as well as the `triggerCollector`.
-
-For the sake of clarity, here comes the definition of the `ResultHandler`
interface:
-
-----
-@FunctionalInterface
-public interface ResultHandler {
-
- /**
- * Callback handler.
- * @param jobName name of the job (from config)
- * @param connectionName alias of the connection (<b>not</b> connection
String)
- * @param results Results in the form alias to result value
- */
- void handle(String jobName, String connectionName, Map<String, Object>
results);
-
-}
-----
-
-== Configuration using a `JSON` or `YAML` file
-
-As an alternative to using the Java API, the Scraper Configuration can also be
read from a `JSON` or `YAML` document.
-
-Here come some examples:
-
-JSON:
-
-----
-{
- "sources": {
- "connectionName": "connectionString"
- },
- "jobs": [
- {
- "name": "jobName",
- "triggerConfig": (SCHEDULED,10000)
- "sources": [
- "connectionName"
- ],
- "fields": {
- "a": "{address-a}",
- "b": "{address-b}"
- }
- }
- ]
-}
-----
-
-YAML:
-
-----
----
-sources:
- connectionName: connectionString
-jobs:
- - name: jobName
- triggerConfig: (SCHEDULED,10000)
- sources:
- - connectionName
- fields:
- a: {address-a}
- b: {address-b}
-----
-
-In both cases, you can create the `ScraperConfiguration` with the following
code:
-
-----
-ScraperConfiguration conf = ScraperConfiguration.fromFile("{path to the JSON
or YAML file}", ScraperConfigurationTriggeredImpl.class);
-----
diff --git a/website/asciidoc/modules/users/pages/tools/testing.adoc
b/website/asciidoc/modules/users/pages/tools/testing.adoc
index 0ebcc685a1..364765b334 100644
--- a/website/asciidoc/modules/users/pages/tools/testing.adoc
+++ b/website/asciidoc/modules/users/pages/tools/testing.adoc
@@ -160,6 +160,5 @@ Some Examples of further (more Complex) use cases can be
found in the PLC4X Code
* `org.apache.plc4x.java.opm.PlcEntityManagerTest`
* `org.apache.plc4x.java.opm.PlcEntityManagerComplexTest`
-* `org.apache.plc4x.java.scraper.ScraperTest`
-and many more Test classes, especially in the OPM and the Scraper Module.
\ No newline at end of file
+and many more Test classes, especially in the OPM Module.
\ No newline at end of file
diff --git a/website/pom.xml b/website/pom.xml
index 87a54a4b07..3f3f0f7c09 100644
--- a/website/pom.xml
+++ b/website/pom.xml
@@ -312,6 +312,24 @@
</executions>
</plugin>
+ <!--
+ Makes the version of this project available as ${parsedVersion.*}
properties, so
+ the release version (without any "-SNAPSHOT" qualifier) can be derived
from it.
+ -->
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>parse-version</id>
+ <phase>validate</phase>
+ <goals>
+ <goal>parse-version</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
<!--
The bootstrap uses "fonts" as directory for locating fonts and
fontawesome uses "webfonts".
This plugin updates the css to also use "fonts".
@@ -321,6 +339,40 @@
<artifactId>replacer</artifactId>
<version>1.5.3</version>
<executions>
+ <!--
+ The documentation refers to the current version in a lot of places
(dependency
+ snippets, download instructions, ...) via the
"current-last-released-version" and
+ "current-full-version" AsciiDoc attributes. Both are defined in
the component
+ descriptor "asciidoc/antora.yml", and were easy to forget when the
version of the
+ project was bumped. This keeps them in sync with the version of
the Maven project.
+
+ They can't simply be passed to Antora on the command line: the
playbook builds the
+ released branches (rel/0.13, rel/0.12, ...) from git alongside
this one, and each of
+ those has to keep documenting its own version rather than the one
being built here.
+ So the value stays in the descriptor of each branch and this only
maintains the copy
+ on the branch it is run on.
+ -->
+ <execution>
+ <id>sync-antora-version</id>
+ <phase>validate</phase>
+ <goals>
+ <goal>replace</goal>
+ </goals>
+ <configuration>
+ <file>${project.basedir}/asciidoc/antora.yml</file>
+ <regex>true</regex>
+ <replacements>
+ <replacement>
+ <token>current-last-released-version: '[^']*'</token>
+ <value>current-last-released-version:
'${project.version}'</value>
+ </replacement>
+ <replacement>
+ <token>current-full-version: '[^']*'</token>
+ <value>current-full-version:
'${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}'</value>
+ </replacement>
+ </replacements>
+ </configuration>
+ </execution>
<execution>
<id>streamline-font-urls</id>
<!-- Only execute this for the parent module -->