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