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

microsoft.exchange.webservices.data.core.service.ServiceObject Maven / Gradle / Ivy

There is a newer version: 2.15
Show newest version
/*
 * 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.core.service;

import microsoft.exchange.webservices.data.attribute.ServiceObjectDefinition;
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.PropertyBag;
import microsoft.exchange.webservices.data.core.PropertySet;
import microsoft.exchange.webservices.data.core.XmlElementNames;
import microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion;
import microsoft.exchange.webservices.data.core.enumeration.service.DeleteMode;
import microsoft.exchange.webservices.data.core.enumeration.service.SendCancellationsMode;
import microsoft.exchange.webservices.data.core.enumeration.service.calendar.AffectedTaskOccurrence;
import microsoft.exchange.webservices.data.core.exception.misc.InvalidOperationException;
import microsoft.exchange.webservices.data.core.exception.service.local.ServiceLocalException;
import microsoft.exchange.webservices.data.core.service.schema.ServiceObjectSchema;
import microsoft.exchange.webservices.data.misc.OutParam;
import microsoft.exchange.webservices.data.property.complex.ExtendedProperty;
import microsoft.exchange.webservices.data.property.complex.ExtendedPropertyCollection;
import microsoft.exchange.webservices.data.property.complex.IServiceObjectChangedDelegate;
import microsoft.exchange.webservices.data.property.complex.ServiceId;
import microsoft.exchange.webservices.data.property.definition.ExtendedPropertyDefinition;
import microsoft.exchange.webservices.data.property.definition.PropertyDefinition;
import microsoft.exchange.webservices.data.property.definition.PropertyDefinitionBase;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * Represents the base abstract class for all item and folder types.
 */
public abstract class ServiceObject {

  /**
   * The lock object.
   */
  private Object lockObject = new Object();

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

  /**
   * The property bag.
   */
  private PropertyBag propertyBag;

  /**
   * The xml element name.
   */
  private String xmlElementName;

  /**
   * Triggers dispatch of the change event.
   */
  public void changed() {

    for (IServiceObjectChangedDelegate change : this.onChange) {
      change.serviceObjectChanged(this);
    }
  }

  /**
   * Throws exception if this is a new service object.
   *
   * @throws InvalidOperationException the invalid operation exception
   * @throws ServiceLocalException     the service local exception
   */
  public void throwIfThisIsNew() throws InvalidOperationException,
      ServiceLocalException {
    if (this.isNew()) {
      throw new InvalidOperationException(
          "This operation can't be performed because this service object doesn't have an Id.");
    }
  }

  /**
   * Throws exception if this is not a new service object.
   *
   * @throws InvalidOperationException the invalid operation exception
   * @throws ServiceLocalException     the service local exception
   */
  protected void throwIfThisIsNotNew() throws InvalidOperationException,
      ServiceLocalException {
    if (!this.isNew()) {
      throw new InvalidOperationException(
          "This operation can't be performed because this service object already has an ID. To update this service object, use the Update() method instead.");
    }
  }

  // / This methods lets subclasses of ServiceObject override the default
  // mechanism
  // / by which the XML element name associated with their type is retrieved.

  /**
   * This methods lets subclasses of ServiceObject override the default
   * mechanism by which the XML element name associated with their type is
   * retrieved.
   *
   * @return String
   */
  protected String getXmlElementNameOverride() {
    return null;
  }

  /**
   * GetXmlElementName retrieves the XmlElementName of this type based on the
   * EwsObjectDefinition attribute that decorates it, if present.
   *
   * @return The XML element name associated with this type.
   */
  public String getXmlElementName() {
    if (this.isNullOrEmpty(this.xmlElementName)) {
      this.xmlElementName = this.getXmlElementNameOverride();
      if (this.isNullOrEmpty(this.xmlElementName)) {
        synchronized (this.lockObject) {

          ServiceObjectDefinition annotation = this.getClass()
              .getAnnotation(ServiceObjectDefinition.class);
          if (null != annotation) {
            this.xmlElementName = annotation.xmlElementName();
          }
        }
      }
    }
    EwsUtilities
        .ewsAssert(!isNullOrEmpty(this.xmlElementName), "EwsObject.GetXmlElementName", String
            .format("The class %s does not have an " + "associated XML element name.",
                    this.getClass().getName()));

    return this.xmlElementName;
  }

