All Downloads are FREE. Search and download functionalities are using the official Maven repository.

microsoft.exchange.webservices.data.misc.UserConfiguration Maven / Gradle / Ivy

/*
 * The MIT License
 * Copyright (c) 2012 Microsoft Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package microsoft.exchange.webservices.data.misc;

import microsoft.exchange.webservices.data.core.EwsServiceXmlReader;
import microsoft.exchange.webservices.data.core.EwsServiceXmlWriter;
import microsoft.exchange.webservices.data.core.EwsUtilities;
import microsoft.exchange.webservices.data.core.ExchangeService;
import microsoft.exchange.webservices.data.core.XmlAttributeNames;
import microsoft.exchange.webservices.data.core.XmlElementNames;
import microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion;
import microsoft.exchange.webservices.data.core.enumeration.misc.UserConfigurationProperties;
import microsoft.exchange.webservices.data.core.enumeration.property.WellKnownFolderName;
import microsoft.exchange.webservices.data.core.enumeration.misc.XmlNamespace;
import microsoft.exchange.webservices.data.core.exception.misc.InvalidOperationException;
import microsoft.exchange.webservices.data.core.exception.service.local.PropertyException;
import microsoft.exchange.webservices.data.core.exception.service.local.ServiceVersionException;
import microsoft.exchange.webservices.data.core.exception.service.local.ServiceXmlSerializationException;
import microsoft.exchange.webservices.data.property.complex.FolderId;
import microsoft.exchange.webservices.data.property.complex.ItemId;
import microsoft.exchange.webservices.data.property.complex.UserConfigurationDictionary;
import microsoft.exchange.webservices.data.security.XmlNodeType;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.xml.stream.XMLStreamException;

import java.util.EnumSet;

/**
 * Represents an object that can be used to store user-defined configuration
 * settings.
 */
public class UserConfiguration {

  private static final Log LOG = LogFactory.getLog(UserConfiguration.class);

  /**
   * The object version.
   */
  private static ExchangeVersion ObjectVersion = ExchangeVersion.Exchange2010;

  /**
   * For consistency with ServiceObject behavior, access to ItemId is
   * permitted for a new object.
   */
  /**
   * The Constant PropertiesAvailableForNewObject.
   */
  private final static EnumSet
      PropertiesAvailableForNewObject =
      EnumSet.of(UserConfigurationProperties.BinaryData,
          UserConfigurationProperties.Dictionary,
          UserConfigurationProperties.XmlData);

  /**
   * The No property.
   */
  private final UserConfigurationProperties NoProperties =
      UserConfigurationProperties.values()[0];

  /**
   * The service.
   */
  private ExchangeService service;

  /**
   * The name.
   */
  private String name;

  /**
   * The parent folder id.
   */
  private FolderId parentFolderId = null;

  /**
   * The item id.
   */
  private ItemId itemId = null;

  /**
   * The dictionary.
   */
  private UserConfigurationDictionary dictionary = null;

  /**
   * The xml data.
   */
  private byte[] xmlData = null;

  /**
   * The binary data.
   */
  private byte[] binaryData = null;

  /**
   * The property available for access.
   */
  private EnumSet propertiesAvailableForAccess;

  /**
   * The updated property.
   */
  private EnumSet updatedProperties;

  /**
   * Indicates whether changes trigger an update or create operation.
   */
  private boolean isNew = false;

  /**
   * Initializes a new instance of {@link UserConfiguration} class.
   *
   * @param service The service to which the user configuration is bound.
   * @throws Exception the exception
   */
  public UserConfiguration(ExchangeService service) throws Exception {
    this(service, PropertiesAvailableForNewObject);
  }

