Genesys CTI User Forum
Genesys CTI User Forum => Genesys-related Development => Topic started by: Gabi on March 31, 2016, 01:03:09 PM
-
I am writing a WDE extension. I have been told that I can access the application and agent configuration via the config manager (container.Resolve<IConfigManager>), but the config manager's interface is far from friendly.
Could someone please show me an example of how to get the contents of a configuration section?
Thank you in advance.
-
IConfigManager cfgMgr = container.Resolve<IConfigManager>;
cfgMgr.GetValue("name of the option on WDE object");
Do not know what is not friendly on that..
-
I would like to get the contents of an arbitrary section. Does IConfigManager only return the options of the interaction-workspace section? And is there any way to get the agent's configuration?
-
There is probably an interface in the IWS API that allows you to get the agent information, but I am not familiar with it off the top of my head. Search through the included .chm help file for *Manager* and see if you come up with anything.
If all else fails you can use PSDK from your WDE extension, CfgPersonQuery is what you would want to look up in the PSDK documentation.
-
Perhaps there is a way to access the ConfServerProtocol?
-
There is, perhaps through IAgent / IAgentManager (I forget the name of the interface and dont have the .chm files installed right now).
-
You can try to read some configuration directly by IAgent.
Try with IConfigurationService.
Regards.
-
Thanks, daniel_san, that looks promising. However, I'm still having some problems.
I have done the following.
[code]IConfigurationService = container.Resolve<IConfigurationService>
RequestReadObjects requestReadObjects =
RequestReadObjects.Create(
(int)CfgObjectType.CFGApplication,
filterKey);
configurationService.ConfigServerProtocol.Request(requestReadObjects);[/code]
I have an Event Broker to handle the EventObjectsRead, which I know is deprecated but I still don't know a better way to do it, and in any case that worked when I created my own connection to the Config Server, but now...
This simply doesn't work. WDE gets stuck in some infinite loop and no log is produced.
Does anyone have any idea what I did wrong, and what should be done instead? Is it possible that the ConfigServerProtocol was not yet initialized or something?
Thanks in advance.
-
On CfgServer logs do you see your request?
-
[quote author=Gabi link=topic=9465.msg42957#msg42957 date=1459869466]
Thanks, daniel_san, that looks promising. However, I'm still having some problems.
I have done the following.
[code]IConfigurationService = container.Resolve<IConfigurationService>
RequestReadObjects requestReadObjects =
RequestReadObjects.Create(
(int)CfgObjectType.CFGApplication,
filterKey);
configurationService.ConfigServerProtocol.Request(requestReadObjects);[/code]
I have an Event Broker to handle the EventObjectsRead, which I know is deprecated but I still don't know a better way to do it, and in any case that worked when I created my own connection to the Config Server, but now...
This simply doesn't work. WDE gets stuck in some infinite loop and no log is produced.
Does anyone have any idea what I did wrong, and what should be done instead? Is it possible that the ConfigServerProtocol was not yet initialized or something?
Thanks in advance.
[/quote]
Which application(s) are you trying to get and which information do you need from them?
-
[quote author=PeteHoyle link=topic=9465.msg42959#msg42959 date=1459877797]
Which application(s) are you trying to get and which information do you need from them?
[/quote]I'm trying to access the WDE application and get the [b]whole[/b] configuration, not just the interaction-workspace section.
I will - eventually - need information about the current agent, agent groups and campaigns too.
I'm afraid I don't know much about reading config server logs, but here's the log of the last 2 minutes (I closed WDE right after I failed to read the configuration):
http://pastebin.com/4CSyqrN3
I think the request on line 1641 may be mine, but it may also be the one WDE does on its own when it starts.
-
Nevermind, it worked. I wasn't processing the result of the request correctly.
-
;D Congrats! just a suggestion, try to test always with another app which is not the one on PRD, on CME you just clone the Application you are using on PRD and use that for your tests. Easier to debug ;)
Can you please share your solution code here for reference?
Thanks and good luck!
-
[quote author=Gabi link=topic=9465.msg42991#msg42991 date=1460392615]
Nevermind, it worked. I wasn't processing the result of the request correctly.
[/quote]
Looks like you got it working, another method is like this:
IConfigurationService configService = container.Resolve<IConfigurationService>();
KeyValueCollection options = configService.MyApplication.Options;
-
[quote author=PeteHoyle link=topic=9465.msg42993#msg42993 date=1460449334]
[quote author=Gabi link=topic=9465.msg42991#msg42991 date=1460392615]
Nevermind, it worked. I wasn't processing the result of the request correctly.
[/quote]
Looks like you got it working, another method is like this:
IConfigurationService configService = container.Resolve<IConfigurationService>();
KeyValueCollection options = configService.MyApplication.Options;
[/quote]Thanks! I've already done what I needed, but knowing about this is bound to prove useful someday.
-
[quote author=cavagnaro link=topic=9465.msg42992#msg42992 date=1460401003]
;D Congrats! just a suggestion, try to test always with another app which is not the one on PRD, on CME you just clone the Application you are using on PRD and use that for your tests. Easier to debug ;)
Can you please share your solution code here for reference?
Thanks and good luck!
[/quote]
Sorry, I don't understand. Are you suggesting that I clone the Config Server? Anyway, none of this is in production, I'm just running tests on a demo server while I develop my extension.
Here's the working code. It's a class that keeps a local cache of the application configuration options, and also provides an interface for making requests to the Configuration Server (retrieveConfigXml), which I am using to handle requests from an external application.
I'm not reading the agent configuration yet, that part is left for future work.
[code]
using System;
using System.Configuration;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using Genesyslab.Platform.ApplicationBlocks.Commons.Broker;
using Genesyslab.Platform.Commons.Collections;
using Genesyslab.Platform.Commons.Connection;
using Genesyslab.Platform.Commons.Protocols;
using Genesyslab.Platform.Configuration.Protocols;
using Genesyslab.Platform.Configuration.Protocols.ConfServer;
using Genesyslab.Platform.Configuration.Protocols.ConfServer.Events;
using Genesyslab.Platform.Configuration.Protocols.ConfServer.Requests.Objects;
using Genesyslab.Platform.ApplicationBlocks.Commons.Protocols;
using Genesyslab.Platform.Configuration.Protocols.Types;
using System.Xml.Linq;
using System.Collections;
using Genesyslab.Platform.Commons.Logging;
using Genesyslab.Desktop.Infrastructure.DependencyInjection;
using System.Threading;
using Genesyslab.Desktop.Infrastructure.Configuration;
using Genesyslab.Desktop.Modules.Core.SDK.Configurations;
using Genesyslab.Platform.ApplicationBlocks.ConfigurationObjectModel.Queries;
using Genesyslab.Platform.ApplicationBlocks.ConfigurationObjectModel;
using Genesyslab.Desktop.Modules.Core.Model.Agents;
namespace Genesyslab.Desktop.Modules.ExtensionUtils85.Utils
{
public class ConfigurationServiceClient : LoggingObject
{
protected string appName;
protected XmlDocument doc = null;
protected IDictionary<string, IDictionary<string, string>> config;
private bool objectsRead = false;
protected ILogger log;
protected ConfServerProtocol cfgProtocol;
protected static ConfigurationServiceClient instance;
public ConfigurationServiceClient(IObjectContainer container)
{
this.log = container.Resolve<ILogger>().CreateChildLogger("ConfigurationServiceClient");
this.appName = container.Resolve<IConfigurationService>().ApplicationName;
this.cfgProtocol = container.Resolve<IConfigurationService>().ConfigServerProtocol;
}
/// <summary>
/// Initializes the service and stores the configuration options.
/// </summary>
/// <param name="container">WDE's object container.</param>
public static void initialize(IObjectContainer container)
{
if (instance == null)
{
instance = new ConfigurationServiceClient(container);
instance.ReadObjects();
}
}
protected IMessage prepareRequestReadObjectsMessage(ICfgQuery query) {
if (query is CfgXPathBasedQuery)
return RequestReadObjects2.Create((int)(((CfgXPathBasedQuery) query).ObjectType),((CfgXPathBasedQuery) query).XPath);
int objType = (int)CfgObjectType.CFGNoObject;
if (query is ICfgFilterBasedQuery) {
KeyValueCollection objectFilter = prepareReadObjectsFilter((ICfgFilterBasedQuery) query);
objType = (int)((ICfgFilterBasedQuery) query).QueryObjectType;
return RequestReadObjects.Create(objType, objectFilter);
} else {
throw new ArgumentException("Unsupported query type.");
}
}
protected KeyValueCollection prepareReadObjectsFilter(ICfgFilterBasedQuery query) {
KeyValueCollection objectFilter = new KeyValueCollection();
if (query != null) {
Hashtable filter = query.Filter;
foreach (string key in filter.Keys) {
Object value = filter[key];
if (value is Int64)
{
value = Convert.ToInt32(value);
}
try
{
objectFilter.Add(key, (int)value);
}
catch (Exception)
{
objectFilter.Add(key, value);
}
}
}
return objectFilter;
}
public static ConfigurationServiceClient getInstance()
{
return instance;
}
protected void OnEventError(IMessage theMessage)
{
EventError eventError = theMessage as EventError;
if (eventError == null)
{
log.Error("EventError: null.");
return;
}
log.Error("EventError: " + eventError + "\n");
}
protected void OnEventObjectsSent(IMessage theMessage)
{
EventObjectsSent objectsSent = theMessage as EventObjectsSent;
if (objectsSent == null)
{
log.Debug("EventObjectsSent: null");
return;
}
log.Debug("EventObjectsSent: "
+ objectsSent + "\n");
}
protected void OnEventObjectsRead(IMessage theMessage)
{
log.Debug("Application configuration read.");
EventObjectsRead objects =
(EventObjectsRead)theMessage;
String xml = extractXML(objects);
doc = new XmlDocument();
doc.LoadXml(xml);
log.Debug("Config XML" + xml);
this.objectsRead = true;
}
public string retrieveConfigXml(ICfgQuery query)
{
IMessage request = this.prepareRequestReadObjectsMessage(query);
ConfServerProtocol protocol = getCfgProtocol();
IMessage response = protocol.Request(request);
string xml = "";
if (response is EventObjectsRead)
{
xml = extractXML(response as EventObjectsRead);
}
else if (response is EventError)
{
OnEventError(response);
}
else
{
log.Error("Error on retrieveConfigXml. Response: " + response.ToString());
}
return xml;
}
protected static string extractXML(EventObjectsRead objects)
{
XDocument resultDocument =
(XDocument)objects.ConfObject;
String xml = extractXML(resultDocument);
return xml;
}
protected static string extractXML(XDocument document)
{
StringBuilder xmlAsText = new StringBuilder();
StringWriter stringWriter = new StringWriter(xmlAsText);
XmlTextWriter xmlTextWriter =
new XmlTextWriter(stringWriter);
xmlTextWriter.Formatting = Formatting.Indented;
document.Save(xmlTextWriter);
String xml = xmlAsText.ToString();
return xml;
}
protected string getAttribute(XmlNode node, string attributeName)
{
string res = "null";
if (node.Attributes[attributeName] != null)
{
res = node.Attributes[attributeName].InnerText;
}
return res;
}
protected string getSectionXML(string sectionName, XmlDocument doc)
{
string res = null;
XmlNode node = getSectionNode(sectionName, doc);
if (node != null)
{
res = node.InnerXml;
}
return res;
}
protected XmlNode getSectionNode(string sectionName, XmlDocument doc)
{
XmlNode res = null;
foreach (XmlNode node in doc.DocumentElement.ChildNodes)
{
foreach (XmlNode innernode in node.ChildNodes)
{
if ("options".Equals(innernode.Name))
{
foreach (XmlNode optionnode in innernode.ChildNodes)
{
string key = getAttribute(optionnode, "key");
if (key.Equals(sectionName))
{
res = optionnode;
}
}
}
}
}
return res;
}
/// <summary>
/// Gets a section from the cached application configuration.
/// </summary>
/// <param name="sectionName">the name of the section.</param>
/// <returns>a dictionary with the configuration options for the section.</returns>
public IDictionary<string, string> getSection(string sectionName)
{
if (doc == null)
{
ReadObjects();
}
IDictionary<string, string> dict;
if (config.ContainsKey(sectionName))
{
dict = config[sectionName];
}
else
{
dict = new Dictionary<string, string>();
XmlNode node = getSectionNode(sectionName, doc);
if (node != null)
{
foreach (XmlNode innernode in node.ChildNodes)
{
string key = getAttribute(innernode, "key");
string value = getAttribute(innernode, "value");
dict.Add(key, value);
}
}
config.Add(sectionName, dict);
}
return dict;
}
/// <summary>
/// Gets the value of a configuration option from the local cache as a string.
/// </summary>
/// <param name="sectionName">the name of the section to read from.</param>
/// <param name="key">the key for the desired option.</param>
/// <param name="defaultValue">the default value in case the option is not defined.</param>
/// <returns>the value for the option (as a string), or the default value if it is undefined.</returns>
public string requestProperty(string sectionName, string key, string defaultValue)
{
if (!objectsRead)
{
this.ReadObjects();
}
IDictionary<string, string> section = getSection(sectionName);
return requestProperty(section, key, defaultValue);
}
public string requestProperty(IDictionary<string, string> section, string key, string defaultValue)
{
string res = null;
if (section.ContainsKey(key))
{
res = section[key];
}
if (res == null)
{
log.Info("Using default value " + defaultValue + " for option " + key + ".");
res = defaultValue;
}
return res;
}
/// <summary>
/// Gets the value of a configuration option from the local cache, if it is a boolean.
/// </summary>
/// <param name="sectionName">the name of the section to read from.</param>
/// <param name="key">the key for the desired option.</param>
/// <param name="defaultValue">the default value in case the option is not defined.</param>
/// <returns>the value for the option, or the default value if it is undefined or not a boolean.</returns>
public bool requestProperty(string sectionName, string key, bool defaultValue)
{
bool res = defaultValue;
string defString = defaultValue ? "true" : "false";
string value = this.requestProperty(sectionName, key, defString);
string lowervalue = value.ToLower();
if ("true".Equals(lowervalue))
{
res = true;
}
else if ("false".Equals(lowervalue))
{
res = false;
}
else
{
log.Warn("The value for option " + key + " should be boolean, but it is not.");
}
return res;
}
/// <summary>
/// Gets the value of a configuration option from the local cache, if it is an integer.
/// </summary>
/// <param name="sectionName">the name of the section to read from.</param>
/// <param name="key">the key for the desired option.</param>
/// <param name="defaultValue">the default value in case the option is not defined.</param>
/// <returns>the value for the option, or the default value if it is undefined or not an integer.</returns>
public int requestProperty(string sectionName, string key, int defaultValue)
{
int res = defaultValue;
string defString = defaultValue.ToString();
string value = this.requestProperty(sectionName, key, defString);
try
{
res = int.Parse(value);
}
catch (Exception ex)
{
log.Warn("The value for option " + key + " should be an integer, but it is not.", ex);
res = defaultValue;
}
return res;
}
/// <summary>
/// Updates the local application configuration cache by reading the configuration from the config server.
/// </summary>
public void ReadObjects()
{
//Initialize the dictionary which will store the cached application configuration on demand.
config = new Dictionary<string, IDictionary<string, string>>();
KeyValueCollection filterKey = new KeyValueCollection();
filterKey.Add("name", this.appName);
RequestReadObjects requestReadObjects =
RequestReadObjects.Create(
(int)CfgObjectType.CFGApplication,
filterKey);
ConfServerProtocol protocol = getCfgProtocol();
IMessage response = protocol.Request(requestReadObjects);
if (response is EventObjectsRead)
{
OnEventObjectsRead(response);
}
else if (response is EventError)
{
OnEventError(response);
}
else {
log.Error("Response: "+response.ToString());
}
}
protected static ConfServerProtocol getCfgProtocol()
{
return this.cfgProtocol;
}
public string getApplicationName()
{
return this.appName;
}
}
}
[/code]