1. They must be granted to either application or user

2. Only resources of Service, Application and User type could be used there. %DB are database resources

3. SMP -> Menu -> View Roles -> Choose the role "webapp-admin" -> General Tab -> Priveleges -> Add -> choose the resoure -> OK -> Save

Repeat for webapp-user

4. Like this:

Parameter RESOURCE = "ResourceName1:Permission,ResourceName2,ResourceName3:Permission";

Where Permission is one of: READ, WRITE, USE

If Permission is skipped (see ResourceName2) then USE permission is checked.

Here's an aggregation rss feed which combines the Community Portal RSS and InterSystems StackOverFlow RSS tags. It's available here and works with Thunderbird.

Have you thought about uploading this projects on GitHub?

UPD. Nevermind, seen your message about GitHub in another topic.

If you paste table from somewhere else, when creating a post, sometimes borders may be undisplayed. To fix that switch into HTML view (via "Disable rich-text" button) and find the beginning of your table definition. It would look somewhat like that:

<table class="confluenceTable">

And replace it with:

<table border="1" cellpadding="1" cellspacing="1">

I had a similar problem. The task was to write custom logging system, which would automatically store current method argument values. Here's how I done it.

First the the persistent log class (relevant parts):

Class App.Log Extends %Persistent
{

/// Replacement for missing values
Parameter Null = &quot;Null&quot;;

/// Type of event
Property EventType As %String(MAXLEN = 10, VALUELIST = &quot;,NONE,FATAL,ERROR,WARN,INFO,STAT,DEBUG,RAW&quot;) [ InitialExpression = &quot;INFO&quot; ];

/// Name of class, where event happened
Property ClassName As %String(MAXLEN = 256);

/// Name of method, where event happened
Property MethodName As %String(MAXLEN = 128);

/// Line of int code
Property Source As %String(MAXLEN = 2000);

/// Cache user
Property UserName As %String(MAXLEN = 128) [ InitialExpression = {$Username} ];

/// Arguments&#39; values passed to method
Property Arguments As %String(MAXLEN = 32000, TRUNCATE = 1);

/// Date and time
Property TimeStamp As %TimeStamp [ InitialExpression = {$zdt($h, 3, 1)} ];

/// User message
Property Message As %String(MAXLEN = 32000, TRUNCATE = 1);

/// User IP address
Property ClientIPAddress As %String(MAXLEN = 32) [ InitialExpression = {..GetClientAddress()} ];

/// Add new log event
/// Use via $$$LogEventTYPE().
ClassMethod AddRecord(ClassName As %String = &quot;&quot;, MethodName As %String = &quot;&quot;, Source As %String = &quot;&quot;, EventType As %String = &quot;&quot;, Arguments As %String = &quot;&quot;, Message As %String = &quot;&quot;)
{
    Set record = ..%New()
    Set record.Arguments = Arguments
    Set record.ClassName = ClassName
    Set record.EventType = EventType
    Set record.Message = Message
    Set record.MethodName = MethodName
    Set record.Source = Source
    Do record.%Save()
}
}

And here's macros for client code:

#define StackPlace         $st($st(-1),&quot;PLACE&quot;)
#define CurrentClass     ##Expression($$$quote(%classname))
#define CurrentMethod     ##Expression($$$quote(%methodname))

#define MethodArguments ##Expression(##class(App.Log).GetMethodArguments(%classname,%methodname))

#define LogEvent(%type, %message) Do ##class(App.Log).AddRecord($$$CurrentClass,$$$CurrentMethod,$$$StackPlace,%type,$$$MethodArguments,%message)
#define LogNone(%message)         $$$LogEvent(&quot;NONE&quot;, %message)
#define LogError(%message)         $$$LogEvent(&quot;ERROR&quot;, %message)
#define LogFatal(%message)         $$$LogEvent(&quot;FATAL&quot;, %message)
#define LogWarn(%message)         $$$LogEvent(&quot;WARN&quot;, %message)
#define LogInfo(%message)         $$$LogEvent(&quot;INFO&quot;, %message)
#define LogStat(%message)         $$$LogEvent(&quot;STAT&quot;, %message)
#define LogDebug(%message)         $$$LogEvent(&quot;DEBUG&quot;, %message)
#define LogRaw(%message)         $$$LogEvent(&quot;RAW&quot;, %message)

