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    
024    package microsoft.exchange.webservices.data.property.complex;
025    
026    import microsoft.exchange.webservices.data.core.EwsServiceXmlReader;
027    import microsoft.exchange.webservices.data.core.EwsServiceXmlWriter;
028    import microsoft.exchange.webservices.data.core.EwsUtilities;
029    import microsoft.exchange.webservices.data.core.XmlElementNames;
030    import microsoft.exchange.webservices.data.core.enumeration.misc.XmlNamespace;
031    import microsoft.exchange.webservices.data.core.exception.service.local.ServiceXmlSerializationException;
032    import microsoft.exchange.webservices.data.misc.MapiTypeConverter;
033    import microsoft.exchange.webservices.data.property.definition.ExtendedPropertyDefinition;
034    import org.apache.commons.lang3.StringUtils;
035    
036    import javax.xml.stream.XMLStreamException;
037    
038    import java.util.ArrayList;
039    
040    /**
041     * Represents an extended property.
042     */
043    public 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    }