Skip to content

3D Linked Data browser#287

Closed
namedgraph wants to merge 5 commits intodevelopfrom
ft-3d-linked-data-browser
Closed

3D Linked Data browser#287
namedgraph wants to merge 5 commits intodevelopfrom
ft-3d-linked-data-browser

Conversation

@namedgraph
Copy link
Copy Markdown
Member

No description provided.

namedgraph and others added 5 commits April 10, 2026 20:18
Integrates 3d-force-graph / Three.js as a new GraphMode view in the
container block. RDF/XML results are converted to nodes and links,
rendered in an interactive 3D canvas constrained to the .main.span7
column. Supports node click (info panel), double-click (load linked
resources via proxy), hover tooltip, and background click to dismiss.

- Add three.js, three-spritetext, 3d-force-graph UMD bundles (v0.159.0 / v1.8.2 / v1.73.3)
- Add 3d-force-graph.xsl: ForceGraph3D init template, RDF→graph data conversion, node/link mode templates
- Add graph3d.xsl: event handlers (click, dblclick, hover, background), UpdateForceGraph3D, HTTP response handler, tooltip/info panel rendering
- Add normalize-rdfxml.xsl, merge-rdfxml.xsl: RDF/XML normalization and merging pipeline
- Add bs2:Graph template, GraphMode canvas div, CSS rules for .graph-3d-canvas
- Wire graph3d.xsl into client.xsl; add $load-graph3d param to layout.xsl
- Remove obsolete graph.xsl

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- layout.xsl: server-side GraphMode outputs a .graph-3d-canvas placeholder
  div instead of the 2D SVG renderer; client initializes ForceGraph3D
- client.xsl: detect .graph-3d-canvas divs in ldh:rdf-document-response
  and call ldh:InitDocumentGraph3D (mirrors map/chart init pattern)
- graph3d.xsl: add ldh:InitDocumentGraph3D named template for document mode
- normalize-rdfxml.xsl: add 4th pass to prefix blank node IDs with a
  document-unique token, preventing ID collisions when merging multiple
  fetched RDF documents
- merge-rdfxml.xsl: include blank node descriptions from new documents in
  the merge; split rdf:Description match to [@Rdf:about] for property
  merging and [@Rdf:nodeID] for copy-as-is

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- NodeClick writes to info-content panel (dl/dt/dd) instead of tooltip
- Tooltip retained only for hover (position-aware)
- Zoom-to-fit button and filter checkboxes wired via data-canvas-id
- ldh:redisplay-graph reads per-canvas filter state; used by Init and Update
- canvas-id param added to all ldh:UpdateForceGraph3D call sites
- layout.xsl and view.xsl output info/filter/zoom UI inside canvas div

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ForceGraph3D clears the container element on init, wiping any server-rendered
child elements. Mirror the pattern from 3D-Linked-Data/graph-client.xsl:
server outputs only the bare canvas div; ldh:AppendGraph3DPanels appends
tooltip, info-panel, show-panel, and zoom button via ixsl:append-content
after FG3D has mounted. Called from both ldh:InitDocumentGraph3D and the
view.xsl initial-load block. Also replaced hardcoded convert-data call in
view.xsl with ldh:redisplay-graph so filter checkboxes take effect.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Panels need position:absolute to overlay the ForceGraph3D WebGL canvas
instead of stacking below it (which gets clipped by overflow:hidden).
Adds rules for tooltip, info-panel, show-panel, and zoom button.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@namedgraph namedgraph changed the base branch from master to develop April 10, 2026 20:44
@namedgraph namedgraph closed this Apr 10, 2026
namedgraph added a commit that referenced this pull request Apr 11, 2026
- Add 30 s connectionRequestTimeout to both HTTP client builders in
  Application so pool exhaustion fails fast instead of blocking forever
