    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
    020package org.apache.wiki.plugin;
    021
    022import org.apache.commons.lang3.StringUtils;
    023import org.apache.logging.log4j.LogManager;
    024import org.apache.logging.log4j.Logger;
    025import org.apache.wiki.api.core.Context;
    026import org.apache.wiki.api.core.ContextEnum;
    027import org.apache.wiki.api.exceptions.PluginException;
    028import org.apache.wiki.api.exceptions.ProviderException;
    029import org.apache.wiki.api.plugin.Plugin;
    030import org.apache.wiki.pages.PageManager;
    031import org.apache.wiki.references.ReferenceManager;
    032import org.jdom2.Element;
    033import org.jdom2.Namespace;
    034import org.jdom2.output.Format;
    035import org.jdom2.output.XMLOutputter;
    036
    037import java.util.List;
    038import java.util.Map;
    039import java.util.Set;
    040import java.util.regex.Pattern;
    041import java.util.stream.Collectors;
    042
    043/**
    044 *  A Plugin that creates an index of pages according to a certain pattern.
    045 *  <br />
    046 *  The default is to include all pages.
    047 *  <p>
    048 *  This is a rewrite of the earlier JSPWiki IndexPlugin using JDOM2.
    049 8  </p>
    050 *  <p>
    051 *  Parameters (from AbstractReferralPlugin):
    052 *  </p>
    053 *  <ul>
    054 *    <li><b>include</b> - A regexp pattern for marking which pages should be included.</li>
    055 *    <li><b>exclude</b> - A regexp pattern for marking which pages should be excluded.</li>
    056 *  </ul>
    057 *
    058 * @author Ichiro Furusato
    059 */
    060public class IndexPlugin extends AbstractReferralPlugin implements Plugin {
    061
    062    private static final Logger LOG = LogManager.getLogger(IndexPlugin.class);
    063
    064    private final Namespace xmlns_XHTML = Namespace.getNamespace("http://www.w3.org/1999/xhtml");
    065
    066    /**
    067     * {@inheritDoc}
    068     */
    069    @Override
    070    public String execute( final Context context, final Map<String,String> params ) throws PluginException {
    071        final String include = params.get(PARAM_INCLUDE);
    072        final String exclude = params.get(PARAM_EXCLUDE);
    073
    074        final Element masterDiv = getElement("div","index");
    075        final Element indexDiv = getElement("div","header");
    076        masterDiv.addContent(indexDiv);
    077        try {
    078            final List<String> pages = listPages(context,include,exclude);
    079            context.getEngine().getManager( PageManager.class ).getPageSorter().sort(pages);
    080            char initialChar = ' ';
    081            Element currentDiv = new Element("div",xmlns_XHTML);
    082            for( final String name : pages ) {
    083                if( StringUtils.isNotBlank( name ) &&  name.charAt(0) != initialChar ) {
    084                    if ( initialChar != ' ' ) {
    085                        indexDiv.addContent(" - ");
    086                    }
    087                    initialChar = name.charAt(0);
    088                    masterDiv.addContent(makeHeader(String.valueOf(initialChar)));
    089                    currentDiv = getElement("div","body");
    090                    masterDiv.addContent(currentDiv);
    091                    indexDiv.addContent(getLink("#"+initialChar,String.valueOf(initialChar)));
    092                } else {
    093                    currentDiv.addContent(", ");
    094                }
    095                currentDiv.addContent( getLink( context.getURL( ContextEnum.PAGE_VIEW.getRequestContext(), name ), name ) );
    096            }
    097
    098        } catch( final ProviderException e ) {
    099            LOG.warn("could not load page index",e);
    100            throw new PluginException( e.getMessage() );
    101        }
    102        // serialize to raw format string (no changes to whitespace)
    103        final XMLOutputter out = new XMLOutputter(Format.getRawFormat());
    104        return out.outputString(masterDiv);
    105    }
    106
    107    private Element getLink( final String href, final String content ) {
    108        final Element a = new Element( "a", xmlns_XHTML );
    109        a.setAttribute( "href", href );
    110        a.addContent( content );
    111        return a;
    112    }
    113
    114    private Element makeHeader( final String initialChar ) {
    115        final Element span = getElement( "span", "section" );
    116        final Element a = new Element( "a", xmlns_XHTML );
    117        a.setAttribute( "id", initialChar );
    118        a.addContent( initialChar );
    119        span.addContent( a );
    120        return span;
    121    }
    122
    123    private Element getElement( final String gi, final String classValue ) {
    124        final Element elt = new Element( gi, xmlns_XHTML );
    125        elt.setAttribute( "class", classValue );
    126        return elt;
    127    }
    128
    129    /**
    130     *  Grabs a list of all pages and filters them according to the include/exclude patterns.
    131     *
    132     * @param context
    133     * @param include
    134     * @param exclude
    135     * @return A list containing page names which matched the filters.
    136     * @throws ProviderException
    137     */
    138    private List<String> listPages( final Context context, final String include, final String exclude ) throws ProviderException {
    139        final Pattern includePtrn = include != null ? Pattern.compile( include ) : Pattern.compile(".*");
    140        final Pattern excludePtrn = exclude != null ? Pattern.compile( exclude ) : Pattern.compile("\\p{Cntrl}"); // there are no control characters in page names
    141        final List< String > result;
    142        final Set< String > pages = context.getEngine().getManager( ReferenceManager.class ).findCreated();
    143        result = pages.stream().filter(pageName -> !excludePtrn.matcher(pageName).matches()).filter(pageName -> includePtrn.matcher(pageName).matches()).collect(Collectors.toList());
    144        return result;
    145    }
    146
    147}