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
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.apache.wicket.markup.html.link.ExternalLink;
import org.apache.wicket.model.Model;
import org.apache.wicket.request.flow.RedirectToUrlException;
import org.apache.wicket.request.http.flow.AbortWithHttpErrorCodeException;
import org.apache.wicket.request.mapper.parameter.INamedParameters.NamedPair;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.commonjava.mimeparse.MIMEParse;
Expand Down Expand Up @@ -157,9 +158,15 @@ public ExplorePage(final Nanopub publishedNanopub, final PageParameters paramete
private void initPage() {
PageParameters parameters = getPageParameters();

String tempRef = parameters.get("id").toString();
String tempRef = parameters.get("id").toString("");
// Sometimes these Wicket session IDs end up here and they can mess up the query cache:
tempRef = tempRef.replaceFirst(";jsessionid.*$", "");
// There is nothing to explore without an id. Answering that plainly keeps a request
// that lost the parameter -- a stale link, or an Ajax call to a page that is no longer
// in the page store -- from failing as a server error.
if (tempRef.isEmpty()) {
throw new AbortWithHttpErrorCodeException(400, "Parameter 'id' is required");
}

String contextId = parameters.get("context").toString("");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.nanopub.Nanopub;
import org.nanopub.NanopubWithNs;

import java.io.Serializable;
import java.io.StringWriter;
import java.util.LinkedHashMap;
import java.util.List;
Expand All @@ -24,13 +25,19 @@
* What a resource page has to offer as RDF (issue #710): the download page's view of the
* resource, plus the nanopublications that declare the resource itself, whose assertions
* are small enough to embed in the page.
* <p>
* Pages keep this in a field, and Wicket serializes the pages it stores, so this has to be
* {@link Serializable}: a page holding something that is not never reaches the page store, and
* the next request for it then re-instantiates the page without its parameters, which is how the
* field added for issue #710 made the Explore page's lazy-loaded panels fail.
* The nanopublications it carries are serializable themselves ({@code NanopubImpl}).
*
* @param type the download page's {@code type}: user, space, resource or part
* @param id the resource IRI
* @param contextId the containing resource for a part, null otherwise
* @param declarations the nanopublications declaring the resource; empty when unknown
*/
public record RdfSource(String type, String id, String contextId, List<Nanopub> declarations) {
public record RdfSource(String type, String id, String contextId, List<Nanopub> declarations) implements Serializable {

/**
* Prefixes a nanopublication declares for its own URI space, which mean nothing outside it.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
package com.knowledgepixels.nanodash.page;

import com.knowledgepixels.nanodash.WicketApplication;
import org.apache.wicket.util.tester.WicketTester;
import org.eclipse.rdf4j.model.vocabulary.DCTERMS;
import org.eclipse.rdf4j.model.vocabulary.RDFS;
import org.eclipse.rdf4j.model.vocabulary.SKOS;
import org.junit.jupiter.api.Test;

import static org.eclipse.rdf4j.model.util.Values.iri;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

class ExplorePageTest {

// A request that lost its id -- a stale link, or an Ajax call to a page that is no longer
// in the page store -- used to fail as a server error, which left the status line and the
// other lazy-loaded panels spinning forever.
@Test
void anExploreRequestWithoutAnIdIsRejected() {
WicketTester tester = new WicketTester(new WicketApplication());
tester.executeUrl("." + ExplorePage.MOUNT_PATH);
assertEquals(400, tester.getLastResponse().getStatus(),
"an explore URL without an 'id' parameter should be rejected, not fail as a server error");
}

@Test
void membershipIsDeclaredByPartVersionAndSchemeRelations() {
assertTrue(ExplorePage.declaresMembership(DCTERMS.IS_PART_OF));
Expand Down
29 changes: 29 additions & 0 deletions src/test/java/com/knowledgepixels/nanodash/page/RdfSourceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
import org.nanopub.Nanopub;
import org.nanopub.NanopubImpl;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
Expand Down Expand Up @@ -93,6 +97,31 @@ void nothingToEmbedWithoutDeclarations() {
assertNull(new RdfSource("space", RESOURCE_IRI, null, List.of()).toEmbeddedJsonLd(DUMP_URL));
}

/**
* Wicket serializes the pages it stores, and a page keeps its RdfSource in a field, so
* one has to survive serialization: a page holding something that does not never reaches
* the page store, and the next request for it re-instantiates the page without its
* parameters -- which is how the Explore page's lazy-loaded panels came to fail.
*/
@Test
void survivesPageSerialization() throws Exception {
RdfSource source = new RdfSource("space", RESOURCE_IRI, null, List.of(declaration()));
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
try (ObjectOutputStream out = new ObjectOutputStream(bytes)) {
out.writeObject(source);
}
RdfSource restored;
try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes.toByteArray()))) {
restored = (RdfSource) in.readObject();
}
assertEquals("space", restored.type());
assertEquals(RESOURCE_IRI, restored.id());
assertEquals(1, restored.declarations().size());
String doc = restored.toEmbeddedJsonLd(DUMP_URL);
assertTrue(doc.contains(RESOURCE_IRI), doc);
assertTrue(doc.contains("Test Workshop"), doc);
}

/**
* The download parameters name the resource, its context for a part, and the variant's
* format and assertion switch.
Expand Down
Loading