Files

Echo — scan a barcode and print a copy

Echo is an optional QQQ example application, using the shared Android scanner host. Choose a currently authorized printer and its supported paper/label profile once, then scan repeatedly. Each scan preserves its string value and actual symbology and uses the existing Document Generation → retained original → native Printing path. One event is admitted per run at a time. A successful acknowledgment means queued, not confirmed physical paper.

The source implements ordinary QQQ metadata and processes; no Echo-specific Android screen, business endpoint, barcode encoder or print queue is added. There is deliberately no fabricated printer, hardcoded stock, administrative-permission shortcut or in-process renderer fallback.

At a glance

  • Flow. Choose a printer, its paper/label size and a published Document once; then every scan renders the same value and symbology and prints one job, until you leave. Copies per scan is optional (default 1, range 1–100) and fixed for the run.
  • Where it runs. The maintained local server composes Echo with Collaboration/Record Files, Document Generation and Printing on public QQQ 4.1.0-RC.21 and released Printing 1.0.0 (UI API 1.10, mobile-scanners 1.5, printing 2.3). Start it with the runnable demo; local demo explains how it differs from the basic Scan Capture demo.
  • Verified. In the current 198-test cohort Echo has 68 tests and the composed demo 35, with Checkstyle clean (session state). The automated composed acceptance (an approved scanner, two scans, two retained originals, two accepted jobs, an idempotent retry, leaving) uses a controlled synthetic renderer and a simulated Printing queue.
  • Rendering evidence. The real renderer's Code128 and leading-zero QR outputs pass independent pixel decoding and stock/fit checks (evidence and test images). A separate synthetic HTTP event reached a real printer spooler (delivery receipt).
  • Physical acceptance. The TC22 trigger, paper output and rescan checks were reported by the operator as passing on November 4, as a group report without per-case artifacts. A queue acknowledgment still means queued, not confirmed paper.
  • Not claimed. Production readiness, signed distribution, public Maven coordinates for the document owner's qbits, or universal barcode fidelity (limits).

Host composition

  1. Install/configure the existing Mobile Scanners, Document Generation and retained-source Printing integration under their owner-qualified dependency tuple. Use the same backend/data source for Echo metadata and its state schema. Apply echo-h2.sql through host migrations; registration performs no DDL.
  2. Configure Document Generation to allow echoScan as a source table. Publish appropriate immutable barcode templates through its ordinary definition service and isolated worker. Stock measurements are micrometres with explicit DPI. Do not generate or publish a new template on every scan.
  3. EchoPrintingDestinations implements the destination seam from Printing's public operator authorization (PrintingOperatorAuthorization) and reported media profiles. authorize checks the current actor, printer row, device and ZPL format and pins the exact reported media profile id and revision. plan reauthorizes, then reads the published template revision with enforced permissions and requires its stock to equal that media. The setup step's printer field uses Printing's own table possible values (enabled and available printers); EchoMediaChoices is a semantic possible-value provider that returns only the sizes of the printer already selected. App-selected document dimensions do not imply changing Windows printer stock.
  4. EchoDocumentGenerator calls Generation's public generate and read-only lookupAcceptedPrint with the exact template, revision, stock and selected media profile, under the stable key echo:<scanId>. QUEUED is returned only for a durable, available retained receipt with a job id and the same media profile. Absent or unavailable lookup evidence refuses. It never uses the side-effecting reconcile call or plain byte submission.
  5. EchoHost.install(instance, deployment) composes the above from the owners' public classes: Record Files retained output and print source, PrintingDispatch.forOwnerMediaEnforcement(source) (the owner's explicit adoption factory), Generation with its durable audit, then Echo. Registration order matters: Printing, then Echo's echoScan table, then Generation, which validates its source tables. The isolated renderer, PrintingService and template map are deployment inputs; absent ones are refused. Grant the operator echo.use, ordinary mobile scanning and the owner-approved generation and print-submit permissions. Do not grant printing_admin to make Echo work. EchoTemplatePublisher.publish is the one-time operator action that publishes the ZPL barcode template for one reported media profile.

