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    }