This is an automated email from the ASF dual-hosted git repository.
cziegeler pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/felix-dev.git
The following commit(s) were added to refs/heads/master by this push:
new 77c5f4041f FELIX-6623 : Use Http Whiteboard for Web Console
registration
77c5f4041f is described below
commit 77c5f4041f0ac7a9e0f2572b38ebef943c0e9917
Author: Carsten Ziegeler <[email protected]>
AuthorDate: Mon Aug 14 11:10:08 2023 +0200
FELIX-6623 : Use Http Whiteboard for Web Console registration
---
webconsole/pom.xml | 38 +-
.../felix/webconsole/AbstractWebConsolePlugin.java | 17 +-
.../felix/webconsole/DefaultVariableResolver.java | 1 +
.../felix/webconsole/SimpleWebConsolePlugin.java | 52 +-
.../webconsole/WebConsoleSecurityProvider3.java | 4 +-
.../webconsole/internal/OsgiManagerActivator.java | 6 +-
.../internal/configuration/ConfigurationUtil.java | 33 +-
.../servlet/BasicWebConsoleSecurityProvider.java | 6 +-
.../servlet/ConfigurationMetatypeSupport.java | 13 +-
.../internal/servlet/ConfigurationUtil.java | 6 +-
.../webconsole/internal/servlet/OsgiManager.java | 554 ++++++++-------------
.../internal/servlet/OsgiManagerHttpContext.java | 80 ++-
.../felix/webconsole/internal/servlet/Plugin.java | 6 +-
.../webconsole/internal/servlet/PluginHolder.java | 8 +-
.../configuration/ConfigJsonSupportTest.java | 2 -
.../servlet/OsgiManagerHttpContextTest.java | 10 +-
.../internal/servlet/OsgiManagerTest.java | 215 +++-----
17 files changed, 433 insertions(+), 618 deletions(-)
diff --git a/webconsole/pom.xml b/webconsole/pom.xml
index 5e17cedb52..7fd4e313b8 100644
--- a/webconsole/pom.xml
+++ b/webconsole/pom.xml
@@ -94,7 +94,7 @@
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
- <version>5.1.1</version>
+ <version>5.1.9</version>
<extensions>true</extensions>
<configuration>
<instructions>
@@ -372,13 +372,43 @@
<dependency>
<groupId>org.osgi</groupId>
<artifactId>osgi.core</artifactId>
- <version>6.0.0</version>
+ <version>8.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
- <artifactId>osgi.cmpn</artifactId>
- <version>6.0.0</version>
+ <artifactId>org.osgi.service.http.whiteboard</artifactId>
+ <version>1.1.1</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.service.cm</artifactId>
+ <version>1.6.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.service.metatype</artifactId>
+ <version>1.4.1</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.service.prefs</artifactId>
+ <version>1.1.2</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.service.log</artifactId>
+ <version>1.3.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.service.wireadmin</artifactId>
+ <version>1.0.2</version>
<scope>provided</scope>
</dependency>
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 5b15f9a487..434ea6031b 100644
---
a/webconsole/src/main/java/org/apache/felix/webconsole/AbstractWebConsolePlugin.java
+++
b/webconsole/src/main/java/org/apache/felix/webconsole/AbstractWebConsolePlugin.java
@@ -47,7 +47,7 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.felix.webconsole.internal.servlet.OsgiManager;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
-import org.osgi.service.log.LogService;
+import org.osgi.service.log.LogLevel;
/**
@@ -389,7 +389,7 @@ public abstract class AbstractWebConsolePlugin extends
HttpServlet
{
try
{
- Class cl = resourceProvider.getClass();
+ Class<?> cl = resourceProvider.getClass();
while ( tmpGetResourceMethod == null && cl != Object.class )
{
Method[] methods = cl.getDeclaredMethods();
@@ -633,6 +633,7 @@ public abstract class AbstractWebConsolePlugin extends
HttpServlet
* @throws IOException on I/O error
* @see #endResponse(PrintWriter)
*/
+ @SuppressWarnings({ "unchecked" })
protected PrintWriter startResponse( HttpServletRequest request,
HttpServletResponse response ) throws IOException
{
response.setCharacterEncoding( "utf-8" ); //$NON-NLS-1$
@@ -674,6 +675,7 @@ public abstract class AbstractWebConsolePlugin extends
HttpServlet
* @param request the HTTP request coming from the user
* @param pw the writer, where the HTML data is rendered
*/
+ @SuppressWarnings({ "rawtypes" })
protected void renderTopNavigation( HttpServletRequest request,
PrintWriter pw )
{
// assume pathInfo to not be null, else this would not be called
@@ -730,6 +732,7 @@ public abstract class AbstractWebConsolePlugin extends
HttpServlet
}
+ @SuppressWarnings({ "rawtypes" })
protected void renderMenu( Map menuMap, String appRoot, PrintWriter pw )
{
if ( menuMap != null )
@@ -745,6 +748,7 @@ public abstract class AbstractWebConsolePlugin extends
HttpServlet
}
+ @SuppressWarnings({ "rawtypes" })
private void renderMenu( Map menuMap, String appRoot, PrintWriter pw, int
level )
{
pw.println( "<ul class=\"navMenuLevel-" + level + "\">" );
@@ -753,6 +757,7 @@ public abstract class AbstractWebConsolePlugin extends
HttpServlet
}
+ @SuppressWarnings({ "rawtypes" })
private void renderSubmenu( Map menuMap, String appRoot, PrintWriter pw,
int level )
{
String liStyleClass = " class=\"navMenuItem-" + level + "\"";
@@ -935,7 +940,7 @@ public abstract class AbstractWebConsolePlugin extends
HttpServlet
return readTemplateFile( getClass(), templateFile );
}
- private final String readTemplateFile( final Class clazz, final String
templateFile) {
+ private final String readTemplateFile( final Class<?> clazz, final String
templateFile) {
try(InputStream templateStream = clazz.getResourceAsStream(
templateFile )) {
if ( templateStream != null ) {
@@ -964,7 +969,7 @@ public abstract class AbstractWebConsolePlugin extends
HttpServlet
}
// template file does not exist, return an empty string
- log( LogService.LOG_ERROR, "readTemplateFile: File '" + templateFile +
"' not found through class " + clazz ); //$NON-NLS-1$ //$NON-NLS-2$
+ log( LogLevel.ERROR.ordinal(), "readTemplateFile: File '" +
templateFile + "' not found through class " + clazz ); //$NON-NLS-1$
//$NON-NLS-2$
return ""; //$NON-NLS-1$
}
@@ -1013,6 +1018,7 @@ public abstract class AbstractWebConsolePlugin extends
HttpServlet
}
+ @SuppressWarnings({ "unchecked", "rawtypes" })
private SortedMap sortMenuCategoryMap( Map map, String appRoot )
{
SortedMap sortedMap = new TreeMap<>( String.CASE_INSENSITIVE_ORDER );
@@ -1054,18 +1060,17 @@ public abstract class AbstractWebConsolePlugin extends
HttpServlet
return sortedMap;
}
+ @SuppressWarnings({ "rawtypes" })
private static class MenuItem
{
private String link;
private Map subMenu;
-
public MenuItem( String link )
{
this.link = link;
}
-
public MenuItem( String link, Map subMenu )
{
super();
diff --git
a/webconsole/src/main/java/org/apache/felix/webconsole/DefaultVariableResolver.java
b/webconsole/src/main/java/org/apache/felix/webconsole/DefaultVariableResolver.java
index dfdb7fab7b..c0bafb52d8 100644
---
a/webconsole/src/main/java/org/apache/felix/webconsole/DefaultVariableResolver.java
+++
b/webconsole/src/main/java/org/apache/felix/webconsole/DefaultVariableResolver.java
@@ -31,6 +31,7 @@ import java.util.Map;
* {@link WebConsoleUtil#getVariableResolver(javax.servlet.ServletRequest)}
* as the variable resolver if none has yet been assigned to the request.
*/
+@SuppressWarnings({ "rawtypes" })
public class DefaultVariableResolver extends HashMap implements
VariableResolver
{
diff --git
a/webconsole/src/main/java/org/apache/felix/webconsole/SimpleWebConsolePlugin.java
b/webconsole/src/main/java/org/apache/felix/webconsole/SimpleWebConsolePlugin.java
index 3c69d3d5bb..133928b203 100644
---
a/webconsole/src/main/java/org/apache/felix/webconsole/SimpleWebConsolePlugin.java
+++
b/webconsole/src/main/java/org/apache/felix/webconsole/SimpleWebConsolePlugin.java
@@ -20,6 +20,7 @@ package org.apache.felix.webconsole;
import java.net.URL;
+import java.util.Dictionary;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
@@ -27,6 +28,8 @@ import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
+import javax.servlet.Servlet;
+
import org.apache.felix.webconsole.i18n.LocalizationHelper;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
@@ -61,10 +64,10 @@ public abstract class SimpleWebConsolePlugin extends
AbstractWebConsolePlugin
// used for service registration
private final Object regLock = new Object();
- private ServiceRegistration reg;
+ private ServiceRegistration<Servlet> reg;
// used to obtain services. Structure is: service name -> ServiceTracker
- private final Map services = new HashMap();
+ private final Map<String, ServiceTracker<?, ?>> services = new HashMap<>();
// localized title as servlet name
private String servletName;
@@ -218,20 +221,17 @@ public abstract class SimpleWebConsolePlugin extends
AbstractWebConsolePlugin
* @param bc the bundle context used for service registration.
* @return self
*/
- public final SimpleWebConsolePlugin register( BundleContext bc )
- {
- synchronized ( regLock )
- {
+ public final SimpleWebConsolePlugin register( BundleContext bc ) {
+ synchronized ( regLock ) {
activate( bc ); // don't know why this is needed!
- Hashtable props = new Hashtable();
+ final Dictionary<String, Object> props = new Hashtable<>();
props.put( WebConsoleConstants.PLUGIN_LABEL, getLabel() );
props.put( WebConsoleConstants.PLUGIN_TITLE, getTitle() );
- if ( getCategory() != null )
- {
+ if ( getCategory() != null ) {
props.put( WebConsoleConstants.PLUGIN_CATEGORY, getCategory()
);
}
- reg = bc.registerService( "javax.servlet.Servlet", this, props );
//$NON-NLS-1$
+ reg = bc.registerService( Servlet.class, this, props );
//$NON-NLS-1$
}
return this;
}
@@ -241,14 +241,17 @@ public abstract class SimpleWebConsolePlugin extends
AbstractWebConsolePlugin
* An utility method that removes the service, registered by the
* {@link #register(BundleContext)} method.
*/
- public final void unregister()
- {
- synchronized ( regLock )
- {
+ public final void unregister() {
+ synchronized ( regLock ) {
deactivate(); // is this needed?
- if ( reg != null )
- reg.unregister();
+ if ( reg != null ) {
+ try {
+ reg.unregister();
+ } catch ( final IllegalStateException ise ) {
+ // ignore, bundle context already invalid
+ }
+ }
reg = null;
}
}
@@ -265,11 +268,9 @@ public abstract class SimpleWebConsolePlugin extends
AbstractWebConsolePlugin
* @param serviceName the service name to obtain
* @return the service or <code>null</code> if missing.
*/
- public final Object getService( String serviceName )
- {
- ServiceTracker serviceTracker = ( ServiceTracker ) services.get(
serviceName );
- if ( serviceTracker == null )
- {
+ public final Object getService( String serviceName ) {
+ ServiceTracker<?,?> serviceTracker = services.get( serviceName );
+ if ( serviceTracker == null ) {
serviceTracker = new ServiceTracker( getBundleContext(),
serviceName, new ServiceTrackerCustomizer() {
public Object addingService( ServiceReference reference ) {
return getBundleContext().getService( reference );
@@ -303,15 +304,12 @@ public abstract class SimpleWebConsolePlugin extends
AbstractWebConsolePlugin
*
* @see org.apache.felix.webconsole.AbstractWebConsolePlugin#deactivate()
*/
- public void deactivate()
- {
- for ( Iterator ti = services.values().iterator(); ti.hasNext(); )
- {
- ServiceTracker tracker = ( ServiceTracker ) ti.next();
+ public void deactivate() {
+ for ( Iterator<ServiceTracker<?, ?>> ti =
services.values().iterator(); ti.hasNext(); ) {
+ ServiceTracker<?, ?> tracker = ti.next();
tracker.close();
ti.remove();
}
super.deactivate();
}
-
}
diff --git
a/webconsole/src/main/java/org/apache/felix/webconsole/WebConsoleSecurityProvider3.java
b/webconsole/src/main/java/org/apache/felix/webconsole/WebConsoleSecurityProvider3.java
index a0c470ee84..0b96f5b9d5 100644
---
a/webconsole/src/main/java/org/apache/felix/webconsole/WebConsoleSecurityProvider3.java
+++
b/webconsole/src/main/java/org/apache/felix/webconsole/WebConsoleSecurityProvider3.java
@@ -21,7 +21,7 @@ package org.apache.felix.webconsole;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.osgi.service.http.HttpContext;
+import org.osgi.service.http.context.ServletContextHelper;
/**
* The <code>WebConsoleSecurityProvider3</code> extends the
@@ -34,7 +34,7 @@ import org.osgi.service.http.HttpContext;
* If this service is missing and basic authentication is used, then new
authentication is requested.
*
* In any case, the logout procedure will invalidate the current session and
will remove the
- * {@link HttpContext#REMOTE_USER}, {@link HttpContext#AUTHORIZATION}
attributes from the request and the session.
+ * {@link ServletContextHelper#REMOTE_USER}, {@link
ServletContextHelper#AUTHORIZATION} attributes from the request and the session.
*
* @since 4.2.8; Web Console Bundle 4.2.8
*/
diff --git
a/webconsole/src/main/java/org/apache/felix/webconsole/internal/OsgiManagerActivator.java
b/webconsole/src/main/java/org/apache/felix/webconsole/internal/OsgiManagerActivator.java
index 9a564c0d2b..a9000ee419 100644
---
a/webconsole/src/main/java/org/apache/felix/webconsole/internal/OsgiManagerActivator.java
+++
b/webconsole/src/main/java/org/apache/felix/webconsole/internal/OsgiManagerActivator.java
@@ -22,12 +22,14 @@ package org.apache.felix.webconsole.internal;
import org.apache.felix.webconsole.internal.servlet.OsgiManager;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
+import org.osgi.service.http.whiteboard.annotations.RequireHttpWhiteboard;
/**
* This is the main, starting class of the Bundle. It initializes and disposes
* the Apache Web Console upon bundle lifecycle requests.
*/
+@RequireHttpWhiteboard
public class OsgiManagerActivator implements BundleActivator
{
@@ -45,8 +47,8 @@ public class OsgiManagerActivator implements BundleActivator
osgiManager = new OsgiManager( bundleContext );
try
{
- final Class activatorClass =
bundleContext.getBundle().loadClass(STATUS_ACTIVATOR);
- this.statusActivator = (BundleActivator)
activatorClass.newInstance();
+ final Class<?> activatorClass =
bundleContext.getBundle().loadClass(STATUS_ACTIVATOR);
+ this.statusActivator = (BundleActivator)
activatorClass.getDeclaredConstructor().newInstance();
}
catch (Throwable t)
diff --git
a/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/ConfigurationUtil.java
b/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/ConfigurationUtil.java
index 71ae43551c..3df506a765 100644
---
a/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/ConfigurationUtil.java
+++
b/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/ConfigurationUtil.java
@@ -20,13 +20,16 @@ package org.apache.felix.webconsole.internal.configuration;
import java.io.IOException;
+import java.util.Collections;
import java.util.Dictionary;
import java.util.List;
+import java.util.Set;
import org.apache.felix.webconsole.spi.ConfigurationHandler;
import org.apache.felix.webconsole.spi.ValidationException;
import org.osgi.framework.Constants;
import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
@@ -109,13 +112,11 @@ public class ConfigurationUtil {
this.factoryPid = factoryPid;
}
-
@Override
public String getPid() {
return PLACEHOLDER_PID;
}
-
@Override
public String getFactoryPid() {
return factoryPid;
@@ -157,5 +158,33 @@ public class ConfigurationUtil {
// dummy configuration always returns 0
return 0;
}
+
+ @Override
+ public void addAttributes(ConfigurationAttribute... attrs) throws
IOException {
+ // no attributes
+ }
+
+ @Override
+ public Set<ConfigurationAttribute> getAttributes() {
+ // no attributes
+ return Collections.emptySet();
+ }
+
+ @Override
+ public Dictionary<String, Object>
getProcessedProperties(ServiceReference<?> reference) {
+ // dummy configuration has no properties
+ return null;
+ }
+
+ @Override
+ public void removeAttributes(ConfigurationAttribute... attrs) throws
IOException {
+ // no attributes
+ }
+
+ @Override
+ public boolean updateIfDifferent(Dictionary<String, ?> properties)
throws IOException {
+ // dummy configuration has no properties
+ return false;
+ }
}
}
diff --git
a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/BasicWebConsoleSecurityProvider.java
b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/BasicWebConsoleSecurityProvider.java
index c17e530c5f..2a83284ec3 100644
---
a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/BasicWebConsoleSecurityProvider.java
+++
b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/BasicWebConsoleSecurityProvider.java
@@ -24,7 +24,7 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.felix.webconsole.WebConsoleSecurityProvider2;
import org.osgi.framework.BundleContext;
-import org.osgi.service.http.HttpContext;
+import org.osgi.service.http.context.ServletContextHelper;
/**
* Basic implementation of WebConsoleSecurityProvider to replace logic that
@@ -103,8 +103,8 @@ public class BasicWebConsoleSecurityProvider implements
WebConsoleSecurityProvid
if ( authenticate( username, toString(userPass[1]) )
!= null )
{
// as per the spec, set attributes
- request.setAttribute(
HttpContext.AUTHENTICATION_TYPE, HttpServletRequest.BASIC_AUTH );
- request.setAttribute( HttpContext.REMOTE_USER,
username );
+ request.setAttribute(
ServletContextHelper.AUTHENTICATION_TYPE, HttpServletRequest.BASIC_AUTH );
+ request.setAttribute(
ServletContextHelper.REMOTE_USER, username );
// set web console user attribute
request.setAttribute(
WebConsoleSecurityProvider2.USER_ATTRIBUTE, username );
diff --git
a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/ConfigurationMetatypeSupport.java
b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/ConfigurationMetatypeSupport.java
index cac5440ea0..8c218e9aa4 100644
---
a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/ConfigurationMetatypeSupport.java
+++
b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/ConfigurationMetatypeSupport.java
@@ -35,13 +35,12 @@ import org.osgi.service.metatype.ObjectClassDefinition;
class ConfigurationMetatypeSupport extends ConfigurationSupport implements
MetaTypeProvider
{
private static final String[] CONF_PROPS = new String[]
- { OsgiManager.PROP_MANAGER_ROOT, OsgiManager.DEFAULT_MANAGER_ROOT, //
- OsgiManager.PROP_HTTP_SERVICE_SELECTOR,
OsgiManager.DEFAULT_HTTP_SERVICE_SELECTOR, //
- OsgiManager.PROP_DEFAULT_RENDER, OsgiManager.DEFAULT_PAGE, //
- OsgiManager.PROP_REALM, OsgiManager.DEFAULT_REALM, //
- OsgiManager.PROP_USER_NAME, OsgiManager.DEFAULT_USER_NAME, //
- OsgiManager.PROP_CATEGORY, OsgiManager.DEFAULT_CATEGORY, //
- OsgiManager.PROP_LOCALE, "", //$NON-NLS-1$
+ { OsgiManager.PROP_MANAGER_ROOT, OsgiManager.DEFAULT_MANAGER_ROOT,
+ OsgiManager.PROP_DEFAULT_RENDER, OsgiManager.DEFAULT_PAGE,
+ OsgiManager.PROP_REALM, OsgiManager.DEFAULT_REALM,
+ OsgiManager.PROP_USER_NAME, OsgiManager.DEFAULT_USER_NAME,
+ OsgiManager.PROP_CATEGORY, OsgiManager.DEFAULT_CATEGORY,
+ OsgiManager.PROP_LOCALE, "",
};
private final Object ocdLock = new Object();
diff --git
a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/ConfigurationUtil.java
b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/ConfigurationUtil.java
index 1c4ffdecba..ef5d1840b1 100644
---
a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/ConfigurationUtil.java
+++
b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/ConfigurationUtil.java
@@ -91,7 +91,7 @@ public class ConfigurationUtil
* @return The value of the named property as a string or <code>def</code>
* if the property does not exist
*/
- public static final String getProperty(Map config, String name, String def)
+ public static final String getProperty(Map<String, Object> config, String
name, String def)
{
Object value = config.get(name);
if ( value instanceof String )
@@ -118,7 +118,7 @@ public class ConfigurationUtil
* @return The value of the named property as a string or <code>def</code>
* if the property does not exist
*/
- public static final int getProperty(Map config, String name, int def)
+ public static final int getProperty(Map<String, Object> config, String
name, int def)
{
Object value = config.get(name);
if (value instanceof Number)
@@ -150,7 +150,7 @@ public class ConfigurationUtil
* @param name The name of the property to return
* @return the property value as string array - no matter if originally it
was other kind of array, collection or comma-separated string. Returns
<code>null</code> if the property is not set.
*/
- public static final String[] getStringArrayProperty(Map config, String
name)
+ public static final String[] getStringArrayProperty(Map<String, Object>
config, String name)
{
Object value = config.get(name);
if (value == null)
diff --git
a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
index b42633e1bd..7aa869937a 100644
---
a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
+++
b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
@@ -17,7 +17,10 @@
package org.apache.felix.webconsole.internal.servlet;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.net.URL;
+import java.net.URLConnection;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
@@ -34,13 +37,13 @@ import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
-import java.util.Map.Entry;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListSet;
import javax.servlet.GenericServlet;
+import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
@@ -64,28 +67,24 @@ import
org.apache.felix.webconsole.internal.core.BundlesServlet;
import org.apache.felix.webconsole.internal.filter.FilteringResponseWrapper;
import org.apache.felix.webconsole.internal.i18n.ResourceBundleManager;
import org.apache.felix.webconsole.internal.servlet.Plugin.InternalPlugin;
-import org.apache.felix.webconsole.internal.system.VMStatPlugin;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
-import org.osgi.framework.Filter;
-import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceFactory;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
-import org.osgi.service.http.HttpContext;
-import org.osgi.service.http.HttpService;
-import org.osgi.service.log.LogService;
+import org.osgi.service.http.context.ServletContextHelper;
+import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
+import org.osgi.service.log.LogLevel;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
/**
- * The <code>OSGi Manager</code> is the actual Web Console Servlet which
- * is registered with the OSGi Http Service and which maintains registered
+ * The <code>OSGi Manager</code> is the actual Web Console Servlet. It is
+ * registered with the OSGi Http Whiteboard Service and it manages registered
* console plugins.
*/
-public class OsgiManager extends GenericServlet
-{
+public class OsgiManager extends GenericServlet {
/** Pseudo class version ID to keep the IDE quite. */
private static final long serialVersionUID = 1L;
@@ -179,7 +178,7 @@ public class OsgiManager extends GenericServlet
/** The timeout for VMStat plugin page reload */
public static final String PROP_RELOAD_TIMEOUT = "reload.timeout";
- public static final int DEFAULT_LOG_LEVEL = LogService.LOG_WARNING;
+ public static final int DEFAULT_LOG_LEVEL = LogLevel.WARN.ordinal();
static final String DEFAULT_PAGE = BundlesServlet.NAME;
@@ -191,8 +190,6 @@ public class OsgiManager extends GenericServlet
static final String DEFAULT_CATEGORY = "Main"; //$NON-NLS-1$
- static final String DEFAULT_HTTP_SERVICE_SELECTOR = ""; //$NON-NLS-1$
-
static final int DEFAULT_SHUTDOWN_TIMEOUT = 5; //$NON-NLS-1$
static final int DEFAULT_RELOAD_TIMEOUT = 40; //$NON-NLS-1$
@@ -234,15 +231,13 @@ public class OsgiManager extends GenericServlet
"org.apache.felix.webconsole.internal.system.VMStatPlugin",
"vmstat", //$NON-NLS-1$ //$NON-NLS-2$
};
+ private static final String SERVLEXT_CONTEXT_NAME =
"org.apache.felix.webconsole";
+
/** Flag to control whether secret heuristics is enabled */
public static volatile boolean ENABLE_SECRET_HEURISTICS =
OsgiManager.DEFAULT_ENABLE_SECRET_HEURISTIC;
private BundleContext bundleContext;
- private HttpServiceTracker httpServiceTracker;
-
- private volatile HttpService httpService;
-
private PluginHolder holder;
private ServiceTracker<BrandingPlugin, BrandingPlugin> brandingTracker;
@@ -253,19 +248,19 @@ public class OsgiManager extends GenericServlet
// list of OsgiManagerPlugin instances activated during init. All these
// instances will have to be deactivated during destroy
- private List<OsgiManagerPlugin> osgiManagerPlugins = new ArrayList<>();
+ private volatile List<OsgiManagerPlugin> osgiManagerPlugins = new
ArrayList<>();
- private String webManagerRoot;
+ private volatile String webManagerRoot;
// not-null when the BasicWebConsoleSecurityProvider service is registered
private ServiceRegistration<WebConsoleSecurityProvider>
basicSecurityServiceRegistration;
- // true if the OsgiManager is registered as a Servlet with the HttpService
- private boolean httpServletRegistered;
-
- // true if the resources have been registered with the HttpService
- private boolean httpResourcesRegistered;
-
+ // not-null when the ServletContextHelper service is registered
+ private volatile ServiceRegistration<ServletContextHelper>
servletContextRegistration;
+
+ // not-null when the main servlet and the resources are registered
+ private volatile ServiceRegistration<Servlet> servletRegistration;
+
// default configuration from framework properties
private Map<String, Object> defaultConfiguration;
@@ -335,12 +330,12 @@ public class OsgiManager extends GenericServlet
// message is just a class name, try to be more descriptive
message = "Class " + message + " missing";
}
- log(LogService.LOG_INFO, pluginClassName + " not enabled.
Reason: "
+ log(LogLevel.INFO.ordinal(), pluginClassName + " not enabled.
Reason: "
+ message);
}
catch (Throwable t)
{
- log(LogService.LOG_INFO, "Failed to instantiate plugin "
+ log(LogLevel.INFO.ordinal(), "Failed to instantiate plugin "
+ pluginClassName + ". Reason: " + t);
}
}
@@ -428,18 +423,15 @@ public class OsgiManager extends GenericServlet
}
void updateRegistrationState() {
- if (this.httpService != null) {
- if
(this.registeredSecurityProviders.containsAll(this.requiredSecurityProviders)) {
- // register HTTP service
- registerHttpService();
- return;
- } else {
- log(LogService.LOG_INFO, "Not all requirements met for the Web
Console. Required security providers: "
- + this.registeredSecurityProviders + " Registered
security providers: " + this.registeredSecurityProviders);
- }
+ if
(this.registeredSecurityProviders.containsAll(this.requiredSecurityProviders)) {
+ // register servlet context helper, servlet, resources
+ this.registerHttpWhiteboardServices();
+ } else {
+ log(LogLevel.INFO.ordinal(), "Not all requirements met for the Web
Console. Required security providers: "
+ + this.registeredSecurityProviders + " Registered security
providers: " + this.registeredSecurityProviders);
+ // Not all requirements met, unregister services
+ this.unregisterHttpWhiteboardServices();
}
- // Not all requirements met, unregister service.
- unregisterHttpService();
}
public void dispose()
@@ -472,11 +464,7 @@ public class OsgiManager extends GenericServlet
this.osgiManagerPlugins.clear();
// now drop the HttpService and continue with further destroyals
- if (httpServiceTracker != null)
- {
- httpServiceTracker.close();
- httpServiceTracker = null;
- }
+ this.unregisterHttpWhiteboardServices();
// stop listening for configuration
if (configurationListener != null)
@@ -525,7 +513,18 @@ public class OsgiManager extends GenericServlet
@Override
public Object run() throws Exception
{
- service((HttpServletRequest) req, (HttpServletResponse)
res);
+ final HttpServletRequest wrapper = new
HttpServletRequestWrapper((HttpServletRequest) req) {
+ @Override
+ public String getServletPath() {
+ return "";
+ }
+
+ @Override
+ public String getPathInfo() {
+ return super.getServletPath();
+ }
+ };
+ service(wrapper, (HttpServletResponse) res);
return null;
}
});
@@ -566,16 +565,13 @@ public class OsgiManager extends GenericServlet
}
void service(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException
- {
+ throws ServletException, IOException {
// check whether we are not at .../{webManagerRoot}
final String pathInfo = request.getPathInfo();
- if (pathInfo == null || pathInfo.equals("/")) //$NON-NLS-1$
- {
+ if (pathInfo == null || pathInfo.isEmpty() || pathInfo.equals("/")) {
String path = request.getRequestURI();
- if (!path.endsWith("/")) //$NON-NLS-1$
- {
- path = path.concat("/"); //$NON-NLS-1$
+ if (!path.endsWith("/")) {
+ path = path.concat("/");
}
path = path.concat(holder.getDefaultPluginLabel());
response.setContentLength(0);
@@ -583,11 +579,21 @@ public class OsgiManager extends GenericServlet
return;
}
- if (pathInfo.equals("/logout")) { //$NON-NLS-1$
+ if (pathInfo.equals("/logout")) {
logout(request, response);
return;
}
+ if (pathInfo.startsWith("/res/")) {
+ URL url = this.getBundleContext().getBundle().getResource(
pathInfo );
+ if ( url == null && pathInfo.endsWith( "/" ) ) {
+ url = this.getBundleContext().getBundle().getResource(
pathInfo.substring( 0, pathInfo.length() - 1 ) );
+ }
+ if ( url != null && this.spool(request, response, url)) {
+ return;
+ }
+ }
+
int slash = pathInfo.indexOf("/", 1); //$NON-NLS-1$
if (slash < 2)
{
@@ -613,6 +619,7 @@ public class OsgiManager extends GenericServlet
return;
}
+ @SuppressWarnings("rawtypes")
final Map labelMap = holder.getLocalizedLabelMap(
resourceBundleManager, locale, this.defaultCategory );
final Object flatLabelMap = labelMap.remove(
WebConsoleConstants.ATTR_LABEL_MAP );
@@ -641,60 +648,92 @@ public class OsgiManager extends GenericServlet
plugin.service(request, response);
}
- private final void logout(HttpServletRequest request, HttpServletResponse
response)
- throws IOException
- {
- // check if special logout cookie is set, this is used to prevent
- // from an endless loop with basic auth
- Cookie[] cookies = request.getCookies();
- boolean found = false;
- if ( cookies != null )
- {
- for(int i=0;i<cookies.length;i++)
- {
- if ( cookies[i].getName().equals("logout") ) //$NON-NLS-1$
- {
- found = true;
- break;
+ private boolean spool(final HttpServletRequest request, final
HttpServletResponse response, final URL url)
+ throws IOException {
+ final URLConnection connection = url.openConnection();
+ try ( InputStream ins = connection.getInputStream()) {
+ if (ins == null) {
+ return false;
+ }
+
+ // check whether we may return 304/UNMODIFIED
+ final long lastModified = connection.getLastModified();
+ if ( lastModified > 0 ) {
+ final long ifModifiedSince = request.getDateHeader(
"If-Modified-Since" );
+ if ( ifModifiedSince >= ( lastModified / 1000 * 1000 ) ) {
+ // Round down to the nearest second for a proper compare
+ // A ifModifiedSince of -1 will always be less
+ response.setStatus( HttpServletResponse.SC_NOT_MODIFIED );
+
+ return true;
}
+
+ // have to send, so set the last modified header now
+ response.setDateHeader( "Last-Modified", lastModified );
}
+
+ response.setContentType( getServletContext().getMimeType(
request.getPathInfo() ) );
+ response.setIntHeader( "Content-Length",
connection.getContentLength() );
+
+ // spool the actual contents
+ try (final OutputStream out = response.getOutputStream()) {
+ byte[] buf = new byte[2048];
+ int rd;
+ while ( ( rd = ins.read( buf ) ) >= 0 ) {
+ out.write( buf, 0, rd );
+ }
+ }
+
+ return true;
}
- if ( found )
- {
- // redirect to main page
- String url = request.getRequestURI();
- final int lastSlash = url.lastIndexOf('/');
- final Cookie c = new Cookie("logout", "true"); //$NON-NLS-1$
//$NON-NLS-2$
- c.setMaxAge(0);
- response.addCookie(c);
- response.sendRedirect(url.substring(0, lastSlash));
- return;
- }
- Object securityProvider = securityProviderTracker.getService();
- if (securityProvider instanceof WebConsoleSecurityProvider3)
- {
+ }
+
+ private final void logout(HttpServletRequest request, HttpServletResponse
response)
+ throws IOException {
+ final Object securityProvider = securityProviderTracker.getService();
+ if (securityProvider instanceof WebConsoleSecurityProvider3) {
((WebConsoleSecurityProvider3) securityProvider).logout(request,
response);
- }
- else
- {
- // if the security provider doesn't support logout, we try to
- // logout the default basic authentication mechanism
- // See https://issues.apache.org/jira/browse/FELIX-3006
-
- // check for basic authentication
- String auth = request.getHeader(HEADER_AUTHORIZATION);
//$NON-NLS-1$
- if (null != auth && auth.toLowerCase().startsWith("basic ")) {
//$NON-NLS-1$
- Map<String, Object> config = getConfiguration();
- String realm = ConfigurationUtil.getProperty(config,
PROP_REALM, DEFAULT_REALM);
- response.setHeader(HEADER_WWW_AUTHENTICATE, "Basic realm=\"" +
realm + "\""); //$NON-NLS-1$ //$NON-NLS-2$
- response.addCookie(new Cookie("logout", "true"));
//$NON-NLS-1$ //$NON-NLS-2$
- response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ } else {
+ // check if special logout cookie is set, this is used to prevent
+ // from an endless loop with basic auth
+ final Cookie[] cookies = request.getCookies();
+ boolean found = false;
+ if ( cookies != null ) {
+ for(final Cookie c : cookies) {
+ if (c.getName().equals("logout") ) {
+ found = true;
+ break;
+ }
+ }
+ }
+ if ( found ) {
+ // redirect to main page
+ final String url = request.getRequestURI();
+ final int lastSlash = url.lastIndexOf('/');
+ final Cookie c = new Cookie("logout", "true");
+ c.setMaxAge(0);
+ response.addCookie(c);
+ response.sendRedirect(url.substring(0, lastSlash));
+ } else {
+ // if the security provider doesn't support logout, we try to
+ // logout the default basic authentication mechanism
+ // See https://issues.apache.org/jira/browse/FELIX-3006
+
+ // check for basic authentication
+ final String auth = request.getHeader(HEADER_AUTHORIZATION);
+ if (null != auth && auth.toLowerCase().startsWith("basic ")) {
+ Map<String, Object> config = getConfiguration();
+ String realm = ConfigurationUtil.getProperty(config,
PROP_REALM, DEFAULT_REALM);
+ response.setHeader(HEADER_WWW_AUTHENTICATE, "Basic
realm=\"" + realm + "\"");
+ response.addCookie(new Cookie("logout", "true"));
+ response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ }
}
}
// clean-up
- request.removeAttribute(HttpContext.REMOTE_USER);
- request.removeAttribute(HttpContext.AUTHORIZATION);
+ request.removeAttribute(ServletContextHelper.REMOTE_USER);
+ request.removeAttribute(ServletContextHelper.AUTHORIZATION);
request.removeAttribute(WebConsoleSecurityProvider2.USER_ATTRIBUTE);
request.removeAttribute(User.USER_ATTRIBUTE);
}
@@ -879,80 +918,6 @@ public class OsgiManager extends GenericServlet
return new FilteringResponseWrapper(response, resourceBundle, request);
}
- private static class HttpServiceTracker extends
ServiceTracker<HttpService, HttpService>
- {
- private final OsgiManager osgiManager;
-
- private final String httpServiceSelector;
-
- static HttpServiceTracker create(OsgiManager osgiManager,
- String httpServiceSelector)
- {
- // got a service selector filter
- if (httpServiceSelector != null && httpServiceSelector.length() >
0)
- {
- try
- {
- final String filterString = "(&(" + Constants.OBJECTCLASS
+ "=" //$NON-NLS-1$ //$NON-NLS-2$
- + HttpService.class.getName() + ")(" +
httpServiceSelector + "))"; //$NON-NLS-1$ //$NON-NLS-2$
- Filter filter =
osgiManager.getBundleContext().createFilter(
- filterString);
- return new HttpServiceTracker(osgiManager,
httpServiceSelector,
- filter);
- }
- catch (InvalidSyntaxException ise)
- {
- // TODO: log or throw or ignore ....
- }
- }
-
- // no filter or illegal filter string
- return new HttpServiceTracker(osgiManager);
- }
-
- private HttpServiceTracker(final OsgiManager osgiManager)
- {
- super(osgiManager.getBundleContext(), HttpService.class, null);
- this.osgiManager = osgiManager;
- this.httpServiceSelector = null;
- }
-
- private HttpServiceTracker(final OsgiManager osgiManager, final String
httpServiceSelector, final Filter httpServiceFilter)
- {
- super(osgiManager.getBundleContext(), httpServiceFilter, null);
- this.osgiManager = osgiManager;
- this.httpServiceSelector = httpServiceSelector;
- }
-
- boolean isSameSelector(final String newHttpServiceSelector)
- {
- if (newHttpServiceSelector != null)
- {
- return newHttpServiceSelector.equals(httpServiceSelector);
- }
- return httpServiceSelector == null;
- }
-
- @Override
- public HttpService addingService(ServiceReference<HttpService>
reference)
- {
- HttpService service = super.addingService(reference);
- osgiManager.bindHttpService(service);
- return service;
- }
-
- @Override
- public void removedService(ServiceReference<HttpService> reference,
HttpService service)
- {
- osgiManager.unbindHttpService(service);
- try {
- super.removedService(reference, service);
- } catch ( final IllegalStateException ise) {
- // ignore this as the service is already invalid
- }
- }
- }
-
private static class BrandingServiceTracker extends
ServiceTracker<BrandingPlugin, BrandingPlugin>
{
BrandingServiceTracker(OsgiManager osgiManager)
@@ -981,158 +946,113 @@ public class OsgiManager extends GenericServlet
}
- protected void bindHttpService(HttpService httpService)
- {
- // do not bind service, when we are already bound
- if (this.httpService != null)
- {
- log(LogService.LOG_DEBUG,
- "bindHttpService: Already bound to an HTTP Service, ignoring
further services");
- return;
- }
-
- this.httpService = httpService;
- updateRegistrationState();
- }
-
- synchronized void registerHttpService() {
- Map<String, Object> config = getConfiguration();
+ synchronized void registerHttpWhiteboardServices() {
+ final String realm =
ConfigurationUtil.getProperty(this.getConfiguration(), PROP_REALM,
DEFAULT_REALM);
- // get authentication details
- String realm = ConfigurationUtil.getProperty(config, PROP_REALM,
DEFAULT_REALM);
- String userId = ConfigurationUtil.getProperty(config, PROP_USER_NAME,
DEFAULT_USER_NAME);
- String password = ConfigurationUtil.getProperty(config, PROP_PASSWORD,
DEFAULT_PASSWORD);
+ try{
+ final String httpServiceSelector =
ConfigurationUtil.getProperty(this.getConfiguration(),
PROP_HTTP_SERVICE_SELECTOR, null);
- // register the servlet and resources
- try
- {
- HttpContext httpContext = new OsgiManagerHttpContext(httpService,
- securityProviderTracker, realm);
-
- Dictionary<String, String> servletConfig = toStringConfig(config);
-
- if (basicSecurityServiceRegistration == null) {
+ if (this.basicSecurityServiceRegistration == null) {
//register this component
- BasicWebConsoleSecurityProvider service = new
BasicWebConsoleSecurityProvider(bundleContext,
+ final String userId =
ConfigurationUtil.getProperty(this.getConfiguration(), PROP_USER_NAME,
DEFAULT_USER_NAME);
+ final String password =
ConfigurationUtil.getProperty(this.getConfiguration(), PROP_PASSWORD,
DEFAULT_PASSWORD);
+ final BasicWebConsoleSecurityProvider service = new
BasicWebConsoleSecurityProvider(bundleContext,
userId, password, realm);
- Dictionary<String, Object> serviceProperties = new
Hashtable<>(); // NOSONAR
+ final Dictionary<String, Object> serviceProperties = new
Hashtable<>(); // NOSONAR
// this is a last resort service, so use a low service ranking
to prefer all other services over this one
serviceProperties.put(Constants.SERVICE_RANKING,
Integer.MIN_VALUE);
- basicSecurityServiceRegistration =
bundleContext.registerService(WebConsoleSecurityProvider.class,
+ this.basicSecurityServiceRegistration =
bundleContext.registerService(WebConsoleSecurityProvider.class,
service, serviceProperties);
}
- if (!httpServletRegistered) {
- // register this servlet and take note of this
- httpService.registerServlet(this.webManagerRoot, this,
servletConfig,
- httpContext);
- httpServletRegistered = true;
- }
+ if (this.servletContextRegistration == null) {
+ final ServletContextHelper httpContext = new
OsgiManagerHttpContext(this.bundleContext.getBundle(),
+ securityProviderTracker, realm);
+ final Dictionary<String, Object> props = new Hashtable<>();
+ if (httpServiceSelector != null) {
+ props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_TARGET,
httpServiceSelector);
+ }
+
props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME,
SERVLEXT_CONTEXT_NAME);
+
props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH,
this.webManagerRoot);
- if (!httpResourcesRegistered) {
- // register resources and take of this
- httpService.registerResources(this.webManagerRoot + "/res",
"/res",
- httpContext);
- httpResourcesRegistered = true;
+ this.servletContextRegistration =
getBundleContext().registerService(ServletContextHelper.class,
+ httpContext, props);
}
- }
- catch (Exception e)
- {
- log(LogService.LOG_ERROR, "bindHttpService: Problem setting up",
e);
- }
- }
- protected void unbindHttpService(HttpService httpService)
- {
- if (this.httpService != httpService)
- {
- log(LogService.LOG_DEBUG,
- "unbindHttpService: Ignoring unbind of an HttpService to which
we are not registered");
- return;
- }
+ if (this.servletRegistration == null) {
+ // register this servlet and take note of this
+ final Dictionary<String, Object> props = new Hashtable<>();
+ for(final Map.Entry<String, Object> entry :
this.getConfiguration().entrySet()) {
+ props.put(entry.getKey(),
String.valueOf(entry.getValue()));
+ }
+ if (httpServiceSelector != null) {
+ props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_TARGET,
httpServiceSelector);
+ }
- unregisterHttpService();
+
props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, "/");
+
props.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT, "(" +
HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME + "=" +
SERVLEXT_CONTEXT_NAME + ")");
- // drop the service reference
- this.httpService = null;
+ this.servletRegistration =
getBundleContext().registerService(Servlet.class, this, props);
+ }
+ } catch (final Exception e) {
+ log(LogLevel.ERROR.ordinal(), "registerHttpWhiteboardServices:
Problem setting up", e);
+ this.unregisterHttpWhiteboardServices();
+ }
}
- synchronized void unregisterHttpService() {
- if (httpService == null)
- return;
-
- if (basicSecurityServiceRegistration != null) {
+ synchronized void unregisterHttpWhiteboardServices() {
+ if (this.basicSecurityServiceRegistration != null) {
try {
- basicSecurityServiceRegistration.unregister();
- } catch (Throwable t) {
- log(LogService.LOG_WARNING,
- "unbindHttpService: Failed unregistering basic
WebConsoleSecurityProvider", t);
+ this.basicSecurityServiceRegistration.unregister();
+ } catch (final IllegalStateException ignore) {
+ // ignore
}
- basicSecurityServiceRegistration = null;
+ this.basicSecurityServiceRegistration = null;
}
- if (httpResourcesRegistered)
- {
- try
- {
- httpService.unregister(this.webManagerRoot + "/res");
- }
- catch (Throwable t)
- {
- log(LogService.LOG_WARNING,
- "unbindHttpService: Failed unregistering Resources", t);
+ if (this.servletRegistration != null) {
+ try {
+ this.servletRegistration.unregister();
+ } catch (final IllegalStateException ignore) {
+ // ignore
}
- httpResourcesRegistered = false;
+ this.servletRegistration = null;
}
- if (httpServletRegistered)
- {
- try
- {
- httpService.unregister(this.webManagerRoot);
- }
- catch (Throwable t)
- {
- log(LogService.LOG_WARNING,
- "unbindHttpService: Failed unregistering Servlet", t);
+ if (this.servletContextRegistration != null) {
+ try {
+ this.servletContextRegistration.unregister();
+ } catch (final IllegalStateException ignore) {
+ // ignore
}
- httpServletRegistered = false;
+ this.servletContextRegistration = null;
}
}
-
- private Map<String, Object> getConfiguration()
- {
+ private Map<String, Object> getConfiguration() {
return configuration;
}
-
- Map<String, Object> getDefaultConfiguration()
- {
+ Map<String, Object> getDefaultConfiguration() {
return defaultConfiguration;
}
+ synchronized void updateConfiguration( final Dictionary<String, Object>
osgiConfig) {
+ final Map<String, Object> config = new HashMap<String, Object>(
this.defaultConfiguration );
- synchronized void updateConfiguration( Dictionary<String, Object>
osgiConfig )
- {
- Map<String, Object> config = new HashMap<String, Object>(
this.defaultConfiguration );
-
- if ( osgiConfig != null )
- {
- for ( Enumeration<String> keys = osgiConfig.keys();
keys.hasMoreElements(); )
- {
+ if ( osgiConfig != null ) {
+ for ( Enumeration<String> keys = osgiConfig.keys();
keys.hasMoreElements(); ) {
final String key = keys.nextElement();
config.put( key, osgiConfig.get( key ) );
}
}
- configuration = config;
+ this.configuration = config;
final Object locale = config.get(PROP_LOCALE);
- configuredLocale = locale == null || locale.toString().trim().length()
== 0 //
- ? null : Util.parseLocaleString(locale.toString().trim());
+ this.configuredLocale = locale == null ||
locale.toString().trim().length() == 0 ? null :
Util.parseLocaleString(locale.toString().trim());
- logLevel = ConfigurationUtil.getProperty(config, PROP_LOG_LEVEL,
DEFAULT_LOG_LEVEL);
+ this.logLevel = ConfigurationUtil.getProperty(config, PROP_LOG_LEVEL,
DEFAULT_LOG_LEVEL);
AbstractWebConsolePlugin.setLogLevel(logLevel);
// default plugin page configuration
@@ -1140,67 +1060,33 @@ public class OsgiManager extends GenericServlet
// get the web manager root path
String newWebManagerRoot = ConfigurationUtil.getProperty(config,
PROP_MANAGER_ROOT, DEFAULT_MANAGER_ROOT);
- if (!newWebManagerRoot.startsWith("/")) //$NON-NLS-1$
- {
- newWebManagerRoot = "/" + newWebManagerRoot; //$NON-NLS-1$
+ if (!newWebManagerRoot.startsWith("/")) { //$NON-NLS-1$
+ newWebManagerRoot = "/".concat(newWebManagerRoot); //$NON-NLS-1$
}
// default category
this.defaultCategory = ConfigurationUtil.getProperty( config,
PROP_CATEGORY, DEFAULT_CATEGORY );
- // get the HTTP Service selector (and dispose tracker for later
- // recreation)
- final String newHttpServiceSelector =
ConfigurationUtil.getProperty(config,
- PROP_HTTP_SERVICE_SELECTOR, DEFAULT_HTTP_SERVICE_SELECTOR);
- if (httpServiceTracker != null
- && !httpServiceTracker.isSameSelector(newHttpServiceSelector))
- {
- httpServiceTracker.close();
- httpServiceTracker = null;
- }
-
// secret heuristics
final boolean enableHeuristics = ConfigurationUtil.getProperty(config,
PROP_ENABLE_SECRET_HEURISTIC, DEFAULT_ENABLE_SECRET_HEURISTIC);
OsgiManager.ENABLE_SECRET_HEURISTICS = enableHeuristics;
// get enabled plugins
- String[] plugins = ConfigurationUtil.getStringArrayProperty(config,
PROP_ENABLED_PLUGINS);
- enabledPlugins = null == plugins ? null : new
HashSet<String>(Arrays.asList(plugins));
+ final String[] plugins =
ConfigurationUtil.getStringArrayProperty(config, PROP_ENABLED_PLUGINS);
+ this.enabledPlugins = null == plugins ? null : new
HashSet<String>(Arrays.asList(plugins));
// check for moved config manager class (see FELIX-4074)
- if ( enabledPlugins != null )
- {
- if ( enabledPlugins.remove(OLD_CONFIG_MANAGER_CLASS) )
- {
+ if ( enabledPlugins != null ) {
+ if ( enabledPlugins.remove(OLD_CONFIG_MANAGER_CLASS) ) {
enabledPlugins.add(NEW_CONFIG_MANAGER_CLASS);
}
}
initInternalPlugins();
- // might update HTTP service registration
- HttpService httpService = this.httpService;
- if (httpService != null)
- {
- // unbind old location first
- unbindHttpService(httpService);
-
- // switch location
- this.webManagerRoot = newWebManagerRoot;
-
- // bind new location now
- bindHttpService(httpService);
- }
- else
- {
- // just set the configured location (FELIX-2034)
- this.webManagerRoot = newWebManagerRoot;
- }
-
- // create or recreate the HTTP service tracker with the new selector
- if (httpServiceTracker == null)
- {
- httpServiceTracker = HttpServiceTracker.create(this,
newHttpServiceSelector);
- httpServiceTracker.open();
- }
+ // update http service registrations.
+ this.unregisterHttpWhiteboardServices();
+ // switch location
+ this.webManagerRoot = newWebManagerRoot;
+ this.registerHttpWhiteboardServices();
}
private void initInternalPlugins()
@@ -1239,18 +1125,6 @@ public class OsgiManager extends GenericServlet
return enabledPlugins != null && !enabledPlugins.contains( pluginClass
);
}
-
- private Dictionary<String, String> toStringConfig( Map<String, Object>
config )
- {
- Dictionary<String, String> stringConfig = new Hashtable<>();
- for ( Iterator<Map.Entry<String, Object>> ei =
config.entrySet().iterator(); ei.hasNext(); )
- {
- Entry<String, Object> entry = ei.next();
- stringConfig.put( entry.getKey(), String.valueOf( entry.getValue()
) );
- }
- return stringConfig;
- }
-
static Set<String> splitCommaSeparatedString(final String str) {
if (str == null)
return Collections.emptySet();
diff --git
a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerHttpContext.java
b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerHttpContext.java
index f8a4e4917e..e206756945 100644
---
a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerHttpContext.java
+++
b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerHttpContext.java
@@ -22,71 +22,55 @@ import static
org.apache.felix.webconsole.internal.servlet.BasicWebConsoleSecuri
import static
org.apache.felix.webconsole.internal.servlet.BasicWebConsoleSecurityProvider.HEADER_WWW_AUTHENTICATE;
import java.io.IOException;
-import java.net.URL;
import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import org.apache.felix.webconsole.User;
import org.apache.felix.webconsole.WebConsoleSecurityProvider;
import org.apache.felix.webconsole.WebConsoleSecurityProvider2;
-import org.osgi.service.http.HttpContext;
-import org.osgi.service.http.HttpService;
+import org.osgi.framework.Bundle;
+import org.osgi.service.http.context.ServletContextHelper;
import org.osgi.util.tracker.ServiceTracker;
-final class OsgiManagerHttpContext implements HttpContext
-{
-
- private final HttpContext base;
+final class OsgiManagerHttpContext extends ServletContextHelper {
private final ServiceTracker<WebConsoleSecurityProvider,
WebConsoleSecurityProvider> tracker;
private final String realm;
- OsgiManagerHttpContext(final HttpService httpService,
+ OsgiManagerHttpContext(final Bundle webConsoleBundle,
final ServiceTracker<WebConsoleSecurityProvider,
WebConsoleSecurityProvider> tracker,
- final String realm)
- {
+ final String realm) {
+ super(webConsoleBundle);
this.tracker = tracker;
this.realm = realm;
- this.base = httpService.createDefaultHttpContext();
}
+ @Override
+ public boolean handleSecurity( final HttpServletRequest r, final
HttpServletResponse response ) {
+ final WebConsoleSecurityProvider provider = tracker.getService();
- public String getMimeType( String name )
- {
- return this.base.getMimeType( name );
- }
-
+ // for compatibility we have to adjust a few methods on the request
+ final HttpServletRequest request = new HttpServletRequestWrapper(r) {
- public URL getResource( String name )
- {
- URL url = this.base.getResource( name );
- if ( url == null && name.endsWith( "/" ) )
- {
- return this.base.getResource( name.substring( 0, name.length() - 1
) );
- }
- return url;
- }
+ @Override
+ public String getContextPath() {
+ return "";
+ }
+ @Override
+ public String getServletPath() {
+ return r.getContextPath();
+ }
- /**
- * Checks the <code>Authorization</code> header of the request for Basic
- * authentication user name and password. If contained, the credentials are
- * compared to the user name and password set for the OSGi Console.
- * <p>
- * If no user name is set, the <code>Authorization</code> header is
- * ignored and the client is assumed to be authenticated.
- *
- * @param request The HTTP request used to get the
- * <code>Authorization</code> header.
- * @param response The HTTP response used to send the authentication
request
- * if authentication is required but not satisfied.
- * @return {@code} true if authentication is required and not satisfied by
the request.
- */
- public boolean handleSecurity( final HttpServletRequest request, final
HttpServletResponse response ) {
- final WebConsoleSecurityProvider provider = tracker.getService();
+ @Override
+ public String getPathInfo() {
+ return r.getServletPath();
+ }
+ };
// check whether the security provider can fully handle the request
final boolean result;
@@ -156,8 +140,8 @@ final class OsgiManagerHttpContext implements HttpContext
if ( authenticate( provider, username, userPass[1] ) )
{
// as per the spec, set attributes
- request.setAttribute(
HttpContext.AUTHENTICATION_TYPE, HttpServletRequest.BASIC_AUTH );
- request.setAttribute( HttpContext.REMOTE_USER,
username );
+ request.setAttribute( AUTHENTICATION_TYPE,
HttpServletRequest.BASIC_AUTH );
+ request.setAttribute( REMOTE_USER, username );
// set web console user attribute
request.setAttribute(
WebConsoleSecurityProvider2.USER_ATTRIBUTE, username );
@@ -175,15 +159,12 @@ final class OsgiManagerHttpContext implements HttpContext
}
// request authentication
- try
- {
+ try {
response.setHeader( HEADER_WWW_AUTHENTICATE,
AUTHENTICATION_SCHEME_BASIC + " realm=\"" + this.realm + "\"" );
response.setStatus( HttpServletResponse.SC_UNAUTHORIZED );
response.setContentLength( 0 );
response.flushBuffer();
- }
- catch ( IOException ioe )
- {
+ } catch ( IOException ioe ) {
// failed sending the response ... cannot do anything about it
}
@@ -191,8 +172,7 @@ final class OsgiManagerHttpContext implements HttpContext
return false;
}
- private boolean authenticate( WebConsoleSecurityProvider provider, String
username, byte[] password )
- {
+ private boolean authenticate( WebConsoleSecurityProvider provider, String
username, byte[] password ) {
if ( provider != null )
{
return provider.authenticate( username,
BasicWebConsoleSecurityProvider.toString( password ) ) != null;
diff --git
a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/Plugin.java
b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/Plugin.java
index 9ea34a5adf..5ad14c3144 100644
---
a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/Plugin.java
+++
b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/Plugin.java
@@ -35,7 +35,7 @@ import
org.apache.felix.webconsole.internal.WebConsolePluginAdapter;
import org.osgi.framework.Bundle;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
-import org.osgi.service.log.LogService;
+import org.osgi.service.log.LogLevel;
public abstract class Plugin implements ServletConfig, Comparable<Plugin> {
@@ -279,7 +279,7 @@ public abstract class Plugin implements ServletConfig,
Comparable<Plugin> {
protected AbstractWebConsolePlugin doGetConsolePlugin() {
if (!isEnabled()) {
if (doLog) {
- osgiManager.log( LogService.LOG_INFO, "Ignoring plugin " +
pluginClassName + ": Disabled by configuration" );
+ osgiManager.log( LogLevel.INFO.ordinal(), "Ignoring plugin
" + pluginClassName + ": Disabled by configuration" );
doLog = false;
}
return null;
@@ -299,7 +299,7 @@ public abstract class Plugin implements ServletConfig,
Comparable<Plugin> {
} catch (final Throwable t) {
plugin = null; // in case only activate has faled!
if (doLog) {
- osgiManager.log( LogService.LOG_WARNING, "Failed to
instantiate plugin " + pluginClassName, t );
+ osgiManager.log( LogLevel.WARN.ordinal(), "Failed to
instantiate plugin " + pluginClassName, t );
doLog = false;
}
}
diff --git
a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/PluginHolder.java
b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/PluginHolder.java
index 05e69fd861..17d305bd6d 100644
---
a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/PluginHolder.java
+++
b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/PluginHolder.java
@@ -40,7 +40,7 @@ import org.osgi.framework.Constants;
import org.osgi.framework.Filter;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
-import org.osgi.service.log.LogService;
+import org.osgi.service.log.LogLevel;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
@@ -209,6 +209,7 @@ class PluginHolder implements
ServiceTrackerCustomizer<Servlet, Plugin> {
*
* @return The localized map of labels to titles
*/
+ @SuppressWarnings({ "unchecked", "rawtypes" })
Map getLocalizedLabelMap( final ResourceBundleManager
resourceBundleManager, final Locale locale, final String defaultCategory )
{
final Map map = new HashMap();
@@ -259,6 +260,7 @@ class PluginHolder implements
ServiceTrackerCustomizer<Servlet, Plugin> {
}
+ @SuppressWarnings({ "unchecked", "rawtypes" })
private Map findCategoryMap( Map map, String categoryPath )
{
Map categoryMap = null;
@@ -360,14 +362,14 @@ class PluginHolder implements
ServiceTrackerCustomizer<Servlet, Plugin> {
if (!first.init()) {
list.remove(plugin);
} else if (oldPlugin != null) {
- osgiManager.log(LogService.LOG_WARNING, "Overwriting
existing plugin " + oldPlugin.getId()
+ osgiManager.log(LogLevel.WARN.ordinal(), "Overwriting
existing plugin " + oldPlugin.getId()
+ " having label " + plugin.getLabel() + " with
new plugin " + plugin.getId()
+ " due to higher ranking " );
oldPlugin.dispose();
}
}
if (first == oldPlugin) {
- osgiManager.log(LogService.LOG_WARNING, "Ignoring new plugin "
+ plugin.getId()
+ osgiManager.log(LogLevel.WARN.ordinal(), "Ignoring new plugin
" + plugin.getId()
+ " having existing label " + plugin.getLabel() + "
due to lower ranking than old plugin " + oldPlugin.getId() );
}
}
diff --git
a/webconsole/src/test/java/org/apache/felix/webconsole/internal/configuration/ConfigJsonSupportTest.java
b/webconsole/src/test/java/org/apache/felix/webconsole/internal/configuration/ConfigJsonSupportTest.java
index a6f0dfe856..ea682fda44 100644
---
a/webconsole/src/test/java/org/apache/felix/webconsole/internal/configuration/ConfigJsonSupportTest.java
+++
b/webconsole/src/test/java/org/apache/felix/webconsole/internal/configuration/ConfigJsonSupportTest.java
@@ -19,14 +19,12 @@
package org.apache.felix.webconsole.internal.configuration;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.Dictionary;
import java.util.Hashtable;
-import java.util.List;
import org.apache.felix.webconsole.spi.ConfigurationHandler;
import org.apache.felix.webconsole.spi.ValidationException;
diff --git
a/webconsole/src/test/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerHttpContextTest.java
b/webconsole/src/test/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerHttpContextTest.java
index 70fae7e4cf..6b9a6c7848 100644
---
a/webconsole/src/test/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerHttpContextTest.java
+++
b/webconsole/src/test/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerHttpContextTest.java
@@ -21,8 +21,8 @@ package org.apache.felix.webconsole.internal.servlet;
import org.apache.felix.webconsole.WebConsoleSecurityProvider;
import org.junit.Test;
import org.mockito.Mockito;
+import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
-import org.osgi.service.http.HttpService;
import java.lang.reflect.Method;
@@ -32,8 +32,8 @@ public class OsgiManagerHttpContextTest {
@Test
public void testAuthenticate() throws Exception {
BundleContext bc = Mockito.mock(BundleContext.class);
- HttpService svc = Mockito.mock(HttpService.class);
- OsgiManagerHttpContext ctx = new OsgiManagerHttpContext(svc, null,
"blah");
+ Bundle bundle = Mockito.mock(Bundle.class);
+ OsgiManagerHttpContext ctx = new OsgiManagerHttpContext(bundle, null,
"blah");
Method authenticateMethod =
OsgiManagerHttpContext.class.getDeclaredMethod(
"authenticate", new Class []
{WebConsoleSecurityProvider.class, String.class, byte[].class});
@@ -54,8 +54,8 @@ public class OsgiManagerHttpContextTest {
BundleContext bc = Mockito.mock(BundleContext.class);
Mockito.when(bc.getProperty(OsgiManager.FRAMEWORK_PROP_SECURITY_PROVIDERS)).thenReturn("a");
- HttpService svc = Mockito.mock(HttpService.class);
- OsgiManagerHttpContext ctx = new OsgiManagerHttpContext(svc, null,
"blah");
+ Bundle bundle = Mockito.mock(Bundle.class);
+ OsgiManagerHttpContext ctx = new OsgiManagerHttpContext(bundle, null,
"blah");
Method authenticateMethod =
OsgiManagerHttpContext.class.getDeclaredMethod(
"authenticate", new Class []
{WebConsoleSecurityProvider.class, String.class, byte[].class});
diff --git
a/webconsole/src/test/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerTest.java
b/webconsole/src/test/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerTest.java
index efe73eec46..70b8574d18 100644
---
a/webconsole/src/test/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerTest.java
+++
b/webconsole/src/test/java/org/apache/felix/webconsole/internal/servlet/OsgiManagerTest.java
@@ -19,9 +19,7 @@
package org.apache.felix.webconsole.internal.servlet;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.lang.reflect.Field;
@@ -35,10 +33,12 @@ import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.servlet.Servlet;
import org.apache.felix.webconsole.WebConsoleSecurityProvider;
import org.junit.Test;
-import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
@@ -49,8 +49,8 @@ import org.osgi.framework.Filter;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
-import org.osgi.service.http.HttpContext;
-import org.osgi.service.http.HttpService;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.http.context.ServletContextHelper;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
public class OsgiManagerTest {
@@ -171,38 +171,27 @@ public class OsgiManagerTest {
}
- @SuppressWarnings("serial")
@Test
public void testUpdateRegistrationStateNoRequiredProviders() throws
Exception {
BundleContext bc = mockBundleContext();
- final List<String> invocations = new ArrayList<String>();
- OsgiManager mgr = new OsgiManager(bc) {
+ final AtomicReference<String> invocation = new
AtomicReference<String>();
+ new OsgiManager(bc) {
@Override
- protected synchronized void registerHttpService() {
- invocations.add("register");
+ protected synchronized void registerHttpWhiteboardServices() {
+ invocation.set("register");
}
@Override
- protected synchronized void unregisterHttpService() {
- invocations.add("unregister");
+ protected synchronized void unregisterHttpWhiteboardServices() {
+ invocation.set("unregister");
}
};
- // HTTP Service not present -> unregister
- mgr.updateRegistrationState();
- assertEquals(Collections.singletonList("unregister"), invocations);
-
- // HTTP Service present, no required providers, no registered
providers -> register
- invocations.clear();
- mgr.registeredSecurityProviders.clear();
- mgr.requiredSecurityProviders.clear();
- setPrivateField(OsgiManager.class, mgr, "httpService",
Mockito.mock(HttpService.class));
- mgr.updateRegistrationState();
- assertEquals(Collections.singletonList("register"), invocations);
+ // services are registered by default
+ assertEquals("register", invocation.get());
}
- @SuppressWarnings("serial")
@Test
public void testUpdateRegistrationStateSomeRequiredProviders() throws
Exception {
BundleContext bc = mockBundleContext();
@@ -212,186 +201,92 @@ public class OsgiManagerTest {
final List<String> invocations = new ArrayList<String>();
OsgiManager mgr = new OsgiManager(bc) {
@Override
- protected synchronized void registerHttpService() {
+ protected synchronized void registerHttpWhiteboardServices() {
invocations.add("register");
}
@Override
- protected synchronized void unregisterHttpService() {
+ protected synchronized void unregisterHttpWhiteboardServices() {
invocations.add("unregister");
}
};
- // HTTP Service present, some required providers, no registered
providers -> unregister
+ // some required providers, no registered providers -> unregister
invocations.clear();
mgr.registeredSecurityProviders.clear();
- setPrivateField(OsgiManager.class, mgr, "httpService",
Mockito.mock(HttpService.class));
mgr.updateRegistrationState();
assertEquals(Collections.singletonList("unregister"), invocations);
- // HTTP Service present, some required providers, more registered ones
-> register
+ // some required providers, more registered ones -> register
invocations.clear();
mgr.registeredSecurityProviders.addAll(Arrays.asList("foo", "bar",
"blah"));
- setPrivateField(OsgiManager.class, mgr, "httpService",
Mockito.mock(HttpService.class));
mgr.updateRegistrationState();
assertEquals(Collections.singletonList("register"), invocations);
- // HTTP Service present, some required providers, different registered
ones -> unregister
+ // some required providers, different registered ones -> unregister
invocations.clear();
mgr.registeredSecurityProviders.clear();
mgr.registeredSecurityProviders.addAll(Arrays.asList("foo", "bar"));
- setPrivateField(OsgiManager.class, mgr, "httpService",
Mockito.mock(HttpService.class));
mgr.updateRegistrationState();
assertEquals(Collections.singletonList("unregister"), invocations);
- // HTTP Service not present, some required providers, more registered
ones -> unregister
+ // some required providers, more registered ones -> unregister
invocations.clear();
mgr.registeredSecurityProviders.addAll(Arrays.asList("foo", "bar",
"blah"));
- setPrivateField(OsgiManager.class, mgr, "httpService", null);
mgr.updateRegistrationState();
- assertEquals(Collections.singletonList("unregister"), invocations);
+ assertEquals(Collections.singletonList("register"), invocations);
}
- @SuppressWarnings("serial")
- @Test
- public void testBindService() throws Exception {
- BundleContext bc = mockBundleContext();
- final List<Boolean> updateCalled = new ArrayList<Boolean>();
- OsgiManager mgr = new OsgiManager(bc) {
- @Override
- void updateRegistrationState() {
- updateCalled.add(true);
- }
- };
-
- assertEquals("Precondition", 0, updateCalled.size());
-
- HttpService svc = Mockito.mock(HttpService.class);
- mgr.bindHttpService(svc);
- assertSame(svc, getPrivateField(OsgiManager.class, mgr,
"httpService"));
- assertEquals(1, updateCalled.size());
-
- updateCalled.clear();
- mgr.bindHttpService(null);
- assertSame(svc, getPrivateField(OsgiManager.class, mgr,
"httpService"));
- assertEquals(0, updateCalled.size());
- }
-
- @SuppressWarnings("serial")
+ @SuppressWarnings({ "unchecked" })
@Test
- public void testUnbindService() throws Exception {
- BundleContext bc = mockBundleContext();
+ public void testRegisterHttpWhiteboardServices() throws Exception {
+ final BundleContext bc = mockBundleContext();
+ final OsgiManager mgr = new OsgiManager(bc);
- final List<Boolean> updateCalled = new ArrayList<Boolean>();
- final List<Boolean> unregisterCalled = new ArrayList<Boolean>();
- OsgiManager mgr = new OsgiManager(bc) {
- @Override
- void updateRegistrationState() {
- updateCalled.add(true);
- }
-
- @Override
- synchronized void unregisterHttpService() {
- try {
- if (getPrivateField(OsgiManager.class, this,
"httpService") != null) {
- unregisterCalled.add(true);
- }
- } catch (Exception e) {
- }
- }
- };
-
- HttpService svc = Mockito.mock(HttpService.class);
- mgr.bindHttpService(svc);
- assertSame(svc, getPrivateField(OsgiManager.class, mgr,
"httpService"));
- assertEquals(1, updateCalled.size());
- assertEquals(0, unregisterCalled.size());
-
- updateCalled.clear();
- mgr.unbindHttpService(null);
- assertEquals(0, updateCalled.size());
- assertSame(svc, getPrivateField(OsgiManager.class, mgr,
"httpService"));
- assertEquals(0, unregisterCalled.size());
-
- updateCalled.clear();
- // unbind a different service, this should be ignored
- mgr.unbindHttpService(Mockito.mock(HttpService.class));
- assertEquals(0, updateCalled.size());
- assertSame(svc, getPrivateField(OsgiManager.class, mgr,
"httpService"));
- assertEquals(0, unregisterCalled.size());
-
- updateCalled.clear();
- // unbind the bound service, this should remove it
- mgr.unbindHttpService(svc);
- assertEquals(0, updateCalled.size());
- assertEquals(1, unregisterCalled.size());
- assertNull(getPrivateField(OsgiManager.class, mgr, "httpService"));
- }
-
- @Test
- public void testRegisterHttpService() throws Exception {
- BundleContext bc = mockBundleContext();
- OsgiManager mgr = new OsgiManager(bc);
+ Mockito.verify(bc, Mockito.times(1))
+ .registerService(Mockito.eq(WebConsoleSecurityProvider.class),
Mockito.isA(WebConsoleSecurityProvider.class), Mockito.isA(Dictionary.class));
+ Mockito.verify(bc, Mockito.times(1))
+ .registerService(Mockito.eq(ServletContextHelper.class),
Mockito.isA(ServletContextHelper.class), Mockito.isA(Dictionary.class));
+ Mockito.verify(bc, Mockito.times(1))
+ .registerService(Mockito.eq(Servlet.class),
Mockito.isA(Servlet.class), Mockito.isA(Dictionary.class));
- HttpService httpSvc = Mockito.mock(HttpService.class);
- setPrivateField(OsgiManager.class, mgr, "httpService", httpSvc);
-
- assertFalse((Boolean) getPrivateField(OsgiManager.class, mgr,
"httpServletRegistered"));
- assertFalse((Boolean) getPrivateField(OsgiManager.class, mgr,
"httpResourcesRegistered"));
- mgr.registerHttpService();
- assertTrue((Boolean) getPrivateField(OsgiManager.class, mgr,
"httpServletRegistered"));
- assertTrue((Boolean) getPrivateField(OsgiManager.class, mgr,
"httpResourcesRegistered"));
-
- Mockito.verify(httpSvc,
Mockito.times(1)).registerServlet(Mockito.eq("/system/console"),
Mockito.same(mgr),
- Mockito.isA(Dictionary.class),
- Mockito.isA(HttpContext.class));
- Mockito.verify(httpSvc,
Mockito.times(1)).registerResources(Mockito.eq("/system/console/res"),
Mockito.eq("/res"),
- Mockito.isA(HttpContext.class));
-
- mgr.registerHttpService();
+ mgr.registerHttpWhiteboardServices();
// Should not re-register the services, as they were already registered
- Mockito.verify(httpSvc,
Mockito.times(1)).registerServlet(Mockito.eq("/system/console"),
Mockito.same(mgr),
- Mockito.isA(Dictionary.class),
- Mockito.isA(HttpContext.class));
- Mockito.verify(httpSvc,
Mockito.times(1)).registerResources(Mockito.eq("/system/console/res"),
Mockito.eq("/res"),
- Mockito.isA(HttpContext.class));
+ Mockito.verify(bc, Mockito.times(1))
+ .registerService(Mockito.eq(WebConsoleSecurityProvider.class),
Mockito.isA(WebConsoleSecurityProvider.class), Mockito.isA(Dictionary.class));
+ Mockito.verify(bc, Mockito.times(1))
+ .registerService(Mockito.eq(ServletContextHelper.class),
Mockito.isA(ServletContextHelper.class), Mockito.isA(Dictionary.class));
+ Mockito.verify(bc, Mockito.times(1))
+ .registerService(Mockito.eq(Servlet.class),
Mockito.isA(Servlet.class), Mockito.isA(Dictionary.class));
}
+ @SuppressWarnings({ "rawtypes" })
@Test
public void testUnregisterHttpService() throws Exception {
- BundleContext bc = mockBundleContext();
- OsgiManager mgr = new OsgiManager(bc);
-
- HttpService httpSvc = Mockito.mock(HttpService.class);
- setPrivateField(OsgiManager.class, mgr, "httpService", httpSvc);
- setPrivateField(OsgiManager.class, mgr, "httpServletRegistered", true);
- setPrivateField(OsgiManager.class, mgr, "httpResourcesRegistered",
true);
-
- mgr.unregisterHttpService();
- assertFalse((Boolean) getPrivateField(OsgiManager.class, mgr,
"httpServletRegistered"));
- assertFalse((Boolean) getPrivateField(OsgiManager.class, mgr,
"httpResourcesRegistered"));
+ final BundleContext bc = mockBundleContext();
+ final OsgiManager mgr = new OsgiManager(bc);
- Mockito.verify(httpSvc,
Mockito.times(1)).unregister("/system/console");
- Mockito.verify(httpSvc,
Mockito.times(1)).unregister("/system/console/res");
+ final ServiceRegistration reg1 =
Mockito.mock(ServiceRegistration.class);
+ final ServiceRegistration reg2 =
Mockito.mock(ServiceRegistration.class);
- mgr.unregisterHttpService();
- assertFalse((Boolean) getPrivateField(OsgiManager.class, mgr,
"httpServletRegistered"));
- assertFalse((Boolean) getPrivateField(OsgiManager.class, mgr,
"httpResourcesRegistered"));
+ setPrivateField(OsgiManager.class, mgr, "servletContextRegistration",
reg1);
+ setPrivateField(OsgiManager.class, mgr, "servletRegistration", reg2);
- Mockito.verify(httpSvc,
Mockito.times(1)).unregister("/system/console");
- Mockito.verify(httpSvc,
Mockito.times(1)).unregister("/system/console/res");
+ mgr.unregisterHttpWhiteboardServices();
+ assertNull(getPrivateField(OsgiManager.class, mgr,
"servletContextRegistration"));
+ assertNull(getPrivateField(OsgiManager.class, mgr,
"servletRegistration"));
- // Unset the http service
- setPrivateField(OsgiManager.class, mgr, "httpService", null);
+ Mockito.verify(reg1, Mockito.times(1)).unregister();
+ Mockito.verify(reg2, Mockito.times(1)).unregister();
- mgr.unregisterHttpService();
- assertFalse((Boolean) getPrivateField(OsgiManager.class, mgr,
"httpServletRegistered"));
- assertFalse((Boolean) getPrivateField(OsgiManager.class, mgr,
"httpResourcesRegistered"));
+ mgr.unregisterHttpWhiteboardServices();
+ assertNull(getPrivateField(OsgiManager.class, mgr,
"servletContextRegistration"));
+ assertNull(getPrivateField(OsgiManager.class, mgr,
"servletRegistration"));
- Mockito.verify(httpSvc,
Mockito.times(1)).unregister("/system/console");
- Mockito.verify(httpSvc,
Mockito.times(1)).unregister("/system/console/res");
+ Mockito.verify(reg1, Mockito.times(1)).unregister();
+ Mockito.verify(reg2, Mockito.times(1)).unregister();
}
private Object getPrivateField(Class<?> cls, Object obj, String field)
throws Exception {
@@ -429,6 +324,8 @@ public class OsgiManagerTest {
return
Collections.enumeration(Collections.singleton(rbUrl));
}
});
+ Mockito.when(bc.registerService((Class)Mockito.any(),
(Object)Mockito.any(), (Dictionary)Mockito.any()))
+ .thenReturn(Mockito.mock(ServiceRegistration.class));
return bc;
}
}