blob: c537056dd1d3860983f1cc9cfaa2b1e8359ed1c9 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jena.irix;
import java.util.Objects;
import org.apache.jena.atlas.lib.IRILib;
/**
* Operations in support of {@link IRIx}.
*/
public class IRIs {
/**
* Operation to take a string and make an {@link IRIx}.
* This operation does not resolve the string against a base.
* <p>
* Use this function if the application has been given an URI
* and wants to be sure it is valid for use in RDF.
* <p>
* Use {@link IRIs#resolve} to resolve a potentially relative URI against the current system base.
*/
static public IRIx reference(String iriStr) {
Objects.requireNonNull(iriStr);
IRIx iri = IRIx.create(iriStr);
if ( ! iri.isReference() )
throw new IRIException("Not an RDF IRI: <"+iriStr+">");
return iri;
}
/** Check a string is valid syntax for an IRI (absolute or relative) */
static public boolean check(String iriStr) {
Objects.requireNonNull(iriStr);
try {
checkEx(iriStr);
return true;
} catch(Exception ex) { return false; }
}
/**
* Check a string is valid syntax for an IRI,
* is an absolute IRI (resolve if necessary)
* and normalize (e.g. remove "./.." and "/../").
*/
static public String checkEx(String iriStr) {
Objects.requireNonNull(iriStr);
return reference(iriStr).str();
}
/** The system base {@link IRIx}. */
public static IRIx getSystemBase() {
return SystemIRIx.getSystemBase();
}
/** The system base IRI as a string. */
public static String getBaseStr() {
return SystemIRIx.getSystemBase().toString();
}
/**
* Given a candidate baseURI string, which may be a filename,
* turn it into a IRI suitable as a base IRI.
*/
public static String toBase(String baseURI) {
String scheme = scheme(baseURI);
// Assume scheme of one letter are Windows drive letters.
if ( scheme != null && scheme.length() == 1 )
scheme = "file";
if ( scheme != null && scheme.equals("file") )
return IRILib.filenameToIRI(baseURI);
return IRIs.getSystemBase().resolve(baseURI).toString();
}
/** Return a general purpose resolver, with the current system base as its base IRI. */
public static IRIxResolver stdResolver() {
return resolver(getSystemBase());
}
/** Return a general purpose resolver, with the current system base as its base IRI. */
public static IRIxResolver resolver(String base) {
return IRIxResolver.create(base).resolve(true).allowRelative(false).build();
}
/** Return a general purpose resolver, with the supplied IRI its base. */
public static IRIxResolver resolver(IRIx base) {
return IRIxResolver.create(base).resolve(true).allowRelative(false).build();
}
/** Return a resolver that does not resolve, and have a base and does not allow relative URIs. */
public static IRIxResolver absoluteResolver() {
return IRIxResolver.create().noBase().resolve(false).allowRelative(false).build();
}
/** Return a resolver that does not resolve relative URIs, with the current system base as its base IRI */
public static IRIxResolver relativeResolver() {
return IRIxResolver.create().noBase().resolve(false).allowRelative(true).build();
}
/** Resolve a URI against the system base. */
public static String resolve(String iriStr) {
if ( iriStr == null )
return getSystemBase().str();
return resolve(getSystemBase(), iriStr);
}
/** Resolve a URI against the system base. */
public static IRIx resolveIRI(String iriStr) {
if ( iriStr == null )
return getSystemBase();
return getSystemBase().resolve(iriStr);
}
/** Resolve a URI against a base. */
public static String resolve(IRIx base, String iriStr) {
return base.resolve(iriStr).str();
}
/** Resolve a URI against a base. */
public static String resolve(IRIx base, IRIx iri) {
return base.resolve(iri).str();
}
/** Resolve a URI against a base. The base must be an absolute IRI. */
public static String resolve(String baseStr, String iriStr) {
IRIx base = IRIx.create(baseStr);
if ( ! base.isReference() )
throw new IRIException("Not suitable as a base URI: '"+baseStr+"'");
return resolve(base, iriStr);
}
/**
* Get the URI scheme at the start of the string. This is the substring up to, and
* excluding, the first ":" if it conforms to the syntax requirements. Return null
* if it does not look like a scheme.
* <p>
* The <a href="https://tools.ietf.org/html/rfc3986#appendix-A">RFC 3986 URI
* grammar</a> defines {@code scheme} as:
*
* <pre>
* URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
* scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
* ...
* </pre>
*/
public static String scheme(String str) {
int idx = scheme(str, 0);
if ( idx <= 0 || idx > str.length())
return null;
return str.substring(0, idx);
}
// Return the index of the ":" starting from "start"
// so that start to the returned index is the scheme including ":"
// Return <= 0 for no scheme.
// -1 Syntax error
// 0 did not find a colon.
private static int scheme(String str, int start) {
int p = start;
int end = str.length();
while (p < end) {
char c = str.charAt(p);
if ( c == ':' )
return p;
if ( ! isAlpha(c) ) {
if ( p == start )
// Bad first character
return -1;
if ( ! ( isDigit(c) || c == '+' || c == '-' || c == '.' ) )
// Bad subsequent character
return -1;
}
p++;
}
// Did not find ':'
return 0;
}
private static boolean isDigit(char ch) {
return (ch >= '0' && ch <= '9');
}
private static boolean isAlpha(char ch) {
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
}
}