FELIX-1988 Apply abstr-simple-web-console2.patch by Valentin Valchev (thanks)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@908927 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/AbstractWebConsolePlugin.java b/webconsole/src/main/java/org/apache/felix/webconsole/AbstractWebConsolePlugin.java
index 4bbb13d..0626667 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/AbstractWebConsolePlugin.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/AbstractWebConsolePlugin.java
@@ -27,24 +27,41 @@
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.commons.io.IOUtils;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
+/**
+ * The Web Console can be extended by registering an OSGi service for the interface
+ * {@link javax.servlet.Servlet} with the service property
+ * <code>felix.webconsole.label</code> set to the label (last segment in the URL)
+ * of the page. The respective service is called a Web Console Plugin or a plugin
+ * for short.
+ *
+ * To help rendering the response the Apache Felix Web Console bundle provides two
+ * options. One of the options is to extend the AbstractWebConsolePlugin overwriting
+ * the {@link #renderContent(HttpServletRequest, HttpServletResponse)} method.
+ */
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 */
+ /** The name of the request attribute containing the map of FileItems from the POST request */
public static final String ATTR_FILEUPLOAD = "org.apache.felix.webconsole.fileupload";
+ /**
+ * Web Console Plugin typically consists of servlet and resources such as images,
+ * scripts or style sheets.
+ *
+ * To load resources, a Resource Provider is used. The resource provider is an object,
+ * that provides a method which name is specified by this constants and it is
+ * 'getResource'.
+ *
+ * @see #getResourceProvider()
+ */
public static final String GET_RESOURCE_METHOD_NAME = "getResource";
/**
@@ -72,6 +89,8 @@
/**
* Returns the title for this plugin as returned by {@link #getTitle()}
+ *
+ * @see javax.servlet.GenericServlet#getServletName()
*/
public String getServletName()
{
@@ -93,6 +112,9 @@
* <b>Note</b>: If a resource is sent back for the request only the first
* step is executed. Otherwise the first step is a null-operation actually
* and the latter four steps are executed in order.
+ * @see javax.servlet.http.HttpServlet#doGet(
+ * javax.servlet.http.HttpServletRequest,
+ * javax.servlet.http.HttpServletResponse)
*/
protected void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException,
IOException
@@ -129,6 +151,9 @@
* footers of this plugin be rendered or not. This method always returns
* <code>true</true> but has been overwritten in the
* {@link WebConsolePluginAdapter} for the plugins.
+ *
+ * @param request the original request passed from the HTTP server
+ * @return <code>true</code> if the page should have headers and footers rendered
*/
protected boolean isHtmlRequest( final HttpServletRequest request )
{
@@ -138,27 +163,65 @@
//---------- AbstractWebConsolePlugin API ----------------------------------
+ /**
+ * This method is called from the Felix Web Console to ensure the
+ * AbstractWebConsolePlugin is correctly setup.
+ *
+ * It is called right after the Web Console receives notification for
+ * plugin registration.
+ *
+ * @param bundleContext the context of the plugin bundle
+ */
public void activate( BundleContext bundleContext )
{
this.bundleContext = bundleContext;
}
+ /**
+ * This method is called, by the Web Console to de-activate the plugin and release
+ * all used resources.
+ */
public void deactivate()
{
this.bundleContext = null;
}
- public abstract String getTitle();
-
-
- public abstract String getLabel();
-
-
+ /**
+ * This method is used to render the content of the plug-in. It is called internally
+ * from the Web Console.
+ *
+ * @param req the HTTP request send from the user
+ * @param res the HTTP response object, where to render the plugin data.
+ * @throws IOException if an input or output error is
+ * detected when the servlet handles the request
+ * @throws ServletException if the request for the GET
+ * could not be handled
+ */
protected abstract void renderContent( HttpServletRequest req, HttpServletResponse res ) throws ServletException,
IOException;
+ /**
+ * Retrieves the label. This is the last component in the servlet path.
+ *
+ * This method MUST be overridden, if the {@link #AbstractWebConsolePlugin()}
+ * constructor is used.
+ *
+ * @return the label.
+ */
+ public abstract String getLabel();
+
+ /**
+ * Retrieves the title of the plug-in. It is displayed in the page header
+ * and is also included in the title of the HTML document.
+ *
+ * This method MUST be overridden, if the {@link #AbstractWebConsolePlugin()}
+ * constructor is used.
+ *
+ * @return the plugin title.
+ */
+ public abstract String getTitle();
/**
* Returns a list of CSS reference paths or <code>null</code> if no
@@ -178,12 +241,13 @@
return null;
}
-
/**
* Returns the <code>BundleContext</code> with which this plugin has been
* activated. If the plugin has not be activated by calling the
* {@link #activate(BundleContext)} method, this method returns
* <code>null</code>.
+ *
+ * @return the bundle context or <code>null</code> if the bundle is not activated.
*/
protected BundleContext getBundleContext()
{
@@ -197,6 +261,8 @@
* been activated. If the plugin has not be activated by calling the
* {@link #activate(BundleContext)} method, this method returns
* <code>null</code>.
+ *
+ * @return the bundle or <code>null</code> if the plugin is not activated.
*/
public final Bundle getBundle()
{
@@ -204,7 +270,6 @@
return ( bundleContext != null ) ? bundleContext.getBundle() : null;
}
-
/**
* Returns the object which might provide resources. The class of this
* object is used to find the <code>getResource</code> method.
@@ -223,7 +288,7 @@
/**
* Returns a method which is called on the
- * {@link #getResourceProvider() resource provder} class to return an URL
+ * {@link #getResourceProvider() resource provider} class to return an URL
* to a resource which may be spooled when requested. The method has the
* following signature:
* <pre>
@@ -240,7 +305,7 @@
* if the {@link #getResourceProvider() resource provider} is
* <code>null</code> or does not provide such a method.
*/
- private Method getGetResourceMethod()
+ private final Method getGetResourceMethod()
{
// return what we know of the getResourceMethod, if we already checked
if (getResourceMethodChecked) {
@@ -309,9 +374,9 @@
* @param response The response object
* @return <code>true</code> if the request causes a resource to be sent back.
*
- * @throws IOException If an error occurrs accessing or spooling the resource.
+ * @throws IOException If an error occurs accessing or spooling the resource.
*/
- private boolean spoolResource( HttpServletRequest request, HttpServletResponse response ) throws IOException
+ private final boolean spoolResource( HttpServletRequest request, HttpServletResponse response ) throws IOException
{
// no resource if no resource accessor
Method getResourceMethod = getGetResourceMethod();
@@ -392,22 +457,22 @@
}
finally
{
- if ( ins != null )
- {
- try
- {
- ins.close();
- }
- catch ( IOException ignore )
- {
- }
- }
+ IOUtils.closeQuietly(ins);
}
return false;
}
+ /**
+ * This method is responsible for generating the top heading of the page.
+ *
+ * @param request the HTTP request coming from the user
+ * @param response the HTTP response, where data is rendered
+ * @return the writer that was used for generating the response.
+ * @throws IOException on I/O error
+ * @see #endResponse(PrintWriter)
+ */
protected PrintWriter startResponse( HttpServletRequest request, HttpServletResponse response ) throws IOException
{
response.setCharacterEncoding( "utf-8" );
@@ -428,6 +493,12 @@
}
+ /**
+ * This method is called to generate the top level links with the available plug-ins.
+ *
+ * @param request the HTTP request coming from the user
+ * @param pw the writer, where the HTML data is rendered
+ */
protected void renderTopNavigation( HttpServletRequest request, PrintWriter pw )
{
// assume pathInfo to not be null, else this would not be called
@@ -489,105 +560,57 @@
}
+ /**
+ * This method is responsible for generating the footer of the page.
+ *
+ * @param pw the writer, where the HTML data is rendered
+ * @see #startResponse(HttpServletRequest, HttpServletResponse)
+ */
protected void endResponse( PrintWriter pw )
{
pw.println(getFooter());
}
- public static String getParameter( HttpServletRequest request, String name )
+ /**
+ * An utility method, that is used to filter out simple parameter from file
+ * parameter when multipart transfer encoding is used.
+ *
+ * This method processes the request and sets a request attribute
+ * {@link #ATTR_FILEUPLOAD}. The attribute value is a {@link Map}
+ * where the key is a String specifying the field name and the value
+ * is a {@link org.apache.commons.fileupload.FileItem}.
+ *
+ * @param request the HTTP request coming from the user
+ * @param name the name of the parameter
+ * @return if not multipart transfer encoding is used - the value is the
+ * parameter value or <code>null</code> if not set. If multipart is used,
+ * and the specified parameter is field - then the value of the parameter
+ * is returned.
+ * @deprecated use {@link WebConsoleUtil#getParameter(HttpServletRequest, String)}
+ */
+ public static final 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;
+ return WebConsoleUtil.getParameter(request, name);
}
/**
* 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.
+ * Some application servers like Web Sphere handle relative redirects differently
+ * therefore we should make an absolute URL before invoking send redirect.
+ *
+ * @param request the HTTP request coming from the user
+ * @param response the HTTP response, where data is rendered
+ * @param redirectUrl the redirect URI.
+ * @throws IOException If an input or output exception occurs
+ * @throws IllegalStateException If the response was committed or if a partial
+ * URL is given and cannot be converted into a valid URL
+ * @deprecated use {@link WebConsoleUtil#sendRedirect(HttpServletRequest, HttpServletResponse, String)}
*/
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);
+ WebConsoleUtil.sendRedirect(request, response, redirectUrl);
}
/**
@@ -600,7 +623,7 @@
/**
* @param brandingPlugin the brandingPlugin to set
*/
- public static void setBrandingPlugin(BrandingPlugin brandingPlugin) {
+ public static final void setBrandingPlugin(BrandingPlugin brandingPlugin) {
if(brandingPlugin == null){
AbstractWebConsolePlugin.brandingPlugin = DefaultBrandingPlugin.getInstance();
} else {
@@ -609,7 +632,7 @@
}
- private String getHeader()
+ private final String getHeader()
{
// MessageFormat pattern place holder
// 0 main title (brand name)
@@ -663,7 +686,7 @@
}
- private String getFooter()
+ private final String getFooter()
{
// close <div id="main">, body and html
final String footer = " </div>"
@@ -673,7 +696,7 @@
}
- private String getCssLinks( final String appRoot )
+ private final String getCssLinks( final String appRoot )
{
// get the CSS references and return nothing if there are none
final String[] cssRefs = getCssReferences();
@@ -707,7 +730,7 @@
* the url.
* @throws NullPointerException if <code>url</code> is <code>null</code>.
*/
- private String toUrl( final String url, final String appRoot )
+ private static final String toUrl( final String url, final String appRoot )
{
if ( url.startsWith( "/" ) )
{
@@ -715,4 +738,5 @@
}
return url;
}
+
}
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/SimpleWebConsolePlugin.java b/webconsole/src/main/java/org/apache/felix/webconsole/SimpleWebConsolePlugin.java
new file mode 100644
index 0000000..f41ba98
--- /dev/null
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/SimpleWebConsolePlugin.java
@@ -0,0 +1,224 @@
+/*
+ * 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.net.URL;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.util.tracker.ServiceTracker;
+
+
+/**
+ * SimpleWebConsolePlugin is an utility class that provides default
+ * implementation of the {@link AbstractWebConsolePlugin} and supports the
+ * following features:
+ * <ul>
+ * <li>Methods for (un)registering the web console plugin service</li>
+ * <li>Default implementation for resource loading</li>
+ * </ul>
+ */
+public abstract class SimpleWebConsolePlugin extends AbstractWebConsolePlugin
+{
+
+ // Serializable UID
+ private static final long serialVersionUID = 1500463493078823878L;
+
+ // used for standard AbstractWebConsolePlugin implementation
+ private final String label;
+ private final String title;
+ private final String css[];
+ private final String labelRes;
+ private final int labelResLen;
+
+ // used for service registration
+ private final Object regLock = new Object();
+ private ServiceRegistration reg;
+
+ // used to obtain services. Structure is: service name -> ServiceTracker
+ private final Map services = new HashMap();
+
+
+ /**
+ * Creates new Simple Web Console Plugin.
+ *
+ * @param label the front label. See
+ * {@link AbstractWebConsolePlugin#getLabel()}
+ * @param title the plugin title . See
+ * {@link AbstractWebConsolePlugin#getTitle()}
+ * @param css the additional plugin CSS. See
+ * {@link AbstractWebConsolePlugin#getCssReferences()}
+ */
+ public SimpleWebConsolePlugin( String label, String title, String css[] )
+ {
+ if ( label == null )
+ {
+ throw new NullPointerException( "Null label" );
+ }
+ if ( title == null )
+ {
+ throw new NullPointerException( "Null title" );
+ }
+ this.label = label;
+ this.title = title;
+ this.css = css;
+ this.labelRes = '/' + label + '/';
+ this.labelResLen = labelRes.length() - 1;
+ }
+
+
+ /**
+ * @see org.apache.felix.webconsole.AbstractWebConsolePlugin#getLabel()
+ */
+ public final String getLabel()
+ {
+ return label;
+ }
+
+
+ /**
+ * @see org.apache.felix.webconsole.AbstractWebConsolePlugin#getTitle()
+ */
+ public final String getTitle()
+ {
+ return title;
+ }
+
+
+ /**
+ * @see org.apache.felix.webconsole.AbstractWebConsolePlugin#getCssReferences()
+ */
+ protected final String[] getCssReferences()
+ {
+ return css;
+ }
+
+
+ /**
+ * Called internally by {@link AbstractWebConsolePlugin} to load resources.
+ *
+ * This particular implementation depends on the label. As example, if the
+ * plugin is accessed as <code>/system/console/abc</code>, and the plugin
+ * resources are accessed like <code>/system/console/abc/res/logo.gif</code>,
+ * the code here will try load resource <code>/res/logo.gif</code> from the
+ * bundle, providing the plugin.
+ *
+ *
+ * @param path the path to read.
+ * @return the URL of the resource or <code>null</code> if not found.
+ */
+ protected URL getResource( String path )
+ {
+ return ( path != null && path.startsWith( labelRes ) ) ? //
+ getClass().getResource( path.substring( labelResLen ) )
+ : null;
+ }
+
+
+ // -- begin methods for plugin registration/unregistration
+ /**
+ * This is an utility method. It is used to register the plugin service. Don't
+ * forget to call the {@link #unregister()} when the plugin is no longer
+ * needed.
+ *
+ * @param bc the bundle context used for service registration.
+ * @return self
+ */
+ public final SimpleWebConsolePlugin register( BundleContext bc )
+ {
+ synchronized ( regLock )
+ {
+ activate( bc ); // don't know why this is needed!
+
+ Hashtable props = new Hashtable();
+ props.put( WebConsoleConstants.PLUGIN_LABEL, label );
+ props.put( WebConsoleConstants.PLUGIN_TITLE, title );
+ reg = bc.registerService( "javax.servlet.Servlet", this, props ); //$NON-NLS-1$
+ }
+ return this;
+ }
+
+
+ /**
+ * An utility method that removes the service, registered by the
+ * {@link #register(BundleContext)} method.
+ */
+ public final void unregister()
+ {
+ synchronized ( regLock )
+ {
+ deactivate(); // is this needed?
+
+ if ( reg != null )
+ reg.unregister();
+ reg = null;
+ }
+ }
+
+
+ // -- end methods for plugin registration/unregistration
+
+ // -- begin methods for obtaining services
+
+ /**
+ * Gets the service with the specified class name. Will create a new
+ * {@link ServiceTracker} if the service is not already got.
+ *
+ * @param serviceName the service name to obtain
+ * @return the service or <code>null</code> if missing.
+ */
+ protected final Object getService( String serviceName )
+ {
+ ServiceTracker serviceTracker = ( ServiceTracker ) services.get( serviceName );
+ if ( serviceTracker == null )
+ {
+ serviceTracker = new ServiceTracker( getBundleContext(), serviceName, null );
+ serviceTracker.open();
+
+ services.put( serviceName, serviceTracker );
+ }
+
+ return serviceTracker.getService();
+ }
+
+
+ /**
+ * This method will close all service trackers, created by
+ * {@link #getService(String)} method. If you override this method, don't
+ * forget to call the super.
+ *
+ * @see org.apache.felix.webconsole.AbstractWebConsolePlugin#deactivate()
+ */
+ public void deactivate()
+ {
+ for ( Iterator ti = services.values().iterator(); ti.hasNext(); )
+ {
+ ServiceTracker tracker = ( ServiceTracker ) ti.next();
+ tracker.close();
+ ti.remove();
+ }
+ super.deactivate();
+ }
+
+}
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/WebConsoleConstants.java b/webconsole/src/main/java/org/apache/felix/webconsole/WebConsoleConstants.java
index d634727..a0950b8 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/WebConsoleConstants.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/WebConsoleConstants.java
@@ -18,7 +18,10 @@
*/
package org.apache.felix.webconsole;
-
+/**
+ * WebConsoleConstants provides some common constants that are used by plugin
+ * developers.
+ */
public interface WebConsoleConstants
{
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/WebConsoleUtil.java b/webconsole/src/main/java/org/apache/felix/webconsole/WebConsoleUtil.java
index 5eaf7e3..fafd9d2 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/WebConsoleUtil.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/WebConsoleUtil.java
@@ -19,7 +19,24 @@
package org.apache.felix.webconsole;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.fileupload.FileItem;
+import org.apache.commons.fileupload.FileUploadBase;
+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.json.JSONException;
+import org.json.JSONWriter;
/**
@@ -29,11 +46,16 @@
public final class WebConsoleUtil
{
+ private WebConsoleUtil()
+ {
+ /* no instantiation */
+ }
+
/**
* Returns the {@link VariableResolver} for the given request.
* <p>
* If not resolver
- * has yet be created for the requets, an instance of the
+ * has yet be created for the requests, an instance of the
* {@link DefaultVariableResolver} is created, placed into the request and
* returned.
* <p>
@@ -75,4 +97,216 @@
request.setAttribute( WebConsoleConstants.ATTR_CONSOLE_VARIABLE_RESOLVER, resolver );
}
+
+ /**
+ * An utility method, that is used to filter out simple parameter from file
+ * parameter when multipart transfer encoding is used.
+ *
+ * This method processes the request and sets a request attribute
+ * {@link AbstractWebConsolePlugin#ATTR_FILEUPLOAD}. The attribute value is a {@link Map}
+ * where the key is a String specifying the field name and the value
+ * is a {@link org.apache.commons.fileupload.FileItem}.
+ *
+ * @param request the HTTP request coming from the user
+ * @param name the name of the parameter
+ * @return if not multipart transfer encoding is used - the value is the
+ * parameter value or <code>null</code> if not set. If multipart is used,
+ * and the specified parameter is field - then the value of the parameter
+ * is returned.
+ */
+ public static final String getParameter( HttpServletRequest request, String name )
+ {
+ // just get the parameter if not a multipart/form-data POST
+ if ( !FileUploadBase.isMultipartContent( new ServletRequestContext( request ) ) )
+ {
+ return request.getParameter( name );
+ }
+
+ // check, whether we already have the parameters
+ Map params = ( Map ) request.getAttribute( AbstractWebConsolePlugin.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( AbstractWebConsolePlugin.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 application servers like Web Sphere handle relative redirects differently
+ * therefore we should make an absolute URL before invoking send redirect.
+ *
+ * @param request the HTTP request coming from the user
+ * @param response the HTTP response, where data is rendered
+ * @param redirectUrl the redirect URI.
+ * @throws IOException If an input or output exception occurs
+ * @throws IllegalStateException If the response was committed or if a partial
+ * URL is given and cannot be converted into a valid URL
+ */
+ public static final 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);
+ }
+
+ /**
+ * Escapes HTML special chars like: <>&\r\n and space
+ *
+ *
+ * @param text the text to escape
+ * @return the escaped text
+ */
+ public static final String escapeHtml(String text)
+ {
+ StringBuffer sb = new StringBuffer(text.length() * 4 / 3);
+ synchronized (sb) // faster buffer operations
+ {
+ char ch, oldch = '_';
+ for (int i = 0; i < text.length(); i++)
+ {
+ switch (ch = text.charAt(i))
+ {
+ case '<':
+ sb.append("<"); //$NON-NLS-1$
+ break;
+ case '>':
+ sb.append(">"); //$NON-NLS-1$
+ break;
+ case '&':
+ sb.append("&"); //$NON-NLS-1$
+ break;
+ case ' ':
+ sb.append(" "); //$NON-NLS-1$
+ break;
+ case '\r':
+ case '\n':
+ if (oldch != '\r' && oldch != '\n') // don't add twice <br>
+ sb.append("<br/>\n"); //$NON-NLS-1$
+ break;
+ default:
+ sb.append(ch);
+ }
+ oldch = ch;
+ }
+
+ return sb.toString();
+ }
+ }
+
+ /**
+ * Retrieves a request parameter and converts it to int.
+ *
+ * @param request the HTTP request
+ * @param name the name of the request parameter
+ * @param _default the default value returned if the parameter is not set or is not a valid integer.
+ * @return the request parameter if set and is valid integer, or the default value
+ */
+ public static final int getParameterInt(HttpServletRequest request, String name,
+ int _default)
+ {
+ int ret = _default;
+ String param = request.getParameter(name);
+ try
+ {
+ if (param != null)
+ ret = Integer.parseInt(param);
+ }
+ catch (NumberFormatException nfe)
+ {
+ // don't care, will return default
+ }
+
+ return ret;
+ }
+
+ /**
+ * Writes a key-value pair in a JSON writer. Write is performed only if both key and
+ * value are not null.
+ *
+ * @param jw the writer, where to write the data
+ * @param key the key value, stored under 'key'
+ * @param value the value stored under 'value'
+ * @throws JSONException if the value cannot be serialized.
+ */
+ public static final void keyVal(JSONWriter jw, String key, Object value)
+ throws JSONException
+ {
+ if (key != null && value != null)
+ {
+ jw.object();
+ jw.key("key"); //$NON-NLS-1$
+ jw.value(key);
+ jw.key("value"); //$NON-NLS-1$
+ jw.value(value);
+ jw.endObject();
+ }
+ }
+
}