Core

This page introduces the WOSH Core library, micro-kernel and core-modules of the middleware.

Table of Contents:


Overview

A generic WOSH system is made of:

As the name says, WOSH Core library is the lowest layer of the middleware. It includes:

WOSH.Architecture.WoshKernel.png

WOSH Core Architecture

The WOSH Core layer is shared by (included in) all WOSH projects, all source code is fully multi-platform and implemented from scratch (no external libraries).

Note:
WOSH Core is still based on QT library.

Often, base classes are extended within the WOSH Framework, a good example is Networking: wosh::NetworkProtocol and wosh::NetworkChannel are defined (abstract) within the core, but they are implemented for the UDP and TCP protocols in the wosh::network namespace (WOSH Network Framework), It may seems more complex than required, but keep in mind that WOSH is a modular system, designed for embedded devices too: that's why requirements of the core itself are the fewest possible, moreover there could be many different implementation of the same class (based on different libraries).

QT project file of WOSH Core is /src/core/core.pro.


Bundles

[..]

A generic service of WOSH is called Bundle and implements wosh::Bundle interface. Since most implementation would share a lot of common code, an helper class wosh::BundleGeneric is provided for convenience.

wosh::BundleManager core module manages bundles, their (un)loading and life cycle.

See also:
wosh::BundleManager
wosh::Bundle
wosh::BundleGeneric

Busses

wosh::BusManager service manages wosh:Bus instances, their life cycle and events.

WOSH is a Message-Oriented Middleware.

Bundles interacts each other sending and evaluating wosh::Message objects. wosh::Message is a generic container, it holds:

Message.png

wosh::Message UML diagram

The source code required to send a request message is:

Message* message = new Message( new Request(_METHOD_ListProperties) );
message->setSource(this);
message->getDestination().fromString( "wosh1:Bundles/GTalkBot" );
BusCore.postMessage(message);

There are more Busses on a generic WoshKernel, some of them are always available because are allocated by the kernel or its modules:

wosh::BusManager provides some basic message routing functionalities.

wosh::Message pushing is asynchronous and it can't guarantee that Messages are received. Messages are notified to the (listening) bundles by the Bus.

wosh::Bus is the interface of a generic Messages Dispatcher. Built-in implementation are:

wosh::BusConnector is an helper object which simplifies the implementation, the code required to register to the Core bus is:

BusCore.setMessageHandler(this);
WRESULT bus_connected = BusCore.connect( _Bus_Core );

The object (*this) implements the wosh::IBusListener interface (for receiving messages):

void BundleGeneric::busMessage( const Message& message, Bus* source ) {
    if ( message.isEmpty() ) return;
    if ( !MessageFilter::isMessageTarget(message, this) )
        return;
    if ( !message.getContent()->isRequest() )
        return;
    Message* reply = MPC_busMessageRequest( message, this->Methods, this->Log );
    if ( reply == NULL )
        return;
    BusCore.postMessage(reply);
 }

Few notes:

See also:
wosh::BusManager
wosh::Bus
wosh::BusRing
wosh::BusMT

Devices

wosh::DeviceManager is a distributed component hosting information about devices available to the WOSH system. Information are hold by wosh::Device object.

[..]

See also:
wosh::DeviceManager
wosh::Device

FileSystem

WOSH FileSystem core-module, together with a set of helper classes, provides a standard high-level access to the real file-system.

Most important features are:

Because of WOSH is a multiplatform system and operative systems handle file-system in different ways (with different separators), WOSH defines its own path separator (POSIX standard was chosen: /).

Moreover, since WOSH Hosts may have (want) a standard access to shared resources (for example: a SAMBA share), FileSystem component supports the aliases architecture, integrated within path-resolution.

Aliases are usually defined locally in the main configuration files and they enable location transparency when accessing files. Let's make a real-world example:

