question

Upvotes
Accepted
3 1 1 1

OPENDACS API .NET question regarding usage collection

We’ve used the OpenDACS Api in both JAVA & .NET. The Java version works well, however, for the .NET version we don’t see any usage data collected in the dacs.usage file like we do for other apps. Would an expert be able to take a look at the code & let me know if there is anything missing please?


using Ion.MarketView.Gui.Toolkit.Core.LoggingEx;

using Reuters.RFA.Common;

using Reuters.RFA.DACS;

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading;

using System.Threading.Tasks;

using static RFA_DACS.DACSConfiguration;


namespace RFA_DACS

{

public class DaemonSink

{

static private ILogger logger = LogManager.GetCurrentClassLogger();

static private DaemonSink instance = null;


private Dictionary<String, uint> srcToPe = new Dictionary<string, uint>();

private DACSUser user;

private DACSDispatcher dispatcher;


private static RFA_String AUTHORIZATION_NAME = new RFA_String("DACSMC");

private List<AuthorizationSystem.AUTH_SYSTEM_OPTION_ELEMENT> options = new List<AuthorizationSystem.AUTH_SYSTEM_OPTION_ELEMENT>();

private AuthorizationSystem system = null;

private AuthorizationAgent agent = null;

private AuthorizationRequest.PerformUsageEnum usageLogging = AuthorizationRequest.PerformUsageEnum.AlwaysPerformUsageLogging;

private int serviceId = -1;

private String application = null;

private String serviceName = null;

private RFA_String serviceNameRFA = null;

// private long loginHandle = -1;

// private Boolean loginState = false;

private EventWaitHandle waitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);

private RuntimeConfiguration config = null;

private Site dacsConnectionParameters = null;

private bool checksDisabled = false;


public DaemonSink(RuntimeConfiguration config)

{

this.config = config;

DaemonSink.instance = this;

logger.LogKey = "DACS Audit";

}

public bool Enabled

{

get { return checksDisabled == false; }

}

/*

* Convenience method for defining DACS options.

*/

public void SetOption(String name, String value)

{

AuthorizationSystem.AUTH_SYSTEM_OPTION_ELEMENT option = new AuthorizationSystem.AUTH_SYSTEM_OPTION_ELEMENT();

option.OptionName = new RFA_String(name);

option.OptionValue = new RFA_String(value);

options.Add(option);

}


/*

* Public 'do it all' connector for DACS sink. Iterates defined sites and attempts DACS init and login until success.

* If site cannot be logged into, disables DACS entitlement checks.

*/

public void Connect(String componentName, DACSConfiguration config)

{

if (dispatcher == null)

{

dispatcher = new DACSDispatcher();

dispatcher.LoginFailed += LoginFailed;

dispatcher.LoginSucceeded += LoginSucceeded;

dispatcher.Start();

}

else

{

dispatcher.Stop();

dispatcher.Start();

}


foreach (Site site in config.Sites)

{

logger.Low().Info().Event("Attempting connection to site '" + site.Name + "'.").End();

try

{

Connect(componentName, site.Application, site.Service, int.Parse(site.Port), site.Hosts);

}

catch (System.Exception)

{

CleanUp();

}

if (user != null && user.LoginState)

{

dacsConnectionParameters = site;

logger.Low().Info().Event("Connected to site '" + dacsConnectionParameters.Name + "'.").End();

break;

}

}


if (user == null || user.LoginState == false)

{

// Couldn't login anywhere, so disable DACS checking...

checksDisabled = true;

logger.Low().Error().Event("Unable to connect to any configured DACS site, DACS checks disabled.").End();

}

}


/*

* Throws AuthorizationException on login failure

*

* 'Do it all' internal site connection and login. Initialises DACS for current user and logs in. Called by public method

* for each defined site until a successful login is completed.

*/

private void Connect(String componentName, String application, String serviceName, int port, String[] hosts, int timeout = 30)

{

int tryCount = 0;

String val = string.Join(" ", hosts);

val += ":" + port;

SetOption("hosts", val);

SetOption("forecase", "lower");

this.application = application;

this.serviceName = serviceName;

system = AuthorizationSystem.Acquire(AUTHORIZATION_NAME, options);

agent = system.CreateAuthorizationAgent(new RFA_String(componentName), true);

AuthorizationSystem.InitAuthorizationUsageLogging(new RFA_String("E:\\apps\\Ion\\env\\Test\\Workspaces\\uk280374\\LOGS"), 1024);


do

{

Thread.Sleep(1000);

tryCount++;


switch (ConnectionStatus)

{

case Reuters.RFA.DACS.AuthorizationAgent.AuthorizationConnectionEnum.AuthorizationConnectionUp:

logger.Low().Info().Event("DACS Daemon connection is up").End();

break;


case Reuters.RFA.DACS.AuthorizationAgent.AuthorizationConnectionEnum.AuthorizationConnectionDown:

logger.Low().Info().Event("DACS Daemon connection is down").End();

break;


case Reuters.RFA.DACS.AuthorizationAgent.AuthorizationConnectionEnum.AuthorizationConnectionPending:

logger.Low().Info().Event("DACS Daemon connection is pending").End();

break;

default:

logger.Low().Info().Event("DACS Daemon connection is unknown").End();

break;

}

}

while (ConnectionStatus != AuthorizationAgent.AuthorizationConnectionEnum.AuthorizationConnectionUp && tryCount < timeout);


if (ConnectionStatus != AuthorizationAgent.AuthorizationConnectionEnum.AuthorizationConnectionUp)

{

Disconnect();

logger.Low().Error().Event("Timeout waiting to connect.").End();

throw new System.Exception("Timeout waiting to connect.");

}


serviceNameRFA = new RFA_String(serviceName);

agent.LookupServiceID(serviceNameRFA, ref serviceId);


UpdateServiceList();

try

{

Login();

}

catch (System.Exception ex)

{

logger.Low().Warn().Event("Login attempt for host(s) '" + String.Join(",", hosts) + "' on port " + port + " failed: " + ex.Message);

throw ex;

}

}

/*

* Updates global service/permission entity cache for current DACS connection parameters.

*/

private void UpdateServiceList()

{

List<AuthorizationAgent.AUTH_PE_SUBSERVICE_ELEMENT> services = new List<AuthorizationAgent.AUTH_PE_SUBSERVICE_ELEMENT>();

if (agent.GetPEToSubServiceList(serviceId, services) == AuthorizationAgent.AuthorizationServiceLookupEnum.SuccessfulLookup)

{

logger.Low().Info().Event("Mapping source to PE identifiers for Service: " + serviceName + " (" + serviceId + ")").End();

foreach (AuthorizationAgent.AUTH_PE_SUBSERVICE_ELEMENT svc in services)

{

foreach (RFA_String ss in svc.SubserviceList)

{

srcToPe[ss.ToString()] = svc.PEValue;

String msg = ss.ToString() + " --> " + svc.PEValue;

logger.Low().Info().Event(msg).End();

}


}

logger.Low().Info().Event("Done mapping source to PE identifiers").End();

}

}

public List<String> GetUserAvailableSources()

{

List<String> sources = new List<String>();

if (Enabled && user != null)

{

List<AuthorizationAgent.AUTH_USER_SUBSERVICE_ELEMENT> result = new List<AuthorizationAgent.AUTH_USER_SUBSERVICE_ELEMENT>();

if (agent.GetUserSubServiceList(user.Handle, serviceId, result) == AuthorizationAgent.AuthorizationServiceLookupEnum.SuccessfulLookup)

{

foreach (AuthorizationAgent.AUTH_USER_SUBSERVICE_ELEMENT ss in result)

{

sources.Add(ss.SubserviceName.ToString());

}

}

}

return sources;

}

private void Login()

{

if (user == null)

{

user = new DACSUser(application);

}


if (user.IsSet == false || user.LoginState == false)

{

AuthorizationRequest request = AuthorizationRequest.Create();

request.SetUsageLogging(usageLogging);

request.PrincipalIdentity = user.Identity;


long loginHandle = agent.Login(dispatcher.EventQueue, request, dispatcher, this);


waitHandle.WaitOne();

String msg = "DACS login for Principal " + request.PrincipalIdentity.AppName.ToString() + "/" + request.PrincipalIdentity.Name.ToString() + (user.LoginState ? " successful." : " failed.");

logger.Low().Info().Event(msg).End();

if (user.LoginState == false)

{

throw new System.Exception(msg);

}


}

}

private void LoginFailed(AuthorizationAgentEventStatus.StatusCodeEnum status, string text)

{

user.Set(text);

waitHandle.Set();

}

private void LoginSucceeded(long handle, string text)

{

user.Set(handle, text);

waitHandle.Set();

}

public Boolean CheckAccess(String source, String record)

{

if (config.Enabled == false)

{

return true;

}


Boolean ret = false;


if (srcToPe.ContainsKey(source))

{

try

{

uint pe = srcToPe[source];

List<uint> peList = new List<uint>();

peList.Add(pe);


AuthorizationLockStatus status = new AuthorizationLockStatus();

AuthorizationLockData lockData = new AuthorizationLockData();

AuthorizationLock dacsLock = new AuthorizationLock(serviceId, AuthorizationLock.OperatorEnum.AND, peList);

AuthorizationLockData.LockResultEnum res = dacsLock.GetLock(lockData, status);

AuthorizationAgent.AuthorizationCheckResultEnum checkResult = AuthorizationAgent.AuthorizationCheckResultEnum.AccessDenied;

if (res == AuthorizationLockData.LockResultEnum.LOCK_SUCCESS)

{

AuthorizationCheckStatus reqStatus = new AuthorizationCheckStatus();

checkResult = agent.CheckSubscription(user.Handle, usageLogging, reqStatus, serviceNameRFA);

ret = checkResult == AuthorizationAgent.AuthorizationCheckResultEnum.AccessAllowed;

if (!ret)

{

logger.Low().Warn().Event("Access check, user context [" + user.ToString() + "], source context [" + source + "], record context [" + record + "], auth context [PE=" + pe + ", SVCId=" + serviceId + ", SVCName=" + serviceName + ", Log=" + usageLogging.ToString() + "] DENIED. Site[" + dacsConnectionParameters.ToString() + "]").End();

}

else

{

logger.Low().Info().Event("Access check, user context [" + user.ToString() + "], source context [" + source + "], record context [" + record + "], auth context [PE=" + pe + ", SVCId=" + serviceId + ", SVCName=" + serviceName + ", Log=" + usageLogging.ToString() + "] ALLOWED. Site[" + dacsConnectionParameters.ToString() + "]").End();

}

}

}

catch (System.Exception ex)

{

logger.Low().Error().Event(ex.GetType().Name + " exception in audit(...): " + ex.Message).End();

}

}


return ret;

}

public AuthorizationAgent.AuthorizationConnectionEnum ConnectionStatus

{

get

{

if (agent != null) return agent.DaemonConnectionState;


return AuthorizationAgent.AuthorizationConnectionEnum.AuthorizationConnectionDown;

}

}



public void Disconnect()

{

try

{

dispatcher.Stop();

CleanUp();

}

catch (System.Exception e)

{

logger.Low().Error().Event(e.GetType().Name + " exception during Disconnect: " + e.Message).End();

}

}

private void CleanUp()

{

srcToPe.Clear();


user = null;

checksDisabled = false;


if (agent != null)

{

agent.Destroy();

agent = null;

}

if (system != null)

{

system.Release();

system = null;

}

}

}

}


