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 2014-2015 ForgeRock AS 026 */ 027package org.forgerock.opendj.config.client.spi; 028 029import java.util.Collection; 030import java.util.Collections; 031import java.util.LinkedList; 032import java.util.List; 033import java.util.Set; 034import java.util.SortedSet; 035import java.util.TreeSet; 036 037import org.forgerock.i18n.LocalizableMessage; 038import org.forgerock.opendj.config.AbstractManagedObjectDefinition; 039import org.forgerock.opendj.config.Configuration; 040import org.forgerock.opendj.config.ConfigurationClient; 041import org.forgerock.opendj.config.Constraint; 042import org.forgerock.opendj.config.PropertyException; 043import org.forgerock.opendj.config.DefaultManagedObject; 044import org.forgerock.opendj.config.DefinitionDecodingException; 045import org.forgerock.opendj.config.InstantiableRelationDefinition; 046import org.forgerock.opendj.config.ManagedObjectAlreadyExistsException; 047import org.forgerock.opendj.config.ManagedObjectDefinition; 048import org.forgerock.opendj.config.ManagedObjectNotFoundException; 049import org.forgerock.opendj.config.ManagedObjectPath; 050import org.forgerock.opendj.config.OptionalRelationDefinition; 051import org.forgerock.opendj.config.PropertyDefinition; 052import org.forgerock.opendj.config.PropertyOption; 053import org.forgerock.opendj.config.RelationDefinition; 054import org.forgerock.opendj.config.RelationDefinitionVisitor; 055import org.forgerock.opendj.config.SetRelationDefinition; 056import org.forgerock.opendj.config.SingletonRelationDefinition; 057import org.forgerock.opendj.config.DefinitionDecodingException.Reason; 058import org.forgerock.opendj.config.client.ClientConstraintHandler; 059import org.forgerock.opendj.config.client.ConcurrentModificationException; 060import org.forgerock.opendj.config.client.IllegalManagedObjectNameException; 061import org.forgerock.opendj.config.client.ManagedObject; 062import org.forgerock.opendj.config.client.ManagedObjectDecodingException; 063import org.forgerock.opendj.config.client.ManagementContext; 064import org.forgerock.opendj.config.client.MissingMandatoryPropertiesException; 065import org.forgerock.opendj.config.client.OperationRejectedException; 066import org.forgerock.opendj.config.client.OperationRejectedException.OperationType; 067import org.forgerock.opendj.ldap.LdapException; 068 069/** 070 * An abstract managed object implementation. 071 * 072 * @param <T> 073 * The type of client configuration represented by the client managed 074 * object. 075 */ 076public abstract class AbstractManagedObject<T extends ConfigurationClient> implements ManagedObject<T> { 077 078 /** 079 * Creates any default managed objects associated with a relation 080 * definition. 081 */ 082 private final class DefaultManagedObjectFactory implements RelationDefinitionVisitor<Void, Void> { 083 084 /** Possible exceptions. */ 085 private ManagedObjectAlreadyExistsException moaee; 086 private MissingMandatoryPropertiesException mmpe; 087 private ConcurrentModificationException cme; 088 private OperationRejectedException ore; 089 private LdapException ere; 090 091 /** {@inheritDoc} */ 092 @Override 093 public <C extends ConfigurationClient, S extends Configuration> Void visitInstantiable( 094 InstantiableRelationDefinition<C, S> rd, Void p) { 095 for (String name : rd.getDefaultManagedObjectNames()) { 096 DefaultManagedObject<? extends C, ? extends S> dmo = rd.getDefaultManagedObject(name); 097 ManagedObjectDefinition<? extends C, ? extends S> d = dmo.getManagedObjectDefinition(); 098 ManagedObject<? extends C> child; 099 try { 100 child = createChild(rd, d, name, null); 101 } catch (IllegalManagedObjectNameException e) { 102 // This should not happen. 103 throw new RuntimeException(e); 104 } 105 createDefaultManagedObject(d, child, dmo); 106 } 107 return null; 108 } 109 110 /** {@inheritDoc} */ 111 @Override 112 public <C extends ConfigurationClient, S extends Configuration> Void visitOptional( 113 OptionalRelationDefinition<C, S> rd, Void p) { 114 if (rd.getDefaultManagedObject() != null) { 115 DefaultManagedObject<? extends C, ? extends S> dmo = rd.getDefaultManagedObject(); 116 ManagedObjectDefinition<? extends C, ? extends S> d = dmo.getManagedObjectDefinition(); 117 ManagedObject<? extends C> child = createChild(rd, d, null); 118 createDefaultManagedObject(d, child, dmo); 119 } 120 return null; 121 } 122 123 /** {@inheritDoc} */ 124 @Override 125 public <C extends ConfigurationClient, S extends Configuration> Void visitSingleton( 126 SingletonRelationDefinition<C, S> rd, Void p) { 127 // Do nothing - not possible to create singletons 128 // dynamically. 129 return null; 130 } 131 132 /** {@inheritDoc} */ 133 @Override 134 public <C extends ConfigurationClient, S extends Configuration> Void visitSet(SetRelationDefinition<C, S> rd, 135 Void p) { 136 for (String name : rd.getDefaultManagedObjectNames()) { 137 DefaultManagedObject<? extends C, ? extends S> dmo = rd.getDefaultManagedObject(name); 138 ManagedObjectDefinition<? extends C, ? extends S> d = dmo.getManagedObjectDefinition(); 139 ManagedObject<? extends C> child = createChild(rd, d, null); 140 createDefaultManagedObject(d, child, dmo); 141 } 142 return null; 143 } 144 145 /** Create the child managed object. */ 146 private void createDefaultManagedObject(ManagedObjectDefinition<?, ?> d, ManagedObject<?> child, 147 DefaultManagedObject<?, ?> dmo) { 148 for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) { 149 setPropertyValues(child, pd, dmo); 150 } 151 152 try { 153 child.commit(); 154 } catch (ManagedObjectAlreadyExistsException e) { 155 moaee = e; 156 } catch (MissingMandatoryPropertiesException e) { 157 mmpe = e; 158 } catch (ConcurrentModificationException e) { 159 cme = e; 160 } catch (OperationRejectedException e) { 161 ore = e; 162 } catch (LdapException e) { 163 ere = e; 164 } 165 } 166 167 /** 168 * Creates the default managed objects associated with the provided 169 * relation definition. 170 * 171 * @param rd 172 * The relation definition. 173 */ 174 private void createDefaultManagedObjects(RelationDefinition<?, ?> rd) throws LdapException, 175 ConcurrentModificationException, MissingMandatoryPropertiesException, 176 ManagedObjectAlreadyExistsException, OperationRejectedException { 177 rd.accept(this, null); 178 179 if (ere != null) { 180 throw ere; 181 } else if (cme != null) { 182 throw cme; 183 } else if (mmpe != null) { 184 throw mmpe; 185 } else if (moaee != null) { 186 throw moaee; 187 } else if (ore != null) { 188 throw ore; 189 } 190 } 191 192 /** Set property values. */ 193 private <P> void setPropertyValues(ManagedObject<?> mo, PropertyDefinition<P> pd, 194 DefaultManagedObject<?, ?> dmo) { 195 mo.setPropertyValues(pd, dmo.getPropertyValues(pd)); 196 } 197 } 198 199 /** 200 * The managed object definition associated with this managed 201 * object. 202 */ 203 private final ManagedObjectDefinition<T, ? extends Configuration> definition; 204 205 /** 206 * Indicates whether or not this managed object exists on the server 207 * (false means the managed object is new and has not been 208 * committed). 209 */ 210 private boolean existsOnServer; 211 212 /** Optional naming property definition. */ 213 private final PropertyDefinition<?> namingPropertyDefinition; 214 215 /** The path associated with this managed object. */ 216 private ManagedObjectPath<T, ? extends Configuration> path; 217 218 /** The managed object's properties. */ 219 private final PropertySet properties; 220 221 /** 222 * Creates a new abstract managed object. 223 * 224 * @param d 225 * The managed object's definition. 226 * @param path 227 * The managed object's path. 228 * @param properties 229 * The managed object's properties. 230 * @param existsOnServer 231 * Indicates whether or not the managed object exists on the 232 * server (false means the managed object is new and has not been 233 * committed). 234 * @param namingPropertyDefinition 235 * Optional naming property definition. 236 */ 237 protected AbstractManagedObject(ManagedObjectDefinition<T, ? extends Configuration> d, 238 ManagedObjectPath<T, ? extends Configuration> path, PropertySet properties, boolean existsOnServer, 239 PropertyDefinition<?> namingPropertyDefinition) { 240 this.definition = d; 241 this.path = path; 242 this.properties = properties; 243 this.existsOnServer = existsOnServer; 244 this.namingPropertyDefinition = namingPropertyDefinition; 245 } 246 247 /** {@inheritDoc} */ 248 @Override 249 public final void commit() throws ManagedObjectAlreadyExistsException, MissingMandatoryPropertiesException, 250 ConcurrentModificationException, OperationRejectedException, LdapException { 251 // First make sure all mandatory properties are defined. 252 List<PropertyException> exceptions = new LinkedList<>(); 253 254 for (PropertyDefinition<?> pd : definition.getAllPropertyDefinitions()) { 255 Property<?> p = getProperty(pd); 256 if (pd.hasOption(PropertyOption.MANDATORY) && p.getEffectiveValues().isEmpty()) { 257 exceptions.add(PropertyException.propertyIsMandatoryException(pd)); 258 } 259 } 260 261 if (!exceptions.isEmpty()) { 262 throw new MissingMandatoryPropertiesException(definition.getUserFriendlyName(), exceptions, 263 !existsOnServer); 264 } 265 266 // Now enforce any constraints. 267 List<LocalizableMessage> messages = new LinkedList<>(); 268 boolean isAcceptable = true; 269 ManagementContext context = getDriver().getManagementContext(); 270 271 for (Constraint constraint : definition.getAllConstraints()) { 272 for (ClientConstraintHandler handler : constraint.getClientConstraintHandlers()) { 273 if (existsOnServer) { 274 if (!handler.isModifyAcceptable(context, this, messages)) { 275 isAcceptable = false; 276 } 277 } else { 278 if (!handler.isAddAcceptable(context, this, messages)) { 279 isAcceptable = false; 280 } 281 } 282 } 283 if (!isAcceptable) { 284 break; 285 } 286 } 287 288 if (!isAcceptable) { 289 if (existsOnServer) { 290 throw new OperationRejectedException(OperationType.MODIFY, definition.getUserFriendlyName(), messages); 291 } else { 292 throw new OperationRejectedException(OperationType.CREATE, definition.getUserFriendlyName(), messages); 293 } 294 } 295 296 // Commit the managed object. 297 if (existsOnServer) { 298 modifyExistingManagedObject(); 299 } else { 300 addNewManagedObject(); 301 } 302 303 // Make all pending property values active. 304 properties.commit(); 305 306 // If the managed object was created make sure that any default 307 // subordinate managed objects are also created. 308 if (!existsOnServer) { 309 DefaultManagedObjectFactory factory = new DefaultManagedObjectFactory(); 310 for (RelationDefinition<?, ?> rd : definition.getAllRelationDefinitions()) { 311 factory.createDefaultManagedObjects(rd); 312 } 313 314 existsOnServer = true; 315 } 316 } 317 318 /** {@inheritDoc} */ 319 @Override 320 public final <C extends ConfigurationClient, S extends Configuration, C1 extends C> ManagedObject<C1> createChild( 321 InstantiableRelationDefinition<C, S> r, ManagedObjectDefinition<C1, ? extends S> d, String name, 322 Collection<PropertyException> exceptions) throws IllegalManagedObjectNameException { 323 validateRelationDefinition(r); 324 325 // Empty names are not allowed. 326 if (name.trim().length() == 0) { 327 throw new IllegalManagedObjectNameException(name); 328 } 329 330 // If the relation uses a naming property definition then it must 331 // be a valid value. 332 PropertyDefinition<?> pd = r.getNamingPropertyDefinition(); 333 if (pd != null) { 334 try { 335 pd.decodeValue(name); 336 } catch (PropertyException e) { 337 throw new IllegalManagedObjectNameException(name, pd); 338 } 339 } 340 341 ManagedObjectPath<C1, ? extends S> childPath = path.child(r, d, name); 342 return createNewManagedObject(d, childPath, pd, name, exceptions); 343 } 344 345 /** {@inheritDoc} */ 346 @Override 347 public final <C extends ConfigurationClient, S extends Configuration, C1 extends C> ManagedObject<C1> createChild( 348 OptionalRelationDefinition<C, S> r, ManagedObjectDefinition<C1, ? extends S> d, 349 Collection<PropertyException> exceptions) { 350 validateRelationDefinition(r); 351 ManagedObjectPath<C1, ? extends S> childPath = path.child(r, d); 352 return createNewManagedObject(d, childPath, null, null, exceptions); 353 } 354 355 /** {@inheritDoc} */ 356 @Override 357 public final <C extends ConfigurationClient, S extends Configuration, C1 extends C> ManagedObject<C1> createChild( 358 SetRelationDefinition<C, S> r, ManagedObjectDefinition<C1, ? extends S> d, 359 Collection<PropertyException> exceptions) { 360 validateRelationDefinition(r); 361 362 ManagedObjectPath<C1, ? extends S> childPath = path.child(r, d); 363 return createNewManagedObject(d, childPath, null, null, exceptions); 364 } 365 366 /** {@inheritDoc} */ 367 @Override 368 public final <C extends ConfigurationClient, S extends Configuration> ManagedObject<? extends C> getChild( 369 InstantiableRelationDefinition<C, S> r, String name) throws DefinitionDecodingException, 370 ManagedObjectDecodingException, ManagedObjectNotFoundException, ConcurrentModificationException, 371 LdapException { 372 validateRelationDefinition(r); 373 ensureThisManagedObjectExists(); 374 Driver ctx = getDriver(); 375 return ctx.getManagedObject(path.child(r, name)); 376 } 377 378 /** {@inheritDoc} */ 379 @Override 380 public final <C extends ConfigurationClient, S extends Configuration> ManagedObject<? extends C> getChild( 381 OptionalRelationDefinition<C, S> r) throws DefinitionDecodingException, ManagedObjectDecodingException, 382 ManagedObjectNotFoundException, ConcurrentModificationException, LdapException { 383 validateRelationDefinition(r); 384 ensureThisManagedObjectExists(); 385 Driver ctx = getDriver(); 386 return ctx.getManagedObject(path.child(r)); 387 } 388 389 /** {@inheritDoc} */ 390 @Override 391 public final <C extends ConfigurationClient, S extends Configuration> ManagedObject<? extends C> getChild( 392 SingletonRelationDefinition<C, S> r) throws DefinitionDecodingException, ManagedObjectDecodingException, 393 ManagedObjectNotFoundException, ConcurrentModificationException, LdapException { 394 validateRelationDefinition(r); 395 ensureThisManagedObjectExists(); 396 Driver ctx = getDriver(); 397 return ctx.getManagedObject(path.child(r)); 398 } 399 400 /** {@inheritDoc} */ 401 @Override 402 public final <C extends ConfigurationClient, S extends Configuration> ManagedObject<? extends C> getChild( 403 SetRelationDefinition<C, S> r, String name) throws DefinitionDecodingException, 404 ManagedObjectDecodingException, ManagedObjectNotFoundException, ConcurrentModificationException, 405 LdapException { 406 validateRelationDefinition(r); 407 ensureThisManagedObjectExists(); 408 Driver ctx = getDriver(); 409 410 AbstractManagedObjectDefinition<C, S> d = r.getChildDefinition(); 411 AbstractManagedObjectDefinition<? extends C, ? extends S> cd; 412 413 try { 414 cd = d.getChild(name); 415 } catch (IllegalArgumentException e) { 416 // Unrecognized definition name - report this as a decoding 417 // exception. 418 throw new DefinitionDecodingException(d, Reason.WRONG_TYPE_INFORMATION); 419 } 420 421 return ctx.getManagedObject(path.child(r, cd)); 422 } 423 424 /** {@inheritDoc} */ 425 @Override 426 public final T getConfiguration() { 427 return definition.createClientConfiguration(this); 428 } 429 430 /** {@inheritDoc} */ 431 @Override 432 public final ManagedObjectDefinition<T, ? extends Configuration> getManagedObjectDefinition() { 433 return definition; 434 } 435 436 /** {@inheritDoc} */ 437 @Override 438 public final ManagedObjectPath<T, ? extends Configuration> getManagedObjectPath() { 439 return path; 440 } 441 442 /** {@inheritDoc} */ 443 @Override 444 public final <P> SortedSet<P> getPropertyDefaultValues(PropertyDefinition<P> pd) { 445 return new TreeSet<>(getProperty(pd).getDefaultValues()); 446 } 447 448 /** {@inheritDoc} */ 449 @Override 450 public final <P> P getPropertyValue(PropertyDefinition<P> pd) { 451 Set<P> values = getProperty(pd).getEffectiveValues(); 452 if (!values.isEmpty()) { 453 return values.iterator().next(); 454 } 455 return null; 456 } 457 458 /** {@inheritDoc} */ 459 @Override 460 public final <P> SortedSet<P> getPropertyValues(PropertyDefinition<P> pd) { 461 return new TreeSet<>(getProperty(pd).getEffectiveValues()); 462 } 463 464 /** {@inheritDoc} */ 465 @Override 466 public final <C extends ConfigurationClient, S extends Configuration> boolean hasChild( 467 OptionalRelationDefinition<C, S> r) throws ConcurrentModificationException, LdapException { 468 validateRelationDefinition(r); 469 Driver ctx = getDriver(); 470 try { 471 return ctx.managedObjectExists(path.child(r)); 472 } catch (ManagedObjectNotFoundException e) { 473 throw new ConcurrentModificationException(); 474 } 475 } 476 477 /** {@inheritDoc} */ 478 @Override 479 public final boolean isPropertyPresent(PropertyDefinition<?> pd) { 480 return !getProperty(pd).isEmpty(); 481 } 482 483 /** {@inheritDoc} */ 484 @Override 485 public final <C extends ConfigurationClient, S extends Configuration> String[] listChildren( 486 InstantiableRelationDefinition<C, S> r) throws ConcurrentModificationException, LdapException { 487 return listChildren(r, r.getChildDefinition()); 488 } 489 490 /** {@inheritDoc} */ 491 @Override 492 public final <C extends ConfigurationClient, S extends Configuration> String[] listChildren( 493 InstantiableRelationDefinition<C, S> r, AbstractManagedObjectDefinition<? extends C, ? extends S> d) 494 throws ConcurrentModificationException, LdapException { 495 validateRelationDefinition(r); 496 Driver ctx = getDriver(); 497 try { 498 return ctx.listManagedObjects(path, r, d); 499 } catch (ManagedObjectNotFoundException e) { 500 throw new ConcurrentModificationException(); 501 } 502 } 503 504 /** {@inheritDoc} */ 505 @Override 506 public final <C extends ConfigurationClient, S extends Configuration> String[] listChildren( 507 SetRelationDefinition<C, S> r) throws ConcurrentModificationException, LdapException { 508 return listChildren(r, r.getChildDefinition()); 509 } 510 511 /** {@inheritDoc} */ 512 @Override 513 public final <C extends ConfigurationClient, S extends Configuration> String[] listChildren( 514 SetRelationDefinition<C, S> r, AbstractManagedObjectDefinition<? extends C, ? extends S> d) 515 throws ConcurrentModificationException, LdapException { 516 validateRelationDefinition(r); 517 Driver ctx = getDriver(); 518 try { 519 return ctx.listManagedObjects(path, r, d); 520 } catch (ManagedObjectNotFoundException e) { 521 throw new ConcurrentModificationException(); 522 } 523 } 524 525 /** {@inheritDoc} */ 526 @Override 527 public final <C extends ConfigurationClient, S extends Configuration> void removeChild( 528 InstantiableRelationDefinition<C, S> r, String name) throws ManagedObjectNotFoundException, 529 OperationRejectedException, ConcurrentModificationException, LdapException { 530 validateRelationDefinition(r); 531 Driver ctx = getDriver(); 532 boolean found; 533 534 try { 535 found = ctx.deleteManagedObject(path, r, name); 536 } catch (ManagedObjectNotFoundException e) { 537 throw new ConcurrentModificationException(); 538 } 539 540 if (!found) { 541 throw new ManagedObjectNotFoundException(); 542 } 543 } 544 545 /** {@inheritDoc} */ 546 @Override 547 public final <C extends ConfigurationClient, S extends Configuration> void removeChild( 548 OptionalRelationDefinition<C, S> r) throws ManagedObjectNotFoundException, OperationRejectedException, 549 ConcurrentModificationException, LdapException { 550 validateRelationDefinition(r); 551 Driver ctx = getDriver(); 552 boolean found; 553 554 try { 555 found = ctx.deleteManagedObject(path, r); 556 } catch (ManagedObjectNotFoundException e) { 557 throw new ConcurrentModificationException(); 558 } 559 560 if (!found) { 561 throw new ManagedObjectNotFoundException(); 562 } 563 } 564 565 /** {@inheritDoc} */ 566 @Override 567 public final <C extends ConfigurationClient, S extends Configuration> void removeChild( 568 SetRelationDefinition<C, S> r, String name) throws ManagedObjectNotFoundException, 569 OperationRejectedException, ConcurrentModificationException, LdapException { 570 validateRelationDefinition(r); 571 Driver ctx = getDriver(); 572 boolean found; 573 574 try { 575 found = ctx.deleteManagedObject(path, r, name); 576 } catch (ManagedObjectNotFoundException e) { 577 throw new ConcurrentModificationException(); 578 } 579 580 if (!found) { 581 throw new ManagedObjectNotFoundException(); 582 } 583 } 584 585 /** {@inheritDoc} */ 586 @Override 587 public final <P> void setPropertyValue(PropertyDefinition<P> pd, P value) { 588 if (value != null) { 589 setPropertyValues(pd, Collections.singleton(value)); 590 } else { 591 setPropertyValues(pd, Collections.<P> emptySet()); 592 } 593 } 594 595 /** {@inheritDoc} */ 596 @Override 597 public final <P> void setPropertyValues(PropertyDefinition<P> pd, Collection<P> values) { 598 if (pd.hasOption(PropertyOption.MONITORING)) { 599 throw PropertyException.propertyIsReadOnlyException(pd); 600 } 601 602 if (existsOnServer && pd.hasOption(PropertyOption.READ_ONLY)) { 603 throw PropertyException.propertyIsReadOnlyException(pd); 604 } 605 606 properties.setPropertyValues(pd, values); 607 608 // If this is a naming property then update the name. 609 if (pd.equals(namingPropertyDefinition)) { 610 // The property must be single-valued and mandatory. 611 String newName = pd.encodeValue(values.iterator().next()); 612 path = path.rename(newName); 613 } 614 } 615 616 /** {@inheritDoc} */ 617 @Override 618 public String toString() { 619 StringBuilder builder = new StringBuilder(); 620 621 builder.append("{ TYPE="); 622 builder.append(definition.getName()); 623 builder.append(", PATH=\""); 624 builder.append(path); 625 builder.append('\"'); 626 for (PropertyDefinition<?> pd : definition.getAllPropertyDefinitions()) { 627 builder.append(", "); 628 builder.append(pd.getName()); 629 builder.append('='); 630 builder.append(getPropertyValues(pd)); 631 } 632 builder.append(" }"); 633 634 return builder.toString(); 635 } 636 637 /** 638 * Adds this new managed object. 639 * 640 * @throws ManagedObjectAlreadyExistsException 641 * If the managed object cannot be added to the server because 642 * it already exists. 643 * @throws ConcurrentModificationException 644 * If the managed object's parent has been removed by another 645 * client. 646 * @throws OperationRejectedException 647 * If the managed object cannot be added due to some client-side 648 * or server-side constraint which cannot be satisfied. 649 * @throws LdapException 650 * If any other error occurs. 651 */ 652 protected abstract void addNewManagedObject() throws LdapException, OperationRejectedException, 653 ConcurrentModificationException, ManagedObjectAlreadyExistsException; 654 655 /** 656 * Gets the management context driver associated with this managed object. 657 * 658 * @return Returns the management context driver associated with this 659 * managed object. 660 */ 661 protected abstract Driver getDriver(); 662 663 /** 664 * Gets the naming property definition associated with this managed object. 665 * 666 * @return Returns the naming property definition associated with this 667 * managed object, or <code>null</code> if this managed object does 668 * not have a naming property. 669 */ 670 protected final PropertyDefinition<?> getNamingPropertyDefinition() { 671 return namingPropertyDefinition; 672 } 673 674 /** 675 * Gets the property associated with the specified property definition. 676 * 677 * @param <P> 678 * The underlying type of the property. 679 * @param pd 680 * The Property definition. 681 * @return Returns the property associated with the specified property 682 * definition. 683 * @throws IllegalArgumentException 684 * If this property provider does not recognize the requested 685 * property definition. 686 */ 687 protected final <P> Property<P> getProperty(PropertyDefinition<P> pd) { 688 return properties.getProperty(pd); 689 } 690 691 /** 692 * Applies changes made to this managed object. 693 * 694 * @throws ConcurrentModificationException 695 * If this managed object has been removed from the server by 696 * another client. 697 * @throws OperationRejectedException 698 * If the managed object cannot be added due to some client-side 699 * or server-side constraint which cannot be satisfied. 700 * @throws LdapException 701 * If any other error occurs. 702 */ 703 protected abstract void modifyExistingManagedObject() throws ConcurrentModificationException, 704 OperationRejectedException, LdapException; 705 706 /** 707 * Creates a new managed object. 708 * 709 * @param <M> 710 * The type of client configuration represented by the client 711 * managed object. 712 * @param d 713 * The managed object's definition. 714 * @param path 715 * The managed object's path. 716 * @param properties 717 * The managed object's properties. 718 * @param existsOnServer 719 * Indicates whether or not the managed object exists on the 720 * server (false means the managed object is new and has not been 721 * committed). 722 * @param namingPropertyDefinition 723 * Optional naming property definition. 724 * @return Returns the new managed object. 725 */ 726 protected abstract <M extends ConfigurationClient> ManagedObject<M> newInstance(ManagedObjectDefinition<M, ?> d, 727 ManagedObjectPath<M, ?> path, PropertySet properties, boolean existsOnServer, 728 PropertyDefinition<?> namingPropertyDefinition); 729 730 /** 731 * Creates a new managed object with no active values, just default 732 * values. 733 */ 734 private <M extends ConfigurationClient, P> ManagedObject<M> createNewManagedObject( 735 ManagedObjectDefinition<M, ?> d, ManagedObjectPath<M, ?> p, PropertyDefinition<P> namingPropertyDefinition, 736 String name, Collection<PropertyException> exceptions) { 737 PropertySet childProperties = new PropertySet(); 738 for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) { 739 try { 740 createProperty(childProperties, p, pd); 741 } catch (PropertyException e) { 742 // Add the exception if requested. 743 if (exceptions != null) { 744 exceptions.add(e); 745 } 746 } 747 } 748 749 // Set the naming property if there is one. 750 if (namingPropertyDefinition != null) { 751 P value = namingPropertyDefinition.decodeValue(name); 752 childProperties.setPropertyValues(namingPropertyDefinition, Collections.singleton(value)); 753 } 754 755 return newInstance(d, p, childProperties, false, namingPropertyDefinition); 756 } 757 758 /** Create an empty property. */ 759 private <P> void createProperty(PropertySet properties, ManagedObjectPath<?, ?> p, PropertyDefinition<P> pd) { 760 try { 761 Driver context = getDriver(); 762 Collection<P> defaultValues = context.findDefaultValues(p, pd, true); 763 properties.addProperty(pd, defaultValues, Collections.<P> emptySet()); 764 } catch (PropertyException e) { 765 // Make sure that we have still created the property. 766 properties.addProperty(pd, Collections.<P> emptySet(), Collections.<P> emptySet()); 767 throw e; 768 } 769 } 770 771 /** Makes sure that this managed object exists. */ 772 private void ensureThisManagedObjectExists() throws ConcurrentModificationException, LdapException { 773 if (!path.isEmpty()) { 774 Driver ctx = getDriver(); 775 776 try { 777 if (!ctx.managedObjectExists(path)) { 778 throw new ConcurrentModificationException(); 779 } 780 } catch (ManagedObjectNotFoundException e) { 781 throw new ConcurrentModificationException(); 782 } 783 } 784 } 785 786 /** 787 * Validate that a relation definition belongs to this managed 788 * object. 789 */ 790 private void validateRelationDefinition(RelationDefinition<?, ?> rd) { 791 ManagedObjectDefinition<T, ?> d = getManagedObjectDefinition(); 792 RelationDefinition<?, ?> tmp = d.getRelationDefinition(rd.getName()); 793 if (tmp != rd) { 794 throw new IllegalArgumentException("The relation " + rd.getName() + " is not associated with a " 795 + d.getName()); 796 } 797 } 798 799}