Anatomy of an Application

A NeuroKernel application can be compiled to either JavaScript or WebAssembly and can be executed by a task container. When a request is made to run an application either registered or remote, task processor creates a task container and boots the task to the container. Application code is executed inside this container. The task container is the first level of sandboxing done by NeuroKernel. Task running the application inside the container may have direct access to the resources and kernel modules. Kernel may give access to some resources, and controlled access to some or no access to some others. It all depends on some variables associated with the application itself. Kernel is fused together with a kernel task compiled with NeuroKernel API and low level kernel modules distributed in web browser or server if any.

1. Task Container

Task container is the external mini kernel of a task that runs the Application. It decides what an application can do or cannot do before directing its request to the kernel. The request may be denied or found suspicious by the Kernel, and that would result to an immediate termination of the task. Kernel is especially very ruthless against Remote tasks. The system interfaces are all handled by the task container and can be accessed through ISystem interface.

2. Main Task

Main Task is responsible with running the application and is part of the task container. It boots the application code, makes preflight communications with kernel modules and desktop manager if there is one. Its implementation may differ for each platform.

3. Application

Application is the code written and compiled by the developer. NApplication class is extended for this purpose. Kernel allocates a main window for each application which can be accessed using getMainFrame method. Accessing resource and configuration for generators is done on the main application class.

3.1 Main Method

Main method is the application execution entry point, and called by the task. Main task may require the use of Java static main method on some platforms to initiate the execution process as seen in the below example.

import com.neurokernel.client.*;
import com.neurokernel.adapter.NActionListener;
 
public class HelloWorld extends NApplication {
      public HelloWorld() {
      }
 
      public HelloWorld(String[] argv) {
      }
 
      @Override
      public void main(int argc, String[] argv) {
          final NFrame mainFrame=getMainFrame();
          NButton button=new NButton(mainFrame,"Hello");
 
          button.addActionListener(new NActionListener() {
              @Override
              public void onAction(NEvent e) {
                  NMessageDialog.showInfo(mainFrame,"Hello World");
              }
          });
 
          mainFrame.setTitle("Hello");
          mainFrame.setBounds(20,20,200,200);
          mainFrame.setVisible(true);
      }
 
      public static void main(String[] args) {
          new HelloWorld();
     }
}

It is possible to pass arguments to the application from the static main method when required by implementing a constructor with the arguments as seen in the above example.

4. Application Main Window

When an application execution request reaches Kernel, the task processor module asks window manager to allocate a application main window. This top level window is the root to all other windows, dialogs or tool windows created by the application. Windows and controls are created in a tree hierarchy where the top level main window is the root of all. Destroying the main window means exiting the application entirely.

5. Plug-in Application

An application in NeuroKernel can be used as a plugin inside other applications. By default, an application cannot be used as plugin. If the developer desires the application to be used as a plugin, then isPluggable method of NApplication class is overridden to return true. There is also Configure annotation, and pluggable value of this annotation can be set to true.

6. Configuration Annotation

Configuration annotation gives some runtime cues to the task container about how to run the application. Only NApplication class can define this annotation. Please also see Guide to Annotations for more details and examples.

7. Device Application

A Plugin application can define one or more devices to be used by the parent application. The advantage of using a device is the way the IPC is used. Although the event based communication is still available to use, devices also introduce RPC methods that can be called by parents. This makes the use of same type devices by different applications from different author to be used for the same purpose. Compatible devices must have the same footprint like device name and method definitions. Some commonly used devices may be standardized by NeuroKernel Research via an NDR (NeuroKernel Device Request). NDRs will be considered after NeuroKernel is widely adapted by the community.

8. File System Application

Some plugin applications may choose to implement a file system by implementing IFileSystem interface. This will allow the parent task to mount the plugged in file system. Display Manager for example may implement a file system that would be used as the system default file system available to registered applications.

9. Loading Resources

Loading resources is made easier with the API and generators. It is also possible to use the compiler supported specific ways to load or embed resources to the executable. LoadResources annotation is used to embed resources to the executable. The generators for each supported compiler is automatically add the resources to the executable JavaScript file. If only a server side application is the target, conventional ways to load resources with Java Standard Edition is used. Please also see Guide to Annotations for more details and examples.

import com.neurokernel.client.*;
import com.neurokernel.client.annotation.LoadResources;
import com.neurokernel.client.annotation.Source;
 
@LoadResources(
        resources = {
            @Source(value = "resources/myicon.gif", name = "appicon")
            @Source(value = "resources/banner.png", name = "banner"),
        }, 
        loadIcon = false
)
public class ResourcesExample extends NApplication {
      @Override
      public void main(int argc, String[] argv) {
          loadIcon((NImage)getResource("appicon"));
 
          NFrame mainFrame=getMainFrame();
          new NImageView(mainFrame, (NImage)getResource("banner"));
 
          mainFrame.setTitle("Resources");
          mainFrame.setBounds(20,20,200,200);
          mainFrame.setVisible(true);
      }
}