System Interfaces

NeuroKernel uses many technologies present in modern browsers and makes these features available as system interfaces to the developers via its extensive API. Some features are made available to tasks directly using their task container, and some require authorization from the Kernel and only available if the authorization given. Remote applications if not trusted will be denied to some of these interfaces by the Kernel.

1. Client Storage

Client storage is the persistent storage feature available from the browser client. NeuroKernel uses IndexDB by default for the persistent storage but fall backs to local storage if indexDB is not supported. If remote applications fail to request persistent storage access, a memory based implementation is used to offset operational functionality but nothing will persist in this case. The existence of persistent storage can be checked using the ISystem interface. Client storage can also store images via a sub interface called IPixmapStorage available from IClientStorage.

import com.neurokernel.client.*;
import com.neurokernel.adapter.NDataListener;
 
public class StorageExample extends NApplication {
      @Override
      public void main(int argc, String[] argv) {
          final NFrame mainFrame=getMainFrame();
          mainFrame.setTitle("Storage Interface");
          mainFrame.setBounds(20,20,200,200);
          mainFrame.setVisible(true);
 
          getSystem().getClientStorage().load(new NDataListener() {
             @Override
             public void onSuccess(IResponse connection) {
                  getSystem().getClientStorage().add("Hello", "World", new NDataListener() {
                      @Override
                      public void onSuccess(IResponse connection) {
                            new NLabel(mainFrame,"added "+connection.getRequestData());
                            mainFrame.repaint();
                      }
 
                      @Override
                      public void onFailure(IResponse connection) {
                           NMessageDialog.showError(mainFrame,"Hello already exists");
                      }
                  });
              }
 
              @Override
              public void onFailure(IResponse connection) {
                   NMessageDialog.showError(mainFrame,"Failed to load Storage");
              }
          });
      }
}

2. File System

Accessing file systems is very straight forward with NeuroKernel /OS. System can recognize which file system a file belongs to by its prefix. If the file starts with slash /, then it is the default file system used by the system. If it starts with nfs:[name]/, it is a mounted file system that may be living on a remote location. The default file system is just a memory mapped file system when an application is a unregistered remote application. Trusted remote applications will have access to shared temporary file system. This file system is also available for all registered and trusted applications. Users may copy and paste from default file system to temporary file system so that remote application may access it if desired.

import com.neurokernel.client.*;
import com.neurokernel.client.io.*;
import com.neurokernel.adapter.NActionListener;
 
public class FileSystemExample extends NApplication {
      @Override
      public void main(int argc, String[] argv) {
          final NFrame mainFrame = getMainFrame();
 
          new NButton(mainFrame,"Get Date").addListener(new NActionListener() {
              @Override
              public void onAction(NEvent e) {
                  NFile myFile = new NFile("/myfile.txt");
                  IFileSystem fileSystem=myFile.getFileSystem(getSystem());
                  fileSystem.exists(myFile, new IDataListener() {
                      @Override
                      public void onSuccess(IResponse connection) {
                          NMessageDialog.showInfo(mainFrame,"File exists");
                      }
 
                      @Override
                      public void onFailure( IResponse connection) {
                          NMessageDialog.showError(mainFrame,"File does not exist");
                      }
                  });
              }
          });
 
          mainFrame.setTitle("File System Interface");
          mainFrame.setBounds(20,20,200,200);
          mainFrame.setVisible(true);
      }
}

3. Terminal

NeuroKernel also offers an interface to input and output to a terminal. A terminal application is available with the default package which is used for terminal IO. The terminal access request is made with getTerminal method which returns an ITerminal interface object, and ITerminalListener is used to manage the input and output operations. Application must be executed from the terminal command line in order to have terminal functionality. ITerminal interface object is also passed to the listener methods for more convenient way of interaction.

import com.neurokernel.client.*;
import com.neurokernel.client.io.*;
import com.neurokernel.client.system.*;
 
/**
 * This application must be run from NeuroKernel terminal
 */
public class TerminalExample extends NApplication {
    NLabel label;
 
    @Override
    public void main(int argc, String[] argv) {
       getSystem().getTerminal(new NTerminalListener() {
            @Override
            public void onData(ITerminal stdio) {
                String input=stdio.readString();
                if (input == null && stdio.getKeyCode() == 0) {
                    stdio.writeString("Hello Console!");
                    stdio.setPrompt("password:", true);
                } else if (stdio.getKeyCode() > 0) {
                    stdio.setPrompt("Command> ");
                } else {
                    stdio.writeString("You have entered: " + input);
                    if (input.equals("close")) {
                        stdio.close();
                    } else {
                       label.setText(input); //also sets the label text
                       stdio.writeString("Press any key to continue...", 
                                 NSystemConstants.TERMINAL_WAIT_KEY_INPUT);
                    }
                }
            }
       });
 
       NFrame mainFrame=getMainFrame();
       label=new NLabel(mainFrame);
       mainFrame.setTitle("Terminal Example");
       mainFrame.setBounds(20,20,300,300);
       mainFrame.setVisible(true);
    }
}

