From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

Actor Framework Discussions

cancel
Showing results for 
Search instead for 
Did you mean: 

executable with factory pattern (or using the "Character Lineator") ?

Hi,

I have an application, where I want to select the used child classes specified by a config file.

However, my exe won't find the specific derived classes, even though I manually set those classes as "Always Included" in the build spec (see below).

The base class is "SAM Tool"; the derived class is "SAM Tool Jar".

I managed to get my full application down to the simple VI, where I demonstrate this behavior (just deserializing a demo-class):

demo-app.png

My example JSON input looks like this:

{
"ClassName":"demo-tool", // just contains an array of "SAM Tool"; serializer properly set up
"tools":[
{    //    default "SAM Tool" if no ClassName given
  "name":"java",
  "version info":"-version"
},{  //    derived class, which won't be found during deserialization
  "ClassName":"SAM Tool Jar",
  "name":"tpchecker",
  "version info":"-V"
}]}

Settings:

demo-source-files.png

Is there something, I need to set in the category "Source File Settings" ?

During the build, I can also see that the files are copied over to the build location, however they cannot be located in the executable??

When executing the exe, it cannot find the specialied classes.

The only option that currently works for me is to include the possible child classes as class constants into the LV source code (the two class constants in the diagrom above).

Cheers, Benjamin

_________________________
CLA
0 Kudos
Message 1 of 9
(4,711 Views)

believe it or not, I have submitted a service request to NI about the same issue. I ran into this identical problem, while not even using the actor framework. My application was structured as just a usual QMH. Basically my plug-in classes wouldn't load at run time. Even stripping out the executable name from the path didn't work. "Always-including" the child-classes didn't work either. What did work was to explicitly instantiate each child class as a constant on the diagram of the main vi to be compiled. that however defeats the purpose of the factory pattern, doesn't it. so that was a work around. NI admitted to there being an issue with the get class default value vi, and i was told that an internal investigation was initiated. I then agreed for my SR to be closed. So that was a few months ago and that was the last i heard of it. I have made a phone call to the original applications engineer on this issue and as soon as she gives me and internal NI number which tracks this issue i'll post it here. I would rather not post my original SR number or the name of the applications engineer.

0 Kudos
Message 2 of 9
(4,241 Views)

As far as I can tell, you're only using the class name to identify the class. Using the name works if the class is already loaded, but if it isn't, LV needs to know where to find it. Just including the class doesn't help, because it can still be in multiple places inside the EXE (which is basically a zipped folder which keeps files in the same relative locations they were as source). My suggestion would be to add a VI which lives in the same folder as the plugin classes and does this:

Example_VI_BD.png

This should work both in the source and in the EXE when you include the classes, because they will be in the same relative location. The VI on the right loads the class if it's not already loaded.


___________________
Try to take over the world!
0 Kudos
Message 3 of 9
(4,241 Views)

Is the JSON begin created by the Character Lineator? If so, there's an option on Serializer for embedding relative paths into the serialized JSON so that they can be loaded as needed when deserialized. If you're not doing that, then you have a much harder task in front of you -- you have to make sure the types are already in memory.

Note that this is a limitation faced by dynamic loading systems in ANY language and is a big reason why I put the dynamic load by path facilities into the Character Lineator.

0 Kudos
Message 4 of 9
(4,241 Views)

Example of using the Formatter to embed the paths. By default, the paths are not embedded... you have to set the enum to do so.

Untitled.png

0 Kudos
Message 5 of 9
(4,241 Views)

I use the path to the plugin parent class to identify where plugin child classes have been saved in the exe, and use "Recursive File List" to identify classes saved in nearby directories.   See image:

Find Plugins.png

I also use a special identifier in the class names to distinguish plugins from support classes that get saved with them.

0 Kudos
Message 6 of 9
(4,241 Views)

@AQ: my JSON is not created by the lineator but rather through manual crafting.

@tst: yes, my factory builds instances only by name, not by path.

it would again defer the purpose of the Lineator if I had to specify the paths of the classes to be loaded

I understand that the classes have to be loaded before I can deserialize child instances

I was thinking more like that there should be a "loader" for all objects contained in the exe (something like James proposed), to makeit  possible to load them by ClassName.

unfortunately, I get error 7 when I try to "recursive file list" with the build executable - my list path is "C:\_work\_builds\demo\demo.exe\SAM\Auxiliary\SAM Settings\SAM Settings SAM\SAM Tool"

_________________________
CLA
0 Kudos
Message 7 of 9
(4,241 Views)

stbe wrote:

unfortunately, I get error 7 when I try to "recursive file list" with the build executable - my list path is "C:\_work\_builds\demo\demo.exe\SAM\Auxiliary\SAM Settings\SAM Settings SAM\SAM Tool"

I configure my build to put the plugins in a separate directory from the exe.  Try that.

stbe wrote:

I was thinking more like that there should be a "loader" for all objects contained in the exe (something like James proposed), to makeit  possible to load them by ClassName.

Don't load them, just find the list of those available and their paths.  When you actually need one, then load it from its path, not name.

0 Kudos
Message 8 of 9
(4,241 Views)

Then you've got 4 choices:

1. load all the classes ahead of time

2. have a header on your JSON that tells you what to load on the fly

3. have a fixed directory that you check whenever you're unflattening and if the class isn't already in memory, you try to load from there.

4. something I haven't thought of, but I am leaving room for imagination here... there are many variations on deserialization strategies. 🙂

0 Kudos
Message 9 of 9
(4,241 Views)