Skip to content

Commit 6c3357a

Browse files
Merge pull request #755 from reactome/s015/t069-biopax-service
Spec 015 T069: BioPAX in the library service
2 parents 77c24d7 + 53bea8d commit 6c3357a

17 files changed

Lines changed: 506 additions & 221 deletions

File tree

‎deploy/java-library/Dockerfile‎

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
# Spec 010's library service, started here with SBML as its only operation
2-
# (spec 015 T063): sbml-exporter's library behind one loopback endpoint, which
3-
# node calls.
1+
# Spec 010's library service, started here with SBML (spec 015 T063) and
2+
# BioPAX Level 3 (T069): sbml-exporter's and BioPAX3Exporter's libraries behind
3+
# loopback endpoints, which node calls.
44
#
55
# Every Reactome library is built from the commit deploy/java/PINS.md records,
66
# never taken from a published snapshot: a snapshot can be republished under the
7-
# same version, and the shared parent POM already was once. When the SBML library
8-
# is published at a fixed version, its build stage goes and the pom names it.
7+
# same version, and the shared parent POM already was once. When a library is
8+
# published at a fixed version, its build goes and the pom names it.
99
#
1010
# Built only on the beta host and in CI, and never pushed to a registry: the
1111
# libraries have no licence yet (spec 015 research R10).
@@ -16,6 +16,7 @@ FROM maven:3.9.6-eclipse-temurin-17 AS libraries
1616
ARG REACTOME_PARENT_COMMIT=d93ad5a417724647f04810b476f6c2705a0e3aec
1717
ARG GRAPH_CORE_COMMIT=62aef35d7a89403b8a8800dc004d8de62f847aee
1818
ARG SBML_EXPORTER_COMMIT=f7b10342258d1aacd4f77f44bd928a29b516025e
19+
ARG BIOPAX3_EXPORTER_COMMIT=64c716a7f37081b42c1cf7b30bdebbf55ff580e2
1920

2021
WORKDIR /build
2122

@@ -28,37 +29,47 @@ RUN set -eu; \
2829
}; \
2930
fetch reactome-parent "$REACTOME_PARENT_COMMIT"; \
3031
fetch graph-core "$GRAPH_CORE_COMMIT"; \
31-
fetch sbml-exporter "$SBML_EXPORTER_COMMIT"
32+
fetch sbml-exporter "$SBML_EXPORTER_COMMIT"; \
33+
fetch BioPAX3Exporter "$BIOPAX3_EXPORTER_COMMIT"
3234

3335
# -nsu: a snapshot installed here is never replaced by a repository's.
3436
RUN set -eu; \
3537
cd /build/reactome-parent/boms && mvn -B -q -nsu install -N; \
3638
cd /build/reactome-parent/boms/reactome-bom && mvn -B -q -nsu install; \
3739
cd /build/reactome-parent/parents/reactome-parent && mvn -B -q -nsu install; \
3840
cd /build/graph-core && mvn -B -q -nsu install -DskipTests; \
39-
cd /build/sbml-exporter && mvn -B -q -nsu install -pl lib -am -DskipTests
41+
cd /build/sbml-exporter && mvn -B -q -nsu install -pl lib -am -DskipTests; \
42+
cd /build/BioPAX3Exporter && mvn -B -q -nsu install -pl lib -am -DskipTests
4043

4144
FROM libraries AS service
4245

4346
ARG REACTOME_PARENT_COMMIT=d93ad5a417724647f04810b476f6c2705a0e3aec
4447
ARG GRAPH_CORE_COMMIT=62aef35d7a89403b8a8800dc004d8de62f847aee
4548
ARG SBML_EXPORTER_COMMIT=f7b10342258d1aacd4f77f44bd928a29b516025e
49+
ARG BIOPAX3_EXPORTER_COMMIT=64c716a7f37081b42c1cf7b30bdebbf55ff580e2
4650

4751
WORKDIR /service
4852
COPY deploy/java-library/pom.xml ./
4953
COPY deploy/java-library/src ./src
5054
# The commits the health endpoint reports.
51-
RUN printf 'reactome-parent=%s\ngraph-core=%s\nsbml-exporter=%s\n' \
52-
"$REACTOME_PARENT_COMMIT" "$GRAPH_CORE_COMMIT" "$SBML_EXPORTER_COMMIT" \
55+
RUN printf 'reactome-parent=%s\ngraph-core=%s\nsbml-exporter=%s\nBioPAX3Exporter=%s\n' \
56+
"$REACTOME_PARENT_COMMIT" "$GRAPH_CORE_COMMIT" "$SBML_EXPORTER_COMMIT" "$BIOPAX3_EXPORTER_COMMIT" \
5357
> src/main/resources/pins.properties
5458
RUN mvn -B -q -nsu package
5559

