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