@jaricardodev/ews-javascript-api
Version:
EWS Managed api in JavaScript
464 lines (411 loc) • 18.4 kB
text/typescript
import { ArgumentOutOfRangeException } from "../Exceptions/ArgumentException";
import { ArrayHelper, StringHelper, TypeSystem } from "../ExtensionMethods";
import { EwsLogging } from "../Core/EwsLogging";
import { EwsServiceJsonReader } from "../Core/EwsServiceJsonReader";
import { EwsServiceXmlWriter } from "../Core/EwsServiceXmlWriter";
import { ExchangeService } from "../Core/ExchangeService";
import { ICustomUpdateSerializer } from "../Interfaces/ICustomXmlUpdateSerializer";
import { IEnumerable } from "../Interfaces/IEnumerable";
import { PropertyDefinition } from "../PropertyDefinitions/PropertyDefinition";
import { ServiceLocalException } from '../Exceptions/ServiceLocalException';
import { ServiceObject } from "../Core/ServiceObjects/ServiceObject";
import { Strings } from "../Strings";
import { XmlNamespace } from "../Enumerations/XmlNamespace";
import { ComplexProperty } from "./ComplexProperty";
/**
* Represents a collection of properties that can be sent to and retrieved from EWS.
*
* @type <TComplexProperty> ComplexProperty type.
*/
export abstract class ComplexPropertyCollection<TComplexProperty extends ComplexProperty> extends ComplexProperty implements IEnumerable<TComplexProperty>, ICustomUpdateSerializer {
___typeGenerics: string[] = ["ComplexProperty"];
private items: TComplexProperty[] = [];
private addedItems: TComplexProperty[] = [];
private modifiedItems: TComplexProperty[] = [];
private removedItems: TComplexProperty[] = [];
/**
* @internal Gets the items. (workaround for GetEnumerator)
*
* @return The items.
*/
get Items(): TComplexProperty[] { return this.items; }
/**
* @internal Gets the added items.
*
* @return The added items.
*/
get AddedItems(): TComplexProperty[] { return this.addedItems; }
/**
* @internal Gets the modified items.
*
* @return The modified items
*/
get ModifiedItems(): TComplexProperty[] { return this.modifiedItems; }
/**
* @internal Gets the removed items.
*
* @return The removed items.
*/
get RemovedItems(): TComplexProperty[] { return this.removedItems; }
/**
* Gets the total number of properties in the collection.
*/
get Count(): number { return this.items.length; }
/**
* Gets the property at the specified index.
*
* @param {number} index The zero-based index of the property to get.
* @return {TComplexProperty} The property at the specified index.
*/
_getItem(index: number): TComplexProperty {
if (index < 0 || index >= this.Count) {
throw new ArgumentOutOfRangeException("index", Strings.IndexIsOutOfRange);
}
return this.items[index];
}
/**
* @internal Initializes a new instance of the **ComplexPropertyCollection** class.
*
*/
constructor() {
super();
}
/**
* @internal Clears the change log.
*/
ClearChangeLog(): void {
this.removedItems.splice(0);
this.addedItems.splice(0);
this.modifiedItems.splice(0);
}
/**
* Determines whether a specific property is in the collection.
*
* @param {TComplexProperty} complexProperty The property to locate in the collection.
* @return {boolean} True if the property was found in the collection, false otherwise.
*/
Contains(complexProperty: TComplexProperty): boolean { return this.items.indexOf(complexProperty) >= 0; }
/**
* @internal Creates the complex property.
*
* @param {string} xmlElementName Name of the XML element.
* @return {TComplexProperty} Complex property instance.
*/
abstract CreateComplexProperty(xmlElementName: string): TComplexProperty;
/**
* @internal Creates the default complex property.
*
* @return {TComplexProperty} Complex property instance.
*/
abstract CreateDefaultComplexProperty(): TComplexProperty;
/**
* @internal Loads from XMLJsObject collection to create a new collection item.
*
* @interface IJsonCollectionDeserializer
*
* @param {any} jsObjectCollection The json collection.
* @param {ExchangeService} service The service.
*/
CreateFromXmlJsObjectCollection(jsObjectCollection: any, service: ExchangeService): void {
let collection: TComplexProperty[] = jsObjectCollection;
if (!ArrayHelper.isArray(collection)) {
collection = [];
let collectionElement = this.GetCollectionItemXmlElementName(null);
let typeName = TypeSystem.GetJsObjectTypeName(jsObjectCollection)
if (collectionElement === null || (typeName && collectionElement === typeName)) {
collection = [jsObjectCollection];
}
else {
for (let key in jsObjectCollection) {
if (key.indexOf("__") === 0) //skip xmljsobject conversion entries like __type and __prefix
continue;
let collectionObj: TComplexProperty[] = jsObjectCollection[key];
if (!ArrayHelper.isArray(collectionObj)) {
collectionObj = EwsServiceJsonReader.ReadAsArray(jsObjectCollection, key);
}
ArrayHelper.AddRange(collection, collectionObj);
}
}
}
for (let jsonObject of collection) {
let jsonProperty = jsonObject;
if (jsonProperty != null) {
let complexProperty: TComplexProperty = null;
// If type property is present, use it. Otherwise create default property instance.
// Note: polymorphic collections (such as Attachments) need a type property so
// the CreateDefaultComplexProperty call will fail.
if (TypeSystem.GetJsObjectTypeName(jsonProperty)) {
complexProperty = this.CreateComplexProperty(TypeSystem.GetJsObjectTypeName(jsonProperty));
}
else {
complexProperty = this.CreateDefaultComplexProperty();
}
if (complexProperty != null) {
complexProperty.LoadFromXmlJsObject(jsonProperty, service);
this.InternalAdd(complexProperty, true);
}
}
}
}
/**
* @internal Gets the name of the collection item XML element.
*
* @param {TComplexProperty} complexProperty The complex property.
* @return {string} XML element name.
*/
abstract GetCollectionItemXmlElementName(complexProperty: TComplexProperty): string;
/**
* Returns an enumerator that iterates through the collection. this case this.items
*/
GetEnumerator(): TComplexProperty[] {
return this.items;
}
/**
* Searches for a specific property and return its zero-based index within the collection.
*
* @param {TComplexProperty} complexProperty The property to locate in the collection.
* @return {number} The zero-based index of the property within the collection.
*/
IndexOf(complexProperty: TComplexProperty): number {
return this.items.indexOf(complexProperty);
}
/**
* @internal Add complex property.
*
* @param {TComplexProperty} complexProperty The complex property.
*/
InternalAdd(complexProperty: TComplexProperty): void;
/**
* @private Add complex property.
*
* @param {TComplexProperty} complexProperty The complex property.
* @param {boolean} loading If true, collection is being loaded.
*/
InternalAdd(complexProperty: TComplexProperty, loading: boolean): void;
InternalAdd(complexProperty: TComplexProperty, loading: boolean = false): void {
EwsLogging.Assert(
complexProperty != null,
"ComplexPropertyCollection.InternalAdd",
"complexProperty is null");
if (this.items.indexOf(complexProperty) < 0) {
this.items.push(complexProperty);
if (!loading) {
ArrayHelper.RemoveEntry(this.removedItems, complexProperty);// this.removedItems.Remove(complexProperty);
this.addedItems.push(complexProperty);
}
complexProperty.OnChange.push(this.ItemChanged.bind(this));
this.Changed();
}
}
/**
* @internal Clear collection.
*/
InternalClear(): void {
while (this.Count > 0) {
this.InternalRemoveAt(0);
}
}
/**
* @internal Remove specified complex property.
*
* @param {TComplexProperty} complexProperty The complex property.
* @return {boolean} True if the complex property was successfully removed from the collection, false otherwise.
*/
InternalRemove(complexProperty: TComplexProperty): boolean {
EwsLogging.Assert(
complexProperty != null,
"ComplexPropertyCollection.InternalRemove",
"complexProperty is null");
if (ArrayHelper.RemoveEntry(this.items, complexProperty)) { // this.items.Remove(complexProperty))
ArrayHelper.RemoveEntry(complexProperty.OnChange, this.ItemChanged);// complexProperty.OnChange -= this.ItemChanged;
if (this.addedItems.indexOf(complexProperty) < 0) {
this.removedItems.push(complexProperty);
}
else {
ArrayHelper.RemoveEntry(this.addedItems, complexProperty);// this.addedItems.Remove(complexProperty);
}
ArrayHelper.RemoveEntry(this.modifiedItems, complexProperty);// this.modifiedItems.Remove(complexProperty);
this.Changed();
return true;
}
else {
return false;
}
}
/**
* @internal Remote entry at index.
*
* @param {number} index The index.
*/
InternalRemoveAt(index: number): void {
EwsLogging.Assert(
index >= 0 && index < this.Count,
"ComplexPropertyCollection.InternalRemoveAt",
"index is out of range.");
this.InternalRemove(this.items[index]);
}
/**
* @internal Item changed.
*
* @param {ComplexProperty} complexProperty The complex property.
*/
ItemChanged(complexProperty: ComplexProperty): void {
//TComplexProperty property = complexProperty as TComplexProperty;
let property = complexProperty;
// EwsLogging.Assert(
// property != null,
// "ComplexPropertyCollection.ItemChanged",
// StringHelper.Format("ComplexPropertyCollection.ItemChanged: the type of the complexProperty argument ({0}) is not supported.", complexProperty.___typeName));
if (this.addedItems.indexOf(<TComplexProperty>property) < 0) {
if (this.modifiedItems.indexOf(<TComplexProperty>property) < 0) {
this.modifiedItems.push(<TComplexProperty>property);
this.Changed();
}
}
}
/**
* @internal Loads service object from XML.
*
* @param {any} jsObject Json Object converted from XML.
* @param {ExchangeService} service The service.
*/
LoadFromXmlJsObject(jsObject: any, service: ExchangeService): void {
EwsLogging.Assert(false, "ComplexPropertyCollection.LoadFromXmlJsObject", "LoadFromXmlJsObject was called, should not be calling. Fix it to direct to Create or Update call instad.")
this.CreateFromXmlJsObjectCollection(jsObject, service);
}
/**
* @internal Removes from change log.
*
* @param {TComplexProperty} complexProperty The complex property.
*/
RemoveFromChangeLog(complexProperty: TComplexProperty): void {
ArrayHelper.RemoveEntry(this.removedItems, complexProperty); //this.removedItems.Remove(complexProperty);
ArrayHelper.RemoveEntry(this.modifiedItems, complexProperty); //this.modifiedItems.Remove(complexProperty);
ArrayHelper.RemoveEntry(this.addedItems, complexProperty); //this.addedItems.Remove(complexProperty);
}
/**
* @internal Determine whether we should write collection to XML or not.
*
* @return {boolean} True if collection contains at least one element.
*/
ShouldWriteToRequest(): boolean {
// Only write collection if it has at least one element.
return this.Count > 0;
}
/**
* @internal Loads from XMLJsObject collection to update collection Items.
*
* @interface IJsonCollectionDeserializer
*
* @param {any} jsObjectCollection The XMLJsObject collection.
* @param {ExchangeService} service The service.
*/
UpdateFromXmlJsObjectCollection(jsObjectCollection: any, service: ExchangeService): void {
let collection: TComplexProperty[] = jsObjectCollection;
if (!ArrayHelper.isArray(collection)) {
collection = [];
let collectionElement = this.GetCollectionItemXmlElementName(null);
let typeName = TypeSystem.GetJsObjectTypeName(jsObjectCollection)
if (collectionElement === null || (typeName && collectionElement === typeName)) {
collection = [jsObjectCollection];
}
else {
for (let key in jsObjectCollection) {
if (key.indexOf("__") === 0) //skip xmljsobject conversion entries like __type and __prefix
continue;
let collectionObj: TComplexProperty[] = jsObjectCollection[key];
if (!ArrayHelper.isArray(collectionObj)) {
collectionObj = EwsServiceJsonReader.ReadAsArray(jsObjectCollection, key);
}
ArrayHelper.AddRange(collection, collectionObj);
}
}
}
if (this.Count != collection.length) {
throw new ServiceLocalException(Strings.PropertyCollectionSizeMismatch);
}
let index: number = 0;
for (let jsonObject of collection) {
let jsonProperty = jsonObject;
if (jsonProperty != null) {
let expectedComplexProperty: TComplexProperty = null;
if (TypeSystem.GetJsObjectTypeName(jsonProperty)) {
expectedComplexProperty = this.CreateComplexProperty(TypeSystem.GetJsObjectTypeName(jsonProperty));
}
else {
expectedComplexProperty = this.CreateDefaultComplexProperty();
}
let actualComplexProperty: TComplexProperty = this._getItem(index++);
if (expectedComplexProperty == null || !(actualComplexProperty instanceof expectedComplexProperty.constructor)) {
throw new ServiceLocalException(Strings.PropertyTypeIncompatibleWhenUpdatingCollection);
}
actualComplexProperty.LoadFromXmlJsObject(jsonProperty, service);
}
else {
throw new ServiceLocalException();
}
}
}
/**
* @internal Writes elements to XML.
*
* @param {EwsServiceXmlWriter} writer The writer.
*/
WriteElementsToXml(writer: EwsServiceXmlWriter): void {
for (let complexProperty of this.items) {
complexProperty.WriteToXml(writer, this.GetCollectionItemXmlElementName(complexProperty));
}
}
/**
* @internal Writes to XML.
*
* @param {EwsServiceXmlWriter} writer The writer.
* @param {XmlNamespace} xmlNamespace The XML namespace.
* @param {string} xmlElementName Name of the XML element.
*/
WriteToXml(writer: EwsServiceXmlWriter, xmlElementName: string, xmlNamespace: XmlNamespace = XmlNamespace.Types): void {
if (this.ShouldWriteToRequest()) {
super.WriteToXml(
writer,
xmlElementName,
xmlNamespace);
}
}
/**
* @internal Writes the update to XML.
* ICustomUpdateSerializer.WriteSetUpdateToXml
*
* @param {EwsServiceXmlWriter} writer The writer.
* @param {ServiceObject} ewsObject The ews object.
* @param {PropertyDefinition} propertyDefinition Property definition.
* @return {boolean} True if property generated serialization.
*/
WriteSetUpdateToXml(
writer: EwsServiceXmlWriter,
ewsObject: ServiceObject,
propertyDefinition: PropertyDefinition): boolean {
// If the collection is empty, delete the property.
if (this.Count == 0) {
writer.WriteStartElement(XmlNamespace.Types, ewsObject.GetDeleteFieldXmlElementName());
propertyDefinition.WriteToXml(writer);
writer.WriteEndElement();
return true;
}
// Otherwise, use the default XML serializer.
else {
return false;
}
}
/**
* @internal Writes the deletion update to XML.
* ICustomUpdateSerializer.WriteDeleteUpdateToXml
*
* @param {EwsServiceXmlWriter} writer The writer.
* @param {ServiceObject} ewsObject The ews object.
* @return {boolean} True if property generated serialization.
*/
WriteDeleteUpdateToXml(writer: EwsServiceXmlWriter, ewsObject: ServiceObject): boolean {
// Use the default XML serializer.
return false;
}
}