FELIX-1884 Apply slightly modified patch by Justin Edelson (thanks alot). The modification is that the ConfigurationPrinter output also includes references to the using bundles. Since the new ServicesServlet adds a ConfigurationPrinter for services, the service listing of the ConfigurationRender class is now removed.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@884540 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BundlesServlet.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BundlesServlet.java
index b24f1a5..5315a59 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BundlesServlet.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BundlesServlet.java
@@ -148,7 +148,7 @@
try
{
StringWriter w = new StringWriter();
- writeJSON( w, null, null, true );
+ writeJSON( w, null, null, null, true );
String jsonString = w.toString();
JSONObject json = new JSONObject( jsonString );
@@ -224,7 +224,8 @@
if ( reqInfo.extension.equals("json") )
{
final String pluginRoot = ( String ) request.getAttribute( WebConsoleConstants.ATTR_PLUGIN_ROOT );
- this.renderJSON(response, reqInfo.bundle, pluginRoot);
+ final String servicesRoot = getServicesRoot( request );
+ this.renderJSON(response, reqInfo.bundle, pluginRoot, servicesRoot);
// nothing more to do
return;
@@ -233,7 +234,6 @@
super.doGet( request, response );
}
-
protected void doPost( HttpServletRequest req, HttpServletResponse resp ) throws ServletException, IOException
{
final RequestInfo reqInfo = new RequestInfo(req);
@@ -324,14 +324,20 @@
// we ignore this
}
final String pluginRoot = ( String ) req.getAttribute( WebConsoleConstants.ATTR_PLUGIN_ROOT );
- this.renderJSON(resp, null, pluginRoot);
+ final String servicesRoot = getServicesRoot( req );
+ this.renderJSON(resp, null, pluginRoot, servicesRoot);
}
else
{
super.doPost( req, resp );
}
}
-
+
+ private String getServicesRoot(HttpServletRequest request)
+ {
+ return ( ( String ) request.getAttribute( WebConsoleConstants.ATTR_APP_ROOT ) ) +
+ "/" + ServicesServlet.LABEL + "/";
+ }
private Bundle getBundle( String pathInfo )
{
@@ -418,7 +424,8 @@
Util.startScript( pw );
pw.print( "renderBundles(");
final String pluginRoot = ( String ) request.getAttribute( WebConsoleConstants.ATTR_PLUGIN_ROOT );
- writeJSON(pw, reqInfo.bundle, pluginRoot );
+ final String servicesRoot = getServicesRoot ( request );
+ writeJSON(pw, reqInfo.bundle, pluginRoot, servicesRoot );
pw.println(");" );
Util.endScript( pw );
}
@@ -437,24 +444,26 @@
pw.println( "</form></div");
}
- private void renderJSON( final HttpServletResponse response, final Bundle bundle, final String pluginRoot ) throws IOException
+ private void renderJSON( final HttpServletResponse response, final Bundle bundle, final String pluginRoot, final String servicesRoot )
+ throws IOException
{
response.setContentType( "application/json" );
response.setCharacterEncoding( "UTF-8" );
final PrintWriter pw = response.getWriter();
- writeJSON(pw, bundle, pluginRoot);
+ writeJSON(pw, bundle, pluginRoot, servicesRoot);
}
- private void writeJSON( final PrintWriter pw, final Bundle bundle, final String pluginRoot ) throws IOException
+ private void writeJSON( final PrintWriter pw, final Bundle bundle, final String pluginRoot, final String servicesRoot )
+ throws IOException
{
- writeJSON( pw, bundle, pluginRoot, false );
+ writeJSON( pw, bundle, pluginRoot, servicesRoot, false );
}
private void writeJSON( final Writer pw, final Bundle bundle, final String pluginRoot,
- final boolean fullDetails ) throws IOException
+ final String servicesRoot, final boolean fullDetails ) throws IOException
{
final Bundle[] allBundles = this.getBundles();
final String statusLine = this.getStatusLine(allBundles);
@@ -477,7 +486,7 @@
for ( int i = 0; i < bundles.length; i++ )
{
- bundleInfo( jw, bundles[i], fullDetails || bundle != null, pluginRoot );
+ bundleInfo( jw, bundles[i], fullDetails || bundle != null, pluginRoot, servicesRoot );
}
jw.endArray();
@@ -552,7 +561,8 @@
return buffer.toString();
}
- private void bundleInfo( JSONWriter jw, Bundle bundle, boolean details, final String pluginRoot ) throws JSONException
+ private void bundleInfo( JSONWriter jw, Bundle bundle, boolean details, final String pluginRoot, final String servicesRoot )
+ throws JSONException
{
jw.object();
jw.key( "id" );
@@ -587,7 +597,7 @@
if ( details )
{
- bundleDetails( jw, bundle, pluginRoot );
+ bundleDetails( jw, bundle, pluginRoot, servicesRoot );
}
jw.endObject();
@@ -669,7 +679,8 @@
}
- private void bundleDetails( JSONWriter jw, Bundle bundle, final String pluginRoot ) throws JSONException
+ private void bundleDetails( JSONWriter jw, Bundle bundle, final String pluginRoot, final String servicesRoot)
+ throws JSONException
{
Dictionary headers = bundle.getHeaders();
@@ -705,7 +716,7 @@
listImportExport( jw, bundle, pluginRoot );
}
- listServices( jw, bundle );
+ listServices( jw, bundle, servicesRoot );
listHeaders( jw, bundle );
@@ -944,9 +955,23 @@
}
}
}
+
+ private String getServiceID(ServiceReference ref, final String servicesRoot) {
+ String id = ref.getProperty( Constants.SERVICE_ID ).toString();
+ StringBuffer val = new StringBuffer();
+
+ if ( servicesRoot != null ) {
+ val.append( "<a href='" ).append( servicesRoot ).append( id ).append( "'>" );
+ val.append( id );
+ val.append( "</a>" );
+ return val.toString();
+ } else {
+ return id;
+ }
+ }
- private void listServices( JSONWriter jw, Bundle bundle ) throws JSONException
+ private void listServices( JSONWriter jw, Bundle bundle, final String servicesRoot ) throws JSONException
{
ServiceReference[] refs = bundle.getRegisteredServices();
if ( refs == null || refs.length == 0 )
@@ -956,7 +981,9 @@
for ( int i = 0; i < refs.length; i++ )
{
- String key = "Service ID " + refs[i].getProperty( Constants.SERVICE_ID );
+
+
+ String key = "Service ID " + getServiceID( refs[i], servicesRoot );
JSONArray val = new JSONArray();
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/ServicesServlet.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/ServicesServlet.java
new file mode 100644
index 0000000..7250306
--- /dev/null
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/ServicesServlet.java
@@ -0,0 +1,515 @@
+/*
+ * 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.internal.core;
+
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.text.MessageFormat;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.felix.webconsole.ConfigurationPrinter;
+import org.apache.felix.webconsole.WebConsoleConstants;
+import org.apache.felix.webconsole.internal.BaseWebConsolePlugin;
+import org.apache.felix.webconsole.internal.Util;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.json.JSONWriter;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.log.LogService;
+
+
+public class ServicesServlet extends BaseWebConsolePlugin implements ConfigurationPrinter
+{
+
+ private final class RequestInfo
+ {
+ public final String extension;
+ public final ServiceReference service;
+ public final boolean serviceRequested;
+ public final String pathInfo;
+
+
+ protected RequestInfo( final HttpServletRequest request )
+ {
+ String info = request.getPathInfo();
+ // remove label and starting slash
+ info = info.substring( getLabel().length() + 1 );
+
+ // get extension
+ if ( info.endsWith( ".json" ) )
+ {
+ extension = "json";
+ info = info.substring( 0, info.length() - 5 );
+ }
+ else
+ {
+ extension = "html";
+ }
+
+ // we only accept direct requests to a service if they have a slash
+ // after the label
+ String serviceInfo = null;
+ if ( info.startsWith( "/" ) )
+ {
+ serviceInfo = info.substring( 1 );
+ }
+ if ( serviceInfo == null || serviceInfo.length() == 0 )
+ {
+ service = null;
+ serviceRequested = false;
+ pathInfo = null;
+ }
+ else
+ {
+ service = getServiceById( serviceInfo );
+ serviceRequested = true;
+ pathInfo = serviceInfo;
+ }
+ request.setAttribute( ServicesServlet.class.getName(), this );
+ }
+
+ }
+
+
+ public static RequestInfo getRequestInfo( final HttpServletRequest request )
+ {
+ return ( RequestInfo ) request.getAttribute( ServicesServlet.class.getName() );
+ }
+
+ private ServiceRegistration configurationPrinter;
+
+ public static final String LABEL = "services";
+
+ public static final String TITLE = "Services";
+
+
+ public void activate( BundleContext bundleContext )
+ {
+ super.activate( bundleContext );
+ configurationPrinter = bundleContext.registerService( ConfigurationPrinter.SERVICE, this, null );
+ }
+
+
+ public void deactivate()
+ {
+ if ( configurationPrinter != null )
+ {
+ configurationPrinter.unregister();
+ configurationPrinter = null;
+ }
+
+ super.deactivate();
+ }
+
+
+ public String getLabel()
+ {
+ return LABEL;
+ }
+
+
+ public String getTitle()
+ {
+ return TITLE;
+ }
+
+
+ public void printConfiguration( PrintWriter pw )
+ {
+ try
+ {
+ StringWriter w = new StringWriter();
+ writeJSON( w, null, true );
+ String jsonString = w.toString();
+ JSONObject json = new JSONObject( jsonString );
+
+ pw.println( "Status: " + json.get( "status" ) );
+ pw.println();
+
+ JSONArray data = json.getJSONArray( "data" );
+ for ( int i = 0; i < data.length(); i++ )
+ {
+ if ( !data.isNull( i ) )
+ {
+ JSONObject service = data.getJSONObject( i );
+
+ pw.println( MessageFormat.format( "Service {0} - {1} (pid: {2})", new Object[]
+ { service.get( "id" ), service.get( "types" ), service.get( "pid" ) } ) );
+ pw.println( MessageFormat.format( " from Bundle {0} - {1} ({2}), version {3}", new Object[]
+ { service.get( "bundleId" ), service.get( "bundleName" ), service.get( "bundleSymbolicName" ),
+ service.get( "bundleVersion" ) } ) );
+
+ JSONArray props = service.getJSONArray( "props" );
+ for ( int pi = 0; pi < props.length(); pi++ )
+ {
+ if ( !props.isNull( pi ) )
+ {
+ JSONObject entry = props.getJSONObject( pi );
+
+ pw.print( " " + entry.get( "key" ) + ": " );
+
+ Object entryValue = entry.get( "value" );
+ if ( entryValue instanceof JSONArray )
+ {
+ pw.println();
+ JSONArray entryArray = ( JSONArray ) entryValue;
+ for ( int ei = 0; ei < entryArray.length(); ei++ )
+ {
+ if ( !entryArray.isNull( ei ) )
+ {
+ pw.println( " " + entryArray.get( ei ) );
+ }
+ }
+ }
+ else
+ {
+ pw.println( entryValue );
+ }
+ }
+ }
+
+ JSONArray usingBundles = service.getJSONArray( "usingBundles" );
+ for ( int ui = 0; ui < usingBundles.length(); ui++ )
+ {
+ if ( !usingBundles.isNull( ui ) )
+ {
+ JSONObject bundle = usingBundles.getJSONObject( ui );
+ pw.println( MessageFormat.format( " Using Bundle {0} - {1} ({2}), version {3}", new Object[]
+ { bundle.get( "bundleId" ), bundle.get( "bundleName" ),
+ bundle.get( "bundleSymbolicName" ), bundle.get( "bundleVersion" ) } ) );
+ }
+ }
+
+ pw.println();
+ }
+ }
+ }
+ catch ( Exception e )
+ {
+ getLog().log( LogService.LOG_ERROR, "Problem rendering Bundle details for configuration status", e );
+ }
+ }
+
+
+ private void appendServiceInfoCount( final StringBuffer buf, String msg, int count )
+ {
+ buf.append( count );
+ buf.append( " service" );
+ if ( count != 1 )
+ buf.append( 's' );
+ buf.append( ' ' );
+ buf.append( msg );
+ }
+
+
+ private ServiceReference getServiceById( String pathInfo )
+ {
+ // only use last part of the pathInfo
+ pathInfo = pathInfo.substring( pathInfo.lastIndexOf( '/' ) + 1 );
+
+ StringBuffer filter = new StringBuffer();
+ filter.append( "(" ).append( Constants.SERVICE_ID ).append( "=" );
+ filter.append( pathInfo ).append( ")" );
+ String filterStr = filter.toString();
+ try
+ {
+ ServiceReference[] refs = getBundleContext().getServiceReferences( null, filterStr );
+ if ( refs == null || refs.length != 1 )
+ {
+ return null;
+ }
+ return refs[0];
+ }
+ catch ( InvalidSyntaxException e )
+ {
+ getLog().log( LogService.LOG_WARNING, "Unable to search for services using filter " + filterStr, e );
+ // this shouldn't happen
+ return null;
+ }
+ }
+
+
+ private ServiceReference[] getServices()
+ {
+ try
+ {
+ return getBundleContext().getServiceReferences( null, null );
+ }
+ catch ( InvalidSyntaxException e )
+ {
+ getLog().log( LogService.LOG_WARNING, "Unable to access service reference list.", e );
+ return new ServiceReference[0];
+ }
+ }
+
+
+ private String getStatusLine( final ServiceReference[] services )
+ {
+ final StringBuffer buffer = new StringBuffer();
+ buffer.append( "Services information: " );
+ appendServiceInfoCount( buffer, "in total", services.length );
+ return buffer.toString();
+ }
+
+
+ private void keyVal( JSONWriter jw, String key, Object value ) throws JSONException
+ {
+ if ( key != null && value != null )
+ {
+ jw.object();
+ jw.key( "key" );
+ jw.value( key );
+ jw.key( "value" );
+ jw.value( value );
+ jw.endObject();
+ }
+ }
+
+
+ private String propertyAsString( ServiceReference ref, String name )
+ {
+ Object value = ref.getProperty( name );
+ if ( value instanceof Object[] )
+ {
+ StringBuffer dest = new StringBuffer();
+ Object[] values = ( Object[] ) value;
+ for ( int j = 0; j < values.length; j++ )
+ {
+ if ( j > 0 )
+ dest.append( ", " );
+ dest.append( values[j] );
+ }
+ return dest.toString();
+ }
+ else if ( value != null )
+ {
+ return value.toString();
+ }
+ else
+ {
+ return "n/a";
+ }
+ }
+
+
+ private void renderJSON( final HttpServletResponse response, final ServiceReference service )
+ throws IOException
+ {
+ response.setContentType( "application/json" );
+ response.setCharacterEncoding( "UTF-8" );
+
+ final PrintWriter pw = response.getWriter();
+ writeJSON( pw, service );
+ }
+
+
+ private void serviceDetails( JSONWriter jw, ServiceReference service ) throws JSONException
+ {
+ String[] keys = service.getPropertyKeys();
+
+ jw.key( "props" );
+ jw.array();
+
+ for ( int i = 0; i < keys.length; i++ )
+ {
+ String key = keys[i];
+ if ( Constants.SERVICE_PID.equals( key ) )
+ {
+ keyVal( jw, "Service PID", service.getProperty( key ) );
+ }
+ else if ( Constants.SERVICE_DESCRIPTION.equals( key ) )
+ {
+ keyVal( jw, "Service Description", service.getProperty( key ) );
+ }
+ else if ( Constants.SERVICE_VENDOR.equals( key ) )
+ {
+ keyVal( jw, "Service Vendor", service.getProperty( key ) );
+ }
+ else if ( !Constants.OBJECTCLASS.equals( key ) && !Constants.SERVICE_ID.equals( key ) )
+ {
+ keyVal( jw, key, service.getProperty( key ) );
+ }
+
+ }
+
+ jw.endArray();
+
+ }
+
+
+ private void usingBundles( JSONWriter jw, ServiceReference service ) throws JSONException
+ {
+ jw.key( "usingBundles" );
+ jw.array();
+
+ Bundle[] usingBundles = service.getUsingBundles();
+ if ( usingBundles != null )
+ {
+ for ( int i = 0; i < usingBundles.length; i++ )
+ {
+ jw.object();
+ bundleInfo( jw, usingBundles[i] );
+ jw.endObject();
+ }
+ }
+
+ jw.endArray();
+
+ }
+
+
+ private void serviceInfo( JSONWriter jw, ServiceReference service, boolean details ) throws JSONException
+ {
+ jw.object();
+ jw.key( "id" );
+ jw.value( propertyAsString( service, Constants.SERVICE_ID ) );
+ jw.key( "types" );
+ jw.value( propertyAsString( service, Constants.OBJECTCLASS ) );
+ jw.key( "pid" );
+ jw.value( propertyAsString( service, Constants.SERVICE_PID ) );
+
+ bundleInfo( jw, service.getBundle() );
+
+ if ( details )
+ {
+ serviceDetails( jw, service );
+ usingBundles( jw, service );
+ }
+
+ jw.endObject();
+ }
+
+
+ private void bundleInfo( final JSONWriter jw, final Bundle bundle ) throws JSONException
+ {
+ jw.key( "bundleId" );
+ jw.value( bundle.getBundleId() );
+ jw.key( "bundleName" );
+ jw.value( Util.getName( bundle ) );
+ jw.key( "bundleVersion" );
+ jw.value( Util.getHeaderValue( bundle, Constants.BUNDLE_VERSION ) );
+ jw.key( "bundleSymbolicName" );
+ jw.value( Util.getHeaderValue( bundle, Constants.BUNDLE_SYMBOLICNAME ) );
+ }
+
+
+ private void writeJSON( final PrintWriter pw, final ServiceReference service ) throws IOException
+ {
+ writeJSON( pw, service, false );
+ }
+
+
+ private void writeJSON( final Writer pw, final ServiceReference service, final boolean fullDetails )
+ throws IOException
+ {
+ final ServiceReference[] allServices = this.getServices();
+ final String statusLine = this.getStatusLine( allServices );
+ final ServiceReference[] services = ( service != null ) ? new ServiceReference[]
+ { service } : allServices;
+
+ final JSONWriter jw = new JSONWriter( pw );
+
+ try
+ {
+ jw.object();
+
+ jw.key( "status" );
+ jw.value( statusLine );
+
+ jw.key( "data" );
+
+ jw.array();
+
+ for ( int i = 0; i < services.length; i++ )
+ {
+ serviceInfo( jw, services[i], fullDetails || service != null );
+ }
+
+ jw.endArray();
+
+ jw.endObject();
+
+ }
+ catch ( JSONException je )
+ {
+ throw new IOException( je.toString() );
+ }
+
+ }
+
+
+ protected void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException,
+ IOException
+ {
+ final RequestInfo reqInfo = new RequestInfo( request );
+ if ( reqInfo.service == null && reqInfo.serviceRequested )
+ {
+ response.sendError( 404 );
+ return;
+ }
+ if ( reqInfo.extension.equals( "json" ) )
+ {
+ this.renderJSON( response, reqInfo.service );
+
+ // nothing more to do
+ return;
+ }
+
+ super.doGet( request, response );
+ }
+
+
+ protected void renderContent( HttpServletRequest request, HttpServletResponse response ) throws ServletException,
+ IOException
+ {
+ // get request info from request attribute
+ final RequestInfo reqInfo = getRequestInfo( request );
+ final PrintWriter pw = response.getWriter();
+
+ final String appRoot = ( String ) request.getAttribute( WebConsoleConstants.ATTR_APP_ROOT );
+
+ Util.startScript( pw );
+ pw.println( "var imgRoot = '" + appRoot + "/res/imgs';" );
+ pw.println( "var bundlePath = '" + appRoot + "/" + BundlesServlet.NAME + "/" + "';" );
+ pw.println( "var drawDetails = " + reqInfo.serviceRequested + ";" );
+ Util.endScript( pw );
+
+ Util.script( pw, appRoot, "services.js" );
+
+ pw.println( "<div id='plugin_content'/>" );
+ Util.startScript( pw );
+ pw.print( "renderServices(" );
+ writeJSON( pw, reqInfo.service );
+ pw.println( ");" );
+ Util.endScript( pw );
+
+ }
+}
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/ConfigurationRender.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/ConfigurationRender.java
index 5da56b6..b731941 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/ConfigurationRender.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/misc/ConfigurationRender.java
@@ -24,10 +24,8 @@
import java.text.DateFormat;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
-import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
-import java.util.Dictionary;
import java.util.Iterator;
import java.util.Locale;
import java.util.Properties;
@@ -46,10 +44,6 @@
import org.apache.felix.webconsole.WebConsoleConstants;
import org.apache.felix.webconsole.internal.BaseWebConsolePlugin;
import org.apache.felix.webconsole.internal.Util;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.Constants;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
@@ -189,7 +183,6 @@
private void printConfigurationStatus( ConfigurationWriter pw )
{
this.printSystemProperties( pw );
- this.printServices( pw );
this.printThreads( pw );
for ( Iterator cpi = getConfigurationPrinters().iterator(); cpi.hasNext(); )
@@ -277,60 +270,6 @@
// }
- private void printServices( ConfigurationWriter pw )
- {
- pw.title( "Services" );
-
- // get the list of services sorted by service ID (ascending)
- SortedMap srMap = new TreeMap();
- try
- {
- ServiceReference[] srs = getBundleContext().getAllServiceReferences( null, null );
- for ( int i = 0; i < srs.length; i++ )
- {
- srMap.put( srs[i].getProperty( Constants.SERVICE_ID ), srs[i] );
- }
- }
- catch ( InvalidSyntaxException ise )
- {
- // should handle, for now just print nothing, actually this is not
- // expected
- }
-
- for ( Iterator si = srMap.values().iterator(); si.hasNext(); )
- {
- ServiceReference sr = ( ServiceReference ) si.next();
-
- infoLine( pw, null, String.valueOf( sr.getProperty( Constants.SERVICE_ID ) ), sr
- .getProperty( Constants.OBJECTCLASS ) );
- infoLine( pw, " ", "Bundle", this.getBundleString( sr.getBundle() ) );
-
- Bundle[] users = sr.getUsingBundles();
- if ( users != null && users.length > 0 )
- {
- for ( int i = 0; i < users.length; i++ )
- {
- infoLine( pw, " ", "Using Bundle", this.getBundleString( users[i] ) );
- }
- }
-
- String[] keys = sr.getPropertyKeys();
- Arrays.sort( keys );
- for ( int i = 0; i < keys.length; i++ )
- {
- if ( !Constants.SERVICE_ID.equals( keys[i] ) && !Constants.OBJECTCLASS.equals( keys[i] ) )
- {
- infoLine( pw, " ", keys[i], sr.getProperty( keys[i] ) );
- }
- }
-
- pw.println();
- }
-
- pw.end();
- }
-
-
private void printConfigurationPrinter( ConfigurationWriter pw, ConfigurationPrinter cp )
{
pw.title( cp.getTitle() );
@@ -349,79 +288,37 @@
if ( label != null )
{
pw.print( label );
- pw.print( '=' );
+ pw.print( " = " );
}
- printObject( pw, value );
+ pw.print( asString( value ) );
pw.println();
}
- private static void printObject( PrintWriter pw, Object value )
+ private static String asString( final Object value )
{
if ( value == null )
{
- pw.print( "null" );
+ return "n/a";
}
else if ( value.getClass().isArray() )
{
- printArray( pw, ( Object[] ) value );
- }
- else
- {
- pw.print( value );
- }
- }
-
-
- private static void printArray( PrintWriter pw, Object[] values )
- {
- pw.print( '[' );
- if ( values != null && values.length > 0 )
- {
- for ( int i = 0; i < values.length; i++ )
+ StringBuffer dest = new StringBuffer();
+ Object[] values = ( Object[] ) value;
+ for ( int j = 0; j < values.length; j++ )
{
- if ( i > 0 )
- {
- pw.print( ", " );
- }
- printObject( pw, values[i] );
+ if ( j > 0 )
+ dest.append( ", " );
+ dest.append( values[j] );
}
- }
- pw.print( ']' );
- }
-
-
- private String getBundleString( Bundle bundle )
- {
- StringBuffer buf = new StringBuffer();
-
- if ( bundle.getSymbolicName() != null )
- {
- buf.append( bundle.getSymbolicName() );
- }
- else if ( bundle.getLocation() != null )
- {
- buf.append( bundle.getLocation() );
+ return dest.toString();
}
else
{
- buf.append( bundle.getBundleId() );
+ return value.toString();
}
-
- Dictionary headers = bundle.getHeaders();
- if ( headers.get( Constants.BUNDLE_VERSION ) != null )
- {
- buf.append( " (" ).append( headers.get( Constants.BUNDLE_VERSION ) ).append( ')' );
- }
-
- if ( headers.get( Constants.BUNDLE_NAME ) != null )
- {
- buf.append( " \"" ).append( headers.get( Constants.BUNDLE_NAME ) ).append( '"' );
- }
-
- return buf.toString();
}
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 cc32455..cdb3883 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
@@ -103,6 +103,7 @@
"org.apache.felix.webconsole.internal.compendium.LogServlet",
"org.apache.felix.webconsole.internal.compendium.PreferencesConfigurationPrinter",
"org.apache.felix.webconsole.internal.core.BundlesServlet",
+ "org.apache.felix.webconsole.internal.core.ServicesServlet",
"org.apache.felix.webconsole.internal.core.InstallAction",
"org.apache.felix.webconsole.internal.core.SetStartLevelAction",
"org.apache.felix.webconsole.internal.deppack.DepPackServlet",
diff --git a/webconsole/src/main/resources/res/ui/services.js b/webconsole/src/main/resources/res/ui/services.js
new file mode 100644
index 0000000..29691e5
--- /dev/null
+++ b/webconsole/src/main/resources/res/ui/services.js
@@ -0,0 +1,199 @@
+/*
+ * 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.
+ */
+function renderStatusLine() {
+ $("#plugin_content").append(
+ "<div class='fullwidth'><div class='statusline'/></div>");
+}
+
+function renderView( /* Array of String */columns) {
+ renderStatusLine();
+ var txt = "<div class='table'><table id='plugin_table' class='tablelayout'><thead><tr>";
+ for ( var name in columns) {
+ txt = txt + "<th class='col_" + columns[name] + "'>" + columns[name]
+ + "</th>";
+ }
+ txt = txt + "</tr></thead><tbody></tbody></table></div>";
+ $("#plugin_content").append(txt);
+ renderStatusLine();
+}
+
+function renderData(eventData) {
+ $(".statusline").empty().append(eventData.status);
+ $("#plugin_table > tbody > tr").remove();
+ for ( var idx in eventData.data) {
+ entry(eventData.data[idx]);
+ }
+ $("#plugin_table").trigger("update");
+ if (drawDetails) {
+ renderDetails(eventData);
+ }
+}
+
+function entry( /* Object */dataEntry) {
+ var trElement = tr(null, {
+ id : "entry" + dataEntry.id
+ });
+ entryInternal(trElement, dataEntry);
+ $("#plugin_table > tbody").append(trElement);
+}
+
+function entryInternal( /* Element */parent, /* Object */dataEntry) {
+ var id = dataEntry.id;
+ var name = dataEntry.id;
+
+ var inputElement = createElement("img", "rightButton", {
+ src : appRoot + "/res/imgs/arrow_right.png",
+ style : {
+ border : "none"
+ },
+ id : 'img' + id,
+ title : "Details",
+ alt : "Details",
+ width : 14,
+ height : 14
+ });
+ $(inputElement).click(function() {
+ showDetails(id)
+ });
+ var titleElement;
+ if (drawDetails) {
+ titleElement = text(name);
+ } else {
+ titleElement = createElement("a", null, {
+ href : window.location.pathname + "/" + id
+ });
+ titleElement.appendChild(text(name));
+ }
+ var bundleElement = createElement("a", null, {
+ href : bundlePath + dataEntry.bundleId
+ });
+ bundleElement.appendChild(text(dataEntry.bundleSymbolicName + " ("
+ + dataEntry.bundleId + ")"));
+
+ parent
+ .appendChild(td(null, null,
+ [ inputElement, text(" "), titleElement ]));
+ parent.appendChild(td(null, null, [ text(dataEntry.types) ]));
+ parent.appendChild(td(null, null, [ bundleElement ]));
+}
+
+function showDetails(id) {
+ $.get(pluginRoot + "/" + id + ".json", null, function(data) {
+ renderDetails(data);
+ }, "json");
+}
+
+function hideDetails(id) {
+ $("#img" + id).each(function() {
+ $("#pluginInlineDetails").remove();
+ $(this).attr("src", appRoot + "/res/imgs/arrow_right.png");
+ $(this).attr("title", "Details");
+ $(this).attr("alt", "Details");
+ $(this).unbind('click').click(function() {
+ showDetails(id)
+ });
+ });
+}
+
+function renderDetails(data) {
+ data = data.data[0];
+ $("#pluginInlineDetails").remove();
+ $("#entry" + data.id + " > td").eq(1).append(
+ "<div id='pluginInlineDetails'/>");
+ $("#img" + data.id).each(function() {
+ if (drawDetails) {
+ $(this).attr("src", appRoot + "/res/imgs/arrow_left.png");
+ $(this).attr("title", "Back");
+ $(this).attr("alt", "Back");
+ var ref = window.location.pathname;
+ ref = ref.substring(0, ref.lastIndexOf('/'));
+ $(this).unbind('click').click(function() {
+ window.location = ref;
+ });
+ } else {
+ $(this).attr("src", appRoot + "/res/imgs/arrow_down.png");
+ $(this).attr("title", "Hide Details");
+ $(this).attr("alt", "Hide Details");
+ $(this).unbind('click').click(function() {
+ hideDetails(data.id)
+ });
+ }
+ });
+ $("#pluginInlineDetails").append(
+ "<table border='0'><tbody></tbody></table>");
+ var details = data.props;
+ for ( var idx in details) {
+ var prop = details[idx];
+
+ var txt = "<tr><td class='aligntop' noWrap='true' style='border:0px none'>"
+ + prop.key
+ + "</td><td class='aligntop' style='border:0px none'>";
+ if (prop.value) {
+ if ($.isArray(prop.value)) {
+ var i = 0;
+ for ( var pi in prop.value) {
+ var value = prop.value[pi];
+ if (i > 0) {
+ txt = txt + "<br/>";
+ }
+ var span;
+ if (value.substring(0, 6) == "INFO: ") {
+ txt = txt + "<span style='color: grey;'>!!"
+ + value.substring(5) + "</span>";
+ } else if (value.substring(0, 7) == "ERROR: ") {
+ txt = txt + "<span style='color: red;'>!!"
+ + value.substring(6) + "</span>";
+ } else {
+ txt = txt + value;
+ }
+ i++;
+ }
+ } else {
+ txt = txt + prop.value;
+ }
+ } else {
+ txt = txt + "\u00a0";
+ }
+ txt = txt + "</td></tr>";
+ $("#pluginInlineDetails > table > tbody").append(txt);
+
+ }
+}
+
+function renderServices(data) {
+ $(document).ready(function() {
+ renderView( [ "Id", "Type(s)", "Bundle" ]);
+ renderData(data);
+
+ var extractMethod = function(node) {
+ var link = node.getElementsByTagName("a");
+ if (link && link.length == 1) {
+ return link[0].innerHTML;
+ }
+ return node.innerHTML;
+ };
+ $("#plugin_table").tablesorter( {
+ headers : {
+ 0 : {
+ sorter : "digit"
+ }
+ },
+ sortList : [ [ 1, 0 ] ],
+ textExtraction : extractMethod
+ });
+ });
+}
\ No newline at end of file