I am looking for a tutor for module development

Nah, you're fine. We have occasional job posts/job seekers as well; I think as long as they're not inundating the forum it's not a big deal.

I think at least part of the confusion for people who might be familiar with programming, but struggle to get started with module development, is that you're learning two separate things at the same time.
There's a particular Java build stack (whether you choose Maven or Gradle or whatever), and then attached to it the Ignition API surface, which is fairly massive.

It's also a problem from the other direction: people tell us they want a 'module development' course, but it's almost impossible to target everyone's experience with the different aspects.

I guess I'll start with some very high level principles.
Your build system of choice (generally Gradle or Maven, there's other options but they're certainly the most common these days) is usually in charge of running the Java compiler over your Java source files to generate a jar file. JAR files are just ZIPs full of .class files, which are themselves essentially just JVM bytecode. That's an important point of distinction - once it's a class file, it's not technically Java anymore. That's part of how alternate JVM languages like Kotlin and Scala work - they just have to emit valid bytecode, without the limitations of Java's own syntax and compiler. (There are also tools available to 'decompile' bytecode back to ~the input Java code, but there's always information lost, such as parameter names for method and other issues. IntelliJ has a pretty good decompiler built in, which can help to look into library code you don't have the underlying source for).

By convention, Maven (the big kahuna Java build system for a long time) looks for Java files to compile in src/main/java. Every directory under that root by convention defines your package structure. Package structure is important, because there's a single global namespace in the final JVM - every class must have a unique fully-qualified name. By convention, the package name you use should be a reversed domain name that you control - that allows you to "prove" that you wrote the code, and is useful for library distribution (and part of the verification process on repositories like Maven Central). Gradle follows these conventions precisely because Maven was dominant for such a long time. However, in both Maven and Gradle, you can readily change these things (it's just generally not a good idea unless you have a good reason).

Separate from the actual source file organization, you can organize your projects themselves into "subprojects" (what Gradle calls them, Maven may have a different name). Basically these are just folders at the top-level that contain their own build-system descriptors (build.gradle(.kts)/pom.xml). Somewhere on the top level, you'll define which subprojects you have, and your build system will automatically reach into those subfolders and build their projects too.
For instance, in the Perspective Component example, there's four subprojects: common, designer, gateway, and web. Those are outlined in the settings.gradle at the root.

So that's the very broad overview of Java building. Pivoting a little to Ignition:

That common/gateway/designer split is a common convention in the realm of Ignition, because 1. code re-use is nice, and 2. you almost always want to deliver different artifacts to the different Ignition scopes (because they have different APIs and different capabilities). So you build those subprojects, and each outlines their own dependencies on Ignition; e.g. common depends on Ignition's own common layer: https://github.com/inductiveautomation/ignition-sdk-examples/blob/master/perspective-component/common/build.gradle#L12
And then gateway can depend on both Ignition specific gateway apis and the common subproject:
https://github.com/inductiveautomation/ignition-sdk-examples/blob/master/perspective-component/gateway/build.gradle#L10
That is how you tell the build system (and your IDE) "this code I'm writing in gateway can use anything I've written in common.

The only fundamental unit you need to provide as a module is some implementation of the appropriate hook class for your desired scope. Basically, you author a class that implements the *Hook (or, better extends the abstract class we provide) for the right scope, e.g. AbstractGatewayModuleHook for the gateway:

There are various lifecycle methods that will be invoked for you - setup, startup, and shutdown. Those are how your module gets access to the rest of Ignition - from the GatewayContext you get in setup, you can get access to the myriad subsystems available in Ignition.

However, just implementing the class and putting it into a jar file isn't enough. Ignition doesn't "know" enough to know how to actually do anything with one or more plain .jar files. So there's one final piece - the actual module .modl file. The actual module file is nothing more than a ZIP file that contains a bunch of .jar files and a module.xml file. That module.xml file is crucial - it tells Ignition how to load your various jar files, what scopes they belong to, and most importantly, what your actual hook classes are:

<?xml version="1.0" encoding="UTF-8"?>
<modules>
	<module>
		<id>com.inductiveautomation.ignition.examples.hce</id>
		<name>Gateway Webpage Example</name>
		<description>Implements a fake "Home Connect" hub status and configuration page</description>
		<version>1.0.0-SNAPSHOT</version>
		<requiredignitionversion>8.1.0-SNAPSHOT</requiredignitionversion>
		<depends scope="G">com.inductiveautomation.opcua</depends>
		<jar scope="G">gateway-webpage-gateway-1.0.0-SNAPSHOT.jar</jar>
		<hook scope="G">com.inductiveautomation.ignition.examples.hce.GatewayHook</hook>
	</module>
</modules>

Generating these XML files by hand would be annoying, which is why we provide Maven and Gradle plugins to build modules for you. The 'new' generation is available here, and is the exact same tool we use internally.
Your build system of choice should provide a place to configure this plugin, e.g. Gradle:
https://github.com/inductiveautomation/ignition-sdk-examples/blob/master/perspective-component/build.gradle#L34
or Maven:

I just kinda rambled that all out, and my hand hurts now, but hopefully that helps a bit to orient.

If you've got particular questions on how to approach something in Ignition, I'd definitely say to ask here on the forums. More general build system questions might be better suited for other places, but it doesn't really hurt to ask here either.

18 Likes