/*
     * Ensures that the proposed value is valid based on the set of valid values for OSGs
     * Additional DB lookup required for remote OSGs where the CLC doesn't have the OSG bits
     * installed and therefore doesn't have the same view of the set of valid values.
     * (non-Javadoc)
     * @see com.eucalyptus.configurable.PropertyChangeListener#fireChange(com.eucalyptus.configurable.ConfigurableProperty, java.lang.Object)
     */
    @Override
    public void fireChange(ConfigurableProperty t, String newValue)
        throws ConfigurablePropertyException {
      String existingValue = (String) t.getValue();

      List<ServiceConfiguration> objConfigs = null;
      try {
        objConfigs = ServiceConfigurations.list(ObjectStorage.class);
      } catch (NoSuchElementException e) {
        throw new ConfigurablePropertyException("No ObjectStorage configurations found");
      }

      final String proposedValue = newValue;
      final Set<String> validEntries = Sets.newHashSet();
      EntityTransaction tx = Entities.get(ObjectStorageConfiguration.class);
      try {
        if (!Iterables.any(
            Components.lookup(ObjectStorage.class).services(),
            new Predicate<ServiceConfiguration>() {
              @Override
              public boolean apply(ServiceConfiguration config) {
                if (config.isVmLocal()) {
                  // Service is local, so add entries to the valid list (in case of HA configs)
                  // and then check the local memory state
                  validEntries.addAll(ObjectStorageProviders.list());
                  return ObjectStorageProviders.contains(proposedValue);
                } else {
                  try {
                    // Remote SC, so check the db for the list of valid entries.
                    ObjectStorageConfiguration objConfig =
                        Entities.uniqueResult((ObjectStorageConfiguration) config);
                    for (String entry : Splitter.on(",").split(objConfig.getAvailableClients())) {
                      validEntries.add(entry);
                    }
                    return validEntries.contains(proposedValue);
                  } catch (Exception e) {
                    return false;
                  }
                }
              }
            })) {
          // Nothing matched.
          throw new ConfigurablePropertyException(
              "Cannot modify "
                  + t.getQualifiedName()
                  + "."
                  + t.getFieldName()
                  + " new value is not a valid value.  "
                  + "Legal values are: "
                  + Joiner.on(",").join(validEntries));
        }
      } finally {
        tx.rollback();
      }
    }
    @Override
    public void fireChange(ConfigurableProperty t, String newValue)
        throws ConfigurablePropertyException {
      String existingValue = (String) t.getValue();
      if (existingValue != null && !"<unset>".equals(existingValue)) {
        throw new ConfigurablePropertyException(
            "Cannot change extant storage backend configuration. You must deregister all SCs in the partition before you can change the configuration value");
      } else {
        // Try to figure out the partition name for the request
        String probablePartitionName = ((MultiDatabasePropertyEntry) t).getEntrySetName();
        if (probablePartitionName == null) {
          throw new ConfigurablePropertyException(
              "Could not determing partition name from property to check validity");
        }

        String[] parts = probablePartitionName.split("\\.");
        if (parts == null || parts.length == 0) {
          throw new ConfigurablePropertyException(
              "Could not determing partition name from property to check validity: "
                  + probablePartitionName);
        }
        probablePartitionName = parts[0];

        /*Look through the service configurations for each SC in the partition and see if the value is valid.
         * This step must work if we don't allow the user to change it once set.
         * The difficulty here is if 2 SCs are in an HA pair but have different backends installed (i.e. packages)
         * The implemented semantic is that if the proposed value is valid in either SC, then allow the change.
         */
        List<ServiceConfiguration> scConfigs = null;
        try {
          scConfigs = ServiceConfigurations.listPartition(Storage.class, probablePartitionName);
        } catch (NoSuchElementException e) {
          throw new ConfigurablePropertyException(
              "No Storage Controller configurations found for partition: " + probablePartitionName);
        }

        final String proposedValue = newValue;
        final Set<String> validEntries = Sets.newHashSet();
        EntityTransaction tx = Entities.get(StorageControllerConfiguration.class);
        try {
          if (!Iterables.any(
              scConfigs,
              new Predicate<ServiceConfiguration>() {
                @Override
                public boolean apply(ServiceConfiguration config) {
                  if (config.isVmLocal()) {
                    // Service is local, so add entries to the valid list (in case of HA configs)
                    // and then check the local memory state
                    validEntries.addAll(StorageManagers.list());
                    return StorageManagers.contains(proposedValue);
                  } else {
                    try {
                      // Remote SC, so check the db for the list of valid entries.
                      StorageControllerConfiguration scConfig =
                          Entities.uniqueResult((StorageControllerConfiguration) config);
                      for (String entry : Splitter.on(",").split(scConfig.getAvailableBackends())) {
                        validEntries.add(entry);
                      }
                      return validEntries.contains(proposedValue);
                    } catch (Exception e) {
                      return false;
                    }
                  }
                }
              })) {
            // Nothing matched.
            throw new ConfigurablePropertyException(
                "Cannot modify "
                    + t.getQualifiedName()
                    + "."
                    + t.getFieldName()
                    + " new value is not a valid value.  "
                    + "Legal values are: "
                    + Joiner.on(",").join(validEntries));
          }
        } finally {
          tx.rollback();
        }
      }
    }