- Replace allMatch(HTMLMediaTypePredicate) with Request.selectVariant()
  in ProxyRequestFilter so real browser Accept headers (text/html,
  application/xml;q=0.9, */*;q=0.8) correctly trigger the early return,
  leaving (X)HTML responses to the downstream handler and Varnish cache
- In client.xsl ldh:rdf-document-response, detect external ?uri= URIs
  and replace-content on #content-body with bs2:Row rendering of the
  fetched RDF instead of iterating stale home-page blocks

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@namedgraph namedgraph deleted the ft-3d-linked-data-browser branch April 11, 2026 16:48
namedgraph added a commit that referenced this pull request Apr 11, 2026
- Add 30 s connectionRequestTimeout to both HTTP client builders in
  Application so pool exhaustion fails fast instead of blocking forever
- Replace allMatch(HTMLMediaTypePredicate) with Request.selectVariant()
  in ProxyRequestFilter so real browser Accept headers (text/html,
  application/xml;q=0.9, */*;q=0.8) correctly trigger the early return,
  leaving (X)HTML responses to the downstream handler and Varnish cache
- In client.xsl ldh:rdf-document-response, detect external ?uri= URIs
  and replace-content on #content-body with bs2:Row rendering of the
  fetched RDF instead of iterating stale home-page blocks

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
namedgraph added a commit that referenced this pull request Apr 11, 2026
- Add 30 s connectionRequestTimeout to both HTTP client builders in
  Application so pool exhaustion fails fast instead of blocking forever
- Replace allMatch(HTMLMediaTypePredicate) with Request.selectVariant()
  in ProxyRequestFilter so real browser Accept headers (text/html,
  application/xml;q=0.9, */*;q=0.8) correctly trigger the early return,
  leaving (X)HTML responses to the downstream handler and Varnish cache
- In client.xsl ldh:rdf-document-response, detect external ?uri= URIs
  and replace-content on #content-body with bs2:Row rendering of the
  fetched RDF instead of iterating stale home-page blocks

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
namedgraph added a commit that referenced this pull request Apr 12, 2026
- Add 30 s connectionRequestTimeout to both HTTP client builders in
  Application so pool exhaustion fails fast instead of blocking forever
- Replace allMatch(HTMLMediaTypePredicate) with Request.selectVariant()
  in ProxyRequestFilter so real browser Accept headers (text/html,
  application/xml;q=0.9, */*;q=0.8) correctly trigger the early return,
  leaving (X)HTML responses to the downstream handler and Varnish cache
- In client.xsl ldh:rdf-document-response, detect external ?uri= URIs
  and replace-content on #content-body with bs2:Row rendering of the
  fetched RDF instead of iterating stale home-page blocks

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
namedgraph added a commit that referenced this pull request Apr 12, 2026
- Add 30 s connectionRequestTimeout to both HTTP client builders in
  Application so pool exhaustion fails fast instead of blocking forever
- Replace allMatch(HTMLMediaTypePredicate) with Request.selectVariant()
  in ProxyRequestFilter so real browser Accept headers (text/html,
  application/xml;q=0.9, */*;q=0.8) correctly trigger the early return,
  leaving (X)HTML responses to the downstream handler and Varnish cache
- In client.xsl ldh:rdf-document-response, detect external ?uri= URIs
  and replace-content on #content-body with bs2:Row rendering of the
  fetched RDF instead of iterating stale home-page blocks

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
namedgraph added a commit that referenced this pull request Apr 13, 2026
* Fix connection pool exhaustion from ?uri= proxy requests (#287)

- Add 30 s connectionRequestTimeout to both HTTP client builders in
  Application so pool exhaustion fails fast instead of blocking forever
- Replace allMatch(HTMLMediaTypePredicate) with Request.selectVariant()
  in ProxyRequestFilter so real browser Accept headers (text/html,
  application/xml;q=0.9, */*;q=0.8) correctly trigger the early return,
  leaving (X)HTML responses to the downstream handler and Varnish cache
- In client.xsl ldh:rdf-document-response, detect external ?uri= URIs
  and replace-content on #content-body with bs2:Row rendering of the
  fetched RDF instead of iterating stale home-page blocks

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Server-side condition

* Server-side progress bar

* Fix external URI proxy bypass and client-side rendering

