Skip to main content
phoss SMP is a Java web application that implements the Peppol SMP 1.x, OASIS BDXR SMP 1.0, and OASIS BDXR SMP 2.0 specifications. It is deployed as a WAR file on Tomcat 10.1 or Jetty 12 (Jakarta EE 10), and it exposes both a REST API (consumed by Peppol/BDXR clients) and a Bootstrap 4 management UI.

Three-layer module architecture

The project follows a layered architecture with a backend strategy pattern. Modules are split into three layers:
LayerModulesRole
Backend interfacesphoss-smp-backendCore domain interfaces, REST API logic, configuration, domain model
Backend implementationsphoss-smp-backend-xml, phoss-smp-backend-sql, phoss-smp-backend-mongodbStorage-specific persistence; each implements the interfaces defined in the core module
Web applicationphoss-smp-webapp, phoss-smp-webapp-xml, phoss-smp-webapp-sql, phoss-smp-webapp-mongodbServlets, REST filters, management UI pages; the webapp-* modules are the deployable WARs
Only the phoss-smp-webapp-* modules produce deployable WAR artifacts. Everything else is a library dependency.
phoss-smp-parent-pom
├── phoss-smp-backend          ← interfaces, REST logic, config
├── phoss-smp-backend-xml      ← XML file persistence
├── phoss-smp-backend-sql      ← JDBC + Flyway (MySQL/PostgreSQL/Oracle/DB2)
├── phoss-smp-backend-mongodb  ← MongoDB persistence
├── phoss-smp-webapp           ← servlets, UI, REST filters
├── phoss-smp-webapp-xml       ← deployable WAR (webapp + backend-xml)
├── phoss-smp-webapp-sql       ← deployable WAR (webapp + backend-sql)
└── phoss-smp-webapp-mongodb   ← deployable WAR (webapp + backend-mongodb)

Backend plugin system

Backends are registered and selected at runtime via the Java ServiceLoader SPI mechanism.

Registration

Each backend module provides two SPI implementations on the classpath:
  1. ISMPBackendRegistrarSPI — registers the backend under a string ID ("xml", "sql", or "mongodb") with SMPBackendRegistry.
  2. ISMPManagerProvider — a factory interface that vends all manager instances required by the application.
At startup, SMPMetaManager.initBackendFromConfiguration() reads the smp.backend property, looks up the matching ISMPManagerProvider in the registry, and passes it to SMPMetaManager.setManagerProvider() before the singleton initialises.
// Startup sequence (simplified from SMPMetaManager.java)
SMPBackendRegistry aBackendRegistry = SMPBackendRegistry.getInstance();
String sBackendID = SMPServerConfiguration.getBackend(); // e.g. "xml"
ISMPManagerProvider aManagerProvider = aBackendRegistry.getManagerProvider(sBackendID);
SMPMetaManager.setManagerProvider(aManagerProvider);
SMPMetaManager.getInstance(); // triggers full initialization

ISMPManagerProvider

ISMPManagerProvider is the central factory interface in phoss-smp-backend. Every backend must implement it. The methods it declares:
MethodReturnsNotes
createSMLInfoMgr()ISMLInfoManagerSML endpoint configuration
createSettingsMgr()ISMPSettingsManagerRuntime settings
createTransportProfileMgr()ISMPTransportProfileManagerSupported transport protocols
createServiceGroupMgr()ISMPServiceGroupManagerParticipant registry
createRedirectMgr(factory)ISMPRedirectManagerCross-SMP redirects
createServiceInformationMgr(factory)ISMPServiceInformationManagerDocument-type endpoint routing
createParticipantMigrationMgr()ISMPParticipantMigrationManagerPeppol participant migration
createBusinessCardMgr(factory, sgMgr)ISMPBusinessCardManager (nullable)Peppol Directory cards
getBackendConnectionEstablishedDefaultState()ETriStateXML returns TRUE; SQL returns UNDEFINED until DB is reachable
SMPMetaManager (a global singleton) holds the live instances and exposes static getters (getServiceGroupMgr(), getRedirectMgr(), etc.) used throughout the application.
To implement a custom backend, create a sub-project that provides both ISMPManagerProvider and ISMPBackendRegistrarSPI, following the pattern of phoss-smp-backend-xml. Then create a matching phoss-smp-webapp-* sub-project that bundles your backend with the core web layer.

Key domain concepts

ConceptDescription
ServiceGroupRepresents a participant, identified by a participant ID (e.g. iso6523-actorid-upis::0088:123456789). The top-level entity in the SMP data model.
ServiceMetadata / ServiceInformationPer-document-type routing information for a ServiceGroup. Describes which Access Point endpoints handle a given document type and process combination.
RedirectA pointer to a different SMP for a specific document type under a ServiceGroup. Used when a participant’s metadata is hosted on another SMP.
BusinessCardExtended participant information published to the Peppol Directory (name, address, contacts). Optional — only available when the ISMPBusinessCardManager is non-null.
TransportProfileA supported transport protocol identifier, e.g. peppol-transport-as4-v2_0. Used as a key inside ServiceInformation endpoints.
All manager interfaces for these entities live under com.helger.phoss.smp.domain.* in phoss-smp-backend. Backend-specific implementations live in their respective modules.

