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