1 /* 2 * Copyright (c) 2023 the original author or authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.networknt.schema; 17 18 import java.util.Objects; 19 20 /** 21 * The absolute IRI is an IRI without the fragment. 22 * <p> 23 * absolute-IRI = scheme ":" ihier-part [ "?" iquery ] 24 * <p> 25 * This does not attempt to validate whether the value really conforms to an 26 * absolute IRI format as in earlier drafts the IDs are not defined as such. 27 */ 28 public class AbsoluteIri { 29 private final String value; 30 31 /** 32 * Constructs a new IRI given the value. 33 * 34 * @param value String 35 */ AbsoluteIri(String value)36 public AbsoluteIri(String value) { 37 this.value = value; 38 } 39 40 /** 41 * Constructs a new IRI given the value. 42 * 43 * @param iri the value 44 * @return the new absolute IRI 45 */ of(String iri)46 public static AbsoluteIri of(String iri) { 47 return new AbsoluteIri(iri); 48 } 49 50 /** 51 * Constructs a new IRI by parsing the given string and then resolving it 52 * against this IRI. 53 * 54 * @param iri to resolve 55 * @return the new absolute IRI 56 */ resolve(String iri)57 public AbsoluteIri resolve(String iri) { 58 return new AbsoluteIri(resolve(this.value, iri)); 59 } 60 61 /** 62 * Gets the scheme of the IRI. 63 * 64 * @return the scheme 65 */ getScheme()66 public String getScheme() { 67 return getScheme(this.value); 68 } 69 70 /** 71 * Returns the scheme and authority components of the IRI. 72 * 73 * @return the scheme and authority components 74 */ getSchemeAuthority()75 protected String getSchemeAuthority() { 76 return getSchemeAuthority(this.value); 77 } 78 79 /** 80 * Constructs a new IRI by parsing the given string and then resolving it 81 * against this IRI. 82 * 83 * @param parent the parent absolute IRI 84 * @param iri to resolve 85 * @return the new absolute IRI 86 */ resolve(String parent, String iri)87 public static String resolve(String parent, String iri) { 88 if (iri.contains(":")) { 89 // IRI is absolute 90 return iri; 91 } else { 92 // IRI is relative to this 93 if (parent == null) { 94 return iri; 95 } 96 if (iri.startsWith("/")) { 97 // IRI is relative to this root 98 return getSchemeAuthority(parent) + iri; 99 } else { 100 // IRI is relative to this path 101 String base = parent; 102 int scheme = parent.indexOf("://"); 103 if (scheme == -1) { 104 scheme = 0; 105 } else { 106 scheme = scheme + 3; 107 } 108 base = parent(base, scheme); 109 110 String[] iriParts = iri.split("/"); 111 for (int x = 0; x < iriParts.length; x++) { 112 if ("..".equals(iriParts[x])) { 113 base = parent(base, scheme); 114 } else if (".".equals(iriParts[x])) { 115 // skip 116 } else { 117 base = base + "/" + iriParts[x]; 118 } 119 } 120 if (iri.endsWith("/")) { 121 base = base + "/"; 122 } 123 return base; 124 } 125 } 126 } 127 parent(String iri, int scheme)128 protected static String parent(String iri, int scheme) { 129 int slash = iri.lastIndexOf('/'); 130 if (slash != -1 && slash > scheme) { 131 return iri.substring(0, slash); 132 } 133 return iri; 134 } 135 136 /** 137 * Returns the scheme and authority components of the IRI. 138 * 139 * @param iri to parse 140 * @return the scheme and authority components 141 */ getSchemeAuthority(String iri)142 protected static String getSchemeAuthority(String iri) { 143 if (iri == null) { 144 return ""; 145 } 146 // iri refers to root 147 int start = iri.indexOf("://"); 148 if (start == -1) { 149 start = 0; 150 } else { 151 start = start + 3; 152 } 153 int end = iri.indexOf('/', start); 154 return end != -1 ? iri.substring(0, end) : iri; 155 } 156 157 /** 158 * Returns the scheme of the IRI. 159 * 160 * @param iri to parse 161 * @return the scheme 162 */ getScheme(String iri)163 public static String getScheme(String iri) { 164 if (iri == null) { 165 return ""; 166 } 167 // iri refers to root 168 int start = iri.indexOf(":"); 169 if (start == -1) { 170 return ""; 171 } else { 172 return iri.substring(0, start); 173 } 174 } 175 176 @Override toString()177 public String toString() { 178 return this.value; 179 } 180 181 @Override hashCode()182 public int hashCode() { 183 return Objects.hash(this.value); 184 } 185 186 @Override equals(Object obj)187 public boolean equals(Object obj) { 188 if (this == obj) 189 return true; 190 if (obj == null) 191 return false; 192 if (getClass() != obj.getClass()) 193 return false; 194 AbsoluteIri other = (AbsoluteIri) obj; 195 return Objects.equals(this.value, other.value); 196 } 197 198 } 199