Groovy script runner architecture - groovy

Initial info: I have a groovy app (let's call it Runner) which is capable of running anything implementing certain interface (let's call it Runnable). And I have a pool of Runnables (groovy scripts) which should be visible to this app at the init stage and which app will call (through the interface and passing an object as a param).
Task: What I need is a way to load and call all the Runnables from the Runner.
Requirements: It's tricky, as scripts may not follow certain package structure and can be placed on the same machine as Runner but virtually in any place. They can also be named differently (open discussion for mandatory java alike naming: class name == file name) and can be skipped for now (though if there's gonna be advice on that it's cool!).
NOTES: I imagine it possible through having a config file in which scripts are configured (absolute path is provided) and to load them using this stuff and either cast Object to Runnable interface and trigger what I need or to invokeMethod(...). But have no idea if it can be done easier (there should be a way, cause it looks all too clumsy). I also cant think of a way to handle file naming issue and multiple classes in one file issue.
P.S.: Such long description might cause misunderstanding so please comment on vague parts.

I think you need to know all classes implementing an interface. Find Java classes implementing an interface may be of interest to you.

The option to have a config file in which script's absolute paths are written is good and proved to be a working solution. You'll have to deal with class loading of whatever is not visible in the app class loader. In particular you'll have to deal with annotation based POJO serialization problems. Singleton of Runnable loader is a good practice.

Related

RevitPlugin 2021 does not contain Main method

"RevitPlugin.exe" does not contain a static 'Main' method suitable for an entry point
A plugin has no main method. A plugin attaches to a running process that provides the main method. In this case, i would assume that it plugs in to Revit.exe.
The most effective way forward might be to work through a getting started tutorial from scratch rather than fighting the system and struggling with mistakes like this.

Catel application initialization

I'm looking into Catel. I started following along in the Getting Started for WPF Developers. I create the initial project using the template and run it. All well and good.
Then I take a detailed look at the generated source files. I see references to DataWindow, StyleHelper, and ViewModelBase. And I run in the debugger and watch the Catel debug output, stepping so that I can see when things happen.
And it is all magical.
The view manager somehow runs and registers the MainWindow. And the ViewModelFactory is invoked to create MainWindowViewModel, and the MainWindow DataContext gets set.
How does this all happen? I am missing the documentation that puts together for me the sequence of events when an application starts. I am reluctant to take it on faith, and reluctant to dive into the giant code base without an inkling of where to start. I have read the CodeProject articles and the intro part of the documentation.
Is this driven off of the behaviors some way? How are they invoked? I just can't find the thread that starts me on my way.
Aside: I look at Catel because I found myself implementing a ton of plumbing for a significant MVVM application, and decided that someone else had already solved this problem.
Thanks for any leads. (And thanks, Geert. This is a significant work.)
-reilly.
If I understand correctly, you are looking for advanced information of the inner workings. I think this part of the documentation might be of interest for you.
It might not provide all information you are looking for, but it should provide some.
About some basic questions:
1) The startup windows is defined in App.xaml (that's standard WPF)
2) Since it derives from DataWindow, it uses WindowLogic => LogicBase. The LogicBase uses the IViewModelLocator to find the right view model based on naming conventions (all documented)
3) Then the IViewModelFactory will instantiate the vm (using dependency injection) and return it to the logic which will set it as datacontext.
Note that as the advanced documentation tells you, Catel injects an additional layer to make a difference between the outside datacontext and the VM datacontext (of a window or user control content).
ps. I really recommend starting to use the latest prereleases via NuGet. Catel 4.0 (will be released very soon) is nearly feature complete and will prevent you from a lot of breaking changes that you have to go through (and it is of course much better :-))

Why do modules use classes in puppet (instead of defines)

I've been creating a couple of classes (in different modules) for puppet. Both, separately, require maven. So both classes have something like the following:
class { "maven::maven":
version => "3.0.5"
}
(using the https://forge.puppetlabs.com/maestrodev/maven module from puppet forge)
But, if I have one node that has both of my classes, puppet complains because class 'maven::maven' is declared twice. I feel like each of my classes should be free to declare all of the things it needs. If a node has more than one class both of which require maven, then I don't see the problem.
So, my question is: was the author of that maven module wrong to use a class, should he have used a define instead? (because you can use/call/whatever a define multiple times). It appears that if he had used a define I would be able to have the block of code as many times as I like, so if he was right to use a class, why?
Thanks.
I think the rationale behind this is best explained in John Arundel's Puppet 3 Beginner's Guide:
So if you're wondering which to use, consider:
Will you need to have multiple instances of this on the same node
(for example, a website)? If so, use a definition.
Could this
cause conflicts with other instances of the same thing on this node
(for example, a web server)? If so, use a class.
If you're passing in parameters to a class, there is a possibility of a conflict, the problem being that it is not clear which sets of parameters will get used.
If your first module required maven with 3.0.5 but your second module required maven with 3.0.6, puppet would not know which one to use.
The puppet module, in making it a class and not a resource/defined type, does not handle the resolution as well, because it was probably intended for a single install.
Puppet currently only supports re-using class declarations without parameters, ie. include maven::maven.
Finally, declaring dependencies on other modules in your own module is a tricky thing, that I do not know how to fully resolve yet.

#Grape in scripts with multiple files

I'd like to use #Grape in my groovy program but my program consists of several files. The examples on the Groovy Grape page all seem to assume that your script will consist of one file. How can I do this? Should I just add it to one of the files and expect that the imports will work from the others? If so, then is it common to place all the #Grape calls in one file with no other code? Do I need to add the Grape call to all files that will import the package? Do I need to download the JAR and create a Gradle file, which I was getting away without at this point?
the grape engine and the #grab annotation were created as part of core groovy with single file scripts in mind, to allow a chunk of text to easily become a fully functional program.
for larger applications, gradle is an awesome build tool with lots of useful features.
but yes, you can manage all the application dependencies just with grape.
whether you annotate every file or a single one does not matter, just make sure the #grab annotated file is read before you try to use the external class.
annotating the main class is probably better as you will easily lose track of library versions if you have the annotations scattered.
and yes, you should consider gradle for any application with more than a dozen files or anything you might want to reuse elsewhere as a library.
In my opinion, it depends how your program is to be run...
If your program is to be run as a collection of standalone scripts, then I'd probably stick the #Grab required for each script at the top of each of them.
If your program is more of a standard style program with a single point of entry, then I'd go for using a build tool like Gradle (as you say), as you get a lot of easy wins by using it.
Firstly, it makes it easy to define your dependencies (and build a single large jar containing all of them)
Secondly, Gradle makes it really easy to start writing tests, include code coverage plugins, or useful tools like codenarc to suggest possible fixes or improvements to your code. These all become invaluable not only for improving your code (or knowing your code works), but also when refactoring your code, you know you've not broken anything that used to work.

Log4j category weirdness

I've been having a frustrating time trying to sort out the logging in my project. In particular, one of the 3rd party libraries we use had one class, com.foo.bar.baz.java, that ignored any configuration in the properties file for the com.foo.bar package, instead following the application-wide properties.
Eventually using %c in the pattern layout I learned that Log4J was logging it as Windows rather than its package.
What could be causing this? It's proving remarkably Google-proof.
Don't forget that while the use of the fully qualified name of the class is the usual convention, it's not a requirement!
The author's quite at liberty to use whatever string they want as the Logger name and it sounds as if in this case, they've gone for a component based name.
There could be a lot of things causing it. Can you post your log configuration file? Do you have a gui project? Are you (or the 3rd party library) attempting to log to gui components?
Are you able to view the log4j configuration files of your 3rd party library?
To address your question of what could be causing this, on the surface, it sounds like they have created a custom logging implementation that is overriding your settings. There are lots of ways to achieve that.
For example, our application at work runs on Tomcat and there's a <logging> section in the server-config.xml file that allows one to specify a custom logging target for the server.
As another example, I've been bitten dozens of times by rogue commons-logging.properties files which can change the entire functionality of all logging, application wide, just by modifying a few properties. Further, those files specify a priority flag and if any property file is found on the classpath with a higher priority than the one in your project, it takes precedence!
Overall, there are lots of potential problems here. To be of more assistance, I would need a bit more information.

Resources