Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Higgins Configuration Management

Revision as of 09:38, 15 July 2008 by Kuehrmc.gmail.com (Talk | contribs) (Option 1: ISettingDescriptors)

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.

Option 1: ISettingDescriptors

This option was an option discussed on the mailing list in August 2007 at [1]. Greg Byrd opened the subject again on this thread [2] and started a thread after a dev call to reinvigorate the topic[3].


Greg added the ISettingDescriptor interface to org.eclipse.higgins.configuration.api As an approach to define the structure and type of the data in a configuration store.

public interface ISettingDescriptor {
	public String getName();
	public Class getType();
	public String getDisplayString();
	public String getDocString();
	public List getSubSettings();
	public Object getConstraint(String key);
 
	public void setName(String name);
	public void setType(Class type);
	public void setDisplayString(String display);
	public void setDocString(String doc);
 
	public void addConstraint(String name, Object value);
	public void removeConstraint(String name);
	public void addSubSetting(ISettingDescriptor sub);
	public void addSubSetting(int index, ISettingDescriptor sub);
	public boolean removeSubSetting(ISettingDescriptor sub);
	public ISettingDescriptor removeSubSetting(int index);
 
}


Different constraints are relevant for different setting types. E.g., minValue makes sense for int/float, but not stream. So the manager can query for a particular constraint, if null returned, then that constraint was not specified. Or can iterate through all constraints, etc. Constraint is a string/value pair.

There are some "standard" constraint strings defined as static variables in package org.eclipse.higgins.configuration.common.SettingDescriptor, but any implementation could always do more.

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