FELIX-566 Support restful URLs for Configuration support
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@668622 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/AjaxConfigManagerAction.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/AjaxConfigManagerAction.java
deleted file mode 100644
index d19eda2..0000000
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/AjaxConfigManagerAction.java
+++ /dev/null
@@ -1,544 +0,0 @@
-/*
- * 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.compendium;
-
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.lang.reflect.Array;
-import java.util.Arrays;
-import java.util.Dictionary;
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Properties;
-import java.util.StringTokenizer;
-import java.util.Vector;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.felix.webconsole.Action;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONWriter;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.Constants;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.Version;
-import org.osgi.service.cm.Configuration;
-import org.osgi.service.cm.ConfigurationAdmin;
-import org.osgi.service.metatype.AttributeDefinition;
-import org.osgi.service.metatype.ObjectClassDefinition;
-
-
-/**
- * The <code>AjaxConfigManagerAction</code> TODO
- */
-public class AjaxConfigManagerAction extends ConfigManagerBase implements Action
-{
-
- public static final String NAME = "ajaxConfigManager";
-
-
- public String getName()
- {
- return NAME;
- }
-
-
- public String getLabel()
- {
- return NAME;
- }
-
-
- public boolean performAction( HttpServletRequest request, HttpServletResponse response ) throws IOException
- {
-
- // needed multiple times below
- String pid = request.getParameter( ConfigManager.PID );
- ConfigurationAdmin ca = this.getConfigurationAdmin();
-
- // ignore this request if the pid and/or configuration admin is missing
- if (pid == null || ca == null) {
- // should log this here !!
- return true;
- }
-
- // the configuration to operate on (to be created or "missing")
- Configuration config = null;
-
- // should actually apply the configuration before redirecting
- if ( request.getParameter( "create" ) != null && pid != null )
- {
- if ( ca != null )
- {
- config = ca.createFactoryConfiguration( pid, null );
- pid = config.getPid();
- }
- }
- else if ( request.getParameter( "apply" ) != null )
- {
- return applyConfiguration( request );
- }
-
- if (config == null) {
- try
- {
- // we use listConfigurations to not create configuration
- // objects persistently without the user providing actual
- // configuration
- Configuration[] configs = ca.listConfigurations( "(" + Constants.SERVICE_PID + "=" + pid + ")" );
- if ( configs != null && configs.length > 0 )
- {
- config = configs[0];
- }
- }
- catch ( InvalidSyntaxException ise )
- {
- // should print message
- }
- }
-
- // send the result
- response.setContentType( "text/javascript" );
- response.setCharacterEncoding( "UTF-8" );
-
- JSONWriter result = new JSONWriter( response.getWriter() );
-
- if ( pid != null )
- {
- try
- {
- result.object();
- this.configForm( result, pid, config, getLocale( request ) );
- result.endObject();
- }
- catch ( Exception e )
- {
- // add message
- }
- }
-
- return false;
- }
-
-
- private void configForm( JSONWriter json, String pid, Configuration config, Locale loc ) throws IOException,
- JSONException
- {
- String locale = ( loc == null ) ? null : loc.toString();
-
- json.key( ConfigManager.PID );
- json.value( pid );
-
- Dictionary props = null;
- ObjectClassDefinition ocd;
- if ( config != null )
- {
- props = config.getProperties();
- ocd = this.getObjectClassDefinition( config, locale );
- }
- else
- {
- ocd = this.getObjectClassDefinition( pid, locale );
- }
-
- props = this.mergeWithMetaType( props, ocd, json );
-
- if ( props != null )
- {
-
- json.key( "title" );
- json.value( pid );
- json.key( "description" );
- json
- .value( "Please enter configuration properties for this configuration in the field below. This configuration has no associated description" );
-
- json.key( "propertylist" );
- json.value( "properties" );
-
- json.key( "properties" );
- json.object();
- for ( Enumeration pe = props.keys(); pe.hasMoreElements(); )
- {
- Object key = pe.nextElement();
-
- // ignore well known special properties
- if ( !key.equals( Constants.SERVICE_PID ) && !key.equals( Constants.SERVICE_DESCRIPTION )
- && !key.equals( Constants.SERVICE_ID ) && !key.equals( Constants.SERVICE_RANKING )
- && !key.equals( Constants.SERVICE_VENDOR )
- && !key.equals( ConfigurationAdmin.SERVICE_BUNDLELOCATION )
- && !key.equals( ConfigurationAdmin.SERVICE_FACTORYPID ) )
- {
- json.key( String.valueOf( key ) );
- json.value( props.get( key ) );
- }
- }
- json.endObject();
-
- }
-
- if ( config != null )
- {
- this.addConfigurationInfo( config, json, locale );
- }
- }
-
-
- private Dictionary mergeWithMetaType( Dictionary props, ObjectClassDefinition ocd, JSONWriter json )
- throws JSONException
- {
-
- if ( props == null )
- {
- props = new Hashtable();
- }
-
- if ( ocd != null )
- {
-
- json.key( "title" );
- json.value( ocd.getName() );
-
- if ( ocd.getDescription() != null )
- {
- json.key( "description" );
- json.value( ocd.getDescription() );
- }
-
- AttributeDefinition[] ad = ocd.getAttributeDefinitions( ObjectClassDefinition.ALL );
- if ( ad != null )
- {
-
- JSONArray propertyList = new JSONArray();
-
- for ( int i = 0; i < ad.length; i++ )
- {
- json.key( ad[i].getID() );
- json.object();
-
- Object value = props.get( ad[i].getID() );
- if ( value == null )
- {
- value = ad[i].getDefaultValue();
- if ( value == null )
- {
- if ( ad[i].getCardinality() == 0 )
- {
- value = "";
- }
- else
- {
- value = new String[0];
- }
- }
- }
-
- json.key( "name" );
- json.value( ad[i].getName() );
-
- json.key( "type" );
- if ( ad[i].getOptionLabels() != null && ad[i].getOptionLabels().length > 0 )
- {
- json.object();
- json.key( "labels" );
- json.value( Arrays.asList( ad[i].getOptionLabels() ) );
- json.key( "values" );
- json.value( Arrays.asList( ad[i].getOptionValues() ) );
- json.endObject();
- }
- else
- {
- json.value( ad[i].getType() );
- }
-
- if ( ad[i].getCardinality() == 0 )
- {
- // scalar
- if ( value instanceof Vector )
- {
- value = ( ( Vector ) value ).get( 0 );
- }
- else if ( value.getClass().isArray() )
- {
- value = Array.get( value, 0 );
- }
- json.key( "value" );
- json.value( value );
- }
- else
- {
- if ( value instanceof Vector )
- {
- value = new JSONArray( ( Vector ) value );
- }
- else if ( value.getClass().isArray() )
- {
- value = new JSONArray( Arrays.asList( ( Object[] ) value ) );
- }
- else
- {
- JSONArray tmp = new JSONArray();
- tmp.put( value );
- value = tmp;
- }
- json.key( "values" );
- json.value( value );
- }
-
- if ( ad[i].getDescription() != null )
- {
- json.key( "description" );
- json.value( ad[i].getDescription() );
- }
-
- json.endObject();
- propertyList.put( ad[i].getID() );
- }
-
- json.key( "propertylist" );
- json.value( propertyList );
- }
-
- // nothing more to display
- props = null;
- }
-
- return props;
- }
-
-
- private void addConfigurationInfo( Configuration config, JSONWriter json, String locale ) throws JSONException
- {
-
- if ( config.getFactoryPid() != null )
- {
- json.key( "factoryPID" );
- json.value( config.getFactoryPid() );
- }
-
- String location;
- if ( config.getBundleLocation() == null )
- {
- location = "None";
- }
- else
- {
- Bundle bundle = this.getBundle( config.getBundleLocation() );
-
- Dictionary headers = bundle.getHeaders( locale );
- String name = ( String ) headers.get( Constants.BUNDLE_NAME );
- if ( name == null )
- {
- location = bundle.getSymbolicName();
- }
- else
- {
- location = name + " (" + bundle.getSymbolicName() + ")";
- }
-
- Version v = Version.parseVersion( ( String ) headers.get( Constants.BUNDLE_VERSION ) );
- location += ", Version " + v.toString();
- }
- json.key( "bundleLocation" );
- json.value( location );
- }
-
-
- private boolean applyConfiguration( HttpServletRequest request ) throws IOException
- {
-
- ConfigurationAdmin ca = this.getConfigurationAdmin();
- if ( ca == null )
- {
- return false;
- }
-
- String pid = request.getParameter( "pid" );
-
- if ( request.getParameter( "delete" ) != null )
- {
- // TODO: should log this here !!
- Configuration config = ca.getConfiguration( pid, null );
- config.delete();
- return true;
- }
-
- String propertyList = request.getParameter( "propertylist" );
- if ( propertyList == null )
- {
- String propertiesString = request.getParameter( "properties" );
-
- if ( propertiesString != null )
- {
- byte[] propBytes = propertiesString.getBytes( "ISO-8859-1" );
- ByteArrayInputStream bin = new ByteArrayInputStream( propBytes );
- Properties props = new Properties();
- props.load( bin );
-
- Configuration config = ca.getConfiguration( pid, null );
- config.update( props );
- }
- }
- else
- {
- Configuration config = ca.getConfiguration( pid, null );
- Dictionary props = config.getProperties();
- if ( props == null )
- {
- props = new Hashtable();
- }
-
- Map adMap = ( Map ) this.getAttributeDefinitionMap( config, null );
- if ( adMap != null )
- {
- StringTokenizer propTokens = new StringTokenizer( propertyList, "," );
- while ( propTokens.hasMoreTokens() )
- {
- String propName = propTokens.nextToken();
- AttributeDefinition ad = ( AttributeDefinition ) adMap.get( propName );
- if ( ad == null || ( ad.getCardinality() == 0 && ad.getType() == AttributeDefinition.STRING ) )
- {
- String prop = request.getParameter( propName );
- if ( prop != null )
- {
- props.put( propName, prop );
- }
- }
- else if ( ad.getCardinality() == 0 )
- {
- // scalar of non-string
- String prop = request.getParameter( propName );
- props.put( propName, this.toType( ad.getType(), prop ) );
- }
- else
- {
- // array or vector of any type
- Vector vec = new Vector();
-
- String[] properties = request.getParameterValues( propName );
- if ( properties != null )
- {
- for ( int i = 0; i < properties.length; i++ )
- {
- vec.add( this.toType( ad.getType(), properties[i] ) );
- }
- }
-
- // but ensure size
- int maxSize = Math.abs( ad.getCardinality() );
- if ( vec.size() > maxSize )
- {
- vec.setSize( maxSize );
- }
-
- if ( ad.getCardinality() < 0 )
- {
- // keep the vector
- props.put( propName, vec );
- }
- else
- {
- // convert to an array
- props.put( propName, this.toArray( ad.getType(), vec ) );
- }
- }
- }
- }
-
- config.update( props );
- }
-
- // request.setAttribute(ATTR_REDIRECT_PARAMETERS, "pid=" + pid);
- return true;
- }
-
-
- private Object toType( int type, String value )
- {
- switch ( type )
- {
- case AttributeDefinition.BOOLEAN:
- return Boolean.valueOf( value );
- case AttributeDefinition.BYTE:
- return Byte.valueOf( value );
- case AttributeDefinition.CHARACTER:
- char c = ( value.length() > 0 ) ? value.charAt( 0 ) : 0;
- return new Character( c );
- case AttributeDefinition.DOUBLE:
- return Double.valueOf( value );
- case AttributeDefinition.FLOAT:
- return Float.valueOf( value );
- case AttributeDefinition.LONG:
- return Long.valueOf( value );
- case AttributeDefinition.INTEGER:
- return Integer.valueOf( value );
- case AttributeDefinition.SHORT:
- return Short.valueOf( value );
-
- default:
- // includes AttributeDefinition.STRING
- return value;
- }
- }
-
-
- private Object toArray( int type, Vector values )
- {
- int size = values.size();
-
- // short cut for string array
- if ( type == AttributeDefinition.STRING )
- {
- return values.toArray( new String[size] );
- }
-
- Object array;
- switch ( type )
- {
- case AttributeDefinition.BOOLEAN:
- array = new boolean[size];
- case AttributeDefinition.BYTE:
- array = new byte[size];
- case AttributeDefinition.CHARACTER:
- array = new char[size];
- case AttributeDefinition.DOUBLE:
- array = new double[size];
- case AttributeDefinition.FLOAT:
- array = new float[size];
- case AttributeDefinition.LONG:
- array = new long[size];
- case AttributeDefinition.INTEGER:
- array = new int[size];
- case AttributeDefinition.SHORT:
- array = new short[size];
- default:
- // unexpected, but assume string
- array = new String[size];
- }
-
- for ( int i = 0; i < size; i++ )
- {
- Array.set( array, i, values.get( i ) );
- }
-
- return array;
- }
-}
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ConfigManager.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ConfigManager.java
index a925fc2..08bd8ee 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ConfigManager.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ConfigManager.java
@@ -17,31 +17,49 @@
package org.apache.felix.webconsole.internal.compendium;
+import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.PrintWriter;
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
import java.util.Iterator;
import java.util.Locale;
+import java.util.Map;
+import java.util.Properties;
import java.util.SortedMap;
+import java.util.StringTokenizer;
import java.util.TreeMap;
+import java.util.Vector;
import java.util.Map.Entry;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.apache.felix.webconsole.Render;
+import org.apache.felix.webconsole.internal.Util;
+import org.apache.felix.webconsole.internal.servlet.OsgiManager;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONWriter;
+import org.osgi.framework.Bundle;
import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
+import org.osgi.framework.Version;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.cm.ManagedService;
import org.osgi.service.cm.ManagedServiceFactory;
+import org.osgi.service.metatype.AttributeDefinition;
import org.osgi.service.metatype.ObjectClassDefinition;
/**
* The <code>ConfigManager</code> TODO
*/
-public class ConfigManager extends ConfigManagerBase implements Render
+public class ConfigManager extends ConfigManagerBase
{
public static final String NAME = "configMgr";
@@ -50,95 +68,181 @@
public static final String PID = "pid";
+ public static final String factoryPID = "factoryPid";
- public String getLabel()
+ private static final String PLACEHOLDER_PID = "[Temporary PID replaced by real PID upon save]";
+
+
+ public String getTitle()
{
return LABEL;
}
- public String getName()
+ public String getLabel()
{
return NAME;
}
- public void render( HttpServletRequest request, HttpServletResponse response ) throws IOException
+ protected void doPost( HttpServletRequest request, HttpServletResponse response ) throws IOException
+ {
+ // needed multiple times below
+ String pid = request.getParameter( ConfigManager.PID );
+ if ( pid == null )
+ {
+ String info = request.getPathInfo();
+ pid = info.substring( info.lastIndexOf( '/' ) + 1 );
+ }
+
+ ConfigurationAdmin ca = this.getConfigurationAdmin();
+
+ // ignore this request if the pid and/or configuration admin is missing
+ if ( pid == null || ca == null )
+ {
+ // should log this here !!
+ return;
+ }
+
+ // the configuration to operate on (to be created or "missing")
+ Configuration config = null;
+
+ // should actually apply the configuration before redirecting
+ if ( request.getParameter( "create" ) != null )
+ {
+ if ( ca != null )
+ {
+ config = new PlaceholderConfiguration( pid ); // ca.createFactoryConfiguration( pid, null );
+ pid = config.getPid();
+ }
+ }
+ else if ( request.getParameter( "apply" ) != null )
+ {
+ String redirect = applyConfiguration( request, ca, pid );
+ if ( redirect != null )
+ {
+ response.sendRedirect( redirect );
+ }
+
+ return;
+ }
+
+ if ( config == null )
+ {
+ config = getConfiguration( ca, pid );
+ }
+
+ // send the result
+ response.setContentType( "text/javascript" );
+ response.setCharacterEncoding( "UTF-8" );
+ printConfigurationJson( response.getWriter(), pid, config, getLocale( request ) );
+ }
+
+
+ public void renderContent( HttpServletRequest request, HttpServletResponse response ) throws IOException
{
// true if MetaType service information is not required
boolean optionalMetaType = false;
+ Locale loc = getLocale( request );
+ String locale = ( loc != null ) ? loc.toString() : null;
+
PrintWriter pw = response.getWriter();
- pw.println( "<script type='text/javascript' src='res/ui/configmanager.js'></script>" );
+ String appRoot = (String) request.getAttribute( OsgiManager.ATTR_APP_ROOT );
+ pw.println( "<script src='" + appRoot + "/res/ui/configmanager.js' language='JavaScript'></script>" );
pw.println( "<table class='content' cellpadding='0' cellspacing='0' width='100%'>" );
- pw.println( "<tr class='content' id='configField'>" );
- pw.println( "<td class='content'>Configurations</th>" );
- pw.println( "<td class='content'>" );
- this.listConfigurations( pw, optionalMetaType, getLocale( request ) );
- pw.println( "</td>" );
- pw.println( "</tr>" );
-
- pw.println( "<tr class='content' id='factoryField'>" );
- pw.println( "<td class='content'>Factory Configurations</th>" );
- pw.println( "<td class='content'>" );
- this.listFactoryConfigurations( pw, optionalMetaType, getLocale( request ) );
- pw.println( "</td>" );
- pw.println( "</tr>" );
-
- pw.println( "</table>" );
- }
-
-
- private void listConfigurations( PrintWriter pw, boolean optionalMetaType, Locale loc )
- {
-
ConfigurationAdmin ca = this.getConfigurationAdmin();
if ( ca == null )
{
+ pw.println( "<tr class='content' id='configField'>" );
+ pw.println( "<td class='content'> </th>" );
+ pw.println( "<td class='content'>" );
pw.print( "Configuration Admin Service not available" );
- return;
+ pw.println( "</td>" );
+ pw.println( "</tr>" );
+ }
+ else
+ {
+ pw.println( "<tr class='content' id='configField'>" );
+ pw.println( "<td class='content'>Configurations</th>" );
+ pw.println( "<td class='content'>" );
+ this.listConfigurations( pw, ca, optionalMetaType, locale );
+ pw.println( "</td>" );
+ pw.println( "</tr>" );
+
+ pw.println( "<tr class='content' id='factoryField'>" );
+ pw.println( "<td class='content'>Factory Configurations</th>" );
+ pw.println( "<td class='content'>" );
+ this.listFactoryConfigurations( pw, ca, optionalMetaType, locale );
+ pw.println( "</td>" );
+ pw.println( "</tr>" );
}
- String locale = ( loc != null ) ? loc.toString() : null;
+ pw.println( "</table>" );
- try
+ // if a configuration is addressed, display it immediately
+ Configuration config = getConfiguration( getConfigurationAdmin(), request.getPathInfo() );
+ if ( config != null )
{
- // sorted map of options
- SortedMap optionsPlain = new TreeMap( String.CASE_INSENSITIVE_ORDER );
+ Util.startScript( pw );
- // find all ManagedServices to get the PIDs
- ServiceReference[] refs = this.getBundleContext().getServiceReferences( ManagedService.class.getName(),
- null );
- for ( int i = 0; refs != null && i < refs.length; i++ )
+ pw.println( "var configuration=" );
+ printConfigurationJson( pw, config.getPid(), config, getLocale( request ) );
+ pw.println( ";" );
+
+ pw.println( "displayConfigForm(configuration);" );
+
+ Util.endScript( pw );
+ }
+ }
+
+
+ private Configuration getConfiguration( ConfigurationAdmin ca, String pid )
+ {
+ if ( ca != null )
+ {
+ // only use last part of the pathInfo
+ pid = pid.substring( pid.lastIndexOf( '/' ) + 1 );
+
+ try
{
- Object pidObject = refs[i].getProperty( Constants.SERVICE_PID );
- if ( pidObject instanceof String )
+ // we use listConfigurations to not create configuration
+ // objects persistently without the user providing actual
+ // configuration
+ String filter = "(" + Constants.SERVICE_PID + "=" + pid + ")";
+ Configuration[] configs = ca.listConfigurations( filter );
+ if ( configs != null && configs.length > 0 )
{
- String pid = ( String ) pidObject;
- String name;
- ObjectClassDefinition ocd = this.getObjectClassDefinition( refs[i].getBundle(), pid, locale );
- if ( ocd != null )
- {
- name = ocd.getName() + " (";
- name += pid + ")";
- }
- else
- {
- name = pid;
- }
-
- if ( ocd != null || optionalMetaType )
- {
- optionsPlain.put( pid, name );
- }
+ return configs[0];
}
}
+ catch ( InvalidSyntaxException ise )
+ {
+ // should print message
+ }
+ catch ( IOException ioe )
+ {
+ // should print message
+ }
+ }
- // get a sorted list of configuration PIDs
+ // fallback to no configuration at all
+ return null;
+ }
+
+
+ private void listConfigurations( PrintWriter pw, ConfigurationAdmin ca, boolean optionalMetaType, String locale )
+ {
+ try
+ {
+ // start with ManagedService instances
+ SortedMap optionsPlain = getServices( ManagedService.class.getName(), optionalMetaType, locale );
+
+ // add in existing configuration (not duplicating ManagedServices)
Configuration[] cfgs = ca.listConfigurations( null );
for ( int i = 0; cfgs != null && i < cfgs.length; i++ )
{
@@ -170,19 +274,7 @@
}
}
- // pw.println( "<form method='post' name='configSelection' onSubmit='configure(); return false;'" );
- pw.println( "<select class='select' name='pid' id='configSelection_pid' onChange='configure();'>" );
- for ( Iterator ei = optionsPlain.entrySet().iterator(); ei.hasNext(); )
- {
- Entry entry = ( Entry ) ei.next();
- pw.print( "<option value='" + entry.getKey() + "'>" );
- pw.print( entry.getValue() );
- pw.println( "</option>" );
- }
- pw.println( "</select>" );
- pw.println( " " );
- pw.println( "<input class='submit' type='button' value='Configure' onClick='configure();' />" );
- // pw.println( "</form>" );
+ printOptionsForm( pw, optionsPlain, "configSelection_pid", "configure", "Configure" );
}
catch ( Exception e )
{
@@ -191,66 +283,580 @@
}
- private void listFactoryConfigurations( PrintWriter pw, boolean optionalMetaType, Locale loc )
+ private void listFactoryConfigurations( PrintWriter pw, ConfigurationAdmin ca, boolean optionalMetaType,
+ String locale )
{
-
- ConfigurationAdmin ca = this.getConfigurationAdmin();
- if ( ca == null )
- {
- pw.print( "Configuration Admin Service not available" );
- return;
- }
-
- String locale = ( loc != null ) ? loc.toString() : null;
-
try
{
- // sorted map of options
- SortedMap optionsFactory = new TreeMap( String.CASE_INSENSITIVE_ORDER );
+ SortedMap optionsFactory = getServices( ManagedServiceFactory.class.getName(), optionalMetaType, locale );
+ printOptionsForm( pw, optionsFactory, "configSelection_factory", "create", "Create" );
+ }
+ catch ( Exception e )
+ {
+ // write a message or ignore
+ }
+ }
- // find all ManagedServiceFactories to get the factoryPIDs
- ServiceReference[] refs = this.getBundleContext().getServiceReferences(
- ManagedServiceFactory.class.getName(), null );
- for ( int i = 0; refs != null && i < refs.length; i++ )
+
+ private SortedMap getServices( String serviceClass, boolean optionalMetaType, String locale )
+ throws InvalidSyntaxException
+ {
+ // sorted map of options
+ SortedMap optionsFactory = new TreeMap( String.CASE_INSENSITIVE_ORDER );
+
+ // find all ManagedServiceFactories to get the factoryPIDs
+ ServiceReference[] refs = this.getBundleContext().getServiceReferences( serviceClass, null );
+ for ( int i = 0; refs != null && i < refs.length; i++ )
+ {
+ Object pidObject = refs[i].getProperty( Constants.SERVICE_PID );
+ if ( pidObject instanceof String )
{
- Object factoryPid = refs[i].getProperty( Constants.SERVICE_PID );
- if ( factoryPid instanceof String )
+ String pid = ( String ) pidObject;
+ String name;
+ ObjectClassDefinition ocd = this.getObjectClassDefinition( refs[i].getBundle(), pid, locale );
+ if ( ocd != null )
{
- String pid = ( String ) factoryPid;
- String name;
- ObjectClassDefinition ocd = this.getObjectClassDefinition( refs[i].getBundle(), pid, locale );
- if ( ocd != null )
+ name = ocd.getName() + " (";
+ name += pid + ")";
+ }
+ else
+ {
+ name = pid;
+ }
+
+ if ( ocd != null || optionalMetaType )
+ {
+ optionsFactory.put( pid, name );
+ }
+ }
+ }
+
+ return optionsFactory;
+ }
+
+
+ private void printOptionsForm( PrintWriter pw, SortedMap options, String formId, String submitMethod,
+ String submitLabel )
+ {
+ pw.println( "<select class='select' name='pid' id='" + formId + "' onChange='" + submitMethod + "();'>" );
+ for ( Iterator ei = options.entrySet().iterator(); ei.hasNext(); )
+ {
+ Entry entry = ( Entry ) ei.next();
+ pw.print( "<option value='" + entry.getKey() + "'>" );
+ pw.print( entry.getValue() );
+ pw.println( "</option>" );
+ }
+ pw.println( "</select>" );
+ pw.println( " " );
+ pw.println( "<input class='submit' type='button' value='" + submitLabel + "' onClick='" + submitMethod
+ + "();' />" );
+
+ }
+
+
+ private void printConfigurationJson( PrintWriter pw, String pid, Configuration config, Locale locale )
+ throws IOException
+ {
+
+ JSONWriter result = new JSONWriter( pw );
+
+ if ( pid != null )
+ {
+ try
+ {
+ result.object();
+ this.configForm( result, pid, config, locale );
+ result.endObject();
+ }
+ catch ( Exception e )
+ {
+ // add message
+ }
+ }
+
+ }
+
+
+ private void configForm( JSONWriter json, String pid, Configuration config, Locale loc ) throws IOException,
+ JSONException
+ {
+ String locale = ( loc == null ) ? null : loc.toString();
+
+ json.key( ConfigManager.PID );
+ json.value( pid );
+
+ if ( pid == PLACEHOLDER_PID )
+ {
+ json.key( ConfigManager.factoryPID );
+ json.value( config.getFactoryPid() );
+ }
+
+ Dictionary props = null;
+ ObjectClassDefinition ocd;
+ if ( config != null )
+ {
+ props = config.getProperties();
+ ocd = this.getObjectClassDefinition( config, locale );
+ }
+ else
+ {
+ ocd = this.getObjectClassDefinition( pid, locale );
+ }
+
+ props = this.mergeWithMetaType( props, ocd, json );
+
+ if ( props != null )
+ {
+
+ json.key( "title" );
+ json.value( pid );
+ json.key( "description" );
+ json
+ .value( "Please enter configuration properties for this configuration in the field below. This configuration has no associated description" );
+
+ json.key( "propertylist" );
+ json.value( "properties" );
+
+ json.key( "properties" );
+ json.object();
+ for ( Enumeration pe = props.keys(); pe.hasMoreElements(); )
+ {
+ Object key = pe.nextElement();
+
+ // ignore well known special properties
+ if ( !key.equals( Constants.SERVICE_PID ) && !key.equals( Constants.SERVICE_DESCRIPTION )
+ && !key.equals( Constants.SERVICE_ID ) && !key.equals( Constants.SERVICE_RANKING )
+ && !key.equals( Constants.SERVICE_VENDOR )
+ && !key.equals( ConfigurationAdmin.SERVICE_BUNDLELOCATION )
+ && !key.equals( ConfigurationAdmin.SERVICE_FACTORYPID ) )
+ {
+ json.key( String.valueOf( key ) );
+ json.value( props.get( key ) );
+ }
+ }
+ json.endObject();
+
+ }
+
+ if ( config != null )
+ {
+ this.addConfigurationInfo( config, json, locale );
+ }
+ }
+
+
+ private Dictionary mergeWithMetaType( Dictionary props, ObjectClassDefinition ocd, JSONWriter json )
+ throws JSONException
+ {
+
+ if ( props == null )
+ {
+ props = new Hashtable();
+ }
+
+ if ( ocd != null )
+ {
+
+ json.key( "title" );
+ json.value( ocd.getName() );
+
+ if ( ocd.getDescription() != null )
+ {
+ json.key( "description" );
+ json.value( ocd.getDescription() );
+ }
+
+ AttributeDefinition[] ad = ocd.getAttributeDefinitions( ObjectClassDefinition.ALL );
+ if ( ad != null )
+ {
+
+ JSONArray propertyList = new JSONArray();
+
+ for ( int i = 0; i < ad.length; i++ )
+ {
+ json.key( ad[i].getID() );
+ json.object();
+
+ Object value = props.get( ad[i].getID() );
+ if ( value == null )
{
- name = ocd.getName() + " (";
- name += pid + ")";
+ value = ad[i].getDefaultValue();
+ if ( value == null )
+ {
+ if ( ad[i].getCardinality() == 0 )
+ {
+ value = "";
+ }
+ else
+ {
+ value = new String[0];
+ }
+ }
+ }
+
+ json.key( "name" );
+ json.value( ad[i].getName() );
+
+ json.key( "type" );
+ if ( ad[i].getOptionLabels() != null && ad[i].getOptionLabels().length > 0 )
+ {
+ json.object();
+ json.key( "labels" );
+ json.value( Arrays.asList( ad[i].getOptionLabels() ) );
+ json.key( "values" );
+ json.value( Arrays.asList( ad[i].getOptionValues() ) );
+ json.endObject();
}
else
{
- name = pid;
+ json.value( ad[i].getType() );
}
- if ( ocd != null || optionalMetaType )
+ if ( ad[i].getCardinality() == 0 )
{
- optionsFactory.put( pid, name );
+ // scalar
+ if ( value instanceof Vector )
+ {
+ value = ( ( Vector ) value ).get( 0 );
+ }
+ else if ( value.getClass().isArray() )
+ {
+ value = Array.get( value, 0 );
+ }
+ json.key( "value" );
+ json.value( value );
+ }
+ else
+ {
+ if ( value instanceof Vector )
+ {
+ value = new JSONArray( ( Vector ) value );
+ }
+ else if ( value.getClass().isArray() )
+ {
+ value = new JSONArray( Arrays.asList( ( Object[] ) value ) );
+ }
+ else
+ {
+ JSONArray tmp = new JSONArray();
+ tmp.put( value );
+ value = tmp;
+ }
+ json.key( "values" );
+ json.value( value );
+ }
+
+ if ( ad[i].getDescription() != null )
+ {
+ json.key( "description" );
+ json.value( ad[i].getDescription() );
+ }
+
+ json.endObject();
+ propertyList.put( ad[i].getID() );
+ }
+
+ json.key( "propertylist" );
+ json.value( propertyList );
+ }
+
+ // nothing more to display
+ props = null;
+ }
+
+ return props;
+ }
+
+
+ private void addConfigurationInfo( Configuration config, JSONWriter json, String locale ) throws JSONException
+ {
+
+ if ( config.getFactoryPid() != null )
+ {
+ json.key( "factoryPID" );
+ json.value( config.getFactoryPid() );
+ }
+
+ String location;
+ if ( config.getBundleLocation() == null )
+ {
+ location = "None";
+ }
+ else
+ {
+ Bundle bundle = this.getBundle( config.getBundleLocation() );
+
+ Dictionary headers = bundle.getHeaders( locale );
+ String name = ( String ) headers.get( Constants.BUNDLE_NAME );
+ if ( name == null )
+ {
+ location = bundle.getSymbolicName();
+ }
+ else
+ {
+ location = name + " (" + bundle.getSymbolicName() + ")";
+ }
+
+ Version v = Version.parseVersion( ( String ) headers.get( Constants.BUNDLE_VERSION ) );
+ location += ", Version " + v.toString();
+ }
+ json.key( "bundleLocation" );
+ json.value( location );
+ }
+
+
+ private String applyConfiguration( HttpServletRequest request, ConfigurationAdmin ca, String pid )
+ throws IOException
+ {
+ if ( request.getParameter( "delete" ) != null )
+ {
+ // only delete if the PID is not our place holder
+ if ( !PLACEHOLDER_PID.equals( pid ) )
+ {
+ // TODO: should log this here !!
+ Configuration config = ca.getConfiguration( pid, null );
+ config.delete();
+ }
+ return ""; // up a level
+ }
+
+ String factoryPid = request.getParameter( ConfigManager.factoryPID );
+ Configuration config = null;
+
+ String propertyList = request.getParameter( "propertylist" );
+ if ( propertyList == null )
+ {
+ String propertiesString = request.getParameter( "properties" );
+
+ if ( propertiesString != null )
+ {
+ byte[] propBytes = propertiesString.getBytes( "ISO-8859-1" );
+ ByteArrayInputStream bin = new ByteArrayInputStream( propBytes );
+ Properties props = new Properties();
+ props.load( bin );
+
+ config = getConfiguration( ca, pid, factoryPid );
+ config.update( props );
+ }
+ }
+ else
+ {
+ config = getConfiguration( ca, pid, factoryPid );
+
+ Dictionary props = config.getProperties();
+ if ( props == null )
+ {
+ props = new Hashtable();
+ }
+
+ Map adMap = this.getAttributeDefinitionMap( config, null );
+ if ( adMap != null )
+ {
+ StringTokenizer propTokens = new StringTokenizer( propertyList, "," );
+ while ( propTokens.hasMoreTokens() )
+ {
+ String propName = propTokens.nextToken();
+ AttributeDefinition ad = ( AttributeDefinition ) adMap.get( propName );
+ if ( ad == null || ( ad.getCardinality() == 0 && ad.getType() == AttributeDefinition.STRING ) )
+ {
+ String prop = request.getParameter( propName );
+ if ( prop != null )
+ {
+ props.put( propName, prop );
+ }
+ }
+ else if ( ad.getCardinality() == 0 )
+ {
+ // scalar of non-string
+ String prop = request.getParameter( propName );
+ props.put( propName, this.toType( ad.getType(), prop ) );
+ }
+ else
+ {
+ // array or vector of any type
+ Vector vec = new Vector();
+
+ String[] properties = request.getParameterValues( propName );
+ if ( properties != null )
+ {
+ for ( int i = 0; i < properties.length; i++ )
+ {
+ vec.add( this.toType( ad.getType(), properties[i] ) );
+ }
+ }
+
+ // but ensure size
+ int maxSize = Math.abs( ad.getCardinality() );
+ if ( vec.size() > maxSize )
+ {
+ vec.setSize( maxSize );
+ }
+
+ if ( ad.getCardinality() < 0 )
+ {
+ // keep the vector
+ props.put( propName, vec );
+ }
+ else
+ {
+ // convert to an array
+ props.put( propName, this.toArray( ad.getType(), vec ) );
+ }
}
}
}
- pw.println( "<select class='select' name='pid' id='configSelection_factory' onChange='create();'>" );
- for ( Iterator ei = optionsFactory.entrySet().iterator(); ei.hasNext(); )
- {
- Entry entry = ( Entry ) ei.next();
- pw.print( "<option value='" + entry.getKey() + "'>" );
- pw.print( entry.getValue() );
- pw.println( "</option>" );
- }
- pw.println( "</select>" );
- pw.println( " " );
- pw.println( "<input class='submit' type='button' value='Create' onClick='create();' />" );
+ config.update( props );
}
- catch ( Exception e )
+
+ // redirect to the new configuration (if existing)
+ return (config != null) ? config.getPid() : "";
+ }
+
+
+ private Configuration getConfiguration( ConfigurationAdmin ca, String pid, String factoryPid ) throws IOException
+ {
+ if ( factoryPid != null )
{
- // write a message or ignore
+ return ca.createFactoryConfiguration( factoryPid, null );
+ }
+
+ return ca.getConfiguration( pid, null );
+ }
+
+
+ private Object toType( int type, String value )
+ {
+ switch ( type )
+ {
+ case AttributeDefinition.BOOLEAN:
+ return Boolean.valueOf( value );
+ case AttributeDefinition.BYTE:
+ return Byte.valueOf( value );
+ case AttributeDefinition.CHARACTER:
+ char c = ( value.length() > 0 ) ? value.charAt( 0 ) : 0;
+ return new Character( c );
+ case AttributeDefinition.DOUBLE:
+ return Double.valueOf( value );
+ case AttributeDefinition.FLOAT:
+ return Float.valueOf( value );
+ case AttributeDefinition.LONG:
+ return Long.valueOf( value );
+ case AttributeDefinition.INTEGER:
+ return Integer.valueOf( value );
+ case AttributeDefinition.SHORT:
+ return Short.valueOf( value );
+
+ default:
+ // includes AttributeDefinition.STRING
+ return value;
}
}
+
+
+ private Object toArray( int type, Vector values )
+ {
+ int size = values.size();
+
+ // short cut for string array
+ if ( type == AttributeDefinition.STRING )
+ {
+ return values.toArray( new String[size] );
+ }
+
+ Object array;
+ switch ( type )
+ {
+ case AttributeDefinition.BOOLEAN:
+ array = new boolean[size];
+ case AttributeDefinition.BYTE:
+ array = new byte[size];
+ case AttributeDefinition.CHARACTER:
+ array = new char[size];
+ case AttributeDefinition.DOUBLE:
+ array = new double[size];
+ case AttributeDefinition.FLOAT:
+ array = new float[size];
+ case AttributeDefinition.LONG:
+ array = new long[size];
+ case AttributeDefinition.INTEGER:
+ array = new int[size];
+ case AttributeDefinition.SHORT:
+ array = new short[size];
+ default:
+ // unexpected, but assume string
+ array = new String[size];
+ }
+
+ for ( int i = 0; i < size; i++ )
+ {
+ Array.set( array, i, values.get( i ) );
+ }
+
+ return array;
+ }
+
+ private static class PlaceholderConfiguration implements Configuration
+ {
+
+ private final String factoryPid;
+ private String bundleLocation;
+
+
+ PlaceholderConfiguration( String factoryPid )
+ {
+ this.factoryPid = factoryPid;
+ }
+
+
+ public String getPid()
+ {
+ return PLACEHOLDER_PID;
+ }
+
+
+ public String getFactoryPid()
+ {
+ return factoryPid;
+ }
+
+
+ public void setBundleLocation( String bundleLocation )
+ {
+ this.bundleLocation = bundleLocation;
+ }
+
+
+ public String getBundleLocation()
+ {
+ return bundleLocation;
+ }
+
+
+ public Dictionary getProperties()
+ {
+ // dummy configuration has no properties
+ return null;
+ }
+
+
+ public void update()
+ {
+ // dummy configuration cannot be updated
+ }
+
+
+ public void update( Dictionary properties )
+ {
+ // dummy configuration cannot be updated
+ }
+
+
+ public void delete()
+ {
+ // dummy configuration cannot be deleted
+ }
+
+ }
+
}
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ConfigManagerBase.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ConfigManagerBase.java
index 53e701b..0aae6f4 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ConfigManagerBase.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ConfigManagerBase.java
@@ -23,68 +23,37 @@
import javax.servlet.http.HttpServletRequest;
-import org.apache.felix.webconsole.internal.BaseManagementPlugin;
+import org.apache.felix.webconsole.internal.BaseWebConsolePlugin;
import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.metatype.AttributeDefinition;
import org.osgi.service.metatype.MetaTypeInformation;
import org.osgi.service.metatype.MetaTypeService;
import org.osgi.service.metatype.ObjectClassDefinition;
-import org.osgi.util.tracker.ServiceTracker;
/**
* The <code>ConfigManagerBase</code> TODO
*
*/
-abstract class ConfigManagerBase extends BaseManagementPlugin
+abstract class ConfigManagerBase extends BaseWebConsolePlugin
{
private static final String CONFIGURATION_ADMIN_NAME = ConfigurationAdmin.class.getName();
-
+
private static final String META_TYPE_NAME = MetaTypeService.class.getName();
- private ServiceTracker configurationAdmin;
-
- private ServiceTracker metaTypeService;
-
-
- public void activate( BundleContext bundleContext )
- {
- super.activate( bundleContext );
-
- configurationAdmin = new ServiceTracker( bundleContext, ConfigurationAdmin.class.getName(), null );
- configurationAdmin.open();
- metaTypeService = new ServiceTracker( bundleContext, MetaTypeService.class.getName(), null );
- metaTypeService.open();
- }
-
-
- public void destroy()
- {
- if ( configurationAdmin != null )
- {
- configurationAdmin.close();
- }
- if ( metaTypeService != null )
- {
- metaTypeService.close();
- }
- }
-
protected ConfigurationAdmin getConfigurationAdmin()
{
- //TODO: getService(CONFIGURATION_ADMIN_NAME)
- return ( ConfigurationAdmin ) configurationAdmin.getService();
+ return ( ConfigurationAdmin ) getService( CONFIGURATION_ADMIN_NAME );
}
protected MetaTypeService getMetaTypeService()
{
- //TODO: getService(META_TYPE_NAME)
- return ( MetaTypeService ) metaTypeService.getService();
+ //TODO:
+ return ( MetaTypeService ) getService( META_TYPE_NAME );
}
@@ -142,7 +111,7 @@
{
return mti.getObjectClassDefinition( config.getFactoryPid(), locale );
}
-
+
// otherwise check by configuration PID
return mti.getObjectClassDefinition( config.getPid(), locale );
}
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 421fedc..b0c28c4 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
@@ -40,7 +40,6 @@
import org.apache.felix.webconsole.internal.Logger;
import org.apache.felix.webconsole.internal.OsgiManagerPlugin;
import org.apache.felix.webconsole.internal.Util;
-import org.apache.felix.webconsole.internal.compendium.AjaxConfigManagerAction;
import org.apache.felix.webconsole.internal.compendium.ComponentConfigurationPrinter;
import org.apache.felix.webconsole.internal.compendium.ComponentRenderAction;
import org.apache.felix.webconsole.internal.compendium.ConfigManager;
@@ -77,6 +76,8 @@
public static final String ATTR_LABEL_MAP = OsgiManager.class.getName() + ".labelMap";
+ public static final String ATTR_APP_ROOT = OsgiManager.class.getName() + ".appRoot";
+
/**
* The name and value of a parameter which will prevent redirection to a
* render after the action has been executed (value is "_noredir_"). This
@@ -124,10 +125,10 @@
private static final String DEFAULT_MANAGER_ROOT = "/system/console";
private static final Class[] PLUGIN_CLASSES =
- { AjaxConfigManagerAction.class, ComponentConfigurationPrinter.class, ComponentRenderAction.class,
- ConfigManager.class, BundlesServlet.class, InstallAction.class, SetStartLevelAction.class,
- ConfigurationRender.class, GCAction.class, ShutdownAction.class, ShutdownRender.class, VMStatRender.class,
- BundleRepositoryRender.class, LicenseServlet.class };
+ { ComponentConfigurationPrinter.class, ComponentRenderAction.class, ConfigManager.class, BundlesServlet.class,
+ InstallAction.class, SetStartLevelAction.class, ConfigurationRender.class, GCAction.class,
+ ShutdownAction.class, ShutdownRender.class, VMStatRender.class, BundleRepositoryRender.class,
+ LicenseServlet.class };
private BundleContext bundleContext;
@@ -317,6 +318,8 @@
if ( plugin != null )
{
req.setAttribute( ATTR_LABEL_MAP, labelMap );
+ req.setAttribute( ATTR_APP_ROOT, request.getContextPath() + request.getServletPath() );
+
plugin.service( req, res );
}
else
diff --git a/webconsole/src/main/resources/res/ui/configmanager.js b/webconsole/src/main/resources/res/ui/configmanager.js
index 7c4ce5a..0af2182 100644
--- a/webconsole/src/main/resources/res/ui/configmanager.js
+++ b/webconsole/src/main/resources/res/ui/configmanager.js
@@ -23,8 +23,8 @@
}
var select = document.getElementById('configSelection_pid');
var pid = select.options[select.selectedIndex].value;
- var parm = '?action=ajaxConfigManager&pid=' + pid;
- sendRequest('GET', parm, displayConfigForm);
+ var parm = pluginRoot + '/' + pid;
+ sendRequest('POST', parm, displayConfigForm);
}
@@ -35,8 +35,8 @@
}
var select = document.getElementById('configSelection_factory');
var pid = select.options[select.selectedIndex].value;
- var parm = '?action=ajaxConfigManager&create=true&pid=' + pid;
- sendRequest('GET', parm, displayConfigForm);
+ var parm = pluginRoot + '/' + pid + '?create=true';
+ sendRequest('POST', parm, displayConfigForm);
}
function displayConfigForm(obj) {
@@ -61,9 +61,15 @@
innerHtml += '<tr class="content">';
innerHtml += '<td class="content"> </td>';
innerHtml += '<td class="content">';
- innerHtml += '<form method="post">';
+ innerHtml += '<form method="post" action="' + pluginRoot + '/' + obj.pid + '">';
innerHtml += '<input type="hidden" name="apply" value="true" />';
- innerHtml += '<input type="hidden" name="pid" value="' + obj.pid + '" />';
+
+ // add the factory PID as a hidden form field if present
+ if (obj.factoryPid)
+ {
+ innerHtml += '<input type="hidden" name="factoryPid" value="' + obj.factoryPid + '" />';
+ }
+
innerHtml += '<input type="hidden" name="action" value="ajaxConfigManager" />';
innerHtml += '<table border="0" width="100%">';
if (obj.description) {