  /**
   * Gets the name of the change XML element.
   *
   * @return the change xml element name
   */
  public String getChangeXmlElementName() {
    return XmlElementNames.ItemChange;
  }

  /**
   * Gets the name of the set field XML element.
   *
   * @return String
   */
  public String getSetFieldXmlElementName() {
    return XmlElementNames.SetItemField;
  }

  /**
   * Gets the name of the delete field XML element.
   *
   * @return String
   */
  public String getDeleteFieldXmlElementName() {
    return XmlElementNames.DeleteItemField;
  }

  /**
   * Gets a value indicating whether a time zone SOAP header should be emitted
   * in a CreateItem or UpdateItem request so this item can be property saved
   * or updated.
   *
   * @param isUpdateOperation the is update operation
   * @return boolean
   * @throws ServiceLocalException
   * @throws Exception
   */
  protected boolean getIsTimeZoneHeaderRequired(boolean isUpdateOperation)
      throws ServiceLocalException, Exception {
    return false;
  }

  /**
   * Determines whether property defined with
   * ScopedDateTimePropertyDefinition require custom time zone scoping.
   *
   * @return boolean
   */
  protected boolean getIsCustomDateTimeScopingRequired() {
    return false;
  }

  /**
   * The property bag holding property values for this object.
   *
   * @return the property bag
   */
  public PropertyBag getPropertyBag() {
    return this.propertyBag;
  }

  /**
   * Internal constructor.
   *
   * @param service the service
   * @throws Exception the exception
   */
  protected ServiceObject(ExchangeService service) throws Exception {
    EwsUtilities.validateParam(service, "service");
    EwsUtilities.validateServiceObjectVersion(this, service
        .getRequestedServerVersion());
    this.service = service;
    this.propertyBag = new PropertyBag(this);
  }

  /**
   * Gets the schema associated with this type of object.
   *
   * @return ServiceObjectSchema
   */
  public ServiceObjectSchema schema() {
    return this.getSchema();
  }

  /**
   * Internal method to return the schema associated with this type of object.
   *
   * @return the schema
   */
  public abstract ServiceObjectSchema getSchema();

  /**
   * Gets the minimum required server version.
   *
   * @return the minimum required server version
   */
  public abstract ExchangeVersion getMinimumRequiredServerVersion();

  /**
   * Loads service object from XML.
   *
   * @param reader           the reader
   * @param clearPropertyBag the clear property bag
   * @throws Exception the exception
   */
  public void loadFromXml(EwsServiceXmlReader reader, boolean clearPropertyBag) throws Exception {

    this.getPropertyBag().loadFromXml(reader, clearPropertyBag,
        null, // propertySet
        false); // summaryPropertiesOnly

  }

  // / Validates this instance.

  /**
   * Validate.
   *
   * @throws Exception the exception
   */
  protected void validate() throws Exception {
    this.getPropertyBag().validate();
  }

  // / Loads service object from XML.

  /**
   * Load from xml.
   *
   * @param reader                the reader
   * @param clearPropertyBag      the clear property bag
   * @param requestedPropertySet  the requested property set
   * @param summaryPropertiesOnly the summary property only
   * @throws Exception the exception
   */
  public void loadFromXml(EwsServiceXmlReader reader, boolean clearPropertyBag,
      PropertySet requestedPropertySet, boolean summaryPropertiesOnly) throws Exception {

    this.getPropertyBag().loadFromXml(reader, clearPropertyBag,
        requestedPropertySet, summaryPropertiesOnly);

  }

  // Clears the object's change log.

