Skip to main content

Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "Higgins Configuration Management"

m (Proposal Overview: Associate an IConfigurationHandler with an IConfigurableComponent)
m (Proposal 2: ISetting)
Line 74: Line 74:
 
Add description
 
Add description
  
== Proposal 2: ISetting ==
+
== Option 2: Represent each setting in the configuration file using the ISetting interface ==
  
The other desription
+
Currently, the in-memory configuration is represented by the Map data structure. Thus the 'IdentityAttributeService' section is represented by a Map with the keys 'ContextFactoryInstancesList' and 'ContextIdsList' and whose values are the lists of context factories and context ids respectively. This structure does not represent the 'type' of the value of each setting, which becomes necessary while writing back information to the file.
 +
 
 +
The change of this option is to represent each element in the XML configuration through the com.ibm.higgins.configuration.api.ISetting interface. The global settings is an ISetting whose value could be any of the types represented in the 'SettingHandlers' section of the configuration file. If the type of a setting is a List, then the value of that setting would be a list of ISetting(s). Thus each setting in the XML file has a corresponding in-memory ISetting object.
 +
 
 +
=== Change XML based configuration API ===
 +
 
 +
A new class com.ibm.higgins.configuration.xml.Setting that implements the com.ibm.higgins.configuration.api.ISetting interface has been introduced. It contains the setting name, setting type and setting value. Additionally it also contains the in-memory XML Object Model (OMElement) representation for that setting. It will have methods to add child settings and remove settings.
 +
 
 +
Here is a prototype implementation of the addChildSetting() method:
 +
 
 +
<source lang="java">
 +
public void addChildSetting(String name, String type, Object value) {
 +
 
 +
/* Create an OMElement corresponding to the child setting to add */
 +
OMFactory factory = OMAbstractFactory.getOMFactory();
 +
OMElement addElement = factory.createOMElement("Setting", null);
 +
addElement.addAttribute("Name", name, null);
 +
addElement.addAttribute("Type", type, null);
 +
 
 +
/* Create the new child setting to add to this setting */
 +
ISetting setting = new Setting(name, type, value, addElement);
 +
 
 +
/* Depending on the type of the value of a child setting, create
 +
* sub-settings for the child setting.
 +
*/
 +
if ( type.equalsIgnoreCase("htf:list")) {
 +
List listValues = (List)value;
 +
for ( int i = 0; i < listValues.size(); i++ ) {
 +
ISetting childSetting = (ISetting)listValues.get(i);
 +
setting.addChildSetting(childSetting.getName(), childSetting.getType(),
 +
childSetting.getValue());
 +
}
 +
} else if ( setting.getType().equalsIgnoreCase("htf:map")) {
 +
Map mapValues = (Map)setting.getValue();
 +
Iterator itr = mapValues.keySet().iterator();
 +
while (itr.hasNext()) {
 +
ISetting childSetting = (ISetting)itr.next();
 +
setting.addChildSetting(childSetting.getName(), childSetting.getType(),
 +
childSetting.getValue());
 +
}
 +
} else {
 +
addElement.setText(setting.getValue().toString());
 +
}
 +
 
 +
/* Add the child OMElement to this setting's OMElement */
 +
_element.addChild(addElement);
 +
 
 +
/* Update this setting's values to include the child setting */
 +
if ( _type.equalsIgnoreCase("htf:map")) {
 +
((Map)_value).put(name, setting);
 +
} else if (_type.equalsIgnoreCase("htf:list")) {
 +
((List)_value).add(setting);
 +
}
 +
}
 +
</source>
 +
 
 +
An ISetting represents the global settings in the com.ibm.higgins.configuration.xml.ConfigurationHandler instead of a Map.
 +
 
 +
The signature for the getSetting() method in com.ibm.higgins.configuration.xml.ISettingHandler has changed from:
 +
<source lang="java">
 +
public abstract Object getSetting
 +
(String strName,
 +
String strConfigurationBase,
 +
java.util.Map mapSettingHandlers,
 +
java.util.Map mapSettingsGlobal,
 +
Object settingsParent,
 +
org.apache.axiom.om.OMElement omSetting)
 +
throws Exception;
 +
</source>
 +
to:
 +
<source lang="java">
 +
public abstract ISetting getSetting
 +
(String strName,
 +
String strConfigurationBase,
 +
java.util.Map mapSettingHandlers,
 +
ISetting globalSetting,
 +
ISetting parentSetting,
 +
org.apache.axiom.om.OMElement omSetting,
 +
org.eclipse.higgins.configuration.api.IConfigurationHandler configHandler)
 +
throws Exception;
 +
</source>
 +
 
 +
'''All implementations of ISettingHandler in the com.ibm.higgins.configuration.xml package will be modified to conform to this new method signature.'''
 +
 
 +
All IConfigurableComponent implementatations (i.e. The IdASRegistry, all IContextFactory implementations) will adhere to consistent use of ISetting for representing and manipulating configuration settings.
 +
 +
Example: Register a new context factory with the IdASRegistry
 +
 
 +
The IdAS client application will call the following code to register a new context factory:
 +
 
 +
<source lang="java">
 +
ConfigurationHandler handler = new ConfigurationHandler();
 +
handler.setConfigurationBase(".");
 +
handler.setFileName("TestConfiguration.xml");
 +
Handler.configure();
 +
 
 +
IdASRegistry registry = (IdASRegistry)((ISetting)((Map)handler.getSettings().getValue()).get("IdentityAttributeService")).getValue();
 +
 
 +
String[] types = {"$context+file"};
 +
registry.registerContextFactory(types, "FileContextFactory");
 +
 
 +
The registerContextFactory method in IdASRegistry must persist this change in the XML file under 'ContextFactoryInstancesList' setting as:
 +
 
 +
<Setting Name="FileContextFactory" Type="htf:map">
 +
<Setting Name="Instance" Type="xsd:string">FileContextFactory</Setting>
 +
<Setting Name="ContextTypes" Type="htf:list">
 +
<Setting Name="FileContextType" Type="xsd:string">$context+file</Setting>
 +
</Setting>
 +
</Setting>
 +
</source>
 +
 
 +
To do this, the registerContextFactory method will be updated as follows:
 +
 +
<source lang="java">
 +
/* Get the list of ISettings for 'ContextFactoryInstancesList' */
 +
List factoryList = (List)contextFactoryInstanceSettings.getValue();
 +
 
 +
/* Add a child setting to the context factories list setting. The child
 +
* setting is a map containing details about the new context factory */
 +
Map mapCtxFactory = new HashMap();
 +
this.contextFactoryInstanceSettings.addChildSetting(factoryClassName, "htf:map", mapCtxFactory);
 +
 
 +
for ( int i = 0; i < factoryList.size(); i++ ) {
 +
ISetting factorySetting = (ISetting)factoryList.get(i);
 +
if ( factorySetting.getName().equalsIgnoreCase(factoryClassName) ) {
 +
/* Add the 'Instance' setting to the new context factory setting */
 +
factorySetting.addChildSetting("Instance", "xsd:string", factoryClassName);
 +
 
 +
/* Add the 'ContextTypes' setting of type list to the new context factory setting */
 +
List typeList = new ArrayList(types.length);
 +
factorySetting.addChildSetting("ContextTypes", "htf:list", typeList);
 +
ISetting typeSetting = (ISetting)((Map)factorySetting.getValue()).get("ContextTypes");
 +
for ( int j = 0; j < types.length; j++ ) {
 +
typeSetting.addChildSetting(factoryClassName + "Type", "xsd:string", types[j]);
 +
}
 +
}
 +
}
 +
 
 +
/* Save the update */
 +
_config_handler.applyUpdates();
 +
 
 +
</source>
 +
 
 +
 
 +
 
 +
== Conclusions ==
 +
 
 +
Conclude something
 +
 
 +
== Other considerations ==
 +
 
 +
*Applications may need a way to compare the in memory configuration with what is in the configuration file to detect race conditions with other applications or threads. Once updating the file, the application could check the file contents to make sure that the changes were not overwritten by another application calling applyUpdates.

Revision as of 08:28, 15 July 2008

Configuration Management

Applications need the ability to manage the run time configuration and persisted configuration files of various Higgins components. This example will focus on IdAS Registry as the use case, but applies to any IConfigurableComponent.

The IdAS registry can be initialized from an XML file through the configuration APIs. The 'IdentityAttributeService' section in the configuration XML file that corresponds to the IdAS registry typically contains the following information:

A section of settings for' . context factories, for e.g.

<Setting Name="ContextFactoryInstancesList" Type="htf:list">
	<Setting Name="JNDIContextFactory" Type="htf:map">
		<Setting Name="Instance" Type="xsd:string">JNDIContextFactory</Setting>
		<Setting Name="ContextTypes" Type="htf:list">
			<Setting Name="JNDIContextType" Type="xsd:string">$context+ldap</Setting>
		</Setting>
	</Setting>
</Setting>

A section of settings fhinor the context IDs, for e.g.

