Class Main

java.lang.Object
org.spiderwiz.core.Main

@WizMain
public abstract class Main
extends Object
Starting point for all Spiderwiz applications.

To build a Spiderwiz application start with implementing an extension of this class. To invoke the framework and set everything in motion, call its init() method. You would usually do this in a main() method of a Java Application, or, if you build a Java Web Application, in an implementation of HttpServlet that you run with the loadOnStartup flag. When your application terminates, you should call cleanup(). For example:

    @WebServlet(name="Startup", urlPatterns={"/Startup"}, loadOnStartup = 1)
    public class Startup extends HttpServlet {
        @Override
        public void init() throws ServletException {
            super.init();
            (new MyMain("", "myapp.conf", "My first Spiderwiz web application", "1.00")).init();
        }

        @Override
        public void destroy() {
            MyMain.getInstance().cleanup();
            super.destroy();
        }
    }

There are two places where you can put your own initialization code. The first is by overriding ways to provide your own initialization code. The first is to override preStart(), which is called once the application's configuration file has been loaded and the logging mechanism has been established but before communication channels are established and data starts to flow. The other option is to override postStart(), which is executed after full framework initialization, when communication channels have been established and data starts to flow.

The main ingredient of the framework is the data object, implemented as a class that extends DataObject. By convention, data objects are implemented in organization-shared Java Class Libraries. When you design your application, the first question you should ask yourself is which data object types you are going to use and whether you are a producer or a consumer of each type (you can be both). You tell which objects you produce by implementing getProducedObjects() and which objects you consume by implementing getConsumedObjects().

The next step is to implement and register data object handlers - classes that extend the shared library classes and provide implementation code specific to your application. These are optional for object types that you produce and essential for object types that you consume, as you need to provide event handling code. You must register all the data object classes that you use, whether extended or not, in populateObjectFactory().

Two other methods that you may use frequently are createTopLevelObject() to create an object that is not a child of another object (for a child object use DataObject.createChild()), and createQuery(), which is the short way for creating a QueryObject.

Some methods are used for customizing SpiderAdmin. If you do that then the methods that you will most frequently override are getPageInfo() and customAdminService().

