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.opends.server.admin.client.spi;
028
029import static org.opends.server.admin.PropertyException.*;
030
031import java.util.ArrayList;
032import java.util.Collection;
033import java.util.Collections;
034import java.util.LinkedList;
035import java.util.List;
036import java.util.SortedSet;
037
038import org.forgerock.i18n.LocalizableMessage;
039import org.opends.server.admin.AbsoluteInheritedDefaultBehaviorProvider;
040import org.opends.server.admin.AbstractManagedObjectDefinition;
041import org.opends.server.admin.AliasDefaultBehaviorProvider;
042import org.opends.server.admin.Configuration;
043import org.opends.server.admin.ConfigurationClient;
044import org.opends.server.admin.Constraint;
045import org.opends.server.admin.DefaultBehaviorProviderVisitor;
046import org.opends.server.admin.DefinedDefaultBehaviorProvider;
047import org.opends.server.admin.DefinitionDecodingException;
048import org.opends.server.admin.DefinitionDecodingException.Reason;
049import org.opends.server.admin.InstantiableRelationDefinition;
050import org.opends.server.admin.ManagedObjectNotFoundException;
051import org.opends.server.admin.ManagedObjectPath;
052import org.opends.server.admin.OptionalRelationDefinition;
053import org.opends.server.admin.PropertyDefinition;
054import org.opends.server.admin.PropertyException;
055import org.opends.server.admin.PropertyNotFoundException;
056import org.opends.server.admin.PropertyOption;
057import org.opends.server.admin.RelationDefinition;
058import org.opends.server.admin.RelativeInheritedDefaultBehaviorProvider;
059import org.opends.server.admin.SetRelationDefinition;
060import org.opends.server.admin.UndefinedDefaultBehaviorProvider;
061import org.opends.server.admin.client.AuthorizationException;
062import org.opends.server.admin.client.ClientConstraintHandler;
063import org.opends.server.admin.client.CommunicationException;
064import org.opends.server.admin.client.ManagedObject;
065import org.opends.server.admin.client.ManagedObjectDecodingException;
066import org.opends.server.admin.client.ManagementContext;
067import org.opends.server.admin.client.OperationRejectedException;
068import org.opends.server.admin.client.OperationRejectedException.OperationType;
069import org.opends.server.admin.std.client.RootCfgClient;
070
071/**
072 * An abstract management connection context driver which should form
073 * the basis of driver implementations.
074 */
075public abstract class Driver {
076
077  /**
078   * A default behavior visitor used for retrieving the default values
079   * of a property.
080   *
081   * @param <T>
082   *          The type of the property.
083   */
084  private class DefaultValueFinder<T> implements
085      DefaultBehaviorProviderVisitor<T, Collection<T>, Void> {
086
087    /** Any exception that occurred whilst retrieving inherited default values. */
088    private PropertyException exception;
089
090    /** The path of the managed object containing the first property. */
091    private final ManagedObjectPath<?, ?> firstPath;
092
093    /** Indicates whether the managed object has been created yet. */
094    private final boolean isCreate;
095
096    /** The path of the managed object containing the next property. */
097    private ManagedObjectPath<?, ?> nextPath;
098
099    /** The next property whose default values were required. */
100    private PropertyDefinition<T> nextProperty;
101
102    /** Private constructor. */
103    private DefaultValueFinder(ManagedObjectPath<?, ?> p, boolean isCreate) {
104      this.firstPath = p;
105      this.isCreate = isCreate;
106    }
107
108    /** {@inheritDoc} */
109    @Override
110    public Collection<T> visitAbsoluteInherited(
111        AbsoluteInheritedDefaultBehaviorProvider<T> d, Void p) {
112      try {
113        return getInheritedProperty(d.getManagedObjectPath(), d
114            .getManagedObjectDefinition(), d.getPropertyName());
115      } catch (PropertyException e) {
116        exception = e;
117        return Collections.emptySet();
118      }
119    }
120
121    /** {@inheritDoc} */
122    @Override
123    public Collection<T> visitAlias(AliasDefaultBehaviorProvider<T> d, Void p) {
124      return Collections.emptySet();
125    }
126
127    /** {@inheritDoc} */
128    @Override
129    public Collection<T> visitDefined(DefinedDefaultBehaviorProvider<T> d,
130        Void p) {
131      Collection<String> stringValues = d.getDefaultValues();
132      List<T> values = new ArrayList<>(stringValues.size());
133
134      for (String stringValue : stringValues) {
135        try {
136          values.add(nextProperty.decodeValue(stringValue));
137        } catch (PropertyException e) {
138          exception = defaultBehaviorException(nextProperty, e);
139          break;
140        }
141      }
142
143      return values;
144    }
145
146    /** {@inheritDoc} */
147    @Override
148    public Collection<T> visitRelativeInherited(
149        RelativeInheritedDefaultBehaviorProvider<T> d, Void p) {
150      try {
151        return getInheritedProperty(d.getManagedObjectPath(nextPath), d
152            .getManagedObjectDefinition(), d.getPropertyName());
153      } catch (PropertyException e) {
154        exception = e;
155        return Collections.emptySet();
156      }
157    }
158
159    /** {@inheritDoc} */
160    @Override
161    public Collection<T> visitUndefined(UndefinedDefaultBehaviorProvider<T> d,
162        Void p) {
163      return Collections.emptySet();
164    }
165
166    /** Find the default values for the next path/property. */
167    private Collection<T> find(ManagedObjectPath<?, ?> p,
168        PropertyDefinition<T> pd) throws PropertyException {
169      this.nextPath = p;
170      this.nextProperty = pd;
171
172      Collection<T> values = nextProperty.getDefaultBehaviorProvider().accept(
173          this, null);
174
175      if (exception != null) {
176        throw exception;
177      }
178
179      if (values.size() > 1 && !pd.hasOption(PropertyOption.MULTI_VALUED)) {
180        throw PropertyException.defaultBehaviorException(pd,
181            PropertyException.propertyIsSingleValuedException(pd));
182      }
183
184      return values;
185    }
186
187    /** Get an inherited property value. */
188    @SuppressWarnings("unchecked")
189    private Collection<T> getInheritedProperty(ManagedObjectPath target,
190        AbstractManagedObjectDefinition<?, ?> d, String propertyName)
191        throws PropertyException {
192      // First check that the requested type of managed object
193      // corresponds to the path.
194      AbstractManagedObjectDefinition<?, ?> actualType = target
195          .getManagedObjectDefinition();
196      if (!d.isParentOf(actualType)) {
197        throw PropertyException.defaultBehaviorException(
198            nextProperty, new DefinitionDecodingException(d,
199                Reason.WRONG_TYPE_INFORMATION));
200      }
201
202      // Save the current property in case of recursion.
203      PropertyDefinition<T> pd1 = nextProperty;
204
205      try {
206        // Determine the requested property definition.
207        PropertyDefinition<T> pd2;
208        try {
209          // FIXME: we use the definition taken from the default
210          // behavior here when we should really use the exact
211          // definition of the component being created.
212          PropertyDefinition<?> pdTmp = d.getPropertyDefinition(propertyName);
213          pd2 = pd1.getClass().cast(pdTmp);
214        } catch (IllegalArgumentException e) {
215          throw new PropertyNotFoundException(propertyName);
216        } catch (ClassCastException e) {
217          // FIXME: would be nice to throw a better exception here.
218          throw new PropertyNotFoundException(propertyName);
219        }
220
221        // If the path relates to the current managed object and the
222        // managed object is in the process of being created it won't
223        // exist, so we should just use the default values of the
224        // referenced property.
225        if (isCreate && firstPath.equals(target)) {
226          // Recursively retrieve this property's default values.
227          Collection<T> tmp = find(target, pd2);
228          Collection<T> values = new ArrayList<>(tmp.size());
229          for (T value : tmp) {
230            pd1.validateValue(value);
231            values.add(value);
232          }
233          return values;
234        } else {
235          // FIXME: issue 2481 - this is broken if the referenced property
236          // inherits its defaults from the newly created managed object.
237          return getPropertyValues(target, pd2);
238        }
239      } catch (PropertyException | DefinitionDecodingException | PropertyNotFoundException
240          | AuthorizationException | ManagedObjectNotFoundException | CommunicationException e) {
241        throw PropertyException.defaultBehaviorException(pd1, e);
242      }
243    }
244  }
245
246  /** Creates a new abstract management context. */
247  protected Driver() {
248    // No implementation required.
249  }
250
251  /** Closes any context associated with this management context driver. */
252  public void close() {
253    // do nothing by default
254  }
255
256  /**
257   * Deletes the named instantiable child managed object from the
258   * named parent managed object.
259   *
260   * @param <C>
261   *          The type of client managed object configuration that the
262   *          relation definition refers to.
263   * @param <S>
264   *          The type of server managed object configuration that the
265   *          relation definition refers to.
266   * @param parent
267   *          The path of the parent managed object.
268   * @param rd
269   *          The instantiable relation definition.
270   * @param name
271   *          The name of the child managed object to be removed.
272   * @return Returns <code>true</code> if the named instantiable
273   *         child managed object was found, or <code>false</code>
274   *         if it was not found.
275   * @throws IllegalArgumentException
276   *           If the relation definition is not associated with the
277   *           parent managed object's definition.
278   * @throws ManagedObjectNotFoundException
279   *           If the parent managed object could not be found.
280   * @throws OperationRejectedException
281   *           If the managed object cannot be removed due to some
282   *           client-side or server-side constraint which cannot be
283   *           satisfied (for example, if it is referenced by another
284   *           managed object).
285   * @throws AuthorizationException
286   *           If the server refuses to remove the managed objects
287   *           because the client does not have the correct
288   *           privileges.
289   * @throws CommunicationException
290   *           If the client cannot contact the server due to an
291   *           underlying communication problem.
292   */
293  public final <C extends ConfigurationClient, S extends Configuration>
294  boolean deleteManagedObject(
295      ManagedObjectPath<?, ?> parent, InstantiableRelationDefinition<C, S> rd,
296      String name) throws IllegalArgumentException,
297      ManagedObjectNotFoundException, OperationRejectedException,
298      AuthorizationException, CommunicationException {
299    validateRelationDefinition(parent, rd);
300    ManagedObjectPath<?, ?> child = parent.child(rd, name);
301    return doDeleteManagedObject(child);
302  }
303
304  /**
305   * Deletes the optional child managed object from the named parent
306   * managed object.
307   *
308   * @param <C>
309   *          The type of client managed object configuration that the
310   *          relation definition refers to.
311   * @param <S>
312   *          The type of server managed object configuration that the
313   *          relation definition refers to.
314   * @param parent
315   *          The path of the parent managed object.
316   * @param rd
317   *          The optional relation definition.
318   * @return Returns <code>true</code> if the optional child managed
319   *         object was found, or <code>false</code> if it was not
320   *         found.
321   * @throws IllegalArgumentException
322   *           If the relation definition is not associated with the
323   *           parent managed object's definition.
324   * @throws ManagedObjectNotFoundException
325   *           If the parent managed object could not be found.
326   * @throws OperationRejectedException
327   *           If the managed object cannot be removed due to some
328   *           client-side or server-side constraint which cannot be
329   *           satisfied (for example, if it is referenced by another
330   *           managed object).
331   * @throws AuthorizationException
332   *           If the server refuses to remove the managed objects
333   *           because the client does not have the correct
334   *           privileges.
335   * @throws CommunicationException
336   *           If the client cannot contact the server due to an
337   *           underlying communication problem.
338   */
339  public final <C extends ConfigurationClient, S extends Configuration>
340  boolean deleteManagedObject(
341      ManagedObjectPath<?, ?> parent, OptionalRelationDefinition<C, S> rd)
342      throws IllegalArgumentException, ManagedObjectNotFoundException,
343      OperationRejectedException, AuthorizationException,
344      CommunicationException {
345    validateRelationDefinition(parent, rd);
346    ManagedObjectPath<?, ?> child = parent.child(rd);
347    return doDeleteManagedObject(child);
348  }
349
350  /**
351   * Deletes the named instantiable child managed object from the
352   * named parent managed object.
353   *
354   * @param <C>
355   *          The type of client managed object configuration that the
356   *          relation definition refers to.
357   * @param <S>
358   *          The type of server managed object configuration that the
359   *          relation definition refers to.
360   * @param parent
361   *          The path of the parent managed object.
362   * @param rd
363   *          The instantiable relation definition.
364   * @param name
365   *          The name of the child managed object to be removed.
366   * @return Returns <code>true</code> if the named instantiable
367   *         child managed object was found, or <code>false</code>
368   *         if it was not found.
369   * @throws IllegalArgumentException
370   *           If the relation definition is not associated with the
371   *           parent managed object's definition.
372   * @throws ManagedObjectNotFoundException
373   *           If the parent managed object could not be found.
374   * @throws OperationRejectedException
375   *           If the managed object cannot be removed due to some
376   *           client-side or server-side constraint which cannot be
377   *           satisfied (for example, if it is referenced by another
378   *           managed object).
379   * @throws AuthorizationException
380   *           If the server refuses to remove the managed objects
381   *           because the client does not have the correct
382   *           privileges.
383   * @throws CommunicationException
384   *           If the client cannot contact the server due to an
385   *           underlying communication problem.
386   */
387  public final <C extends ConfigurationClient, S extends Configuration>
388  boolean deleteManagedObject(
389      ManagedObjectPath<?, ?> parent, SetRelationDefinition<C, S> rd,
390      String name) throws IllegalArgumentException,
391      ManagedObjectNotFoundException, OperationRejectedException,
392      AuthorizationException, CommunicationException {
393    validateRelationDefinition(parent, rd);
394    ManagedObjectPath<?, ?> child = parent.child(rd, name);
395    return doDeleteManagedObject(child);
396  }
397
398  /**
399   * Gets the named managed object. The path is guaranteed to be
400   * non-empty, so implementations do not need to worry about handling
401   * this special case.
402   *
403   * @param <C>
404   *          The type of client managed object configuration that the
405   *          path definition refers to.
406   * @param <S>
407   *          The type of server managed object configuration that the
408   *          path definition refers to.
409   * @param path
410   *          The non-empty path of the managed object.
411   * @return Returns the named managed object.
412   * @throws DefinitionDecodingException
413   *           If the managed object was found but its type could not
414   *           be determined.
415   * @throws ManagedObjectDecodingException
416   *           If the managed object was found but one or more of its
417   *           properties could not be decoded.
418   * @throws ManagedObjectNotFoundException
419   *           If the requested managed object could not be found on
420   *           the server.
421   * @throws AuthorizationException
422   *           If the server refuses to retrieve the managed object
423   *           because the client does not have the correct
424   *           privileges.
425   * @throws CommunicationException
426   *           If the client cannot contact the server due to an
427   *           underlying communication problem.
428   */
429  public abstract <C extends ConfigurationClient, S extends Configuration>
430  ManagedObject<? extends C> getManagedObject(
431      ManagedObjectPath<C, S> path) throws DefinitionDecodingException,
432      ManagedObjectDecodingException, ManagedObjectNotFoundException,
433      AuthorizationException, CommunicationException;
434
435  /**
436   * Gets the effective values of a property in the named managed
437   * object.
438   * <p>
439   * Implementations MUST NOT not use
440   * {@link #getManagedObject(ManagedObjectPath)} to read the
441   * referenced managed object in its entirety. Specifically,
442   * implementations MUST only attempt to resolve the default values
443   * for the requested property and its dependencies (if it uses
444   * inherited defaults). This is to avoid infinite recursion where a
445   * managed object contains a property which inherits default values
446   * from another property in the same managed object.
447   *
448   * @param <C>
449   *          The type of client managed object configuration that the
450   *          path definition refers to.
451   * @param <S>
452   *          The type of server managed object configuration that the
453   *          path definition refers to.
454   * @param <PD>
455   *          The type of the property to be retrieved.
456   * @param path
457   *          The path of the managed object containing the property.
458   * @param pd
459   *          The property to be retrieved.
460   * @return Returns the property's effective values, or an empty set
461   *         if there are no values defined.
462   * @throws IllegalArgumentException
463   *           If the property definition is not associated with the
464   *           referenced managed object's definition.
465   * @throws DefinitionDecodingException
466   *           If the managed object was found but its type could not
467   *           be determined.
468   * @throws PropertyException
469   *           If the managed object was found but the requested
470   *           property could not be decoded.
471   * @throws ManagedObjectNotFoundException
472   *           If the requested managed object could not be found on
473   *           the server.
474   * @throws AuthorizationException
475   *           If the server refuses to retrieve the managed object
476   *           because the client does not have the correct
477   *           privileges.
478   * @throws CommunicationException
479   *           If the client cannot contact the server due to an
480   *           underlying communication problem.
481   */
482  public abstract <C extends ConfigurationClient, S extends Configuration, PD>
483  SortedSet<PD> getPropertyValues(
484      ManagedObjectPath<C, S> path, PropertyDefinition<PD> pd)
485      throws IllegalArgumentException, DefinitionDecodingException,
486      AuthorizationException, ManagedObjectNotFoundException,
487      CommunicationException, PropertyException;
488
489  /**
490   * Gets the root configuration managed object associated with this
491   * management context driver.
492   *
493   * @return Returns the root configuration managed object associated
494   *         with this management context driver.
495   */
496  public abstract
497  ManagedObject<RootCfgClient> getRootConfigurationManagedObject();
498
499  /**
500   * Lists the child managed objects of the named parent managed
501   * object which are a sub-type of the specified managed object
502   * definition.
503   *
504   * @param <C>
505   *          The type of client managed object configuration that the
506   *          relation definition refers to.
507   * @param <S>
508   *          The type of server managed object configuration that the
509   *          relation definition refers to.
510   * @param parent
511   *          The path of the parent managed object.
512   * @param rd
513   *          The instantiable relation definition.
514   * @param d
515   *          The managed object definition.
516   * @return Returns the names of the child managed objects which are
517   *         a sub-type of the specified managed object definition.
518   * @throws IllegalArgumentException
519   *           If the relation definition is not associated with the
520   *           parent managed object's definition.
521   * @throws ManagedObjectNotFoundException
522   *           If the parent managed object could not be found.
523   * @throws AuthorizationException
524   *           If the server refuses to list the managed objects
525   *           because the client does not have the correct
526   *           privileges.
527   * @throws CommunicationException
528   *           If the client cannot contact the server due to an
529   *           underlying communication problem.
530   */
531  public abstract <C extends ConfigurationClient, S extends Configuration>
532  String[] listManagedObjects(
533      ManagedObjectPath<?, ?> parent, InstantiableRelationDefinition<C, S> rd,
534      AbstractManagedObjectDefinition<? extends C, ? extends S> d)
535      throws IllegalArgumentException, ManagedObjectNotFoundException,
536      AuthorizationException, CommunicationException;
537
538  /**
539   * Lists the child managed objects of the named parent managed
540   * object which are a sub-type of the specified managed object
541   * definition.
542   *
543   * @param <C>
544   *          The type of client managed object configuration that the
545   *          relation definition refers to.
546   * @param <S>
547   *          The type of server managed object configuration that the
548   *          relation definition refers to.
549   * @param parent
550   *          The path of the parent managed object.
551   * @param rd
552   *          The set relation definition.
553   * @param d
554   *          The managed object definition.
555   * @return Returns the names of the child managed objects which are
556   *         a sub-type of the specified managed object definition.
557   * @throws IllegalArgumentException
558   *           If the relation definition is not associated with the
559   *           parent managed object's definition.
560   * @throws ManagedObjectNotFoundException
561   *           If the parent managed object could not be found.
562   * @throws AuthorizationException
563   *           If the server refuses to list the managed objects
564   *           because the client does not have the correct
565   *           privileges.
566   * @throws CommunicationException
567   *           If the client cannot contact the server due to an
568   *           underlying communication problem.
569   */
570  public abstract <C extends ConfigurationClient, S extends Configuration>
571  String[] listManagedObjects(
572      ManagedObjectPath<?, ?> parent, SetRelationDefinition<C, S> rd,
573      AbstractManagedObjectDefinition<? extends C, ? extends S> d)
574      throws IllegalArgumentException, ManagedObjectNotFoundException,
575      AuthorizationException, CommunicationException;
576
577  /**
578   * Determines whether or not the named managed object exists.
579   * <p>
580   * Implementations should always return <code>true</code> when the
581   * provided path is empty.
582   *
583   * @param path
584   *          The path of the named managed object.
585   * @return Returns <code>true</code> if the named managed object
586   *         exists, <code>false</code> otherwise.
587   * @throws ManagedObjectNotFoundException
588   *           If the parent managed object could not be found.
589   * @throws AuthorizationException
590   *           If the server refuses to make the determination because
591   *           the client does not have the correct privileges.
592   * @throws CommunicationException
593   *           If the client cannot contact the server due to an
594   *           underlying communication problem.
595   */
596  public abstract boolean managedObjectExists(ManagedObjectPath<?, ?> path)
597      throws ManagedObjectNotFoundException, AuthorizationException,
598      CommunicationException;
599
600  /**
601   * Deletes the named managed object.
602   * <p>
603   * Implementations do not need check whether the named managed
604   * object exists, nor do they need to enforce client constraints.
605   *
606   * @param <C>
607   *          The type of client managed object configuration that the
608   *          relation definition refers to.
609   * @param <S>
610   *          The type of server managed object configuration that the
611   *          relation definition refers to.
612   * @param path
613   *          The path of the managed object to be deleted.
614   * @throws OperationRejectedException
615   *           If the managed object cannot be removed due to some
616   *           server-side constraint which cannot be satisfied (for
617   *           example, if it is referenced by another managed
618   *           object).
619   * @throws AuthorizationException
620   *           If the server refuses to remove the managed objects
621   *           because the client does not have the correct
622   *           privileges.
623   * @throws CommunicationException
624   *           If the client cannot contact the server due to an
625   *           underlying communication problem.
626   */
627  protected abstract <C extends ConfigurationClient, S extends Configuration>
628  void deleteManagedObject(
629      ManagedObjectPath<C, S> path) throws OperationRejectedException,
630      AuthorizationException, CommunicationException;
631
632  /**
633   * Gets the default values for the specified property.
634   *
635   * @param <PD>
636   *          The type of the property.
637   * @param p
638   *          The managed object path of the current managed object.
639   * @param pd
640   *          The property definition.
641   * @param isCreate
642   *          Indicates whether the managed object has been created
643   *          yet.
644   * @return Returns the default values for the specified property.
645   * @throws PropertyException
646   *           If the default values could not be retrieved or decoded
647   *           properly.
648   */
649  protected final <PD> Collection<PD> findDefaultValues(
650      ManagedObjectPath<?, ?> p, PropertyDefinition<PD> pd, boolean isCreate)
651      throws PropertyException {
652    DefaultValueFinder<PD> v = new DefaultValueFinder<>(p, isCreate);
653    return v.find(p, pd);
654  }
655
656  /**
657   * Gets the management context associated with this driver.
658   *
659   * @return Returns the management context associated with this
660   *         driver.
661   */
662  protected abstract ManagementContext getManagementContext();
663
664  /**
665   * Validate that a relation definition belongs to the managed object
666   * referenced by the provided path.
667   *
668   * @param path
669   *          The parent managed object path.
670   * @param rd
671   *          The relation definition.
672   * @throws IllegalArgumentException
673   *           If the relation definition does not belong to the
674   *           managed object definition.
675   */
676  protected final void validateRelationDefinition(ManagedObjectPath<?, ?> path,
677      RelationDefinition<?, ?> rd) throws IllegalArgumentException {
678    AbstractManagedObjectDefinition<?, ?> d = path.getManagedObjectDefinition();
679    RelationDefinition<?, ?> tmp = d.getRelationDefinition(rd.getName());
680    if (tmp != rd) {
681      throw new IllegalArgumentException("The relation " + rd.getName()
682          + " is not associated with a " + d.getName());
683    }
684  }
685
686  /**
687   * Remove a managed object, first ensuring that the parent exists,
688   * then ensuring that the child exists, before ensuring that any
689   * constraints are satisfied.
690   */
691  private <C extends ConfigurationClient, S extends Configuration>
692  boolean doDeleteManagedObject(
693      ManagedObjectPath<C, S> path) throws ManagedObjectNotFoundException,
694      OperationRejectedException, AuthorizationException,
695      CommunicationException {
696    // First make sure that the parent exists.
697    if (!managedObjectExists(path.parent())) {
698      throw new ManagedObjectNotFoundException();
699    }
700
701    // Make sure that the targeted managed object exists.
702    if (!managedObjectExists(path)) {
703      return false;
704    }
705
706    // The targeted managed object is guaranteed to exist, so enforce
707    // any constraints.
708    AbstractManagedObjectDefinition<?, ?> d = path.getManagedObjectDefinition();
709    List<LocalizableMessage> messages = new LinkedList<>();
710    boolean isAcceptable = true;
711
712    for (Constraint constraint : d.getAllConstraints()) {
713      for (ClientConstraintHandler handler : constraint
714          .getClientConstraintHandlers()) {
715        ManagementContext context = getManagementContext();
716        if (!handler.isDeleteAcceptable(context, path, messages)) {
717          isAcceptable = false;
718        }
719      }
720      if (!isAcceptable) {
721        break;
722      }
723    }
724
725    if (!isAcceptable) {
726      throw new OperationRejectedException(OperationType.DELETE, d
727          .getUserFriendlyName(), messages);
728    }
729
730    deleteManagedObject(path);
731    return true;
732  }
733}