- ProxyRequestFilter: use Core-only MediaTypes (no HTML) with combined
  Model+ResultSet writable variant list; selectVariant==null is the sole
  bypass signal so Accept:*/* correctly reaches the proxy instead of
  falling through to the HTML handler
- Thread pre-computed Variant through all getResponse() overloads to
  avoid a second selectVariant call inside Core's Response constructor
- client.xsl onsubmit: skip the XHTML round-trip for external URIs and
  call PushState + RDFDocumentLoad directly, advancing the progress bar
  to 66% between the two steps; fixes the double-click issue
- client.xsl ldh:rdf-document-response: respect the #layout-modes mode
  selector for client-side rendered external resources; refactor the
  duplicate id('content-body') lookup out of both xsl:choose branches
- ProxyRequestFilterTest: stub Request.selectVariant() to return a
  non-null Variant so both tests reach the logic they exercise

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ProxyRequestFilter: document HTML bypass rationale; cache MediaTypes instance

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ProxyRequestFilter: clarify HTML bypass as resource exhaustion defence

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Make HTTP client connectionRequestTimeout configurable

Defaults to 30000 ms (via Dockerfile ENV). Passed through the
CATALINA_OPTS path (same as allowInternalUrls) to avoid exceeding
the ~30-param libxslt limit already reached by context.xsl.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix ProxyRequestFilter HTML bypass: check Accept header explicitly

Replace the selectVariant==null bypass with an explicit check for
non-wildcard text/html or application/xhtml+xml in the Accept header.
Browsers list these types explicitly (q=1.0) and get bypassed to the
app shell; API clients that send only */* reach the proxy.

The old approach (Core MediaTypes, selectVariant==null) failed for
browsers because their */*;q=0.8 wildcard matched RDF variants,
causing the proxy to return RDF instead of the (X)HTML app shell.

Add testHtmlAcceptBypassesProxy to cover the bypass path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix ContentMode block rendering for proxied external resources

Proxied resources' ContentMode blocks (charts, maps) were querying the
local SPARQL endpoint instead of the remote one because ProxyRequestFilter
discarded all external response headers and ResponseHeadersFilter then
injected the local sd:endpoint Link.

- ApplicationFilter: register external ?uri= target in request context
  (AC.uri property) as authoritative proxy marker
- ProxyRequestFilter: forward all Link headers from external response
- ResponseHeadersFilter: skip local sd:endpoint/ldt:ontology/ac:stylesheet
  for proxy requests; removes now-unused parseLinkHeaderValues/getLinksByRel
- client.xsl (ldh:rdf-document-response): extract sd:endpoint from Link
  header and store in LinkedDataHub.endpoint, mirroring acl:mode pattern
- functions.xsl (sd:endpoint()): return LinkedDataHub.endpoint when set,
  fall back to local /sparql — no changes needed in view.xsl or chart.xsl
- CLAUDE.md: document the proxy/client-side rendering architecture

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Replace proxy-detection heuristics with ac:uri() / $ac:uri throughout

- ApplicationFilter: store external URI as AC.uri context property; strip ?uri= from UriInfo
- ProxyRequestFilter: read proxy target from AC.uri context property; bypass HTML requests
- XsltExecutableFilter: remove SYSTEM_ID_PROPERTY; XSLTWriterBase reads AC.uri directly
- XSLTWriterBase: pass $ac:uri to server-side XSLT when proxying
- layout.xsl: declare $ac:uri param; use it for export links and search input pre-fill
- document.xsl: remove proxy spinner branch from bs2:ContentBody
- client/functions.xsl: add ac:uri() function (dynamic read of ixsl:query-params()?uri);
  ldh:base-uri() now calls ac:uri() instead of stale global $ac:uri
- client.xsl: drop global $ac:uri param; ldh:HTMLDocumentLoaded passes ldh:base-uri(.)
  to ldh:RDFDocumentLoad after pushState so URL is already updated
- ProxyRequestFilterTest: update mocks to use AC.uri context property

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add server-side ac:uri() function; refactor ActionBar templates into document.xsl

- Add ac:uri() server-side function to imports/default.xsl (mirrors acl:mode() pattern)
- Move ActionBarLeft/ActionBarMain/ActionBarRight/BreadCrumbBar/ModeList/MediaTypeList templates from layout.xsl to document.xsl
- Fix $effective-mode type error (xs:string → xs:anyURI) and simplify with [1] idiom
- Use ac:uri() instead of $ac:uri in MediaTypeList hrefs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant