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.core.response;
025    
026    import microsoft.exchange.webservices.data.attribute.EditorBrowsable;
027    import microsoft.exchange.webservices.data.core.EwsServiceXmlReader;
028    import microsoft.exchange.webservices.data.core.EwsUtilities;
029    import microsoft.exchange.webservices.data.core.PropertySet;
030    import microsoft.exchange.webservices.data.core.XmlElementNames;
031    import microsoft.exchange.webservices.data.core.service.ServiceObject;
032    import microsoft.exchange.webservices.data.core.enumeration.sync.ChangeType;
033    import microsoft.exchange.webservices.data.core.enumeration.attribute.EditorBrowsableState;
034    import microsoft.exchange.webservices.data.core.enumeration.misc.XmlNamespace;
035    import microsoft.exchange.webservices.data.core.exception.service.local.ServiceLocalException;
036    import microsoft.exchange.webservices.data.sync.Change;
037    import microsoft.exchange.webservices.data.sync.ChangeCollection;
038    import 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)
047    public 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    }