Supply the renderer's configured byte limit as Deployment.maximumOutputBytes. Both demo launchers propagate ECHO_RENDERER_MAXIMUM_BYTES to Generation and the renderer. Leaving Generation at its 20 MiB owner default with a 1 MiB renderer rejects every render request before the worker starts. The composed acceptance uses a bounded renderer and a nondefault 256 KiB cap. Existing six-argument Deployment callers retain the owner default and must only use it with a renderer that accepts that allowance.

The process begins with server-owned run state, shows printer/media setup, then loops only between the semantic SCANNER frontend and the print backend. Its native Cancel step closes the run, including cancellation during setup. Already processing or accepted work may still print; leaving prevents new admission and retains receipts. Protected framework process identity, rather than an echoed run ID alone, binds the selected printer to that process.

Copies per scan

Setup asks Copies per scan: an optional ordinary integer form field, default 1, registered with core ValueRangeBehavior limits of 1 and 100 (inclusive, error) so the native client's validation.minValue/maxValue match the server. Omitted, null or blank means 1; fractions, 0, 101 and non-numbers are rejected at setup. The server validates it, pins it on the run (echo_run.copies, a non-null additive column that defaults existing runs to 1) and uses that pinned count for every scan until Leave. A repeated setup can confirm but not change it, and a differing scan-stage copies value is refused before any event row exists; the value never decides what is printed. The scanner instructions state the count when it is above one. Bounds are Printing's own: a whole number from 1 to 100, expressed by that owner as the copies option of one print job, so Echo never queues one job per copy or renders per copy, and retries and lookup reuse the same pinned count.

EchoDocumentGenerator builds DocumentGenerationService.Request(..., mediaProfile, copies) with the run's pinned count, so Generation binds it to the echo:<scanId> key and its printing bridge submits one job with options.copies; the accepted-print lookup compares the committed count with the pinned one before Echo adopts a job. This needs the Generation copies cohort (GenerationPorts.PrintRequest/Request with the appended copies, the request-table copies migration 20261102-print-copies-h2.sql, and a Printing owner that honors options.copies); an owner without supportsCopies() refuses a count above 1 before any row, render or submit. Physical copy counts are not verified.

Fidelity and limits

Input Behavior
CODE128, QRCODE, CODE39, Data Matrix, PDF417, Aztec (printable ASCII) Admitted on the plain document.
EAN13, EAN8, UPCA, UPCE0 Admitted only with the scanner's AIM identifier, an exact-length value with a valid check digit (UPC-E number system 0 only) and a document published with publishScannerFidelity; otherwise refused before any print.
GS1-128 (]C1) Bounded profile below; requires matching raw-byte evidence and a separate GS1 document with printed HRI.
Other GS1, ECI and structured-append modes (for example ]Q3, ]A4) Refused; no qualified profile.
Control, binary or non-ASCII payloads Refused.
UNKNOWN symbology or manual entry Refused. No symbology is inferred from the value or substituted with QR/Code128.
Raw bytes (rawDataBase64, mobile-scanners 1.5) Must decode to exactly the ASCII bytes of the displayed value, else refused. Required for GS1-128; absent evidence remains admitted for legacy plain profiles and proves nothing.

Independent decoding (ZXing on the rendered raster) is recorded only for Code128 QQQ-TEST-123456 and QR 001234567890 on 4 x 1 in stock at 300 dpi. Hardware AIM output and physical copy counts are covered by the operator's accepted group report (not reopened), but have no separate instrumented evidence; no exact-AIM or all-symbology claim is made.

