001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2008 Sun Microsystems, Inc. 025 * Portions Copyright 2014-2015 ForgeRock AS 026 */ 027package org.opends.server.admin; 028 029 030 031import org.forgerock.opendj.ldap.ByteString; 032import org.opends.server.types.DN; 033import org.opends.server.types.DirectoryException; 034import org.opends.server.types.RDN; 035import org.opends.server.util.StaticUtils; 036 037 038 039/** 040 * A reference to another managed object. 041 * 042 * @param <C> 043 * The type of client managed object configuration that this 044 * reference refers to. 045 * @param <S> 046 * The type of server managed object configuration that this 047 * reference refers to. 048 */ 049public final class Reference<C extends ConfigurationClient, 050 S extends Configuration> { 051 052 /** 053 * Parses a DN string value as a reference using the provided 054 * managed object path and relation definition. 055 * 056 * @param <C> 057 * The type of client managed object configuration that 058 * this reference refers to. 059 * @param <S> 060 * The type of server managed object configuration that 061 * this reference refers to. 062 * @param p 063 * The path of the referenced managed object's parent. 064 * @param rd 065 * The instantiable relation in the parent which contains 066 * the referenced managed object. 067 * @param s 068 * The DN string value. 069 * @return Returns the new reference based on the provided DN string 070 * value. 071 * @throws IllegalArgumentException 072 * If the DN string value could not be decoded as a DN or 073 * if the provided DN did not correspond to the provided 074 * path and relation. 075 */ 076 public static <C extends ConfigurationClient, S extends Configuration> 077 Reference<C, S> parseDN( 078 ManagedObjectPath<?, ?> p, InstantiableRelationDefinition<C, S> rd, 079 String s) throws IllegalArgumentException { 080 AbstractManagedObjectDefinition<?, ?> d = p.getManagedObjectDefinition(); 081 RelationDefinition<?, ?> tmp = d.getRelationDefinition(rd.getName()); 082 if (tmp != rd) { 083 throw new IllegalArgumentException("The relation \"" + rd.getName() 084 + "\" is not associated with the definition \"" + d.getName() + "\""); 085 } 086 087 DN dn; 088 try { 089 dn = DN.valueOf(s); 090 } catch (DirectoryException e) { 091 throw new IllegalArgumentException("Unabled to decode the DN string: \"" 092 + s + "\""); 093 } 094 095 RDN rdn = dn.rdn(); 096 if (rdn == null) { 097 throw new IllegalArgumentException("Unabled to decode the DN string: \"" 098 + s + "\""); 099 } 100 101 ByteString av = rdn.getAttributeValue(0); 102 if (av == null) { 103 throw new IllegalArgumentException("Unabled to decode the DN string: \"" 104 + s + "\""); 105 } 106 107 String name = av.toString(); 108 109 // Check that the DN was valid. 110 DN expected = p.child(rd, name).toDN(); 111 if (!dn.equals(expected)) { 112 throw new IllegalArgumentException("Unabled to decode the DN string: \"" 113 + s + "\""); 114 } 115 116 return new Reference<>(p, rd, name); 117 } 118 119 120 121 /** 122 * Parses a name as a reference using the provided managed object 123 * path and relation definition. 124 * 125 * @param <C> 126 * The type of client managed object configuration that 127 * this reference refers to. 128 * @param <S> 129 * The type of server managed object configuration that 130 * this reference refers to. 131 * @param p 132 * The path of the referenced managed object's parent. 133 * @param rd 134 * The instantiable relation in the parent which contains 135 * the referenced managed object. 136 * @param s 137 * The name of the referenced managed object. 138 * @return Returns the new reference based on the provided name. 139 * @throws IllegalArgumentException 140 * If the relation is not associated with the provided 141 * parent's definition, or if the provided name is empty. 142 */ 143 public static <C extends ConfigurationClient, S extends Configuration> 144 Reference<C, S> parseName( 145 ManagedObjectPath<?, ?> p, InstantiableRelationDefinition<C, S> rd, 146 String s) throws IllegalArgumentException { 147 // Sanity checks. 148 AbstractManagedObjectDefinition<?, ?> d = p.getManagedObjectDefinition(); 149 RelationDefinition<?, ?> tmp = d.getRelationDefinition(rd.getName()); 150 if (tmp != rd) { 151 throw new IllegalArgumentException("The relation \"" + rd.getName() 152 + "\" is not associated with the definition \"" + d.getName() + "\""); 153 } 154 155 if (s.trim().length() == 0) { 156 throw new IllegalArgumentException("Empty names are not allowed"); 157 } 158 159 return new Reference<>(p, rd, s); 160 } 161 162 /** The name of the referenced managed object. */ 163 private final String name; 164 165 /** The path of the referenced managed object. */ 166 private final ManagedObjectPath<C, S> path; 167 168 /** 169 * The instantiable relation in the parent which contains the 170 * referenced managed object. 171 */ 172 private final InstantiableRelationDefinition<C, S> relation; 173 174 175 176 /** Private constructor. */ 177 private Reference(ManagedObjectPath<?, ?> parent, 178 InstantiableRelationDefinition<C, S> relation, String name) 179 throws IllegalArgumentException { 180 this.relation = relation; 181 this.name = name; 182 this.path = parent.child(relation, name); 183 } 184 185 186 187 /** 188 * Gets the name of the referenced managed object. 189 * 190 * @return Returns the name of the referenced managed object. 191 */ 192 public String getName() { 193 return name; 194 } 195 196 197 198 /** 199 * Gets the normalized name of the referenced managed object. 200 * 201 * @return Returns the normalized name of the referenced managed 202 * object. 203 */ 204 public String getNormalizedName() { 205 PropertyDefinition<?> pd = relation.getNamingPropertyDefinition(); 206 return normalizeName(pd); 207 } 208 209 210 211 /** 212 * Gets the DN of the referenced managed object. 213 * 214 * @return Returns the DN of the referenced managed object. 215 */ 216 public DN toDN() { 217 return path.toDN(); 218 } 219 220 221 222 /** {@inheritDoc} */ 223 public String toString() { 224 return name; 225 } 226 227 228 229 /** 230 * Normalize a value using the specified naming property definition 231 * if defined. 232 */ 233 private <T> String normalizeName(PropertyDefinition<T> pd) { 234 if (pd != null) { 235 try { 236 T tvalue = pd.decodeValue(name); 237 return pd.normalizeValue(tvalue); 238 } catch (PropertyException e) { 239 // Fall through to default normalization. 240 } 241 } 242 243 // FIXME: should really use directory string normalizer. 244 String s = name.trim().replaceAll(" +", " "); 245 return StaticUtils.toLowerCase(s); 246 } 247}