5660
# The jar must carry the libraries built above, not a repository's copies of
57-
# their versions: compare their bytes.
61+
# their versions: compare their bytes. And the BioPAX library's Kotlin and
62+
# Paxtools at its own versions, alone: Spring Boot's dependency management
63+
# would give Kotlin's standard library as 1.6.21 (the pom holds it).
5864
RUN set -eu; \
5965
mkdir /check && cd /check && jar -xf /service/target/java-library.jar BOOT-INF/lib; \
6066
cmp BOOT-INF/lib/graph-core-3.0.0-SNAPSHOT.jar /build/graph-core/target/graph-core.jar; \
61-
cmp BOOT-INF/lib/sbml-exporter-lib-3.0.0-SNAPSHOT.jar /build/sbml-exporter/lib/target/sbml-exporter-lib-3.0.0-SNAPSHOT.jar
67+
cmp BOOT-INF/lib/sbml-exporter-lib-3.0.0-SNAPSHOT.jar /build/sbml-exporter/lib/target/sbml-exporter-lib-3.0.0-SNAPSHOT.jar; \
68+
cmp BOOT-INF/lib/biopax3-exporter-lib-0.0.1-SNAPSHOT.jar /build/BioPAX3Exporter/lib/target/biopax3-exporter-lib-0.0.1-SNAPSHOT.jar; \
69+
kotlin=$(sed -n 's|.*<kotlin.version>\(.*\)</kotlin.version>.*|\1|p' /build/BioPAX3Exporter/pom.xml); \
70+
paxtools=$(sed -n 's|.*<paxtools.version>\(.*\)</paxtools.version>.*|\1|p' /build/BioPAX3Exporter/pom.xml); \
71+
[ "$(ls BOOT-INF/lib | grep '^kotlin-stdlib-[0-9]')" = "kotlin-stdlib-$kotlin.jar" ]; \
72+
[ "$(ls BOOT-INF/lib | grep '^paxtools-core-')" = "paxtools-core-$paxtools.jar" ]
6273

6374
FROM eclipse-temurin:17-jre
6475

‎deploy/java-library/check.sh‎

Lines changed: 105 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,33 @@
11
#!/usr/bin/env bash
2-
# The library service, checked end to end over sbml-exporter's fixture graph
3-
# (spec 015 T063): the image this repository builds, its answers for the
4-
# fixture's three events compared with the expected files of the sbml-exporter
5-
# commit it is pinned to, by that commit's own ci/compare.py.
2+
# The library service, checked end to end (spec 015 T063, T069): the image this
3+
# repository builds, over each exporter's own fixture graph, its answers
4+
# compared with the expected files of the commit it is pinned to, by that
5+
# commit's own instruments:
6+
# - SBML over sbml-exporter's fixture: the three events' files, by its
7+
# ci/compare.py;
8+
# - BioPAX over BioPAX3Exporter's fixture: events of each kind and both
9+
# species, each contained in its species' expected file, by its
10+
# ci/contained.py, with the release's per-event xml:base.
611
#
712
# Usage: deploy/java-library/check.sh [image]
8-
# GRAPH_PORT (7687) and FILES_PORT (8097) move the fixture graph and the files
9-
# off ports a host already uses; the service keeps its own, 4360.
13+
# GRAPH_PORT (7687), FILES_PORT (8097) and SERVICE_PORT (4360) move the fixture
14+
# graph, the files and the service off ports a host already uses (a deployment's
15+
# own service is on 4360).
1016
# Without an image, it builds one. Needs docker, curl and python3 with
1117
# python-libsbml 5.21.2 (pip install python-libsbml==5.21.2).
1218
set -euo pipefail
1319

1420
graph_port=${GRAPH_PORT:-7687}
1521
files_port=${FILES_PORT:-8097}
22+
service_port=${SERVICE_PORT:-4360}
1623