The first explicit mapping covers CODE128, QRCODE, CODE39, Data Matrix, PDF417 and Aztec scanner identifiers and their documented legacy label aliases. Leading zeros are never parsed as numbers. EAN13/EAN8/UPCA/UPCE0 are admitted only with the scanner's AIM identifier (]E0, EAN-8 ]E4), a full-length value of the exact length with a valid GS1 check digit (UPC-E number system 0 only), and a document published with EchoTemplatePublisher.publishScannerFidelity. That separate, clearly named scanner-fidelity document passes the recorded scanner label and AIM identifier (echoScan.symbology, new nullable echoScan.aimIdentifier) to the renderer's scanner mode, which verifies them again and converts the value. It requires an AIM identifier on every scan, so the original plain document stays the choice for older scanners and servers; an EAN/UPC scan on a plain document, or a scan without AIM on a scanner-fidelity document, is refused before any print and the operator leaves Echo to choose the other document. The AIM column is an additive, nullable migration in echo-h2.sql (other databases need the equivalent); a retry is bound to the stored AIM. UNKNOWN, manual input, unsupported variants and control/binary payloads outside the GS1-128 profile below are refused until their exact metadata/encoder profile is qualified. When the canonical scan context carries the optional mobile-scanners 1.5 evidence, Echo checks it before admission: outside the GS1-128 profile, an aimIdentifier other than the renderer's plain-mode identifier for that type (for example ]Q3, ]A4) is refused as a GS1/ECI/structured mode, and rawDataBase64 must decode to exactly the ASCII bytes of the display value. Absent evidence (legacy 1.4 servers, older clients, or a Zebra read where the host did not confirm its AIM output profile by configuration read-back) is admitted as before and proves nothing, and physical AIM output on the handheld is not yet qualified; no fidelity is inferred from the display string. No symbology is inferred from value or substituted with QR/Code128.

Each canonical mobile scan has one durable echoScan source with the same ID and a stable echo:<scanId> generation request key across every run. A duplicate accepted event in the same run returns its existing job; moving that event into another run is rejected. A deliberate new trigger event with the same value is a new print intent. A changed value/type/source/timestamp cannot reuse the event. An uncertain/crashed call never automatically renders or prints again: recovery requires read-only exact owner acceptance evidence; absent/unavailable evidence remains visibly unconfirmed and the user may leave. Independent decoding and physical scanner/printer acceptance remain mandatory for any claimed barcode profile.

Build and acceptance

From the repository root, use Java 21 and the included wrapper:

./mvnw -f examples/echo/pom.xml verify

On Windows, run mvnw.cmd -f examples/echo/pom.xml verify from the repository root. From examples/echo, use ../../mvnw -f pom.xml verify (Windows: ..\..\mvnw.cmd -f pom.xml verify). Both forms use the checked-in wrapper; Checkstyle and resource paths resolve from the module directory.

This optional module is outside the root lifecycle. The POM's defaults are qqq.version 4.1.0-RC.21 (public), printing.version 1.0.0 (released Printing, qualified with public RC.21), and mobile.version and generation.version 0.1.0-SNAPSHOT. The other owner qbits (Generation and bridges, Collaboration, Record Files, Scripting) are still qualified owner inputs, not a public or released dependency cohort, so their snapshot defaults alone may not resolve or match what was verified. Copies per scan also needs the Generation copies change described above. Use a dedicated Maven repository and one coherent owner cohort; never install cross-chat snapshots over the shared cache. When the owner publishes public versions, adopt them in a reviewed dependency change; until then do not guess coordinates. The source requires the narrow protected-process-identity API and the current MobileScannerActions.capture(input, appName) API. The primary forge is Gitea; GitHub is a shadow/archive.

