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