Now, how that works in client code?  Let's say there is a class:

Include App.LogMacro
Class App.Use [ CompileAfter = App.Log ]
{

/// Do ##class(App.Use).Test()
ClassMethod Test(a As %Integer = 1, ByRef b = 2)
{
    $$$LogWarn("Message")
}
}

In the int code, the $$$LogWarn macro would be transformed into:

Do ##class(App.Log).AddRecord(&quot;App.Use&quot;,&quot;Test&quot;,$st($st(-1),&quot;PLACE&quot;),&quot;WARN&quot;,&quot;a=&quot;_$g(a,&quot;Null&quot;)_&quot;; b=&quot;_$g(b,&quot;Null&quot;)_&quot;;&quot;, &quot;Message&quot;)

And after execution a new record would be added to App.Log table (note, that the method was called with default params - if it was called with other values they would be saved, as this logging system gets arguments values at runtime):

There is also some additional functionality, such as objects serializationinto json and context restoration at a later date, but that does not pertrain to the current discussion.

Anyway, the main idea is that at compile time we have a macro that:

  • Gets method arguments list from %Dictionary.CompiledMethod

  • For each argument decides on a strategy on how to get it's value at runtime

  • Writes source code that would implement value get at runtime

  • Builds code to get all method arguments values

  • Inserts this  code into method

Relevant methods (in App.Log):

/// Entry point to get method arguments string
ClassMethod GetMethodArguments(ClassName As %String, MethodName As %String) As %String
{
    Set list = ..GetMethodArgumentsList(ClassName,MethodName)
    Set string = ..ArgumentsListToString(list)
    Return string
}

/// Get a list of method arguments
ClassMethod GetMethodArgumentsList(ClassName As %String, MethodName As %String) As %List
{
    Set result = &quot;&quot;
    Set def = ##class(%Dictionary.CompiledMethod).%OpenId(ClassName _ &quot;||&quot; _ MethodName)
    If ($IsObject(def)) {
        Set result = def.FormalSpecParsed
    }
    Return result
}

/// Convert list of method arguments to string
ClassMethod ArgumentsListToString(List As %List) As %String
{
    Set result = &quot;&quot;
    For i=1:1:$ll(List) {
        Set result = result _ $$$quote($s(i&gt;1=0:&quot;&quot;,1:&quot;; &quot;) _ $lg($lg(List,i))_&quot;=&quot;)
        _ ..GetArgumentValue($lg($lg(List,i)),$lg($lg(List,i),2))
        _$S(i=$ll(List)=0:&quot;&quot;,1:$$$quote(&quot;;&quot;))
    }
    Return result
}

ClassMethod GetArgumentValue(Name As %String, ClassName As %Dictionary.CacheClassname) As %String
{
    If $ClassMethod(ClassName, &quot;%Extends&quot;, &quot;%RegisteredObject&quot;) {
        // it&#39;s an object
        Return &quot;_##class(App.Log).SerializeObject(&quot;_Name _ &quot;)_&quot;
    } Else {
        // it&#39;s a datatype
        Return &quot;_$g(&quot; _ Name _ &quot;,&quot;_$$$quote(..#Null)_&quot;)_&quot;
    }
}

The project is open-sourced and availible on GitHub (to use import all classes from App package into any namespace).

I modified your code like this:

Class test.DummyClass Extends %RegisteredObject
{

Property notanumber As %String;

Property aboolean As %Boolean;

/// do ##class(test.DummyClass).Test()
ClassMethod Test()
{
    
    set dummy = ..%New()
    set dummy.notanumber = &quot;28001&quot;
    set dummy.aboolean = 1
    do ##class(%ZEN.Auxiliary.jsonProvider).%ObjectToJSON(dummy,,,&quot;aelotw&quot;)
}
}

Terminal output:

>do ##class(test.DummyClass).Test()
{
        "notanumber":"28001",
        "aboolean":true
}