View Javadoc

1   /****************************************************************
2    * Licensed to the Apache Software Foundation (ASF) under one   *
3    * or more contributor license agreements.  See the NOTICE file *
4    * distributed with this work for additional information        *
5    * regarding copyright ownership.  The ASF licenses this file   *
6    * to you under the Apache License, Version 2.0 (the            *
7    * "License"); you may not use this file except in compliance   *
8    * with the License.  You may obtain a copy of the License at   *
9    *                                                              *
10   *   http://www.apache.org/licenses/LICENSE-2.0                 *
11   *                                                              *
12   * Unless required by applicable law or agreed to in writing,   *
13   * software distributed under the License is distributed on an  *
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15   * KIND, either express or implied.  See the License for the    *
16   * specific language governing permissions and limitations      *
17   * under the License.                                           *
18   ****************************************************************/
19  
20  package org.apache.james.mailboxmanager.manager;
21  
22  /**
23   * Expresses select criteria for mailboxes.
24   */
25  public class MailboxExpression {
26  
27      private final String base;
28  
29      private final String expression;
30  
31      private final char freeWildcard;
32  
33      private final char localWildcard;
34  
35      private final int expressionLength;
36  
37      /**
38       * Constructs an expression determining a set of mailbox names.
39       * 
40       * @param base
41       *            base reference name, not null
42       * @param expression
43       *            mailbox match expression, not null
44       * @param freeWildcard
45       *            matches any series of charaters
46       * @param localWildcard
47       *            matches any sequence of characters up to the next hierarchy
48       *            delimiter
49       */
50      public MailboxExpression(final String base, final String expression,
51              final char freeWildcard, final char localWildcard) {
52          super();
53          if (base == null) {
54              this.base = "";
55          } else {
56              this.base = base;
57          }
58          if (expression == null) {
59              this.expression = "";
60          } else {
61              this.expression = expression;
62          }
63          expressionLength = this.expression.length();
64          this.freeWildcard = freeWildcard;
65          this.localWildcard = localWildcard;
66      }
67  
68      /**
69       * Gets the base reference name for the search.
70       * 
71       * @return the base
72       */
73      public final String getBase() {
74          return base;
75      }
76  
77      /**
78       * Gets the name search expression. This may contain wildcards.
79       * 
80       * @return the expression
81       */
82      public final String getExpression() {
83          return expression;
84      }
85  
86      /**
87       * Gets wildcard character that matches any series of characters.
88       * 
89       * @return the freeWildcard
90       */
91      public final char getFreeWildcard() {
92          return freeWildcard;
93      }
94  
95      /**
96       * Gets wildacard character that matches any series of characters excluding
97       * hierarchy delimiters. Effectively, this means that it matches any
98       * sequence within a name part.
99       * 
100      * @return the localWildcard
101      */
102     public final char getLocalWildcard() {
103         return localWildcard;
104     }
105 
106     /**
107      * Is the given name a match for {@link #getExpression()}?
108      * 
109      * @param name
110      *            name to be matched
111      * @param hierarchyDelimiter
112      *            mailbox hierarchy delimiter
113      * @return true if the given name matches this expression, false otherwise
114      */
115     public final boolean isExpressionMatch(String name, char hierarchyDelimiter) {
116         final boolean result;
117         if (isWild()) {
118             if (name == null) {
119                 result = false;
120             } else {
121                 result = isWildcardMatch(name, 0, 0, hierarchyDelimiter);
122             }
123         } else {
124             result = expression.equals(name);
125         }
126         return result;
127     }
128 
129     private final boolean isWildcardMatch(final String name,
130             final int nameIndex, final int expressionIndex,
131             final char hierarchyDelimiter) {
132         final boolean result;
133         if (expressionIndex < expressionLength) {
134             final char expressionNext = expression.charAt(expressionIndex);
135             if (expressionNext == freeWildcard) {
136                 result = isFreeWildcardMatch(name, nameIndex, expressionIndex,
137                         hierarchyDelimiter);
138             } else if (expressionNext == localWildcard) {
139                 result = isLocalWildcardMatch(name, nameIndex, expressionIndex,
140                         hierarchyDelimiter);
141             } else {
142                 if (nameIndex < name.length()) {
143                     final char nameNext = name.charAt(nameIndex);
144                     if (nameNext == expressionNext) {
145                         result = isWildcardMatch(name, nameIndex + 1,
146                                 expressionIndex + 1, hierarchyDelimiter);
147                     } else {
148                         result = false;
149                     }
150                 } else {
151                     // more expression characters to match
152                     // but no more name
153                     result = false;
154                 }
155             }
156         } else {
157             // no more expression characters to match
158             result = true;
159         }
160         return result;
161     }
162 
163     private boolean isLocalWildcardMatch(final String name,
164             final int nameIndex, final int expressionIndex,
165             final char hierarchyDelimiter) {
166         final boolean result;
167         if (expressionIndex < expressionLength) {
168             final char expressionNext = expression.charAt(expressionIndex);
169             if (expressionNext == localWildcard) {
170                 result = isLocalWildcardMatch(name, nameIndex,
171                         expressionIndex + 1, hierarchyDelimiter);
172             } else if (expressionNext == freeWildcard) {
173                 result = isFreeWildcardMatch(name, nameIndex,
174                         expressionIndex + 1, hierarchyDelimiter);
175             } else {
176                 boolean matchRest = false;
177                 for (int i = nameIndex; i < name.length(); i++) {
178                     final char tasteNextName = name.charAt(i);
179                     if (expressionNext == tasteNextName) {
180                         if (isLocalWildcardMatch(name, i, expressionIndex + 1,
181                                 hierarchyDelimiter)) {
182                             matchRest = true;
183                             break;
184                         }
185                     } else if (tasteNextName == hierarchyDelimiter) {
186                         matchRest = false;
187                         break;
188                     }
189                 }
190                 result = matchRest;
191             }
192         } else {
193             boolean containsDelimiter = false;
194             for (int i = nameIndex; i < name.length(); i++) {
195                 if (name.charAt(i) == hierarchyDelimiter) {
196                     containsDelimiter = true;
197                     break;
198                 }
199             }
200             result = !containsDelimiter;
201         }
202         return result;
203     }
204 
205     private boolean isWildcard(char character) {
206         return character == freeWildcard || character == localWildcard;
207     }
208 
209     private boolean isFreeWildcardMatch(final String name, final int nameIndex,
210             final int expressionIndex, final char hierarchyDelimiter) {
211         final boolean result;
212         int nextNormal = expressionIndex;
213         while (nextNormal < expressionLength
214                 && isWildcard(expression.charAt(nextNormal))) {
215             nextNormal++;
216         }
217         if (nextNormal < expressionLength) {
218             final char expressionNextNormal = expression.charAt(nextNormal);
219             boolean matchRest = false;
220             for (int i = nameIndex; i < name.length(); i++) {
221                 final char tasteNextName = name.charAt(i);
222                 if (expressionNextNormal == tasteNextName) {
223                     if (isWildcardMatch(name, i, nextNormal, hierarchyDelimiter)) {
224                         matchRest = true;
225                         break;
226                     }
227                 }
228             }
229             result = matchRest;
230         } else {
231             // no more expression characters to match
232             result = true;
233         }
234         return result;
235     }
236 
237     /**
238      * Get combined name formed by adding expression to base using the given
239      * hierarchy delimiter. Note that the wildcards are retained in the combined
240      * name.
241      * 
242      * @param hierarchyDelimiter
243      *            delimiter for mailbox hierarchy
244      * @return {@link #getBase()} combined with {@link #getExpression()}, not
245      *         null
246      */
247     public String getCombinedName(char hierarchyDelimiter) {
248         final String result;
249         final int baseLength = base.length();
250         if (base != null && baseLength > 0) {
251             final int lastChar = baseLength - 1;
252             if (base.charAt(lastChar) == hierarchyDelimiter) {
253                 if (expression != null && expression.length() > 0) {
254                     if (expression.charAt(0) == hierarchyDelimiter) {
255                         result = base + expression.substring(1);
256                     } else {
257                         result = base + expression;
258                     }
259                 } else {
260                     result = base;
261                 }
262             } else {
263                 if (expression != null && expression.length() > 0) {
264                     if (expression.charAt(0) == hierarchyDelimiter) {
265                         result = base + expression;
266                     } else {
267                         result = base + hierarchyDelimiter + expression;
268                     }
269                 } else {
270                     result = base;
271                 }
272             }
273         } else {
274             result = expression;
275         }
276         return result;
277     }
278 
279     /**
280      * Is this expression wild?
281      * 
282      * @return true if wildcard contained, false otherwise
283      */
284     public boolean isWild() {
285         return expression != null
286                 && (expression.indexOf(freeWildcard) >= 0 || expression
287                         .indexOf(localWildcard) >= 0);
288     }
289 
290     /**
291      * Renders a string sutable for logging.
292      * 
293      * @return a <code>String</code> representation of this object.
294      */
295     public String toString() {
296         final String TAB = " ";
297 
298         String retValue = "";
299 
300         retValue = "MailboxExpression [ " + "base = " + this.base + TAB
301                 + "expression = " + this.expression + TAB + "freeWildcard = "
302                 + this.freeWildcard + TAB + "localWildcard = "
303                 + this.localWildcard + TAB + " ]";
304 
305         return retValue;
306     }
307 
308 }