Tests: core and HTTP-fixture tests (real QQQ process state, H2 persistence and the mobile QBit's approval and binding, with synthetic destination, layout and queue fixtures) and adapter tests (controlled owner facades for exact pins, receipts, lookup, media filtering, the published scene geometry and the absent-deployment refusals). They qualify orchestration, event identity, permission boundaries and adapter mapping, not render output or physical printing. The adapter tests do not run the renderer worker.

Runnable demo

demo/ is a separate optional module that composes the real owners into a startable server (tested, Checkstyle clean). Its production EchoDemo keeps the owner's cold bridge, which defaults to the runsc Docker runtime and fails closed on Windows Docker Desktop (runc). TrustedLocalEchoDemo is the explicit developer launcher over the renderer owner's public trusted-local factory (the demo copies no transport) and is not a production sandbox qualification. Operator prerequisites, from its README: a Printing tenant and administration token, a Windows printing agent that reports printer media, an approved scanner enrolled through the mobile flow, published Echo-compatible ZPL templates for the reported media (chosen by the operator during process setup), and Record Files' generated-file release switch. The demo README's first section says which launcher to use; the basic Scan Capture demo is a different, smaller server (local demo).

Release limits

Echo is an example, not a released product. Source and development publication are done on Gitea (scanner develop snapshot from run 3645; Android main 0ae2101, run 3634). Still open: public Generation/bridges/Record Files/Scripting artifacts from their owner, signed-build HTTPS device qualification and distribution (the signed Android APK and channel already exist locally), and any barcode profile beyond the limits above. Earlier GitHub references are historical.

License packaging

Echo uses Apache License 2.0. Packaging includes the existing repository LICENSE and NOTICE unchanged under META-INF/qqq-echo/, alongside Echo's SQL resources. This namespace preserves dependency notices. No duplicate license source files or modified license text are maintained in the example.

Isolated native UI fixture

com.kingsrook.examples.echo.fixture.EchoHttpFixture is a test-scope HTTP host using the existing demo TABLE authentication and registered QQQ semantic routes. It brands itself Echo UI E2E — simulated printing. The simulated printer/media and acceptance recorder exercise navigation and receipts only; they never render or print.

Launch its test classpath with one unused loopback port argument and private environment variables ECHO_FIXTURE_TYPE=echo-ui-e2e, ECHO_FIXTURE_SCANNER_PASSWORD, and ECHO_FIXTURE_ADMIN_PASSWORD. Use generated secrets of at least 24 characters. Accounts are scanner and admin. The process initializes a fresh random in-memory H2 database, refuses known production/test-peer ports, and emits ECHO_UI_E2E_READY port=<port> simulatedPrinting=true. Closing it stops only its own server. Keep its credentials in private run descriptors, never this repository.

The printer/media choices are fixture-printer / fixture-4x6, labeled “Simulated printer” / “Simulated 4 x 6 in — 300 dpi”. Standard native queries of echoScan and test-only echoFixtureRun use the scanner session and approved device credentials, retaining actor locks. The HTTP smoke covers login, real enrollment/admin approval, metadata, setup, two symbologies, same-event retry, queued receipts, row inspection and cancellation. Android device acceptance remains a separate test; none of these fixture results qualify physical output.

Retained Echo source reads use a separate read-only permission: the current authenticated actor must still have echo.use, and native actor row locks restrict results to that actor. Desktop source reads after leaving Echo do not reconstruct a scanner session or grant capture authority. Echo app/process/widget/capture operations still require the currently approved device. Direct source-table writes are denied. Accepted print delivery/retry also requires the printing owner's reviewed original-actor source-reauthorization policy; this table read rule alone does not qualify delayed byte release.

GS1-128 duplication profile

Choose a separate document created with EchoTemplatePublisher.publishGs1; existing plain documents cannot print GS1 scans. This profile requires AIM ]C1, a supported Code128/GS1 scanner label, and raw bytes matching the original payload (optionally including its AIM prefix). It preserves the original scan and derives rendererValue and humanReadable in additive nullable columns. Apply the H2 additions in echo-h2.sql before use; other database owners must supply equivalent migrations.

Supported AIs: fixed-length 00, 01, 02, 11, 12, 13, 15, 16, 17, 20; variable-length 10, 21, 30, 37. ASCII group separators terminate variable fields; boundaries are never guessed. The bounded profile admits at most 48 payload characters and refuses unknown AIs and unsupported controls. Example: 01095011015300031120101421TEST000123 prints (01)09501101530003(11)201014(21)TEST000123 below a GS1-128 barcode. The renderer checks the canonical data independently.

Two synthetic 4-by-1-inch, 300-dpi outputs passed independent decoding with exact GS1 data, matching HRI and non-overlapping geometry. Native acceptance is in progress; physical print/rescan and suitability for the operator's actual media remain unverified.