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