LasUsage

Overview

The Tideland Lightweight Application Server is a small framework for the implementation of business logic in loose coupled components and services. The broker is the lynchpin of the system, it controls the instantiation of the components and the priorized delivering of messages to the connected services.

Lookup, Configuration and Access

One image can run multiple brokers in parallel processes. A reference is stored in the process environment, the lookup searches the process tree up until no parent process is left. In this case a new unconfigured instance will be created and registered, future lookups in the same or in child processes will find this one. So a starting application has to lookup and configure the broker in its top level process.

env := CslRuntimeEnvironment lookup: #MyApplication.
broker := LasBroker lookup: env.
components := broker components.

components
    registerContextComponent: CarPoolAuthenticationComponent id: #authentication;
    registerContextComponent: LdapAuthenticationComponent id: #authentication client: #test;
    registerSharedComponent: CarPoolAuthorizationComponent id: #authorization;
    registerSharedComponent: SosDatabaseComponent id: #database;
    registerSharedComponent: ConfigurationComponent id: #configuration;
    registerContextComponent: CarPoolCarSearchComponent id: #carSearch;
    registerContextComponent: CarPoolCarReportComponent id: #carReport initBlock: [:cmp :ctx | ...].

In this example a set of components get registered at the broker. The shared components will be instantiated once per broker and shared between all accessing contexts, the context components will be instantiated once per context. So they may have a local state while the first once should only have states like a reference to the database or a cache. If the registration is done with a client id as parameter this component will only be used for a context with the same client id. Optional initialization blocks will be executed once when a component gets instantiated.

To access the broker in the same or a child process you need the context class.

"Create a default context."

env := CslRuntimeEnvironment lookup: #MyApplication.
context := LasContext new: env.

"Create a context for client 'test'."

context := LasContext new: env clientId: #test.

You're now able to retrieve the configured components from the context and send messages to services.

Components

Component Types

The LAS knows two types of components: context and shared components.

Shared Component

This component type is only instantiated once per broker. It is intended for central tasks like the access to a database or a cache. So a shared component contains no context specific information.

Context Component

A context component is instantiated once per context. It is allowed to be stateful, e.g. storing the current user in the authentication component.

Component Instantiation

To retrieve a component from the context the message component: has to be used. If this component is allready instantiated in the context or the broker - for shared components - it will be returned. Otherwise it will be instantiated and initialized then.

  1. If the component responds to context: the current context will be set. this mechanism should only be used in context components.

  2. All setters inside the protocol las are iterated. For each one the equal named component (without the colons) will be retrieved from the context and set.

  3. If an init block is configured it will be called last.

So in case of the authentication component for a login the sequence would be

authentication := context component: #authentication.

authentication login: aUsername password: aPassword.

authentication isLoggedIn ifTrue: [...].

If the authentication component is a shared component then the user status has to be stored otherwise. Otherwise the state could change between the two messages.

userState := authentication login: aUsername password: aPassword.

userState isLoggedIn ifTrue: [...].

Services

Another usage scenario is performing asynchronous actions. To do this you need to define a connector with a filter and the action and connect it with the broker.

env := CslRuntimeEnvironment lookup: #MyApplication.
broker := LasBroker lookup: env.
connector := LasConnector on: broker.

connector filter: [:msg | msg header priority > 70].
connector action: [:msg | Transcript show: 'Message "' , msg , '" has a high priority!'].

Now messages can be created in different ways.

"Empty message, everythng has to be set later."

msg := LasMessage new.

"Message based on the content."

msg := LasMessage content: aNewCustomer.

"Message based on the type."

msg := LasMessage messageType: #logging.

"Message based on verb, noun, and content."

msg := LasMessage verb: #add noun: #customer content: aCustomer.

A message now can be sent via

answerId := context sendMessage: msg.

Based on the filter settings the message will now be handled asynchronously by no, one or several connectors. The message priority is in the same range that is allowed for Smalltalk processes. Forked processes up to a limited number will do the handling ordered by and with this priority.

Do to the context inside each message it is possible to return a number of answers to this context or call components inside this context. Those can be retrieved later with

answers := context answers: answerId.

For a simple service implementation own services can be derived from LasBaseService. It has to overwrite the method nouns and to implement own message handling methods with a defined naming.

nouns
    "Define the nouns this service is interested in. Those messages will be filtered."

    ^#(#customer #customers)

addCustomer: aMessage
    "Add a customer."

    ...

findCustomer: aMessage
    "Find a customer."

    ...

queryCustomers: aMessage
    "Query for customers."

   ...

Additionally the method defaultProcessMessage: aMessage can be overloaded. If this service is now connected with

"Connect a service to the broker."

env := CslRuntimeEnvironment lookup: #MyApplication.
broker := LasBroker lookup: env.
connector := LasConnector on: broker.

connector service: MyCustomerService new.

it will handle message like

msg := LasMessage verb: #add noun: #customer content: aCustomer.

msg := LasMessage verb: #find noun: #customer content: 4711.

msg := LasMessage verb: #query noun: #customers content: aQuery.

CategoryTidelandLas

last edited 2007-07-30 07:58:47 by FrankMueller