Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/main/java/life/qbic/compass/SignPostingProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import java.util.List;
import java.util.Objects;
import life.qbic.compass.model.SignPostingView;
import life.qbic.compass.spi.SignPostingResult;
import life.qbic.compass.model.SignPostingResult;
import life.qbic.compass.spi.SignPostingValidator;
import life.qbic.compass.validation.Level1SignPostingValidator;
import life.qbic.linksmith.model.WebLink;
Expand Down Expand Up @@ -70,7 +70,7 @@ public SignPostingResult process(List<WebLink> webLinks) throws NullPointerExcep
.flatMap(report -> report.issues().stream())
.toList();

return new SignPostingResult(new SignPostingView(webLinks), new IssueReport(recordedIssues));
return new SignPostingResult(new SignPostingView(webLinks), new IssueReport(recordedIssues), null);
}

public static final class Builder {
Expand Down
40 changes: 40 additions & 0 deletions src/main/java/life/qbic/compass/model/ContentResourceView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package life.qbic.compass.model;

import java.net.URI;
import java.util.List;
import life.qbic.linksmith.model.WebLink;

/**
* Represents a validated FAIR Signposting <strong>content resource</strong>
* context (Level&nbsp;2).
*
* <p>
* A content resource typically represents the actual data or files
* associated with a scholarly object and is usually linked from a landing
* page using {@code rel=item}.
* </p>
*
* <p>
* Content resources commonly link back to their landing page using
* {@code rel=collection}.
* </p>
*
* <p>
* All WebLinks in this view share the same {@link #origin()} and were
* validated according to the Level&nbsp;2 content resource recipe.
* </p>
*
* @param origin
* the content resource origin URI
* @param webLinks
* all WebLinks belonging to this content resource context
*
* @since 1.0.0
*/
public record ContentResourceView(URI origin, List<WebLink> webLinks) implements SameOriginView {

@Override
public SignPostingView signPostingView() {
return null;
}
}
40 changes: 40 additions & 0 deletions src/main/java/life/qbic/compass/model/LandingPageView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package life.qbic.compass.model;

import java.net.URI;
import java.util.List;
import life.qbic.linksmith.model.WebLink;

/**
* Represents a validated FAIR Signposting <strong>landing page</strong>
* resource context (Level&nbsp;2).
*
* <p>
* A landing page is the primary entry point for a scholarly object and
* typically provides:
* </p>
*
* <ul>
* <li>a persistent identifier ({@code rel=cite-as}),</li>
* <li>links to one or more content resources ({@code rel=item}), and</li>
* <li>links to descriptive metadata ({@code rel=describedby}).</li>
* </ul>
*
* <p>
* All WebLinks in this view share the same {@link #origin()} and were
* classified as a landing page recipe during Level&nbsp;2 validation.
* </p>
*
* @param origin
* the landing page origin URI
* @param webLinks
* all WebLinks belonging to this landing page context
*
* @since 1.0.0
*/
public record LandingPageView(URI origin, List<WebLink> webLinks) implements SameOriginView {

@Override
public SignPostingView signPostingView() {
return null;
}
}
91 changes: 91 additions & 0 deletions src/main/java/life/qbic/compass/model/Level2LinksetView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package life.qbic.compass.model;

import static java.util.Objects.requireNonNull;

import java.util.List;

/**
* A structured, domain-oriented view over a validated FAIR Signposting
* <strong>Level&nbsp;2 Link Set</strong>.
*
* <p>
* A {@code Level2LinksetView} represents the result of interpreting a collection
* of {@link life.qbic.linksmith.model.WebLink WebLinks} according to the
* Level&nbsp;2 FAIR Signposting recipes.
* It groups validated links into <em>origin-scoped resource views</em>,
* where each origin corresponds to a single resource context as defined by
* the {@code anchor} parameter in RFC&nbsp;8288 / RFC&nbsp;9264.
* </p>
*
* <h2>Contained views</h2>
*
* <ul>
* <li>{@link LandingPageView} – origins classified as landing pages</li>
* <li>{@link ContentResourceView} – origins classified as content resources</li>
* <li>{@link MetadataResourceView} – origins classified as metadata resources</li>
* </ul>
*
* <p>
* Each view contains all WebLinks that share the same origin and were
* successfully associated with a concrete Level&nbsp;2 recipe.
* </p>
*
* <h2>Missing origins</h2>
*
* <p>
* WebLinks that lack an {@code anchor} parameter cannot be assigned to a
* Level&nbsp;2 recipe context.
* Such links are reported separately via {@link MissingOriginLink} entries
* and are <em>not</em> included in any recipe view.
* </p>
*
* <h2>Validation relationship</h2>
*
* <p>
* This view is a <strong>derived interpretation</strong> of validated input:
* </p>
*
* <ul>
* <li>Its presence implies that Level&nbsp;2 validation was attempted.</li>
* <li>Its contents reflect the outcome of heuristic recipe detection
* and subsequent recipe-specific validation.</li>
* <li>It does <em>not</em> replace {@link SignPostingView}, which always
* represents the full, unfiltered set of parsed WebLinks.</li>
* </ul>
*
* <p>
* Clients are expected to inspect {@link SignPostingResult#issueReport()}
* alongside this view to assess completeness and correctness.
* </p>
*
* <h2>Immutability</h2>
*
* <p>
* All collections exposed by this record are immutable defensive copies.
* </p>
*
* @param landingPages
* validated landing page origins
* @param contentResources
* validated content resource origins
* @param metadataResources
* validated metadata resource origins
* @param missingOriginLinks
* links that could not be assigned to any origin due to missing {@code anchor}
*
* @since 1.0.0
*/
public record Level2LinksetView(
List<LandingPageView> landingPages,
List<ContentResourceView> contentResources,
List<MetadataResourceView> metadataResources,
List<MissingOriginLink> missingOriginLinks
) {

public Level2LinksetView {
landingPages = List.copyOf(requireNonNull(landingPages));
contentResources = List.copyOf(requireNonNull(contentResources));
metadataResources = List.copyOf(requireNonNull(metadataResources));
missingOriginLinks = List.copyOf(requireNonNull(missingOriginLinks));
}
}
35 changes: 35 additions & 0 deletions src/main/java/life/qbic/compass/model/MetadataResourceView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package life.qbic.compass.model;

import java.net.URI;
import java.util.List;
import life.qbic.linksmith.model.WebLink;

/**
* Represents a validated FAIR Signposting <strong>metadata resource</strong>
* context (Level&nbsp;2).
*
* <p>
* A metadata resource provides structured descriptive information
* about a scholarly object and typically links to the resource it
* describes using {@code rel=describes}.
* </p>
*
* <p>
* All WebLinks in this view share the same {@link #origin()} and were
* validated according to the Level&nbsp;2 metadata resource recipe.
* </p>
*
* @param origin
* the metadata resource origin URI
* @param webLinks
* all WebLinks belonging to this metadata resource context
*
* @since 1.0.0
*/
public record MetadataResourceView(URI origin, List<WebLink> webLinks) implements SameOriginView {

@Override
public SignPostingView signPostingView() {
return null;
}
}
12 changes: 12 additions & 0 deletions src/main/java/life/qbic/compass/model/MissingOriginLink.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package life.qbic.compass.model;

import life.qbic.linksmith.model.WebLink;

/**
* <class short description>
*
* @since <version tag>
*/
public record MissingOriginLink(int index, WebLink webLink) {

}
54 changes: 54 additions & 0 deletions src/main/java/life/qbic/compass/model/SameOriginView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package life.qbic.compass.model;

import java.net.URI;

/**
* Common abstraction for Level&nbsp;2 FAIR Signposting views that represent
* a single <em>origin-scoped resource context</em>.
*
* <p>
* In FAIR Signposting Level&nbsp;2, links are grouped by their
* <strong>origin</strong>, which is expressed using the {@code anchor}
* parameter on RFC&nbsp;8288 Web Links.
* A {@code SameOriginView} guarantees that all contained WebLinks share
* the same origin.
* </p>
*
* <h2>Domain contract</h2>
*
* <ul>
* <li>{@link #origin()} must be non-null.</li>
* <li>All WebLinks represented by {@link #signPostingView()} must have
* an {@code anchor} value equal to {@link #origin()}.</li>
* <li>Implementations are immutable and read-only.</li>
* </ul>
*
* <p>
* This interface enables clients to treat landing pages, content resources,
* and metadata resources uniformly when iterating over Level&nbsp;2 results,
* while still allowing recipe-specific APIs on concrete view types.
* </p>
*
* @since 1.0.0
*/
public sealed interface SameOriginView permits LandingPageView, MetadataResourceView, ContentResourceView {

/**
* Returns the origin URI that defines the resource context for this view.
*
* @return the common origin of all contained WebLinks
*/
URI origin();

/**
* Returns a {@link SignPostingView} over all WebLinks belonging to this origin.
*
* <p>
* The returned view is a semantic convenience wrapper and does not imply
* additional validation beyond what has already been performed.
* </p>
*
* @return a non-null {@link SignPostingView} for this origin
*/
SignPostingView signPostingView();
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package life.qbic.compass.spi;
package life.qbic.compass.model;

import life.qbic.compass.model.SignPostingView;
import life.qbic.linksmith.model.WebLink;
import life.qbic.linksmith.spi.WebLinkValidator.IssueReport;

Expand All @@ -19,6 +18,16 @@
* an {@link IssueReport}, which aggregates all warnings and errors detected
* during validation.
* </li>
* <li>
* <strong>{@link Level2LinksetView}</strong> (optional),
* a structured, domain-oriented interpretation of the validated links
* according to <em>FAIR Signposting Level&nbsp;2</em>.
* <br>
* When present, this view exposes validated resource contexts
* (landing pages, content resources, metadata resources) grouped by
* their common <em>origin</em>, as defined by the {@code anchor} parameter
* in RFC&nbsp;8288 / RFC&nbsp;9264.
* </li>
* </ul>
*
* <p>
Expand All @@ -44,5 +53,9 @@
*
* @author Sven Fillinger
*/
public record SignPostingResult(SignPostingView signPostingView, IssueReport issueReport) {
public record SignPostingResult(
SignPostingView signPostingView,
IssueReport issueReport,
Level2LinksetView level2LinksetView) {

}
Loading
Loading