<Setting Name="ContextIdsList" Type="htf:list">
	<Setting Name="urn:ldap@ltoyota" Type="htf:map">
		<Setting Name="ContextId" Type="xsd:string">urn:ldap@ltoyota</Setting>
			<Setting Name="ContextTypes" Type="htf:list">
				<Setting Name="JNDIContextType" Type="xsd:string">$context+ldap</Setting>
			</Setting>
			<Setting Name="Connection" Type="htf:map">
				<Setting Name="Address" Type="xsd:string">ldap://ltoyota:389</Setting> 
				<Setting Name="SearchBase" Type="xsd:string">o=Higgins</Setting>
			</Setting>
		</Setting>
	</Setting>
</Setting>

Following APIs exist to update the IdASRegistry:

  • registerContextFactory
  • removeContextFactory
  • registerContextId
  • removeContextId

All the above APIs currently update only the in-memory data-structures corresponding to the list of context factories and contextIds. There is no mechanism to persist updates through these APIs to the configuration XML file.

API Proposal

Associate an IConfigurationHandler with an IConfigurableComponent

The Configuration API defines:

  • An interface that must be implemented by all components that must be configured through the Configuration API
  • An IConfigurationHandler interface that must be implemented by all methods of configuring the IdAS components like XML/XRDS etc.

In order for updates to a configurable component be reflected in the persistent storage, it must be associated with a configuration handler. A new API would be added to the com.ibm.higgins.configuration.api.IConfigurableComponent interface:

public abstract void setConfigurationHandler(org.eclipse.higgins.configuration.api.IConfigurationHandler handler);

Additionally, the IConfigurationHandler interface would be extended to have a new API

public abstract void applyUpdates() throws Exception;

This API would be called by the IConfigurableComponent whenever it wants to save the in-memory XML Object Model to the file.

Typing the data

Currently, the in-memory configuration is represented by the Map data structure. Thus the 'IdentityAttributeService' section is represented by a Map with the keys 'ContextFactoryInstancesList' and 'ContextIdsList' and whose values are the lists of context factories and context ids respectively. This structure does not represent the 'type' of the value of each setting, which becomes necessary while writing back information to the file.

There are two options for handling the data types (so far), Adding an ISettingDescriptor to detail the Types in the Map, or representing each element in the configuration through the com.ibm.higgins.configuration.api.ISetting interface.

Proposal 1: ISettingDescriptors

Add description

Option 2: Represent each setting in the configuration file using the ISetting interface

Currently, the in-memory configuration is represented by the Map data structure. Thus the 'IdentityAttributeService' section is represented by a Map with the keys 'ContextFactoryInstancesList' and 'ContextIdsList' and whose values are the lists of context factories and context ids respectively. This structure does not represent the 'type' of the value of each setting, which becomes necessary while writing back information to the file.

The change of this option is to represent each element in the XML configuration through the com.ibm.higgins.configuration.api.ISetting interface. The global settings is an ISetting whose value could be any of the types represented in the 'SettingHandlers' section of the configuration file. If the type of a setting is a List, then the value of that setting would be a list of ISetting(s). Thus each setting in the XML file has a corresponding in-memory ISetting object.

Change XML based configuration API

A new class com.ibm.higgins.configuration.xml.Setting that implements the com.ibm.higgins.configuration.api.ISetting interface has been introduced. It contains the setting name, setting type and setting value. Additionally it also contains the in-memory XML Object Model (OMElement) representation for that setting. It will have methods to add child settings and remove settings.

Here is a prototype implementation of the addChildSetting() method:

public void addChildSetting(String name, String type, Object value) { 
 
	/* Create an OMElement corresponding to the child setting to add */
	OMFactory factory = OMAbstractFactory.getOMFactory();
	OMElement addElement = factory.createOMElement("Setting", null);
	addElement.addAttribute("Name", name, null);
	addElement.addAttribute("Type", type, null);
 
	/* Create the new child setting to add to this setting */
	ISetting setting = new Setting(name, type, value, addElement);
 
	/* Depending on the type of the value of a child setting, create 
	 * sub-settings for the child setting.
	 */
	if ( type.equalsIgnoreCase("htf:list")) { 
		List listValues = (List)value;
		for ( int i = 0; i < listValues.size(); i++ ) { 
			ISetting childSetting = (ISetting)listValues.get(i);
			setting.addChildSetting(childSetting.getName(), childSetting.getType(),
			childSetting.getValue());
		}
	} else if ( setting.getType().equalsIgnoreCase("htf:map")) { 
		Map mapValues = (Map)setting.getValue();
		Iterator itr = mapValues.keySet().iterator();
		while (itr.hasNext()) { 
			ISetting childSetting = (ISetting)itr.next();
			setting.addChildSetting(childSetting.getName(), childSetting.getType(),
			childSetting.getValue());
		}
	} else { 
		addElement.setText(setting.getValue().toString());
	}
 
	/* Add the child OMElement to this setting's OMElement */
	_element.addChild(addElement);
 
	/* Update this setting's values to include the child setting */
	if ( _type.equalsIgnoreCase("htf:map")) { 
		((Map)_value).put(name, setting);
	} else if (_type.equalsIgnoreCase("htf:list")) { 
		((List)_value).add(setting);
	}
}

