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 */ 019package org.apache.wiki.search; 020 021import org.apache.log4j.Logger; 022import org.apache.wiki.WikiContext; 023import org.apache.wiki.WikiEngine; 024import org.apache.wiki.WikiPage; 025import org.apache.wiki.api.exceptions.NoRequiredPropertyException; 026import org.apache.wiki.api.exceptions.ProviderException; 027import org.apache.wiki.attachment.Attachment; 028import org.apache.wiki.auth.AuthorizationManager; 029import org.apache.wiki.auth.permissions.PagePermission; 030import org.apache.wiki.providers.WikiPageProvider; 031 032import java.io.IOException; 033import java.util.Collection; 034import java.util.Iterator; 035import java.util.List; 036import java.util.Properties; 037import java.util.StringTokenizer; 038import java.util.TreeSet; 039 040/** 041 * Interface for the search providers that handle searching the Wiki 042 * 043 * @since 2.2.21. 044 */ 045public class BasicSearchProvider implements SearchProvider 046{ 047 private static final Logger log = Logger.getLogger(BasicSearchProvider.class); 048 049 private WikiEngine m_engine; 050 051 /** 052 * {@inheritDoc} 053 */ 054 public void initialize(WikiEngine engine, Properties props) 055 throws NoRequiredPropertyException, IOException 056 { 057 m_engine = engine; 058 } 059 060 /** 061 * {@inheritDoc} 062 */ 063 public void pageRemoved(WikiPage page) {} 064 065 /** 066 * {@inheritDoc} 067 */ 068 public void reindexPage(WikiPage page) {} 069 070 /** 071 * Parses a query into something that we can use. 072 * 073 * @param query A query string. 074 * @return A parsed array. 075 */ 076 public QueryItem[] parseQuery(String query) 077 { 078 StringTokenizer st = new StringTokenizer( query, " \t," ); 079 080 QueryItem[] items = new QueryItem[st.countTokens()]; 081 int word = 0; 082 083 log.debug("Expecting "+items.length+" items"); 084 085 // 086 // Parse incoming search string 087 // 088 089 while( st.hasMoreTokens() ) 090 { 091 log.debug("Item "+word); 092 String token = st.nextToken().toLowerCase(); 093 094 items[word] = new QueryItem(); 095 096 switch( token.charAt(0) ) 097 { 098 case '+': 099 items[word].type = QueryItem.REQUIRED; 100 token = token.substring(1); 101 log.debug("Required word: "+token); 102 break; 103 104 case '-': 105 items[word].type = QueryItem.FORBIDDEN; 106 token = token.substring(1); 107 log.debug("Forbidden word: "+token); 108 break; 109 110 default: 111 items[word].type = QueryItem.REQUESTED; 112 log.debug("Requested word: "+token); 113 break; 114 } 115 116 items[word++].word = token; 117 } 118 119 return items; 120 } 121 122 private String attachmentNames(WikiPage page, String separator) 123 { 124 if(m_engine.getAttachmentManager().hasAttachments(page)) 125 { 126 List< Attachment > attachments; 127 try 128 { 129 attachments = m_engine.getAttachmentManager().listAttachments(page); 130 } 131 catch (ProviderException e) 132 { 133 log.error("Unable to get attachments for page", e); 134 return ""; 135 } 136 137 StringBuilder attachmentNames = new StringBuilder(); 138 for( Iterator< Attachment > it = attachments.iterator(); it.hasNext(); ) 139 { 140 Attachment att = it.next(); 141 attachmentNames.append(att.getName()); 142 if(it.hasNext()) { 143 attachmentNames.append(separator); 144 } 145 } 146 return attachmentNames.toString(); 147 } 148 149 return ""; 150 } 151 152 private Collection< SearchResult > findPages( QueryItem[] query, WikiContext wikiContext ) 153 { 154 TreeSet<SearchResult> res = new TreeSet<>( new SearchResultComparator() ); 155 SearchMatcher matcher = new SearchMatcher( m_engine, query ); 156 157 Collection< WikiPage > allPages = null; 158 try { 159 allPages = m_engine.getPageManager().getAllPages(); 160 } catch( ProviderException pe ) { 161 log.error( "Unable to retrieve page list", pe ); 162 return null; 163 } 164 165 AuthorizationManager mgr = m_engine.getAuthorizationManager(); 166 167 Iterator< WikiPage > it = allPages.iterator(); 168 while( it.hasNext() ) { 169 try { 170 WikiPage page = it.next(); 171 if (page != null) { 172 173 PagePermission pp = new PagePermission( page, PagePermission.VIEW_ACTION ); 174 if( wikiContext==null || mgr.checkPermission( wikiContext.getWikiSession(), pp ) ) { 175 String pageName = page.getName(); 176 String pageContent = m_engine.getPageManager().getPageText(pageName, WikiPageProvider.LATEST_VERSION) + 177 attachmentNames(page, " "); 178 SearchResult comparison = matcher.matchPageContent( pageName, pageContent ); 179 180 if( comparison != null ) { 181 res.add( comparison ); 182 } 183 } 184 } 185 } catch( ProviderException pe ) { 186 log.error( "Unable to retrieve page from cache", pe ); 187 } catch( IOException ioe ) { 188 log.error( "Failed to search page", ioe ); 189 } 190 } 191 192 return res; 193 } 194 195 /** 196 * {@inheritDoc} 197 */ 198 public Collection< SearchResult > findPages(String query, WikiContext wikiContext) { 199 return findPages(parseQuery(query), wikiContext); 200 } 201 202 /** 203 * {@inheritDoc} 204 */ 205 public String getProviderInfo() { 206 return "BasicSearchProvider"; 207 } 208 209}