/*
* Copyright 2000-2001,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.apache.jetspeed.portal.portlets;
import org.apache.ecs.ConcreteElement;
import org.apache.ecs.StringElement;
import org.apache.jetspeed.portal.portlets.AbstractPortlet;
import org.apache.turbine.util.RunData;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
/**
* This portlet class is intended to be used for internal URLs that will
* not work properly if they are part of the same request as the Jetspeed/Turbine
* controller servlet--Struts-mapped URLs are an example of these.
* <br>
* ServletProxyPortlet uses an application context-relative URL as an input parameter. It uses data obtained from
* <code>org.apache.turbine.util.RunData</code> to construct an absolute URL and append the session id to it. Using this
* URL, it constructs a java.net.URL object, retrieves the content from it, and converts the content to a String. Finally,
* it returns an ECS StringElement created with this String for Jetspeed to render as a portlet. Content is returned as-is;
* no filtering is performed on the html before returning it.
* <br/><br/>
* This portlet accepts 3 parameters:<br/>
*
* URL (required) -- the web application-context relative URL (a query string may be used to pass parameters)<br/>
* session_token (optional) -- token key used by the web server to pass the session id on the query string<br/>
* protocol (optional) -- protocol to use to make the URL request
*
* @author <a href="mailto:joe.barefoot@motiva.com">Joe Barefoot</a>
*/
public class ServletProxyPortlet extends AbstractPortlet
{
private final static int BUFFER_SIZE = 2048;
/** The name of the parameter to hold our application context-relative URL */
public static final String URL_PARAMETER_NAME = "URL";
/** The name of the parameter to hold the protocol to use (optional, default is http) **/
public static final String PROTOCOL_PARAMETER_NAME = "protocol";
/** The name of the parameter to hold the token by which the session ID is passed on the query string (optional, default is jsessionid)
* This is included to accomodate all web servers, as the token is usually different from one server to another.
*/
public static final String SESSION_TOKEN_PARAMETER_NAME = "session_token";
/** The default protocol used to construct the URL -- http */
public static final String DEFAULT_PROTOCOL = "http";
/** The default token to use to pass the session ID on the query String -- jsessionid */
public static final String DEFAULT_SESSION_TOKEN = "jsessionid";
/** Gets content by proxy (java.net.URL) from an internal URL and returns it
*
* @param rundata The RunData object for the current request
* @return an ECS StringElement
*/
public ConcreteElement getContent(RunData rundata)
{
String servletURL = processURL(rundata);
if(servletURL == null)
{
return new StringElement("ServletInvokerPortlet: Must specify a URL using the URL parameter");
}
String content;
// This is probably not robust for large content returns, but should work okay within an application context with small amounts of content.
try
{
URL url = new URL(servletURL);
URLConnection connection = url.openConnection();
InputStream stream = connection.getInputStream();
BufferedInputStream in = new BufferedInputStream(stream);
int length = 0;
byte[] buf = new byte[BUFFER_SIZE];
ByteArrayOutputStream out = new ByteArrayOutputStream();
while ((in != null) && ((length = in.read(buf)) != -1))
{
// the data has already been read into buf
out.write(buf, 0, length);
}
content = out.toString();
return new StringElement(content);
}
catch (Exception e)
{
String message = "ServletInvokerPortlet: Error invoking " + servletURL + ": " + e.getMessage();
return new StringElement(message);
}
}
/** Constructs a full URL to retrieve content from. Override to append custom (default) query parameters, etc.
*
* @param rundata The RunData object for the current request
* @return An absolute URL with the session ID appended
*/
protected String processURL(RunData rundata)
{
String servletURL = getPortletConfig().getInitParameter(URL_PARAMETER_NAME);
if( servletURL == null) // short-circuit
{
return null;
}
String protocol = getPortletConfig().getInitParameter(PROTOCOL_PARAMETER_NAME);
if(protocol == null)
{
protocol = DEFAULT_PROTOCOL;
}
String token = getPortletConfig().getInitParameter(SESSION_TOKEN_PARAMETER_NAME);
if(token == null)
{
token = DEFAULT_SESSION_TOKEN;
}
String queryString = new String();
int queryIndex = servletURL.indexOf("?");
if(queryIndex > 0)
{
queryString = servletURL.substring(queryIndex);
servletURL = servletURL.substring(0, queryIndex);
}
servletURL = protocol + "://" + rundata.getServerName() + ":" + rundata.getServerPort() + rundata.getContextPath() + servletURL + ";" + token + "=" + rundata.getSession().getId() + queryString;
return servletURL;
}
}