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-2009 Sun Microsystems, Inc. 015 * Portions Copyright 2015-2016 ForgeRock AS. 016 */ 017 018package org.forgerock.opendj.config; 019 020import org.forgerock.util.Reject; 021 022import java.util.EnumSet; 023import java.util.Locale; 024import java.util.MissingResourceException; 025import java.util.Set; 026 027import org.forgerock.i18n.LocalizableMessage; 028 029/** 030 * Relation definitions define relationships between types of managed objects. 031 * In addition they define the ownership model: 032 * <ul> 033 * <li>composition - referenced managed objects are owned by the parent managed 034 * object and are deleted when the parent is deleted 035 * <li>aggregation - referenced managed objects are not owned by the parent 036 * managed object. Instead they are shared by other managed objects. 037 * </ul> 038 * Relations define how clients interact with the configuration. For example, 039 * clients manage aggregated managed objects in a shared location and attach 040 * them to parent managed objects. Composed managed objects, on the other hand, 041 * would be created directly beneath the parent managed object and destroyed 042 * with it too. 043 * <p> 044 * Within the server, listeners can choose to request notification of managed 045 * objects being added or removed from relations. 046 * <p> 047 * In LDAP, compositions are represented as follows: 048 * <ul> 049 * <li>singleton relations (one to one): a referenced managed object is 050 * represented using a child entry directly beneath the parent 051 * <li>optional relations (one to zero or one): a referenced managed object is 052 * represented using a child entry directly beneath the parent 053 * <li>instantiable relations (one to many): the relation is represented using a 054 * child entry directly beneath the parent. Referenced managed objects are 055 * represented using child entries of this "relation entry" and are named by the 056 * user 057 * <li>set relations (one to many): the relation is represented using a child 058 * entry directly beneath the parent. Referenced managed objects are represented 059 * using child entries of this "relation entry" whose name is the type of the 060 * managed object. 061 * </ul> 062 * Whereas, aggregations are represented by storing the DNs of the referenced 063 * managed objects in an attribute of the aggregating managed object. 064 * 065 * @param <C> 066 * The type of client managed object configuration that this relation 067 * definition refers to. 068 * @param <S> 069 * The type of server managed object configuration that this relation 070 * definition refers to. 071 */ 072public abstract class RelationDefinition<C extends ConfigurationClient, S extends Configuration> { 073 074 /** 075 * An interface for incrementally constructing relation definitions. 076 * 077 * @param <C> 078 * The type of client managed object configuration that this 079 * relation definition refers to. 080 * @param <S> 081 * The type of server managed object configuration that this 082 * relation definition refers to. 083 * @param <D> 084 * The type of relation definition constructed by this builder. 085 */ 086 protected static abstract class AbstractBuilder<C extends ConfigurationClient, S extends Configuration, 087 D extends RelationDefinition<C, S>> { 088 089 /** Common fields. */ 090 private final Common<C, S> common; 091 092 /** 093 * Create a property definition builder. 094 * 095 * @param pd 096 * The parent managed object definition. 097 * @param name 098 * The name of the relation. 099 * @param cd 100 * The child managed object definition. 101 */ 102 protected AbstractBuilder(AbstractManagedObjectDefinition<?, ?> pd, String name, 103 AbstractManagedObjectDefinition<C, S> cd) { 104 this.common = new Common<>(pd, name, cd); 105 } 106 107 /** 108 * Construct a relation definition based on the properties of this 109 * builder. 110 * 111 * @return The new relation definition. 112 */ 113 public final D getInstance() { 114 return buildInstance(common); 115 } 116 117 /** 118 * Add a relation definition option. 119 * 120 * @param option 121 * The relation option. 122 */ 123 public final void setOption(RelationOption option) { 124 Reject.ifNull(option); 125 common.options.add(option); 126 } 127 128 /** 129 * Build a relation definition based on the properties of this builder. 130 * 131 * @param common 132 * The common fields of the new relation definition. 133 * @return The new relation definition. 134 */ 135 protected abstract D buildInstance(Common<C, S> common); 136 } 137 138 /** 139 * Opaque structure containing fields common to all relation definition 140 * types. 141 * 142 * @param <C> 143 * The type of client managed object configuration that this 144 * relation definition refers to. 145 * @param <S> 146 * The type of server managed object configuration that this 147 * relation definition refers to. 148 */ 149 protected static final class Common<C extends ConfigurationClient, S extends Configuration> { 150 151 /** The definition of the child managed object. */ 152 private final AbstractManagedObjectDefinition<C, S> cd; 153 154 /** The name of the relation. */ 155 private final String name; 156 157 /** Options applicable to this definition. */ 158 private final Set<RelationOption> options; 159 160 /** The definition of the parent managed object. */ 161 private final AbstractManagedObjectDefinition<?, ?> pd; 162 163 /** Private constructor. */ 164 private Common(AbstractManagedObjectDefinition<?, ?> pd, String name, 165 AbstractManagedObjectDefinition<C, S> cd) { 166 this.name = name; 167 this.pd = pd; 168 this.cd = cd; 169 this.options = EnumSet.noneOf(RelationOption.class); 170 } 171 } 172 173 /** Common fields. */ 174 private final Common<C, S> common; 175 176 /** 177 * Create a new managed object relation definition with the specified common 178 * fields. 179 * 180 * @param common 181 * The common fields of the new relation definition. 182 */ 183 protected RelationDefinition(Common<C, S> common) { 184 this.common = common; 185 } 186 187 /** 188 * Apply a visitor to this relation definition. 189 * 190 * @param <R> 191 * The return type of the visitor's methods. 192 * @param <P> 193 * The type of the additional parameters to the visitor's 194 * methods. 195 * @param v 196 * The relation definition visitor. 197 * @param p 198 * Optional additional visitor parameter. 199 * @return Returns a result as specified by the visitor. 200 */ 201 public abstract <R, P> R accept(RelationDefinitionVisitor<R, P> v, P p); 202 203 /** 204 * Get the definition of the child managed object. 205 * 206 * @return Returns the definition of the child managed object. 207 */ 208 public final AbstractManagedObjectDefinition<C, S> getChildDefinition() { 209 return common.cd; 210 } 211 212 /** 213 * Gets the optional description of this relation definition in the default 214 * locale. 215 * 216 * @return Returns the description of this relation definition in the 217 * default locale, or <code>null</code> if there is no description. 218 */ 219 public final LocalizableMessage getDescription() { 220 return getDescription(Locale.getDefault()); 221 } 222 223 /** 224 * Gets the optional description of this relation definition in the 225 * specified locale. 226 * 227 * @param locale 228 * The locale. 229 * @return Returns the description of this relation definition in the 230 * specified locale, or <code>null</code> if there is no 231 * description. 232 */ 233 public final LocalizableMessage getDescription(Locale locale) { 234 try { 235 String property = "relation." + common.name + ".description"; 236 return ManagedObjectDefinitionI18NResource.getInstance().getMessage(getParentDefinition(), property, 237 locale); 238 } catch (MissingResourceException e) { 239 return null; 240 } 241 } 242 243 /** 244 * Get the name of the relation. 245 * 246 * @return Returns the name of the relation. 247 */ 248 public final String getName() { 249 return common.name; 250 } 251 252 /** 253 * Get the definition of the parent managed object. 254 * 255 * @return Returns the definition of the parent managed object. 256 */ 257 public final AbstractManagedObjectDefinition<?, ?> getParentDefinition() { 258 return common.pd; 259 } 260 261 /** 262 * Gets the synopsis of this relation definition in the default locale. 263 * 264 * @return Returns the synopsis of this relation definition in the default 265 * locale. 266 */ 267 public final LocalizableMessage getSynopsis() { 268 return getSynopsis(Locale.getDefault()); 269 } 270 271 /** 272 * Gets the synopsis of this relation definition in the specified locale. 273 * 274 * @param locale 275 * The locale. 276 * @return Returns the synopsis of this relation definition in the specified 277 * locale. 278 */ 279 public final LocalizableMessage getSynopsis(Locale locale) { 280 String property = "relation." + common.name + ".synopsis"; 281 return ManagedObjectDefinitionI18NResource.getInstance().getMessage(getParentDefinition(), property, locale); 282 } 283 284 /** 285 * Gets the user friendly name of this relation definition in the default 286 * locale. 287 * 288 * @return Returns the user friendly name of this relation definition in the 289 * default locale. 290 */ 291 public final LocalizableMessage getUserFriendlyName() { 292 return getUserFriendlyName(Locale.getDefault()); 293 } 294 295 /** 296 * Gets the user friendly name of this relation definition in the specified 297 * locale. 298 * 299 * @param locale 300 * The locale. 301 * @return Returns the user friendly name of this relation definition in the 302 * specified locale. 303 */ 304 public final LocalizableMessage getUserFriendlyName(Locale locale) { 305 String property = "relation." + common.name + ".user-friendly-name"; 306 return ManagedObjectDefinitionI18NResource.getInstance().getMessage(getParentDefinition(), property, locale); 307 } 308 309 /** 310 * Check if the specified option is set for this relation definition. 311 * 312 * @param option 313 * The option to test. 314 * @return Returns <code>true</code> if the option is set, or 315 * <code>false</code> otherwise. 316 */ 317 public final boolean hasOption(RelationOption option) { 318 return common.options.contains(option); 319 } 320 321 @Override 322 public final String toString() { 323 StringBuilder builder = new StringBuilder(); 324 toString(builder); 325 return builder.toString(); 326 } 327 328 /** 329 * Append a string representation of the managed object relation to the 330 * provided string builder. 331 * 332 * @param builder 333 * The string builder where the string representation should be 334 * appended. 335 */ 336 public abstract void toString(StringBuilder builder); 337 338 /** 339 * Performs any run-time initialization required by this relation 340 * definition. This may include resolving managed object paths and property 341 * names. 342 * 343 * @throws Exception 344 * If this relation definition could not be initialized. 345 */ 346 protected void initialize() throws Exception { 347 // No implementation required. 348 } 349}