001 package org.apache.ojb.broker.query;
002
003 /* Copyright 2002-2005 The Apache Software Foundation
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 /**
019 * Model a Like Criteria</br>
020 * Escape Processing by Paul R. Nase
021 * <p>
022 * The pattern string is a simple pattern string using % or * as a wildcard.
023 * So Ander* would match Anderson and Anderton. The _ or ? character is used to match a single occurence
024 * of a character. The '\' is used to escape the wildcard characters so that we can search for
025 * strings containing * and ?.
026 * <p>
027 * To change the escape character use setEscapeCharacter.
028 * @see LikeCriteria#setEscapeCharacter(char)
029 *
030 * @author <a href="mailto:jbraeuchi@gmx.ch">Jakob Braeuchi </a>
031 * @author <a href="mailto:Nase.Paul@mayo.edu">Paul Nase </a>
032 * @version $Id: LikeCriteria.java,v 1.1 2007-08-24 22:17:36 ewestfal Exp $
033 */
034 public class LikeCriteria extends ValueCriteria
035 {
036 /**
037 * The Dfault-Character used for Escaping Wildcards
038 */
039 public static final char DEFAULT_ESCPAPE_CHARACTER = '\\';
040
041 /**
042 * The Character used for Escaping Wildcards
043 */
044 private static char escapeCharacter = DEFAULT_ESCPAPE_CHARACTER;
045
046 /**
047 * @param anAttribute
048 * @param aValue
049 * @param aClause
050 * @param anAlias
051 */
052 public LikeCriteria(Object anAttribute, Object aValue, String aClause, String anAlias)
053 {
054 super(anAttribute, generateSQLSearchPattern(aValue), aClause, anAlias);
055 }
056
057 /**
058 * @param anAttribute
059 * @param aValue
060 * @param aClause
061 * @param anAlias
062 */
063 public LikeCriteria(Object anAttribute, Object aValue, String aClause, UserAlias anAlias)
064 {
065 super(anAttribute, generateSQLSearchPattern(aValue), aClause, anAlias);
066 }
067
068 /**
069 * @see org.apache.ojb.broker.query.SelectionCriteria#bind(java.lang.Object)
070 */
071 public void bind(Object newValue)
072 {
073 super.bind(generateSQLSearchPattern(newValue));
074 }
075
076 /**
077 * Generate a SQL search string from the pattern string passed.
078 * The pattern string is a simple pattern string using % or * as a wildcard.
079 * So Ander* would match Anderson and Anderton. The _ or ? character is used to match a single occurence
080 * of a character. The escapeCharacter is used to escape the wildcard characters so that we can search for
081 * strings containing * and ?. This method converts the criteria wildcard strings to SQL wildcards.
082 *
083 * @param pattern a criteria search pattern containing optional wildcards
084 * @return a SQL search pattern string with all escape codes processed.
085 */
086 private static String generateSQLSearchPattern(Object pattern)
087 {
088 if (pattern == null)
089 {
090 return null;
091 }
092 else
093 {
094 StringBuffer sqlpattern = new StringBuffer();
095 char[] chars = pattern.toString().toCharArray();
096
097 for (int i = 0; i < chars.length; i++)
098 {
099 if (chars[i] == escapeCharacter)
100 {
101 // for the escape character add the next char as is.
102 // find the next non-escape character.
103 int x = i + 1;
104 for (;(x < chars.length); x++)
105 {
106 if (chars[x] != escapeCharacter)
107 {
108 break;
109 }
110 }
111 boolean oddEscapes = (((x - i) % 2) > 0) ? true : false;
112 if (oddEscapes)
113 {
114 // only escape characters allowed are '%', '_', and '\'
115 // if the escaped character is a '\', then oddEscapes
116 // will be false.
117 // if the character following this last escape is not a
118 // '%' or an '_', eat this escape character.
119 if ((x < chars.length)
120 && ((chars[x] == '%') || (chars[x] == '_')))
121 {
122 // leave the escape character in, along with the following char
123 x++;
124 }
125 else
126 {
127 // remove the escape character, will cause problems in sql statement.
128 i++; // removing the first escape character.
129 if ((x < chars.length)
130 && ((chars[x] == '*') || (chars[x] == '?')))
131 {
132 // but if it is a '*' or a '?', we want to keep these
133 // characters as is, they were 'escaped' out.
134 x++; // include the first non-escape character.
135 }
136 }
137 }
138 if (i < chars.length)
139 {
140 sqlpattern.append(chars, i, x - i);
141 }
142 i = x - 1; // set index to last character copied.
143 }
144 else if (chars[i] == '*')
145 {
146 sqlpattern.append("%");
147 }
148 else if (chars[i] == '?')
149 {
150 sqlpattern.append("_");
151 }
152 else
153 {
154 sqlpattern.append(chars[i]);
155 }
156 }
157 return sqlpattern.toString();
158 }
159 }
160
161 /**
162 * @return Returns the escapeCharacter.
163 */
164 public static char getEscapeCharacter()
165 {
166 return escapeCharacter;
167 }
168
169 /**
170 * Global change of the escapeCharacter
171 * @param escChar The escapeCharacter to set.
172 */
173 public static void setEscapeCharacter(char escChar)
174 {
175 escapeCharacter = escChar;
176 }
177
178 }