blob: edc185805dea4e459a944b9d7406e532108ebcbc [file] [log] [blame]
/*
* 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.
*/
package org.apache.felix.webconsole;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.MessageFormat;
import java.util.*;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.servlet.ServletRequestContext;
import org.apache.felix.webconsole.internal.servlet.OsgiManager;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
public abstract class AbstractWebConsolePlugin extends HttpServlet
{
/** Pseudo class version ID to keep the IDE quite. */
private static final long serialVersionUID = 1L;
/** The name of the request attribute containig the map of FileItems from the POST request */
public static final String ATTR_FILEUPLOAD = "org.apache.felix.webconsole.fileupload";
private static final String HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"
+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"xhtml1-transitional.dtd\">"
+ "<html xmlns=\"http://www.w3.org/1999/xhtml\">"
+ "<head>"
+ "<meta http-equiv=\"Content-Type\" content=\"text/html; utf-8\">"
+ "<link rel=\"icon\" href=\"{6}/res/imgs/favicon.ico\">"
+ "<title>{0} - {2}</title>"
+ "<script src=\"{5}/res/ui/jquery-1.3.2.min.js\" language=\"JavaScript\"></script>"
+ "<script src=\"{5}/res/ui/jquery.tablesorter-2.0.3.min.js\" language=\"JavaScript\"></script>"
+ "<script src=\"{5}/res/ui/admin.js\" language=\"JavaScript\"></script>"
+ "<script src=\"{5}/res/ui/ui.js\" language=\"JavaScript\"></script>"
+ "<script language=\"JavaScript\">"
+ "appRoot = \"{5}\";"
+ "pluginRoot = appRoot + \"/{6}\";"
+ "</script>"
+ "<link href=\"{5}/res/ui/admin.css\" rel=\"stylesheet\" type=\"text/css\">"
+ "</head>"
+ "<body>"
+ "<div id=\"main\">"
+ "<div id=\"lead\">"
+ "<h1>"
+ "{0}<br>{2}"
+ "</h1>"
+ "<p>"
+ "<a target=\"_blank\" href=\"{3}\" title=\"{1}\"><img src=\"{5}/res/imgs/logo.png\" width=\"165\" height=\"63\" border=\"0\"></a>"
+ "</p>" + "</div>";
/**
String header = MessageFormat.format( HEADER, new Object[]
{ adminTitle, productName, getTitle(), productWeb, vendorName,
( String ) request.getAttribute( OsgiManager.ATTR_APP_ROOT ), getLabel() } );
*/
private BundleContext bundleContext;
private String adminTitle;
private String productName;
private String productWeb;
private String vendorName;
//---------- HttpServlet Overwrites ----------------------------------------
/**
* Returns the title for this plugin as returned by {@link #getTitle()}
*/
public String getServletName()
{
return getTitle();
}
/**
* Renders the web console page for the request. This consist of the following
* four parts called in order:
* <ol>
* <li>{@link #startResponse(HttpServletRequest, HttpServletResponse)}</li>
* <li>{@link #renderTopNavigation(HttpServletRequest, PrintWriter)}</li>
* <li>{@link #renderContent(HttpServletRequest, HttpServletResponse)}</li>
* <li>{@link #endResponse(PrintWriter)}</li>
* </ol>
*/
protected void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException,
IOException
{
PrintWriter pw = startResponse( request, response );
renderTopNavigation( request, pw );
renderContent( request, response );
endResponse( pw );
}
//---------- AbstractWebConsolePlugin API ----------------------------------
public void activate( BundleContext bundleContext )
{
this.bundleContext = bundleContext;
Dictionary headers = bundleContext.getBundle().getHeaders();
adminTitle = ( String ) headers.get( Constants.BUNDLE_NAME ); // "OSGi Management Console";
productName = "Apache Felix";
productWeb = ( String ) headers.get( Constants.BUNDLE_DOCURL );
vendorName = ( String ) headers.get( Constants.BUNDLE_VENDOR );
}
public void deactivate()
{
this.bundleContext = null;
}
public abstract String getTitle();
public abstract String getLabel();
protected abstract void renderContent( HttpServletRequest req, HttpServletResponse res ) throws ServletException,
IOException;
protected BundleContext getBundleContext()
{
return bundleContext;
}
protected PrintWriter startResponse( HttpServletRequest request, HttpServletResponse response ) throws IOException
{
response.setCharacterEncoding( "utf-8" );
response.setContentType( "text/html" );
PrintWriter pw = response.getWriter();
String header = MessageFormat.format( HEADER, new Object[]
{ adminTitle, productName, getTitle(), productWeb, vendorName,
( String ) request.getAttribute( OsgiManager.ATTR_APP_ROOT ), getLabel() } );
pw.println( header );
return pw;
}
protected void renderTopNavigation( HttpServletRequest request, PrintWriter pw )
{
// assume pathInfo to not be null, else this would not be called
boolean linkToCurrent = true;
String current = request.getPathInfo();
int slash = current.indexOf( "/", 1 );
if ( slash < 0 )
{
slash = current.length();
linkToCurrent = false;
}
current = current.substring( 1, slash );
boolean disabled = false;
String appRoot = ( String ) request.getAttribute( OsgiManager.ATTR_APP_ROOT );
Map labelMap = ( Map ) request.getAttribute( OsgiManager.ATTR_LABEL_MAP );
if ( labelMap != null )
{
pw.println( "<div id='technav'>" );
SortedMap map = new TreeMap();
for ( Iterator ri = labelMap.entrySet().iterator(); ri.hasNext(); )
{
Map.Entry labelMapEntry = ( Map.Entry ) ri.next();
if ( labelMapEntry.getKey() == null )
{
// ignore renders without a label
}
else if ( disabled || current.equals( labelMapEntry.getKey() ) )
{
if ( linkToCurrent )
{
map.put( labelMapEntry.getValue(), "<a class='technavat' href='" + appRoot + "/"
+ labelMapEntry.getKey() + "'>" + labelMapEntry.getValue() + "</a>" );
}
else
{
map.put( labelMapEntry.getValue(), "<span class='technavat'>" + labelMapEntry.getValue()
+ "</span>" );
}
}
else
{
map.put( labelMapEntry.getValue(), "<a href='" + appRoot + "/" + labelMapEntry.getKey() + "'>"
+ labelMapEntry.getValue() + "</a>" );
}
}
for ( Iterator li = map.values().iterator(); li.hasNext(); )
{
pw.print( "<nobr>" );
pw.print( li.next() );
pw.println( "</nobr>" );
}
pw.println( "</div>" );
}
}
protected void endResponse( PrintWriter pw )
{
pw.println( "</body>" );
pw.println( "</html>" );
}
public static String getParameter( HttpServletRequest request, String name )
{
// just get the parameter if not a multipart/form-data POST
if ( !ServletFileUpload.isMultipartContent( new ServletRequestContext( request ) ) )
{
return request.getParameter( name );
}
// check, whether we alread have the parameters
Map params = ( Map ) request.getAttribute( ATTR_FILEUPLOAD );
if ( params == null )
{
// parameters not read yet, read now
// Create a factory for disk-based file items
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold( 256000 );
// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload( factory );
upload.setSizeMax( -1 );
// Parse the request
params = new HashMap();
try
{
List items = upload.parseRequest( request );
for ( Iterator fiter = items.iterator(); fiter.hasNext(); )
{
FileItem fi = ( FileItem ) fiter.next();
FileItem[] current = ( FileItem[] ) params.get( fi.getFieldName() );
if ( current == null )
{
current = new FileItem[]
{ fi };
}
else
{
FileItem[] newCurrent = new FileItem[current.length + 1];
System.arraycopy( current, 0, newCurrent, 0, current.length );
newCurrent[current.length] = fi;
current = newCurrent;
}
params.put( fi.getFieldName(), current );
}
}
catch ( FileUploadException fue )
{
// TODO: log
}
request.setAttribute( ATTR_FILEUPLOAD, params );
}
FileItem[] param = ( FileItem[] ) params.get( name );
if ( param != null )
{
for ( int i = 0; i < param.length; i++ )
{
if ( param[i].isFormField() )
{
return param[i].getString();
}
}
}
// no valid string parameter, fail
return null;
}
/**
* Utility method to handle relative redirects.
* Some app servers like web sphere handle relative redirects differently
* therefore we should make an absolute url before invoking send redirect.
*/
protected void sendRedirect(final HttpServletRequest request,
final HttpServletResponse response,
String redirectUrl) throws IOException {
// check for relative url
if ( !redirectUrl.startsWith("/") ) {
String base = request.getContextPath() + request.getServletPath() + request.getPathInfo();
int i = base.lastIndexOf('/');
if (i > -1) {
base = base.substring(0, i);
} else {
i = base.indexOf(':');
base = (i > -1) ? base.substring(i + 1, base.length()) : "";
}
if (!base.startsWith("/")) {
base = '/' + base;
}
redirectUrl = base + '/' + redirectUrl;
}
response.sendRedirect(redirectUrl);
}
}