Fixed FELIX-4677 : Web Console Configuration plugin is confusing about default values & optionality of elements
https://issues.apache.org/jira/browse/FELIX-4677
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1640155 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/ConfigAdminSupport.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/ConfigAdminSupport.java
index a52d684..bd1aa3c 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/ConfigAdminSupport.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/ConfigAdminSupport.java
@@ -21,11 +21,13 @@
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
+import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.SortedMap;
@@ -183,6 +185,7 @@
final MetaTypeServiceSupport mtss = getMetaTypeSupport();
final Map adMap = ( mtss != null ) ? mtss.getAttributeDefinitionMap( config, null ) : new HashMap();
final StringTokenizer propTokens = new StringTokenizer( propertyList, "," ); //$NON-NLS-1$
+ final List propsToKeep = new ArrayList();
while ( propTokens.hasMoreTokens() )
{
String propName = propTokens.nextToken();
@@ -191,6 +194,7 @@
|| ConfigManager.ACTION_APPLY.equals(propName)
|| ConfigManager.PROPERTY_LIST.equals(propName)
? '$' + propName : propName;
+ propsToKeep.add(propName);
PropertyDescriptor ad = (PropertyDescriptor) adMap.get( propName );
@@ -283,6 +287,16 @@
}
}
}
+
+ // remove the properties that are not specified in the request
+ for ( Enumeration e = props.keys(); e.hasMoreElements(); )
+ {
+ final Object key = e.nextElement();
+ if ( !propsToKeep.contains(key) )
+ {
+ props.remove(key);
+ }
+ }
config.update( props );
}
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/MetaTypeServiceSupport.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/MetaTypeServiceSupport.java
index 5abbe9e..149c256 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/MetaTypeServiceSupport.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/MetaTypeServiceSupport.java
@@ -17,9 +17,13 @@
package org.apache.felix.webconsole.internal.configuration;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.Dictionary;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+
import org.json.JSONException;
import org.json.JSONWriter;
import org.osgi.framework.Bundle;
@@ -249,7 +253,7 @@
{
for ( int i = 0; i < ad.length; i++ )
{
- adMap.put( ad[i].getID(), new MetatypePropertyDescriptor( ad[i] ) );
+ adMap.put( ad[i].getID(), new MetatypePropertyDescriptor( ad[i], false ) );
}
}
}
@@ -267,6 +271,8 @@
}
AttributeDefinition[] ad = ocd.getAttributeDefinitions( ObjectClassDefinition.ALL );
+ AttributeDefinition[] optionalArray = ocd.getAttributeDefinitions( ObjectClassDefinition.OPTIONAL );
+ List/*<AttributeDefinition>*/ optional = optionalArray == null ? Collections.EMPTY_LIST : Arrays.asList( optionalArray );
if ( ad != null )
{
json.key( "properties" ).object(); //$NON-NLS-1$
@@ -275,7 +281,8 @@
final AttributeDefinition adi = ad[i];
final String attrId = adi.getID();
json.key( attrId );
- attributeToJson( json, new MetatypePropertyDescriptor( adi ), props.get( attrId ) );
+ boolean isOptional = optional.contains( adi );
+ attributeToJson( json, new MetatypePropertyDescriptor( adi, isOptional ), props.get( attrId ) );
}
json.endObject();
}
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/MetaTypeSupport.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/MetaTypeSupport.java
index f58d4bb..bcfc6ff 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/MetaTypeSupport.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/MetaTypeSupport.java
@@ -102,6 +102,10 @@
json.key( "name" ); //$NON-NLS-1$
json.value( ad.getName() );
+ json.key( "optional" ); //$NON-NLS-1$
+ json.value( ad.isOptional() );
+ json.key( "is_set" ); //$NON-NLS-1$
+ json.value( propValue != null );
// attribute type - overwrite metatype provided type
// if the property name contains "password" and the
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/MetatypePropertyDescriptor.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/MetatypePropertyDescriptor.java
index 533c1e5..96adeb0 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/MetatypePropertyDescriptor.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/MetatypePropertyDescriptor.java
@@ -30,12 +30,14 @@
public class MetatypePropertyDescriptor extends PropertyDescriptor
{
private final AttributeDefinition ad;
+ private final boolean optional;
- public MetatypePropertyDescriptor( AttributeDefinition ad )
+ public MetatypePropertyDescriptor( AttributeDefinition ad, boolean optional )
{
super( ad.getID(), ad.getType(), ad.getCardinality() );
this.ad = ad;
+ this.optional = optional;
}
@@ -79,4 +81,9 @@
{
return ad.getDefaultValue();
}
+
+ public boolean isOptional()
+ {
+ return optional;
+ }
}
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/PropertyDescriptor.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/PropertyDescriptor.java
index dc412c3..9ea82e4 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/PropertyDescriptor.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/configuration/PropertyDescriptor.java
@@ -94,4 +94,10 @@
{
return null;
}
+
+ public boolean isOptional()
+ {
+ return false;
+ }
+
}
\ No newline at end of file
diff --git a/webconsole/src/main/resources/OSGI-INF/l10n/bundle.properties b/webconsole/src/main/resources/OSGI-INF/l10n/bundle.properties
index f99802a..a3014a3 100644
--- a/webconsole/src/main/resources/OSGI-INF/l10n/bundle.properties
+++ b/webconsole/src/main/resources/OSGI-INF/l10n/bundle.properties
@@ -187,6 +187,8 @@
config.title.bundle=Bundle
config.title.name=Name
config.bind.error=Error: the PID "{0}" is bound to "{1}" but the actual managed service is registered from "{2}" bundle
+config.property.default.value=Note, that this property is not set. The above field contains is the *default value* specified in the Meta Type service.
+config.property.optional.value=This attribute is optional. To save it in the current configuration you must check it. To remove it from the configuration uncheck the checkbox.
# License plugin
licenses.pluginTitle=Licenses
diff --git a/webconsole/src/main/resources/res/ui/config.css b/webconsole/src/main/resources/res/ui/config.css
index 5f69d84..21e543d 100644
--- a/webconsole/src/main/resources/res/ui/config.css
+++ b/webconsole/src/main/resources/res/ui/config.css
@@ -33,3 +33,6 @@
.subpid { margin-left: 1em; float: left }
tr.fpid td { font-style:italic }
#factoryTableCaption { margin-top: 1.5em }
+span.default_value {
+ float: left; margin-right: .3em;
+}
\ No newline at end of file
diff --git a/webconsole/src/main/resources/res/ui/config.js b/webconsole/src/main/resources/res/ui/config.js
index 02ca0ff..54d0868 100644
--- a/webconsole/src/main/resources/res/ui/config.js
+++ b/webconsole/src/main/resources/res/ui/config.js
@@ -107,7 +107,7 @@
if (obj.description)
{
trEl = tr( );
- tdEl = td( null, { colSpan: "2" } );
+ tdEl = td( null, { colSpan: "3" } );
addText( tdEl, obj.description );
trEl.appendChild( tdEl );
bodyEl.appendChild( trEl );
@@ -134,13 +134,41 @@
.dialog('open'));
}
+/* Element */ function addDefaultValue( /* Element */ element ) {
+ if (element) {
+ element.appendChild(
+ createElement('span', 'default_value ui-state-highlight1 ui-icon ui-icon-alert', {
+ title : i18n.dflt_value
+ })
+ );
+ }
+ return element;
+}
+
function printForm( /* Element */ parent, /* Object */ properties ) {
var propList;
for (var prop in properties)
{
var attr = properties[prop];
-
+
+ // create optionality element
+ var optElement = false;
+ if (attr.optional) {
+ var elAttributes = {
+ type: "checkbox",
+ name: "opt" + prop,
+ title: i18n.opt_value
+ };
+ if (attr.is_set) {
+ elAttributes['checked'] = 'checked';
+ }
+ optElement = createElement( "input", "optionality", elAttributes);
+ } else {
+ optElement = text( "" );
+ }
+ // create the raw
var trEl = tr( null, null, [
+ td( null, null, [ optElement ] ),
td( null, null, [ text( attr.name ) ] )
]);
parent.appendChild( trEl );
@@ -152,7 +180,8 @@
{
// check is required to also handle empty strings, 0 and false
var inputName = (prop == "action" || prop == "propertylist" || prop == "apply" || prop == "delete") ? '$' + prop : prop;
- tdEl.appendChild( createInput( inputName, attr.value, attr.type, '99%' ) );
+ var inputEl = createInput( inputName, attr.value, attr.type, '99%' );
+ tdEl.appendChild( inputEl );
tdEl.appendChild( createElement( "br" ) );
}
else if (typeof(attr.type) == 'object')
@@ -173,6 +202,10 @@
}
}
+ if (!attr.is_set) {
+ addDefaultValue( tdEl );
+ }
+
if (attr.description)
{
addText( tdEl, attr.description );
@@ -514,6 +547,20 @@
unbindConfig($(this).attr('__pid'), $(this).attr('__location'));
}
_buttons[i18n.save] = function() {
+ // get all the configuration properties names
+ var propListElement = $(this).find('form').find('[name=propertylist]');
+ var propListArray = propListElement.val().split(',');
+
+ // removes the properties, that are unchecked
+ $(this).find('form').find('input.optionality:not(:checked)').each( function(idx, el) {
+ var name = $(el).attr('name').substring(3); // name - 'opt'
+ var index = propListArray.indexOf(name);
+ if (index >= 0) {
+ propListArray.splice(index, 1);
+ }
+ });
+ propListElement.val(propListArray.join(','));
+
$.post(pluginRoot + '/' + $(this).attr('__pid'), $(this).find('form').serialize(), function() {
// reload on success - prevents AJAX errors - see FELIX-3116
document.location.href = pluginRoot;
diff --git a/webconsole/src/main/resources/templates/config.html b/webconsole/src/main/resources/templates/config.html
index 1934d43..97d21c7 100644
--- a/webconsole/src/main/resources/templates/config.html
+++ b/webconsole/src/main/resources/templates/config.html
@@ -24,6 +24,8 @@
del_config : '${config.del.config}', // "Configuration: ";
del_bundle : '${config.del.bundle}', // "Bundle: ";
unbind_ask : '${config.unbind.ask}', // "Are you sure to unbind this configuration ?"
+ dflt_value : '${config.property.default.value}', // "Note, that this property is not set. The above field contains is the *default value* specified in the Meta Type service"
+ opt_value : '${config.property.optional.value}', // "This attribute is optional. To save it in the current configuration you must check it. To remove it from the configuration uncheck the checkbox."
err_bind : '${config.bind.error}' // Error: the PID'{0}' is bound to '{1}' but the actual managed service is registered from '{2}' bundle
};
var param = { // param