See the description below for these and other methods that are used less frequently.

  • Constructor Details

    • Main

      public Main​(String rootFolder, String configFileName, String appName, String appVersion)
      Constructs an instance with root directory, configuration file name, default application name and version number.
      Parameters:
      rootFolder - the application root directory. An empty string refers to the project base directory (${basedir}).
      configFileName - the application configuration file that must reside in the application root directory. See How to configure a Spiderwiz application for the syntax and semantics of Spiderwiz configuration files.
      appName - the default application name that shows in case you do not configure an application name in the application's configuration file. You can dynamically override this value by implementing getAppname().
      appVersion - the default application version number. You can dynamically override this value by implementing getAppVersion().
  • Method Details

    • getInstance

      public static Main getInstance()
      Returns the singleton instance of the class.

      Class Main runs as a singleton whose instance is set when you call init(). Use it to call the class public methods from anywhere in your application.

      Returns:
      the class singleton instance or null if this method is called before calling init().
    • getConfig

      public static ZConfig getConfig()
      Returns an object that lets you access and manipulate the application's configuration file.

      The method should be called only after you call init().

      Returns:
      an object used to access and manipulate Spiderwiz configuration files.
    • getLogger

      public static ZLog getLogger()
      Returns an object that lets you print custom log messages to the application's main logging system.

      The method should be called only after you call init().

      For details about logging see Spiderwiz Logging System.

      Returns:
      the application's logging object.
    • getRootFolder

      public String getRootFolder()
      Returns the application's root folder.
      Returns:
      the full pathname of the application's root folder.
    • getAppName

      public String getAppName()
      Returns the application name.

      The application name is used for application monitoring and identification. If the application's configuration file contains an [application name] property then the value of the property is returned, otherwise the appName parameter value given to the class constructor is used.

      You can override this method to provide your custom application name.

      Returns:
      the application name.
    • getAppVersion

      public String getAppVersion()
      Returns the application's version number.

      This method is used by SpiderAdmin when you use it to monitor your application.

      By default, the application's version number is appVersion parameter value given to the class constructor. You can override this method to provide your custom version number.

      Returns:
      the application's version number.
    • getCoreVersion

      protected String getCoreVersion()
      Returns Spiderwiz library version number used to build the application.

      This method is used by SpiderAdmin when you use it to monitor your application.

      Spiderwiz library version number is hard coded. You can override this method to return another value, or a value that combines the library version number with another value. For instance, assuming you have a library that is used across your organization that subclasses Main by OrgMain, which is then extended by individual implementations. You want SpiderAdmin to show the organization library version along Spiderwiz library version. You can then implement in OrgMain:

          private static const String ORG_LIB_VERSION = "14.92";
          @Override
          protected String getCoreVersion() {
              return String.format("%1$s (OrgLib %2$s)", super.getCoreVersion(), ORG_LIB_VERSION);
          }
      Returns:
      a string that represents a version number.
    • getAppUUID

      public final UUID getAppUUID()
      Returns the application UUID.

      The application's UUID is automatically generated the first time the application runs and is stored as the value of the [application uuid] property in the application's configuration file. Normally you should never touch this value by hand.

      Returns:
      the application's UUID.
    • getAppParams

      public Map<String,​String> getAppParams()
      Returns application instance parameters.

      Every Spiderwiz application instance may define a set of arbitrary parameters, which are published across the network along with other information about the application. Peer applications can implement DataObject.filterDestination() to review the parameters and filter output to the parameterized application accordingly.

      Override this method to define application parameters as a name-value map.

      Returns:
      application parameters as a name-value map, or null if the application instance defines no parameters.
    • init

      public final boolean init()
      Initializes the class singleton, putting the application in motion.

      Application initialization includes the following steps:

      • Set the class singleton instance.
      • Process the configuration file.
      • Start the logging mechanism.
      • Registering data object handlers.
      • Establish the configured network connections.
      • Broadcast requests for all consumed data objects and start processing input data.
      Returns:
      true if this the first time the method is called and the instance has been properly initialized
    • postStart

      protected void postStart()
      Override this method to run extra initialization code after full framework initialization.
    • cleanup

      public void cleanup()
      Cleans up application resources before termination.

      Call this method before your application terminates in order to release all resources and shut down network connections gracefully. See the example above.

    • preStart

      protected boolean preStart()
      Executes custom initialization code.

      Override this method if you want to do anything once the application's configuration file has been loaded and the logging mechanism has been established, but before communication channels are established and data starts to flow.

      Returns:
      true if application shall continue, false if something has gone wrong and you want to abort application execution.
    • reset

      public final void reset()
      Resets application data.

      This method clears the entire data object tree and broadcasts a request to all peer applications to reset the objects that it consumes. The method will be called daily at the time set by [start of day] property of the application's configuration file (unless you override runDailyTask()). You can also call this method on other occasions, for instance when you want to promote a change in getAppParams(), which affects the behavior of filterDestination() of peer applications.

    • getProducedObjects

      protected abstract String[] getProducedObjects()
      Registers the application as a producer of the listed data object types.

      Implement this method to tell Spiderwiz runtime engine which data object types your application produces. The produced data objects are identified by their Object Codes, i.e. the static ObjectCode field defined for the object class. You can also specify predefined object codes.

      This is an abstract method that you must implement. If your application does not produce any data object then return an empty array.

      Note that this method is called after the application's configuration file is processed, so it can return dynamic values depending on the configuration.

      Example:

          @Override
          protected String[] getProducedObjects() {
              return getConfig().isPropertySet("is producer") ? new String[]{
                  MyFirstObject.ObjectCode, MySecondObject.ObjectCode
              } : new String[]{
                  ObjectCodes.EventReport
              };
          }
      Returns:
      an array of String containing the codes of the produced objects.
    • getConsumedObjects

      protected abstract String[] getConsumedObjects()
      Registers the application as a consumer of the listed data object types.

      Implement this method to tell Spiderwiz runtime engine which data object types your application consumes. The consumed data objects are identified by their Object Codes, i.e. the static ObjectCode field defined for the object class. You can also specify predefined object codes.

      This is an abstract method that you must implement. If your application does not consume any data object then return an empty array.

      Note that this method is called after the application's configuration file is processed, so it can return dynamic values depending on the configuration.

      Example:

          @Override
          protected String[] getConsumedObjects() {
              return getConfig().isPropertySet("is producer") ? new String[]{
                  ObjectCodes.EventReport
              } : new String[]{
                  MyFirstObject.ObjectCode, MySecondObject.ObjectCode
              };
          }
      Returns:
      an array of String containing the codes of the consumed objects.
    • populateObjectFactory

      protected void populateObjectFactory​(List<Class<? extends DataObject>> factoryList)
      Registers application-specific object handlers.

      Override this method to add your data object implementations to the framework's object factory. This is done by adding the class object of the implementation classes to the given factoryList parameter.

      To preserve predefined object handlers and handlers registered up in the hierarchy of Main subclasses, call the super instance of this method.

      Typically, object handlers implement either a producer or a consumer subclass of a data object (class that extends DataObject).

      Example:

          @Override
          protected void populateObjectFactory(List<Class<? extends DataObject>> factoryList) {
              super.populateObjectFactory(factoryList);
              if (getConfig().isPropertySet("is producer"))
                  factoryList.add(MyFirstObjectProducer.class);
              else
                  factoryList.add(MyFirstObjectConsumer.class);
          }
      Parameters:
      factoryList - a List of elements of type Class, modeled to accept only classes that extend DataObject.
    • createTopLevelObject

      public static <T extends DataObject> T createTopLevelObject​(Class<T> type, String id) throws NoSuchFieldException, IllegalAccessException
      Creates a top level data object.

      Top level data objects are objects whose getParentCode() method returns null. These objects, unless defined disposable, are stored as children of a predefined root object. Use this method to create a top level data object. To create a child object, use createChild().

      The method accepts two parameters: the Class of the object you want to create (that must extend DataObject) and the object ID. The ID may be null if the class is a singleton or disposable.

      If the given class is not disposable, the method first tries to locate an object with the same object code and ID (or an existing singleton if ID is null). If none exists, or if the class is disposable, the method creates a new object with the given ID. Note that the actual class that will be created is the class registered by populateObjectFactory(), which may be a subclass of the given type. The type of the returned object is the type specified in the parameter.

      The given class type must contain or inherit a public static field named ObjectCode, otherwise the method will throw an exception.

      Type Parameters:
      T - class type of the object you want to create.
      Parameters:
      type - the class of the object you want to create.
      id - the object ID of the object. Can be null if the object is a singleton or disposable.
      Returns:
      the found or created object, or null if the object could not be created or it is not defined as a top level object.
      Throws:
      NoSuchFieldException - if class type doesn't contain a static ObjectCode field.
      IllegalAccessException - if ObjectCode field of class type is not public.
    • createQuery

      public final <T extends QueryObject> T createQuery​(Class<T> type) throws NoSuchFieldException, IllegalAccessException
      Creates a query object.

      Query objects are data objects that extend QueryObject, used for round trip messaging. By default, they are top level and disposable. Use this method to create a top level disposable query object. To create a child query object, use createChild(). To create an indisposable top-level query object, use createTopLevelObject().

      The method accepts one parameter: the Class of the object you want to create (that must extend QueryObject).

      Note that the actual class that will be created is the class registered by populateObjectFactory(), which may be a subclass of the given type. The type of the returned object is the type specified in the parameter.

      The given class type must contain or inherit a public static field named ObjectCode, otherwise the method will throw an exception.

      Type Parameters:
      T - class type of the object you want to create.
      Parameters:
      type - the class of the object you want to create.
      Returns:
      the found or created object, or null if the object could not be created or it is not defined as a top level object.
      Throws:
      NoSuchFieldException - if class type doesn't contain a static ObjectCode field.
      IllegalAccessException - if ObjectCode field of class type is not public.
    • getRootObject

      public final DataObject getRootObject()
      Returns the root data object.

      The 'root' data object is a predefined extension of DataObject that stores all top level objects. Call it when you need to search or manipulate the system object tree.

      Returns:
      the system root data object.
    • onConfigChange

      protected void onConfigChange()
      Handles the event that the application's configuration file is modified and reloaded, through SpiderAdmin or by custom code.

      Override this method if your application flow depends on configuration parameters that might be changed.

    • startLogging

      protected void startLogging​(boolean append)
      Starts application logging.

      This method is called during the initialization phase of the application. You can override it to implement custom logging initialization in addition to the default one. Don't forget to call the super instance of this method.

      By default, log files are appended to. If for any reason you want to rewrite the files, you can call the super instance of this method with append parameter set to false.

      Parameters:
      append - true if content of new logs shall be appended to the files containing old logs, otherwise the files will be rewritten.
    • reloadConfig

      public OpResults reloadConfig()
      Reloads the application's configuration file.

      This method is called from SpiderAdmin after the application's configuration file is modified in order to apply modifications, i.e. cause configuration-dependent code to be affected. You can override it if you implement custom configuration. Do not forget to call the super instance of this method and return the object returned by it.

      Returns:
      OpResults object (will be documented in a future release).
    • flushLogs

      public OpResults flushLogs()
      Flushes all open log files.

      This method is called from SpiderAdmin upon request of its user. You can override it if you implement custom logging and you want to flush your log files on that occasion. Do not forget to call the super instance of this method and return the object returned by it.

      Returns:
      OpResults object (will be documented in a future release).
    • runPeriodicalTasks

      protected void runPeriodicalTasks()
      Executes custom periodical tasks.

      This method is called once a minute from a dedicated thread. It does nothing by default, but you can override it to do anything that you want.

    • runDailyTask

      protected void runDailyTask()
      Executes the daily task.

      This method is called once a day at the time set by [start of day] property in the application's configuration file. By default it calls resetCounters() and reset(). You can override it to do something else or something more.

    • resetCounters

      public final void resetCounters()
      Resets communication monitoring counters.
    • sendNotificationMail

      public void sendNotificationMail​(String msg, String additionalInfo, ZDate eventTime, boolean alert)
      Sends a notification mail.

      The method sends a notification mail on behalf of the application. You can call this method from anywhere in your application. The method is also called internally by the Spiderwiz framework on events like disconnection and reconnection of communication sessions. You can configure the exact conditions to send a notification through the application's configuration file.

      If the application has access to a mail server and a mail system and mail connection properties are defined in the application's configuration file, the mail is sent to the address(es) specified in [mail to] property with CC to the address(es) specified in [cc to] property.

      A mail can be sent on behalf of the application even if it does not have mail access. To do so, include ObjectCodes.EventReport in the list of object codes returned by getProducedObjects(), then include ObjectCodes.EventReport in the list of object codes returned by getConsumedObjects() of any peer application that do have mail access. The application with the mail access will trap the notification and mail it to the addresses defined in its own configuration file on behalf of the application without mail access.

      Parameters:
      msg - the message to send. Will appear as the mail subject and as a title inside the mail body.
      additionalInfo - multi-line additional information. Separate lines by the newline character ('\n'). Can be null if not required.
      eventTime - time of the notified event if needed, null otherwise.
      alert - if true, the title in the mail body will appear in red, otherwise it will appear in green.
    • sendExceptionMail

      public void sendExceptionMail​(Throwable ex, String msg, String additionalInfo, boolean critical)
      Sends an alert mail on thrown exceptions.

      The method sends an exception alert mail on behalf of the application. You can call this method when you catch an exception in your application. The method is also called internally when exceptions are caught inside the Spiderwiz framework.

      There are two types of exceptions - critical and non-critical. Every call to this method for a critical exception will be handled and a mail message will be sent. Non-critical exceptions are handled only periodically, at the time interval defined by [exception alert rate] property in the configuration file.

      If the application has access to a mail server and a mail system and mail connection properties are defined in the application's configuration file, the mail is sent to the address(es) specified in [mail exception to] property with CC to the address(es) specified in [cc exception to] property.

      A mail can be sent on behalf of the application even if it does not have mail access. To do so, include ObjectCodes.EventReport in the list of object codes returned by getProducedObjects(), then include ObjectCodes.EventReport in the list of object codes returned by getConsumedObjects() of any peer application that do have mail access. The application with the mail access will trap the notification and mail it to the addresses defined in its own configuration file on behalf of the application without mail access.

      Parameters:
      ex - the caught exception object.
      msg - the message to send. Will appear as the mail subject and as a title inside the mail body.
      additionalInfo - multi-line additional information. Separate lines by the newline character ('\n'). Can be null if not needed.
      critical - true if the exception is critical.
    • onConnectFailed

      protected void onConnectFailed​(String remoteAddress, Exception e)
      Called when a communication session could not be established.

      When Spiderwiz framework fails to establish a connection it prints a log message. If you want to do anything more, override this method.

      Parameters:
      remoteAddress - the remote address that could not be reached.
      e - the exception that was thrown in the failed connection attempt if applicable, null otherwise.
    • onObjectReset

      protected boolean onObjectReset​(Resetter resetter)
      Called when a data object of a specific type needs a reset.

      Spiderwiz keeps the integrity of your data by sequencing the distributed data objects. When a receiver detects that an object has gone out of sequence, it issues an Object Reset request. Upon reception of this request for a specific object type, the producer of the lost objects should resend all the objects of that type. Normally this is done internally by the framework, but there are cases, for instance when a data object is defined disposable the application may need to do a reset from an external source (e.g. a database). To do that, override this method. In this case make sure to return true.

      Another use of this method is to modify the Resetter argument before it is used for automatic reset by the framework (see the class description for modifiable properties). In this case return false.

      Parameters:
      resetter - An object that contains information about the object type that needs a reset and provides a mechanism for streaming the reset data to its destination.
      Returns:
      true if this method handled the reset request, false if it is left to the framework to do automatic object reset.
    • onResetCompleted

      protected void onResetCompleted​(Resetter resetter)
      Called when a data object reset is completed.

      When you use a Resetter to reset a data object and you call Resetter.endOfData() when you are done, this method will be called when the resetter object is fully flushed for delivery. Override it if you want to do something in this case.

      Parameters:
      resetter - an object that contains information about the object type that needs a reset and provides a mechanism for streaming the recovered data to its destination.
    • createImportHandler

      protected ImportHandler createImportHandler()
      Creates an import/export data handler.

      Spiderwiz framework includes an import/export mechanism to interact with external data, implemented in ImportHandler class. If necessary, you can subclass it. If you do then you need to make sure that your subclass will be instantiated and used instead of the default one. This is done by overriding this method. If you do not override it, the default ImportHandler will be created.

      Returns:
      a new instance of ImportHandler or a subclass of it.
      See Also:
      ImportHandler
    • commandLineHook

      public void commandLineHook()
      Adds a hook for a graceful termination of a command line application.

      If you use Spiderwiz to build a command line Java application, you can call this method to add a hook for a graceful termination.The method will:

      Call this method after you call init(). Note that the method runs on its caller thread, so if you have other things to do after calling it, start a new thread and call the method from it.

    • getStatus

      protected String getStatus()
      Returns the application's status.

      Used by SpiderAdmin to show the status of the application. By default the method returns "OK". Override the method if you want it to return something else.

      Returns:
      string describing the application status.
    • getApplicationInfo

      public ApplicationInfo getApplicationInfo()
      Returns general information about the application.

      Used by SpiderAdmin. The method returns an object that contains:

      • Application name
      • Application version
      • Version of Spiderwiz framework library used to build the application
      • Application's IP address
      • Application's deploy time
      • Application's status
      • Application's root folder
      • Application's UUID.
      Returns:
      an object containing application information.
    • getPageInfo

      public PageInfo getPageInfo​(String userID)
      Returns the layout of the application's administration page.

      Used by SpiderAdmin. The method returns an object that specifies the elements displayed in the application's administration page. Override it to customize the administration page layout.

      You can customize a page by adding control buttons and tables to it. You can assign actions to buttons and fill tables with data by overriding customAdminService().

      Parameters:
      userID - If not null the page will display only nodes connecting with this user ID.
      Returns:
      an object containing page layout information.
    • getServerInfoTableStructure

      public PageInfo.TableInfo getServerInfoTableStructure()
      Returns the structure of the Server Information table displayed in the application's administration page.

      Used by SpiderAdmin. The method returns an object that specifies the structure of the Server Information table displayed in the application's administration page. Override it to customize the table layout.

      Returns:
      an object containing table structure information.
    • addServerInfoRowData

      protected void addServerInfoRowData​(TableData.RowData row)
      Requests data for the one-row Server Information table displayed in the application's administration page.

      Used by SpiderAdmin. The method fills data in the Server Information table displayed in the application's administration page. You can override it to customize the data, for instance if you want to delete or add columns. In this case you will also need to override getServerInfoTableStructure().

      Parameters:
      row - an object to fill in data for one row of an administration table.
    • getServerInfoTableData

      public TableData getServerInfoTableData()
      Returns data for the Server Information table displayed in the application's administration page.

      Used by SpiderAdmin. The method returns an object that contains the data to display in the Server Information table displayed in the application's administration page. Override it to customize the table data.

      Returns:
      an object containing table data.
    • getApplicationsTableStructure

      public PageInfo.TableInfo getApplicationsTableStructure​(String tableTitle, String tableService)
      Returns the structure of the Applications table displayed in the application's administration page.

      Used by SpiderAdmin. The method returns an object that specifies the structure of the Applications table (describing peer applications of the current application) displayed in the application's administration page. Override it to customize the table layout.

      Parameters:
      tableTitle - the shown title of the table. Can be customized.
      tableService - a tag that identifies the table. Shall not be touched.
      Returns:
      an object containing table structure information.
    • getConnectedNodesTableStructure

      public PageInfo.TableInfo getConnectedNodesTableStructure​(String tableTitle, String tableService)
      Returns the structure of the connected nodes tables displayed in the application's administration page.

      Used by SpiderAdmin. The method returns an object that specifies the structure of the tables that give information about connected nodes (Producers or Consumers) displayed in the application's administration page. Override it to customize the table layout.

      Parameters:
      tableTitle - the shown title of the table. Can be customized.
      tableService - a tag that identifies the table. Shall not be touched.
      Returns:
      an object containing table structure information.
    • getImportsTableStructure

      public PageInfo.TableInfo getImportsTableStructure​(String tableTitle, String tableService)
      Returns the structure of the Imports Channels table displayed in the application's administration page.

      Used by SpiderAdmin. The method returns an object that specifies the structure of the Imports Channels table displayed in the application's administration page. Override it to customize the table layout.

      Parameters:
      tableTitle - the shown title of the table. Can be customized.
      tableService - a tag that identifies the table. Shall not be touched.
      Returns:
      an object containing table structure information.
    • getApplicationsTableData

      public TableData getApplicationsTableData​(String userID)
      Returns data for the Applications table displayed in the application's administration page.

      Used by SpiderAdmin. The method returns an object that contains the data to display in the Applications table (describing peer applications of the current application) displayed in the application's administration page. Override it to customize the table data.

      Parameters:
      userID - if not null the query is only for nodes connecting with this user ID.
      Returns:
      an object containing table data.
    • getConnectedNodesData

      public TableData getConnectedNodesData​(boolean consumers, String userID)
      Returns data for the connected nodes tables displayed in the application's administration page.

      Used by SpiderAdmin. The method returns an object that contains the data to display in the tables that present information about connected nodes (Producers or Consumers) displayed in the application's administration page. Override it to customize the table data.

      Parameters:
      consumers - if true, the request is for consumers, otherwise it is for producers.
      userID - if not null the query is only for nodes connecting with this user ID.
      Returns:
      an object containing table data.
    • getImporNodesData

      public TableData getImporNodesData()
      Returns data for the Import Channels table displayed in the application's administration page.

      Used by SpiderAdmin. The method returns an object that contains the data to display in the Import Channels table displayed in the application's administration page. Override it to customize the table data.

      Returns:
      an object containing table data.
    • customAdminService

      public Object customAdminService​(String serviceTag, String userID)
      Does a custom administration action.

      The method is used by SpiderAdmin when the application's administration page is customized through getPageInfo(). Override this method to assign actions to buttons and fill custom tables with data.

      Parameters:
      serviceTag - the tag assigned to your custom element.
      userID - if not null the request pertains to this user ID.
      Returns:
      an object that shall be OpResults if the tag identifies a button or TableData if it identifies a table.