4. CallBack Handler

Callbacks are important part of protocol based systems. There should be an automated interaction between application and presentation system. Callbacks can be used for this purpose. A callback can also be used to display or process a repeated job. It is possible to make a callback continuous that can be called constantly in a specified interval until it is stopped. ICallbackHandler is the main system interface for this purpose. The delay interval is given as milliseconds.

import com.neurokernel.client.*;
import com.neurokernel.client.system.adapter.*;
 
public class CallBackExample extends NApplication {
      private NConsolePane console;
 
      @Override
      public void main(int argc, String[] argv) {
         NFrame mainFrame = getMainFrame();
         console = new NConsolePane(new NScrollView(mainFrame);
 
         ICallbackHandler callbackHandler=getSystem().getCallbackHandler();
         callbackHandler.start(1000, new NCallbackAdapter() {
             @Override
             public void run() {
                console.print("Hello Callback");
             }
         });
 
          mainFrame.setTitle("Callback Interface");
          mainFrame.setBounds(20,20,200,200);
          mainFrame.setVisible(true);
      }
}
   import com.neurokernel.client.*;
   import com.neurokernel.client.adapter.NCallbackAdapter;
 
   public class CallBackHandler extends NApplication {
      @Override
      public void main(int argc, String[] argv) {
          getSystem().getCallbackHandler().start(new Callback(), 1000);
      }
 
      public class Callback extends NCallbackAdapter {
          private int counter;
          @Override
          public void run() {
              getConsole().println("Hello "+ (counter++));
              if (counter < 20) {
                  getSystem().getCallbackHandler().start(this, 1000);
              }
          }
      }
   }
 }
 

5. System Console

Modern web browsers have a console for information tracing purposes from the running scripts. NeuroKernel can utilize this console feature with a IConsole system interface. C like text formatting can be achieved with printf method which is also available from NTools utility class for any kind of string formatting purpose. It does not have all the functionality of the C supplied version of the formatting.

import com.neurokernel.client.*;
import com.neurokernel.client.adapter.*;
 
public class HistoryExample extends NApplication {
      private int currentState;
      @Override
      public void main(int argc, String[] argv) {
          final NFrame mainFrame = getMainFrame();
 
          new NButton(mainFrame,"Print").addListener(new NActionListener() {
               @Override
               public void onAction(NEvent e) {
                    getConsole().print("Hello "+(currentState++));
               }
          });
 
          mainFrame.setTitle("History Interface");
          mainFrame.setBounds(20,20,200,200);
          mainFrame.setVisible(true);
      }
}

6. History

Web browser history feature is accessible using IHistory interface. Applications can push or pop history states which may be triggered using the back and forward buttons of the browser. It may useful for many practical purposes.

import com.neurokernel.client.*;
import com.neurokernel.client.adapter.*;
import com.neurokernel.client.system.*;
import com.neurokernel.client.system.adapter.*;
 
public class HistoryExample extends NApplication {
      private int currentState;
      @Override
      public void main(int argc, String[] argv) {
          final NFrame mainFrame = getMainFrame();
 
          final IHistory history = getSystem().getHistoryManager();
          history.addHistoryListener(new NHistoryListener() {
               @Override
               public void onChange(String id) {
                   NMessageDialog.showInfo(mainFrame,"History State:"+ id);
               }
          });
 
          new NButton(mainFrame,"Push State").addListener(new NActionListener() {
               @Override
               public void onAction(NEvent e) {
                    history.pushState("State"+(currentState++));
               }
          });
 
          mainFrame.setTitle("History Interface");
          mainFrame.setBounds(20,20,200,200);
          mainFrame.setVisible(true);
      }
}

7. Geo Location

Geo location interface is only available when the application is run from an HTTPS secure domain. Browser will also ask permission to use the geo location. An example of how to use this IGeoLocation system interface given below.

import com.neurokernel.client.*;
import com.neurokernel.client.system.*;
import com.neurokernel.client.system.adapter.*;
 
