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*/ 019package org.apache.wiki.plugin; 020 021import java.util.*; 022 023import org.apache.log4j.Logger; 024import org.apache.oro.text.regex.*; 025import org.apache.wiki.ReferenceManager; 026import org.apache.wiki.WikiContext; 027import org.apache.wiki.WikiEngine; 028import org.apache.wiki.WikiPage; 029import org.apache.wiki.api.exceptions.PluginException; 030import org.apache.wiki.api.plugin.WikiPlugin; 031import org.apache.wiki.util.TextUtil; 032 033 034/** 035 * Displays the pages referring to the current page. 036 * 037 * <p>Parameters</p> 038 * <ul> 039 * <li><b>name</b> - Name of the root page. Default name of calling page 040 * <li><b>type</b> - local|externalattachment 041 * <li><b>depth</b> - How many levels of pages to be parsed. 042 * <li><b>include</b> - Include only these pages. (eg. include='UC.*|BP.*' ) 043 * <li><b>exclude</b> - Exclude with this pattern. (eg. exclude='LeftMenu' ) 044 * <li><b>format</b> - full|compact, FULL now expands all levels correctly 045 * </ul> 046 * 047 */ 048public class ReferredPagesPlugin implements WikiPlugin 049{ 050 private static Logger log = Logger.getLogger( ReferredPagesPlugin.class ); 051 private WikiEngine m_engine; 052 private int m_depth; 053 private HashSet<String> m_exists = new HashSet<String>(); 054 private StringBuffer m_result = new StringBuffer(1024); 055 private PatternMatcher m_matcher = new Perl5Matcher(); 056 private Pattern m_includePattern; 057 private Pattern m_excludePattern; 058 private boolean m_formatCompact = true; 059 private boolean m_formatSort = false; 060 061 /** The parameter name for the root page to start from. Value is <tt>{@value}</tt>. */ 062 public static final String PARAM_ROOT = "page"; 063 064 /** The parameter name for the depth. Value is <tt>{@value}</tt>. */ 065 public static final String PARAM_DEPTH = "depth"; 066 067 /** The parameter name for the type of the references. Value is <tt>{@value}</tt>. */ 068 public static final String PARAM_TYPE = "type"; 069 070 /** The parameter name for the included pages. Value is <tt>{@value}</tt>. */ 071 public static final String PARAM_INCLUDE = "include"; 072 073 /** The parameter name for the excluded pages. Value is <tt>{@value}</tt>. */ 074 public static final String PARAM_EXCLUDE = "exclude"; 075 076 /** The parameter name for the format. Value is <tt>{@value}</tt>. */ 077 public static final String PARAM_FORMAT = "format"; 078 079 /** The minimum depth. Value is <tt>{@value}</tt>. */ 080 public static final int MIN_DEPTH = 1; 081 082 /** The maximum depth. Value is <tt>{@value}</tt>. */ 083 public static final int MAX_DEPTH = 8; 084 085 /** 086 * {@inheritDoc} 087 */ 088 public String execute( WikiContext context, Map<String, String> params ) 089 throws PluginException 090 { 091 m_engine = context.getEngine(); 092 093 WikiPage page = context.getPage(); 094 if( page == null ) return ""; 095 096 // parse parameters 097 String rootname = params.get( PARAM_ROOT ); 098 if( rootname == null ) rootname = page.getName() ; 099 100 String format = params.get( PARAM_FORMAT ); 101 if( format == null) format = ""; 102 if( format.indexOf( "full" ) >=0 ) m_formatCompact = false ; 103 if( format.indexOf( "sort" ) >=0 ) m_formatSort = true ; 104 105 m_depth = TextUtil.parseIntParameter( params.get( PARAM_DEPTH ), MIN_DEPTH ); 106 if( m_depth > MAX_DEPTH ) m_depth = MAX_DEPTH; 107 108 String includePattern = params.get(PARAM_INCLUDE); 109 if( includePattern == null ) includePattern = ".*"; 110 111 String excludePattern = params.get(PARAM_EXCLUDE); 112 if( excludePattern == null ) excludePattern = "^$"; 113 114 log.debug( "Fetching referred pages for "+ rootname + 115 " with a depth of "+ m_depth + 116 " with include pattern of "+ includePattern + 117 " with exclude pattern of "+ excludePattern ); 118 119 // 120 // do the actual work 121 // 122 String href = context.getViewURL(rootname); 123 String title = "ReferredPagesPlugin: depth["+m_depth+ 124 "] include["+includePattern+"] exclude["+excludePattern+ 125 "] format["+(m_formatCompact ? "compact" : "full") + 126 (m_formatSort ? " sort" : "") + "]"; 127 128 m_result.append("<div class=\"ReferredPagesPlugin\">\n"); 129 m_result.append("<a class=\"wikipage\" href=\""+ href + 130 "\" title=\"" + title + 131 "\">" + rootname + "</a>\n"); 132 m_exists.add(rootname); 133 134 // pre compile all needed patterns 135 // glob compiler : * is 0..n instance of any char -- more convenient as input 136 // perl5 compiler : .* is 0..n instances of any char -- more powerful 137 //PatternCompiler g_compiler = new GlobCompiler(); 138 PatternCompiler compiler = new Perl5Compiler(); 139 140 try 141 { 142 m_includePattern = compiler.compile(includePattern); 143 144 m_excludePattern = compiler.compile(excludePattern); 145 } 146 catch( MalformedPatternException e ) 147 { 148 if (m_includePattern == null ) 149 { 150 throw new PluginException("Illegal include pattern detected."); 151 } 152 else if (m_excludePattern == null ) 153 { 154 throw new PluginException("Illegal exclude pattern detected."); 155 } 156 else 157 { 158 throw new PluginException("Illegal internal pattern detected."); 159 } 160 } 161 162 // go get all referred links 163 getReferredPages(context,rootname, 0); 164 165 // close and finish 166 m_result.append ("</div>\n" ) ; 167 168 return m_result.toString() ; 169 } 170 171 172 /** 173 * Retrieves a list of all referred pages. Is called recursively 174 * depending on the depth parameter 175 */ 176 @SuppressWarnings("unchecked") 177 private void getReferredPages( WikiContext context, String pagename, int depth ) 178 { 179 if( depth >= m_depth ) return; // end of recursion 180 if( pagename == null ) return; 181 if( !m_engine.pageExists(pagename) ) return; 182 183 ReferenceManager mgr = m_engine.getReferenceManager(); 184 185 Collection<String> allPages = mgr.findRefersTo( pagename ); 186 187 handleLinks( context, allPages, ++depth, pagename ); 188 } 189 190 private void handleLinks(WikiContext context,Collection<String> links, int depth, String pagename) 191 { 192 boolean isUL = false; 193 HashSet<String> localLinkSet = new HashSet<String>(); // needed to skip multiple 194 // links to the same page 195 localLinkSet.add(pagename); 196 197 ArrayList<String> allLinks = new ArrayList<String>(); 198 199 if( links != null ) 200 allLinks.addAll( links ); 201 202 if( m_formatSort ) context.getEngine().getPageSorter().sort( allLinks ); 203 204 for( Iterator<String> i = allLinks.iterator(); i.hasNext(); ) 205 { 206 String link = i.next() ; 207 208 if( localLinkSet.contains( link ) ) continue; // skip multiple links to the same page 209 localLinkSet.add( link ); 210 211 if( !m_engine.pageExists( link ) ) continue; // hide links to non existing pages 212 213 if( m_matcher.matches( link , m_excludePattern ) ) continue; 214 if( !m_matcher.matches( link , m_includePattern ) ) continue; 215 216 if( m_exists.contains( link ) ) 217 { 218 if( !m_formatCompact ) 219 { 220 if( !isUL ) 221 { 222 isUL = true; m_result.append("<ul>\n"); 223 } 224 225 //See https://www.w3.org/wiki/HTML_lists for proper nesting of UL and LI 226 m_result.append("<li> " + link + "\n"); 227 228 getReferredPages( context, link, depth ); // added recursive 229 // call - on general 230 // request 231 232 m_result.append("\n</li>\n"); 233 234 } 235 } 236 else 237 { 238 if( !isUL ) 239 { 240 isUL = true; m_result.append("<ul>\n"); 241 } 242 243 String href = context.getURL(WikiContext.VIEW,link); 244 m_result.append("<li><a class=\"wikipage\" href=\""+ href +"\">"+link+"</a>\n" ); 245 246 m_exists.add( link ); 247 248 getReferredPages( context, link, depth ); 249 250 m_result.append("\n</li>\n"); 251 252 } 253 } 254 255 if( isUL ) m_result.append("</ul>\n"); 256 } 257} 258