• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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