  /**
   * Writes a byte array to Xml.
   *
   * @param writer         the writer
   * @param byteArray      byte array to write
   * @param xmlElementName name of the Xml element
   * @throws XMLStreamException the XML stream exception
   * @throws ServiceXmlSerializationException the service xml serialization exception
   */
  private static void writeByteArrayToXml(EwsServiceXmlWriter writer,
      byte[] byteArray, String xmlElementName) throws XMLStreamException, ServiceXmlSerializationException {
    EwsUtilities.ewsAssert(writer != null, "UserConfiguration.WriteByteArrayToXml", "writer is null");
    EwsUtilities.ewsAssert(xmlElementName != null, "UserConfiguration.WriteByteArrayToXml",
                           "xmlElementName is null");

    writer.writeStartElement(XmlNamespace.Types, xmlElementName);

    if (byteArray != null && byteArray.length > 0) {
      writer.writeValue(Base64.encodeBase64String(byteArray), xmlElementName);
    }

    writer.writeEndElement();
  }


  /**
   * Writes to Xml.
   *
   * @param writer         The writer.
   * @param xmlNamespace   The XML namespace.
   * @param name           The user configuration name.
   * @param parentFolderId The Id of the folder containing the user configuration.
   * @throws Exception the exception
   */
  public static void writeUserConfigurationNameToXml(EwsServiceXmlWriter writer, XmlNamespace xmlNamespace,
      String name, FolderId parentFolderId) throws Exception {
    EwsUtilities.ewsAssert(writer != null, "UserConfiguration.WriteUserConfigurationNameToXml",
                           "writer is null");
    EwsUtilities.ewsAssert(name != null, "UserConfiguration.WriteUserConfigurationNameToXml", "name is null");
    EwsUtilities.ewsAssert(parentFolderId != null, "UserConfiguration.WriteUserConfigurationNameToXml",
                           "parentFolderId is null");

    writer.writeStartElement(xmlNamespace,
        XmlElementNames.UserConfigurationName);

    writer.writeAttributeValue(XmlAttributeNames.Name, name);

    parentFolderId.writeToXml(writer);

    writer.writeEndElement();
  }

  /**
   * Initializes a new instance of {@link UserConfiguration} class.
   *
   * @param service             The service to which the user configuration is bound.
   * @param requestedProperties The property requested for this user configuration.
   * @throws Exception the exception
   */
  public UserConfiguration(ExchangeService service, EnumSet requestedProperties)
      throws Exception {
    EwsUtilities.validateParam(service, "service");

    if (service.getRequestedServerVersion().ordinal() < UserConfiguration.ObjectVersion.ordinal()) {
      throw new ServiceVersionException(String.format(
          "The object type %s is only valid for Exchange Server version %s or later versions.", this
              .getClass().getName(), UserConfiguration.ObjectVersion));
    }

    this.service = service;
    this.isNew = true;

    this.initializeProperties(requestedProperties);
  }

  /**
   * Gets the name of the user configuration.
   *
   * @return the name
   */
  public String getName() {
    return this.name;
  }

  /**
   * Sets the name.
   *
   * @param value the new name
   */
  public void setName(String value) {
    this.name = value;
  }

  /**
   * Gets the Id of the folder containing the user configuration.
   *
   * @return the parent folder id
   */
  public FolderId getParentFolderId() {
    return this.parentFolderId;
  }

  /**
   * Sets the parent folder id.
   *
   * @param value the new parent folder id
   */
  public void setParentFolderId(FolderId value) {
    this.parentFolderId = value;
  }

  /**
   * Gets the Id of the user configuration.
   *
   * @return the item id
   */
  public ItemId getItemId() {
    return this.itemId;
  }

  /**
   * Gets the dictionary of the user configuration.
   *
   * @return the dictionary
   */
  public UserConfigurationDictionary getDictionary() {
    return this.dictionary;
  }

  /**
   * Gets the xml data of the user configuration.
   *
   * @return the xml data
   * @throws PropertyException the property exception
   */
  public byte[] getXmlData() throws PropertyException {

    this.validatePropertyAccess(UserConfigurationProperties.XmlData);

    return this.xmlData;
  }

  /**
   * Sets the xml data.
   *
   * @param value the new xml data
   */
  public void setXmlData(byte[] value) {
    this.xmlData = value;

    this.markPropertyForUpdate(UserConfigurationProperties.XmlData);
  }

  /**
   * Gets the binary data of the user configuration.
   *
   * @return the binary data
   * @throws PropertyException the property exception
   */
  public byte[] getBinaryData() throws PropertyException {
    this.validatePropertyAccess(UserConfigurationProperties.BinaryData);

    return this.binaryData;

  }