17-
# The check's own service takes 4360 on the host's network. One already there
24+
# The check's own service takes its port on the host's network. One already there
1825
# (a deployment's) would answer the checks below in its place, over its graph.
1926
# Any answer refuses, a 503 too (a deployment whose graph is down), and it is
2027
# refused before the trap below, whose clean-up would remove another run's
2128
# containers.
22-
if curl -s -m 5 -o /dev/null http://127.0.0.1:4360/health; then
23-
echo "Something already answers on 127.0.0.1:4360; stop it, or run this elsewhere" >&2
29+
if curl -s -m 5 -o /dev/null http://127.0.0.1:$service_port/health; then
30+
echo "Something already answers on 127.0.0.1:$service_port; stop it, or set SERVICE_PORT" >&2
2431
exit 1
2532
fi
2633

@@ -30,9 +37,11 @@ work=$(mktemp -d)
3037
# Named for this run, so a run that stops early removes only its own.
3138
neo=java-library-check-graph-$$
3239
service=java-library-check-$$
40+
neo2=java-library-check-graph2-$$
41+
service2=java-library-check2-$$
3342
# shellcheck disable=SC2317 # called by the trap
3443
cleanup() {
35-
docker rm -f -v "$neo" "$service" >/dev/null 2>&1 || true
44+
docker rm -f -v "$neo" "$service" "$neo2" "$service2" >/dev/null 2>&1 || true
3645
if [ -n "${server:-}" ]; then kill "$server" 2>/dev/null || true; fi
3746
rm -rf "$work"
3847
}
@@ -51,37 +60,47 @@ curl -fsSL "https://codeload.github.com/reactome/sbml-exporter/tar.gz/$commit" \
5160
| tar -xz -C "$work/sbml-exporter" --strip-components=1 --wildcards '*/ci/*'
5261
ci="$work/sbml-exporter/ci"
5362

54-
# The fixture graph, on loopback.
55-
docker run -d --name "$neo" -p "127.0.0.1:$graph_port:7687" \
56-
-e NEO4J_AUTH=neo4j/fixturepass -e NEO4J_dbms_default__database=graph.db \
57-
-v "$ci/fixture/fixture.cypher:/fixture.cypher:ro" neo4j:4.4.48-community >/dev/null
58-
for _ in $(seq 90); do
59-
docker exec "$neo" cypher-shell -u neo4j -p fixturepass -d graph.db 'RETURN 1' >/dev/null 2>&1 && break
60-
sleep 2
61-
done
62-
docker exec "$neo" cypher-shell -u neo4j -p fixturepass -d graph.db -f /fixture.cypher >/dev/null
63+
# A fixture graph, on loopback: start_graph <container> <fixture.cypher>
64+
start_graph() {
65+
docker run -d --name "$1" -p "127.0.0.1:$graph_port:7687" \
66+
-e NEO4J_AUTH=neo4j/fixturepass -e NEO4J_dbms_default__database=graph.db \
67+
-v "$2:/fixture.cypher:ro" neo4j:4.4.48-community >/dev/null
68+
for _ in $(seq 90); do
69+
docker exec "$1" cypher-shell -u neo4j -p fixturepass -d graph.db 'RETURN 1' >/dev/null 2>&1 && break
70+
sleep 2
71+
done
72+
docker exec "$1" cypher-shell -u neo4j -p fixturepass -d graph.db -f /fixture.cypher >/dev/null
73+
}
74+
75+
# The service over it, answering its health check: start_service <container>
76+
start_service() {
77+
docker run -d --name "$1" --network host \
78+
-e NEO4J_URI="bolt://127.0.0.1:$graph_port" -e NEO4J_USER=neo4j -e NEO4J_PASSWORD=fixturepass \
79+
-e DIAGRAM_BASE="http://127.0.0.1:$files_port/" -e SBML_CACHE=/cache \
80+
-e SERVER_PORT="$service_port" "$image" >/dev/null
81+
for _ in $(seq 90); do
82+
curl -fs http://127.0.0.1:$service_port/health >/dev/null && break
83+
sleep 2
84+
done
85+
if ! curl -fsS http://127.0.0.1:$service_port/health; then
86+
echo "The service did not answer its health check. Its log:" >&2
87+
docker logs "$1" 2>&1 | tail -60 >&2
88+
exit 1
89+
fi
90+
echo
91+
}
92+
93+
start_graph "$neo" "$ci/fixture/fixture.cypher"
6394

6495
# The release's download directory, as far as the fixture needs it.
6596
mkdir -p "$work/www/97/diagram"
6697
cp "$ci"/fixture/R-*.json "$work/www/97/diagram/"
6798
python3 -m http.server "$files_port" --bind 127.0.0.1 --directory "$work/www" >/dev/null 2>&1 &
6899
server=$!
69100

