📄 linktool.java
字号:
package org.apache.velocity.tools.view.tools;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.velocity.tools.generic.ValueParser;
import org.apache.velocity.tools.view.context.ViewContext;
import org.apache.velocity.tools.view.servlet.ServletUtils;
/**
* View tool to make building URIs pleasant and fun!
* <p><pre>
* Template example(s):
* #set( $base = $link.relative('MyPage.vm').anchor('view') )
* <a href="$base.param('select','this')">this</a>
* <a href="$base.param('select','that')">that</a>
*
* Toolbox configuration:
* <tool>
* <key>link</key>
* <scope>request</scope>
* <class>org.apache.velocity.tools.view.tools.LinkTool</class>
* </tool>
* </pre></p>
*
* <p>This tool should only be used in the request scope.</p>
*
* @author <a href="mailto:sidler@teamup.com">Gabe Sidler</a>
* @author Nathan Bubna
* @since VelocityTools 1.0
* @version $Id: LinkTool.java 485175 2006-12-10 12:52:56Z henning $
*/
public class LinkTool implements Cloneable
{
protected static final Log LOG = LogFactory.getLog(LinkTool.class);
/**
* Parameter key for configuring {@link #setSelfAbsolute} state
* @since VelocityTools 1.3
*/
public static final String SELF_ABSOLUTE_KEY = "self-absolute";
/**
* Parameter key for configuring {@link #setSelfIncludeParameters} state
* @since VelocityTools 1.3
*/
public static final String SELF_INCLUDE_PARAMETERS_KEY = "self-include-parameters";
/** Standard HTML delimiter for query data ('&') */
public static final String HTML_QUERY_DELIMITER = "&";
/** XHTML delimiter for query data ('&amp;') */
public static final String XHTML_QUERY_DELIMITER = "&";
/** A reference to the ServletContext */
protected ServletContext application;
/** A reference to the HttpServletRequest. */
protected HttpServletRequest request;
/** A reference to the HttpServletResponse. */
protected HttpServletResponse response;
/** The URI reference set for this link. */
private String uri;
/** The anchor set for this link. */
private String anchor;
/** A list of query string parameters. */
private ArrayList queryData;
/** The current delimiter for query data */
private String queryDataDelim;
/** The self-absolute status */
private boolean selfAbsolute;
/** The self-include-parameters status */
private boolean selfParams;
/** Java 1.4 encode method to use instead of deprecated 1.3 version. */
private static Method encode = null;
/* Initialize the encode variable with the 1.4 method if available.
* this code was adapted from org.apache.struts.utils.RequestUtils */
static
{
try
{
/* get version of encode method with two String args */
Class[] args = new Class[] { String.class, String.class };
encode = URLEncoder.class.getMethod("encode", args);
}
catch (NoSuchMethodException e)
{
LOG.debug("Can't find JDK 1.4 encode method. Using JDK 1.3 version.");
}
}
/**
* Default constructor. Tool must be initialized before use.
*/
public LinkTool()
{
uri = null;
anchor = null;
queryData = null;
queryDataDelim = HTML_QUERY_DELIMITER;
selfAbsolute = false;
selfParams = false;
}
// --------------------------------------- Protected Methods -------------
/**
* <p>Controls the delimiter used for separating query data pairs.
* By default, the standard '&' character is used.</p>
* <p>This is not exposed to templates as this decision is best not
* made at that level.</p>
* <p>Subclasses may easily override the init() method to set this
* appropriately and then call super.init()</p>
*
* @param useXhtml if true, the XHTML query data delimiter ('&amp;')
* will be used. if false, then '&' will be used.
* @see <a href="http://www.w3.org/TR/xhtml1/#C_12">Using Ampersands in Attribute Values (and Elsewhere)</a>
*/
protected void setXhtml(boolean useXhtml)
{
queryDataDelim =
(useXhtml) ? XHTML_QUERY_DELIMITER : HTML_QUERY_DELIMITER;
}
/**
* <p>Controls whether or not the {@link #getSelf()} method will return
* a duplicate with a URI in absolute or relative form.</p>
*
* @param selfAbsolute if true, the {@link #getSelf()} method will return
* a duplicate of this tool with an absolute self-referencing URI;
* if false, a duplicate with a relative self-referencing URI will
* be returned
* @see #getSelf()
* @since VelocityTools 1.3
*/
protected void setSelfAbsolute(boolean selfAbsolute)
{
this.selfAbsolute = selfAbsolute;
}
/**
* <p>Controls whether or not the {@link #getSelf()} method will return
* a duplicate that includes current request parameters.</p>
*
* @param selfParams if true, the {@link #getSelf()} method will return
* a duplicate of this tool that includes current request parameters
* @see #getSelf()
* @since VelocityTools 1.3
*/
protected void setSelfIncludeParameters(boolean selfParams)
{
this.selfParams = selfParams;
}
/**
* For internal use.
*
* Copies 'that' LinkTool into this one and adds the new query data.
*
* @param pair the query parameter to add
*/
protected LinkTool copyWith(QueryPair pair)
{
LinkTool copy = duplicate();
if (copy.queryData != null)
{
// set the copy's query data to a shallow clone of
// the current query data array
copy.queryData = (ArrayList)this.queryData.clone();
}
else
{
copy.queryData = new ArrayList();
}
//add new pair to this LinkTool's query data
copy.queryData.add(pair);
return copy;
}
/**
* For internal use.
*
* Copies 'that' LinkTool into this one and adds the new query data.
*
* @param newQueryData the query parameters to add
* @since VelocityTools 1.3
*/
protected LinkTool copyWith(Map newQueryData)
{
LinkTool copy = duplicate();
if (copy.queryData != null)
{
// set the copy's query data to a shallow clone of
// the current query data array
copy.queryData = (ArrayList)this.queryData.clone();
}
else
{
copy.queryData = new ArrayList();
}
for (Iterator i = newQueryData.keySet().iterator(); i.hasNext(); )
{
Object key = i.next();
Object value = newQueryData.get(key);
copy.queryData.add(new QueryPair(String.valueOf(key), value));
}
return copy;
}
/**
* For internal use.
*
* Copies 'that' LinkTool into this one and sets the new URI.
*
* @param uri uri string
*/
protected LinkTool copyWith(String uri)
{
LinkTool copy = duplicate();
copy.uri = uri;
return copy;
}
/**
* For internal use.
*
* Copies 'that' LinkTool into this one and sets the new
* anchor for the link.
*
* @param anchor URI string
*/
protected LinkTool copyWithAnchor(String anchor)
{
LinkTool copy = duplicate();
copy.anchor = anchor;
return copy;
}
/**
* This is just to avoid duplicating this code for both copyWith() methods
*/
protected LinkTool duplicate()
{
try
{
return (LinkTool)this.clone();
}
catch (CloneNotSupportedException e)
{
LOG.warn("Could not properly clone " + getClass() + " - " + e);
// "clone" manually
LinkTool copy;
try
{
// one last try for a subclass instance...
copy = (LinkTool)getClass().newInstance();
}
catch (Exception ee)
{
// fine, we'll use the base class
copy = new LinkTool();
}
copy.application = this.application;
copy.request = this.request;
copy.response = this.response;
copy.uri = this.uri;
copy.anchor = this.anchor;
copy.queryData = this.queryData;
copy.queryDataDelim = this.queryDataDelim;
copy.selfAbsolute = this.selfAbsolute;
copy.selfParams = this.selfParams;
return copy;
}
}
// --------------------------------------- Toolbox Methods -------------
/**
* Configures this tool
*
* @param params Map of configuration parameters
* @since VelocityTools 1.3
*/
public void configure(Map params)
{
ValueParser parser = new ValueParser(params);
Boolean selfAbsolute = parser.getBoolean(SELF_ABSOLUTE_KEY);
if (selfAbsolute != null)
{
setSelfAbsolute(selfAbsolute.booleanValue());
}
Boolean selfParams = parser.getBoolean(SELF_INCLUDE_PARAMETERS_KEY);
if (selfParams != null)
{
setSelfIncludeParameters(selfParams.booleanValue());
}
}
/**
* Initializes this tool.
*
* @param obj the current ViewContext
* @throws IllegalArgumentException if the param is not a ViewContext
*/
public void init(Object obj)
{
if (!(obj instanceof ViewContext))
{
throw new IllegalArgumentException("Tool can only be initialized with a ViewContext");
}
ViewContext context = (ViewContext)obj;
this.request = context.getRequest();
this.response = context.getResponse();
this.application = context.getServletContext();
Boolean b = (Boolean)context.getAttribute(ViewContext.XHTML);
if (b != null)
{
setXhtml(b.booleanValue());
}
}
// --------------------------------------------- Template Methods -----------
/**
* <p>Returns a copy of the link with the specified anchor to be
* added to the end of the generated hyperlink.</p>
*
* Example:<br>
* <code><a href='$link.setAnchor("foo")'>Foo</a></code><br>
* produces something like</br>
* <code><a href="#foo">Foo</a></code><br>
*
* @param anchor an internal document reference
*
* @return a new instance of LinkTool with the set anchor
*/
public LinkTool setAnchor(String anchor)
{
return copyWithAnchor(anchor);
}
/**
* Convenience method equivalent to {@link #setAnchor}.
* @since VelocityTools 1.3
*/
public LinkTool anchor(String anchor)
{
return setAnchor(anchor);
}
/**
* Returns the anchor (internal document reference) set for this link.
*/
public String getAnchor()
{
return anchor;
}
/**
* <p>Returns a copy of the link with the specified context-relative
* URI reference converted to a server-relative URI reference. This
* method will overwrite any previous URI reference settings but will
* copy the query string.</p>
*
* Example:<br>
* <code><a href='$link.setRelative("/templates/login/index.vm")'>Login Page</a></code><br>
* produces something like</br>
* <code><a href="/myapp/templates/login/index.vm">Login Page</a></code><br>
*
* @param uri A context-relative URI reference. A context-relative URI
* is a URI that is relative to the root of this web application.
*
* @return a new instance of LinkTool with the specified URI
*/
public LinkTool setRelative(String uri)
{
String ctxPath = request.getContextPath();
/* if the context path is the webapp root */
if (ctxPath.equals("/"))
{
/* then don't append anything for it */
ctxPath = "";
}
if (uri.startsWith("/"))
{
return copyWith(ctxPath + uri);
}
else
{
return copyWith(ctxPath + '/' + uri);
}
}
/**
* Convenience method equivalent to {@link #setRelative}.
* @since VelocityTools 1.3
*/
public LinkTool relative(String uri)
{
return setRelative(uri);
}
/**
* <p>Returns a copy of the link with the specified URI reference
* either used as or converted to an absolute (non-relative)
* URI reference. This method will overwrite any previous URI
* reference settings but will copy the query string.</p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -