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