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.core.EwsServiceXmlReader;
027import microsoft.exchange.webservices.data.core.EwsServiceXmlWriter;
028import microsoft.exchange.webservices.data.core.EwsUtilities;
029import microsoft.exchange.webservices.data.core.XmlElementNames;
030import microsoft.exchange.webservices.data.core.enumeration.misc.XmlNamespace;
031import microsoft.exchange.webservices.data.core.exception.service.local.ServiceXmlSerializationException;
032import microsoft.exchange.webservices.data.misc.MapiTypeConverter;
033import microsoft.exchange.webservices.data.property.definition.ExtendedPropertyDefinition;
034import org.apache.commons.lang3.StringUtils;
035
036import javax.xml.stream.XMLStreamException;
037
038import java.util.ArrayList;
039
040/**
041 * Represents an extended property.
042 */
043public final class ExtendedProperty extends ComplexProperty {
044
045  /**
046   * The property definition.
047   */
048  private ExtendedPropertyDefinition propertyDefinition;
049
050  /**
051   * The value.
052   */
053  private Object value;
054
055  /**
056   * Initializes a new instance.
057   */
058  protected ExtendedProperty() {
059  }
060
061  /**
062   * Initializes a new instance.
063   *
064   * @param propertyDefinition The definition of the extended property.
065   * @throws Exception the exception
066   */
067  protected ExtendedProperty(ExtendedPropertyDefinition propertyDefinition)
068      throws Exception {
069    this();
070    EwsUtilities.validateParam(propertyDefinition, "propertyDefinition");
071    this.propertyDefinition = propertyDefinition;
072  }
073
074  /**
075   * Tries to read element from XML.
076   *
077   * @param reader The reader.
078   * @return true, if successful
079   * @throws Exception the exception
080   */
081  @Override
082  public boolean tryReadElementFromXml(EwsServiceXmlReader reader)
083      throws Exception {
084
085    if (reader.getLocalName().equals(XmlElementNames.ExtendedFieldURI)) {
086      this.propertyDefinition = new ExtendedPropertyDefinition();
087      this.propertyDefinition.loadFromXml(reader);
088      return true;
089    } else if (reader.getLocalName().equals(XmlElementNames.Value)) {
090      EwsUtilities.ewsAssert(this.getPropertyDefinition() != null, "ExtendedProperty.TryReadElementFromXml",
091                             "PropertyDefintion is missing");
092      String stringValue = reader.readElementValue();
093      this.value = MapiTypeConverter.convertToValue(this.getPropertyDefinition().getMapiType(), stringValue);
094      return true;
095    } else if (reader.getLocalName().equals(XmlElementNames.Values)) {
096      EwsUtilities.ewsAssert(this.getPropertyDefinition() != null, "ExtendedProperty.TryReadElementFromXml",
097                             "PropertyDefintion is missing");
098
099      StringList stringList = new StringList(XmlElementNames.Value);
100      stringList.loadFromXml(reader, reader.getLocalName());
101      this.value = MapiTypeConverter.convertToValue(this
102          .getPropertyDefinition().getMapiType(), stringList
103          .iterator());
104      return true;
105    } else {
106      return false;
107    }
108  }
109
110  /**
111   * Writes elements to XML.
112   *
113   * @param writer the writer
114   * @throws ServiceXmlSerializationException the service xml serialization exception
115   * @throws XMLStreamException the XML stream exception
116   */
117  @Override
118  public void writeElementsToXml(EwsServiceXmlWriter writer)
119      throws ServiceXmlSerializationException, XMLStreamException {
120    this.getPropertyDefinition().writeToXml(writer);
121
122    if (MapiTypeConverter.isArrayType(this.getPropertyDefinition()
123        .getMapiType())) {
124      ArrayList<?> array = (ArrayList<?>) this.getValue();
125      writer
126          .writeStartElement(XmlNamespace.Types,
127              XmlElementNames.Values);
128      for (int index = 0; index < array.size(); index++) {
129        writer.writeElementValue(XmlNamespace.Types,
130            XmlElementNames.Value, MapiTypeConverter
131                .convertToString(this.getPropertyDefinition()
132                    .getMapiType(), array.get(index)));
133      }
134      writer.writeEndElement();
135    } else {
136      writer.writeElementValue(XmlNamespace.Types, XmlElementNames.Value,
137          MapiTypeConverter.convertToString(this
138              .getPropertyDefinition().getMapiType(), this
139              .getValue()));
140    }
141  }
142
143  /**
144   * Gets the definition of the extended property.
145   *
146   * @return The definition of the extended property.
147   */
148  public ExtendedPropertyDefinition getPropertyDefinition() {
149    return this.propertyDefinition;
150  }
151
152  /**
153   * Gets the value of the extended property.
154   *
155   * @return the value
156   */
157  public Object getValue() {
158    return this.value;
159  }
160
161  /**
162   * Sets the value of the extended property.
163   *
164   * @param val value of the extended property
165   * @throws Exception the exception
166   */
167  public void setValue(Object val) throws Exception {
168    EwsUtilities.validateParam(val, "value");
169    if (this.canSetFieldValue(this.value, MapiTypeConverter.changeType(this
170        .getPropertyDefinition().getMapiType(), val))) {
171      this.value = MapiTypeConverter.changeType(this
172          .getPropertyDefinition().getMapiType(), val);
173      this.changed();
174    }
175  }
176
177  /**
178   * Gets the string value.
179   *
180   * @return String
181   */
182  private String getStringValue() {
183    if (MapiTypeConverter.isArrayType(this.getPropertyDefinition()
184        .getMapiType())) {
185      ArrayList<?> array = (ArrayList<?>) this.getValue();
186      if (array == null) {
187        return null;
188      } else {
189        StringBuilder sb = new StringBuilder();
190        sb.append("[");
191        for (int index = 0; index < array.size(); index++) {
192          sb.append(MapiTypeConverter.convertToString(this
193              .getPropertyDefinition().getMapiType(), array
194              .get(index)));
195          sb.append(",");
196        }
197        sb.append("]");
198
199        return sb.toString();
200      }
201    } else {
202      return MapiTypeConverter.convertToString(this
203          .getPropertyDefinition().getMapiType(), this.getValue());
204    }
205  }
206
207  /**
208   * Determines whether the specified <see cref="T:System.Object"/> is equal
209   * to the current <see cref="T:System.Object"/> true if the specified <see
210   * cref="T:System.Object"/> is equal to the current <see
211   * cref="T:System.Object"/>
212   *
213   * @param obj the obj
214   * @return boolean
215   */
216  @Override
217  public boolean equals(final Object obj) {
218    if (obj instanceof ExtendedProperty) {
219      final ExtendedProperty other = (ExtendedProperty) obj;
220      return other.getPropertyDefinition().equals(this.getPropertyDefinition())
221        && StringUtils.equals(this.getStringValue(), other.getStringValue());
222    }
223    return false;
224  }
225
226  /**
227   * Serves as a hash function for a particular type.
228   *
229   * @return int
230   */
231  @Override
232  public int hashCode() {
233    String printableName = this.getPropertyDefinition() != null ? this
234        .getPropertyDefinition().getPrintableName() : "";
235    String stringVal = this.getStringValue();
236    return (printableName + stringVal).hashCode();
237  }
238}