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