Assume two or more networked PC running some kind of WOSH application, some of these WOSH hosts run a bundle of type PlayerAudio. In short, each host is able to play music from/within WOSH system. Assume also that we have a shared file-system hosting the music archive (such as a shared SAMBA partition) and it is reachable by all hosts.

So, the local path to the archive will be different on each host, on Windows it may look like "T:\" but on Linux it will point to "/shared/music". Here aliases comes to simplify and standardize the resource address.

Once configured, the alias "$MUSIC" will point to the right path on each host, and we may enqueue "$MUSIC/MyArtist/MySong.mp3" without even knowing the OS and path of the target host.

Some global aliases are defined by WOSH itself on initialization:

FilePath class is very helpful when dealing with WOSH vs. local paths:

WRESULT load_file( const std::string& wosh_path )
    FilePath xmlFile;
    if ( !xmlFile.set( Properties.getValueOf(wosh_path).toString() ) ) {
        SystemInfo::raise(this, &Log, SystemInfo::TYPE_ERROR, SystemInfo::MODE_PERMANENT, SystemInfo::PRIORITY_CRITICAL,
                            "Failed loading archive (file)",
                            "load_file() FAILED#1 Invalid Archive File [%s]", xmlFile.getPath().c_str() );
        return WRET_ERR_PARAM;
     }
    if ( !xmlFile.exists() ) {
        SystemInfo::raise(this, &Log, SystemInfo::TYPE_ERROR, SystemInfo::MODE_PERMANENT, SystemInfo::PRIORITY_CRITICAL,
                            "Failed loading archive (file)",
                            "load_file() FAILED#1 Archive File doesn't exists %s [%s]!", xmlFile.getPath().c_str(), xmlFile.getPathLocal().c_str() );
        return WRET_ERR_PARAM;
     }
    // [..]
    return WRET_OK;
 }
See also:
wosh::FileSystem
wosh::FilePath, wosh::ResourcePath
wosh::FileInfo, wosh::DriveInfo

Network

WOSH provides an high abstraction layer of networking communication, also called network overlay.

Within a single WOSH host, services exchange information through messages (wosh::Message) over busses (wosh::Bus), as you have seen in Busses.

Connecting multiple WOSH hosts means, basically, connected their busses, manage routing and connection resilience. The wosh::NetworkManager core-module accomplishes these tasks.

Todo:
topics [..]
See also:
wosh::NetworkManager
wosh::NetworkProtocol
wosh::NetworkChannel

Object Factory

Note:
ObjectFactory and the current Object-Allocation model has been introduced in WOSH 0.8.013 [icarus]

WOSH Framework is deeply based on polymorphism (inheritance and multiple-inheritance, sometimes even diamond inheritance) and composition of classes. Moreover, services are usually recognized by interfaces (abstract classes) they implement.

The current Interface/Broker model is still weak (not strongly typed), but implementations are quite standardized and already explicitly implement the reference interface (abstract class). For example, wosh::bundles::ModemDslBundle implements wosh::interfaces::network::ModemDsl.

There are some more points which make things complex:

Before explaning how the WOSH model works, here are the results:

Here is a sample of a rendered tree from WOSH WorkShop front-end:

WOSH.GUI.FormObjectFactory.2a.png

wosh::gui::FormObjectFactory::Tab 2a

As you may have seen in the screenshot, the parent is not necessarly the parent node. This is part of the multiple-inheritance support: each type has only one defined parent (or none), which usually is the most significative interface, but may have an unlimited number of other (direct) parent and super-parent (nested).

Let's start from the beginning: registration and maintenance of types.

wosh::ObjectFactory is a skeleton for accessing to available (registered) Allocators and providing standard function (as other wosh::WoshModule). Basically the component forwards (iterative) common calls (such as create-new, search, ..) to registered allocators.

wosh::ObjectAllocator is an particular Object capable of (de)allocating a set of object-types. Once an allocator is unregistered, its services aren't available anymore, this is useful when dealing with dynamic libraries/registration.