An ISetting represents the global settings in the com.ibm.higgins.configuration.xml.ConfigurationHandler instead of a Map.

The signature for the getSetting() method in com.ibm.higgins.configuration.xml.ISettingHandler has changed from:

		public abstract Object getSetting
		(String strName,
		String strConfigurationBase,
		java.util.Map mapSettingHandlers,
		java.util.Map mapSettingsGlobal,
		Object settingsParent,
		org.apache.axiom.om.OMElement omSetting)
		throws Exception;

to:

		public abstract ISetting getSetting
		(String strName,
		String strConfigurationBase,
		java.util.Map mapSettingHandlers,
		ISetting globalSetting,
		ISetting parentSetting,
		org.apache.axiom.om.OMElement omSetting,
		org.eclipse.higgins.configuration.api.IConfigurationHandler configHandler)
		throws Exception;

All implementations of ISettingHandler in the com.ibm.higgins.configuration.xml package will be modified to conform to this new method signature.

All IConfigurableComponent implementatations (i.e. The IdASRegistry, all IContextFactory implementations) will adhere to consistent use of ISetting for representing and manipulating configuration settings.

Example: Register a new context factory with the IdASRegistry

The IdAS client application will call the following code to register a new context factory:

ConfigurationHandler handler = new ConfigurationHandler();
handler.setConfigurationBase(".");
handler.setFileName("TestConfiguration.xml");
Handler.configure();
 
IdASRegistry registry = (IdASRegistry)((ISetting)((Map)handler.getSettings().getValue()).get("IdentityAttributeService")).getValue();
 
String[] types = {"$context+file"};
registry.registerContextFactory(types, "FileContextFactory");
 
The registerContextFactory method in IdASRegistry must persist this change in the XML file under 'ContextFactoryInstancesList' setting as: 
 
<Setting Name="FileContextFactory" Type="htf:map">
	<Setting Name="Instance" Type="xsd:string">FileContextFactory</Setting>
	<Setting Name="ContextTypes" Type="htf:list">
		<Setting Name="FileContextType" Type="xsd:string">$context+file</Setting>
	</Setting>
</Setting>

To do this, the registerContextFactory method will be updated as follows:

/* Get the list of ISettings for 'ContextFactoryInstancesList' */
List factoryList = (List)contextFactoryInstanceSettings.getValue();
 
/* Add a child setting to the context factories list setting. The child
 * setting is a map containing details about the new context factory */
Map mapCtxFactory = new HashMap();
this.contextFactoryInstanceSettings.addChildSetting(factoryClassName, "htf:map", mapCtxFactory);
 
for ( int i = 0; i < factoryList.size(); i++ ) { 
	ISetting factorySetting = (ISetting)factoryList.get(i);
	if ( factorySetting.getName().equalsIgnoreCase(factoryClassName) ) { 
		/* Add the 'Instance' setting to the new context factory setting */
		factorySetting.addChildSetting("Instance", "xsd:string", factoryClassName);
 
		/* Add the 'ContextTypes' setting of type list to the new context factory setting */
		List typeList = new ArrayList(types.length);
		factorySetting.addChildSetting("ContextTypes", "htf:list", typeList);
		ISetting typeSetting = 	(ISetting)((Map)factorySetting.getValue()).get("ContextTypes");
		for ( int j = 0; j < types.length; j++ ) {
			typeSetting.addChildSetting(factoryClassName + "Type", "xsd:string", types[j]);
		}
	}
}
 
/* Save the update */
_config_handler.applyUpdates();


Conclusions

Conclude something

Other considerations

  • Applications may need a way to compare the in memory configuration with what is in the configuration file to detect race conditions with other applications or threads. Once updating the file, the application could check the file contents to make sure that the changes were not overwritten by another application calling applyUpdates.

Back to the top