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.attribute.EditorBrowsable;
027    import microsoft.exchange.webservices.data.core.EwsServiceXmlReader;
028    import microsoft.exchange.webservices.data.core.EwsServiceXmlWriter;
029    import microsoft.exchange.webservices.data.core.EwsUtilities;
030    import microsoft.exchange.webservices.data.core.XmlAttributeNames;
031    import microsoft.exchange.webservices.data.core.XmlElementNames;
032    import microsoft.exchange.webservices.data.core.enumeration.attribute.EditorBrowsableState;
033    import microsoft.exchange.webservices.data.core.enumeration.property.UserConfigurationDictionaryObjectType;
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.core.exception.service.local.ServiceXmlSerializationException;
037    import microsoft.exchange.webservices.data.misc.OutParam;
038    import microsoft.exchange.webservices.data.util.DateTimeUtils;
039    import org.apache.commons.codec.binary.Base64;
040    
041    import javax.xml.stream.XMLStreamException;
042    
043    import java.lang.reflect.Array;
044    import java.util.ArrayList;
045    import java.util.Date;
046    import java.util.HashMap;
047    import java.util.Iterator;
048    import java.util.List;
049    import java.util.Map;
050    import java.util.Map.Entry;
051    
052    /**
053     * Represents a user configuration's Dictionary property.
054     */
055    @EditorBrowsable(state = EditorBrowsableState.Never)
056    public final class UserConfigurationDictionary extends ComplexProperty
057        implements Iterable<Object> {
058    
059      // TODO: Consider implementing IsDirty mechanism in ComplexProperty.
060    
061      /**
062       * The dictionary.
063       */
064      private Map<Object, Object> dictionary;
065    
066      /**
067       * The is dirty.
068       */
069      private boolean isDirty = false;
070    
071      /**
072       * Initializes a new instance of "UserConfigurationDictionary" class.
073       */
074      public UserConfigurationDictionary() {
075        super();
076        this.dictionary = new HashMap<Object, Object>();
077      }
078    
079      /**
080       * Gets the element with the specified key.
081       *
082       * @param key The key of the element to get or set.
083       * @return The element with the specified key.
084       */
085      public Object getElements(Object key) {
086        return this.dictionary.get(key);
087      }
088    
089      /**
090       * Sets the element with the specified key.
091       *
092       * @param key   The key of the element to get or set
093       * @param value the value
094       * @throws Exception the exception
095       */
096      public void setElements(Object key, Object value) throws Exception {
097        this.validateEntry(key, value);
098        this.dictionary.put(key, value);
099        this.changed();
100      }
101    
102      /**
103       * Adds an element with the provided key and value to the user configuration
104       * dictionary.
105       *
106       * @param key   The object to use as the key of the element to add.
107       * @param value The object to use as the value of the element to add.
108       * @throws Exception the exception
109       */
110      public void addElement(Object key, Object value) throws Exception {
111        this.validateEntry(key, value);
112        this.dictionary.put(key, value);
113        this.changed();
114      }
115    
116      /**
117       * Determines whether the user configuration dictionary contains an element
118       * with the specified key.
119       *
120       * @param key The key to locate in the user configuration dictionary.
121       * @return true if the user configuration dictionary contains an element
122       * with the key; otherwise false.
123       */
124      public boolean containsKey(Object key) {
125        return this.dictionary.containsKey(key);
126      }
127    
128      /**
129       * Removes the element with the specified key from the user configuration
130       * dictionary.
131       *
132       * @param key The key of the element to remove.
133       * @return true if the element is successfully removed; otherwise false.
134       */
135      public boolean remove(Object key) {
136        boolean isRemoved = false;
137        if (key != null) {
138          this.dictionary.remove(key);
139          isRemoved = true;
140        }
141    
142        if (isRemoved) {
143          this.changed();
144        }
145    
146        return isRemoved;
147      }
148    
149      /**
150       * Gets the value associated with the specified key.
151       *
152       * @param key   The key whose value to get.
153       * @param value When this method returns, the value associated with the
154       *              specified key, if the key is found; otherwise, null.
155       * @return true if the user configuration dictionary contains the key;
156       * otherwise false.
157       */
158      public boolean tryGetValue(Object key, OutParam<Object> value) {
159        if (this.dictionary.containsKey(key)) {
160          value.setParam(this.dictionary.get(key));
161          return true;
162        } else {
163          value.setParam(null);
164          return false;
165        }
166    
167      }
168    
169      /**
170       * Gets the number of elements in the user configuration dictionary.
171       *
172       * @return the count
173       */
174      public int getCount() {
175        return this.dictionary.size();
176      }
177    
178      /**
179       * Removes all item from the user configuration dictionary.
180       */
181      public void clear() {
182        if (this.dictionary.size() != 0) {
183          this.dictionary.clear();
184    
185          this.changed();
186        }
187      }
188    
189      /**
190       * Gets the enumerator.
191       *
192       * @return the enumerator
193       */
194    
195      /**
196       * Returns an enumerator that iterates through
197       * the user configuration dictionary.
198       *
199       * @return An IEnumerator that can be used
200       * to iterate through the user configuration dictionary.
201       */
202      public Iterator<Object> getEnumerator() {
203        return (this.dictionary.values().iterator());
204      }
205    
206      /**
207       * Gets the isDirty flag.
208       *
209       * @return the checks if is dirty
210       */
211      public boolean getIsDirty() {
212        return this.isDirty;
213      }
214    
215      /**
216       * Sets the isDirty flag.
217       *
218       * @param value the new checks if is dirty
219       */
220      public void setIsDirty(boolean value) {
221        this.isDirty = value;
222      }
223    
224      /**
225       * Instance was changed.
226       */
227      @Override public void changed() {
228        super.changed();
229        this.isDirty = true;
230      }
231    
232      /**
233       * Writes elements to XML.
234       *
235       * @param writer accepts EwsServiceXmlWriter
236       * @throws XMLStreamException the XML stream exception
237       * @throws ServiceXmlSerializationException the service xml serialization exception
238       */
239      @Override
240      public void writeElementsToXml(EwsServiceXmlWriter writer)
241          throws XMLStreamException, ServiceXmlSerializationException {
242        EwsUtilities.ewsAssert(writer != null, "UserConfigurationDictionary.WriteElementsToXml", "writer is null");
243        Iterator<Entry<Object, Object>> it = this.dictionary.entrySet()
244            .iterator();
245        while (it.hasNext()) {
246          Entry<Object, Object> dictionaryEntry = it.next();
247          writer.writeStartElement(XmlNamespace.Types,
248              XmlElementNames.DictionaryEntry);
249          this.writeObjectToXml(writer, XmlElementNames.DictionaryKey,
250              dictionaryEntry.getKey());
251          this.writeObjectToXml(writer, XmlElementNames.DictionaryValue,
252              dictionaryEntry.getValue());
253          writer.writeEndElement();
254        }
255      }
256    
257      /**
258       * Writes a dictionary object (key or value) to Xml.
259       *
260       * @param writer           the writer
261       * @param xmlElementName   the Xml element name
262       * @param dictionaryObject the object to write
263       * @throws XMLStreamException the XML stream exception
264       * @throws ServiceXmlSerializationException the service xml serialization exception
265       */
266      private void writeObjectToXml(EwsServiceXmlWriter writer,
267          String xmlElementName, Object dictionaryObject)
268          throws XMLStreamException, ServiceXmlSerializationException {
269        EwsUtilities.ewsAssert(writer != null, "UserConfigurationDictionary.WriteObjectToXml", "writer is null");
270        EwsUtilities.ewsAssert(xmlElementName != null, "UserConfigurationDictionary.WriteObjectToXml",
271                               "xmlElementName is null");
272        writer.writeStartElement(XmlNamespace.Types, xmlElementName);
273    
274        if (dictionaryObject == null) {
275          EwsUtilities.ewsAssert((!xmlElementName.equals(XmlElementNames.DictionaryKey)),
276                                 "UserConfigurationDictionary.WriteObjectToXml", "Key is null");
277    
278          writer.writeAttributeValue(
279              EwsUtilities.EwsXmlSchemaInstanceNamespacePrefix,
280              XmlAttributeNames.Nil, EwsUtilities.XSTrue);
281        } else {
282          this.writeObjectValueToXml(writer, dictionaryObject);
283        }
284    
285        writer.writeEndElement();
286      }
287    
288      /**
289       * Writes a dictionary Object's value to Xml.
290       *
291       * @param writer           The writer.
292       * @param dictionaryObject The dictionary object to write. <br />
293       *                         Object values are either:  <br />
294       *                         an array of strings, an array of bytes (which will be encoded into base64) <br />
295       *                         or a single value. Single values can be: <br />
296       *                         - datetime, boolean, byte, int, long, string
297       * @throws XMLStreamException the XML stream exception
298       * @throws ServiceXmlSerializationException the service xml serialization exception
299       */
300      private void writeObjectValueToXml(final EwsServiceXmlWriter writer,
301          final Object dictionaryObject) throws XMLStreamException,
302          ServiceXmlSerializationException {
303        // Preconditions
304        if (dictionaryObject == null) {
305          throw new NullPointerException("DictionaryObject must not be null");
306        }
307        if (writer == null) {
308          throw new NullPointerException(
309              "EwsServiceXmlWriter must not be null");
310        }
311    
312        // Processing
313        final UserConfigurationDictionaryObjectType dictionaryObjectType;
314        if (dictionaryObject instanceof String[]) {
315          dictionaryObjectType = UserConfigurationDictionaryObjectType.StringArray;
316          this.writeEntryTypeToXml(writer, dictionaryObjectType);
317    
318          for (String arrayElement : (String[]) dictionaryObject) {
319            this.writeEntryValueToXml(writer, arrayElement);
320          }
321        } else {
322          final String valueAsString;
323          if (dictionaryObject instanceof String) {
324            dictionaryObjectType = UserConfigurationDictionaryObjectType.String;
325            valueAsString = String.valueOf(dictionaryObject);
326          } else if (dictionaryObject instanceof Boolean) {
327            dictionaryObjectType = UserConfigurationDictionaryObjectType.Boolean;
328            valueAsString = EwsUtilities
329                .boolToXSBool((Boolean) dictionaryObject);
330          } else if (dictionaryObject instanceof Byte) {
331            dictionaryObjectType = UserConfigurationDictionaryObjectType.Byte;
332            valueAsString = String.valueOf(dictionaryObject);
333          } else if (dictionaryObject instanceof Date) {
334            dictionaryObjectType = UserConfigurationDictionaryObjectType.DateTime;
335            valueAsString = writer.getService()
336                .convertDateTimeToUniversalDateTimeString(
337                    (Date) dictionaryObject);
338          } else if (dictionaryObject instanceof Integer) {
339            // removed unsigned integer because in Java, all types are
340            // signed, there are no unsigned versions
341            dictionaryObjectType = UserConfigurationDictionaryObjectType.Integer32;
342            valueAsString = String.valueOf(dictionaryObject);
343          } else if (dictionaryObject instanceof Long) {
344            // removed unsigned integer because in Java, all types are
345            // signed, there are no unsigned versions
346            dictionaryObjectType = UserConfigurationDictionaryObjectType.Integer64;
347            valueAsString = String.valueOf(dictionaryObject);
348          } else if (dictionaryObject instanceof byte[]) {
349            dictionaryObjectType = UserConfigurationDictionaryObjectType.ByteArray;
350            valueAsString = Base64.encodeBase64String((byte[]) dictionaryObject);
351          } else if (dictionaryObject instanceof Byte[]) {
352            dictionaryObjectType = UserConfigurationDictionaryObjectType.ByteArray;
353    
354            // cast Byte[] to byte[]
355            Byte[] from = (Byte[]) dictionaryObject;
356            byte[] to = new byte[from.length];
357            for (int currentIndex = 0; currentIndex < from.length; currentIndex++) {
358              to[currentIndex] = (byte) from[currentIndex];
359            }
360    
361            valueAsString = Base64.encodeBase64String(to);
362          } else {
363            throw new IllegalArgumentException(String.format(
364                "Unsupported type: %s", dictionaryObject.getClass()
365                    .toString()));
366          }
367          this.writeEntryTypeToXml(writer, dictionaryObjectType);
368          this.writeEntryValueToXml(writer, valueAsString);
369        }
370      }
371    
372    
373      /**
374       * Writes a dictionary entry type to Xml.
375       *
376       * @param writer               the writer
377       * @param dictionaryObjectType type to write
378       * @throws XMLStreamException the XML stream exception
379       * @throws ServiceXmlSerializationException the service xml serialization exception
380       */
381      private void writeEntryTypeToXml(EwsServiceXmlWriter writer,
382          UserConfigurationDictionaryObjectType dictionaryObjectType)
383          throws XMLStreamException, ServiceXmlSerializationException {
384        writer.writeStartElement(XmlNamespace.Types, XmlElementNames.Type);
385        writer
386            .writeValue(dictionaryObjectType.toString(),
387                XmlElementNames.Type);
388        writer.writeEndElement();
389      }
390    
391      /**
392       * Writes a dictionary entry value to Xml.
393       *
394       * @param writer the writer
395       * @param value  value to write
396       * @throws XMLStreamException the XML stream exception
397       * @throws ServiceXmlSerializationException the service xml serialization exception
398       */
399      private void writeEntryValueToXml(EwsServiceXmlWriter writer, String value)
400          throws XMLStreamException, ServiceXmlSerializationException {
401        writer.writeStartElement(XmlNamespace.Types, XmlElementNames.Value);
402    
403        // While an entry value can't be null, if the entry is an array, an
404        // element of the array can be null.
405        if (value != null) {
406          writer.writeValue(value, XmlElementNames.Value);
407        }
408    
409        writer.writeEndElement();
410      }
411    
412      /*
413       * (non-Javadoc)
414       *
415       * @see
416       * microsoft.exchange.webservices.ComplexProperty#loadFromXml(microsoft.
417       * exchange.webservices.EwsServiceXmlReader,
418       * microsoft.exchange.webservices.XmlNamespace, java.lang.String)
419       */
420      @Override
421      /**
422       * Loads this dictionary from the specified reader.
423       * @param reader The reader.
424       * @param xmlNamespace The dictionary's XML namespace.
425       * @param xmlElementName Name of the XML element
426       * representing the dictionary.
427       */ public void loadFromXml(EwsServiceXmlReader reader, XmlNamespace xmlNamespace, String xmlElementName) throws Exception {
428        super.loadFromXml(reader, xmlNamespace, xmlElementName);
429    
430        this.isDirty = false;
431      }
432    
433      /*
434       * (non-Javadoc)
435       *
436       * @see
437       * microsoft.exchange.webservices.ComplexProperty#tryReadElementFromXml(
438       * microsoft.exchange.webservices.EwsServiceXmlReader)
439       */
440      @Override
441      /**
442       * Tries to read element from XML.
443       * @param reader The reader.
444       * @return True if element was read.
445       */
446      public boolean tryReadElementFromXml(EwsServiceXmlReader reader)
447          throws Exception {
448        reader.ensureCurrentNodeIsStartElement(this.getNamespace(),
449            XmlElementNames.DictionaryEntry);
450        this.loadEntry(reader);
451        return true;
452      }
453    
454      /**
455       * Loads an entry, consisting of a key value pair, into this dictionary from
456       * the specified reader.
457       *
458       * @param reader The reader.
459       * @throws Exception the exception
460       */
461      private void loadEntry(EwsServiceXmlReader reader) throws Exception {
462        EwsUtilities.ewsAssert(reader != null, "UserConfigurationDictionary.LoadEntry", "reader is null");
463    
464        Object key;
465        Object value = null;
466    
467        // Position at DictionaryKey
468        reader.readStartElement(this.getNamespace(),
469            XmlElementNames.DictionaryKey);
470    
471        key = this.getDictionaryObject(reader);
472    
473        // Position at DictionaryValue
474        reader.readStartElement(this.getNamespace(),
475            XmlElementNames.DictionaryValue);
476    
477        String nil = reader.readAttributeValue(XmlNamespace.XmlSchemaInstance,
478            XmlAttributeNames.Nil);
479        boolean hasValue = (nil == null)
480            || (!nil.getClass().equals(Boolean.TYPE));
481        if (hasValue) {
482          value = this.getDictionaryObject(reader);
483        }
484        this.dictionary.put(key, value);
485      }
486    
487      /**
488       * Extracts a dictionary object (key or entry value) from the specified
489       * reader.
490       *
491       * @param reader The reader.
492       * @return Dictionary object.
493       * @throws Exception the exception
494       */
495      private Object getDictionaryObject(EwsServiceXmlReader reader)
496          throws Exception {
497        EwsUtilities.ewsAssert(reader != null, "UserConfigurationDictionary.loadFromXml", "reader is null");
498        UserConfigurationDictionaryObjectType type = this.getObjectType(reader);
499        List<String> values = this.getObjectValue(reader, type);
500        return this.constructObject(type, values, reader);
501      }
502    
503      /**
504       * Extracts a dictionary object (key or entry value) as a string list from
505       * the specified reader.
506       *
507       * @param reader The reader.
508       * @param type   The object type.
509       * @return String list representing a dictionary object.
510       * @throws Exception the exception
511       */
512      private List<String> getObjectValue(EwsServiceXmlReader reader,
513          UserConfigurationDictionaryObjectType type) throws Exception {
514        EwsUtilities.ewsAssert(reader != null, "UserConfigurationDictionary.loadFromXml", "reader is null");
515    
516        List<String> values = new ArrayList<String>();
517    
518        reader.readStartElement(this.getNamespace(), XmlElementNames.Value);
519    
520        do {
521          String value = null;
522    
523          if (reader.isEmptyElement()) {
524            // Only string types can be represented with empty values.
525            if (type.equals(UserConfigurationDictionaryObjectType.String)
526                || type
527                .equals(UserConfigurationDictionaryObjectType.
528                    StringArray)) {
529              value = "";
530            } else {
531              EwsUtilities
532                  .ewsAssert(false, "UserConfigurationDictionary." + "GetObjectValue",
533                             "Empty element passed for type: " + type.toString());
534    
535            }
536    
537          } else {
538            value = reader.readElementValue();
539          }
540    
541          values.add(value);
542          reader.read(); // Position at next element or
543          // DictionaryKey/DictionaryValue end element
544        } while (reader.isStartElement(this.getNamespace(),
545            XmlElementNames.Value));
546        return values;
547      }
548    
549      /**
550       * Extracts the dictionary object (key or entry value) type from the
551       * specified reader.
552       *
553       * @param reader The reader.
554       * @return Dictionary object type.
555       * @throws Exception the exception
556       */
557      private UserConfigurationDictionaryObjectType getObjectType(
558          EwsServiceXmlReader reader) throws Exception {
559        EwsUtilities.ewsAssert(reader != null, "UserConfigurationDictionary.loadFromXml", "reader is null");
560    
561        reader.readStartElement(this.getNamespace(), XmlElementNames.Type);
562    
563        String type = reader.readElementValue();
564        return UserConfigurationDictionaryObjectType.valueOf(type);
565      }
566    
567      /**
568       * Constructs a dictionary object (key or entry value) from the specified
569       * type and string list.
570       *
571       * @param type   Object type to construct.
572       * @param value  Value of the dictionary object as a string list
573       * @param reader The reader.
574       * @return Dictionary object.
575       */
576      private Object constructObject(UserConfigurationDictionaryObjectType type,
577          List<String> value, EwsServiceXmlReader reader) {
578        EwsUtilities.ewsAssert(value != null, "UserConfigurationDictionary.ConstructObject", "value is null");
579        EwsUtilities
580            .ewsAssert((value.size() == 1 || type == UserConfigurationDictionaryObjectType.StringArray),
581    
582                       "UserConfigurationDictionary.ConstructObject",
583                       "value is array but type is not StringArray");
584        EwsUtilities
585            .ewsAssert(reader != null, "UserConfigurationDictionary.ConstructObject", "reader is null");
586    
587        Object dictionaryObject = null;
588        if (type.equals(UserConfigurationDictionaryObjectType.Boolean)) {
589          dictionaryObject = Boolean.parseBoolean(value.get(0));
590        } else if (type.equals(UserConfigurationDictionaryObjectType.Byte)) {
591          dictionaryObject = Byte.parseByte(value.get(0));
592        } else if (type.equals(UserConfigurationDictionaryObjectType.ByteArray)) {
593          dictionaryObject = Base64.decodeBase64(value.get(0));
594        } else if (type.equals(UserConfigurationDictionaryObjectType.DateTime)) {
595          Date dateTime = DateTimeUtils.convertDateTimeStringToDate(value.get(0));
596          if (dateTime != null) {
597            dictionaryObject = dateTime;
598          } else {
599            EwsUtilities.ewsAssert(false, "UserConfigurationDictionary.ConstructObject", "DateTime is null");
600          }
601        } else if (type.equals(UserConfigurationDictionaryObjectType.Integer32)) {
602          dictionaryObject = Integer.parseInt(value.get(0));
603        } else if (type.equals(UserConfigurationDictionaryObjectType.Integer64)) {
604          dictionaryObject = Long.parseLong(value.get(0));
605        } else if (type.equals(UserConfigurationDictionaryObjectType.String)) {
606          dictionaryObject = String.valueOf(value.get(0));
607        } else if (type
608            .equals(UserConfigurationDictionaryObjectType.StringArray)) {
609          dictionaryObject = value.toArray();
610        } else if (type
611            .equals(UserConfigurationDictionaryObjectType.
612                UnsignedInteger32)) {
613          dictionaryObject = Integer.parseInt(value.get(0));
614        } else if (type
615            .equals(UserConfigurationDictionaryObjectType.
616                UnsignedInteger64)) {
617          dictionaryObject = Long.parseLong(value.get(0));
618        } else {
619          EwsUtilities.ewsAssert(false, "UserConfigurationDictionary.ConstructObject",
620                                 "Type not recognized: " + type.toString());
621        }
622    
623        return dictionaryObject;
624      }
625    
626      /**
627       * Validates the specified key and value.
628       *
629       * @param key   The key.
630       * @param value The diction dictionary entry key.ary entry value.
631       * @throws Exception the exception
632       */
633      private void validateEntry(Object key, Object value) throws Exception {
634        this.validateObject(key);
635        this.validateObject(value);
636    
637      }
638    
639      /**
640       * Validates the dictionary object (key or entry value).
641       *
642       * @param dictionaryObject Object to validate.
643       * @throws Exception the exception
644       */
645      private void validateObject(Object dictionaryObject) throws Exception {
646        // Keys may not be null but we rely on the internal dictionary to throw
647        // if the key is null.
648        if (dictionaryObject != null) {
649          if (dictionaryObject.getClass().isArray()) {
650            int length = Array.getLength(dictionaryObject);
651            Class<?> wrapperType = Array.get(dictionaryObject, 0).getClass();
652            Object[] newArray = (Object[]) Array.
653                newInstance(wrapperType, length);
654            for (int i = 0; i < length; i++) {
655              newArray[i] = Array.get(dictionaryObject, i);
656            }
657            this.validateArrayObject(newArray);
658          } else {
659            this.validateObjectType(dictionaryObject);
660    
661          }
662    
663        } else {
664          throw new NullPointerException();
665        }
666      }
667    
668      /**
669       * Validate the array object.
670       *
671       * @param dictionaryObjectAsArray Object to validate
672       * @throws ServiceLocalException the service local exception
673       */
674      private void validateArrayObject(Object[] dictionaryObjectAsArray)
675          throws ServiceLocalException {
676        // This logic is based on
677        // Microsoft.Exchange.Data.Storage.ConfigurationDictionary.
678        // CheckElementSupportedType().
679        // if (dictionaryObjectAsArray is string[])
680    
681        if (dictionaryObjectAsArray instanceof String[]) {
682          if (dictionaryObjectAsArray.length > 0) {
683            for (Object arrayElement : dictionaryObjectAsArray) {
684              if (arrayElement == null) {
685                throw new ServiceLocalException("The array contains at least one null element.");
686              }
687            }
688          } else {
689            throw new ServiceLocalException("The array must contain at least one element.");
690          }
691        } else if (dictionaryObjectAsArray instanceof Byte[]) {
692          if (dictionaryObjectAsArray.length <= 0) {
693            throw new ServiceLocalException("The array must contain at least one element.");
694          }
695        } else {
696          throw new ServiceLocalException(String.format(
697              "Objects of type %s can't be added to the dictionary. The following types are supported: string array, byte array, boolean, byte, DateTime, integer, long, string, unsigned integer, and unsigned long.", dictionaryObjectAsArray
698                  .getClass()));
699        }
700      }
701    
702      /**
703       * Validates the dictionary object type.
704       *
705       * @param theObject Object to validate.
706       * @throws ServiceLocalException the service local exception
707       */
708      private void validateObjectType(Object theObject) throws ServiceLocalException {
709        // This logic is based on
710        // Microsoft.Exchange.Data.Storage.ConfigurationDictionary.
711        // CheckElementSupportedType().
712        boolean isValidType = false;
713        if (theObject != null) {
714          if (theObject instanceof String ||
715              theObject instanceof Boolean ||
716              theObject instanceof Byte ||
717              theObject instanceof Long ||
718              theObject instanceof Date ||
719              theObject instanceof Integer) {
720            isValidType = true;
721          }
722        }
723    
724        if (!isValidType) {
725          throw new ServiceLocalException(
726              String.format(
727                  "Objects of type %s can't be added to the dictionary. The following types are supported: string array, byte array, boolean, byte, DateTime, integer, long, string, unsigned integer, and unsigned long.", (theObject != null ?
728                  theObject.getClass().toString() : "null")));
729        }
730      }
731    
732      /*
733       * (non-Javadoc)
734       *
735       * @see java.lang.Iterable#iterator()
736       */
737      @Override
738      public Iterator<Object> iterator() {
739        return this.dictionary.values().iterator();
740    
741      }
742    
743    }