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.core.response;
025
026import microsoft.exchange.webservices.data.attribute.EditorBrowsable;
027import microsoft.exchange.webservices.data.core.EwsServiceXmlReader;
028import microsoft.exchange.webservices.data.core.EwsUtilities;
029import microsoft.exchange.webservices.data.core.PropertySet;
030import microsoft.exchange.webservices.data.core.XmlElementNames;
031import microsoft.exchange.webservices.data.core.service.ServiceObject;
032import microsoft.exchange.webservices.data.core.enumeration.sync.ChangeType;
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.service.local.ServiceLocalException;
036import microsoft.exchange.webservices.data.sync.Change;
037import microsoft.exchange.webservices.data.sync.ChangeCollection;
038import microsoft.exchange.webservices.data.sync.ItemChange;
039
040/**
041 * Represents the base response class for synchronuization operations.
042 *
043 * @param <TServiceObject> ServiceObject type.
044 * @param <TChange>        Change type.
045 */
046@EditorBrowsable(state = EditorBrowsableState.Never)
047public abstract class SyncResponse<TServiceObject extends ServiceObject,
048    TChange extends Change> extends ServiceResponse {
049
050  /**
051   * The changes.
052   */
053  private ChangeCollection<TChange> changes = new ChangeCollection<TChange>();
054
055  /**
056   * The property set.
057   */
058  private PropertySet propertySet;
059
060  /**
061   * Initializes a new instance of the class.
062   *
063   * @param propertySet the property set
064   */
065  protected SyncResponse(PropertySet propertySet) {
066    super();
067    this.propertySet = propertySet;
068    EwsUtilities.ewsAssert(this.propertySet != null, "SyncResponse.ctor", "PropertySet should not be null");
069  }
070
071  /**
072   * Gets the name of the includes last in range XML element.
073   *
074   * @return XML element name.
075   */
076  protected abstract String getIncludesLastInRangeXmlElementName();
077
078  /**
079   * Creates the change instance.
080   *
081   * @return TChange instance
082   */
083  protected abstract TChange createChangeInstance();
084
085  /**
086   * Reads response elements from XML.
087   *
088   * @param reader the reader
089   * @throws ServiceLocalException the service local exception
090   * @throws Exception             the exception
091   */
092  @Override
093  protected void readElementsFromXml(EwsServiceXmlReader reader)
094      throws ServiceLocalException, Exception {
095    this.changes.setSyncState(reader.readElementValue(
096        XmlNamespace.Messages, XmlElementNames.SyncState));
097    this.changes.setMoreChangesAvailable(!reader.readElementValue(
098        Boolean.class, XmlNamespace.Messages, this
099            .getIncludesLastInRangeXmlElementName()));
100
101    reader.readStartElement(XmlNamespace.Messages, XmlElementNames.Changes);
102    if (!reader.isEmptyElement()) {
103      do {
104        reader.read();
105
106        if (reader.isStartElement()) {
107          TChange change = this.createChangeInstance();
108
109          if (reader.getLocalName().equals(XmlElementNames.Create)) {
110            change.setChangeType(ChangeType.Create);
111          } else if (reader.getLocalName().equals(
112              XmlElementNames.Update)) {
113            change.setChangeType(ChangeType.Update);
114          } else if (reader.getLocalName().equals(
115              XmlElementNames.Delete)) {
116            change.setChangeType(ChangeType.Delete);
117          } else if (reader.getLocalName().equals(
118              XmlElementNames.ReadFlagChange)) {
119            change.setChangeType(ChangeType.ReadFlagChange);
120          } else {
121            reader.skipCurrentElement();
122          }
123
124          if (change != null) {
125            reader.read();
126            reader.ensureCurrentNodeIsStartElement();
127
128            if (change.getChangeType().equals(ChangeType.Delete)
129                || change.getChangeType().equals(
130                ChangeType.ReadFlagChange)) {
131              change.setId(change.createId());
132              change.getId().loadFromXml(reader,
133                  change.getId().getXmlElementName());
134
135              if (change.getChangeType().equals(
136                  ChangeType.ReadFlagChange)) {
137                reader.read();
138                reader.ensureCurrentNodeIsStartElement();
139                ItemChange itemChange = null;
140                if (change instanceof ItemChange) {
141                  itemChange = (ItemChange) change;
142                }
143                EwsUtilities
144                    .ewsAssert(itemChange != null, "SyncResponse." + "ReadElementsFromXml",
145                               "ReadFlagChange is only " + "valid on ItemChange");
146
147                itemChange.setIsRead(reader.readElementValue(
148                    Boolean.class, XmlNamespace.Types,
149                    XmlElementNames.IsRead));
150              }
151            } else {
152
153              change.setServiceObject(EwsUtilities
154                  .createEwsObjectFromXmlElementName(null,
155                      reader.getService(), reader
156                          .getLocalName()));
157
158              change.getServiceObject().loadFromXml(reader,
159                  true, /* clearPropertyBag */
160                  this.propertySet, this.getSummaryPropertiesOnly());
161            }
162
163            reader.readEndElementIfNecessary(XmlNamespace.Types,
164                change.getChangeType().toString());
165
166            this.changes.add(change);
167          }
168        }
169      } while (!reader.isEndElement(XmlNamespace.Messages,
170          XmlElementNames.Changes));
171    } else {
172      reader.read();
173    }
174  }
175
176  /**
177   * Gets a list of changes that occurred on the synchronized folder.
178   *
179   * @return the changes
180   */
181  public ChangeCollection<TChange> getChanges() {
182    return this.changes;
183  }
184
185  /**
186   * Gets a value indicating whether this request returns full or summary
187   * property.
188   *
189   * @return the summary property only
190   */
191  protected abstract boolean getSummaryPropertiesOnly();
192
193}