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.ISelfValidate; 027import microsoft.exchange.webservices.data.attribute.EditorBrowsable; 028import microsoft.exchange.webservices.data.core.EwsServiceXmlReader; 029import microsoft.exchange.webservices.data.core.EwsServiceXmlWriter; 030import microsoft.exchange.webservices.data.core.enumeration.attribute.EditorBrowsableState; 031import microsoft.exchange.webservices.data.core.enumeration.misc.XmlNamespace; 032import microsoft.exchange.webservices.data.core.exception.service.local.ServiceValidationException; 033import microsoft.exchange.webservices.data.core.exception.service.local.ServiceXmlSerializationException; 034import microsoft.exchange.webservices.data.security.XmlNodeType; 035 036import java.util.ArrayList; 037import java.util.List; 038 039/** 040 * Represents a property that can be sent to or retrieved from EWS. 041 */ 042@EditorBrowsable(state = EditorBrowsableState.Never) 043public abstract class ComplexProperty implements ISelfValidate, ComplexFunctionDelegate<EwsServiceXmlReader> { 044 045 /** 046 * The xml namespace. 047 */ 048 private XmlNamespace xmlNamespace = XmlNamespace.Types; 049 050 /** 051 * Initializes a new instance. 052 */ 053 protected ComplexProperty() { 054 055 } 056 057 /** 058 * Gets the namespace. 059 * 060 * @return the namespace. 061 */ 062 public XmlNamespace getNamespace() { 063 return xmlNamespace; 064 } 065 066 /** 067 * Sets the namespace. 068 * 069 * @param xmlNamespace the namespace. 070 */ 071 public void setNamespace(XmlNamespace xmlNamespace) { 072 this.xmlNamespace = xmlNamespace; 073 } 074 075 /** 076 * Instance was changed. 077 */ 078 public void changed() { 079 if (!onChangeList.isEmpty()) { 080 for (IComplexPropertyChangedDelegate change : onChangeList) { 081 change.complexPropertyChanged(this); 082 } 083 } 084 } 085 086 /** 087 * Sets value of field. 088 * 089 * @param <T> Field type. 090 * @param field The field. 091 * @param value The value. 092 * @return true, if successful 093 */ 094 public <T> boolean canSetFieldValue(T field, T value) { 095 boolean applyChange; 096 if (field == null) { 097 applyChange = value != null; 098 } else { 099 if (field instanceof Comparable<?>) { 100 Comparable<T> c = (Comparable<T>) field; 101 applyChange = value != null && c.compareTo(value) != 0; 102 } else { 103 applyChange = true; 104 } 105 } 106 return applyChange; 107 } 108 109 /** 110 * Clears the change log. 111 */ 112 public void clearChangeLog() { 113 } 114 115 /** 116 * Reads the attribute from XML. 117 * 118 * @param reader The reader. 119 * @throws Exception the exception 120 */ 121 public void readAttributesFromXml(EwsServiceXmlReader reader) 122 throws Exception { 123 } 124 125 /** 126 * Reads the text value from XML. 127 * 128 * @param reader The reader. 129 * @throws Exception the exception 130 */ 131 public void readTextValueFromXml(EwsServiceXmlReader reader) 132 throws Exception { 133 } 134 135 /** 136 * Tries to read element from XML. 137 * 138 * @param reader The reader. 139 * @return True if element was read. 140 * @throws Exception the exception 141 */ 142 public boolean tryReadElementFromXml(EwsServiceXmlReader reader) 143 throws Exception { 144 return false; 145 } 146 147 /** 148 * Tries to read element from XML to patch this property. 149 * 150 * @param reader The reader. 151 * True if element was read. 152 */ 153 public boolean tryReadElementFromXmlToPatch(EwsServiceXmlReader reader) throws Exception { 154 return false; 155 } 156 157 /** 158 * Writes the attribute to XML. 159 * 160 * @param writer The writer. 161 * @throws ServiceXmlSerializationException the service xml serialization exception 162 */ 163 public void writeAttributesToXml(EwsServiceXmlWriter writer) 164 throws ServiceXmlSerializationException { 165 } 166 167 /** 168 * Writes elements to XML. 169 * 170 * @param writer The writer. 171 * @throws Exception the exception 172 */ 173 public void writeElementsToXml(EwsServiceXmlWriter writer) 174 throws Exception { 175 } 176 177 /** 178 * Loads from XML. 179 * 180 * @param reader The reader. 181 * @param xmlNamespace the xml namespace 182 * @param xmlElementName Name of the XML element. 183 * @throws Exception the exception 184 */ 185 public void loadFromXml(EwsServiceXmlReader reader, XmlNamespace xmlNamespace, String xmlElementName) throws Exception { 186 187 /*reader.ensureCurrentNodeIsStartElement(xmlNamespace, xmlElementName); 188 this.readAttributesFromXml(reader); 189 190 if (!reader.isEmptyElement()) { 191 do { 192 reader.read(); 193 194 switch (reader.getNodeType().nodeType) { 195 case XmlNodeType.START_ELEMENT: 196 if (!this.tryReadElementFromXml(reader)) { 197 reader.skipCurrentElement(); 198 } 199 break; 200 case XmlNodeType.CHARACTERS: 201 this.readTextValueFromXml(reader); 202 break; 203 } 204 } while (!reader.isEndElement(xmlNamespace, xmlElementName)); 205 } else { 206 // Adding this code to skip the END_ELEMENT of an Empty Element. 207 reader.read(); 208 reader.isEndElement(xmlNamespace, xmlElementName); 209 } */ 210 211 this.internalLoadFromXml(reader, xmlNamespace, xmlElementName); 212 } 213 214 /** 215 * Loads from XML to update this property. 216 * 217 * @param reader The reader. 218 * @param xmlElementName Name of the XML element. 219 * @throws Exception 220 */ 221 public void updateFromXml(EwsServiceXmlReader reader, String xmlElementName) throws Exception { 222 this.updateFromXml(reader, this.getNamespace(), xmlElementName); 223 } 224 225 /** 226 * Loads from XML to update itself. 227 * 228 * @param reader The reader. 229 * @param xmlNamespace The XML namespace. 230 * @param xmlElementName Name of the XML element. 231 */ 232 public void updateFromXml( 233 EwsServiceXmlReader reader, 234 XmlNamespace xmlNamespace, 235 String xmlElementName) throws Exception { 236 this.internalupdateLoadFromXml(reader, xmlNamespace, xmlElementName); 237 } 238 239 /** 240 * Loads from XML 241 * 242 * @param reader The Reader. 243 * @param xmlNamespace The Xml NameSpace. 244 * @param xmlElementName The Xml ElementName 245 */ 246 private void internalLoadFromXml( 247 EwsServiceXmlReader reader, 248 XmlNamespace xmlNamespace, 249 String xmlElementName) throws Exception { 250 reader.ensureCurrentNodeIsStartElement(xmlNamespace, xmlElementName); 251 252 this.readAttributesFromXml(reader); 253 254 if (!reader.isEmptyElement()) { 255 do { 256 reader.read(); 257 258 switch (reader.getNodeType().nodeType) { 259 case XmlNodeType.START_ELEMENT: 260 if (!this.tryReadElementFromXml(reader)) { 261 reader.skipCurrentElement(); 262 } 263 break; 264 case XmlNodeType.CHARACTERS: 265 this.readTextValueFromXml(reader); 266 break; 267 } 268 } while (!reader.isEndElement(xmlNamespace, xmlElementName)); 269 } else { 270 // Adding this code to skip the END_ELEMENT of an Empty Element. 271 reader.read(); 272 reader.isEndElement(xmlNamespace, xmlElementName); 273 } 274 } 275 276 private void internalupdateLoadFromXml( 277 EwsServiceXmlReader reader, 278 XmlNamespace xmlNamespace, 279 String xmlElementName) throws Exception { 280 reader.ensureCurrentNodeIsStartElement(xmlNamespace, xmlElementName); 281 282 this.readAttributesFromXml(reader); 283 284 if (!reader.isEmptyElement()) { 285 do { 286 reader.read(); 287 288 switch (reader.getNodeType().nodeType) { 289 case XmlNodeType.START_ELEMENT: 290 if (!this.tryReadElementFromXmlToPatch(reader)) { 291 reader.skipCurrentElement(); 292 } 293 break; 294 case XmlNodeType.CHARACTERS: 295 this.readTextValueFromXml(reader); 296 break; 297 } 298 } while (!reader.isEndElement(xmlNamespace, xmlElementName)); 299 } 300 } 301 302 /** 303 * Loads from XML. 304 * 305 * @param reader The reader. 306 * @param xmlElementName Name of the XML element. 307 * @throws Exception the exception 308 */ 309 public void loadFromXml(EwsServiceXmlReader reader, String xmlElementName) 310 throws Exception { 311 this.loadFromXml(reader, this.getNamespace(), xmlElementName); 312 } 313 314 /** 315 * Writes to XML. 316 * 317 * @param writer The writer. 318 * @param xmlNamespace The XML namespace. 319 * @param xmlElementName Name of the XML element. 320 * @throws Exception the exception 321 */ 322 public void writeToXml(EwsServiceXmlWriter writer, XmlNamespace xmlNamespace, String xmlElementName) throws Exception { 323 writer.writeStartElement(xmlNamespace, xmlElementName); 324 this.writeAttributesToXml(writer); 325 this.writeElementsToXml(writer); 326 writer.writeEndElement(); 327 } 328 329 /** 330 * Writes to XML. 331 * 332 * @param writer The writer. 333 * @param xmlElementName Name of the XML element. 334 * @throws Exception the exception 335 */ 336 public void writeToXml(EwsServiceXmlWriter writer, String xmlElementName) 337 throws Exception { 338 this.writeToXml(writer, this.getNamespace(), xmlElementName); 339 } 340 341 /** 342 * Change events occur when property changed. 343 */ 344 private List<IComplexPropertyChangedDelegate> onChangeList = 345 new ArrayList<IComplexPropertyChangedDelegate>(); 346 347 /** 348 * Set event to happen when property changed. 349 * 350 * @param change change event 351 */ 352 public void addOnChangeEvent(IComplexPropertyChangedDelegate change) { 353 onChangeList.add(change); 354 } 355 356 /** 357 * Remove the event from happening when property changed. 358 * 359 * @param change change event 360 */ 361 public void removeChangeEvent(IComplexPropertyChangedDelegate change) { 362 onChangeList.remove(change); 363 } 364 365 /** 366 * Clears change events list. 367 */ 368 protected void clearChangeEvents() { 369 onChangeList.clear(); 370 } 371 372 /** 373 * Implements ISelfValidate.validate. Validates this instance. 374 * 375 * @throws Exception the exception 376 */ 377 public void validate() throws Exception { 378 this.internalValidate(); 379 } 380 381 /** 382 * Validates this instance. 383 * 384 * @throws Exception the exception 385 */ 386 protected void internalValidate() throws Exception { 387 } 388 389 public Boolean func(EwsServiceXmlReader reader) throws Exception { 390 return !this.tryReadElementFromXml(reader); 391 } 392}