UNPKG

@jaricardodev/ews-javascript-api

Version:
464 lines (411 loc) 18.4 kB
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; } }