Note:
support of dynamic plugin is planned but not integrated yet.
Todo:
explain Meyer singleton and initialization order (fiasco)
WOSH_REGISTER_INTERFACE(wosh::network::SocketTcp, wosh::ClassNull, 0.8677, network_SocketTcp )

Someway, in another source files, dynamically executed before or after previous snipped, the implementation is defined:

WOSH_REGISTER(wosh::network::qt::SocketTcpQt, wosh::network::SocketTcp, 0.8677, core_SocketTcpQt )

Dynamic allocation-by-interface Snippet (from wosh::network::NetworkChannelTcp::initializingThread()):

this->tcpSocket = ObjectFactory::createTypeOf<wosh::network::SocketTcp>();
if ( this->tcpSocket == NULL ) {
    Log(LOG_CRITICAL, ":initializingThread() FAILED Creating SocketTcp!" );
    return false;
 }
this->tcpSocket->setListener(this);

It's so simple as amazing, until run-time we have no idea if there is really an implementation of SocketTcp neither which it will be created. Indeed this is a design choice and the template function is provided for convenience.

It is possible to define the class-type using:

IReflection* new_obj = ObjectFactory::createTypeOf( "wosh::network::Qt::SocketTcpQt" );
wosh::network::Qt::SocketTcpQt* new_socket = dynamic_cast<wosh::network::Qt::SocketTcpQt>(new_obj);
new_socket->setListener(this);

Object should be destroyed as follow:

WRESULT destroyed = ObjectFactory::destroy(this->tcpSocket);
Todo:
[..]
See also:
wosh::ObjectFactory
wosh::ObjectAllocator

Persistence

The basic task of persistency is simple. The application or some important data of the application is represented as a set of objects with some references to each other. Persistency means, that these objects can be saved to permanent storage i.e. a file and later the program will be able to restore the original state from that file. More precisely an application or data is persistent, if its lifetime is longer than the running time of the application.

[..]

See also:
wosh::PersistenceManager

Security

Warning:
WOSH Security architecture is still under planning and may be revisited.

Brief of WOSH Security architecture at 0.8.588

See also:
wosh::SecurityManager
wosh::SecurityToken

Sessions

WOSH Sessions allow users to interact with WOSH system itself, like a POSIX shell.

wosh::Session is the (abstract) handler of a communication session between a valid (logged, authorized) user and the WOSH system.

Sessions are managed by wosh::SessionManager core-module.

Session implementation may be registered by a system component or the application itself, or created inline by the system (used for instant messaging), its key roles are:

There are few Session implementations included in the page_framework_communication:

See also:
wosh::SessionManager
wosh::Session
wosh::communication

Logging

Since WOSH is a complex software, made of thousand of components, a custom logging system has been integrated. It is based on following concepts and components:

The WOSH Logging architecture is totally reentrant and thread-safe.

Here is a snippet of using WOSH logging system:

    LogContext Log;
    Log.setContext( getName() );
    Log.setIndent( 2 );
    Log.setLevel( LOG_INFO );

    Log(LOG_DEBUG, " Initializing Properties.." );
    if ( false ) {
        Log(LOG_WARNING, ":Object() Missing Properties for '%s'", getName().c_str() );
     }

Basically, LogContext class accomplish following aspects:

LogContext is mapped to a valid (global) LogHandler instance, on initialization it binds by default to wosh::StaticLogHandler singleton (meyer pattern).

A generic log entry has following fields:

Log entries are usually formatted as: "LEVEL TIMESTAMP CONTEXT(+indentation) CONTENT"

SystemLogger core-module manages (live instances of) contexts and handlers, it also has the ability to change handlers and their settings at run-time.

alex@woshshop# cd Logger
alex@woshshop:Logger# list
  Response of 'list' : OK [wosh::Table]
Log Contexts
                                  Name             Type LogLevel[Str]   HandlerID Indent
----------------------------------------------------------------------------------------
                       StaticAllocator wosh::LogContext          INFO 1965321638      1
                              Settings wosh::LogContext          INFO 1965321638      2
                            WoshKernel wosh::LogContext       VERBOSE 1965321638      1
