001/*
002 * The MIT License
003 * Copyright (c) 2012 Microsoft Corporation
004 *
005 * Permission is hereby granted, free of charge, to any person obtaining a copy
006 * of this software and associated documentation files (the "Software"), to deal
007 * in the Software without restriction, including without limitation the rights
008 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
009 * copies of the Software, and to permit persons to whom the Software is
010 * furnished to do so, subject to the following conditions:
011 *
012 * The above copyright notice and this permission notice shall be included in
013 * all copies or substantial portions of the Software.
014 *
015 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
016 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
017 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
018 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
019 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
020 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
021 * THE SOFTWARE.
022 */
023
024package microsoft.exchange.webservices.data.property.complex;
025
026import microsoft.exchange.webservices.data.attribute.EditorBrowsable;
027import microsoft.exchange.webservices.data.core.EwsServiceXmlReader;
028import microsoft.exchange.webservices.data.core.EwsServiceXmlWriter;
029import microsoft.exchange.webservices.data.core.EwsUtilities;
030import microsoft.exchange.webservices.data.core.ICustomXmlUpdateSerializer;
031import microsoft.exchange.webservices.data.core.XmlElementNames;
032import microsoft.exchange.webservices.data.core.service.ServiceObject;
033import microsoft.exchange.webservices.data.core.enumeration.attribute.EditorBrowsableState;
034import microsoft.exchange.webservices.data.core.enumeration.misc.XmlNamespace;
035import microsoft.exchange.webservices.data.core.exception.misc.ArgumentException;
036import microsoft.exchange.webservices.data.core.exception.service.local.ServiceXmlSerializationException;
037import microsoft.exchange.webservices.data.misc.OutParam;
038import microsoft.exchange.webservices.data.property.definition.ExtendedPropertyDefinition;
039import microsoft.exchange.webservices.data.property.definition.PropertyDefinition;
040
041import javax.xml.stream.XMLStreamException;
042
043import java.util.ArrayList;
044import java.util.List;
045
046/**
047 * Represents a collection of extended property.
048 */
049@EditorBrowsable(state = EditorBrowsableState.Never)
050public final class ExtendedPropertyCollection extends ComplexPropertyCollection<ExtendedProperty> implements
051                                                                                                  ICustomXmlUpdateSerializer {
052
053  /**
054   * Creates the complex property.
055   *
056   * @param xmlElementName Name of the XML element.
057   * @return Complex property instance.
058   */
059  @Override
060  protected ExtendedProperty createComplexProperty(String xmlElementName) {
061    // This method is unused in this class, so just return null.
062    return null;
063  }
064
065  /**
066   * Gets the name of the collection item XML element.
067   *
068   * @param complexProperty The complex property.
069   * @return XML element name.
070   */
071  @Override
072  protected String getCollectionItemXmlElementName(
073      ExtendedProperty complexProperty) {
074    // This method is unused in this class, so just return null.
075    return null;
076  }
077
078  /**
079   * Loads from XML.
080   *
081   * @param reader           The reader.
082   * @param localElementName Name of the local element.
083   * @throws Exception the exception
084   */
085  @Override public void loadFromXml(EwsServiceXmlReader reader, String localElementName) throws Exception {
086    ExtendedProperty extendedProperty = new ExtendedProperty();
087    extendedProperty.loadFromXml(reader, reader.getLocalName());
088    this.internalAdd(extendedProperty);
089  }
090
091  /**
092   * Writes to XML.
093   *
094   * @param writer         The writer.
095   * @param xmlElementName Name of the XML element.
096   * @throws Exception the exception
097   */
098  @Override public void writeToXml(EwsServiceXmlWriter writer, String xmlElementName)
099      throws Exception {
100    for (ExtendedProperty extendedProperty : this) {
101      extendedProperty.writeToXml(writer,
102          XmlElementNames.ExtendedProperty);
103    }
104  }
105
106  /**
107   * Gets existing or adds new extended property.
108   *
109   * @param propertyDefinition The property definition.
110   * @return ExtendedProperty.
111   * @throws Exception the exception
112   */
113  private ExtendedProperty getOrAddExtendedProperty(
114      ExtendedPropertyDefinition propertyDefinition) throws Exception {
115    ExtendedProperty extendedProperty = null;
116    OutParam<ExtendedProperty> extendedPropertyOut =
117        new OutParam<ExtendedProperty>();
118    if (!this.tryGetProperty(propertyDefinition, extendedPropertyOut)) {
119      extendedProperty = new ExtendedProperty(propertyDefinition);
120      this.internalAdd(extendedProperty);
121    } else {
122      extendedProperty = extendedPropertyOut.getParam();
123    }
124    return extendedProperty;
125  }
126
127  /**
128   * Sets an extended property.
129   *
130   * @param propertyDefinition The property definition.
131   * @param value              The value.
132   * @throws Exception the exception
133   */
134  public void setExtendedProperty(ExtendedPropertyDefinition propertyDefinition, Object value)
135      throws Exception {
136    ExtendedProperty extendedProperty = this
137        .getOrAddExtendedProperty(propertyDefinition);
138    extendedProperty.setValue(value);
139  }
140
141  /**
142   * Removes a specific extended property definition from the collection.
143   *
144   * @param propertyDefinition The definition of the extended property to remove.
145   * @return True if the property matching the extended property definition
146   * was successfully removed from the collection, false otherwise.
147   * @throws Exception the exception
148   */
149  public boolean removeExtendedProperty(ExtendedPropertyDefinition propertyDefinition) throws Exception {
150    EwsUtilities.validateParam(propertyDefinition, "propertyDefinition");
151
152    ExtendedProperty extendedProperty = null;
153    OutParam<ExtendedProperty> extendedPropertyOut =
154        new OutParam<ExtendedProperty>();
155    if (this.tryGetProperty(propertyDefinition, extendedPropertyOut)) {
156      extendedProperty = extendedPropertyOut.getParam();
157      return this.internalRemove(extendedProperty);
158    } else {
159      return false;
160    }
161  }
162
163  /**
164   * Tries to get property.
165   *
166   * @param propertyDefinition  The property definition.
167   * @param extendedPropertyOut The extended property.
168   * @return True of property exists in collection.
169   */
170  private boolean tryGetProperty(
171      ExtendedPropertyDefinition propertyDefinition,
172      OutParam<ExtendedProperty> extendedPropertyOut) {
173    boolean found = false;
174    extendedPropertyOut.setParam(null);
175    for (ExtendedProperty prop : this.getItems()) {
176      if (prop.getPropertyDefinition().equals(propertyDefinition)) {
177        found = true;
178        extendedPropertyOut.setParam(prop);
179        break;
180      }
181    }
182    return found;
183  }
184
185  /**
186   * Tries to get property value.
187   *
188   * @param propertyDefinition The property definition.
189   * @param propertyValueOut   The property value.
190   * @return True if property exists in collection.
191   * @throws ArgumentException
192   */
193  public <T> boolean tryGetValue(Class<T> cls, ExtendedPropertyDefinition propertyDefinition,
194      OutParam<T> propertyValueOut) throws ArgumentException {
195    ExtendedProperty extendedProperty = null;
196    OutParam<ExtendedProperty> extendedPropertyOut =
197        new OutParam<ExtendedProperty>();
198    if (this.tryGetProperty(propertyDefinition, extendedPropertyOut)) {
199      extendedProperty = extendedPropertyOut.getParam();
200      if (!cls.isAssignableFrom(propertyDefinition.getType())) {
201        String errorMessage = String.format(
202            "Property definition type '%s' and type parameter '%s' aren't compatible.",
203            propertyDefinition.getType().getSimpleName(),
204            cls.getSimpleName());
205        throw new ArgumentException(errorMessage, "propertyDefinition");
206      }
207      propertyValueOut.setParam((T) extendedProperty.getValue());
208      return true;
209    } else {
210      propertyValueOut.setParam(null);
211      return false;
212    }
213  }
214
215
216  /**
217   * Writes the update to XML.
218   *
219   * @param writer             The writer.
220   * @param ewsObject          The ews object.
221   * @param propertyDefinition Property definition.
222   * @return True if property generated serialization.
223   * @throws Exception the exception
224   */
225  @Override
226  public boolean writeSetUpdateToXml(EwsServiceXmlWriter writer,
227      ServiceObject ewsObject, PropertyDefinition propertyDefinition)
228      throws Exception {
229    List<ExtendedProperty> propertiesToSet =
230        new ArrayList<ExtendedProperty>();
231
232    propertiesToSet.addAll(this.getAddedItems());
233    propertiesToSet.addAll(this.getModifiedItems());
234
235    for (ExtendedProperty extendedProperty : propertiesToSet) {
236      writer.writeStartElement(XmlNamespace.Types, ewsObject
237          .getSetFieldXmlElementName());
238      extendedProperty.getPropertyDefinition().writeToXml(writer);
239
240      writer.writeStartElement(XmlNamespace.Types, ewsObject
241          .getXmlElementName());
242      extendedProperty.writeToXml(writer,
243          XmlElementNames.ExtendedProperty);
244      writer.writeEndElement();
245
246      writer.writeEndElement();
247    }
248
249    for (ExtendedProperty extendedProperty : this.getRemovedItems()) {
250      writer.writeStartElement(XmlNamespace.Types, ewsObject
251          .getDeleteFieldXmlElementName());
252      extendedProperty.getPropertyDefinition().writeToXml(writer);
253      writer.writeEndElement();
254    }
255
256    return true;
257  }
258
259  /**
260   * Writes the deletion update to XML.
261   *
262   * @param writer    the writer
263   * @param ewsObject the ews object
264   * @return true if property generated serialization
265   * @throws XMLStreamException the XML stream exception
266   * @throws ServiceXmlSerializationException the service xml serialization exception
267   */
268  @Override
269  public boolean writeDeleteUpdateToXml(EwsServiceXmlWriter writer,
270      ServiceObject ewsObject) throws XMLStreamException, ServiceXmlSerializationException {
271    for (ExtendedProperty extendedProperty : this.getItems()) {
272      writer.writeStartElement(XmlNamespace.Types, ewsObject
273          .getDeleteFieldXmlElementName());
274      extendedProperty.getPropertyDefinition().writeToXml(writer);
275      writer.writeEndElement();
276    }
277
278    return true;
279  }
280}