public class GeoLocationExample extends NApplication {
      @Override
      public void main(int argc, String[] argv) {
          final NFrame mainFrame = getMainFrame();
 
          new NButton(mainFrame,"GeoLocation").addListener(new NActionListener() {
              @Override
              public void onAction(NEvent e) {
                   IGeoLocation location=getSystem().getGeoLocation();
                   location.addPositionListener(new NGeoPositionListener() {
                        public void onChange(IGeoPosition position) {
                            NMessageDialog.showInfo(mainFrame, position.getLongitude()+" "+position.getLatitude());
                        }
                   });
              }
          });
 
          mainFrame.setTitle("Geo Location Interface");
          mainFrame.setBounds(20,20,200,200);
          mainFrame.setVisible(true);
      }
}

8. Game Pad

NeuroKernel has support for gamepad interface available in modern browsers. IGamepadHandler is the main system interface to access to the gamepad features. IGamepad is on the other hand is used to process the events sent from the gamepad control. Gamepad handler can be accessed from the IWindowContext interface. When a new gamepad is connected to the computer, system makes the gamepad ready. It then sends the actions on gamepad in an event package to the currently focused task window. Gamepad interface is especially useful for game developers.

9. Shared Data

Shared data access is available to all trusted applications. It is important not to use easy to guess shared data entries for important data if remote applications are utilized. Shared data entries can be created as read only which cannot be overwritten by other tasks.

import com.neurokernel.client.*;
import com.neurokernel.client.system.*;
import com.neurokernel.client.system.adapter.*;
 
public class SharedDataExample extends NApplication {
      private ISharedData sharedData;
      @Override
      public void main(int argc, String[] argv) {
          final NFrame mainFrame = getMainFrame();
          sharedData=getSystem().getSharedDataHandler();
          sharedData.write("Where","NeuroKernel in Cambridge",true);
 
          new NButton(mainFrame,"Read").addListener(new NActionListener() {
              @Override
              public void onAction(NEvent e) {
                   sharedData.read("Where",new NDataListener() {
                        @Override
                        public void onSuccess(IResponse response) {
                             NMessageDialog.showInfo(mainFrame, "Data:",response.readString());
                        }
                   });
              }
          });
 
          mainFrame.setTitle("Shared Data Interface");
          mainFrame.setBounds(20,20,200,200);
          mainFrame.setVisible(true);
      }
}

10. Creating Sound Effects

NeuroKernel allows developers to create custom sound effects using IAudioGenerator interface. The created custom sound can be cached to the display server.

   import com.neurokernel.client.*;
   import com.neurokernel.client.media.IAudioGenerator;
   import com.neurokernel.client.adapter.NActionListener;
 
   public class MyApplication extends NApplication {
       @Override
       public void main(int argc, String[] argv) {
           final NFrame mainFrame=getMainFrame();
           NButton button=new NButton(mainFrame,"Play");
 
           button.addActionListener(new NActionListener() {
               @Override
               public void onAction(NEvent e) {
                   IAudioGenerator audio = getSystem().getAudioGenerator();
                   audio.setWaveType(WaveType.SINE);
                   audio.setEnvelopeSustainTime(0.31718502829007483);
                   audio.setEnvelopeDecayTime(0.2718540993592685);
                   audio.setStartFrequency(0.26126191208337196);
                   audio.setFrequencySlide(0.43787689856926615);
                   audio.setDutyCycle(1);
                   audio.setRetriggerRate(0.7558565452384385);
                   audio.setVolume(25);
                   audio.setSampleRate(44100);
                   audio.setSampleSize(8);
                   audio.play();
               }
           });
 
           mainFrame.setTitle("Audio Generator Demo");
           mainFrame.setBounds(20,20,200,200);
           mainFrame.setVisible(true);
       }
   }
 

11. Printing

Printing in NeuroKernel is integrated into the printing functionality of the web browser itself. NeuroKernel API gives support on paper sizes and other printing related features. System allows developers to print a window or single component. PDF Viewer can also be used for printing purposes. PDF Viewer component does not use browser native pdf viewer, and it is based on pdf.js library for better programmatic control. The printContent method is available to all components and containers. Some containers may have more specific printing options.

import com.neurokernel.client.*;
import com.neurokernel.adapter.NActionListener;
 
public class HelloWorld extends NApplication {
      @Override
      public void main(int argc, String[] argv) {
          final NFrame mainFrame=getMainFrame();
          NButton button=new NButton(mainFrame,"Print");
 
          button.addActionListener(new NActionListener() {
              @Override
              public void onAction(NEvent e) {
                  //print window with decorations
                  main.printContent(true);
              }
          });
 
          mainFrame.setTitle("Print Window");
          mainFrame.setBounds(20,20,200,200);
          mainFrame.setVisible(true);
      }
}