Skip to content

Commit 67a78a0

Browse files
committed
update link uri handler
1 parent 54d4dc7 commit 67a78a0

File tree

1 file changed

+124
-0
lines changed

1 file changed

+124
-0
lines changed
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/*-
2+
* #%L
3+
* URL scheme handlers for SciJava.
4+
* %%
5+
* Copyright (C) 2023 - 2025 SciJava developers.
6+
* %%
7+
* Redistribution and use in source and binary forms, with or without
8+
* modification, are permitted provided that the following conditions are met:
9+
*
10+
* 1. Redistributions of source code must retain the above copyright notice,
11+
* this list of conditions and the following disclaimer.
12+
* 2. Redistributions in binary form must reproduce the above copyright notice,
13+
* this list of conditions and the following disclaimer in the documentation
14+
* and/or other materials provided with the distribution.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
20+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26+
* POSSIBILITY OF SUCH DAMAGE.
27+
* #L%
28+
*/
29+
package org.scijava.links;
30+
31+
import java.net.URI;
32+
import java.util.LinkedHashMap;
33+
import java.util.Map;
34+
import java.util.Arrays;
35+
import java.net.URI;
36+
import java.net.URISyntaxException;
37+
import java.nio.charset.StandardCharsets;
38+
import java.util.Objects;
39+
40+
/**
41+
* Utility class for working with {@link URI} objects.
42+
*
43+
* @author Curtis Rueden, Marwan Zouinkhi
44+
*/
45+
public final class FijiURILink {
46+
47+
48+
private final String plugin; // e.g., "BDV"
49+
private final String subPlugin; // e.g., "open" (nullable)
50+
private final String query; // e.g., "a=1&b=2" (nullable)
51+
private final String rawQuery; // e.g., "a=1&b=2" (nullable)
52+
53+
private FijiURILink(String plugin, String subPlugin, String query, String rawQuery) {
54+
this.plugin = plugin;
55+
this.subPlugin = subPlugin;
56+
this.query = query;
57+
this.rawQuery = rawQuery;
58+
}
59+
60+
public static FijiURILink parse(String uriString) {
61+
Objects.requireNonNull(uriString, "uriString");
62+
final URI uri;
63+
try {
64+
uri = new URI(uriString);
65+
} catch (URISyntaxException e) {
66+
throw new IllegalArgumentException("Invalid URI: " + uriString, e);
67+
}
68+
69+
if (!"fiji".equalsIgnoreCase(uri.getScheme())) {
70+
throw new IllegalArgumentException("Scheme must be fiji://");
71+
}
72+
// For opaque vs hierarchical handling: ensure it's hierarchical (has //)
73+
String authority = uri.getAuthority(); // first segment after //
74+
if (authority == null || authority.isEmpty()) {
75+
throw new IllegalArgumentException("Missing plugin name after fiji://");
76+
}
77+
String plugin = authority;
78+
79+
String path = uri.getPath(); // includes leading '/'
80+
String sub = null;
81+
if (path != null && !path.isEmpty()) {
82+
// normalize: "/open" -> "open"; "/" -> null
83+
String trimmed = path.startsWith("/") ? path.substring(1) : path;
84+
sub = trimmed.isEmpty() ? null : trimmed;
85+
}
86+
87+
// Raw query (no '?'), leave as-is; users can parse if they want.
88+
String q = uri.getQuery();
89+
// Optional: decode percent-escapes (uncomment if desired)
90+
// q = (q == null) ? null : java.net.URLDecoder.decode(q, StandardCharsets.UTF_8);
91+
String raw = uri.getRawQuery();
92+
return new FijiURILink(plugin, sub, q, raw);
93+
}
94+
95+
public String getPlugin() { return plugin; }
96+
public String getSubPlugin() { return subPlugin; } // may be null
97+
public String getQuery() { return query; } // may be null
98+
public String getRawQuery() { return rawQuery; } // may be null
99+
100+
public Map<String, String> getParsedQuery() {
101+
final LinkedHashMap<String, String> map = new LinkedHashMap<>();
102+
final String[] tokens = query == null ? new String[0] : query.split("&");
103+
for (final String token : tokens) {
104+
final String[] kv = token.split("=", 2);
105+
final String k = kv[0];
106+
final String v = kv.length > 1 ? kv[1] : null;
107+
map.put(k, v);
108+
}
109+
return map;
110+
}
111+
112+
@Override public String toString() {
113+
StringBuilder sb = new StringBuilder("fiji://").append(plugin);
114+
if (subPlugin != null) sb.append('/').append(subPlugin);
115+
if (query != null) sb.append('?').append(query);
116+
return sb.toString();
117+
}
118+
119+
// Convenience helper: returns null instead of throwing
120+
public static FijiURILink tryParse(String uriString) {
121+
try { return parse(uriString); } catch (RuntimeException e) { return null; }
122+
}
123+
}
124+

0 commit comments

Comments
 (0)