  /**
   * Clear change log.
   */
  public void clearChangeLog() {
    this.getPropertyBag().clearChangeLog();
  }

  // / Writes service object as XML.

  /**
   * Write to xml.
   *
   * @param writer the writer
   * @throws Exception the exception
   */
  public void writeToXml(EwsServiceXmlWriter writer) throws Exception {
    this.getPropertyBag().writeToXml(writer);
  }

  // Writes service object for update as XML.

  /**
   * Write to xml for update.
   *
   * @param writer the writer
   * @throws Exception the exception
   */
  public void writeToXmlForUpdate(EwsServiceXmlWriter writer)
      throws Exception {
    this.getPropertyBag().writeToXmlForUpdate(writer);
  }

  // / Loads the specified set of property on the object.

  /**
   * Internal load.
   *
   * @param propertySet the property set
   * @throws Exception the exception
   */
  protected abstract void internalLoad(PropertySet propertySet)
      throws Exception;

  // / Deletes the object.

  /**
   * Internal delete.
   *
   * @param deleteMode              the delete mode
   * @param sendCancellationsMode   the send cancellations mode
   * @param affectedTaskOccurrences the affected task occurrences
   * @throws Exception the exception
   */
  protected abstract void internalDelete(DeleteMode deleteMode,
      SendCancellationsMode sendCancellationsMode,
      AffectedTaskOccurrence affectedTaskOccurrences) throws Exception;

  // / Loads the specified set of property. Calling this method results in a
  // call to EWS.

  /**
   * Load.
   *
   * @param propertySet the property set
   * @throws Exception the exception
   */
  public void load(PropertySet propertySet) throws Exception {
    this.internalLoad(propertySet);
  }

  // Loads the first class property. Calling this method results in a call
  // to EWS.

  /**
   * Load.
   *
   * @throws Exception the exception
   */
  public void load() throws Exception {
    this.internalLoad(PropertySet.getFirstClassProperties());
  }

  /**
   * Gets the value of specified property in this instance.
   *
   * @param propertyDefinition Definition of the property to get.
   * @return The value of specified property in this instance.
   * @throws Exception the exception
   */
  public Object getObjectFromPropertyDefinition(
      PropertyDefinitionBase propertyDefinition) throws Exception {
    PropertyDefinition propDef = (PropertyDefinition) propertyDefinition;

    if (propDef != null) {
      return this.getPropertyBag().getObjectFromPropertyDefinition(propDef);
    } else {
      // E14:226103 -- Other subclasses of PropertyDefinitionBase are not supported.
      throw new UnsupportedOperationException(String.format(
          "This operation isn't supported for property definition type %s.",
          propertyDefinition.getType().getName()));
    }
  }

  /**
   * Try to get the value of a specified extended property in this instance.
   *
   * @param propertyDefinition the property definition
   * @param propertyValue      the property value
   * @return true, if successful
   * @throws Exception the exception
   */
  protected  boolean tryGetExtendedProperty(Class cls,
      ExtendedPropertyDefinition propertyDefinition,
      OutParam propertyValue) throws Exception {
    ExtendedPropertyCollection propertyCollection = this
        .getExtendedProperties();

    if ((propertyCollection != null) &&
        propertyCollection.tryGetValue(cls, propertyDefinition, propertyValue)) {
      return true;
    } else {
      propertyValue.setParam(null);
      return false;
    }
  }

  /**
   * Try to get the value of a specified property in this instance.
   *
   * @param propertyDefinition The property definition.
   * @param propertyValue      The property value
   * @return True if property retrieved, false otherwise.
   * @throws Exception
   */
  public boolean tryGetProperty(PropertyDefinitionBase propertyDefinition, OutParam propertyValue)
      throws Exception {
    return this.tryGetProperty(Object.class, propertyDefinition, propertyValue);
  }

