/*
* Copyright 1999-2004 The Apache Software Foundation.
*
* Licensed 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.
*/
package org.anodyneos.xp.tag.core;
import java.io.UnsupportedEncodingException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.el.ELException;
import org.anodyneos.xp.XpContext;
import org.anodyneos.xp.XpException;
import org.anodyneos.xp.XpOutput;
import org.anodyneos.xp.http.HttpXpContext;
import org.anodyneos.xp.tag.Config;
import org.anodyneos.xp.tagext.XpTagSupport;
import org.xml.sax.SAXException;
/**
* <p>
* Support for tag handlers for <url>, the URL creation and rewriting tag
* in JSTL 1.0.
* </p>
*
* @author Shawn Bayern
*/
public class UrlTag extends XpTagSupport implements ParamParent {
public static final String DEFAULT_URI_ENCODING = "UTF-8";
public static final String VALID_SCHEME_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+.-";
private String value; // 'value' attribute
private String context; // 'context' attribute
private String uriEncoding; // 'uriEncoding' attribute
private String attributeName; // 'attributeName' attribute
private String attributeNamespace; // 'attributeNamespace' attribute
private String var; // 'var' attribute
private String fragment; // 'fragment' attribute
private int scope; // processed 'scope' attr
private ParamTag.ParamManager params; // added parameters
public UrlTag() {
value = var = null;
params = null;
context = null;
scope = XpContext.PAGE_SCOPE;
}
// attribute setters & getters
public void setVar(String var) { this.var = var; }
public void setValue(String value) { this.value = value; }
public void setAttributeName(String attributeName) { this.attributeName = attributeName; }
public void setAttributeNamespace(String attributeNamespace) { this.attributeNamespace = attributeNamespace; }
public void setScope(String scope) { this.scope = getXpContext().resolveScope(scope); }
public void setContext(String context) { this.context = context; }
public void setUriEncoding(String uriEncoding) { this.uriEncoding = uriEncoding; }
public void setFragment(String fragment) { this.fragment = fragment; }
public String getContext() {
String ctx = null;
// try explicit setting via "context" tag attribute
if (null != this.context) {
ctx = this.context;
}
// try config
if (null == ctx) {
ctx = (String) Config.find(getXpContext(), Config.CORE_CONTEXT_URI);
}
// try http servlet
if (null == ctx && getXpContext() instanceof HttpXpContext) {
HttpServletRequest request = (HttpServletRequest) ((HttpXpContext)getXpContext()).getRequest();
ctx = request.getContextPath();
}
return ctx;
}
// *********************************************************************
// Collaboration with subtags
public void addParameter(String name, String value) {
params.addParameter(name, value);
}
// *********************************************************************
// Tag logic
public void doTag(XpOutput out) throws XpException, SAXException, ELException {
params = new ParamTag.ParamManager();
if (null != getXpBody()) {
getXpBody().invokeToString();
}
String result; // the eventual result
String contextUri = getContext();
String baseUrl = resolveUri(value, contextUri);
String encoding = getUriEncodingFor(baseUrl);
try {
result = params.aggregateParams(baseUrl, fragment, encoding);
} catch (UnsupportedEncodingException ex) {
throw new XpException(ex);
}
// if the URL is relative, rewrite it to include non-cookie based session ID
/*
if (!isAbsoluteUri(result) && getXpContext() instanceof HttpXpContext) {
// JIRA ZP-6
// The result looks like: /zeus-proto/;jsessionid=AAECA83C53178F746DAFB5CE56CE9EA3
// which causes some pre-login problems (pre session cookie). Disabling until solution worked out for
// using the output of <c:url> to produce a baseURL template for post-process skinning.
HttpServletResponse response = ((HttpServletResponse) ((HttpXpContext) getXpContext()).getResponse());
result = response.encodeURL(result);
}
*/
// store or print the output
if (var != null) {
getXpContext().setAttribute(var, result, scope);
} else if (attributeName == null){
out.write(result);
}
// always set an attribute if asked to do so
if (attributeName != null) {
out.addAttribute(attributeNamespace, attributeName, result);
}
}
// *********************************************************************
// Utility methods
/**
* @param uri
* The absolute or relative URI to resolve;
* @param contextUri
* The context URI used to resolve relative URIs with
* absolute paths; may be absolute or relative with an
* absolute path component.
*
* @return The resolved URI; may be relative, fully qualified, or absolute.
*/
public static String resolveUri(String uri, String contextUri) throws XpException {
if (null == contextUri) {
return uri;
}
if (! isAbsoluteUri(contextUri) && ! contextUri.startsWith("/")) {
throw new XpException("context URI must be absolute or relative with an absolute path");
}
if (isAbsoluteUri(uri)) {
// don't touch absolute URIs
return uri;
} else if (! uri.startsWith("/")) {
// don't touch relative URIs
return uri;
} else {
// uri is an absolute path
// avoid "//" in path part
if(contextUri.endsWith("/")) {
return (contextUri + uri.substring(1));
} else {
return (contextUri + uri);
}
}
}
/**
* Returns <tt>true</tt> if our current URL is absolute, <tt>false</tt>
* otherwise.
*/
public static boolean isAbsoluteUri(String url) {
// a null URL is not absolute, by our definition
if (url == null) {
return false;
}
// do a fast, simple check first
int colonPos;
if ((colonPos = url.indexOf(":")) == -1) {
return false;
}
// if we DO have a colon, make sure that every character
// leading up to it is a valid scheme character
for (int i = 0; i < colonPos; i++) {
if (VALID_SCHEME_CHARS.indexOf(url.charAt(i)) == -1) {
return false;
}
}
// if so, we've got an absolute url
return true;
}
protected String getUriEncodingFor(String uri) {
String encoding;
encoding = this.uriEncoding;
if (null == encoding) {
encoding = (String) Config.find(getXpContext(), Config.CORE_URI_ENCODING);
}
if (null == encoding && !isAbsoluteUri(uri) && (getXpContext() instanceof HttpXpContext)) {
encoding = ((HttpXpContext) getXpContext()).getResponse().getCharacterEncoding();
}
if (null == encoding) {
encoding = (String) Config.find(getXpContext(), Config.CORE_FALLBACK_URI_ENCODING);
}
if (null == encoding) {
encoding = DEFAULT_URI_ENCODING;
}
return encoding;
}
}