  /**
   * Sets the binary data.
   *
   * @param value the new binary data
   */
  public void setBinaryData(byte[] value) {
    this.binaryData = value;
    this.markPropertyForUpdate(UserConfigurationProperties.BinaryData);
  }

  /**
   * Gets a value indicating whether this user configuration has been
   * modified.
   *
   * @return the checks if is dirty
   */
  public boolean getIsDirty() {
    return (!this.updatedProperties.contains(NoProperties))
        || this.dictionary.getIsDirty();
  }

  /**
   * Binds to an existing user configuration and loads the specified
   * property. Calling this method results in a call to EWS.
   *
   * @param service        The service to which the user configuration is bound.
   * @param name           The name of the user configuration.
   * @param parentFolderId The Id of the folder containing the user configuration.
   * @param properties     The property to load.
   * @return A user configuration instance.
   * @throws IndexOutOfBoundsException the index out of bounds exception
   * @throws Exception                 the exception
   */
  public static UserConfiguration bind(ExchangeService service, String name,
      FolderId parentFolderId, UserConfigurationProperties properties)
      throws IndexOutOfBoundsException, Exception {

    UserConfiguration result = service.getUserConfiguration(name,
        parentFolderId, properties);
    result.isNew = false;
    return result;
  }

  /**
   * Binds to an existing user configuration and loads the specified
   * property.
   *
   * @param service          The service to which the user configuration is bound.
   * @param name             The name of the user configuration.
   * @param parentFolderName The name of the folder containing the user configuration.
   * @param properties       The property to load.
   * @return A user configuration instance.
   * @throws IndexOutOfBoundsException the index out of bounds exception
   * @throws Exception                 the exception
   */
  public static UserConfiguration bind(ExchangeService service, String name,
      WellKnownFolderName parentFolderName,
      UserConfigurationProperties properties)
      throws IndexOutOfBoundsException, Exception {
    return UserConfiguration.bind(service, name, new FolderId(
        parentFolderName), properties);
  }

  /**
   * Saves the user configuration. Calling this method results in a call to
   * EWS.
   *
   * @param name           The name of the user configuration.
   * @param parentFolderId The Id of the folder in which to save the user configuration.
   * @throws Exception the exception
   */
  public void save(String name, FolderId parentFolderId) throws Exception {
    EwsUtilities.validateParam(name, "name");
    EwsUtilities.validateParam(parentFolderId, "parentFolderId");

    parentFolderId.validate(this.service.getRequestedServerVersion());

    if (!this.isNew) {
      throw new InvalidOperationException(
          "Calling Save isn't allowed because this user configuration isn't new. To apply local changes to this user configuration, call Update instead.");
    }

    this.parentFolderId = parentFolderId;
    this.name = name;

    this.service.createUserConfiguration(this);

    this.isNew = false;

    this.resetIsDirty();
  }

  /**
   * Saves the user configuration. Calling this method results in a call to
   * EWS.
   *
   * @param name             The name of the user configuration.
   * @param parentFolderName The name of the folder in which to save the user
   *                         configuration.
   * @throws Exception the exception
   */
  public void save(String name, WellKnownFolderName parentFolderName)
      throws Exception {
    this.save(name, new FolderId(parentFolderName));
  }

  /**
   * Updates the user configuration by applying local changes to the Exchange
   * server. Calling this method results in a call to EWS
   *
   * @throws Exception the exception
   */

  public void update() throws Exception {
    if (this.isNew) {
      throw new InvalidOperationException(
          "This user configuration can't be updated because it's never been saved.");
    }

    if (this.isPropertyUpdated(UserConfigurationProperties.BinaryData)
        || this
        .isPropertyUpdated(UserConfigurationProperties.
            Dictionary)
        || this.isPropertyUpdated(UserConfigurationProperties.
        XmlData)) {

      this.service.updateUserConfiguration(this);
    }

    this.resetIsDirty();
  }