  /**
   * Try to get the value of a specified property in this instance.
   *
   * @param propertyDefinition the property definition
   * @param propertyValue      the property value
   * @return true, if successful
   * @throws Exception the exception
   */
  public  boolean tryGetProperty(Class cls, PropertyDefinitionBase propertyDefinition,
      OutParam propertyValue) throws Exception {

    PropertyDefinition propDef = (PropertyDefinition) propertyDefinition;
    if (propDef != null) {
      return this.getPropertyBag().tryGetPropertyType(cls, propDef, propertyValue);
    } else {
      // E14:226103 -- Other subclasses of PropertyDefinitionBase are not supported.
      throw new UnsupportedOperationException(String.format(
          "This operation isn't supported for property definition type %s.",
          propertyDefinition.getType().getName()));
    }
  }

  /**
   * Gets the collection of loaded property definitions.
   *
   * @return the loaded property definitions
   * @throws Exception the exception
   */
  public Collection getLoadedPropertyDefinitions()
      throws Exception {

    Collection propDefs =
        new ArrayList();
    for (PropertyDefinition propDef : this.getPropertyBag().getProperties()
        .keySet()) {
      propDefs.add(propDef);
    }

    if (this.getExtendedProperties() != null) {
      for (ExtendedProperty extProp : getExtendedProperties()) {
        propDefs.add(extProp.getPropertyDefinition());
      }
    }

    return propDefs;
  }

  /**
   * Gets the service.
   *
   * @return the service
   */
  public ExchangeService getService() {
    return service;
  }

  /**
   * Sets the service.
   *
   * @param service the new service
   */
  protected void setService(ExchangeService service) {
    this.service = service;
  }

  // / The property definition for the Id of this object.

  /**
   * Gets the id property definition.
   *
   * @return the id property definition
   */
  public PropertyDefinition getIdPropertyDefinition() {
    return null;
  }

  // / The unique Id of this object.

  /**
   * Gets the id.
   *
   * @return the id
   * @throws ServiceLocalException the service local exception
   */
  public ServiceId getId() throws ServiceLocalException {
    PropertyDefinition idPropertyDefinition = this
        .getIdPropertyDefinition();

    OutParam serviceId = new OutParam();

    if (idPropertyDefinition != null) {
      this.getPropertyBag().tryGetValue(idPropertyDefinition, serviceId);
    }

    return (ServiceId) serviceId.getParam();
  }

  // / Indicates whether this object is a real store item, or if it's a local
  // object
  // / that has yet to be saved.

  /**
   * Checks if is new.
   *
   * @return true, if is new
   * @throws ServiceLocalException the service local exception
   */
  public boolean isNew() throws ServiceLocalException {

    ServiceId id = this.getId();

    return id == null ? true : !id.isValid();

  }

  // / Gets a value indicating whether the object has been modified and should
  // be saved.

  /**
   * Checks if is dirty.
   *
   * @return true, if is dirty
   */
  public boolean isDirty() {
    return this.getPropertyBag().getIsDirty();

  }

  // Gets the extended property collection.

  /**
   * Gets the extended property.
   *
   * @return the extended property
   * @throws Exception the exception
   */
  protected ExtendedPropertyCollection getExtendedProperties()
      throws Exception {
    return null;
  }

  /**
   * Checks is the string is null or empty.
   *
   * @param namespacePrefix the namespace prefix
   * @return true, if is null or empty
   */
  private boolean isNullOrEmpty(String namespacePrefix) {
    return (namespacePrefix == null || namespacePrefix.isEmpty());

  }

  /**
   * The on change.
   */
  private List onChange =
      new ArrayList();

  /**
   * Adds the service object changed event.
   *
   * @param change the change
   */
  public void addServiceObjectChangedEvent(
      IServiceObjectChangedDelegate change) {
    this.onChange.add(change);
  }

  /**
   * Removes the service object changed event.
   *
   * @param change the change
   */
  public void removeServiceObjectChangedEvent(
      IServiceObjectChangedDelegate change) {
    this.onChange.remove(change);
  }

  /**
   * Clear service object changed event.
   */
  public void clearServiceObjectChangedEvent() {
    this.onChange.clear();
  }

}