001    /*
002        Licensed to the Apache Software Foundation (ASF) under one
003        or more contributor license agreements.  See the NOTICE file
004        distributed with this work for additional information
005        regarding copyright ownership.  The ASF licenses this file
006        to you under the Apache License, Version 2.0 (the
007        "License"); you may not use this file except in compliance
008        with the License.  You may obtain a copy of the License at
009    
010           http://www.apache.org/licenses/LICENSE-2.0
011    
012        Unless required by applicable law or agreed to in writing,
013        software distributed under the License is distributed on an
014        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015        KIND, either express or implied.  See the License for the
016        specific language governing permissions and limitations
017        under the License.    
018     */
019    package org.apache.wiki.search;
020    
021    import java.io.IOException;
022    import java.util.Collection;
023    import java.util.Iterator;
024    import java.util.Properties;
025    import java.util.StringTokenizer;
026    import java.util.TreeSet;
027    
028    import org.apache.log4j.Logger;
029    import org.apache.wiki.WikiEngine;
030    import org.apache.wiki.WikiPage;
031    import org.apache.wiki.api.exceptions.NoRequiredPropertyException;
032    import org.apache.wiki.api.exceptions.ProviderException;
033    import org.apache.wiki.attachment.Attachment;
034    import org.apache.wiki.providers.WikiPageProvider;
035    
036    /**
037     *  Interface for the search providers that handle searching the Wiki
038     *
039     *  @since 2.2.21.
040     */
041    public class BasicSearchProvider implements SearchProvider
042    {
043        private static final Logger log = Logger.getLogger(BasicSearchProvider.class);
044    
045        private WikiEngine m_engine;
046    
047        /**
048         *  {@inheritDoc}
049         */
050        public void initialize(WikiEngine engine, Properties props)
051                throws NoRequiredPropertyException, IOException
052        {
053            m_engine = engine;
054        }
055    
056        /**
057         *  {@inheritDoc}
058         */
059        public void pageRemoved(WikiPage page) {}
060    
061        /**
062         *  {@inheritDoc}
063         */
064        public void reindexPage(WikiPage page) {}
065    
066        /**
067         *  Parses a query into something that we can use.
068         *  
069         *  @param query A query string.
070         *  @return A parsed array.
071         */
072        public  QueryItem[] parseQuery(String query)
073        {
074            StringTokenizer st = new StringTokenizer( query, " \t," );
075    
076            QueryItem[] items = new QueryItem[st.countTokens()];
077            int word = 0;
078    
079            log.debug("Expecting "+items.length+" items");
080    
081            //
082            //  Parse incoming search string
083            //
084    
085            while( st.hasMoreTokens() )
086            {
087                log.debug("Item "+word);
088                String token = st.nextToken().toLowerCase();
089    
090                items[word] = new QueryItem();
091    
092                switch( token.charAt(0) )
093                {
094                  case '+':
095                    items[word].type = QueryItem.REQUIRED;
096                    token = token.substring(1);
097                    log.debug("Required word: "+token);
098                    break;
099    
100                  case '-':
101                    items[word].type = QueryItem.FORBIDDEN;
102                    token = token.substring(1);
103                    log.debug("Forbidden word: "+token);
104                    break;
105    
106                  default:
107                    items[word].type = QueryItem.REQUESTED;
108                    log.debug("Requested word: "+token);
109                    break;
110                }
111    
112                items[word++].word = token;
113            }
114    
115            return items;
116        }
117    
118        private String attachmentNames(WikiPage page, String separator)
119        {
120            if(m_engine.getAttachmentManager().hasAttachments(page))
121            {
122                Collection attachments;
123                try
124                {
125                    attachments = m_engine.getAttachmentManager().listAttachments(page);
126                }
127                catch (ProviderException e)
128                {
129                    log.error("Unable to get attachments for page", e);
130                    return "";
131                }
132    
133                StringBuffer attachmentNames = new StringBuffer();
134                for( Iterator it = attachments.iterator(); it.hasNext(); )
135                {
136                    Attachment att = (Attachment) it.next();
137                    attachmentNames.append(att.getName());
138                    if(it.hasNext())
139                        attachmentNames.append(separator);
140                }
141                return attachmentNames.toString();
142            }
143    
144            return "";
145        }
146    
147        private Collection findPages( QueryItem[] query )
148        {
149            TreeSet<SearchResult> res = new TreeSet<SearchResult>( new SearchResultComparator() );
150            SearchMatcher matcher = new SearchMatcher( m_engine, query );
151    
152            Collection allPages = null;
153            try
154            {
155                allPages = m_engine.getPageManager().getAllPages();
156            }
157            catch( ProviderException pe )
158            {
159                log.error( "Unable to retrieve page list", pe );
160                return null;
161            }
162    
163            Iterator it = allPages.iterator();
164            while( it.hasNext() )
165            {
166                try
167                {
168                    WikiPage page = (WikiPage) it.next();
169                    if (page != null)
170                    {
171                        String pageName = page.getName();
172                        String pageContent = m_engine.getPageManager().getPageText(pageName, WikiPageProvider.LATEST_VERSION) +
173                                             attachmentNames(page, " ");
174                        SearchResult comparison = matcher.matchPageContent( pageName, pageContent );
175    
176                        if( comparison != null )
177                        {
178                            res.add( comparison );
179                        }
180                    }
181                }
182                catch( ProviderException pe )
183                {
184                    log.error( "Unable to retrieve page from cache", pe );
185                }
186                catch( IOException ioe )
187                {
188                    log.error( "Failed to search page", ioe );
189                }
190            }
191    
192            return res;
193        }
194    
195        /**
196         *  {@inheritDoc}
197         */
198        public Collection findPages(String query)
199        {
200            return findPages(parseQuery(query));
201        }
202    
203        /**
204         *  {@inheritDoc}
205         */
206        public String getProviderInfo()
207        {
208            return "BasicSearchProvider";
209        }
210    
211    }