70-
docker run -d --name "$service" --network host \
71-
-e NEO4J_URI="bolt://127.0.0.1:$graph_port" -e NEO4J_USER=neo4j -e NEO4J_PASSWORD=fixturepass \
72-
-e DIAGRAM_BASE="http://127.0.0.1:$files_port/" -e SBML_CACHE=/cache "$image" >/dev/null
73-
for _ in $(seq 90); do
74-
curl -fs http://127.0.0.1:4360/health >/dev/null && break
75-
sleep 2
76-
done
77-
if ! curl -fsS http://127.0.0.1:4360/health; then
78-
echo "The service did not answer its health check. Its log:" >&2
79-
docker logs "$service" 2>&1 | tail -60 >&2
80-
exit 1
81-
fi
82-
echo
101+
start_service "$service"
83102

84-
status() { curl -s -o "$2" -w '%{http_code}' "http://127.0.0.1:4360/sbml/$1"; }
103+
status() { curl -s -o "$2" -w '%{http_code}' "http://127.0.0.1:$service_port/sbml/$1"; }
85104
fail=0
86105
mkdir "$work/out"
87106
for id in $(find "$ci/fixture/expected" -name 'R-*.sbml' -exec basename {} .sbml \; | sort); do
@@ -93,6 +112,57 @@ code=$(status R-HSA-1 /dev/null)
93112
code=$(status R-HSA-9613354.1 /dev/null)
94113
[ "$code" = 400 ] || { echo "R-HSA-9613354.1 (not a bare stable id): $code, expected 400" >&2; fail=1; }
95114

