001/* 002 * Copyright 2020-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2020-2024 Ping Identity Corporation 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020/* 021 * Copyright (C) 2020-2024 Ping Identity Corporation 022 * 023 * This program is free software; you can redistribute it and/or modify 024 * it under the terms of the GNU General Public License (GPLv2 only) 025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 026 * as published by the Free Software Foundation. 027 * 028 * This program is distributed in the hope that it will be useful, 029 * but WITHOUT ANY WARRANTY; without even the implied warranty of 030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 031 * GNU General Public License for more details. 032 * 033 * You should have received a copy of the GNU General Public License 034 * along with this program; if not, see <http://www.gnu.org/licenses>. 035 */ 036package com.unboundid.util; 037 038 039 040import java.io.InputStream; 041import java.io.Serializable; 042import java.util.Collections; 043import java.util.Map; 044import java.util.TreeMap; 045import java.util.concurrent.atomic.AtomicReference; 046 047import com.unboundid.ldap.sdk.schema.AttributeSyntaxDefinition; 048import com.unboundid.ldap.sdk.schema.AttributeTypeDefinition; 049import com.unboundid.ldap.sdk.schema.MatchingRuleDefinition; 050import com.unboundid.ldap.sdk.schema.NameFormDefinition; 051import com.unboundid.ldap.sdk.schema.ObjectClassDefinition; 052import com.unboundid.ldap.sdk.schema.Schema; 053import com.unboundid.util.json.JSONObject; 054import com.unboundid.util.json.JSONObjectReader; 055 056 057 058/** 059 * This class represents a data structure with information about a variety of 060 * object identifiers (OIDs) used in LDAP-related contexts. 061 */ 062@NotMutable() 063@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 064public final class OIDRegistry 065 implements Serializable 066{ 067 /** 068 * A reference to the default instance of this OID registry. 069 */ 070 @NotNull private static final AtomicReference<OIDRegistry> DEFAULT_INSTANCE = 071 new AtomicReference<>(); 072 073 074 075 /** 076 * The name of the resource that holds the data for the default OID registry. 077 */ 078 @NotNull private static final String OID_REGISTRY_JSON_RESOURCE_NAME = 079 "com/unboundid/util/oid-registry.json"; 080 081 082 083 /** 084 * The name of the X-ORIGIN extension that schema elements may use to specify 085 * their origin. 086 */ 087 @NotNull private static final String X_ORIGIN_EXTENSION_NAME = "X-ORIGIN"; 088 089 090 091 /** 092 * The serial version UID for this serializable class. 093 */ 094 private static final long serialVersionUID = 867525903925430865L; 095 096 097 098 // A map of the items contained in the OID registry, indexed by 099 @NotNull private final Map<OID,OIDRegistryItem> items; 100 101 102 103 /** 104 * Creates an OID registry instance with the provided set of items. 105 * 106 * @param items The map of items to include in the OID registry. 107 */ 108 private OIDRegistry(@NotNull final Map<OID,OIDRegistryItem> items) 109 { 110 this.items = items; 111 } 112 113 114 115 /** 116 * Retrieves the default instance of this OID registry. 117 * 118 * @return The default instance of this OID registry. 119 */ 120 @NotNull() 121 public static OIDRegistry getDefault() 122 { 123 OIDRegistry oidRegistry = DEFAULT_INSTANCE.get(); 124 if (oidRegistry == null) 125 { 126 synchronized (DEFAULT_INSTANCE) 127 { 128 oidRegistry = DEFAULT_INSTANCE.get(); 129 if (oidRegistry == null) 130 { 131 final Map<OID,OIDRegistryItem> items = new TreeMap<>(); 132 try (InputStream inputStream = 133 OIDRegistry.class.getClassLoader().getResourceAsStream( 134 OID_REGISTRY_JSON_RESOURCE_NAME); 135 JSONObjectReader jsonObjectReader = 136 new JSONObjectReader(inputStream)) 137 { 138 while (true) 139 { 140 final JSONObject o = jsonObjectReader.readObject(); 141 if (o == null) 142 { 143 break; 144 } 145 146 try 147 { 148 final OIDRegistryItem item = new OIDRegistryItem(o); 149 items.put(new OID(item.getOID()), item); 150 } 151 catch (final Exception e) 152 { 153 Debug.debugException(e); 154 } 155 } 156 } 157 catch (final Exception e) 158 { 159 Debug.debugException(e); 160 } 161 162 oidRegistry = new OIDRegistry(Collections.unmodifiableMap(items)); 163 DEFAULT_INSTANCE.set(oidRegistry); 164 } 165 } 166 } 167 168 return oidRegistry; 169 } 170 171 172 173 /** 174 * Retrieves a copy of this OID registry that has been augmented with 175 * information from the provided schema. 176 * 177 * @param schema The schema that may be used to augment the information in 178 * this OID registry. It must not be {@code null}. 179 * 180 * @return A copy of this OID registry that has been augmented with 181 * information from the provided schema. 182 */ 183 @NotNull() 184 public OIDRegistry withSchema(@NotNull final Schema schema) 185 { 186 final TreeMap<OID,OIDRegistryItem> newItems = new TreeMap<>(items); 187 for (final AttributeSyntaxDefinition syntax : schema.getAttributeSyntaxes()) 188 { 189 final String oidString = syntax.getOID(); 190 final OID oid = new OID(syntax.getOID()); 191 if (newItems.containsKey(oid)) 192 { 193 continue; 194 } 195 196 String name = syntax.getDescription(); 197 if (name == null) 198 { 199 name = oidString; 200 } 201 202 newItems.put(oid, 203 new OIDRegistryItem(syntax.getOID(), name, "Attribute Syntax", 204 getOrigin(syntax.getExtensions()), null)); 205 } 206 207 for (final MatchingRuleDefinition matchingRule : schema.getMatchingRules()) 208 { 209 final String oidString = matchingRule.getOID(); 210 final OID oid = new OID(matchingRule.getOID()); 211 if (newItems.containsKey(oid)) 212 { 213 continue; 214 } 215 216 newItems.put(oid, 217 new OIDRegistryItem(matchingRule.getOID(), 218 matchingRule.getNameOrOID(), "Matching Rule", 219 getOrigin(matchingRule.getExtensions()), null)); 220 } 221 222 for (final AttributeTypeDefinition attributeType : 223 schema.getAttributeTypes()) 224 { 225 final String oidString = attributeType.getOID(); 226 final OID oid = new OID(attributeType.getOID()); 227 if (newItems.containsKey(oid)) 228 { 229 continue; 230 } 231 232 newItems.put(oid, 233 new OIDRegistryItem(attributeType.getOID(), 234 attributeType.getNameOrOID(), "Attribute Type", 235 getOrigin(attributeType.getExtensions()), null)); 236 } 237 238 for (final ObjectClassDefinition objectClass : 239 schema.getObjectClasses()) 240 { 241 final String oidString = objectClass.getOID(); 242 final OID oid = new OID(objectClass.getOID()); 243 if (newItems.containsKey(oid)) 244 { 245 continue; 246 } 247 248 newItems.put(oid, 249 new OIDRegistryItem(objectClass.getOID(), 250 objectClass.getNameOrOID(), "Object Class", 251 getOrigin(objectClass.getExtensions()), null)); 252 } 253 254 for (final NameFormDefinition nameForm : schema.getNameForms()) 255 { 256 final String oidString = nameForm.getOID(); 257 final OID oid = new OID(nameForm.getOID()); 258 if (newItems.containsKey(oid)) 259 { 260 continue; 261 } 262 263 newItems.put(oid, 264 new OIDRegistryItem(nameForm.getOID(), 265 nameForm.getNameOrOID(), "Name Form", 266 getOrigin(nameForm.getExtensions()), null)); 267 } 268 269 return new OIDRegistry(Collections.unmodifiableMap(newItems)); 270 } 271 272 273 274 /** 275 * Retrieves the value for the X-ORIGIN extension from the provided map, if 276 * available. 277 * 278 * @param extensions The map of extensions for the associated schema 279 * element. 280 * 281 * @return The value for the X-ORIGIN extension from the provided map, or 282 * {@code null} if there is no such extension. 283 */ 284 @Nullable() 285 private static String getOrigin( 286 @NotNull final Map<String,String[]> extensions) 287 { 288 final String[] values = extensions.get(X_ORIGIN_EXTENSION_NAME); 289 if ((values != null) && (values.length > 0)) 290 { 291 return values[0]; 292 } 293 294 return null; 295 } 296 297 298 299 /** 300 * Retrieves an unmodifiable map of all items in the OID registry, indexed by 301 * OID. 302 * 303 * @return An unmodifiable map of all items in the OID registry, indexed by 304 * OID. 305 */ 306 @NotNull() 307 public Map<OID,OIDRegistryItem> getItems() 308 { 309 return items; 310 } 311 312 313 314 /** 315 * Retrieves the OID registry item for the specified OID, if available. 316 * 317 * @param oid The OID for the item to retrieve. 318 * 319 * @return The OID registry item for the specified OID, or {@code null} if 320 * this registry does not have any information about the specified 321 * OID. 322 */ 323 @Nullable() 324 public OIDRegistryItem get(@NotNull final String oid) 325 { 326 return get(new OID(oid)); 327 } 328 329 330 331 /** 332 * Retrieves the OID registry item for the specified OID, if available. 333 * 334 * @param oid The OID for the item to retrieve. 335 * 336 * @return The OID registry item for the specified OID, or {@code null} if 337 * this registry does not have any information about the specified 338 * OID. 339 */ 340 @Nullable() 341 public OIDRegistryItem get(@NotNull final OID oid) 342 { 343 return items.get(oid); 344 } 345}