DACSopen-dacseikon-.net-api
icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

1 Answer

Upvotes
Accepted
32.2k 40 11 19

Hello @adam.martin,

The code looks about right to me.

However, if usage file is not being updated, where you would expect it, I would go back to basics:

  • Are you connecting to a local daemon or remote?
  • Verify that the path to the usage file is existing, no typos, and permissioned to the user executing (if in doubt, permission everybody for full control, and once all working, then go back to the required perms).
  • If it's a local daemon and local usage file, testing is easier:
    • Restart the daemon, make sure it is healthy and starts writing the file, makes a startup entry
    • Instead of custom client, run the client that came with your SDK, such as DACSSubscribeClient
    • Make sure the entry is created
    • Compare to your code, and if still can not figure the difference, as it can be subtle, build up from the working DACSSubscribeClient up, to your custom requirements
  • If it's a shared remote daemon, still I would test with standard example .Net client that came with SDK, such as DACSSubscribeClient and make sure you generate usages on that first, then compare to the custom client and try to figure out the difference, only restarting it and making sure that it writes usage on startup may not be in your control in this case.

Hope this helps


icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

  • Are you connecting to a local daemon or remote? - remote dacs.snkd being used, same one as the Java component is using.
  • Verify that the path to the usage file is existing, no typos, and permissioned to the user executing (if in doubt, permission everybody for full control, and once all working, then go back to the required perms). - usage file is updating with usage data from other components. I also see the user Login success, but no usage. Could this be something to do with the DACSLOCK?
  • If it's a local daemon and local usage file, testing is easier:
    • Restart the daemon, make sure it is healthy and starts writing the file, makes a startup entry
    • Instead of custom client, run the client that came with your SDK, such as DACSSubscribeClient
    • Make sure the entry is created
    • Compare to your code, and if still can not figure the difference, as it can be subtle, build up from the working DACSSubscribeClient up, to your custom requirements - will try this
  • If it's a shared remote daemon, still I would test with standard example .Net client that came with SDK, such as DACSSubscribeClient and make sure you generate usages on that first, then compare to the custom client and try to figure out the difference, only restarting it and making sure that it writes usage on startup may not be in your control in this case. - Will try this

Hello @adam.martin,

If you mean the libraries, dacslock dlls, if there is any doubt would obtain from a clean SDK download and re-test.

If you mean locks in the items? Don't think so either, as you are mentioning that Java client is creating usages on them properly, I would not expect anything is off with the dacslocks in the items.