REST API dispatch flow

All incoming HTTP requests hit the SMPRestFilter (mapped to /*) first. The filter inspects the request path and method to decide which API handler to invoke:
HTTP request


SMPRestFilter  (/*)

    ├─► SMPServerAPI     — Peppol SMP 1.x
    ├─► BDXR1ServerAPI   — OASIS BDXR SMP 1.0
    └─► BDXR2ServerAPI   — OASIS BDXR SMP 2.0
The active API variant is controlled by smp.rest.type in application.properties (peppol or bdxr). All three API classes live in:
phoss-smp-backend/src/main/java/com/helger/phoss/smp/restapi/

REST endpoints

MethodPathAuth requiredDescription
GET/{ServiceGroupId}NoList document types for participant
PUT/{ServiceGroupId}YesCreate service group
DELETE/{ServiceGroupId}YesDelete service group
GET/{ServiceGroupId}/services/{DocumentTypeId}NoGet endpoints for document type
PUT/{ServiceGroupId}/services/{DocumentTypeId}YesCreate/update endpoint metadata
DELETE/{ServiceGroupId}/services/{DocumentTypeId}YesDelete endpoint metadata
GET/businesscard/{ServiceGroupId}NoGet business card
PUT/businesscard/{ServiceGroupId}YesCreate/update business card
DELETE/businesscard/{ServiceGroupId}YesDelete business card
GET/smp-status/NoHealth/status JSON (disabled by default)

Authentication

Authenticated endpoints accept two schemes:
  • Bearer token (preferred, v6.0.7+): Authorization: Bearer <token> — tokens are created under Administration > Security > User Tokens in the management UI.
  • Basic auth (legacy): Authorization: Basic Base64(email:password)
The Remote Query API (/smpquery/*) is disabled by default for security reasons. Enable it with smp.rest.remote.queryapi.disabled=false.

Web layer servlet mappings

The management UI is built on the ph-oton / Photon framework (server-side HTML generation, Bootstrap 4). It does not use a template engine — UI page classes extend AbstractSMPWebPageForm or AbstractSMPWebPageSimpleForm and generate HTML programmatically.
PathServlet / FilterPurpose
/*SMPRestFilterREST API dispatch (runs before all other mappings)
/secure/*SecureApplicationServletAuthenticated management UI
/public/*PublicApplicationServletPublic information pages
/smp-status/*SMPStatusServletHealth/status JSON endpoint
/ping/*PingPongServletLiveness probe
/logout/*SMPLogoutServletSession logout

Configuration system

Configuration is loaded from application.properties (inside the WAR) and optionally overridden by a file specified at startup:
# Override config file path at startup
java -Dconfig.file=/etc/phoss-smp/application.properties -jar ...
For local development, place overrides in private-application.properties next to application.properties — it is gitignored and takes precedence over the committed defaults. Key configuration groups:
GroupProperty prefixPurpose
Backend selectionsmp.backendChoose xml, sql, or mongodb
Identifier schemesmp.identifiertype, smp.rest.typePeppol or BDXR identifier/REST flavour
PKI / keystoresmp.keystore.*TLS and SML signing certificate
SQL connectionjdbc.*, target-databaseJDBC URL, credentials, Flyway target
Data directorywebapp.datapathRoot path for XML backend storage
Public URLsmp.publicurl, smp.publicurl.modeURL returned in SMP responses
SML integrationsml.enabled, sml.smpidRegistration with the SML
Directorysmp.directory.integration.*Peppol Directory auto-update
Securitycsp.enabled, webapp.security.*CSP headers, login error detail suppression
Service Group identifiers may contain encoded slashes (%2F). Tomcat 10+ requires encodedSolidusHandling="passthrough" (or "decode") on the HTTP Connector in server.xml. This is pre-configured in the official Docker images.

Technology stack

CategoryTechnology
RuntimeJava 17+, Jakarta EE 10
App serverTomcat 10.1.x or Jetty 12.x
BuildMaven 3.6+
Web/UI frameworkph-oton (Bootstrap 4, server-side HTML)
Peppol librariespeppol-commons, peppol-smp-client, peppol-sml-client
SQL persistenceApache Commons DBCP2 (pooling), Flyway 12 (migrations)
NoSQL persistenceMongoDB driver 5.6.3
LoggingLog4j 2 + SLF4J
LicenseMPL 2.0 + Apache 2.0

Build docs developers (and LLMs) love