Class WidgetsMixin
juneau-calendar.js, juneau-calendar.css), plus the
contract-version handshake constants those runtimes bake in.
Compose into a host resource via @Rest(mixins=WidgetsMixin.class); the asset URLs then become
available alongside the host's own endpoints.
These assets still need the view runtime beside them
The bytes live here, but they are not a standalone widget runtime: the calendar script
resolves its glyphs through the rich-view module's icon registry (juneau-icons.js) and pushes its
popovers onto the ONE shared layer stack that juneau-views.js publishes. A page that loads
this script must therefore also load the view module's juneau-icons.js and
juneau-views.js. "Widgets without views" is deliberately not a goal here; what this module owns is the
bean contracts and the bytes, not independence from views.
For backwards compatibility the rich-view mixin keeps deprecated accessors at the same paths it served these assets from before they moved, reading the bytes from this module's classpath. An existing application therefore keeps working unchanged; a new one composes this mixin.
Contract-version handshake:
Each *_CONTRACT_VERSION constant is the handshake stamp the matching runtime bakes in.
CALENDAR_CONTRACT_VERSION aliases CalendarDef.CONTRACT_VERSION;
BAR_CONTRACT_VERSION aliases BarSlot.CONTRACT_VERSION;
HEADER_CONTRACT_VERSION is a literal (the header bean is gone). The three are deliberately distinct from one another: a calendar-envelope
revision must never force a header or bar-sidecar bump, or vice-versa.
Cache-busting + versioned URLs:
widgetAssetUrl(String) carries the same ?v=<buildVersion>-<hash8> content-sensitive cache-buster
shape the views mixin uses: an 8-hex-char content hash of the asset's own served bytes, computed once and cached.
Keying the buster off content rather than the version string alone matters for -SNAPSHOT builds, whose
version is stable across dev rebuilds. The hashing itself is the shared
ChecksumUtils.hash8(byte[]) function reached through
ClasspathAssetCache; this module holds its own cache instance anchored on this class, so its
buildVersion resolves this module's implementation version rather than a neighbouring module's. The two
modules share the hash function, not a cache.
The serving-path Widget.validate() gate
This class also nests WidgetsMixin.WidgetValidationProcessor, a ResponseProcessor that calls
Widget.validate() on any REST response content that is a Widget, fail-closed, ahead of every
byte-writing processor. It is registered two ways — both belt-and-braces, not redundant duplicates, since
ResponseProcessorList de-duplicates by class:
- Via
ServiceLoader(META-INF/services/org.apache.juneau.rest.server.processor.ResponseProcessor), so it applies to every resource on a classpath that carries this module, with no consumer opt-in. - Via this class's own
@Rest(responseProcessors=...)+mergeResponseProcessorsIntoHost=true, so a host that composes this mixin is covered even if its classpath loses the services file (a shading/repackaging step, for example).
Widgets_ModuleBoundary_Test.b01_onlyTheMixinReferencesTheRestServingFramework allowlists exactly this file
as the module's single exception to "the beans stay independent of the REST serving framework"; a response
processor is itself a serving-framework type, so nesting it here keeps that rule literally true rather than
requiring an amendment.
See Also:
- Since:
- 10.0.0
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic classThe serving-pathWidget.validate()gate: fail-closed structural validation for any REST response content that is aWidget, giving the JSON serving path the same gate thejuneau-console-viewsHTML emitters already give everyWidgetthey consume. -
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final StringThe bar-slot refresh-envelope contract-version handshake constant that the console shell bakes in, aliased from the value the bar model emits (BarSlot.CONTRACT_VERSION).static final StringThe per-month calendar-event envelope contract-version handshake constant that the calendar runtime bakes in, aliased from the value the calendar model emits (CalendarDef.CONTRACT_VERSION).static final StringThe URL path at which the reusable-calendar stylesheet is served (relative to the host mount).static final StringThe URL path at which the reusable-calendar runtime is served (relative to the host mount).static final StringThe app-header refresh-envelope contract-version handshake constant that the console shell bakes in. -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescription[GET /juneau-calendar.js] — serve the reusable-calendar runtime.[GET /juneau-calendar.css] — serve the reusable-calendar stylesheet.static StringwidgetAssetUrl(String path) Returns the servlet-relative URL for a widget asset served by this mixin, carrying a?v=<buildVersion>-<hash8>content-sensitive cache-buster suitable for a page'shead=block.static StringwidgetAssetUrl(RestRequest req, String path) Returns a real, browser-fetchable absolute URL for a widget asset served by this mixin, resolved against the given request's context path and mount — carrying the same cache-buster aswidgetAssetUrl(String).
-
Field Details
-
CALENDAR_JS_PATH
The URL path at which the reusable-calendar runtime is served (relative to the host mount).Load order is a contract, not a preference:
This
<script>MUST come after the view module'sjuneau-views.js. The calendar's"+N more"popover is pushed onto the ONE shared layer stack that script publishes, so Escape, focus return and z-order match every other layer in the page. The calendar deliberately defines no second stack of its own: if the shared one is absent it fails loud rather than opening a popover nothing can dismiss.- See Also:
-
CALENDAR_CSS_PATH
The URL path at which the reusable-calendar stylesheet is served (relative to the host mount).- See Also:
-
CALENDAR_CONTRACT_VERSION
The per-month calendar-event envelope contract-version handshake constant that the calendar runtime bakes in, aliased from the value the calendar model emits (CalendarDef.CONTRACT_VERSION).- See Also:
-
HEADER_CONTRACT_VERSION
The app-header refresh-envelope contract-version handshake constant that the console shell bakes in.- See Also:
-
BAR_CONTRACT_VERSION
The bar-slot refresh-envelope contract-version handshake constant that the console shell bakes in, aliased from the value the bar model emits (BarSlot.CONTRACT_VERSION).- See Also:
-
-
Constructor Details
-
WidgetsMixin
public WidgetsMixin()
-
-
Method Details
-
getCalendarScript
[GET /juneau-calendar.js] — serve the reusable-calendar runtime.- Returns:
- The calendar runtime as a JavaScript
HttpResource.
-
getCalendarStylesheet
[GET /juneau-calendar.css] — serve the reusable-calendar stylesheet.- Returns:
- The calendar stylesheet as a CSS
HttpResource.
-
widgetAssetUrl
Returns the servlet-relative URL for a widget asset served by this mixin, carrying a?v=<buildVersion>-<hash8>content-sensitive cache-buster suitable for a page'shead=block.- Parameters:
path- One of the asset path constants (CALENDAR_JS_PATH,CALENDAR_CSS_PATH).- Returns:
- The servlet-relative asset URL with the version+content-hash cache-buster appended.
- Throws:
IllegalArgumentException- If this mixin does not ship the bytes for the given path.
-
widgetAssetUrl
Returns a real, browser-fetchable absolute URL for a widget asset served by this mixin, resolved against the given request's context path and mount — carrying the same cache-buster aswidgetAssetUrl(String).widgetAssetUrl(String)returns aservlet:-prefixed URL that only Juneau's own HTML serializer resolves. A template-rendering consumer sits downstream of that serializer, so it never sees the rewrite and would otherwise receive the literal, unfetchable string. This overload resolves the URL itself, per-request.The path is validated before the request is touched, so an unserved path is rejected identically with or without a live request.
- Parameters:
req- The current request, supplying the context path/mount to resolve against.path- One of the asset path constants (CALENDAR_JS_PATH,CALENDAR_CSS_PATH).- Returns:
- The absolute asset URL with the version+content-hash cache-buster appended.
- Throws:
IllegalArgumentException- If this mixin does not ship the bytes for the given path.
-