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    
020    package org.apache.wiki.plugin;
021    
022    import org.apache.log4j.Logger;
023    import org.apache.wiki.WikiContext;
024    import org.apache.wiki.api.exceptions.PluginException;
025    import org.apache.wiki.api.exceptions.ProviderException;
026    import org.apache.wiki.api.plugin.WikiPlugin;
027    import org.apache.wiki.plugin.AbstractReferralPlugin;
028    import org.jdom2.Element;
029    import org.jdom2.Namespace;
030    import org.jdom2.output.Format;
031    import org.jdom2.output.XMLOutputter;
032    
033    import java.util.ArrayList;
034    import java.util.Collection;
035    import java.util.Iterator;
036    import java.util.List;
037    import java.util.Map;
038    import 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     */
057    public 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    }