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