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 package org.apache.wiki.tags; 020 021 import java.util.HashMap; 022 import java.util.Iterator; 023 import java.util.Map; 024 025 import javax.servlet.jsp.JspException; 026 import javax.servlet.jsp.JspWriter; 027 import javax.servlet.jsp.tagext.BodyContent; 028 import javax.servlet.jsp.tagext.BodyTag; 029 030 import org.apache.log4j.Logger; 031 import org.apache.wiki.WikiContext; 032 import org.apache.wiki.WikiEngine; 033 import org.apache.wiki.WikiPage; 034 import org.apache.wiki.WikiProvider; 035 import org.apache.wiki.api.exceptions.ProviderException; 036 import org.apache.wiki.attachment.Attachment; 037 import org.apache.wiki.parser.JSPWikiMarkupParser; 038 import org.apache.wiki.parser.MarkupParser; 039 import org.apache.wiki.util.TextUtil; 040 041 /** 042 * Provides a generic link tag for all kinds of linking 043 * purposes. 044 * <p> 045 * If parameter <i>jsp</i> is defined, constructs a URL pointing 046 * to the specified JSP page, under the baseURL known by the WikiEngine. 047 * Any ParamTag name-value pairs contained in the body are added to this 048 * URL to provide support for arbitrary JSP calls. 049 * <p> 050 * @since 2.3.50 051 */ 052 public class LinkTag extends WikiLinkTag implements ParamHandler, BodyTag { 053 054 static final long serialVersionUID = 0L; 055 private static final Logger log = Logger.getLogger( LinkTag.class ); 056 057 private String m_version = null; 058 private String m_class = null; 059 private String m_style = null; 060 private String m_title = null; 061 private String m_target = null; 062 private String m_compareToVersion = null; 063 private String m_rel = null; 064 private String m_jsp = null; 065 private String m_ref = null; 066 private String m_context = WikiContext.VIEW; 067 private String m_accesskey = null; 068 private String m_templatefile = null; 069 070 private boolean m_absolute = false; 071 private boolean m_overrideAbsolute = false; 072 073 private Map<String, String> m_containedParams; 074 075 private BodyContent m_bodyContent; 076 077 public void initTag() 078 { 079 super.initTag(); 080 m_version = m_class = m_style = m_title = m_target = m_compareToVersion = m_rel = m_jsp = m_ref = m_accesskey = m_templatefile = null; 081 m_context = WikiContext.VIEW; 082 m_absolute = false; 083 } 084 085 public void setTemplatefile( String key ) 086 { 087 m_templatefile = key; 088 } 089 090 public void setAccessKey( String key ) 091 { 092 m_accesskey = key; 093 } 094 095 public void setAbsolute( String arg ) 096 { 097 m_overrideAbsolute = true; 098 m_absolute = TextUtil.isPositive( arg ); 099 } 100 101 public String getVersion() 102 { 103 return m_version; 104 } 105 106 public void setVersion( String arg ) 107 { 108 m_version = arg; 109 } 110 111 public void setClass( String arg ) 112 { 113 m_class = arg; 114 } 115 116 public void setStyle( String style ) 117 { 118 m_style = style; 119 } 120 121 public void setTitle( String title ) 122 { 123 m_title = title; 124 } 125 126 public void setTarget( String target ) 127 { 128 m_target = target; 129 } 130 131 public void setCompareToVersion( String ver ) 132 { 133 m_compareToVersion = ver; 134 } 135 136 public void setRel( String rel ) 137 { 138 m_rel = rel; 139 } 140 141 public void setRef( String ref ) 142 { 143 m_ref = ref; 144 } 145 146 public void setJsp( String jsp ) 147 { 148 m_jsp = jsp; 149 } 150 151 public void setContext( String context ) 152 { 153 m_context = context; 154 } 155 156 /** 157 * Support for ParamTag supplied parameters in body. 158 */ 159 public void setContainedParameter( String name, String value ) 160 { 161 if( name != null ) 162 { 163 if( m_containedParams == null ) 164 { 165 m_containedParams = new HashMap<String, String>(); 166 } 167 m_containedParams.put( name, value ); 168 } 169 } 170 171 172 /** 173 * This method figures out what kind of an URL should be output. It mirrors heavily 174 * on JSPWikiMarkupParser.handleHyperlinks(); 175 * 176 * @return the URL 177 * @throws ProviderException 178 */ 179 private String figureOutURL() 180 throws ProviderException 181 { 182 String url = null; 183 WikiEngine engine = m_wikiContext.getEngine(); 184 185 if( m_pageName == null ) 186 { 187 WikiPage page = m_wikiContext.getPage(); 188 189 if( page != null ) 190 { 191 m_pageName = page.getName(); 192 } 193 } 194 195 if( m_templatefile != null ) 196 { 197 String params = addParamsForRecipient( null, m_containedParams ); 198 String template = engine.getTemplateDir(); 199 url = engine.getURL( WikiContext.NONE, "templates/"+template+"/"+m_templatefile, params, false ); 200 } 201 else if( m_jsp != null ) 202 { 203 String params = addParamsForRecipient( null, m_containedParams ); 204 //url = m_wikiContext.getURL( WikiContext.NONE, m_jsp, params ); 205 url = engine.getURL( WikiContext.NONE, m_jsp, params, m_absolute ); 206 } 207 else if( m_ref != null ) 208 { 209 int interwikipoint; 210 211 if( JSPWikiMarkupParser.isExternalLink(m_ref) ) 212 { 213 url = m_ref; 214 } 215 else if( (interwikipoint = m_ref.indexOf(":")) != -1 ) 216 { 217 String extWiki = m_ref.substring( 0, interwikipoint ); 218 String wikiPage = m_ref.substring( interwikipoint+1 ); 219 220 url = engine.getInterWikiURL( extWiki ); 221 222 if( url != null ) 223 { 224 url = TextUtil.replaceString( url, "%s", wikiPage ); 225 } 226 } 227 else if( m_ref.startsWith("#") ) 228 { 229 // Local link 230 } 231 else if( TextUtil.isNumber(m_ref) ) 232 { 233 // Reference 234 } 235 else 236 { 237 int hashMark = -1; 238 239 String parms = (m_version != null) ? "version="+getVersion() : null; 240 241 // 242 // Internal wiki link, but is it an attachment link? 243 // 244 WikiPage p = engine.getPage( m_pageName ); 245 246 if( p instanceof Attachment ) 247 { 248 url = m_wikiContext.getURL( WikiContext.ATTACH, m_pageName ); 249 } 250 else if( (hashMark = m_ref.indexOf('#')) != -1 ) 251 { 252 // It's an internal Wiki link, but to a named section 253 254 String namedSection = m_ref.substring( hashMark+1 ); 255 String reallink = m_ref.substring( 0, hashMark ); 256 257 reallink = MarkupParser.cleanLink( reallink ); 258 259 String matchedLink; 260 String sectref = ""; 261 if( (matchedLink = engine.getFinalPageName( reallink )) != null ) 262 { 263 sectref = "section-"+engine.encodeName(matchedLink)+"-"+namedSection; 264 sectref = "#"+sectref.replace('%', '_'); 265 } 266 else 267 { 268 matchedLink = reallink; 269 } 270 271 url = makeBasicURL( m_context, matchedLink, parms, m_absolute ) + sectref; 272 } 273 else 274 { 275 String reallink = MarkupParser.cleanLink( m_ref ); 276 277 url = makeBasicURL( m_context, reallink, parms, m_absolute ); 278 } 279 } 280 } 281 else if( m_pageName != null && m_pageName.length() > 0 ) 282 { 283 WikiPage p = engine.getPage( m_pageName ); 284 285 String parms = (m_version != null) ? "version="+getVersion() : null; 286 287 parms = addParamsForRecipient( parms, m_containedParams ); 288 289 if( p instanceof Attachment ) 290 { 291 String ctx = m_context; 292 // Switch context appropriately when attempting to view an 293 // attachment, but don't override the context setting otherwise 294 if( m_context == null || m_context.equals( WikiContext.VIEW ) ) 295 { 296 ctx = WikiContext.ATTACH; 297 } 298 url = engine.getURL( ctx, m_pageName, parms, m_absolute ); 299 //url = m_wikiContext.getURL( ctx, m_pageName, parms ); 300 } 301 else 302 { 303 url = makeBasicURL( m_context, m_pageName, parms, m_absolute ); 304 } 305 } 306 else 307 { 308 String page = engine.getFrontPage(); 309 url = makeBasicURL( m_context, page, null, m_absolute ); 310 } 311 312 return url; 313 } 314 315 private String addParamsForRecipient( String addTo, Map< String, String > params ) 316 { 317 if( params == null || params.size() == 0 ) 318 { 319 return addTo; 320 } 321 StringBuilder buf = new StringBuilder(); 322 Iterator< Map.Entry< String, String > > it = params.entrySet().iterator(); 323 while( it.hasNext() ) 324 { 325 Map.Entry< String, String > e = it.next(); 326 String n = e.getKey(); 327 String v = e.getValue(); 328 buf.append( n ); 329 buf.append( "=" ); 330 buf.append( v ); 331 if( it.hasNext() ) 332 { 333 buf.append( "&" ); 334 } 335 } 336 if( addTo == null ) 337 { 338 return buf.toString(); 339 } 340 if( !addTo.endsWith( "&" ) ) 341 { 342 return addTo + "&" + buf.toString(); 343 } 344 return addTo + buf.toString(); 345 } 346 347 private String makeBasicURL( String context, String page, String parms, boolean absolute ) 348 { 349 String url; 350 WikiEngine engine = m_wikiContext.getEngine(); 351 352 if( context.equals( WikiContext.DIFF ) ) 353 { 354 int r1 = 0; 355 int r2 = 0; 356 357 if( DiffLinkTag.VER_LATEST.equals(getVersion()) ) 358 { 359 WikiPage latest = engine.getPage( page, WikiProvider.LATEST_VERSION ); 360 361 r1 = latest.getVersion(); 362 } 363 else if( DiffLinkTag.VER_PREVIOUS.equals(getVersion()) ) 364 { 365 r1 = m_wikiContext.getPage().getVersion() - 1; 366 r1 = (r1 < 1 ) ? 1 : r1; 367 } 368 else if( DiffLinkTag.VER_CURRENT.equals(getVersion()) ) 369 { 370 r1 = m_wikiContext.getPage().getVersion(); 371 } 372 else 373 { 374 r1 = Integer.parseInt( getVersion() ); 375 } 376 377 if( DiffLinkTag.VER_LATEST.equals(m_compareToVersion) ) 378 { 379 WikiPage latest = engine.getPage( page, WikiProvider.LATEST_VERSION ); 380 381 r2 = latest.getVersion(); 382 } 383 else if( DiffLinkTag.VER_PREVIOUS.equals(m_compareToVersion) ) 384 { 385 r2 = m_wikiContext.getPage().getVersion() - 1; 386 r2 = (r2 < 1 ) ? 1 : r2; 387 } 388 else if( DiffLinkTag.VER_CURRENT.equals(m_compareToVersion) ) 389 { 390 r2 = m_wikiContext.getPage().getVersion(); 391 } 392 else 393 { 394 r2 = Integer.parseInt( m_compareToVersion ); 395 } 396 397 parms = "r1="+r1+"&r2="+r2; 398 } 399 400 //url = m_wikiContext.getURL( m_context, m_pageName, parms ); 401 url = engine.getURL( m_context, m_pageName, parms, m_absolute ); 402 403 return url; 404 } 405 406 public int doWikiStartTag() throws Exception 407 { 408 return EVAL_BODY_BUFFERED; 409 } 410 411 public int doEndTag() 412 { 413 try 414 { 415 if( !m_overrideAbsolute ) 416 { 417 // TODO: see WikiContext.getURL(); this check needs to be specified somewhere. 418 WikiEngine engine = m_wikiContext.getEngine(); 419 m_absolute = "absolute".equals( engine.getWikiProperties().getProperty( WikiEngine.PROP_REFSTYLE ) ); 420 } 421 422 JspWriter out = pageContext.getOut(); 423 String url = figureOutURL(); 424 425 StringBuffer sb = new StringBuffer( 20 ); 426 427 sb.append( (m_class != null) ? "class=\""+m_class+"\" " : "" ); 428 sb.append( (m_style != null) ? "style=\""+m_style+"\" " : "" ); 429 sb.append( (m_target != null ) ? "target=\""+m_target+"\" " : "" ); 430 sb.append( (m_title != null ) ? "title=\""+m_title+"\" " : "" ); 431 sb.append( (m_rel != null ) ? "rel=\""+m_rel+"\" " : "" ); 432 sb.append( (m_accesskey != null) ? "accesskey=\""+m_accesskey+"\" " : "" ); 433 434 switch( m_format ) 435 { 436 case URL: 437 out.print( url ); 438 break; 439 default: 440 case ANCHOR: 441 out.print("<a "+sb.toString()+" href=\""+url+"\">"); 442 break; 443 } 444 445 // Add any explicit body content. This is not the intended use 446 // of LinkTag, but happens to be the way it has worked previously. 447 if( m_bodyContent != null ) 448 { 449 String linktext = m_bodyContent.getString().trim(); 450 out.write( linktext ); 451 } 452 453 // Finish off by closing opened anchor 454 if( m_format == ANCHOR ) out.print("</a>"); 455 } 456 catch( Exception e ) 457 { 458 // Yes, we want to catch all exceptions here, including RuntimeExceptions 459 log.error( "Tag failed", e ); 460 } 461 462 return EVAL_PAGE; 463 } 464 465 public void setBodyContent( BodyContent bc ) 466 { 467 m_bodyContent = bc; 468 } 469 470 public void doInitBody() throws JspException 471 { 472 } 473 }