diff --git a/http-tests/admin/model/ontology-import-upload-no-deadlock.sh b/http-tests/admin/model/ontology-import-upload-no-deadlock.sh index af69d213f..939da9687 100755 --- a/http-tests/admin/model/ontology-import-upload-no-deadlock.sh +++ b/http-tests/admin/model/ontology-import-upload-no-deadlock.sh @@ -47,16 +47,12 @@ file_doc_ntriples=$(get.sh \ upload_uri=$(echo "$file_doc_ntriples" | sed -rn "s/<${file_doc//\//\\/}> <(.*)> \./\1/p") -echo "Uploaded file URI: $upload_uri" - # Verify the uploaded file is accessible before we add it as an import curl -k -f -s \ -E "$AGENT_CERT_FILE":"$AGENT_CERT_PWD" \ -H "Accept: ${file_content_type}" \ "$upload_uri" > /dev/null -echo "Upload file is accessible" - # Step 3: Add the uploaded file as an owl:import to the namespace ontology namespace_doc="${END_USER_BASE_URL}ns" @@ -69,8 +65,6 @@ add-ontology-import.sh \ --import "$upload_uri" \ "$ontology_doc" -echo "Added owl:import of uploaded file to namespace ontology" - # Step 4: Clear the namespace ontology from memory to force reload on next request clear-ontology.sh \ @@ -79,66 +73,22 @@ clear-ontology.sh \ -b "$ADMIN_BASE_URL" \ --ontology "$namespace" -echo "Cleared ontology cache to force reload" - -# Step 5: Make a request that triggers ontology loading -# This would cause a deadlock without the OntologyFilter fix -# Use portable timeout implementation (works on both macOS and Linux) - -echo "Making request to trigger ontology loading (testing for deadlock)..." - -# Portable timeout function - works on both macOS and Linux -request_pid="" -( - curl -k -f -s \ - -E "$OWNER_CERT_FILE":"$OWNER_CERT_PWD" \ - -H "Accept: application/n-triples" \ - "$namespace_doc" > /dev/null -) & -request_pid=$! - -# Wait up to 30 seconds for the request to complete -timeout_seconds=30 -elapsed=0 -while kill -0 "$request_pid" 2>/dev/null; do - if [ $elapsed -ge $timeout_seconds ]; then - kill -9 "$request_pid" 2>/dev/null || true - echo "ERROR: Request timed out after ${timeout_seconds} seconds - deadlock detected!" - exit 1 - fi - sleep 1 - ((elapsed++)) -done - -# Check if curl succeeded -wait "$request_pid" -curl_exit_code=$? -if [ $curl_exit_code -ne 0 ]; then - echo "ERROR: Request failed with exit code $curl_exit_code" - exit 1 -fi - -echo "Request completed successfully in ${elapsed}s (no deadlock)" - -# Step 6: Verify the import is present in the loaded ontology +# Step 5: Verify the import is present in the loaded ontology +# This request also triggers ontology loading and would detect deadlock curl -k -f -s \ -H "Accept: application/n-triples" \ "$namespace_doc" \ | grep "<${namespace}> <${upload_uri}>" > /dev/null -echo "Verified owl:import is present in namespace ontology" - -# Step 7: Verify the uploaded file is still accessible after ontology loading +# Step 6: Verify the uploaded file is still accessible after ontology loading curl -k -f -s \ -E "$AGENT_CERT_FILE":"$AGENT_CERT_PWD" \ -H "Accept: ${file_content_type}" \ "$upload_uri" > /dev/null -echo "Uploaded file is still accessible after ontology import" - -# Step 8: Verify that the imported ontology content is accessible via the namespace document +# Step 7: Verify that the imported ontology content is accessible via the namespace document # This confirms the import was actually loaded (not just skipped) curl -k -f -s \ @@ -148,7 +98,3 @@ curl -k -f -s \ --data-urlencode "query=SELECT * { ?p ?o }" \ "$namespace_doc" \ | grep 'Test Class' > /dev/null - -echo "Verified imported ontology content is accessible via SPARQL" - -echo "✓ All tests passed - no deadlock detected when importing uploaded files in ontology" diff --git a/src/main/java/com/atomgraph/linkeddatahub/server/filter/request/OntologyFilter.java b/src/main/java/com/atomgraph/linkeddatahub/server/filter/request/OntologyFilter.java index c996d5214..0390a989b 100644 --- a/src/main/java/com/atomgraph/linkeddatahub/server/filter/request/OntologyFilter.java +++ b/src/main/java/com/atomgraph/linkeddatahub/server/filter/request/OntologyFilter.java @@ -54,12 +54,43 @@ public class OntologyFilter implements ContainerRequestFilter private static final Logger log = LoggerFactory.getLogger(OntologyFilter.class); + /** + * Paths that should not trigger ontology loading to avoid circular dependencies. + * + * When an ontology contains owl:imports pointing to URIs within these paths, + * loading the ontology would trigger HTTP requests to those URIs. If those requests + * are intercepted by this filter, it creates a circular dependency: + * + * 1. Request arrives for /uploads/xyz + * 2. OntologyFilter intercepts it and loads ontology + * 3. Ontology has owl:imports for /uploads/xyz + * 4. Jena FileManager makes HTTP request to /uploads/xyz + * 5. OntologyFilter intercepts it again → infinite loop/deadlock + * + * Additionally, uploaded files are binary/RDF content that don't require + * ontology context for their serving logic. + */ + private static final java.util.Set IGNORED_PATH_PREFIXES = java.util.Set.of( + "uploads/" + ); + @Inject com.atomgraph.linkeddatahub.Application system; @Override public void filter(ContainerRequestContext crc) throws IOException { + String path = crc.getUriInfo().getPath(); + + // Skip ontology loading for paths that may be referenced in owl:imports + // to prevent circular dependency deadlocks during ontology resolution + if (IGNORED_PATH_PREFIXES.stream().anyMatch(path::startsWith)) + { + if (log.isTraceEnabled()) log.trace("Skipping ontology loading for path: {}", path); + crc.setProperty(OWL.Ontology.getURI(), Optional.empty()); + return; + } + crc.setProperty(OWL.Ontology.getURI(), getOntology(crc)); }