1package de.gultsch.common;
2
3import com.google.common.base.MoreObjects;
4import com.google.common.base.Splitter;
5import com.google.common.base.Strings;
6import com.google.common.collect.ImmutableMap;
7import java.io.UnsupportedEncodingException;
8import java.net.URLDecoder;
9import java.util.Collections;
10import java.util.Locale;
11import java.util.Map;
12import org.checkerframework.checker.nullness.qual.NonNull;
13
14public class MiniUri {
15
16 private static final String EMPTY_STRING = "";
17
18 private final String scheme;
19 private final String authority;
20 private final String path;
21 private final Map<String, String> parameter;
22
23 public MiniUri(final String uri) {
24 final var schemeAndRest = Splitter.on(':').limit(2).splitToList(uri);
25 if (schemeAndRest.size() < 2) {
26 this.scheme = uri;
27 this.authority = null;
28 this.path = null;
29 this.parameter = Collections.emptyMap();
30 return;
31 }
32 this.scheme = schemeAndRest.get(0);
33 final var rest = schemeAndRest.get(1);
34 final var authorityPathAndQuery = Splitter.on('?').limit(2).splitToList(rest);
35 final var authorityPath = authorityPathAndQuery.get(0);
36 System.out.println("authorityPath " + authorityPath);
37 if (authorityPath.length() >= 2 && authorityPath.startsWith("//")) {
38 final var authorityPathParts =
39 Splitter.on('/').limit(2).splitToList(authorityPath.substring(2));
40 this.authority = authorityPathParts.get(0);
41 this.path = authorityPathParts.size() == 2 ? authorityPathParts.get(1) : null;
42 } else {
43 this.authority = null;
44 // TODO path ; style path components from something like geo uri
45 this.path = authorityPath;
46 }
47 if (authorityPathAndQuery.size() == 2) {
48 this.parameter = parseParameters(authorityPathAndQuery.get(1), getDelimiter(scheme));
49 } else {
50 this.parameter = Collections.emptyMap();
51 }
52 }
53
54 private static char getDelimiter(final String scheme) {
55 return switch (scheme) {
56 case "xmpp", "geo" -> ';';
57 default -> '&';
58 };
59 }
60
61 private static Map<String, String> parseParameters(final String query, final char separator) {
62 final ImmutableMap.Builder<String, String> builder = new ImmutableMap.Builder<>();
63 for (final String pair : Splitter.on(separator).split(query)) {
64 final String[] parts = pair.split("=", 2);
65 if (parts.length == 0) {
66 continue;
67 }
68 final String key = parts[0].toLowerCase(Locale.US);
69 if (parts.length == 2) {
70 try {
71 builder.put(key, URLDecoder.decode(parts[1], "UTF-8"));
72 } catch (final UnsupportedEncodingException e) {
73 builder.put(key, EMPTY_STRING);
74 }
75 } else {
76 builder.put(key, EMPTY_STRING);
77 }
78 }
79 return builder.build();
80 }
81
82 @NonNull
83 @Override
84 public String toString() {
85 return MoreObjects.toStringHelper(this)
86 .add("scheme", scheme)
87 .add("authority", authority)
88 .add("path", path)
89 .add("parameter", parameter)
90 .toString();
91 }
92
93 public String getScheme() {
94 return this.scheme;
95 }
96
97 public String getAuthority() {
98 return this.authority;
99 }
100
101 public String getPath() {
102 return Strings.isNullOrEmpty(this.path) || this.authority == null
103 ? this.path
104 : '/' + this.path;
105 }
106
107 public Map<String, String> getParameter() {
108 return this.parameter;
109 }
110}