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 }