96-
python3 "$ci/validate.py" "$work/out"
97-
python3 "$ci/compare.py" "$ci/fixture/expected" "$work/out"
115+
python3 "$ci/validate.py" "$work/out" || fail=1
116+
python3 "$ci/compare.py" "$ci/fixture/expected" "$work/out" || fail=1
117+
118+
# BioPAX, over BioPAX3Exporter's fixture graph (release 98), in a graph and a
119+
# service of their own.
120+
docker rm -f -v "$neo" "$service" >/dev/null
121+
bcommit=$(sed -n 's/^ARG BIOPAX3_EXPORTER_COMMIT=\([0-9a-f]\{40\}\)$/\1/p' "$root/deploy/java-library/Dockerfile" | sort -u)
122+
[ "$(printf '%s\n' "$bcommit" | wc -l)" -eq 1 ] || { echo "The Dockerfile names more than one BioPAX3Exporter commit" >&2; exit 1; }
123+
mkdir "$work/BioPAX3Exporter"
124+
curl -fsSL "https://codeload.github.com/reactome/BioPAX3Exporter/tar.gz/$bcommit" \
125+
| tar -xz -C "$work/BioPAX3Exporter" --strip-components=1 --wildcards '*/ci/*'
126+
bci="$work/BioPAX3Exporter/ci"
127+
start_graph "$neo2" "$bci/fixture/fixture.cypher"
128+
start_service "$service2"
129+
130+
# Events of each kind and both species: of the graph's, by database id, the
131+
# first of each kind that its species' expected file holds (the fixture has
132+
# events beyond those files, such as an inferred event's source). Each line:
133+
# stId, dbId, species.
134+
candidates=$(docker exec "$neo2" cypher-shell -u neo4j -p fixturepass -d graph.db --format plain '
135+
CALL {
136+
MATCH (e:TopLevelPathway {speciesName: "Homo sapiens"}) RETURN "pathway" AS kind, e
137+
UNION ALL MATCH (e:Reaction {speciesName: "Homo sapiens"}) RETURN "reaction" AS kind, e
138+
UNION ALL MATCH (e:BlackBoxEvent {speciesName: "Homo sapiens"}) RETURN "blackbox" AS kind, e
139+
UNION ALL MATCH (e:ReactionLikeEvent {dbId: 174731}) RETURN "degradation" AS kind, e
140+
UNION ALL MATCH (e:Pathway {speciesName: "Plasmodium falciparum"}) RETURN "falciparum" AS kind, e
141+
}
142+
RETURN kind + " " + e.stId + " " + e.dbId + " " + replace(e.speciesName, " ", "_")
143+
ORDER BY kind, e.dbId' | tail -n +2 | tr -d '"')
144+
events=$(while read -r kind id dbid species; do
145+
grep -q ">$dbid</bp:id>" "$bci/fixture/expected/$species.owl" && echo "$kind $id $dbid $species"
146+
done <<<"$candidates" | sort -u -k1,1 | cut -d' ' -f2-)
147+
[ "$(printf '%s\n' "$events" | wc -l)" -eq 5 ] || { echo "Expected one event of each of five kinds in the fixture's files, got: $events" >&2; exit 1; }
148+
149+
bstatus() { curl -s -o "$2" -w '%{http_code}' "http://127.0.0.1:$service_port/biopax/$1"; }
150+
mkdir -p "$work/owl/Homo_sapiens" "$work/owl/Plasmodium_falciparum"
151+
while read -r id dbid species; do
152+
file="$work/owl/$species/$id.owl"
153+
code=$(bstatus "$id" "$file")
154+
[ "$code" = 200 ] || { echo "$id: $code, expected 200" >&2; fail=1; continue; }
155+
# The release's per-event base: Reactome's BioPAX namespace, the release, the event's database id
156+
grep -q "xml:base=\"http://www.reactome.org/biopax/98/$dbid#\"" "$file" \
157+
|| { echo "$id: not the release's per-event xml:base" >&2; fail=1; }
158+
done <<<"$events"
159+
code=$(bstatus R-HSA-1 /dev/null)
160+
[ "$code" = 404 ] || { echo "R-HSA-1 (not in the graph): $code, expected 404" >&2; fail=1; }
161+
code=$(bstatus R-HSA-174731.1 /dev/null)
162+
[ "$code" = 400 ] || { echo "R-HSA-174731.1 (not a bare stable id): $code, expected 400" >&2; fail=1; }
163+
164+
# Each event's file holds nothing its species' file lacks, and is whole
165+
for species in Homo_sapiens Plasmodium_falciparum; do
166+
python3 -I "$bci/contained.py" "$bci/fixture/expected/$species.owl" "$work/owl/$species"/*.owl || fail=1
167+
done
98168
exit $fail

‎deploy/java-library/pins.spec.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const pins = readFileSync(join(__dirname, '../java/PINS.md'), 'utf8');
1515
/** The Dockerfile's ARG <NAME>_COMMIT=<sha> lines, by name, each stage's. */
1616
function commitArgs(text: string) {
1717
const found = new Map<string, Set<string>>();
18-
for (const [, name = '', sha = ''] of text.matchAll(/^ARG ([A-Z_]+)_COMMIT=([0-9a-f]{40})$/gm))
18+
for (const [, name = '', sha = ''] of text.matchAll(/^ARG ([A-Z0-9_]+)_COMMIT=([0-9a-f]{40})$/gm))
1919
found.set(name, (found.get(name) ?? new Set()).add(sha));
2020
return found;
2121
}
@@ -30,6 +30,7 @@ const REPOSITORIES: Record<string, string> = {
3030
REACTOME_PARENT: 'reactome-parent',
3131
GRAPH_CORE: 'graph-core',
3232
SBML_EXPORTER: 'sbml-exporter',
33+
BIOPAX3_EXPORTER: 'BioPAX3Exporter',
3334
};
3435

3536
describe('the library service pins', () => {

‎deploy/java-library/pom.xml‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
44
<modelVersion>4.0.0</modelVersion>
55

6-
<!-- Spec 010's library service, started here with SBML as its only operation (spec 015 T063). -->
6+
<!-- Spec 010's library service, started here with SBML (spec 015 T063) and BioPAX Level 3 (T069). -->
77
<groupId>org.reactome.server</groupId>
88
<artifactId>java-library</artifactId>
99
<version>0.1.0</version>
@@ -26,6 +26,12 @@
2626
<!-- sbml-exporter's graph-only branch, built from its commit by the Dockerfile. Once the library is
2727
published, the Dockerfile's build stage goes and this names the published version. -->
2828
<sbml-exporter-lib.version>3.0.0-SNAPSHOT</sbml-exporter-lib.version>
29+
<!-- BioPAX3Exporter's main, built from its commit by the Dockerfile, likewise. -->
30+
<biopax3-exporter-lib.version>0.0.1-SNAPSHOT</biopax3-exporter-lib.version>
31+
<!-- The BioPAX library's Kotlin (its pom's kotlin.version). Spring Boot 2.7's dependency management, which
32+
the parent brings, would otherwise give its standard library as 1.6.21 under a library compiled with
33+
2.4; the Dockerfile checks the jar carries this one. -->
34+
<kotlin.version>2.4.21</kotlin.version>
2935
</properties>
3036

3137
<dependencies>
@@ -34,6 +40,11 @@
3440
<artifactId>sbml-exporter-lib</artifactId>
3541
<version>${sbml-exporter-lib.version}</version>
3642
</dependency>
43+
<dependency>
44+
<groupId>org.reactome.server.tools</groupId>
45+
<artifactId>biopax3-exporter-lib</artifactId>
46+
<version>${biopax3-exporter-lib.version}</version>
47+
</dependency>
3748
<dependency>
3849
<groupId>org.springframework.boot</groupId>
3950
<artifactId>spring-boot-starter-web</artifactId>

deploy/java-library/src/main/java/org/reactome/server/library/SbmlController.java renamed to deploy/java-library/src/main/java/org/reactome/server/library/ExportController.java

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import org.slf4j.Logger;
1111
import org.slf4j.LoggerFactory;
12+
import org.springframework.beans.factory.annotation.Qualifier;
1213
import org.springframework.core.io.FileSystemResource;
1314
import org.springframework.core.io.Resource;
1415
import org.springframework.http.HttpStatus;
@@ -20,35 +21,52 @@
2021

2122
/**
2223
* The service's answers to node, over loopback. Node writes the public answer: its headers, its errors in the
23-
* service's envelope and its cache labels (spec 015 T065). This writes only the body, or a status and a reason.
24+
* service's envelope and its cache labels (spec 015 T065, T070). This writes only the body, or a status and a reason.
2425
*/
2526
@RestController
26-
public class SbmlController {
27+
public class ExportController {
2728

28-
private static final Logger logger = LoggerFactory.getLogger(SbmlController.class);
29+
private static final Logger logger = LoggerFactory.getLogger(ExportController.class);
2930
private static final Pattern ST_ID = Pattern.compile("R-[A-Z]{3}-\\d+");
3031
static final MediaType SBML = MediaType.parseMediaType("application/sbml+xml;charset=UTF-8");
32+
static final MediaType BIOPAX = MediaType.parseMediaType("application/rdf+xml;charset=UTF-8");
3133

32-
private final SbmlFiles files;
33-
private final SbmlFiles.Graph graph;
34+
private final ExportFiles sbml;
35+
private final ExportFiles biopax;
36+
private final ExportFiles.Graph graph;
3437
private final Properties pins;
3538

36-
public SbmlController(SbmlFiles files, SbmlFiles.Graph graph, Properties pins) {
37-
this.files = files;
39+
public ExportController(@Qualifier("sbmlFiles") ExportFiles sbml, @Qualifier("biopaxFiles") ExportFiles biopax,
40+
ExportFiles.Graph graph, Properties pins) {
41+
this.sbml = sbml;
42+
this.biopax = biopax;
3843
this.graph = graph;
3944
this.pins = pins;
4045
}
4146

4247
/** An event's SBML, by its stable id without a version: node resolves any other form first. */
4348
@GetMapping("/sbml/{stId}")
4449
public ResponseEntity<?> sbml(@PathVariable String stId) throws InterruptedException {
50+
return answer(sbml, SBML, stId);
51+
}
52+
53+
/**
54+
* An event's BioPAX Level 3, by its stable id without a version. Node decides 404 and 400 first (T070); the
55+
* service's own 404 is a backstop.
56+
*/
57+
@GetMapping("/biopax/{stId}")
58+
public ResponseEntity<?> biopax(@PathVariable String stId) throws InterruptedException {
59+
return answer(biopax, BIOPAX, stId);
60+
}
61+
62+
private static ResponseEntity<?> answer(ExportFiles files, MediaType type, String stId) throws InterruptedException {
4563
if (!ST_ID.matcher(stId).matches()) return reason(HttpStatus.BAD_REQUEST, "Not a stable id: " + stId);
4664
try {
4765
Optional<Path> file = files.get(stId);
4866
if (file.isEmpty()) return reason(HttpStatus.NOT_FOUND, "No event " + stId + " in the graph");
4967
Resource body = new FileSystemResource(file.get());
50-
return ResponseEntity.ok().contentType(SBML).body(body);
51-
} catch (SbmlFiles.DiagramUnavailable e) {
68+
return ResponseEntity.ok().contentType(type).body(body);
69+
} catch (ExportFiles.DiagramUnavailable e) {
5270
logger.warn("{}: {}", stId, e.getMessage());
5371
return reason(HttpStatus.SERVICE_UNAVAILABLE, e.getMessage());
5472
} catch (RuntimeException e) {

0 commit comments

Comments
 (0)