001 /*
002 * Copyright 2010 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package com.hs.mail.imap.dao;
017
018 import java.sql.ResultSet;
019 import java.sql.SQLException;
020 import java.util.ArrayList;
021 import java.util.List;
022
023 import org.apache.commons.collections.CollectionUtils;
024 import org.apache.commons.collections.ListUtils;
025 import org.apache.commons.lang.StringUtils;
026 import org.apache.james.mime4j.codec.DecoderUtil;
027 import org.springframework.jdbc.core.RowCallbackHandler;
028
029 import com.hs.mail.imap.mailbox.UidToMsnMapper;
030 import com.hs.mail.imap.message.SequenceRange;
031 import com.hs.mail.imap.message.search.AllKey;
032 import com.hs.mail.imap.message.search.AndKey;
033 import com.hs.mail.imap.message.search.CompositeKey;
034 import com.hs.mail.imap.message.search.HeaderKey;
035 import com.hs.mail.imap.message.search.KeywordKey;
036 import com.hs.mail.imap.message.search.NotKey;
037 import com.hs.mail.imap.message.search.OrKey;
038 import com.hs.mail.imap.message.search.RecipientStringKey;
039 import com.hs.mail.imap.message.search.SearchKey;
040 import com.hs.mail.imap.message.search.SearchKeyList;
041 import com.hs.mail.imap.message.search.SequenceKey;
042
043 /**
044 *
045 * @author Won Chul Doh
046 * @since Apr 5, 2010
047 *
048 */
049
050 @SuppressWarnings("unchecked")
051 public class MySqlSearchDao extends AbstractDao implements SearchDao {
052
053 public List<Long> query(UidToMsnMapper map, long mailboxID, SearchKey key) {
054 if (key instanceof AndKey) {
055 return query(map, mailboxID, (AndKey) key);
056 } else if (key instanceof OrKey) {
057 return query(map, mailboxID, (OrKey) key);
058 } else if (key instanceof NotKey) {
059 return query(map, mailboxID, (NotKey) key);
060 } else if (key instanceof AllKey) {
061 return map.getUIDList();
062 } else if (key instanceof HeaderKey) {
063 return query(map, mailboxID, (HeaderKey) key);
064 } else if (key instanceof RecipientStringKey) {
065 return query(map, mailboxID, (RecipientStringKey) key);
066 } else if (key instanceof SequenceKey) {
067 return query(map, mailboxID, (SequenceKey) key);
068 } else if (key instanceof KeywordKey) {
069 return query(map, mailboxID, (KeywordKey) key);
070 } else if (key instanceof CompositeKey) {
071 return query(map, mailboxID, (CompositeKey) key);
072 } else {
073 return query(map, mailboxID, new CompositeKey(key));
074 }
075 }
076
077 private List<Long> query(UidToMsnMapper map, long mailboxID, AndKey key) {
078 return conjunctionQuery(map, mailboxID, key, true);
079 }
080
081 private List<Long> query(UidToMsnMapper map, long mailboxID, OrKey key) {
082 return conjunctionQuery(map, mailboxID, key, false);
083 }
084
085 private List<Long> query(UidToMsnMapper map, long mailboxID, NotKey key) {
086 SearchKey k = key.getSearchKey();
087 if (k.isComposite()) {
088 return ListUtils.subtract(map.getUIDList(),
089 query(map, mailboxID, k));
090 } else {
091 return ListUtils.subtract(map.getUIDList(), query(map, mailboxID,
092 new CompositeKey(k)));
093 }
094 }
095
096 private List<Long> query(UidToMsnMapper map, long mailboxID,
097 final HeaderKey key) {
098 return query(map, mailboxID, key.getHeaderName(), key.getPattern());
099 }
100
101 private List<Long> query(UidToMsnMapper map, long mailboxID, String name,
102 final String pattern) {
103 if (StringUtils.isEmpty(pattern)) {
104 String sql = SearchQuery.toQuery(mailboxID, name, true);
105 return getJdbcTemplate().queryForList(sql, Long.class);
106 } else {
107 String sql = SearchQuery.toQuery(mailboxID, name, false);
108 final List<Long> results = new ArrayList<Long>();
109 getJdbcTemplate().query(sql, new RowCallbackHandler() {
110 public void processRow(ResultSet rs) throws SQLException {
111 // Stored header values are not decoded.
112 String value = DecoderUtil.decodeEncodedWords(rs
113 .getString(2));
114 if (StringUtils.contains(value, pattern)) {
115 results.add(rs.getLong(1));
116 }
117 }
118 });
119 return results;
120 }
121 }
122
123 private List<Long> query(UidToMsnMapper map, long mailboxID,
124 RecipientStringKey key) {
125 return query(map, mailboxID, key.getRecipientType().toString(),
126 key.getPattern());
127 }
128
129 private List<Long> query(UidToMsnMapper map, long mailboxID, SequenceKey key) {
130 List<Long> result = new ArrayList<Long>();
131 SequenceRange[] sequenceSet = key.getSequenceSet();
132 for (int i = 0; i < sequenceSet.length; i++) {
133 long min = map.getMinMessageNumber(sequenceSet[i].getMin());
134 long max = map.getMaxMessageNumber(sequenceSet[i].getMax());
135 for (long j = min; j <= max && j >= 0; j++) {
136 long messageID = map.getUID((int) j);
137 if (messageID != -1) {
138 result.add(messageID);
139 }
140 }
141 }
142 return result;
143 }
144
145 private List<Long> query(UidToMsnMapper map, long mailboxID, KeywordKey key) {
146 String sql = SearchQuery.toQuery(mailboxID, key);
147 if (key.getTestSet()) {
148 return getJdbcTemplate().queryForList(sql, Long.class);
149 } else {
150 return ListUtils.subtract(map.getUIDList(), getJdbcTemplate()
151 .queryForList(sql, Long.class));
152 }
153 }
154
155 private List<Long> query(UidToMsnMapper map, long mailboxID, CompositeKey key) {
156 String sql = SearchQuery.toQuery(mailboxID, key);
157 return getJdbcTemplate().queryForList(sql, Long.class);
158 }
159
160 private List<Long> conjunctionQuery(UidToMsnMapper map, long mailboxID,
161 SearchKeyList key, boolean and) {
162 List<Long> result = null;
163 List<SearchKey> keys = key.getSearchKeys();
164 CompositeKey ck = null;
165 for (SearchKey k : keys) {
166 if (k.isComposite()) {
167 result = query(result, map, mailboxID, k, and);
168 } else {
169 if (ck == null) {
170 ck = new CompositeKey();
171 }
172 ck.addKey(k);
173 }
174 }
175 if (ck != null) {
176 return query(result, map, mailboxID, ck, and);
177 } else {
178 return result;
179 }
180 }
181
182 private List<Long> query(List<Long> result, UidToMsnMapper map, long mailboxID,
183 SearchKey key, boolean and) {
184 List<Long> list = query(map, mailboxID, key);
185 if (CollectionUtils.isNotEmpty(result)) {
186 return (and) ? ListUtils.intersection(result, list)
187 : ListUtils.sum(result, list);
188 } else {
189 return list;
190 }
191 }
192
193 }