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.search.filter; 025 026import microsoft.exchange.webservices.data.attribute.EditorBrowsable; 027import microsoft.exchange.webservices.data.core.EwsServiceXmlReader; 028import microsoft.exchange.webservices.data.core.EwsServiceXmlWriter; 029import microsoft.exchange.webservices.data.core.XmlAttributeNames; 030import microsoft.exchange.webservices.data.core.XmlElementNames; 031import microsoft.exchange.webservices.data.core.enumeration.search.ComparisonMode; 032import microsoft.exchange.webservices.data.core.enumeration.search.ContainmentMode; 033import microsoft.exchange.webservices.data.core.enumeration.attribute.EditorBrowsableState; 034import microsoft.exchange.webservices.data.core.enumeration.search.LogicalOperator; 035import microsoft.exchange.webservices.data.core.enumeration.misc.XmlNamespace; 036import microsoft.exchange.webservices.data.core.exception.service.local.ServiceValidationException; 037import microsoft.exchange.webservices.data.core.exception.service.local.ServiceXmlDeserializationException; 038import microsoft.exchange.webservices.data.core.exception.service.local.ServiceXmlSerializationException; 039import microsoft.exchange.webservices.data.misc.OutParam; 040import microsoft.exchange.webservices.data.property.complex.ComplexProperty; 041import microsoft.exchange.webservices.data.property.complex.IComplexPropertyChangedDelegate; 042import microsoft.exchange.webservices.data.property.complex.ISearchStringProvider; 043import microsoft.exchange.webservices.data.property.definition.PropertyDefinitionBase; 044import org.apache.commons.logging.Log; 045import org.apache.commons.logging.LogFactory; 046 047import javax.xml.stream.XMLStreamException; 048 049import java.util.ArrayList; 050import java.util.Iterator; 051 052/** 053 * Represents the base search filter class. Use descendant search filter classes 054 * such as SearchFilter.IsEqualTo, SearchFilter.ContainsSubstring and 055 * SearchFilter.SearchFilterCollection to define search filter. 056 */ 057public abstract class SearchFilter extends ComplexProperty { 058 059 private static final Log LOG = LogFactory.getLog(SearchFilter.class); 060 061 /** 062 * Initializes a new instance of the SearchFilter class. 063 */ 064 protected SearchFilter() { 065 } 066 067 /** 068 * The search. 069 * 070 * @param reader the reader 071 * @return the search filter 072 * @throws Exception the exception 073 */ 074 //static SearchFilter search; 075 076 /** 077 * Loads from XML. 078 * 079 * @param reader the reader 080 * @return SearchFilter 081 * @throws Exception the exception 082 */ 083 public static SearchFilter loadFromXml(EwsServiceXmlReader reader) 084 throws Exception { 085 reader.ensureCurrentNodeIsStartElement(); 086 087 SearchFilter searchFilter = null; 088 089 if (reader.getLocalName().equalsIgnoreCase(XmlElementNames.Exists)) { 090 searchFilter = new Exists(); 091 } else if (reader.getLocalName().equalsIgnoreCase( 092 XmlElementNames.Contains)) { 093 searchFilter = new ContainsSubstring(); 094 } else if (reader.getLocalName().equalsIgnoreCase( 095 XmlElementNames.Excludes)) { 096 searchFilter = new ExcludesBitmask(); 097 } else if (reader.getLocalName().equalsIgnoreCase(XmlElementNames.Not)) { 098 searchFilter = new Not(); 099 } else if (reader.getLocalName().equalsIgnoreCase(XmlElementNames.And)) { 100 searchFilter = new SearchFilterCollection( 101 LogicalOperator.And); 102 } else if (reader.getLocalName().equalsIgnoreCase(XmlElementNames.Or)) { 103 searchFilter = new SearchFilterCollection( 104 LogicalOperator.Or); 105 } else if (reader.getLocalName().equalsIgnoreCase( 106 XmlElementNames.IsEqualTo)) { 107 searchFilter = new IsEqualTo(); 108 } else if (reader.getLocalName().equalsIgnoreCase( 109 XmlElementNames.IsNotEqualTo)) { 110 searchFilter = new IsNotEqualTo(); 111 } else if (reader.getLocalName().equalsIgnoreCase( 112 XmlElementNames.IsGreaterThan)) { 113 searchFilter = new IsGreaterThan(); 114 } else if (reader.getLocalName().equalsIgnoreCase( 115 XmlElementNames.IsGreaterThanOrEqualTo)) { 116 searchFilter = new IsGreaterThanOrEqualTo(); 117 } else if (reader.getLocalName().equalsIgnoreCase( 118 XmlElementNames.IsLessThan)) { 119 searchFilter = new IsLessThan(); 120 } else if (reader.getLocalName().equalsIgnoreCase( 121 XmlElementNames.IsLessThanOrEqualTo)) { 122 searchFilter = new IsLessThanOrEqualTo(); 123 } else { 124 searchFilter = null; 125 } 126 127 if (searchFilter != null) { 128 searchFilter.loadFromXml(reader, reader.getLocalName()); 129 } 130 131 return searchFilter; 132 } 133 134 /** 135 * Gets the name of the XML element. 136 * 137 * @return the xml element name 138 */ 139 protected abstract String getXmlElementName(); 140 141 /** 142 * Writes to XML. 143 * 144 * @param writer the writer 145 * @throws Exception the exception 146 */ 147 public void writeToXml(EwsServiceXmlWriter writer) throws Exception { 148 super.writeToXml(writer, this.getXmlElementName()); 149 } 150 151 /** 152 * Represents a search filter that checks for the presence of a substring 153 * inside a text property. Applications can use ContainsSubstring to define 154 * conditions such as "Field CONTAINS Value" or 155 * "Field IS PREFIXED WITH Value". 156 */ 157 public static final class ContainsSubstring extends PropertyBasedFilter { 158 159 /** 160 * The containment mode. 161 */ 162 private ContainmentMode containmentMode = ContainmentMode.Substring; 163 164 /** 165 * The comparison mode. 166 */ 167 private ComparisonMode comparisonMode = ComparisonMode.IgnoreCase; 168 169 /** 170 * The value. 171 */ 172 private String value; 173 174 /** 175 * Initializes a new instance of the class. 176 */ 177 public ContainsSubstring() { 178 super(); 179 } 180 181 /** 182 * Initializes a new instance of the class. 183 * 184 * @param propertyDefinition The definition of the property that is being compared. 185 * @param value The value to compare with. 186 */ 187 public ContainsSubstring(PropertyDefinitionBase propertyDefinition, 188 String value) { 189 super(propertyDefinition); 190 this.value = value; 191 } 192 193 /** 194 * Initializes a new instance of the class. 195 * 196 * @param propertyDefinition The definition of the property that is being compared. 197 * @param value The value to compare with. 198 * @param containmentMode The containment mode. 199 * @param comparisonMode The comparison mode. 200 */ 201 public ContainsSubstring(PropertyDefinitionBase propertyDefinition, 202 String value, ContainmentMode containmentMode, 203 ComparisonMode comparisonMode) { 204 this(propertyDefinition, value); 205 this.containmentMode = containmentMode; 206 this.comparisonMode = comparisonMode; 207 } 208 209 /** 210 * validates instance. 211 * 212 * @throws ServiceValidationException the service validation exception 213 */ 214 @Override 215 protected void internalValidate() throws ServiceValidationException { 216 super.internalValidate(); 217 if ((this.value == null) || this.value.isEmpty()) { 218 throw new ServiceValidationException("The Value property must be set."); 219 } 220 } 221 222 /** 223 * Gets the name of the XML element. 224 * 225 * @return the xml element name 226 */ 227 @Override 228 protected String getXmlElementName() { 229 return XmlElementNames.Contains; 230 } 231 232 /** 233 * Tries to read element from XML. 234 * 235 * @param reader the reader 236 * @return True if element was read. 237 * @throws Exception the exception 238 */ 239 @Override 240 public boolean tryReadElementFromXml(EwsServiceXmlReader reader) 241 throws Exception { 242 boolean result = super.tryReadElementFromXml(reader); 243 244 if (!result) { 245 if (reader.getLocalName().equals(XmlElementNames.Constant)) { 246 this.value = reader 247 .readAttributeValue(XmlAttributeNames.Value); 248 result = true; 249 } 250 } 251 return result; 252 } 253 254 /** 255 * Reads the attribute of Xml. 256 * 257 * @param reader the reader 258 * @throws Exception the exception 259 */ 260 @Override 261 public void readAttributesFromXml(EwsServiceXmlReader reader) 262 throws Exception { 263 264 super.readAttributesFromXml(reader); 265 this.containmentMode = reader.readAttributeValue( 266 ContainmentMode.class, XmlAttributeNames.ContainmentMode); 267 try { 268 this.comparisonMode = reader.readAttributeValue( 269 ComparisonMode.class, 270 XmlAttributeNames.ContainmentComparison); 271 } catch (IllegalArgumentException ile) { 272 // This will happen if we receive a value that is defined in the 273 // EWS 274 // schema but that is not defined 275 // in the API. We map that 276 // value to IgnoreCaseAndNonSpacingCharacters. 277 this.comparisonMode = ComparisonMode. 278 IgnoreCaseAndNonSpacingCharacters; 279 } 280 } 281 282 /** 283 * Writes the attribute to XML. 284 * 285 * @param writer the writer 286 * @throws ServiceXmlSerializationException the service xml serialization exception 287 */ 288 @Override 289 public void writeAttributesToXml(EwsServiceXmlWriter writer) 290 throws ServiceXmlSerializationException { 291 super.writeAttributesToXml(writer); 292 293 writer.writeAttributeValue(XmlAttributeNames.ContainmentMode, 294 this.containmentMode); 295 writer.writeAttributeValue(XmlAttributeNames.ContainmentComparison, 296 this.comparisonMode); 297 } 298 299 /** 300 * Writes the elements to Xml. 301 * 302 * @param writer the writer 303 * @throws XMLStreamException the XML stream exception 304 * @throws ServiceXmlSerializationException the service xml serialization exception 305 */ 306 @Override 307 public void writeElementsToXml(EwsServiceXmlWriter writer) 308 throws XMLStreamException, ServiceXmlSerializationException { 309 super.writeElementsToXml(writer); 310 311 writer.writeStartElement(XmlNamespace.Types, 312 XmlElementNames.Constant); 313 writer.writeAttributeValue(XmlAttributeNames.Value, this.value); 314 writer.writeEndElement(); // Constant 315 } 316 317 /** 318 * Gets the containment mode. 319 * 320 * @return ContainmentMode 321 */ 322 public ContainmentMode getContainmentMode() { 323 return containmentMode; 324 } 325 326 /** 327 * sets the ContainmentMode. 328 * 329 * @param containmentMode the new containment mode 330 */ 331 public void setContainmentMode(ContainmentMode containmentMode) { 332 this.containmentMode = containmentMode; 333 } 334 335 /** 336 * Gets the comparison mode. 337 * 338 * @return ComparisonMode 339 */ 340 public ComparisonMode getComparisonMode() { 341 return comparisonMode; 342 } 343 344 /** 345 * sets the comparison mode. 346 * 347 * @param comparisonMode the new comparison mode 348 */ 349 public void setComparisonMode(ComparisonMode comparisonMode) { 350 this.comparisonMode = comparisonMode; 351 } 352 353 /** 354 * gets the value to compare the specified property with. 355 * 356 * @return String 357 */ 358 public String getValue() { 359 return value; 360 } 361 362 /** 363 * sets the value to compare the specified property with. 364 * 365 * @param value the new value 366 */ 367 public void setValue(String value) { 368 this.value = value; 369 } 370 } 371 372 373 /** 374 * Represents a bitmask exclusion search filter. Applications can use 375 * ExcludesBitExcludesBitmaskFilter to define conditions such as 376 * "(OrdinalField and 0x0010) != 0x0010" 377 */ 378 public static class ExcludesBitmask extends PropertyBasedFilter { 379 380 /** 381 * The bitmask. 382 */ 383 private int bitmask; 384 385 /** 386 * Initializes a new instance of the class. 387 */ 388 public ExcludesBitmask() { 389 super(); 390 } 391 392 /** 393 * Initializes a new instance of the class. 394 * 395 * @param propertyDefinition the property definition 396 * @param bitmask the bitmask 397 */ 398 public ExcludesBitmask(PropertyDefinitionBase propertyDefinition, 399 int bitmask) { 400 super(propertyDefinition); 401 this.bitmask = bitmask; 402 } 403 404 /** 405 * Gets the name of the XML element. 406 * 407 * @return XML element name 408 */ 409 @Override 410 public String getXmlElementName() { 411 return XmlElementNames.Excludes; 412 } 413 414 /** 415 * Tries to read element from XML. 416 * 417 * @param reader the reader 418 * @return true if element was read 419 * @throws Exception the exception 420 */ 421 @Override 422 public boolean tryReadElementFromXml(EwsServiceXmlReader reader) 423 throws Exception { 424 boolean result = super.tryReadElementFromXml(reader); 425 426 if (!result) { 427 if (reader.getLocalName().equals(XmlElementNames.Bitmask)) { 428 // EWS always returns the Bitmask value in hexadecimal 429 this.bitmask = Integer.parseInt(reader 430 .readAttributeValue(XmlAttributeNames.Value)); 431 } 432 } 433 434 return result; 435 } 436 437 /** 438 * Writes the elements to XML. 439 * 440 * @param writer the writer 441 * @throws javax.xml.stream.XMLStreamException , ServiceXmlSerializationException 442 * @throws ServiceXmlSerializationException the service xml serialization exception 443 */ 444 @Override 445 public void writeElementsToXml(EwsServiceXmlWriter writer) 446 throws XMLStreamException, ServiceXmlSerializationException { 447 super.writeElementsToXml(writer); 448 449 writer.writeStartElement(XmlNamespace.Types, 450 XmlElementNames.Bitmask); 451 writer.writeAttributeValue(XmlAttributeNames.Value, this.bitmask); 452 writer.writeEndElement(); // Bitmask 453 } 454 455 /** 456 * Gets the bitmask to compare the property with. 457 * 458 * @return bitmask 459 */ 460 public int getBitmask() { 461 return bitmask; 462 } 463 464 /** 465 * Sets the bitmask to compare the property with. 466 * 467 * @param bitmask the new bitmask 468 */ 469 public void setBitmask(int bitmask) { 470 this.bitmask = bitmask; 471 } 472 473 } 474 475 476 /** 477 * Represents a search filter checking if a field is set. Applications can 478 * use ExistsFilter to define conditions such as "Field IS SET". 479 */ 480 public static final class Exists extends PropertyBasedFilter { 481 482 /** 483 * Initializes a new instance of the class. 484 */ 485 public Exists() { 486 super(); 487 } 488 489 /** 490 * Initializes a new instance of the class. 491 * 492 * @param propertyDefinition the property definition 493 */ 494 public Exists(PropertyDefinitionBase propertyDefinition) { 495 super(propertyDefinition); 496 } 497 498 /** 499 * Gets the name of the XML element. 500 * 501 * @return the xml element name 502 */ 503 @Override 504 protected String getXmlElementName() { 505 return XmlElementNames.Exists; 506 } 507 } 508 509 510 /** 511 * Represents a search filter that checks if a property is equal to a given 512 * value or other property. 513 */ 514 public static class IsEqualTo extends RelationalFilter { 515 516 /** 517 * Initializes a new instance of the class. 518 */ 519 public IsEqualTo() { 520 super(); 521 } 522 523 /** 524 * Initializes a new instance of the class. 525 * 526 * @param propertyDefinition The definition of the property that is being compared. 527 * @param otherPropertyDefinition The definition of the property to compare with. 528 */ 529 public IsEqualTo(PropertyDefinitionBase propertyDefinition, 530 PropertyDefinitionBase otherPropertyDefinition) { 531 super(propertyDefinition, otherPropertyDefinition); 532 } 533 534 /** 535 * Initializes a new instance of the class. 536 * 537 * @param propertyDefinition The definition of the property that is being compared. 538 * @param value The value of the property to compare with. 539 */ 540 public IsEqualTo(PropertyDefinitionBase propertyDefinition, 541 Object value) { 542 super(propertyDefinition, value); 543 } 544 545 /** 546 * Gets the name of the XML element. 547 * 548 * @return the xml element name 549 */ 550 @Override 551 protected String getXmlElementName() { 552 return XmlElementNames.IsEqualTo; 553 } 554 555 } 556 557 558 /** 559 * Represents a search filter that checks if a property is greater than a 560 * given value or other property. 561 */ 562 public static class IsGreaterThan extends RelationalFilter { 563 564 /** 565 * Initializes a new instance of the class. 566 */ 567 public IsGreaterThan() { 568 super(); 569 } 570 571 /** 572 * Initializes a new instance of the class. 573 * 574 * @param propertyDefinition The definition of the property that is being compared. 575 * @param otherPropertyDefinition The definition of the property to compare with. 576 */ 577 public IsGreaterThan(PropertyDefinitionBase propertyDefinition, 578 PropertyDefinitionBase otherPropertyDefinition) { 579 super(propertyDefinition, otherPropertyDefinition); 580 } 581 582 /** 583 * Initializes a new instance of the class. 584 * 585 * @param propertyDefinition The definition of the property that is being compared. 586 * @param value The value of the property to compare with. 587 */ 588 public IsGreaterThan(PropertyDefinitionBase propertyDefinition, 589 Object value) { 590 super(propertyDefinition, value); 591 } 592 593 /** 594 * Gets the name of the XML element. 595 * 596 * @return XML element name. 597 */ 598 @Override 599 protected String getXmlElementName() { 600 return XmlElementNames.IsGreaterThan; 601 } 602 } 603 604 605 /** 606 * Represents a search filter that checks if a property is greater than or 607 * equal to a given value or other property. 608 */ 609 public static class IsGreaterThanOrEqualTo extends RelationalFilter { 610 611 /** 612 * Initializes a new instance of the class. 613 */ 614 public IsGreaterThanOrEqualTo() { 615 super(); 616 } 617 618 /** 619 * Initializes a new instance of the class. 620 * 621 * @param propertyDefinition The definition of the property that is being compared. 622 * @param otherPropertyDefinition The definition of the property to compare with. 623 */ 624 public IsGreaterThanOrEqualTo( 625 PropertyDefinitionBase propertyDefinition, 626 PropertyDefinitionBase otherPropertyDefinition) { 627 super(propertyDefinition, otherPropertyDefinition); 628 } 629 630 /** 631 * Initializes a new instance of the class. 632 * 633 * @param propertyDefinition The definition of the property that is being compared. 634 * @param value The value of the property to compare with. 635 */ 636 public IsGreaterThanOrEqualTo( 637 PropertyDefinitionBase propertyDefinition, Object value) { 638 super(propertyDefinition, value); 639 } 640 641 /** 642 * Gets the name of the XML element. XML element name. 643 * 644 * @return the xml element name 645 */ 646 @Override 647 protected String getXmlElementName() { 648 return XmlElementNames.IsGreaterThanOrEqualTo; 649 } 650 651 } 652 653 654 /** 655 * Represents a search filter that checks if a property is less than a given 656 * value or other property. 657 */ 658 public static class IsLessThan extends RelationalFilter { 659 660 /** 661 * Initializes a new instance of the class. 662 */ 663 public IsLessThan() { 664 super(); 665 } 666 667 /** 668 * Initializes a new instance of the class. 669 * 670 * @param propertyDefinition The definition of the property that is being compared. 671 * @param otherPropertyDefinition The definition of the property to compare with. 672 */ 673 public IsLessThan(PropertyDefinitionBase propertyDefinition, 674 PropertyDefinitionBase otherPropertyDefinition) { 675 super(propertyDefinition, otherPropertyDefinition); 676 } 677 678 /** 679 * Initializes a new instance of the class. 680 * 681 * @param propertyDefinition The definition of the property that is being compared. 682 * @param value The value of the property to compare with. 683 */ 684 public IsLessThan(PropertyDefinitionBase propertyDefinition, 685 Object value) { 686 super(propertyDefinition, value); 687 } 688 689 /** 690 * Gets the name of the XML element. XML element name. 691 * 692 * @return the xml element name 693 */ 694 @Override 695 protected String getXmlElementName() { 696 return XmlElementNames.IsLessThan; 697 } 698 699 } 700 701 702 /** 703 * Represents a search filter that checks if a property is less than or 704 * equal to a given value or other property. 705 */ 706 public static class IsLessThanOrEqualTo extends RelationalFilter { 707 708 /** 709 * Initializes a new instance of the class. 710 */ 711 public IsLessThanOrEqualTo() { 712 super(); 713 } 714 715 /** 716 * Initializes a new instance of the class. 717 * 718 * @param propertyDefinition The definition of the property that is being compared. 719 * @param otherPropertyDefinition The definition of the property to compare with. 720 */ 721 public IsLessThanOrEqualTo(PropertyDefinitionBase propertyDefinition, 722 PropertyDefinitionBase otherPropertyDefinition) { 723 super(propertyDefinition, otherPropertyDefinition); 724 } 725 726 /** 727 * Initializes a new instance of the class. 728 * 729 * @param propertyDefinition The definition of the property that is being compared. 730 * @param value The value of the property to compare with. 731 */ 732 public IsLessThanOrEqualTo(PropertyDefinitionBase propertyDefinition, 733 Object value) { 734 super(propertyDefinition, value); 735 } 736 737 /** 738 * Gets the name of the XML element. XML element name. 739 * 740 * @return the xml element name 741 */ 742 @Override 743 protected String getXmlElementName() { 744 return XmlElementNames.IsLessThanOrEqualTo; 745 } 746 747 } 748 749 750 /** 751 * Represents a search filter that checks if a property is not equal to a 752 * given value or other property. 753 */ 754 public static class IsNotEqualTo extends RelationalFilter { 755 756 /** 757 * Initializes a new instance of the class. 758 */ 759 public IsNotEqualTo() { 760 super(); 761 } 762 763 /** 764 * Initializes a new instance of the class. 765 * 766 * @param propertyDefinition The definition of the property that is being compared. 767 * @param otherPropertyDefinition The definition of the property to compare with. 768 */ 769 public IsNotEqualTo(PropertyDefinitionBase propertyDefinition, 770 PropertyDefinitionBase otherPropertyDefinition) { 771 super(propertyDefinition, otherPropertyDefinition); 772 } 773 774 /** 775 * Initializes a new instance of the class. 776 * 777 * @param propertyDefinition The definition of the property that is being compared. 778 * @param value The value of the property to compare with. 779 */ 780 public IsNotEqualTo(PropertyDefinitionBase propertyDefinition, 781 Object value) { 782 super(propertyDefinition, value); 783 } 784 785 /** 786 * Gets the name of the XML element. 787 * 788 * @return XML element name. 789 */ 790 @Override 791 protected String getXmlElementName() { 792 return XmlElementNames.IsNotEqualTo; 793 } 794 795 } 796 797 798 /** 799 * Represents a search filter that negates another. Applications can use 800 * NotFilter to define conditions such as "NOT(other filter)". 801 */ 802 public static class Not extends SearchFilter implements IComplexPropertyChangedDelegate { 803 804 /** 805 * The search filter. 806 */ 807 private SearchFilter searchFilter; 808 809 /** 810 * Initializes a new instance of the class. 811 */ 812 public Not() { 813 super(); 814 } 815 816 /** 817 * Initializes a new instance of the class. 818 * 819 * @param searchFilter the search filter 820 */ 821 public Not(SearchFilter searchFilter) { 822 super(); 823 this.searchFilter = searchFilter; 824 } 825 826 /** 827 * Search filter changed. 828 * 829 * @param complexProperty the complex property 830 */ 831 private void searchFilterChanged(ComplexProperty complexProperty) { 832 this.changed(); 833 } 834 835 /** 836 * validates the instance. 837 * 838 * @throws ServiceValidationException the service validation exception 839 */ 840 @Override 841 protected void internalValidate() throws ServiceValidationException { 842 if (this.searchFilter == null) { 843 throw new ServiceValidationException("The SearchFilter property must be set."); 844 } 845 } 846 847 /** 848 * Gets the name of the XML element. 849 * 850 * @return the xml element name 851 */ 852 @Override 853 protected String getXmlElementName() { 854 return XmlElementNames.Not; 855 } 856 857 /** 858 * Tries to read element from XML. 859 * 860 * @param reader the reader 861 * @return true if the element was read 862 * @throws Exception the exception 863 */ 864 @Override 865 public boolean tryReadElementFromXml(EwsServiceXmlReader reader) 866 throws Exception { 867 this.searchFilter = SearchFilter.loadFromXml(reader); 868 return true; 869 } 870 871 /** 872 * Writes the elements to XML. 873 * 874 * @param writer the writer 875 * @throws Exception the exception 876 */ 877 @Override 878 public void writeElementsToXml(EwsServiceXmlWriter writer) 879 throws Exception { 880 this.searchFilter.writeToXml(writer); 881 } 882 883 /** 884 * Gets the search filter to negate. Available search filter 885 * classes include SearchFilter.IsEqualTo, 886 * SearchFilter.ContainsSubstring and 887 * SearchFilter.SearchFilterCollection. 888 * 889 * @return SearchFilter 890 */ 891 public SearchFilter getSearchFilter() { 892 return searchFilter; 893 } 894 895 /** 896 * Sets the search filter to negate. Available search filter classes 897 * include SearchFilter.IsEqualTo, SearchFilter.ContainsSubstring and 898 * SearchFilter.SearchFilterCollection. 899 * 900 * @param searchFilter the new search filter 901 */ 902 public void setSearchFilter(SearchFilter searchFilter) { 903 if (this.searchFilter != null) { 904 this.searchFilter.removeChangeEvent(this); 905 } 906 907 if (this.canSetFieldValue(this.searchFilter, searchFilter)) { 908 this.searchFilter = searchFilter; 909 this.changed(); 910 911 } 912 913 if (this.searchFilter != null) { 914 this.searchFilter.addOnChangeEvent(this); 915 } 916 } 917 918 /* 919 * (non-Javadoc) 920 * 921 * @see 922 * microsoft.exchange.webservices. 923 * ComplexPropertyChangedDelegateInterface# 924 * complexPropertyChanged(microsoft.exchange.webservices.ComplexProperty 925 * ) 926 */ 927 @Override 928 public void complexPropertyChanged(ComplexProperty complexProperty) { 929 searchFilterChanged(complexProperty); 930 931 } 932 } 933 934 935 /** 936 * Represents a search filter where an item or folder property is involved. 937 */ 938 @EditorBrowsable(state = EditorBrowsableState.Never) 939 public static abstract class PropertyBasedFilter extends SearchFilter { 940 941 /** 942 * The property definition. 943 */ 944 private PropertyDefinitionBase propertyDefinition; 945 946 /** 947 * Initializes a new instance of the class. 948 */ 949 PropertyBasedFilter() { 950 super(); 951 } 952 953 /** 954 * Initializes a new instance of the class. 955 * 956 * @param propertyDefinition the property definition 957 */ 958 PropertyBasedFilter(PropertyDefinitionBase propertyDefinition) { 959 super(); 960 this.propertyDefinition = propertyDefinition; 961 } 962 963 /** 964 * validate instance. 965 * 966 * @throws ServiceValidationException the service validation exception 967 */ 968 @Override 969 protected void internalValidate() throws ServiceValidationException { 970 if (this.propertyDefinition == null) { 971 throw new ServiceValidationException("The PropertyDefinition property must be set."); 972 } 973 } 974 975 /** 976 * Tries to read element from XML. 977 * 978 * @param reader the reader 979 * @return true if element was read 980 * @throws Exception the exception 981 */ 982 @Override 983 public boolean tryReadElementFromXml(EwsServiceXmlReader reader) 984 throws Exception { 985 OutParam<PropertyDefinitionBase> outParam = 986 new OutParam<PropertyDefinitionBase>(); 987 outParam.setParam(this.propertyDefinition); 988 989 return PropertyDefinitionBase.tryLoadFromXml(reader, outParam); 990 } 991 992 /** 993 * Writes the elements to XML. 994 * 995 * @param writer the writer 996 * @throws XMLStreamException the XML stream exception 997 * @throws ServiceXmlSerializationException the service xml serialization exception 998 */ 999 @Override 1000 public void writeElementsToXml(EwsServiceXmlWriter writer) 1001 throws XMLStreamException, ServiceXmlSerializationException { 1002 this.propertyDefinition.writeToXml(writer); 1003 } 1004 1005 /** 1006 * Gets the definition of the property that is involved in the search 1007 * filter. 1008 * 1009 * @return propertyDefinition 1010 */ 1011 public PropertyDefinitionBase getPropertyDefinition() { 1012 return this.propertyDefinition; 1013 } 1014 1015 /** 1016 * Sets the definition of the property that is involved in the search 1017 * filter. 1018 * 1019 * @param propertyDefinition the new property definition 1020 */ 1021 public void setPropertyDefinition( 1022 PropertyDefinitionBase propertyDefinition) { 1023 this.propertyDefinition = propertyDefinition; 1024 } 1025 } 1026 1027 1028 /** 1029 * Represents the base class for relational filter (for example, IsEqualTo, 1030 * IsGreaterThan or IsLessThanOrEqualTo). 1031 */ 1032 @EditorBrowsable(state = EditorBrowsableState.Never) 1033 public abstract static class RelationalFilter extends PropertyBasedFilter { 1034 1035 /** 1036 * The other property definition. 1037 */ 1038 private PropertyDefinitionBase otherPropertyDefinition; 1039 1040 /** 1041 * The value. 1042 */ 1043 private Object value; 1044 1045 /** 1046 * Initializes a new instance of the class. 1047 */ 1048 RelationalFilter() { 1049 super(); 1050 } 1051 1052 /** 1053 * Initializes a new instance of the class. 1054 * 1055 * @param propertyDefinition The definition of the property that is being compared. 1056 * @param otherPropertyDefinition The definition of the property to compare with 1057 */ 1058 RelationalFilter(PropertyDefinitionBase propertyDefinition, 1059 PropertyDefinitionBase otherPropertyDefinition) { 1060 super(propertyDefinition); 1061 this.otherPropertyDefinition = otherPropertyDefinition; 1062 } 1063 1064 /** 1065 * Initializes a new instance of the class. 1066 * 1067 * @param propertyDefinition The definition of the property that is being compared. 1068 * @param value The value to compare with. 1069 */ 1070 RelationalFilter(PropertyDefinitionBase propertyDefinition, 1071 Object value) { 1072 super(propertyDefinition); 1073 this.value = value; 1074 } 1075 1076 /** 1077 * validates the instance. 1078 * 1079 * @throws ServiceValidationException the service validation exception 1080 */ 1081 @Override 1082 protected void internalValidate() throws ServiceValidationException { 1083 super.internalValidate(); 1084 1085 if (this.otherPropertyDefinition == null && this.value == null) { 1086 throw new ServiceValidationException( 1087 "Either the OtherPropertyDefinition or the Value property must be set."); 1088 } 1089 } 1090 1091 /** 1092 * Tries to read element from XML. 1093 * 1094 * @param reader the reader 1095 * @return true if element was read 1096 * @throws Exception the exception 1097 */ 1098 @Override 1099 public boolean tryReadElementFromXml(EwsServiceXmlReader reader) 1100 throws Exception { 1101 boolean result = super.tryReadElementFromXml(reader); 1102 1103 if (!result) { 1104 if (reader.getLocalName().equals( 1105 XmlElementNames.FieldURIOrConstant)) { 1106 try { 1107 reader.read(); 1108 reader.ensureCurrentNodeIsStartElement(); 1109 } catch (ServiceXmlDeserializationException e) { 1110 LOG.error(e); 1111 } catch (XMLStreamException e) { 1112 LOG.error(e); 1113 } 1114 1115 if (reader.isStartElement(XmlNamespace.Types, 1116 XmlElementNames.Constant)) { 1117 this.value = reader 1118 .readAttributeValue(XmlAttributeNames.Value); 1119 result = true; 1120 } else { 1121 OutParam<PropertyDefinitionBase> outParam = 1122 new OutParam<PropertyDefinitionBase>(); 1123 outParam.setParam(this.otherPropertyDefinition); 1124 1125 result = PropertyDefinitionBase.tryLoadFromXml(reader, 1126 outParam); 1127 } 1128 } 1129 } 1130 1131 return result; 1132 } 1133 1134 /** 1135 * Writes the elements to XML. 1136 * 1137 * @param writer the writer 1138 * @throws javax.xml.stream.XMLStreamException , ServiceXmlSerializationException 1139 * @throws ServiceXmlSerializationException the service xml serialization exception 1140 */ 1141 @Override 1142 public void writeElementsToXml(EwsServiceXmlWriter writer) 1143 throws XMLStreamException, ServiceXmlSerializationException { 1144 super.writeElementsToXml(writer); 1145 1146 writer.writeStartElement(XmlNamespace.Types, 1147 XmlElementNames.FieldURIOrConstant); 1148 1149 if (this.value != null) { 1150 writer.writeStartElement(XmlNamespace.Types, 1151 XmlElementNames.Constant); 1152 writer.writeAttributeValue(XmlAttributeNames.Value, 1153 true /* alwaysWriteEmptyString */, this.value); 1154 writer.writeEndElement(); // Constant 1155 } else { 1156 this.otherPropertyDefinition.writeToXml(writer); 1157 } 1158 1159 writer.writeEndElement(); // FieldURIOrConstant 1160 } 1161 1162 /** 1163 * Gets the definition of the property to compare with. 1164 * 1165 * @return otherPropertyDefinition 1166 */ 1167 public PropertyDefinitionBase getOtherPropertyDefinition() { 1168 return this.otherPropertyDefinition; 1169 } 1170 1171 /** 1172 * Sets the definition of the property to compare with. 1173 * 1174 * @param OtherPropertyDefinition the new other property definition 1175 */ 1176 public void setOtherPropertyDefinition( 1177 PropertyDefinitionBase OtherPropertyDefinition) { 1178 this.otherPropertyDefinition = OtherPropertyDefinition; 1179 this.value = null; 1180 } 1181 1182 /** 1183 * Gets the value of the property to compare with. 1184 * 1185 * @return the value 1186 */ 1187 public Object getValue() { 1188 return value; 1189 } 1190 1191 /** 1192 * Sets the value of the property to compare with. 1193 * 1194 * @param value the new value 1195 */ 1196 public void setValue(Object value) { 1197 this.value = value; 1198 this.otherPropertyDefinition = null; 1199 } 1200 1201 /** 1202 * gets Xml Element name. 1203 * 1204 * @return the xml element name 1205 */ 1206 @Override 1207 protected String getXmlElementName() { 1208 return null; 1209 } 1210 } 1211 1212 1213 /** 1214 * Represents a collection of search filter linked by a logical operator. 1215 * Applications can use SearchFilterCollection to define complex search 1216 * filter such as "Condition1 AND Condition2". 1217 */ 1218 public static class SearchFilterCollection extends SearchFilter implements 1219 Iterable<SearchFilter>, IComplexPropertyChangedDelegate { 1220 1221 /** 1222 * The logical operator. 1223 */ 1224 private LogicalOperator logicalOperator = LogicalOperator.And; 1225 1226 /** 1227 * The search filter. 1228 */ 1229 private ArrayList<SearchFilter> searchFilters = 1230 new ArrayList<SearchFilter>(); 1231 1232 /** 1233 * Initializes a new instance of the class. 1234 */ 1235 public SearchFilterCollection() { 1236 super(); 1237 } 1238 1239 /** 1240 * Initializes a new instance of the class. 1241 * 1242 * @param logicalOperator The logical operator used to initialize the collection. 1243 */ 1244 public SearchFilterCollection(LogicalOperator logicalOperator) { 1245 this.logicalOperator = logicalOperator; 1246 } 1247 1248 /** 1249 * Initializes a new instance of the class. 1250 * 1251 * @param logicalOperator The logical operator used to initialize the collection. 1252 * @param searchFilters The search filter to add to the collection. 1253 */ 1254 public SearchFilterCollection(LogicalOperator logicalOperator, 1255 SearchFilter... searchFilters) { 1256 this(logicalOperator); 1257 for (SearchFilter search : searchFilters) { 1258 Iterable<SearchFilter> searchFil = java.util.Arrays 1259 .asList(search); 1260 this.addRange(searchFil); 1261 } 1262 } 1263 1264 /** 1265 * Initializes a new instance of the class. 1266 * 1267 * @param logicalOperator The logical operator used to initialize the collection. 1268 * @param searchFilters The search filter to add to the collection. 1269 */ 1270 public SearchFilterCollection(LogicalOperator logicalOperator, 1271 Iterable<SearchFilter> searchFilters) { 1272 this(logicalOperator); 1273 this.addRange(searchFilters); 1274 } 1275 1276 /** 1277 * Validate instance. 1278 * 1279 * @throws Exception 1280 */ 1281 @Override 1282 protected void internalValidate() throws Exception { 1283 for (int i = 0; i < this.getCount(); i++) { 1284 try { 1285 this.searchFilters.get(i).internalValidate(); 1286 } catch (ServiceValidationException e) { 1287 throw new ServiceValidationException(String.format("The search filter at index %d is invalid.", i), 1288 e); 1289 } 1290 } 1291 } 1292 1293 /** 1294 * A search filter has changed. 1295 * 1296 * @param complexProperty The complex property 1297 */ 1298 private void searchFilterChanged(ComplexProperty complexProperty) { 1299 this.changed(); 1300 } 1301 1302 /** 1303 * Gets the name of the XML element. 1304 * 1305 * @return xml element name 1306 */ 1307 @Override 1308 protected String getXmlElementName() { 1309 return this.logicalOperator.toString(); 1310 } 1311 1312 /** 1313 * Tries to read element from XML. 1314 * 1315 * @param reader the reader 1316 * @return true, if successful 1317 * @throws Exception the exception 1318 */ 1319 @Override 1320 public boolean tryReadElementFromXml(EwsServiceXmlReader reader) 1321 throws Exception { 1322 1323 this.add(SearchFilter.loadFromXml(reader)); 1324 return true; 1325 } 1326 1327 /** 1328 * Writes the elements to XML. 1329 * 1330 * @param writer the writer 1331 * @throws Exception the exception 1332 */ 1333 @Override 1334 public void writeElementsToXml(EwsServiceXmlWriter writer) 1335 throws Exception { 1336 for (SearchFilter searchFilter : this.searchFilters) { 1337 searchFilter.writeToXml(writer); 1338 } 1339 } 1340 1341 /** 1342 * Writes to XML. 1343 * 1344 * @param writer the writer 1345 * @throws Exception the exception 1346 */ 1347 @Override public void writeToXml(EwsServiceXmlWriter writer) throws Exception { 1348 // If there is only one filter in the collection, which developers 1349 // tend 1350 // to do, 1351 // we need to not emit the collection and instead only emit the one 1352 // filter within 1353 // the collection. This is to work around the fact that EWS does not 1354 // allow filter 1355 // collections that have less than two elements. 1356 if (this.getCount() == 1) { 1357 this.searchFilters.get(0).writeToXml(writer); 1358 } else { 1359 super.writeToXml(writer); 1360 } 1361 } 1362 1363 /** 1364 * Adds a search filter of any type to the collection. 1365 * 1366 * @param searchFilter >The search filter to add. Available search filter classes 1367 * include SearchFilter.IsEqualTo, 1368 * SearchFilter.ContainsSubstring and 1369 * SearchFilter.SearchFilterCollection. 1370 */ 1371 public void add(SearchFilter searchFilter) { 1372 if (searchFilter == null) { 1373 throw new IllegalArgumentException("searchFilter"); 1374 } 1375 searchFilter.addOnChangeEvent(this); 1376 this.searchFilters.add(searchFilter); 1377 this.changed(); 1378 } 1379 1380 /** 1381 * Adds multiple search filter to the collection. 1382 * 1383 * @param searchFilters The search filter to add. Available search filter classes 1384 * include SearchFilter.IsEqualTo, 1385 * SearchFilter.ContainsSubstring and 1386 * SearchFilter.SearchFilterCollection 1387 */ 1388 public void addRange(Iterable<SearchFilter> searchFilters) { 1389 if (searchFilters == null) { 1390 throw new IllegalArgumentException("searchFilters"); 1391 } 1392 1393 for (SearchFilter searchFilter : searchFilters) { 1394 searchFilter.addOnChangeEvent(this); 1395 this.searchFilters.add(searchFilter); 1396 } 1397 this.changed(); 1398 } 1399 1400 /** 1401 * Clears the collection. 1402 */ 1403 public void clear() { 1404 if (this.getCount() > 0) { 1405 for (SearchFilter searchFilter : this.searchFilters) { 1406 searchFilter.removeChangeEvent(this); 1407 } 1408 this.searchFilters.clear(); 1409 this.changed(); 1410 } 1411 } 1412 1413 /** 1414 * Determines whether a specific search filter is in the collection. 1415 * 1416 * @param searchFilter The search filter to locate in the collection. 1417 * @return True is the search filter was found in the collection, false 1418 * otherwise. 1419 */ 1420 public boolean contains(SearchFilter searchFilter) { 1421 return this.searchFilters.contains(searchFilter); 1422 } 1423 1424 /** 1425 * Removes a search filter from the collection. 1426 * 1427 * @param searchFilter The search filter to remove 1428 */ 1429 public void remove(SearchFilter searchFilter) { 1430 if (searchFilter == null) { 1431 throw new IllegalArgumentException("searchFilter"); 1432 } 1433 1434 if (this.contains(searchFilter)) { 1435 searchFilter.removeChangeEvent(this); 1436 this.searchFilters.remove(searchFilter); 1437 this.changed(); 1438 } 1439 } 1440 1441 /** 1442 * Removes the search filter at the specified index from the collection. 1443 * 1444 * @param index The zero-based index of the search filter to remove. 1445 */ 1446 public void removeAt(int index) { 1447 if (index < 0 || index >= this.getCount()) { 1448 throw new IllegalArgumentException( 1449 String.format("index %d is out of range [0..%d[.", index, this.getCount())); 1450 } 1451 1452 this.searchFilters.get(index).removeChangeEvent(this); 1453 this.searchFilters.remove(index); 1454 this.changed(); 1455 } 1456 1457 /** 1458 * Gets the total number of search filter in the collection. 1459 * 1460 * @return the count 1461 */ 1462 public int getCount() { 1463 1464 return this.searchFilters.size(); 1465 } 1466 1467 /** 1468 * Gets the search filter at the specified index. 1469 * 1470 * @param index the index 1471 * @return The search filter at the specified index. 1472 */ 1473 public SearchFilter getSearchFilter(int index) { 1474 if (index < 0 || index >= this.getCount()) { 1475 throw new IllegalArgumentException( 1476 String.format("index %d is out of range [0..%d[.", index, this.getCount()) 1477 ); 1478 } 1479 return this.searchFilters.get(index); 1480 } 1481 1482 /** 1483 * Sets the search filter at the specified index. 1484 * 1485 * @param index the index 1486 * @param searchFilter the search filter 1487 */ 1488 public void setSearchFilter(int index, SearchFilter searchFilter) { 1489 if (index < 0 || index >= this.getCount()) { 1490 throw new IllegalArgumentException( 1491 String.format("index %d is out of range [0..%d[.", index, this.getCount()) 1492 ); 1493 } 1494 this.searchFilters.add(index, searchFilter); 1495 } 1496 1497 /** 1498 * Gets the logical operator that links the serach filter in this 1499 * collection. 1500 * 1501 * @return LogicalOperator 1502 */ 1503 public LogicalOperator getLogicalOperator() { 1504 return logicalOperator; 1505 } 1506 1507 /** 1508 * Sets the logical operator that links the serach filter in this 1509 * collection. 1510 * 1511 * @param logicalOperator the new logical operator 1512 */ 1513 public void setLogicalOperator(LogicalOperator logicalOperator) { 1514 this.logicalOperator = logicalOperator; 1515 } 1516 1517 /* 1518 * (non-Javadoc) 1519 * 1520 * @see 1521 * microsoft.exchange.webservices. 1522 * ComplexPropertyChangedDelegateInterface# 1523 * complexPropertyChanged(microsoft.exchange.webservices.ComplexProperty 1524 * ) 1525 */ 1526 @Override 1527 public void complexPropertyChanged(ComplexProperty complexProperty) { 1528 searchFilterChanged(complexProperty); 1529 } 1530 1531 /* 1532 * (non-Javadoc) 1533 * 1534 * @see java.lang.Iterable#iterator() 1535 */ 1536 @Override 1537 public Iterator<SearchFilter> iterator() { 1538 return this.searchFilters.iterator(); 1539 } 1540 1541 } 1542}