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