/* ===============================================================================
*
* Part of the InfoGlue Content Management Platform (www.infoglue.org)
*
* ===============================================================================
*
* Copyright (C)
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 2, as published by the
* Free Software Foundation. See the file LICENSE.html for more information.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY, including the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc. / 59 Temple
* Place, Suite 330 / Boston, MA 02111-1307 / USA.
*
* ===============================================================================
*/
package org.infoglue.deliver.taglib.common;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspTagException;
import org.apache.log4j.Logger;
import org.infoglue.deliver.taglib.TemplateControllerTag;
import org.infoglue.cms.util.CmsPropertyHandler;
/**
* This class implements the <common:urlBuilder> tag, which creates an url
* from a base url (user supplied or taken from the request),
* a query string (user supplied ot taken from the reuest) and
* any number of parameters specified using nested <common:parameter> tags.
*/
public class URLTag extends TemplateControllerTag
{
private final static Logger logger = Logger.getLogger(URLTag.class.getName());
/**
*
*/
private static final long serialVersionUID = 4433903132736259601L;
/**
* The universal version identifier.
*/
/**
* The base url to use when constructing the url.
*/
private String baseURL;
/**
* The query to use when constructing the url.
*/
private String query;
/**
* The parameter names to exclude from the quertyString. Commasseperated string.
*/
private String excludedQueryStringParameters;
/**
* The parameter that controls if the full servername etc should be included in the base url.
*/
private boolean fullBaseUrl = false;
/**
* Include languageId in created urls
* */
private boolean includeLanguageId = true;
/**
* Determine if you want to replace https with http
* */
private boolean forceHTTPProtocol = false;
/**
* The parameters to use when constructing the url.
*/
private List parameters; // type: <String>, format: <name>=<value>
/**
* The names of all parameters added.
*/
private Map parameterNames; // <type>: <String>-><String>
/**
* Tells the tag if the nice uri option should be disabled if enabled.
*/
private boolean disableNiceURI = false;
/**
* Tells if parameter should be allowed even though there are parameters with that name
*/
private boolean allowMultipleArguments = false;
/**
* Tells if parameter should be allowed even though there are parameters with that name
*/
private boolean includeCurrentQueryString = true;
/**
* Default constructor.
*/
public URLTag()
{
super();
}
/**
* Initializes the parameters to make it accessible for the children tags (if any).
*
* @return indication of whether to evaluate the body or not.
* @throws JspException if an error occurred while processing this tag.
*/
public int doStartTag() throws JspException
{
return EVAL_BODY_INCLUDE;
}
/**
* Generates the url and either sets the result attribute or writes the url
* to the output stream.
*
* @return indication of whether to continue evaluating the JSP page.
* @throws JspException if an error occurred while processing this tag.
*/
public int doEndTag() throws JspException
{
addQueryParameters();
produceResult(generateURL());
this.baseURL = null;
this.query = null;
this.excludedQueryStringParameters = null;
this.fullBaseUrl = false;
this.includeLanguageId = true;
this.parameters = null;
this.parameterNames = null;
this.disableNiceURI = false;
this.allowMultipleArguments = false;
this.includeCurrentQueryString = true;
return EVAL_PAGE;
}
/**
* Returns the parameters to use when constructing the url.
*
* @return the parameters to use when constructing the url.
*/
private List getParameters()
{
if(parameters == null)
{
parameters = new ArrayList();
}
return parameters;
}
/**
* Returns the name of all parameters that has been added.
*
* @return the name of all parameters that has been added.
*/
private Map getParameterNames()
{
if(parameterNames == null)
{
parameterNames = new HashMap();
}
return parameterNames;
}
/**
*
*/
protected final void addParameter(final String name, final String value)
{
getParameters().add(name + "=" + value);
getParameterNames().put(name, name);
}
/**
* Returns the url attribute if present; otherwise the url is taken from the request.
*
* @return the url attribute if present; otherwise the url is taken from the request.
*/
private String getBaseURL()
{
String newBaseUrl = "";
try
{
logger.info("fullBaseUrl:" + fullBaseUrl);
if(this.fullBaseUrl)
{
int indexOfProtocol = getRequest().getRequestURL().indexOf("://");
int indexFirstSlash = getRequest().getRequestURL().indexOf("/", indexOfProtocol + 3);
String base = null;
if(indexFirstSlash > -1)
base = getRequest().getRequestURL().substring(0, indexFirstSlash);
else
base = getRequest().getRequestURL().substring(0);
String currentPageUrl = this.getController().getCurrentPageUrl(includeLanguageId);
if(currentPageUrl != null)
{
int cidIndex = currentPageUrl.indexOf("cid");
if(excludedQueryStringParameters != null && (excludedQueryStringParameters.indexOf("contentId") > -1 || excludedQueryStringParameters.indexOf("cid") > -1) && cidIndex > -1)
{
int lastIndexOf = currentPageUrl.lastIndexOf("/", cidIndex);
int nextIndexOf = currentPageUrl.indexOf("/", cidIndex);
currentPageUrl = currentPageUrl.substring(0, lastIndexOf);
if(nextIndexOf > -1)
currentPageUrl = currentPageUrl + currentPageUrl.substring(nextIndexOf);
}
currentPageUrl = currentPageUrl.split("\\?")[0];
newBaseUrl = (baseURL == null) ? base + currentPageUrl : baseURL;
}
else
{
logger.warn("How can this happen:" + this.getController().getOriginalFullURL());
newBaseUrl = (baseURL == null) ? base : baseURL;
}
}
else
{
String currentPageUrl = this.getController().getCurrentPageUrl(includeLanguageId);
if(currentPageUrl != null)
{
int cidIndex = currentPageUrl.indexOf("cid");
if(excludedQueryStringParameters != null && (excludedQueryStringParameters.indexOf("contentId") > -1 || excludedQueryStringParameters.indexOf("cid") > -1) && cidIndex > -1)
{
int lastIndexOf = currentPageUrl.lastIndexOf("/", cidIndex);
int nextIndexOf = currentPageUrl.indexOf("/", cidIndex);
currentPageUrl = currentPageUrl.substring(0, lastIndexOf);
if(nextIndexOf > -1)
currentPageUrl = currentPageUrl + currentPageUrl.substring(nextIndexOf);
}
currentPageUrl = currentPageUrl.split("\\?")[0];
newBaseUrl = (baseURL == null) ? currentPageUrl : baseURL;
}
else
{
logger.warn("How can this happen:" + this.getController().getOriginalFullURL());
newBaseUrl = (baseURL == null) ? getRequest().getRequestURL().toString() : baseURL;
}
}
}
catch(Exception e)
{
logger.warn("Error getting url:" + e.getMessage(), e);
newBaseUrl = (baseURL == null) ? getRequest().getRequestURL().toString() : baseURL;
}
logger.info("newBaseUrl:" + newBaseUrl);
if (forceHTTPProtocol || CmsPropertyHandler.getForceHTTPProtocol()) {
newBaseUrl = newBaseUrl.replaceFirst("https:", "http:");
}
return newBaseUrl;
}
/**
* Returns the query attribute if present; otherwise the query is taken from the request.
*
* @return the query attribute if present; otherwise the query is taken from the request.
*/
private String getQuery()
{
String q = null;
if(includeCurrentQueryString)
q = (query == null) ? getRequest().getQueryString() : query;
else
q = query;
if(q != null && (q.startsWith("?") || q.startsWith("&")))
{
return q.substring(1);
}
return q;
}
/**
* Returns the (http) request object.
*
* @return the (http) request object.
*/
private final HttpServletRequest getRequest()
{
return (HttpServletRequest) pageContext.getRequest();
}
/**
* Adds the parameter from the query string to the parameters to use
* when constructing the url. If a parameter present in the query already
* exists in the parameters, the query parameter will be skipped.
*
* @throws JspException if the format of the query string is illegal.
*/
private void addQueryParameters() throws JspException
{
if(getQuery() != null)
{
for(final StringTokenizer st = new StringTokenizer(getQuery(), "&"); st.hasMoreTokens(); )
{
final String token = st.nextToken();
final StringTokenizer parameter = new StringTokenizer(token, "=");
if(parameter.countTokens() == 0 || parameter.countTokens() > 2)
{
logger.warn("The url contained illegal parameters [" + token + "].");
break;
}
final String name = parameter.nextToken();
final String value = parameter.hasMoreTokens() ? parameter.nextToken() : "";
if(allowMultipleArguments || !getParameterNames().containsKey(name))
{
if(excludedQueryStringParameters == null || excludedQueryStringParameters.indexOf(name) == -1)
addParameter(name, value);
}
}
}
}
/**
* Generates the url string.
*
* @return the url.
*/
public String generateURL()
{
if(!getParameters().isEmpty())
{
StringBuffer sb = new StringBuffer();
for(Iterator i = getParameters().iterator(); i.hasNext(); )
{
String parameter = i.next().toString();
sb.append(parameter + (i.hasNext() ? "&" : ""));
}
if(getBaseURL().indexOf("?") > -1)
return getBaseURL() + (sb.toString().length() > 0 ? "&" + sb.toString() : "");
else
return getBaseURL() + (sb.toString().length() > 0 ? "?" + sb.toString() : "");
}
return getBaseURL();
}
/**
* Sets the base url attribute.
*
* @param baseURL the base url to use.
* @throws JspException if an error occurs while evaluating base url parameter.
*/
public void setBaseURL(final String baseURL) throws JspException
{
this.baseURL = evaluateString("url", "baseURL", baseURL);
}
/**
* Sets the query attribute.
*
* @param query the query to use.
* @throws JspException if an error occurs while evaluating query parameter.
*/
public void setQuery(final String query) throws JspException
{
this.query = evaluateString("url", "query", query);
}
public void setExcludedQueryStringParameters(String excludedQueryStringParameters) throws JspException
{
this.excludedQueryStringParameters = evaluateString("url", "excludedQueryStringParameters", excludedQueryStringParameters);
}
public void setFullBaseUrl(boolean fullBaseUrl)
{
this.fullBaseUrl = fullBaseUrl;
}
/**
* Sets wether to include languageId in the url .
*
* @param includeLanguageId.
* @throws JspException if an error occurs while evaluating base includeLanguageId parameter.
*/
public void setIncludeLanguageId(final String includeLanguageId) throws JspException
{
this.includeLanguageId = evaluateBoolean("url", "includeLanguageId", includeLanguageId);
}
public void setForceHTTPProtocol(final String forceHTTPProtocol) throws JspException
{
this.forceHTTPProtocol = evaluateBoolean("url", "forceHTTPProtocol", forceHTTPProtocol);
}
public void setDisableNiceURI(boolean disableNiceURI)
{
this.disableNiceURI = disableNiceURI;
}
public void setAllowMultipleArguments(boolean allowMultipleArguments)
{
this.allowMultipleArguments = allowMultipleArguments;
}
public void setIncludeCurrentQueryString(boolean includeCurrentQueryString)
{
this.includeCurrentQueryString = includeCurrentQueryString;
}
}