[..]

alex@woshshop:Logger# list_handlers
  Response of 'list_handlers' : OK [wosh::Table]
Log Handlers
          ID                          Type isOpen                            Protocol
-------------------------------------------------------------------------------------
  1965321638 wosh::StaticLogHandler   true           multiplex[1]://702051004;
   702051004     wosh::LogHandlerPlainText   true file://../var/log/wosh.workshop.log

See also:
wosh::SystemLogger
wosh::LogContext, wosh::LogHandler

Monitoring

wosh::SystemMonitor is a diagnostic core module designed to log wosh::SystemInfo (raised by generic components), gather local system-information (PID, memory, ..), forward access to wosh::SystemProfiler data (when profiling is enabled)

See also:
WOSH Profiling
wosh::SystemMonitor
wosh::SystemInfo
wosh::SystemProfiler

Objects might easily raise a wosh::SystemInfo as following snippet:

    SystemInfo::raise(this, &Log, SystemInfo::TYPE_ERROR, SystemInfo::MODE_PERMANENT, SystemInfo::PRIORITY_WARNING,
                        "Unable to stop Process/Operation",
                        "stopThreads() : Can't stop thread#%ld [%s]", currThread->getThreadID(), currThread->getThreadName().c_str() );
Warning:
SystemInfo::raise and logging-interleaving is going to change in WOSH 0.8.5xx in order to simplify call but provide more information and relations with the state of caller. Potentially, a custom SystemInfo could force the system to destroy and restore the failed component.

Threading

wosh::ThreadManager is a core-module provided for debugging and monitoring internal threads of the application.

The wosh::Thread class provides an high-level abstraction layer for implementing threads, moreover it raises events and cooperates transparently with ThreadManager.

wosh::Thread base class transparently (un)registers itself and notifies state-changes.

Current implementation is based (only) on QT4 classes (QThread). An implementation on pthreads is under planning.

The wosh::Thread implementation provides usual start/stop/quit/wait calls, synchronous and asynchronous, getters for current thread-state. Each thread is associated with an (internal) unique identifier (numeric) and an optional (string) name.

See also:
wosh::Thread for sample implementation of a generic thread.

Thread Manager provides also a monitoring utility which periodically evaluates if a thread has been crashed/dead-locked (not-responding). wosh::ThreadMonitor is enabled by default and required in order to detect crashed threads. Termination detection is probabilistic and depend on implementation (some components may not support this feature), it is based on iterative timestamping and timeout evaluation, the crash probability is estimated agaist last alive-timestamp and projected timeout (custom value for each thread).

High-rate tasks may use wosh::ThreadPool to distribute work in a predefined set of threads, eventually linked to local methods. wosh::BusMT and wosh::bundles::TaskManagerBundle are based on that component.

See also:
wosh::ThreadManager
wosh::Thread

Users

wosh::UserManager collects users (object) instances (wosh::User) and offers methods for accessing and updating information (properties) of Users.

Users are loaded from a WOSH compatible database (see Persistence).

See also:
wosh::UserManager
wosh::User

Kernel

wosh::WoshKernel allocates and destroys the core modules.

wosh::WoshKernel is a singleton component, required by any Applications and should be allocated within main entry-point (see woshsrv's source code).

int main(int argc, char **argv)
 {
    WoshSettings* woshSettings = new WoshSettings();
    woshSettings->loadFromArgs(argc, argv);
    std::string woshName = woshSettings->getValueOf( "WoshKernel", "Name", "" ).toString();

    WoshKernel core( woshName, woshSettings );
    core.init();
    core.start();
    core.enterLoop();
    return 0;
 }
See also:
Core-Modules, wosh::WoshModule

Generated on Sat Feb 26 2011 11:28:29 for WOSH system 0.8.888 [phoenix] by Alessandro Polo, using DoxyGen 1.7.2 hosted by WOSH Framework