Showing results for 
Search instead for 
Did you mean: 

Re: "The 12 Days of Rulestream"

Siemens Genius Siemens Genius
Siemens Genius

Day 7: 7 Swans a Swimming

A.K.A. Initializing g_RsEngineer


Rule authors of sophisticated Rulestream rulesets, perhaps the kind that might be used to automate the engineering of a bevy of 7 swimming swans, often rely on “g_RsEngineer” to access advanced functionality of the Rulestream runtime environment. This includes things like user and profile information, access to a host of functions that control the running model, and runtime events to name a few. In order to use g_RsEngineer, you must first declare and then initialize it. This article covers how this can be done and the tradeoffs of each approach.


g_RsEnginer is generally declared at the top of the Custom module in Custom.vb. Since Model Services and the Thin Client server are multi-threaded (one thread per running model), the following definition is recommended (over defining it simply as a global) as this works properly in all Rulestream runtime environments, including Engineer.


<ThreadStatic()> Public WithEvents g_RsEngineer As IRsEngineer


Now that g_RsEngineer is declared, it must be initialized before it can be used and there are two different ways this may be done, each with its own advantages.


Method 1. Profile Setting.


The AutoSetRsEngineer profile setting, if set to True, will automatically define g_RsEngineer when any and all rule DLLs load. Advantages of this approach include:

- This method defines g_RsEngineer across all Rulestream applications so any rule (or custom.vb function/subroutine referenced by those rules in any application will work. This is generally quite important in a Rulestream product control model uses rules in multiple applications.

- This method is a visible way to cause this initialization to happen.

- This method isn’t dependent on any specific process definition or specific process step (as below).


However, keep the following in mind when selecting this approach.

- You need to make sure any user that will run that Rulestream product control model must have that set to True in their profile. That is not under the direct control of the rule author.

- If you are using Rulestream events, make sure the handling subroutines are only declared using the Handler Mappings tab of the top-level part family in Architect. With this method, do not declare your handler subroutines in Custom.VB with the “handles eventname” clause if the subroutine definition. If you use the “handles” clause and have a multi-application Rulestream ruleset, you will register one event handler for each loaded rule application DLL and this will result in what appears duplicate event notifications for the same event.

- When first setting this profile option, be certain to remove all code generated files from the temp folder in Rulestream’s program data folder and then regenerate all rules from scratch. This will force the necessary code to be injected into the generated rules.


Method 2. Process Step Formula.


Prior to 8.11, this was the only option. You would include the following in the status formula of the first process step:


If g_rsEngineer Is Nothing Then
g_rsEngineer = g_ObjectManager.RSEngineer
End If

Because the process step status formula of every step in the current process is evaluated immediately after a Rulestream line item model loads, and the process step rules are defined in the application of the top level part family, this method will cause g_RsEngineer to be initialized in the top-level application (only) and therefore be available immediately to rules in that application and custom.vb functions.


This has a few advantages:

- Using this method, initialization is totally under the control of the rule author so there is no reliance on the user-controlled profile setting.

- Multi-application Rulestream rulesets will not cause duplicate event handlers to be called as the process rules run only in the top-level application and thus g_RsEngineer would only be defined in the top-level application.


However, this approach has two limitations.

- It is a bit hidden away in a status formula of a process step and unknowingly deleting that code as you remove a process step will stop the initialization from happening. Or, if you create a second process, you need to take care that the initialization code above is included somewhere in that new process as well.

- g_RsEngineer is only initialized for the top-level application and references to g_RsEngineer from any other application (including custom.vb functions called from any other application) will fail as g_RsEngineer in those DLLs isn’t initialized.


Armed with these details, you should be able to make the decision of which approach is best suited to your Rulestream implementation.


Re: "The 12 Days of Rulestream"

Community Manager Community Manager
Community Manager

Day 8: “Flush out the system”

A.K.A.: How to wipe out all compiled Part Families so that you can be sure to have every one recompiled from scratch

Top 2.jpg

Have you ever gotten to a point in creating an application where what you’re seeing at runtime just doesn’t make sense? “I made a change to a Part Family but it sure doesn’t appear to be reflected in the

There are times when, if only for your sanity, it would be nice to wipe out all compilations, all temporary files and rebuild.

I stumbled across the following when I got very twisted while working with an inherited application. It got to the point where I would make a change to a Part Family yet it wouldn’t come up as needing compilation when I ran the Line Item. Through a series of User Errors I was at a point of exasperation.



Now… What I’m about to describe didn’t necessarily solve any of the problems that I had created myself, but it did provide me one more tool to help with the diagnosis. By wiping out all temporary files and recreating them by running a Line Item I was able to confirm that no spurious remnants were corrupting my data.

This is a very simple 2-step process consisting of:

1. Find and delete the Temporary folder for the application
2. Re-Run a Line Item



As with any administrative function such as the one described here, your ability to use it is dependent on your environment and your willingness to take risks. This tip is presented here because if executed
correctly it will not harm a system. IF, however, you manage to delete the wrong folder…

You never saw this tip. You don’t know me. Reference the name “Rick Smith” when filing all complaints.

Finding the Temp Folder

The folder we’re looking for is under Program Data, a folder typically hidden. So to start, Show Hidden Files. If you’re not sure how to do this, here’s a link from Microsoft with instructions for various operating systems:

1. Now, open Program Data
2. Open the sub-folder of the version of Rulestream under which you’re running the application in question
3. Expand the temp folder found here

You should now see a folder for each application you have run.

4. Go ahead an open the application folder




 The application folder will have contents similar to what I’m showing here:




Before deleting the application folder (I.e., the one indicated as #4 in the first image) it’s always best to have a backup. This folder will be re-created next time you run a Line Item for this application, but if I were you the first time doing this I’d rename the current folder to something else so that I could revert should things go south.

5. Now either delete the application folder or rename it



Recompiling your application

6. Return to your application and run a Line Item. If you deleted/renamed the correct folder under the correct version of Rulestream you will see that all Part Families of the application need to be compiled:



7. [Continue] and all Part Families are assured to be recompiled. You may confirm that everything is back as it was by returning to the temp folder and verifying that a new Sub-Folder for your application was created.

Bottom Holiday.jpg

Re: "The 12 Days of Rulestream"

Community Manager Community Manager
Community Manager

Day 9: “A logging we will go”

A.K.A.: Debugging 101 - A Log file can be your friend
Top 2.jpg

The following is one person’s tip on how to use the logging within Rulestream to figure out what to do when things aren’t working right. As with Rulestream in general, there is more than one way to go about using the tools provided to get the job done. What I’m presenting here is not necessarily the gold standard for debugging, but rather my experience that might be helpful to you who are new to Rulestream application development.

This tip may cause some of you “Old Timers” to roll your eyes. “Why… in my day we’d use our bare hands to figur’ out problems with our Rulestream applications. Lookin’ at a log file was considered cheattin’!”

 LOG3.jpgRulestream Architects ca 1849. From left to right: Rick, Gary, Kijin, Brian

Those of you who are well versed in the use of logging within Rulestream may look away. This tip is presented for the many new Rulestream users that may not be aware of the existence of the log files created when running a Rulestream application. The information they contain is very useful in debugging an issue, so understanding the basics is a great starting point.

The Concept
Let’s say I’m a Rulestream product developer (Siemens PLM Software development employee, not a Rulestream Application Architect) writing code for our NX integration and in a particular section I’d like to capture, for the log, that a particular operation is about to occur. I will write into the application something like this:

Source: NXManager (referred to as the logger name)
Type:    INFO (referred to as the level)
Messg: “About to ask NX to do xyz”

Now, whenever your Rulestream application hits this line of code the date/time, Logger, Level and Messg is captured.

As a user, you determine Level of information to be captured. The explanation of “How” is coming up shortly. The Levels available are: 

  • WARN
  • INFO

When a level is specified for adding data to a log file, the indicated level and all those below (as shown in the list above) are saved to a log file. For example, setting the threshold to DEBUG will also allow INFO, WARN, ERROR and FATAL messages to log along with DEBUG messages. (DEBUG is the lowest level).

So let’s say as a Rulestream product develop, on an If/Then/Else clause the Else indicates that something outside of the standard bounds has been provided by the user. Maybe the value being passed should either be an Integer or Real and anything else will cause NX to fail. In my code for the NX integration I would add something like this to the ELSE clause:

Logger: NXManager
Level:    ERROR
Messg: “NX expected a numeric value for xyz but instead received _________ ”


As a user, when I setup my Logging and set the Level to anything at ERROR or below (I.e., WARN, INFO, DEBUG) this message, if triggered, will be saved to the log.

NOTE: I’m pretty sure any of our Rulestream Product Developers reading this explanation are having issues with my oversimplification, but hopefully you’re getting the picture of where the message is coming from.

Now on to where the message is going.


The Log Files
As I mentioned, one of the attributes I specify as a Product Developer for Rulestream is the logger name. There are loggers for NX, SWX, Engineer, Architect, etc. and each time you run your Rulestream application a log file is being created for each one of these feature areas in a default location (FYI: this location may have been modified at your site modified). Here’s where to look:

The folder we’re looking for is under Program Data, a folder typically hidden. So to start, Show Hidden Files. If you’re not sure how to do this, here’s a link from Microsoft with instructions for various operating systems:

1. Now, open Program Data
2. Expand the Rulestream folder
3. Open the sub-folder of the version of Rulestream under which you’re running the application in question
4. Open the Logs folder



If you have already run your Rulestream application under the version of the folder you selected a list of Log files similar to the following should appear:F3.JPG


To see this list in a similar fashion to what I’m showing above you may have to change your display settings on the folder to NOT hide extensions for known file types. Do this by selecting Organize, Folder and search options. . .




And then under the View tab uncheck Hide extensions for known file types:



Some basic items with regards to the files in this folder: 

  • The most recent version is the “.log” without an index. Previous versions – those from your earlier run of your application – are numbered
  • The number of version retained is controllable (that explanation coming up shortly)
  • Many of the log files will be empty if you aren’t using that feature. For example, if you’re working with NX only you will still see log files for SWX, SE and so on. The easiest way to see log files of meaning to you is to sort by size. Unused feature logs will have a size of zero. Anything you will be interested in will have a size greater than zero.
  • If your system cannot open the file upon selection, set the application for viewing to Notepad

Here is an example of a log file: F6.jpg

In addition to the date/timestamp you can see:

1. Level of the message
2. Logger name (in this example the Rulestream log captures both Kernel and Engineer messages)
3. The message the coder wanted to display. In this example we see that my application is setting the base unit for length to inches

What you typically want to look for in a Log file is any message with a level of ERROR or FATAL. If found, look at the message and those that proceed it to determine what the system was doing prior to and at time of the ERROR.

Note: Not all log entries of ERROR are FATAL. Although it’s nice to strive for an application that never has an ERROR in the log this is not always possible. Only your situation will tell if the ERROR is something of concern or not.

Controlling Log Files
The creation of log files, from where they’re saved to what they contain, is controlled by a file located under the Program Folder under the version of Rulestream you’re using: 



Navigating to this folder you will see a collection of files similar to this:



The file you want to look into is Rulestream.log4net. This is a large file so I will jump to two sections that will be of interest for this discussion. Jumping near the bottom you will see something like this:


Staying with our NX example, this portion of the file indicates that the NX log file will filter to message levels of INFO or greater (as per our earlier discussion). Change this to FATAL and only fatal messages are logged.

We can also see that an “Appender” named NXManagerAppender is being used. Scrolling up in the file we find the code of the NXManagerAppender:


The Appender is where information pertaining to the log file is specified. For instance, in this example we can see that file value sets the location for the log file. The maximum number of versions I’m saving is 5. The file size won’t exceed 20MB, etc.

The attributes in this file may be used to do a lot of advanced logging. For more information on how to use this file, please refer to the section in your Rulestream ETO Install Guide titled:

“Using log4net logging at runtime (Customer customizations)”


I hope this tip provides the new users with some insight into the tools available when creating a Rulestream application. I’ve found that it’s very easy to forget to check a Log file when my process step fails, but with practice, you will find that checking these files first can save a lot of time in debugging.




Re: "The 12 Days of Rulestream"

Community Manager Community Manager
Community Manager

Day 10: Lords Alertin’

A.K.A. Creating a System of Validations and Warnings

Although posted by me (TonyB) this tip is provided by Kijin who can’t remember his password for logging into the Community. I won’t say too much eggnog was a factor, but . . .

Top 2.jpg

Sometimes, your model may require more functionality than the built-in warnings grid, with validations that go beyond a simple check for minimum or maximum values.


For example, you may wish to validate that a string has a certain number of characters, or that an entry is a number instead of a string, or that the user has changed an entry to one that is other than the default value.


The method of validations and warning messages below requires a pair of subpart collections, each with its own part family. Typically, you will want to create these subparts under the part family that contains the properties on the UI form that you wish to validate.


In the following example, we have created the Validation and Warnings subpart collections off of two part families at different levels in the tree. You may re-use the same Validation part family for all Validation subpart collections, but keep in mind that you will need context overrides for the properties in the Validation part.


You may also create unique part families for each Validation subpart collection to avoid using context overrides, but there will always be a quantity of one Validation subpart. The Warning part family is generic enough to re-use in every Warnings subpart collection.




In the Validation part, create a connection that points to the part family that contains the properties that you wish to validate. For each validation, create a boolean validation property that evaluates to True (if valid) or False (if invalid). For example, to validate that a property has a value of something other than the default (going through a connection called UI), you might create a property called ValidatePumpSelection:


If me.UI(1).PumpModel <> "Select pump" Then
result = True
result = False
End If


In the validation part, create a warnings array property (or properties) that performs multiple validations and assigns a message for each. In the following example, we create a property called WarningsArrayPump, with three possible states of each message (Warning, Error, and Info):


Const MSG_WARN as String = "Warning: "
Const MSG_ERROR as String = "Error: "
Const MSG_INFO as String = "Info: "

Dim arr as New ArrayList
Dim strMsg as String = ""

'check to see if pump has been selected
If NOT Me.ValidatePumpSelection Then
strMsg = "Please select a valid pump."
arr.Add( MSG_ERROR & strMsg )
End If

'check to see if pump sizing is in range
If NOT Me.ValidateInRange Then
strMsg = "Size is out of range of " & me.UI(1).PumpMin & " and " & me.UI(1).PumpMax & "."
arr.Add( MSG_WARN & strMsg )
End If

'explode array
If arr.Count > 0 Then
result = Join( arr.ToArray(), vbCRLF )
result = ""
End If


Depending on the number of validations, the above property might be very long, and you may need to split the validations up into more than one property (for example, WarningsArrayPump1, WarningsArrayPump2, etc.). Create a new property that collects all the warnings into one array, here called WarningsArray:


Dim arr as New ArrayList
'Gather all warnings

Dim arrpump1 as Array
If WarningsArrayPump1 <> "" Then
arrwatch = Split( WarningsArrayPump1, vbCRLF )
For Each strArr as String in arrpump1
If ( NOT arr.Contains( strArr )) Then arr.Add( strArr )
End If

Dim arrpump2 as Array
If WarningsArrayPump2 <> "" Then
arrbar = Split( WarningsArrayPump2, vbCRLF )
For Each strArr as String in arrpump2
If ( NOT arr.Contains( strArr )) Then arr.Add( strArr )
End If

Dim arrbase as Array
If WarningsArrayBase <> "" Then
arrbar = Split( WarningsArrayBase, vbCRLF )
For Each strArr as String in arrbase
If ( NOT arr.Contains( strArr )) Then arr.Add( strArr )
End If

'create the entire array

If arr.Count > 0 Then
result = Join ( arr.ToArray(), vbCRLF )
result = ""
End If


Now we need to split up the warnings array into separate warning parts. In the Warnings subpart collection, set the quantity to the number of items in the array:


If me.Validation(1).WarningsArray = "" Then
result = 0
result = split( me.Validation(1).WarningsArrayWatch, vbCRLF ).length
End If


In the Warning part family, create a connection called Validation that points to the validation part:


Result = Me.Parent.Validation(1)


In the Warning part family, create a string property called Prefix:


If Message.Substring( 0, 9 ) = "Warning: " Then
result = "WARNING"
Else If Message.Substring( 0, 6 ) = "Info: " Then
result = "INFO"
Else If Message.Substring( 0, 7 ) = "Error: " Then
result = "ERROR"
End If


In the Warning part family, create a string property called Message:


result = Split( Me.Validation(1).WarningsArray, vbCRLF )( SubpartID - 1 )


In the Warning part family, create a string property called Icon:


result = Me.Prefix & ".png"


This presumes that there are bitmap files called warning.png, info.png, and error.png in the Master Documents folder (these would be small icons next to the message in a grid).



Create a read-only grid on the form that you wish to validate, and point the grid to the Warnings subpart collection. Display the icon, the severity (prefix), and the message.


Re: "The 12 Days of Rulestream"

Siemens Genius Siemens Genius
Siemens Genius

Day 11 – 11 Pipers Piping

A.K.A. IntelliSense for Custom.vb


You might ask why the pipers are piping? Well, it’s because they have IntelliSense while editing Custom.vb just as shown in the picture here:


IntellisenseExample.jpgEditing Custom.vb with IntelliSense

This is done by creating a Visual Studio solution that has all the proper references and using build events to copy custom.vb from the solution to Master Docs. Here is the step-by-step instructions for setting this up.

Step 1. Using Visual Studio 2015, create a new class library project targeted at .NET 4.5.2.

Step 2. Under Project Properties->References, first specify the reference path to the Rulestream Program Files folder. Then add references to Rulestream, Rulestream.Kernel, Rulestream.Dataservice, and System.Windows.Forms. Make sure the “copy local” setting for each of these references (lower gith corner) is set to false.

Note that just because you add a reference here (or an “Import” at step 5 below) does not mean that Rulestream will link that at rule compile time. This is only a solution that is being used to facilitate editing of custom.vb. The list of modules that are compiled in is fixed in Rulestream.

Step 3. Under Project Properties->Compile, click the “Build Events” button and add the following to the Post Build Event command line. This will copy Custom.VB to Master Docs if the VB solution folder and Master Docs are peers.


copy $(ProjectDir)\Custom.vb ..\..\..\..\MasterDocs\Custom.vb

Step 4. To the project, right-click to add->existing for C:\ProgramData\RuleStream\8.12.1\Modules\common.vb. Though you won’t ever edit this, it will provide references to the functions that are defined in common.vb.

Step 5. To the project, right-click to add->module and name it custom.vb. Open that module and paste the following code into this as a starting point.


Option Explicit On

Imports RuleStream
Imports RuleStream.DataService
Imports RuleStream.Kernel
Imports Microsoft.VisualBasic
Imports System
Imports System.Windows.Forms
Imports System.Data
Imports System.Data.Common
Imports System.Collections
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.IO
Imports System.Text
Imports System.Reflection

Module Custom

<ThreadStatic()> Friend g_RsApp As RuleStream.Designer.RuleStreamApplication
<ThreadStatic()> Friend g_RsSite As RuleStream.DataService.SiteSettings
<ThreadStatic()> Public WithEvents g_RsEngineer As IRsEngineer


End Module

That is it!


You may now edit custom.vb from within this solution and benefit from IntelliSense. When ready, build the solution and you’ll see the custom.vb that you edited here be copied over to Master Docs.


Fin: "The 12 Days of Rulestream"

Community Manager Community Manager
Community Manager

Day 12: "Thank You!"


We hope you found our 12 Days of Rulestream tips and ideas helpful and something that you can apply to your Rulestream implementation. If any of you have any of your own tips or tricks that you’d like to share with the Rulestream community, please take a few minutes and post them here.Ending.jpg





Re: "The 12 Days of Rulestream"


Here's another way Rick - you shouldn't need to remember to 'AutoSetRsEngineer' and also don't need to initialize in the first process step. All you need to do is the following:


Public ReadOnly Property RSEngineer As IRsEngineer


        If g_RsEngineer Is Nothing Then g_RsEngineer = g_ObjectManager.RsEngineer

        Return g_RsEngineer

    End Get

End Property


Do this and make sure to always use this property to refer to the RsEngineer object. You will ALWAYS get a valid reference.


In fact, this is probably something that can also be included in Common.vb so the end users don't even have to havev it.



Re: "The 12 Days of Rulestream"

Alternatively, you can just open the vbproj file that is generated in the temp folder for the given application and add an additional fie (Custom.vb from masterdocuments) and start editing it. You should get intellisense while typing.


Re: "The 12 Days of Rulestream"

Siemens Experimenter Siemens Experimenter
Siemens Experimenter
I think you should probably be careful of this approach if you are running in a multi-threaded Rulestream application (like if you are running in Rule Services) as g_RsEngineer will get set to point to an instance from a different thread.

Re: "The 12 Days of Rulestream"


Point taken in terms of thread safety but because the return variable still returns the threadstatic g_rsEngineer variable, I believe it might be OK. Please let me know if your team has done any testing with this scenario.



Dharmesh Sanghavi