Contact Expert v7.2 for Skype for Business Server
CAS Configuration Service
The Client Access Server Configuration Service exposes configuration capabilities to 3rd party O&M solutions. It offers remote monitoring and configuration facilities. Among others, clients can easily change system runtime properties and can ask for internal runtime details.
The capabilities exposed by the Configuration Service can be categorized as follows:
Methods | Description |
---|---|
SetLogLevel() |
Set a specific log level |
GetLogLevel() |
Retrieve the current log level |
Update() |
Reload configuration |
GetProperty() |
Retrieve a specific runtime property |
SetProperty() |
Change a specific runtime property |
GetServerVersion() |
Retrieve the version number |
DumpState() |
Dump internal state to log |
The following sections provide detailed information about each of these methods.
Note
Source code examples are for demonstration purposes only.
More sophisticated error handling might be required in real-world scenarios.
Since the capabilities exposed by the Configuration Service have low security impact, unauthenticated access is available to the Configuration Service.
Connecting to the service
After the proxy code is generated based on the web service WSDL, connecting to the Configuration Service is quite easy. The following code snippet shows how to do that.
@javax.xml.ws.WebServiceRef(wsdlLocation="http://[FQDN]:[Port]/ClientAccessServer/ConfigurationService?wsdl")
static ConfigurationService configService = new ConfigurationService();
public static ConfigurationPortType connect() {
ConfigurationPortType configPort = null;
try {
if((configPort = configService.getConfigurationPortTypePort()) != null) {
System.out.println("Connecting to Configuration Service is done");
} else {
System.err.println("Failed to connect to Configuration Service");
}
}
catch(Exception ex) {
System.err.println("Failed to connect to Configuration Service. Reason: " + ex.getMessage());
}
return configPort;
}
Changing log level
Each log entry written by the Client Access Server is associated with a specific log level. Some log entries hold only debug information; some of them indicate fatal errors. The Client Access Server writes only those entries to the log file whose levels are above a given threshold. This threshold can be changed by any client. The following example shows how to change the threshold to LEVEL_DEBUG.
setLogLevel(configPort, LogLevel.LEVEL_DEBUG);
public static void setLogLevel(ConfigurationPortType configPort, LogLevel newLogLevel) {
try {
if(configPort.setLogLevel(newLogLevel) == WsStatus.STATUS_OK) {
System.out.println("Service log level is changed to: " + newLogLevel.toString());
} else {
System.err.println("Failed to change log level");
}
}
catch(GenException_Exception gex) {
System.err.println("Failed to change log level. Reason: " + gex.getMessage());
}
catch(Exception ex) {
System.err.println("Communication failure. Reason: " + ex.getMessage());
}
}
Retrieving current log level
The current log threshold can be retrieved as shown by the following code snippet.
public static LogLevel getLogLevel(ConfigurationPortType configPort) {
javax.xml.ws.Holder<LogLevel> logLevel = new javax.xml.ws.Holder<LogLevel>();
javax.xml.ws.Holder<WsStatus> result = new javax.xml.ws.Holder<WsStatus>();
try {
configPort.getLogLevel(result, logLevel);
if(result.value == WsStatus.STATUS_OK) {
System.out.println("Current service log level: " + logLevel.value);
return logLevel.value;
} else {
System.err.println("Failed to retrieve log level");
}
}
catch(GenException_Exception gex) {
System.err.println("Failed to retrieve log level. Reason: " + gex.getMessage());
}
catch(Exception ex) {
System.err.println("Communication failure. Reason: " + ex.getMessage());
}
return LogLevel.LEVEL_NONE;
}
Reloading configuration
The Client Access Server reads several configuration properties from its Java web.xml file. Generally, this file is loaded only when the server is starting up. Sometimes it is practical to change the file content manually and instruct the Client Access Server to reload the updated values. This makes possible to avoid the server restart which otherwise would be necessary. The following code shows how to instruct the Client Access Server to reload configuration properties.
public static void update(ConfigurationPortType configPort) {
try {
if(configPort.update() == WsStatus.STATUS_OK) {
System.out.println("Service configuration is reloaded");
} else {
System.err.println("Failed to reload service configuration");
}
}
catch(GenException_Exception gex) {
System.err.println("Failed to reload service configuration. Reason: " + gex.getMessage());
}
catch(Exception ex) {
System.err.println("Communication failure. Reason: " + ex.getMessage());
}
}
Retrieving runtime property
The Client Access Server can be queried to retrieve the current value of a specific runtime property. The code below shows how to do that. Actually, the code retrieves the time the Client Access Server is most recently started up.
public static String getProperty(ConfigurationPortType configPort, String propertyName) {
javax.xml.ws.Holder<Property> runtimeProperty = new javax.xml.ws.Holder<Property>();
runtimeProperty.value = new Property();
runtimeProperty.value.setName(propertyName);
runtimeProperty.value.setValue("");
try {
if(configPort.getProperty(runtimeProperty) == WsStatus.STATUS_OK) {
System.out.println("Property value: " + runtimeProperty.value.getValue());
return runtimeProperty.value.getValue();
} else {
System.err.println("Failed to retrieve runtime property");
}
}
catch(GenException_Exception gex) {
System.err.println("Failed to retrieve runtime property. Reason: " + gex.getMessage());
}
catch(Exception ex) {
System.err.println("Communication failure. Reason: " + ex.getMessage());
}
return null;
}
There are several other runtime properties which can be retrieved. The following table lists all of them by indicating which ones can be updated and which are read-only.
Property | Read only? | Description |
---|---|---|
AvailableProcessors |
Yes | The number of processors available on the server. |
FreeMemory |
Yes | Currently allocated but available memory (in bytes). |
MaximumMemory |
Yes | Maximum memory can be allocated (in bytes). |
TotalMemory |
Yes | Currently allocated memory (in bytes). |
StartupTime |
Yes | Most recent time the service was started up. |
ThreadBlockingUnitTimeMsecs |
No | Time unit (in milliseconds) to block client threads. |
ThreadBlockingCycles |
No | Maximum number of times client threads can be blocked. |
MaxInactiveTimeSecs |
No | Client session timeout (in seconds). |
CleanUpPeriodSecs |
No | Time period (in seconds) to reclaim unused resources. |
URLDefaultTask |
Yes | URL to navigate operators to when having no active tasks. |
URLDisplayTask |
Yes | URL used to download tasks from. |
URLCloseTask |
Yes | URL to navigate operators to when closing tasks. |
URLDisplayHistory |
Yes | URL used to download contact history from. |
URLDefaultHistory |
Yes | URL to navigate operators to when no contact history to be displayed. |
URLContactSearch |
Yes | URL used to browse contact database. |
URLContactProperty |
Yes | URL used to display contact specific details. |
URLCampaignHelp |
Yes | URL to navigate operators to when deciding to display campaign specific help pages. |
URLContactSwap |
Yes | URL to navigate operators to when deciding to replace the current contact record. |
URLContactPrint |
Yes | URL to navigate operators to when deciding to print the content of the current contact record. |
URLMessageSend |
Yes | URL to navigate operators to when deciding to send a message to the contact. |
SendDDEEvents |
No | Specifies whether agent applications should send client side DDE events or not. |
ClosureCodes |
Yes | Closure codes available for operators when closing tasks. |
Updating runtime property
Updating a property value in the web.xml
file has permanent effect. The new value affects the operation even after the Client Access Server is restarted. There are several situations where changing a property only temporarily would be beneficial. The following code snippet shows how to increase the session timeout temporarily.
setProperty(configPort, "MaxInactiveTimeSecs", "600");
public static void setProperty(ConfigurationPortType configPort, String propertyName, String propertyValue) {
Property runtimeProperty = new Property();
runtimeProperty.setName(propertyName);
runtimeProperty.setValue(propertyValue);
try {
if(configPort.setProperty(runtimeProperty) == WsStatus.STATUS_OK) {
System.out.println("Property is updated");
} else {
System.err.println("Failed to update runtime property");
}
}
catch(GenException_Exception gex) {
System.err.println("Failed to update runtime property. Reason: " + gex.getMessage());
}
catch(Exception ex) {
System.err.println("Communication failure. Reason: " + ex.getMessage());
}
}
Checking server version
There is a separate method to retrieve the version number of the Client Access Server programmatically.
public static String getServerVersion(ConfigurationPortType configPort) {
javax.xml.ws.Holder<String> version = new javax.xml.ws.Holder<String>();
javax.xml.ws.Holder<WsStatus> result = new javax.xml.ws.Holder<WsStatus>();
try {
configPort.getServerVersion(result, version);
if(result.value == WsStatus.STATUS_OK) {
System.out.println("Service version: " + version.value);
return version.value;
} else {
System.err.println("Failed to retrieve service version");
}
}
catch(GenException_Exception gex) {
System.err.println("Failed to retrieve service version. Reason: " + gex.getMessage());
}
catch(Exception ex) {
System.err.println("Communication failure. Reason: " + ex.getMessage());
}
return null;
}
Dumping internal state
Dumping the present internal state of the Client Access Server to the log file might significantly speed up the process of analyzing strange behaviors. The following code shows how to instruct the Client Access Server to dump its state to the log file.
public static void dumpState(ConfigurationPortType configPort) {
try {
configPort.dumpState();
System.out.println("Service internal state is dumped to log");
}
catch(Exception ex) {
System.err.println("Communication failure. Reason: " + ex.getMessage());
}
}