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