  /**
   * Deletes the user configuration. Calling this method results in a call to
   * EWS.
   *
   * @throws Exception the exception
   */
  public void delete() throws Exception {
    if (this.isNew) {
      throw new InvalidOperationException(
          "This user configuration object can't be deleted because it's never been saved.");
    } else {
      this.service
          .deleteUserConfiguration(this.name, this.parentFolderId);
    }
  }

  /**
   * Loads the specified property on the user configuration. Calling this
   * method results in a call to EWS.
   *
   * @param properties The property to load.
   * @throws Exception the exception
   */
  public void load(UserConfigurationProperties properties) throws Exception {
    this.initializeProperties(EnumSet.of(properties));
    this.service.loadPropertiesForUserConfiguration(this, properties);
  }

  /**
   * Writes to XML.
   *
   * @param writer         The writer.
   * @param xmlNamespace   The XML namespace.
   * @param xmlElementName Name of the XML element.
   * @throws Exception the exception
   */
  public void writeToXml(EwsServiceXmlWriter writer, XmlNamespace xmlNamespace, String xmlElementName) throws Exception {
    EwsUtilities.ewsAssert(writer != null, "UserConfiguration.WriteToXml", "writer is null");
    EwsUtilities.ewsAssert(xmlElementName != null, "UserConfiguration.WriteToXml", "xmlElementName is null");

    writer.writeStartElement(xmlNamespace, xmlElementName);

    // Write the UserConfigurationName element
    writeUserConfigurationNameToXml(writer, XmlNamespace.Types, this.name,
        this.parentFolderId);

    // Write the Dictionary element
    if (this.isPropertyUpdated(UserConfigurationProperties.Dictionary)) {
      this.dictionary.writeToXml(writer, XmlElementNames.Dictionary);
    }

    // Write the XmlData element
    if (this.isPropertyUpdated(UserConfigurationProperties.XmlData)) {
      this.writeXmlDataToXml(writer);
    }

    // Write the BinaryData element
    if (this.isPropertyUpdated(UserConfigurationProperties.BinaryData)) {
      this.writeBinaryDataToXml(writer);
    }

    writer.writeEndElement();
  }

  /**
   * Determines whether the specified property was updated.
   *
   * @param property property to evaluate.
   * @return Boolean indicating whether to send the property Xml.
   */
  private boolean isPropertyUpdated(UserConfigurationProperties property) {
    boolean isPropertyDirty = false;
    boolean isPropertyEmpty = false;

    switch (property) {
      case Dictionary:
        isPropertyDirty = this.getDictionary().getIsDirty();
        isPropertyEmpty = this.getDictionary().getCount() == 0;
        break;
      case XmlData:
        isPropertyDirty = this.updatedProperties.contains(property);
        isPropertyEmpty = (this.xmlData == null) ||
            (this.xmlData.length == 0);
        break;
      case BinaryData:
        isPropertyDirty = this.updatedProperties.contains(property);
        isPropertyEmpty = (this.binaryData == null) ||
            (this.binaryData.length == 0);
        break;
      default:
        EwsUtilities.ewsAssert(false, "UserConfiguration.IsPropertyUpdated",
                               "property not supported: " + property.toString());
        break;
    }

    // Consider the property updated, if it's been modified, and either
    // . there's a value or
    // . there's no value but the operation is update.
    return isPropertyDirty && ((!isPropertyEmpty) || (!this.isNew));
  }

  /**
   * Writes the XmlData property to Xml.
   *
   * @param writer the writer
   * @throws XMLStreamException the XML stream exception
   * @throws ServiceXmlSerializationException the service xml serialization exception
   */
  private void writeXmlDataToXml(EwsServiceXmlWriter writer)
      throws XMLStreamException, ServiceXmlSerializationException {
    EwsUtilities.ewsAssert(writer != null, "UserConfiguration.WriteXmlDataToXml", "writer is null");

    writeByteArrayToXml(writer, this.xmlData, XmlElementNames.XmlData);
  }

