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.plugin;
020
021import org.apache.logging.log4j.LogManager;
022import org.apache.logging.log4j.Logger;
023import org.apache.wiki.api.core.Context;
024import org.apache.wiki.api.core.ContextEnum;
025import org.apache.wiki.api.core.Engine;
026import org.apache.wiki.api.exceptions.PluginException;
027import org.apache.wiki.api.exceptions.ProviderException;
028import org.apache.wiki.api.plugin.Plugin;
029import org.apache.wiki.api.search.SearchResult;
030import org.apache.wiki.render.RenderingManager;
031import org.apache.wiki.search.SearchManager;
032import org.apache.wiki.util.TextUtil;
033import org.apache.wiki.util.XHTML;
034import org.apache.wiki.util.XhtmlUtil;
035import org.jdom2.Element;
036
037import java.io.IOException;
038import java.util.Collection;
039import java.util.Iterator;
040import java.util.Locale;
041import java.util.Map;
042import java.util.ResourceBundle;
043
044/**
045 *  The "Search" plugin allows you to access the JSPWiki search routines and show the displays in an array on your page.
046 *
047 *  <p>Parameters : </p>
048 *  <ul>
049 *  <li><b>query</b> - String. A standard JSPWiki search query.</li>
050 *  <li><b>set</b> - String. The JSPWiki context variable that will hold the results of the query. This allows you to pass your queries to other plugins on the same page as well. </li>
051 *  <li><b>max</b> - Integer. How many search results are shown at maximum.</li>
052 *  </ul>
053 *
054 *  @since
055 */
056public class Search implements Plugin {
057
058    private static final Logger LOG = LogManager.getLogger(Search.class);
059
060    /** Parameter name for setting the query string.  Value is <tt>{@value}</tt>. */
061    public static final String PARAM_QUERY = "query";
062
063    /** Parameter name for setting the name of the set where the results are stored. Value is <tt>{@value}</tt>. */
064    public static final String PARAM_SET   = "set";
065
066    /** The default name of the result set. */
067    public static final String DEFAULT_SETNAME = "_defaultSet";
068
069    /** The parameter name for setting the how many results will be fetched. Value is <tt>{@value}</tt>. */
070    public static final String PARAM_MAX   = "max";
071
072    @Override
073    public String getDisplayName(Locale locale) {
074        final ResourceBundle rb = ResourceBundle.getBundle(PluginManager.PLUGIN_I18N_RESOURCE, locale);
075        return rb.getString(this.getClass().getSimpleName());
076    }
077    
078    @Override
079    public String getSnipExample() {
080        return "Search query='{Janne}' max='10'";
081    }
082    
083    
084    /**
085     * {@inheritDoc}
086     */
087    @Override
088    public String execute( final Context context, final Map<String, String> params ) throws PluginException {
089        int maxItems = Integer.MAX_VALUE;
090        final Collection< SearchResult > results;
091
092        final String queryString = params.get( PARAM_QUERY );
093        String set               = params.get( PARAM_SET );
094        final String max         = params.get( PARAM_MAX );
095
096        if ( set == null ) set = DEFAULT_SETNAME;
097        if ( max != null ) maxItems = Integer.parseInt( max );
098
099        if ( queryString == null ) {
100            results = context.getVariable( set );
101        } else {
102            try {
103                results = doBasicQuery( context, queryString );
104                context.setVariable( set, results );
105            } catch( final Exception e ) {
106                return "<div class='error'>" + TextUtil.replaceEntities(e.getMessage()) + "</div>\n";
107            }
108        }
109
110        String res = "";
111
112        if ( results != null ) {
113            res = renderResults(results,context,maxItems);
114        }
115
116        return res;
117    }
118
119    private Collection<SearchResult> doBasicQuery( final Context context, final String query ) throws ProviderException, IOException {
120        LOG.debug( "Searching for string " + query );
121        return context.getEngine().getManager( SearchManager.class ).findPages( query, context );
122    }
123
124    private String renderResults( final Collection<SearchResult> results, final Context context, final int maxItems ) {
125        final Engine engine = context.getEngine();
126
127        final Element table = XhtmlUtil.element(XHTML.table);
128        //table.setAttribute(XHTML.ATTR_border,"0");
129        //table.setAttribute(XHTML.ATTR_cellpadding,"4");
130        table.setAttribute(XHTML.ATTR_class,"wikitable search-result");
131
132        Element row = XhtmlUtil.element(XHTML.tr);
133        table.addContent(row);
134
135        final Element th1 = XhtmlUtil.element(XHTML.th,"Page");
136        th1.setAttribute(XHTML.ATTR_width,"30%");
137        th1.setAttribute(XHTML.ATTR_align,"left");
138        row.addContent(th1);
139
140        final Element th2 = XhtmlUtil.element(XHTML.th,"Score");
141        th2.setAttribute(XHTML.ATTR_align,"left");
142        row.addContent(th2);
143
144        int idx = 0;
145        for ( final Iterator<SearchResult> i = results.iterator(); i.hasNext() && idx++ <= maxItems; ) {
146            final SearchResult sr = i.next();
147            row = XhtmlUtil.element(XHTML.tr);
148
149            final Element name = XhtmlUtil.element(XHTML.td);
150            name.setAttribute(XHTML.ATTR_width,"30%");
151
152            name.addContent( XhtmlUtil.link(context.getURL( ContextEnum.PAGE_VIEW.getRequestContext(), sr.getPage().getName() ),
153                             engine.getManager( RenderingManager.class ).beautifyTitle(sr.getPage().getName() ) ) );
154
155            row.addContent(name);
156
157            row.addContent(XhtmlUtil.element(XHTML.td,""+sr.getScore()));
158
159            table.addContent(row);
160        }
161
162        if ( results.isEmpty() ) {
163            row = XhtmlUtil.element(XHTML.tr);
164
165            final Element td = XhtmlUtil.element(XHTML.td);
166            td.setAttribute(XHTML.ATTR_colspan,"2");
167            final Element b = XhtmlUtil.element(XHTML.b,"No results");
168            td.addContent(b);
169
170            row.addContent(td);
171
172            table.addContent(row);
173        }
174
175        return XhtmlUtil.serialize(table);
176    }
177}