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 2015 ForgeRock AS. 026 */ 027package org.forgerock.opendj.config; 028 029import static com.forgerock.opendj.util.StaticUtils.*; 030 031import org.forgerock.opendj.ldap.DN; 032import org.forgerock.opendj.ldap.RDN; 033 034/** 035 * A reference to another managed object. 036 * 037 * @param <C> 038 * The type of client managed object configuration that this 039 * reference refers to. 040 * @param <S> 041 * The type of server managed object configuration that this 042 * reference refers to. 043 */ 044public final class Reference<C extends ConfigurationClient, S extends Configuration> { 045 046 /** 047 * Parses a DN string value as a reference using the provided managed object 048 * path and relation definition. 049 * 050 * @param <C> 051 * The type of client managed object configuration that this 052 * reference refers to. 053 * @param <S> 054 * The type of server managed object configuration that this 055 * reference refers to. 056 * @param path 057 * The path of the referenced managed object's parent. 058 * @param relationDef 059 * The instantiable relation in the parent which contains the 060 * referenced managed object. 061 * @param dnAsString 062 * The DN string value. 063 * @return Returns the new reference based on the provided DN string value. 064 * @throws IllegalArgumentException 065 * If the DN string value could not be decoded as a DN or if the 066 * provided DN did not correspond to the provided path and 067 * relation. 068 */ 069 public static <C extends ConfigurationClient, S extends Configuration> Reference<C, S> parseDN( 070 ManagedObjectPath<?, ?> path, InstantiableRelationDefinition<C, S> relationDef, String dnAsString) { 071 AbstractManagedObjectDefinition<?, ?> definition = path.getManagedObjectDefinition(); 072 RelationDefinition<?, ?> tmp = definition.getRelationDefinition(relationDef.getName()); 073 if (tmp != relationDef) { 074 // TODO : i18n ? 075 throw new IllegalArgumentException("The relation \"" + relationDef.getName() 076 + "\" is not associated with the definition \"" + definition.getName() + "\""); 077 } 078 079 DN dn = DN.valueOf(dnAsString); 080 RDN rdn = dn.rdn(); 081 if (rdn == null) { 082 // TODO : i18n ? 083 throw new IllegalArgumentException("Unabled to decode the DN string: \"" + dnAsString + "\""); 084 } 085 086 // Check that the DN was valid. 087 String name = rdn.getFirstAVA().getAttributeValue().toString(); 088 DN expected = path.child(relationDef, name).toDN(); 089 if (!dn.equals(expected)) { 090 // TODO : i18n ? 091 throw new IllegalArgumentException("Unabled to decode the DN string: \"" + dnAsString + "\""); 092 } 093 094 return new Reference<>(path, relationDef, name); 095 } 096 097 /** 098 * Parses a name as a reference using the provided managed object path and 099 * relation definition. 100 * 101 * @param <C> 102 * The type of client managed object configuration that this 103 * reference refers to. 104 * @param <S> 105 * The type of server managed object configuration that this 106 * reference refers to. 107 * @param p 108 * The path of the referenced managed object's parent. 109 * @param rd 110 * The instantiable relation in the parent which contains the 111 * referenced managed object. 112 * @param s 113 * The name of the referenced managed object. 114 * @return Returns the new reference based on the provided name. 115 * @throws IllegalArgumentException 116 * If the relation is not associated with the provided parent's 117 * definition, or if the provided name is empty. 118 */ 119 public static <C extends ConfigurationClient, S extends Configuration> Reference<C, S> parseName( 120 ManagedObjectPath<?, ?> p, InstantiableRelationDefinition<C, S> rd, String s) { 121 // Sanity checks. 122 AbstractManagedObjectDefinition<?, ?> d = p.getManagedObjectDefinition(); 123 RelationDefinition<?, ?> tmp = d.getRelationDefinition(rd.getName()); 124 if (tmp != rd) { 125 throw new IllegalArgumentException("The relation \"" + rd.getName() 126 + "\" is not associated with the definition \"" + d.getName() + "\""); 127 } 128 129 if (s.trim().length() == 0) { 130 throw new IllegalArgumentException("Empty names are not allowed"); 131 } 132 133 return new Reference<>(p, rd, s); 134 } 135 136 /** The name of the referenced managed object. */ 137 private final String name; 138 139 /** The path of the referenced managed object. */ 140 private final ManagedObjectPath<C, S> path; 141 142 /** 143 * The instantiable relation in the parent which contains the 144 * referenced managed object. 145 */ 146 private final InstantiableRelationDefinition<C, S> relation; 147 148 /** Private constructor. */ 149 private Reference(ManagedObjectPath<?, ?> parent, InstantiableRelationDefinition<C, S> relation, String name) { 150 this.relation = relation; 151 this.name = name; 152 this.path = parent.child(relation, name); 153 } 154 155 /** 156 * Gets the name of the referenced managed object. 157 * 158 * @return Returns the name of the referenced managed object. 159 */ 160 public String getName() { 161 return name; 162 } 163 164 /** 165 * Gets the normalized name of the referenced managed object. 166 * 167 * @return Returns the normalized name of the referenced managed object. 168 */ 169 public String getNormalizedName() { 170 PropertyDefinition<?> pd = relation.getNamingPropertyDefinition(); 171 return normalizeName(pd); 172 } 173 174 /** 175 * Gets the DN of the referenced managed object. 176 * 177 * @return Returns the DN of the referenced managed object. 178 */ 179 public DN toDN() { 180 return path.toDN(); 181 } 182 183 /** {@inheritDoc} */ 184 public String toString() { 185 return name; 186 } 187 188 /** 189 * Normalize a value using the specified naming property definition 190 * if defined. 191 */ 192 private <T> String normalizeName(PropertyDefinition<T> pd) { 193 if (pd != null) { 194 try { 195 // TODO : is it correct to have no validation ? 196 T tvalue = pd.decodeValue(name); 197 return pd.normalizeValue(tvalue); 198 } catch (PropertyException e) { 199 // Fall through to default normalization. 200 } 201 } 202 203 // FIXME: should really use directory string normalizer. 204 String s = name.trim().replaceAll(" +", " "); 205 return toLowerCase(s); 206 } 207}