  /**
   * Writes the BinaryData property to Xml.
   *
   * @param writer the writer
   * @throws XMLStreamException the XML stream exception
   * @throws ServiceXmlSerializationException the service xml serialization exception
   */
  private void writeBinaryDataToXml(EwsServiceXmlWriter writer)
      throws XMLStreamException, ServiceXmlSerializationException {
    EwsUtilities.ewsAssert(writer != null, "UserConfiguration.WriteBinaryDataToXml", "writer is null");

    writeByteArrayToXml(writer, this.binaryData,
        XmlElementNames.BinaryData);
  }



  /**
   * Loads from XML.
   *
   * @param reader The reader.
   * @throws Exception the exception
   */
  public void loadFromXml(EwsServiceXmlReader reader) throws Exception {
    EwsUtilities.ewsAssert(reader != null, "UserConfiguration.loadFromXml", "reader is null");

    reader.readStartElement(XmlNamespace.Messages,
        XmlElementNames.UserConfiguration);
    reader.read(); // Position at first property element

    do {
      if (reader.getNodeType().getNodeType() == XmlNodeType.START_ELEMENT) {
        if (reader.getLocalName().equals(
            XmlElementNames.UserConfigurationName)) {
          String responseName = reader
              .readAttributeValue(XmlAttributeNames.Name);

          EwsUtilities.ewsAssert(this.name.equals(responseName), "UserConfiguration.loadFromXml",
                                 "UserConfigurationName does not match: Expected: " + this.name
                                 + " Name in response: " + responseName);

          reader.skipCurrentElement();
        } else if (reader.getLocalName().equals(XmlElementNames.ItemId)) {
          this.itemId = new ItemId();
          this.itemId.loadFromXml(reader, XmlElementNames.ItemId);
        } else if (reader.getLocalName().equals(
            XmlElementNames.Dictionary)) {
          this.dictionary.loadFromXml(reader,
              XmlElementNames.Dictionary);
        } else if (reader.getLocalName()
            .equals(XmlElementNames.XmlData)) {
          this.xmlData = Base64.decodeBase64(reader.readElementValue());
        } else if (reader.getLocalName().equals(
            XmlElementNames.BinaryData)) {
          this.binaryData = Base64.decodeBase64(reader.readElementValue());
        } else {
          EwsUtilities.ewsAssert(false, "UserConfiguration.loadFromXml",
                                 "Xml element not supported: " + reader.getLocalName());
        }
      }

      // If XmlData was loaded, read is skipped because GetXmlData
      // positions the reader at the next property.
      reader.read();
    } while (!reader.isEndElement(XmlNamespace.Messages,
        XmlElementNames.UserConfiguration));
  }

  /**
   * Initializes property.
   *
   * @param requestedProperties The property requested for this UserConfiguration.
   */
  // / InitializeProperties is called in 3 cases:
  // / . Create new object: From the UserConfiguration constructor.
  // / . Bind to existing object: Again from the constructor. The constructor
  // is called eventually by the GetUserConfiguration request.
  // / . Refresh property: From the Load method.
  private void initializeProperties(
      EnumSet requestedProperties) {
    this.itemId = null;
    this.dictionary = new UserConfigurationDictionary();
    this.xmlData = null;
    this.binaryData = null;
    this.propertiesAvailableForAccess = requestedProperties;

    this.resetIsDirty();
  }

  /**
   * Resets flags to indicate that property haven't been modified.
   */
  private void resetIsDirty() {
    try {
      this.updatedProperties = EnumSet.of(NoProperties);
    } catch (Exception e) {
      LOG.error(e);
    }
    this.dictionary.setIsDirty(false);
  }

  /**
   * Determines whether the specified property may be accessed.
   *
   * @param property Property to access.
   * @throws PropertyException the property exception
   */
  private void validatePropertyAccess(UserConfigurationProperties property)
      throws PropertyException {
    if (!this.propertiesAvailableForAccess.contains(property)) {
      throw new PropertyException("You must load or assign this property before you can read its value.", property
          .toString());
    }
  }

  /**
   * Adds the passed property to updatedProperties.
   *
   * @param property Property to update.
   */
  private void markPropertyForUpdate(UserConfigurationProperties property) {
    this.updatedProperties.add(property);
    this.propertiesAvailableForAccess.add(property);

  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy