5. Building Block View

Level 1: Modules

Architecture overview of the Wiki Publisher
Module Artifact Responsibility

Client

wiki-client

Typed access to the Confluence Cloud REST API. Generated from Atlassian’s OpenAPI v2 specification, plus one hand-maintained v1 API for attachment upload. Contains no documentation logic.

Publisher

wiki-publisher

The domain core: parses the local site into a page tree, resolves links, transforms content into Confluence Storage Format, and drives the Confluence calls. Usable standalone as a library.

Maven plugin

atlassian-maven-plugin

Adapter to the build. Maps plugin parameters onto a Configuration, resolves credentials from settings.xml, and runs the publisher. Contains no publishing logic.

Sample

architecture-docs

This documentation. Builds an Antora site and publishes it with the plugin — the end-to-end test of the whole chain.

The dependency direction is strictly one way: plugin → publisher → client. Nothing in the publisher references a Maven type, which is what keeps the library usable outside a build.

Level 2: Inside wiki-publisher

Class diagram of the Wiki Publisher

Publisher

The entry point and the only component that knows the overall workflow. It resolves the parser implementation, runs the two publishing phases (see 6. Runtime View), builds the link index across all mappers, and collects per-mapper failures.

Parser resolution deserves a note, because it is a place where flexibility and safety collide: the class named by Configuration.parserClass is loaded without running its static initializers and is only instantiated after it has been verified to implement Parser. A wrong class name therefore fails the build instead of executing unrelated code.

final var type = Class.forName(className, false, loader);   // no initialization
if (!Parser.class.isAssignableFrom(type)) {                 // check before instantiation
    throw new IllegalStateException(...);
}
final var parser = type.asSubclass(Parser.class).getDeclaredConstructor().newInstance();
parser.init(config);

Parser and AntoraParser

Parser is the seam towards the source format. Implementations need a public no-argument constructor and receive their configuration through init(Configuration).

AntoraParser is the built-in implementation. resolvePages reads the navigation panel of index.html and turns the data-depth attributes into a Page tree; loadContent extracts the article.doc element of a single page. Every href from the HTML passes through SafePaths before it becomes a file path — see 8. Cross-cutting Concepts.

LinkResolver

Holds one index over the page trees of all mappers, keyed by title and space key. resolve classifies an href into one of five kinds:

PAGE

A published Confluence page, possibly in another space (foreign).

ANCHOR

A position within the current page.

ATTACHMENT

A local file that has to be published as an attachment.

EXTERNAL

Points outside the documentation and is left untouched.

UNRESOLVED

Points into the documentation but cannot be mapped — reported, and the link text is kept without a link.

Transformer and ConfluenceTransformer

Converts an HTML fragment into Confluence Storage Format: rewrites links using the LinkResolver, converts admonition blocks into Confluence macros, maps images onto ri:attachment references, normalises code blocks, and collects the attachments a page needs.

ConfluenceClient

The only component that talks to Confluence. Beyond create/update it owns the two mechanisms that protect the target space:

  • Change detection through the page property page-content-hash, written after every successful update and read before the next one.

  • Orphan handling in syncPageStructure: everything below the root page that the current run did not touch is an orphan, reported always and trashed only when deleteOrphans is set.

Page, Attachment, Configuration

Plain data types. Page forms the tree via parent/children. Configuration carries the connection settings, the parser class name and the mappers — with username and password excluded from toString() so that a configuration dump cannot leak them.

Level 2: Inside wiki-client

Part Note

Generated v2 APIs

PageApi, SpaceApi, ContentPropertiesApi and the model classes, generated by openapi-generator into net.atlassian.wiki.rest.

ContentAttachmentsApi (v1)

The exception to the generated world. Needed because REST v2 cannot create attachments, and it requires multipart/form-data plus the XSRF header X-Atlassian-Token: nocheck.

Patched OpenAPI spec

The bundled specification is not upstream verbatim: in four likes/count responses the schema title Integer has to be renamed, otherwise the generator emits a model class that clashes with java.lang.Integer.

The patch to the OpenAPI specification must be re-applied whenever the spec is refreshed from Atlassian. It is documented in the wiki-client README — without it, the generated sources do not compile.