View Javadoc

1   /*
2    * Copyright 2006-2010 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package net.sourceforge.domian.specification;
17  
18  
19  import java.util.regex.Pattern;
20  
21  import org.apache.commons.lang.NotImplementedException;
22  import org.apache.commons.lang.Validate;
23  
24  import static java.lang.Boolean.FALSE;
25  import static java.lang.Boolean.TRUE;
26  import static net.sourceforge.domian.util.ReflectionUtils.canCast;
27  
28  
29  /**
30   * Specification that uses a regular expression engine for specifying wildcard strings.
31   *
32   * @author Eirik Torske
33   * @since 0.2
34   */
35  class WildcardExpressionMatcherStringSpecification extends RegularExpressionMatcherStringSpecification {
36  
37      protected String originalWildcardExpression;
38  
39      WildcardExpressionMatcherStringSpecification(final String regularExpression) {
40          super(regularExpression);
41          this.originalWildcardExpression = regularExpression;
42          this.compiledRegularExpression = compileWildcardRegexPattern(convertWildcardToRegex(this.originalWildcardExpression));
43      }
44  
45      protected Boolean ignoreCase() {
46          return FALSE;
47      }
48  
49      private String convertWildcardToRegex(final String wildcardExpression) {
50          final StringBuilder convertedWildcardExpression = new StringBuilder();
51          for (final char ch : wildcardExpression.toCharArray()) {
52              if (ch == '*') {
53                  convertedWildcardExpression.append("[\\S\\s]*");
54              } else if (ch == '?') {
55                  convertedWildcardExpression.append("[\\S\\s]");
56              } else {
57                  convertedWildcardExpression.append(ch);
58              }
59          }
60          return convertedWildcardExpression.toString();
61      }
62  
63      @Override
64      protected Pattern compileRegexPattern(final String regularExpression) {
65          return null; // Deliberately overriding possible PatternSyntaxExceptions by returning null
66      }
67  
68      private Pattern compileWildcardRegexPattern(final String wildcardExpression) {
69          if (this.ignoreCase()) {
70              return Pattern.compile(wildcardExpression, Pattern.CASE_INSENSITIVE);
71          } else {
72              return Pattern.compile(wildcardExpression);
73          }
74      }
75  
76      protected String createSimplestPossibleSatisfiableStringFor(final String wildcardExpression) {
77          final StringBuilder simplestPossibleSatisfiableString = new StringBuilder();
78          for (final char ch : wildcardExpression.toCharArray()) {
79              if (ch == '*') {
80                  // Add nothing
81              } else if (ch == '?') {
82                  simplestPossibleSatisfiableString.append("x");
83              } else {
84                  simplestPossibleSatisfiableString.append(ch);
85              }
86          }
87          return simplestPossibleSatisfiableString.toString();
88      }
89  
90      @Override
91      public Boolean isDisjointWith(final Specification<?> specification) {
92          Validate.notNull(specification, "Specification parameter cannot be null");
93          if (this == specification || this.equals(specification)) { return FALSE; }
94          if (specification instanceof WildcardExpressionMatcherStringSpecification) {
95              final WildcardExpressionMatcherStringSpecification regexSpecCandidate = (WildcardExpressionMatcherStringSpecification) specification;
96              final String satisfiableStringForThis = createSimplestPossibleSatisfiableStringFor(this.originalWildcardExpression);
97              final String satisfiableStringForCandidate = createSimplestPossibleSatisfiableStringFor(regexSpecCandidate.originalWildcardExpression);
98              return !(this.isSatisfiedBy(satisfiableStringForThis) && regexSpecCandidate.isSatisfiedBy(satisfiableStringForThis) ||
99                       this.isSatisfiedBy(satisfiableStringForCandidate) && regexSpecCandidate.isSatisfiedBy(satisfiableStringForCandidate));
100 
101         } else if (specification instanceof JointDenialSpecification) {
102             final JointDenialSpecification jointDenialSpecification = (JointDenialSpecification) specification;
103             final Specification negatedSpec = getNegatedSpecification(jointDenialSpecification);
104             // Pruning: if specifications and types are fundamentally disjoint
105             if (canCast(this.getType(), negatedSpec.getType()) && jointDenialSpecification.isTypeExcludingSpecification()) {
106                 return TRUE;
107             }
108             final int numberOfLevelsOfInversions = getNumberOfLevelsOfNegations(jointDenialSpecification, 0);
109             if (isOddNumber(numberOfLevelsOfInversions)) {
110                 return !negatedSpec.isDisjointWith(this);
111             } else {
112                 return negatedSpec.isDisjointWith(this);
113             }
114 
115         } else if (specification instanceof EqualSpecification) {
116             return !this.isSatisfiedBy(((EqualSpecification) specification).getValue().toString());
117 
118         } else if (specification instanceof EqualIgnoreCaseStringSpecification) {
119             WildcardExpressionMatcherIgnoreCaseStringSpecification ignoreCaseSpecificationVersion = new WildcardExpressionMatcherIgnoreCaseStringSpecification(this.originalWildcardExpression);
120             return !ignoreCaseSpecificationVersion.isSatisfiedBy(((EqualIgnoreCaseStringSpecification) specification).getValue().toString());
121 
122         } else {
123             throw new NotImplementedException();
124         }
125     }
126 }