FELIX-1988 Apply 14.configmgr_plugin.patch by Valentin Valchev (thanks)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@911447 13f79535-47bb-0310-9956-ffa450edef68
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 6d0655a..5da4c13 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
@@ -31,21 +31,19 @@
import java.util.Map;
import java.util.Properties;
import java.util.SortedMap;
-import java.util.SortedSet;
import java.util.StringTokenizer;
import java.util.TreeMap;
-import java.util.TreeSet;
import java.util.Vector;
-import java.util.Map.Entry;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.apache.felix.webconsole.WebConsoleConstants;
-import org.apache.felix.webconsole.internal.Util;
+import org.apache.felix.webconsole.DefaultVariableResolver;
+import org.apache.felix.webconsole.WebConsoleUtil;
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.Constants;
@@ -57,7 +55,6 @@
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.cm.ManagedService;
import org.osgi.service.cm.ManagedServiceFactory;
-import org.osgi.service.log.LogService;
import org.osgi.service.metatype.AttributeDefinition;
import org.osgi.service.metatype.ObjectClassDefinition;
@@ -67,32 +64,31 @@
*/
public class ConfigManager extends ConfigManagerBase
{
+ private static final String LABEL = "configMgr"; // was name
+ private static final String TITLE = "Configuration";
+ private static final String CSS[] = { "/res/ui/config.css" };
private static final String PID_FILTER = "pidFilter";
-
- public static final String NAME = "configMgr";
-
- public static final String LABEL = "Configuration";
-
- public static final String PID = "pid";
-
- public static final String factoryPID = "factoryPid";
+ private static final String PID = "pid";
+ private static final String factoryPID = "factoryPid";
private static final String PLACEHOLDER_PID = "[Temporary PID replaced by real PID upon save]";
+ // templates
+ private final String TEMPLATE;
- public String getTitle()
+ /** Default constructor */
+ public ConfigManager()
{
- return LABEL;
+ super(LABEL, TITLE, CSS);
+
+ // load templates
+ TEMPLATE = readTemplateFile( "/templates/config.html" );
}
-
- public String getLabel()
- {
- return NAME;
- }
-
-
+ /**
+ * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+ */
protected void doPost( HttpServletRequest request, HttpServletResponse response ) throws IOException
{
// needed multiple times below
@@ -133,7 +129,7 @@
redirect += "?" + PID_FILTER + "=" + pidFilter;
}
- this.sendRedirect(request, response, redirect);
+ WebConsoleUtil.sendRedirect(request, response, redirect);
}
return;
@@ -148,7 +144,7 @@
if ( request.getParameter( "unbind" ) != null )
{
config.setBundleLocation( null );
- sendRedirect( request, response, config.getPid() );
+ WebConsoleUtil.sendRedirect( request, response, config.getPid() );
return;
}
@@ -227,7 +223,7 @@
}
pw.write("]");
} catch (InvalidSyntaxException e) {
- // this should not happend as we checked the filter before
+ // this should not happened as we checked the filter before
}
// nothing more to do
return;
@@ -239,7 +235,7 @@
/**
* @see org.apache.felix.webconsole.AbstractWebConsolePlugin#renderContent(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
- public void renderContent( HttpServletRequest request, HttpServletResponse response ) throws IOException
+ protected void renderContent( HttpServletRequest request, HttpServletResponse response ) throws IOException
{
// extract the configuration pid from the request path
@@ -281,42 +277,20 @@
final Locale loc = getLocale( request );
final String locale = ( loc != null ) ? loc.toString() : null;
+
- final PrintWriter pw = response.getWriter();
-
- final String appRoot = (String) request.getAttribute( WebConsoleConstants.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%'>" );
-
- if ( ca == null )
+ JSONObject json = new JSONObject();
+ try
{
- 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" );
- pw.println( "</td>" );
- pw.println( "</tr>" );
+ json.put("status", ca != null ? Boolean.TRUE : Boolean.FALSE);
+ listConfigurations(json, ca, pidFilter, locale);
+ listFactoryConfigurations(json, pidFilter, locale);
}
- else
+ catch (JSONException e)
{
- pw.println( "<tr class='content' id='configField'>" );
- pw.println( "<td class='content'>Configurations</th>" );
- pw.println( "<td class='content'>" );
- this.listConfigurations( pw, ca, pidFilter, 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, pidFilter, locale );
- pw.println( "</td>" );
- pw.println( "</tr>" );
+ throw new IOException(e.toString());
}
-
- pw.println( "</table>" );
-
+
// if a configuration is addressed, display it immediately
final Configuration config;
if ( request.getParameter( "create" ) != null && pid != null )
@@ -329,18 +303,13 @@
config = getConfiguration( ca, pid );
}
- if ( pid != null )
- {
- Util.startScript( pw );
- pw.println( "var configuration=" );
- printConfigurationJson( pw, pid, config, pidFilter, locale );
- pw.println( ";" );
+ // prepare variables
+ DefaultVariableResolver vars = ( ( DefaultVariableResolver ) WebConsoleUtil.getVariableResolver( request ) );
+ vars.put( "__data__", json.toString() );
+ vars.put( "selectedPid", pid != null ? pid : "");
- pw.println( "displayConfigForm(configuration);" );
-
- Util.endScript( pw );
- }
+ response.getWriter().print(TEMPLATE);
}
@@ -375,33 +344,57 @@
}
- private void listConfigurations( PrintWriter pw, ConfigurationAdmin ca, String pidFilter, String locale )
+ private final void listFactoryConfigurations(JSONObject json, String pidFilter,
+ String locale)
+ {
+ try
+ {
+ Map optionsFactory = getServices(ManagedServiceFactory.class.getName(),
+ pidFilter, locale, true);
+ addMetaTypeNames(optionsFactory, getFactoryPidObjectClasses(locale),
+ pidFilter, ConfigurationAdmin.SERVICE_FACTORYPID);
+ for (Iterator i = optionsFactory.keySet().iterator(); i.hasNext();)
+ {
+ String id = (String) i.next();
+ Object name = optionsFactory.get(id);
+ json.append("fpids", new JSONObject().put("id", id).put("name", name));
+ }
+ }
+ catch (Exception e)
+ {
+ log("listFactoryConfigurations: Unexpected problem encountered", e);
+ }
+ }
+
+ private final void listConfigurations(JSONObject json, ConfigurationAdmin ca,
+ String pidFilter, String locale)
{
try
{
// start with ManagedService instances
- SortedMap optionsPlain = getServices( ManagedService.class.getName(), pidFilter, locale, true );
+ Map optionsPlain = getServices(ManagedService.class.getName(), pidFilter,
+ locale, true);
// next are the MetaType informations without ManagedService
- addMetaTypeNames( optionsPlain, getPidObjectClasses( locale ), pidFilter, Constants.SERVICE_PID );
+ addMetaTypeNames(optionsPlain, getPidObjectClasses(locale), pidFilter,
+ Constants.SERVICE_PID);
// add in existing configuration (not duplicating ManagedServices)
- Configuration[] cfgs = ca.listConfigurations( pidFilter );
- for ( int i = 0; cfgs != null && i < cfgs.length; i++ )
+ Configuration[] cfgs = ca.listConfigurations(pidFilter);
+ for (int i = 0; cfgs != null && i < cfgs.length; i++)
{
- // ignore configuration object if an entry already exists in the
- // map
+ // ignore configuration object if an entry already exists in the map
String pid = cfgs[i].getPid();
- if ( optionsPlain.containsKey( pid ) )
+ if (optionsPlain.containsKey(pid))
{
continue;
}
- // insert and entry for the pid
- ObjectClassDefinition ocd = this.getObjectClassDefinition( cfgs[i], locale );
+ // insert and entry for the PID
+ ObjectClassDefinition ocd = this.getObjectClassDefinition(cfgs[i], locale);
String name;
- if ( ocd != null )
+ if (ocd != null)
{
name = ocd.getName() + " (";
name += pid + ")";
@@ -411,35 +404,22 @@
name = pid;
}
- optionsPlain.put( pid, name );
+ optionsPlain.put(pid, name);
}
- printOptionsForm( pw, optionsPlain, "configSelection_pid", "configure", "Configure" );
+ for (Iterator i = optionsPlain.keySet().iterator(); i.hasNext();)
+ {
+ String id = (String) i.next();
+ Object name = optionsPlain.get(id);
+ json.append("pids", new JSONObject().put("id", id).put("name", name));
+ }
}
- catch ( Exception e )
+ catch (Exception e)
{
- getLog().log( LogService.LOG_ERROR, "listConfigurations: Unexpected problem encountered", e );
+ log("listConfigurations: Unexpected problem encountered", e);
}
}
-
- private void listFactoryConfigurations( PrintWriter pw, ConfigurationAdmin ca, String pidFilter,
- String locale )
- {
- try
- {
- SortedMap optionsFactory = getServices( ManagedServiceFactory.class.getName(), pidFilter, locale, true );
- addMetaTypeNames( optionsFactory, getFactoryPidObjectClasses( locale ), pidFilter,
- ConfigurationAdmin.SERVICE_FACTORYPID );
- printOptionsForm( pw, optionsFactory, "configSelection_factory", "create", "Create" );
- }
- catch ( Exception e )
- {
- getLog().log( LogService.LOG_ERROR, "listFactoryConfigurations: Unexpected problem encountered", e );
- }
- }
-
-
private SortedMap getServices( String serviceClass, String serviceFilter, String locale, boolean ocdRequired )
throws InvalidSyntaxException
{
@@ -487,6 +467,7 @@
}
catch ( InvalidSyntaxException not_expected )
{
+ /* filter is correct */
}
}
@@ -506,35 +487,6 @@
}
- private void printOptionsForm( PrintWriter pw, SortedMap options, String formId, String submitMethod,
- String submitLabel )
- {
- SortedSet set = new TreeSet();
- for ( Iterator ei = options.entrySet().iterator(); ei.hasNext(); )
- {
- Entry entry = ( Entry ) ei.next();
- set.add(entry.getValue().toString() + Character.MAX_VALUE + entry.getKey().toString());
- }
-
- pw.println( "<select class='select' name='pid' id='" + formId + "' onChange='" + submitMethod + "();'>" );
- for ( Iterator ei = set.iterator(); ei.hasNext(); )
- {
- String entry = ( String ) ei.next();
- int sep = entry.indexOf( Character.MAX_VALUE );
- String value = entry.substring( 0, sep );
- String key = entry.substring( sep + 1 );
- pw.print( "<option value='" + key + "'>" );
- pw.print( value );
- 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, String pidFilter,
String locale )
{
@@ -801,7 +753,7 @@
// only delete if the PID is not our place holder
if ( !PLACEHOLDER_PID.equals( pid ) )
{
- getLog().log( LogService.LOG_INFO, "applyConfiguration: Deleting configuration " + pid );
+ log( "applyConfiguration: Deleting configuration " + pid );
Configuration config = ca.getConfiguration( pid, null );
config.delete();
}
@@ -861,7 +813,7 @@
{
try
{
- props.put( propName, this.toType( ad.getType(), prop ) );
+ props.put( propName, toType( ad.getType(), prop ) );
}
catch ( NumberFormatException nfe )
{
@@ -881,7 +833,7 @@
{
try
{
- vec.add( this.toType( ad.getType(), properties[i] ) );
+ vec.add( toType( ad.getType(), properties[i] ) );
}
catch ( NumberFormatException nfe )
{
@@ -906,7 +858,7 @@
else
{
// convert to an array
- props.put( propName, this.toArray( ad.getType(), vec ) );
+ props.put( propName, toArray( ad.getType(), vec ) );
}
}
}
@@ -920,7 +872,7 @@
}
- private Configuration getConfiguration( ConfigurationAdmin ca, String pid, String factoryPid ) throws IOException
+ private static final Configuration getConfiguration( ConfigurationAdmin ca, String pid, String factoryPid ) throws IOException
{
if ( factoryPid != null && ( pid == null || pid.equals( PLACEHOLDER_PID ) ) )
{
@@ -935,7 +887,7 @@
* @throws NumberFormatException If the value cannot be converted to
* a number and type indicates a numeric type
*/
- private Object toType( int type, String value )
+ private static final Object toType( int type, String value )
{
switch ( type )
{
@@ -964,7 +916,7 @@
}
- private Object toArray( int type, Vector values )
+ private static final Object toArray( int type, Vector values )
{
int size = values.size();
@@ -979,20 +931,28 @@
{
case AttributeDefinition.BOOLEAN:
array = new boolean[size];
+ break;
case AttributeDefinition.BYTE:
array = new byte[size];
+ break;
case AttributeDefinition.CHARACTER:
array = new char[size];
+ break;
case AttributeDefinition.DOUBLE:
array = new double[size];
+ break;
case AttributeDefinition.FLOAT:
array = new float[size];
+ break;
case AttributeDefinition.LONG:
array = new long[size];
+ break;
case AttributeDefinition.INTEGER:
array = new int[size];
+ break;
case AttributeDefinition.SHORT:
array = new short[size];
+ break;
default:
// unexpected, but assume string
array = new String[size];
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 8943a25..fea1f37 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
@@ -25,7 +25,8 @@
import javax.servlet.http.HttpServletRequest;
-import org.apache.felix.webconsole.internal.BaseWebConsolePlugin;
+import org.apache.felix.webconsole.SimpleWebConsolePlugin;
+import org.apache.felix.webconsole.internal.OsgiManagerPlugin;
import org.osgi.framework.Bundle;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
@@ -39,11 +40,16 @@
* The <code>ConfigManagerBase</code> is the base class for the
* ConfigurationAdmin support in the web console. It provides various helper
* methods mostly with respect to using the MetaTypeService to access
- * configuration descriptiorns.
+ * configuration descriptions.
*/
-abstract class ConfigManagerBase extends BaseWebConsolePlugin
+abstract class ConfigManagerBase extends SimpleWebConsolePlugin implements OsgiManagerPlugin
{
+ ConfigManagerBase(String label, String title, String[] css)
+ {
+ super(label, title, css);
+ }
+
private static final long serialVersionUID = -6691093960031418130L;
private static final String CONFIGURATION_ADMIN_NAME = ConfigurationAdmin.class.getName();
@@ -67,6 +73,9 @@
* Returns a map of PIDs and providing bundles of MetaType information. The
* map is indexed by PID and the value of each entry is the bundle providing
* the MetaType information for that PID.
+ *
+ * @param locale The name of the locale to get the meta data for.
+ * @return see the method description
*/
protected Collection getPidObjectClasses( final String locale )
{
@@ -79,6 +88,9 @@
* information. The map is indexed by factory PID and the value of each
* entry is the bundle providing the MetaType information for that factory
* PID.
+ *
+ * @param locale The name of the locale to get the meta data for.
+ * @return see the method description
*/
protected Collection getFactoryPidObjectClasses( final String locale )
{
@@ -87,13 +99,13 @@
/**
- * Returns the <code>ObjectClassDefinition</code> objects for the ids
+ * Returns the <code>ObjectClassDefinition</code> objects for the IDs
* returned by the <code>idGetter</code>. Depending on the
* <code>idGetter</code> implementation this will be for factory PIDs or
* plain PIDs.
*
* @param idGetter The {@link IdGetter} used to get the list of factory PIDs
- * or PIDs from <code>MetaTypeInformation</code> objetcs.
+ * or PIDs from <code>MetaTypeInformation</code> objects.
* @param locale The name of the locale to get the object class definitions
* for.
*/
diff --git a/webconsole/src/main/resources/res/ui/config.css b/webconsole/src/main/resources/res/ui/config.css
new file mode 100644
index 0000000..8f96a81
--- /dev/null
+++ b/webconsole/src/main/resources/res/ui/config.css
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+/* IE hack */
+select { width: 50em }
+html>select { width: auto; min-width: 50em }
+#config_content table th {
+ width:20%
+}
+#config_content {
+ min-width: 80em;
+ width:100%;
+ margin:0;
+ padding:0
+}
+.multiselect {
+ display: block;
+}
diff --git a/webconsole/src/main/resources/res/ui/config.js b/webconsole/src/main/resources/res/ui/config.js
new file mode 100644
index 0000000..96f19f1
--- /dev/null
+++ b/webconsole/src/main/resources/res/ui/config.js
@@ -0,0 +1,507 @@
+/*
+ * 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 configure() {
+ var select = document.getElementById('configSelection_pid');
+ var pid = select.options[select.selectedIndex].value;
+ var parm = pluginRoot + '/' + pid;
+ $.post(parm, null, displayConfigForm, "json");
+}
+
+
+function create() {
+ var select = document.getElementById('configSelection_factory');
+ var pid = select.options[select.selectedIndex].value;
+ var parm = pluginRoot + '/' + pid + '?create=true';
+ $.post(parm, null, displayConfigForm, "json");
+}
+
+function displayConfigForm(obj) {
+ var span1 = document.getElementById('configField');
+ var span2 = document.getElementById('factoryField');
+ if (!span1 && !span2) {
+ return;
+ }
+
+ var parent = span1 ? span1.parentNode : span2.parentNode;
+
+ clearChildren( parent );
+
+ if (span1) {
+ parent.appendChild( span1 );
+ }
+ if (span2) {
+ parent.appendChild( span2 );
+ }
+
+ var trEl = tr( null );
+ var tdEl = createElement( "th", null, { colSpan: "2" } );
+ addText( tdEl, obj.title );
+ trEl.appendChild( tdEl );
+ parent.appendChild( trEl );
+
+ trEl = tr( );
+ parent.appendChild( trEl );
+
+ tdEl = td( );
+ addText( tdEl, "\u00a0" );
+ trEl.appendChild( tdEl );
+
+ tdEl = td( );
+ trEl.appendChild( tdEl );
+
+ var formEl = createElement( "form", null, {
+ method: "POST",
+ action: pluginRoot + "/" + obj.pid
+ });
+ tdEl.appendChild( formEl );
+
+ var inputEl = createElement( "input", null, {
+ type: "hidden",
+ name: "apply",
+ value: "true"
+ });
+ formEl.appendChild( inputEl );
+
+ // add the factory PID as a hidden form field if present
+ if (obj.factoryPid)
+ {
+ inputEl = createElement( "input", null, {
+ type: "hidden",
+ name: "factoryPid",
+ value: obj.factoryPid
+ });
+ formEl.appendChild( inputEl );
+ }
+
+ // add the PID filter as a hidden form field if present
+ if (obj.pidFilter)
+ {
+ inputEl = createElement( "input", null, {
+ type: "hidden",
+ name: "pidFilter",
+ value: obj.pidFilter
+ });
+ formEl.appendChild( inputEl );
+ }
+
+ inputEl = createElement( "input", null, {
+ type: "hidden",
+ name: "action",
+ value: "ajaxConfigManager"
+ });
+ formEl.appendChild( inputEl );
+
+ var tableEl = createElement( "table", null, {
+ border: 0,
+ width: "100%"
+ });
+ formEl.appendChild( tableEl );
+
+ var bodyEl = createElement( "tbody" );
+ tableEl.appendChild( bodyEl );
+
+ if (obj.description)
+ {
+ trEl = tr( );
+ tdEl = td( null, { colSpan: "2" } );
+ addText( tdEl, obj.description );
+ trEl.appendChild( tdEl );
+ bodyEl.appendChild( trEl );
+ }
+
+ if (obj.propertylist == 'properties')
+ {
+ printTextArea(bodyEl, obj.properties);
+ }
+ else
+ {
+ printForm(bodyEl, obj);
+ }
+
+ trEl = tr( );
+ bodyEl.appendChild( trEl );
+
+ tdEl = td( );
+ addText( tdEl, "\u00a0" );
+ trEl.appendChild( tdEl );
+
+ tdEl = td( );
+ trEl.appendChild( tdEl );
+
+ // define this TD as innerHTML otherwise the onClick event handler
+ // of the Delete button is not accepted by IE6 (!)...
+ var innerHTML = '<input type="submit" name="submit" value="'+i18n.save+'" />';
+ innerHTML += ' ';
+ innerHTML += '<input type="reset" name="reset" value="'+i18n.reset+'" />';
+ innerHTML += ' ';
+ innerHTML += '<input type="submit" name="delete" value="'+i18n.del+'" onClick="return confirmDelete(\'' + obj.pid + '\', \'' + obj.bundleLocation + '\');"/>';
+ tdEl.innerHTML = innerHTML;
+
+ printConfigurationInfo(parent, obj);
+ initStaticWidgets($(parent));
+}
+
+function printTextArea(/* Element */ parent, props )
+{
+
+ var propsValue = "";
+ for (var key in props)
+ {
+ propsValue += key + ' = ' + props[key] + '\r\n';
+ }
+
+ parent.appendChild(
+ tr( null, null, [
+ td( null, null, [
+ text( i18n.props_title )
+ ]),
+ td( null, { style: { width: "99%" } }, [
+ createElement( "textarea", null, {
+ name: "properties",
+ style: { height: "50%", width: "99%" }
+ }, [ text( propsValue ) ] ),
+ text( i18n.props_enter )
+ ])
+ ])
+ );
+}
+
+function printForm( /* Element */ parent, obj ) {
+ var propList;
+ for (var idx in obj.propertylist)
+ {
+ var prop = obj.propertylist[idx];
+ var attr = obj[prop];
+
+ var trEl = tr( null, null, [
+ td( null, null, [ text( attr.name ) ] )
+ ]);
+ parent.appendChild( trEl );
+
+ var tdEl = td( null, { style: { width: "99%" } } );
+ trEl.appendChild( tdEl );
+
+ if (attr.value != undefined)
+ {
+ // check is required to also handle empty strings, 0 and false
+ tdEl.appendChild( createInput( prop, attr.value, attr.type, '99%' ) );
+ tdEl.appendChild( createElement( "br" ) );
+ }
+ else if (typeof(attr.type) == 'object')
+ {
+ // assume attr.values and multiselect
+ createMultiSelect( tdEl, prop, attr.values, attr.type, '99%' );
+ tdEl.appendChild( createElement( "br" ) );
+ }
+ else if (attr.values.length == 0)
+ {
+ tdEl.appendChild( createSpan( prop, "", attr.type ) );
+ }
+ else
+ {
+ for (var i=0;i<attr.values.length;i++)
+ {
+ tdEl.appendChild( createSpan( prop, attr.values[i], attr.type ) );
+ }
+ }
+
+ if (attr.description)
+ {
+ addText( tdEl, attr.description );
+ }
+
+ if (propList) {
+ propList += ',' + prop;
+ } else {
+ propList = prop;
+ }
+ }
+
+ parent.appendChild( createElement( "input", null, {
+ type: "hidden",
+ name: "propertylist",
+ value: propList
+ })
+ );
+ // FIX for IE6 and above: checkbox can only be checked after it is in the DOM
+ $(".checked_box").attr("checked", true).removeClass("checked_box");
+}
+
+function printConfigurationInfo( /* Element */ parent, obj )
+{
+ parent.appendChild( tr( null, null, [
+ createElement( "th", null, { colSpan: "2" }, [
+ text( i18n.cfg_title )
+ ])
+ ])
+ );
+
+ parent.appendChild( tr( null, null, [
+ td( null, null, [
+ text( i18n.pid )
+ ]),
+ td( null, null, [
+ text( obj.pid )
+ ])
+ ])
+ );
+
+ if (obj.factoryPid)
+ {
+ parent.appendChild( tr( null, null, [
+ td( null, null, [
+ text( i18n.fpid )
+ ]),
+ td( null, null, [
+ text( obj.factoryPid )
+ ])
+ ])
+ );
+ }
+
+ var binding = obj.bundleLocation;
+ if (!binding)
+ {
+ binding = i18n.unbound;
+ }
+
+ parent.appendChild( tr( null, null, [
+ td( null, null, [
+ text( i18n.binding )
+ ]),
+ td( null, null, [
+ text( binding )
+ ])
+ ])
+ );
+
+ if (obj.bundleLocation)
+ {
+ var form = createElement( "form", null, {
+ method: "POST",
+ action: pluginRoot + "/" + obj.pid
+ });
+
+ // define this form contents as innerHTML otherwise the onClick
+ // event handler of the Unbind button is not accepted by IE6 (!)...
+ var formInner = '<input type="hidden" name="unbind" value="true"/>';
+ formInner += '<input type="submit" name="submit" value="'+i18n.unbind_btn+'" class="ui-state-default ui-corner-all" title="'+i18n.unbind_tip+'" onClick="return confirmUnbind(\'' + obj.pid + '\', \'' + obj.bundleLocation + '\');"/>';
+ form.innerHTML = formInner;
+
+ parent.appendChild( tr( null, null, [
+ td( null, null, [
+ text( " " )
+ ]),
+ td( null, null, [ form ] )
+ ])
+ );
+ }
+ //$(form).ready(initStaticWidgets);
+}
+
+
+var spanCounter = 0;
+/* Element */ function createSpan(prop, value, type) {
+ spanCounter++;
+ var newId = prop + spanCounter;
+
+ var addButton = createElement("input", null,
+ { type: "button",
+ style: {width : "5%"},
+ value: "+"
+ }
+ );
+ $(addButton).click(function() {addValue(prop, newId)});
+ var remButton = createElement("input", null,
+ { type: "button",
+ style: {width : "5%"},
+ value: "-"
+ }
+ );
+ $(remButton).click(function() {removeValue(newId)});
+ var spanEl = createElement( "span", null, { id: newId }, [
+ createInput( prop, value, type, '89%' ), addButton, remButton,
+ createElement("br")
+ ]);
+
+ return spanEl;
+}
+
+/* Element */ function createInput(prop, value, type, width) {
+ if (type == 11) { // AttributeDefinition.BOOLEAN
+
+ var inputEl = createElement( "input", null, {
+ type: "checkbox",
+ name: prop,
+ value: "true"
+ });
+
+ if (value && typeof(value) != "boolean")
+ {
+ value = value.toString().toLowerCase() == "true";
+ }
+ if (value)
+ {
+ $(inputEl).addClass("checked_box");
+ }
+ var hiddenEl = createElement( "input", null, {
+ type: "hidden",
+ name: prop,
+ value: "false"
+ });
+ var divEl = createElement("div");
+ divEl.appendChild(inputEl);
+ divEl.appendChild(hiddenEl);
+ return divEl;
+
+ } else if (typeof(type) == "object") { // predefined values
+
+ var selectEl = createElement( "select", null, {
+ name: prop,
+ style: { width: width }
+ });
+
+ var labels = type.labels;
+ var values = type.values;
+ for (var idx in labels) {
+ var optionEl = createElement( "option", null, {
+ value: values[idx]
+ }, [ text( labels[idx] ) ]);
+
+ if (value == values[idx])
+ {
+ optionEl.setAttribute( "selected", true );
+ }
+ selectEl.appendChild( optionEl );
+ }
+
+ return selectEl;
+
+ } else { // Simple
+ return createElement( "input", null, {
+ type: "text",
+ name: prop,
+ value: value,
+ style: { width: width }
+ });
+ }
+}
+
+function createMultiSelect(/* Element */ parent, prop, values, options, width) {
+ // convert value list into 'set'
+ var valueSet = new Object();
+ for (var idx in values) {
+ valueSet[ values[idx] ] = true;
+ }
+
+ var labels = options.labels;
+ var values = options.values;
+ for (var idx in labels) {
+
+ var inputEl = createElement( "input", null, {
+ type: "checkbox",
+ name: prop,
+ value: values[idx]
+ });
+
+ if (valueSet[ values[idx] ])
+ {
+ inputEl.setAttribute( "checked", true );
+ }
+
+ var labelEl = createElement( "label", "multiselect" );
+ labelEl.appendChild( inputEl );
+ addText( labelEl, labels[idx] );
+
+ parent.appendChild( labelEl );
+ }
+}
+
+
+function addValue(prop, vidx)
+{
+ var span = document.getElementById(vidx);
+ if (!span)
+ {
+ return;
+ }
+ var newSpan = createSpan(prop, '');
+ span.parentNode.insertBefore(newSpan, span.nextSibling);
+ // FIX for IE6 and above: checkbox can only be checked after it is in the DOM
+ $(".checked_box").attr("checked", true).removeClass("checked_box");
+ //$(span).ready(initStaticWidgets);
+}
+
+function removeValue(vidx)
+{
+ var span = document.getElementById(vidx);
+ if (!span)
+ {
+ return;
+ }
+ span.parentNode.removeChild(span);
+}
+
+function configConfirm(/* String */ message, /* String */ title, /* String */ location)
+{
+ var message = i18n.del_ask;
+
+ if (title) {
+ message += "\r\n" + i18n.del_config + title;
+ }
+ if (location) {
+ message += "\r\n" + i18n.del_bundle + location;
+ }
+
+ return confirm(message);
+}
+
+function confirmDelete(/* String */ title, /* String */ location)
+{
+ return configConfirm(i18n.unbind_ask, title, location);
+}
+
+function confirmUnbind(/* String */ title, /* String */ location)
+{
+ return configConfirm(i18n.unbind_ask, title, location);
+}
+
+function addOption(list, target)
+{
+ var html = "";
+ for (i in list) {
+ var sel = list[i].id == selectedPid ? '" selected="selected' : '';
+ html += '<option value="' + list[i].id + sel + '">' + list[i].name + '</option>';
+ }
+ if (html) target.html(html);
+}
+
+var configSelection_pid = false;
+var configSelection_factory = false;
+$(document).ready(function() {
+ configSelection_pid = $('#configSelection_pid');
+ configSelection_factory = $('#configSelection_factory');
+ $(".statline").html(configData.status ? i18n.stat_ok : i18n.stat_missing);
+ $("#config_content").css("display", configData.status ? "block" : "none");
+ if (configData.status) {
+ addOption(configData.pids, $("#configSelection_pid"));
+ addOption(configData.fpids, $("#configSelection_factory"));
+ }
+ if (selectedPid) configure();
+});
\ No newline at end of file
diff --git a/webconsole/src/main/resources/templates/config.html b/webconsole/src/main/resources/templates/config.html
new file mode 100644
index 0000000..6c4b3d2
--- /dev/null
+++ b/webconsole/src/main/resources/templates/config.html
@@ -0,0 +1,59 @@
+<script type="text/javascript" src="res/ui/config.js"></script>
+<script type="text/javascript">
+// <![CDATA[
+// data
+var configData = ${__data__};
+var selectedPid = '${selectedPid}';
+var i18n = { // i18n
+ stat_ok : '${config.status.ok}', // "Configuration Admin Service is running.";
+ stat_missing : '${config.status.missing}', //"Configuration Admin Service is not installed/running."
+ save : '${save}',
+ reset : '${reset}',
+ del : '${delete}',
+ props_title : '${config.properties}',
+ props_enter : '${config.properties.enter}', // "Enter Name-Value pairs of configuration properties"
+ cfg_title : '${config.info.title}', // "Configuration Information"
+ pid : '${config.info.pid}', // "Persistent Identity (PID)";
+ fpid : '${config.info.fpid}', // "Factory Peristent Identifier (Factory PID)";
+ binding : '${config.info.binding}', // "Configuration Binding";
+ unbound : '${config.info.unbound}', // "Unbound or new configuration";
+ unbind_btn : '${config.unbind.btn}', // "Unbind;
+ unbind_tip : '${config.unbind.tip}', // "Unbind Configuration from Bundle"
+ del_ask : '${config.del.ask}', // "Are you sure to delete this configuration ?";
+ del_config : '${config.del.config}', // "Configuration: ";
+ del_bundle : '${config.del.bundle}', // "Bundle: ";
+ unbind_ask : '${config.unbind.ask}', // "Are you sure to unbind this configuration ?"
+ 'xx' : '${config.form.properties}',
+ 'xx' : '${config.form.properties}',
+
+}
+// ]]>
+</script>
+
+<!-- status line -->
+<p class="statline"> </p>
+
+<div id="config_content" >
+ <table class="nicetable">
+ <tr id="configField">
+ <td>Configurations</td>
+ <td>
+ <select name="pid" id="configSelection_pid" onchange="configure();">
+ <option> </option>
+ </select>
+
+ <button onclick="configure();">Configure</button>
+ </td>
+ </tr>
+ <tr id="factoryField">
+ <td>Factory Configurations</td>
+ <td>
+ <select name="pid" id="configSelection_factory" onchange="create();">
+ <option> </option>
+ </select>
+
+ <button onclick="create();">Create</button>
+ </td>
+ </tr>
+ </table>
+</div>