001/* 002 * Copyright 2021 Global Biodiversity Information Facility (GBIF) 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.gbif.dwc.terms; 017 018import java.io.Serializable; 019import java.io.UnsupportedEncodingException; 020import java.net.URI; 021import java.net.URLEncoder; 022import java.nio.charset.StandardCharsets; 023import java.util.Objects; 024import java.util.regex.Matcher; 025import java.util.regex.Pattern; 026 027public class UnknownTerm implements Term, Serializable { 028 029 private final URI uri; 030 private final String name; 031 private final String prefix; 032 private final boolean isClass; 033 034 private static final String NS = "unknown.org"; 035 private static final String SCHEME = "http://"; 036 private static final String URL = SCHEME + NS + "/"; 037 private static final String PREFIX = "unknown"; 038 private static final Pattern PREFIX_PATTERN = Pattern.compile("^([a-zA-Z0-9]+):([a-zA-Z0-9._+# -]+)$"); 039 040 public static UnknownTerm build(String name){ 041 return build(name, false); 042 } 043 044 private static URI unknownURI(String name) { 045 return URI.create(URL + name); 046 } 047 048 public static UnknownTerm build(String name, boolean isClass){ 049 Matcher m = PREFIX_PATTERN.matcher(name); 050 if (m.find()) { 051 if (m.group(1).equalsIgnoreCase(PREFIX)) { 052 // unknown: 053 return new UnknownTerm(unknownURI(m.group(2)), PREFIX, m.group(2), isClass); 054 } else { 055 return new UnknownTerm(unknownURI(m.group(1) + "/" + m.group(2)), m.group(1), m.group(2), isClass); 056 } 057 } 058 URI uri = URI.create(name); 059 if (uri.getAuthority() != null) { 060 return new UnknownTerm(uri, isClass); 061 062 } else if (uri.getScheme() != null) { 063 String scheme = uri.getScheme().equalsIgnoreCase(PREFIX) ? "" : uri.getScheme() + "/"; 064 return build(URL + scheme + uri.getSchemeSpecificPart(), isClass); 065 066 } else { 067 if (!name.contains("/") && !name.contains("#")) { 068 try { 069 name = URLEncoder.encode(name, StandardCharsets.UTF_8.name()); 070 } catch (UnsupportedEncodingException e) { 071 } 072 } 073 return build(URL +name, isClass); 074 } 075 } 076 077 public static UnknownTerm build(String qualifiedName, String simpleName){ 078 return build(qualifiedName, simpleName, false); 079 } 080 081 public static UnknownTerm build(String qualifiedName, String simpleName, boolean isClass){ 082 return new UnknownTerm(URI.create(qualifiedName), null, simpleName, isClass); 083 } 084 085 public UnknownTerm(URI uri, String prefix, String name, boolean isClass) { 086 this.isClass = isClass; 087 if (uri == null || !uri.isAbsolute()) { 088 throw new IllegalArgumentException("The qualified name URI must be an absolute URI"); 089 } 090 if (name == null || name.isEmpty()) { 091 throw new IllegalArgumentException("The simple name is required"); 092 } 093 this.uri = uri; 094 this.name = name; 095 this.prefix = prefix != null ? prefix : ( 096 uri.getAuthority().equalsIgnoreCase(NS) ? PREFIX : null 097 ); 098 } 099 100 public UnknownTerm(URI uri, boolean isClass) { 101 this(uri, null, extractName(uri), isClass); 102 } 103 104 private static String extractName(URI uri) { 105 if (uri == null || !uri.isAbsolute()) { 106 throw new IllegalArgumentException("The qualified name URI is required and must be an absolute URI"); 107 } 108 109 if (uri.getFragment() != null) { 110 return uri.getFragment(); 111 112 } else if (uri.getPath() != null) { 113 String name = uri.getPath(); 114 // remove trailing and ending slash if existing 115 if (name.endsWith("/")) { 116 name = name.substring(0, name.length() - 1); 117 } 118 if (name.startsWith("/")) { 119 name = name.substring(1); 120 } 121 // only use last part of path 122 int pos = name.lastIndexOf("/"); 123 if (pos > 0) { 124 name = name.substring(pos + 1); 125 } 126 return name; 127 128 } else { 129 throw new IllegalArgumentException("The qualified name URI must have a path or fragment to automatically derive a simple name"); 130 } 131 } 132 133 @Override 134 public String qualifiedName() { 135 return uri.toString(); 136 } 137 138 @Override 139 public String simpleName() { 140 return name; 141 } 142 143 @Override 144 public boolean isClass() { 145 return isClass; 146 } 147 148 @Override 149 public String toString() { 150 return prefixedName(); 151 } 152 153 @Override 154 public String prefixedName() { 155 return prefix != null ? prefix + ":" + simpleName() : qualifiedName(); 156 } 157 158 @Override 159 public String prefix() { 160 return prefix; 161 } 162 163 @Override 164 public URI namespace() { 165 return URI.create(uri.getScheme() + "://" + uri.getAuthority()); 166 } 167 168 @Override 169 public boolean equals(Object o) { 170 if (this == o) return true; 171 if (!(o instanceof Term)) return false; 172 173 Term that = (Term) o; 174 175 return qualifiedName().equals(that.qualifiedName()); 176 } 177 178 @Override 179 public int hashCode() { 180 return qualifiedName().hashCode(); 181 } 182}