2012. november 8., csütörtök

Esti mese: Viktor és a léghajó

Ennek úgy tűnik sosem lesz vége... Újra karattyolok Antalffy Tibor blogján.


2012.november.7th. at 20:07

... amit Orbán tesz, az ő szempontjából szerintem teljesen racionális, csak addig tűnik bénázásnak, amíg nem akarjuk elfogadni, hogy egyszerűen a saját kapunkra támad. A hülye ötletek tárháza a nekünk szóló “pávatánc”, rágni való gumicsont – a lényeg viszont az, hogy ne maradjon egyéni mozgástered, anyagi függetlenséged, szorulj rá a nemzeti tőgyre. És ne is reméld, hogy lehet máshogy is, mert a “hazán kívül” csak a “gonoszok” vannak.


2012.november.8th. at 04:14

60, Ábel: Én látok bizonyos lépéseket, amik éppen abban az irányba hatnak, hogy minél kevésbé szoruljanak rá az egyes alrendszerek az állami tőgyre, ami nemsokára úgyis teljesen elapad/levágják stb.

Pl. mindenhol szabad már állatot tartani. Vagy az, hogy fokozatosan kivonják az állami pénzt a felsőoktatásból, egészségügyből: ettől ezek részben sorvadnak, de részben meg fogják találni azokat a forrásokat, amikből mégis fennmaradhatnak. Persze nem mindenki számára, csak annak, aki meg tudja fizetni. Ez a társadalmi mobilitás vége lesz, de a geddon után úgysincs más.

Ne haragudj, ez ostobaság. Elég közelről látom, ahogy a szó szoros értelmében kivéreztetik a magyar civil társadalmat, például a környezetvédelmi szervezeteket, amelyek a közfelfogással ellentétben NEM a szemétszedésről meg az atomos láncolgatásról szólnak, hanem a fenntartható élet-minták feltárásáról és népszerűsítéséről (lásd itt például Géza tudását). Most már egyre inkább múlt időben.
A társadalmi rendszerek fenntartása NEM “rentábilis”, ezek nem teremtenek pénzre váltható értéket, nincs “nettó bevétel”; elvileg a gazdaság termelő részének kellene finanszíroznia (erről szólnak az adók). Ha ez nem történik meg, akkor a kiváltságos kevesek számára marad elérhető, a “többiek” mennek a levesbe, ami NEM a megoldás, hanem a totális összeomlás receptje, lásd Görögországot (de ha jobban figyelsz, az egész “fejlett nyugatot” élen Amerikával) a lejtőn lefelé – és Argentínát, ahogy jóvátehetetlen következmények mellett kifelé próbál araszolni. Engedelmeddel Tibor bá, egy régi(!!!) írásom: újsütetű messiásunkat ekéztem ezzel áprilisban.
59, Tibor bá: Az egészet megette a fene, de miért kell siettetni? legalább én szeretnék “békebeli” módon elhunyni.
De nem ezért firkálok itt megint, hanem azért, mert megint egy ide szánt szösszenettel ébredtem (fél négykor, rohadt dolog ez a prófétaság). Figyelj csak:

Viktorunk olyan, mint a süllyedő léghajó kapitánya, aki kidobja az égőt (mert veszélyes), aztán a gázpalackokat (mert égő nélkül minek), lebontja a kosár oldalát és a köteleket nyiszálgatja. Minden ilyen lépés után megtapsoltatja magát, hogy na, megint emelkedünk, akárki láthatja! És miért? Mert a ballaszt homokból szép várat épít Kennek és Barbie-nak (a “benne hívő igaz magyaroknak”), és ahhoz semmiképpen nem akar hozzányúlni.

Ezzel az a bajom, Tibor bá, hogy például ebből lehet plakátot nyomni, meg pólóra felrajzolni, meg hőbörögni – de a léghajó felemelése, amelyért való erőfeszítés az EGYETLEN erkölcsileg, emberileg elfogadható megoldás (azért, hogy nem csak TE, hanem mindannyian tisztességben addig élhessünk, amíg adatik, és békében nyugodjunk el, amikor eljön az ideje) nem ezen múlik.

—

Ahogy egyébként az “apostoli magyar királyságon”, okoskodáson vagy a lezuhanásra való felkészülésen sem. Azt a vitát meg nem nyitom újra, hogy aki MA, a kényelmes székecskéjéből és életkéjéből a “geddon után” szöveggel jön, az az én szótáramban nem felel meg az “ember” fogalom definíciójának. Mindegy, ezzel ébredtem, leírtam, szép napot. Dolgozni is kéne még, mielőtt munkába mennék.


2012.november.8th. at 05:05

Ó basszus… hát most kellett leessen a lényeg! Tibor bá! Orbán Viktor TE VAGY!

Pontosan ugyanazt a forgatókönyvet látja, mint te, ugyanazt a logikát követi – csak neki hatalma is van a túlélésre érdemes tíz százalék kiválasztására és támogatására “a többi” rovására (szerk: és ő az, aki a tanácsomnak megfelelően szektát csinál belőlük). De milyen rohadt dolog már ezt a turulos csónakot kívülről nézni…

Bocs… :-D

2012. november 7., szerda

Entities 2

References

The fundamental difference of Dust is that it considers the software (all of them without exceptions) a state machine. The software is built up from components having many attributes and connections to each other, but both the attributes and the connections are managed and kept inside the framework runtime environment, can be accessed and managed by framework API calls. The software code on the other hand is responsible only for handling events, and not for representing the system state. That is: no "main" function, no waiting cycles and polling, and no final and static variables, local buffers for storing system state information.

Whenever a code (an internal event handler of a component instance) wants to access another component, it can do so only through dust API calls, and only by a component (Aspect) reference that it has received from the incoming message, its own existing component links or by searching for entities using API calls. The code has a very short life: runs only to respond a message (and not to represent a "listening state" for example), and has no need to "remember" any component or state (except for storing such information in its own or other components' attributes).

This means that the Dust runtime is free to handle the actual entity instances behind the API wall as it wants. It is totally irrelevant if the instance is purged from memory and reloaded, replaced with another instance ("dll hell"), exists or temporarily moved to another computer - as long as its attributes are reachable and messages can be sent to it using their references.

2012. november 5., hétfő

Entities 1

Entity versus Aspect

Separation of these terms is fundamental in Dust. The Entity represents the "existence", be it a message, a software component, a real life object or person. The Entity has a life cycle independent from the computer environment, and its computer representation must be synchronized to reflect those changes - this is why we have "information systems". Behind all operations Dust manages entity instances in the background; all information packages come and go in Dust in Entity instances.

Aspects are "objects" of declared and managed types having attributes and implementing business logic (that is: processing and responding to incoming messages). An Entity instance has a collection of Aspects, which collection may change along the life of the Entity - so the Entity itself has a history of changing Aspects, while the Aspects have history of changing Variants, receiving and sending messages.

In any business logic (software code) we can only see Aspects. We use and communicate with these feature collections, not the Entities themselves. Every Aspect instance, where my business logic is integrated, have the list of required service components, with which I have to communicate to do my job. These links are defined in my type, declared when the application configuration is created (deployed to the actual running environment), and resolved when my entity is loaded. In fact, most business logic does not have to get and store entities dynamically, variable content come with the messages that it has to process.

Knowing this, I assume that the business logic code should never access entities, nor aspects directly, through a memory reference or object instance. The Dust kernel API therefore can totally separate the "user" business logic from internal memory and data management, and this is a fundamental step towards security and reliability.

On the other hand, there are special components that have to see through this layer: the generic services like expressions; automatic GUIs that are generated to an Entity by listing its Aspects; or serialization. The idea: i should create Entity, Aspect, Field aspect instances! The component can request them from an incoming Entity instance, and through them it can manage those generic operations. With this trick, there is no programmatic or API difference between kernel and user level code, no new "protected" kernel functions. Of course, the operations must be protected, but again with the same tools as all other Dust security features will be implemented, with the same declaration features.

2012. november 3., szombat

Working with data 3

Collections again

It is very hard to get rid of old habits and choose a more complex-looking solution (which is complex only until we peek under the hood of the programming language where the problems are hidden).

I thought (and programmed in this way many times) that collections are generic part of data management. Again: they are not. Collections are aspects themselves, they either are part of the owner entity (like: subpanels of a window, scheduled commands of the scheduler, etc.) or referred internal entity members. Yes, the last time I have said that I did not need a collection directly, but only the iteration/search function - but forgot to mention the term "temporary". It is true that I don't need temporary collections, but the object themselves do contain many collections. If they are hidden under the "variant" layer, I have returned to the same problem of temporary collections, but under the hood with expressions for example.

So: Variants do not have multi-value content. If there is a need of it, it is a reference to a Collection aspect or entity. When expression evaluation encounters such a reference, that is again an accumulate / broadcast / search action (and reintroduce the parallel execution on this very low level).

Serialization

When different nodes communicate, they need to serialize their content. This component is responsible for working with references (independent of the actual implementation or the syntax of the stream). The generic solution is that each serialization action contains an ID map, where the unique id of the entity instance and a local, action-unique id is connected. The local id is used all the time, while the content is pushed into the stream only on the first call, when the item is registered into the map. In this way both sides have the simplest way to write and read the self referring structures properly.

Very important: the mapping must be set when starting the serialization: the referred entities may contain back references to the entity being serialized. They must receive the local id only, not start a recursive serialization process. On the other hand: anytime a local id based reference is resolved, the instance itself should be considered "final", but may be incomplete, and its content should not be used at this time. The read process should end with an independent initialization action after all referred components are read.

Content in serialization

From the content point of view, we have static and dynamic serialization.

Static is when I want to store and "remember" something as it is, like a configuration file: I want to keep some settings... NO! The config files are actually the primary source of the stored instances! Hmm... This means that for persistent entities, I have to serialize the content only if that serialization is actually the primary storage for those instances. All the others must only be stored by their unique identifiers (global type Id plus the identifier there). Of course, static serialization cannot contain temporal instances? NO: in some cases, like logging, anything, including temporal instances, must be stored persistently.

Dynamic serialization occurs when I send some content to another active node, which can ask back for additional information as well. In this case, the content of the stream should be optimized by the number of other request that the target has to make when processing the stream content. Some of the referred entities it may already have; others it can miss and ask back for. To cut it short: the sender may add the content of any entity instances to a dynamic serialization, even though the target is not the primary source of that information. This happens if the aim of the communication is in fact to get that instance (like requesting a Person record from a node that owns them), or that they are required to understand the response (sending Address, or Medical records as well with the Person).

It is possible that the sender keeps a sort of log about which objects is had sent to the requester, because it is responsible for keeping them in sync with the actual state, or even add event communication to them (later, this is screen sharing and active teamwork), or at least to optimize the serialization content: send only if the information is not available on the requester side. Of course, this is just an optimization: the requester is allowed to reload all content again (the client may be restarted or lose any content independently from what the server knows about it).

Format and type negotiation

When thinking about connecting to other nodes, we have to keep in mind that the endpoints may have different feature set. The most important is when the client is limited, like it has static type management, so it is simply unable to load a new type to understand the content of the serialization stream.

Level zero is to be able to build a stream connection and be able to transfer bytes through that line reliably. This is a lower level requirement that has to be solved with implementing the proper connector components; as long as I work with Java or other higher level languages, this should be a no issue. However, it also means that I must pack the stream operations into units as well, otherwise I might surprise myself when moving to a more limited environment.

The first level is that both ends must be able to parse and write the stream, that is: be able to handle the actual syntax. This means having Serializer component implementation, and the language elements for that syntax. This is a reference to an existing declarative information package, the EBNF-like declaration of the JSON language, which is actually used to parse and generate JSON streams (and in the hand of the Serializer, a valid JSON serialization) works just like the type declaration themselves. They are persistent entity instances, can be referred to, etc.

So, the limited client has the JSON language definition compiled into its codebase, and the client introduction contains the reference to that instance along with the statement that it is a static client, and cannot handle additional stream formats. When a stream connection is made, this information is used, and the more dynamic node can adapt to this requirement, optionally download the required language definition.

The second level is the content type set. Again, a static client may have final set of types, perhaps encoded again. This is a more generic limitation affecting any environment that is unable to load codes and object dynamically. For example the GWT environment can adapt to additional stream syntax, because if it has the generic EBNF code set, a new syntax is just another structure made from them. However, the GUI declaration types are final, a "Table" type is mapped to one specific code; it is not able to understand new, derived Table types. On a really static client this is also not a question: it is not even able to download and integrate new Type definitions.

So, a limited client introduction can also contain that it has a final type set, and the identifiers of the accepted types. The dynamic sender must "downcast" its content to the required types, and skip aspects that are of types unknown to the client. Naturally, this may result errors because of the lack of required references - the sender must handle these situations. But at least, they are visible...

2012. október 26., péntek

Working with data 2

Some more meditation on working with data... not surprisingly, they are restrictions.

Floating point

Floating point values are nice, we have the normal mathematical operations with them and also tons of functions like trigonometry, root, etc. As I have just learned, some CPU families don't support floating point operations, and the math library provided with them actually emulates the functions with complex library calls. In a real time system this is not an advantage. Thinking on it further, even a current PC processor should not run floating point calculations because it has a way stronger neighbor there: the GPU...

So, floating point variables should not be considered "generic", but wrapped into a unit, and when deploying an application on a PC, we can consider that as a heterogeneous parallel processing environment, and let the GPU do the calculations. (I don't know how to do this yet, but I am sure that this would be a real advantage). Also some real time systems where floating point calculations are available but not hardware supported (therefore not recommended) can simply declare that they are not compatible with floating point using units.

Collections

Now, collections are wrapped into intelligent Variants that helps message communication, locking, etc., but there is one more thing. The collection should not be available directly, as an independent object or unit. In several years of programming I have found that I actually never use the collection as an object; I iterate the members (sometimes filtered) to collect some information or initiate actions on them. Therefore, I should support the real requirement: the basic functions: isEmpty, count, contains, insert, remove, clear, ... and the iteration itself, either by requiring callbacks with the items or broadcast the same message to them (or some of them based on a filter).

Without this temptation I will not waste memory on creating (sometimes huge) temporal collections just because I want to iterate the members. This also is a kind of "inversion of control": it is not me iterating a collection, but an iteration runs somewhere and I get a callback with each item. If the environment supports it, this can be a parallel operation either for fetching the data, broadcasting a message to them or calling me back with them.

Strings

Strings are basic language elements in most environments, but that is completely wrong. I have to write many string manipulation codes (like searching in them, building them, etc.), but if I look closer, I just repeat features that are available already: in regular expressions/parsers, template engines. Apart from this ad hoc transformation, I just take strings from one place and move them to another - even I take them from source code (or some language provided container like the Java properties file), and write it to the screen, to a log, database (or System.out...). I introduce problems like encoding, language dependency, different formatting standards, etc.

No. Strings (and its big brother, formatted documents) must have their own unit with proper (and black boxed) support for encoding, I/O, templating, etc. and the code must have only one way to deal with them: through their Units, as entity instances.

There is one exception: the Identifier, which is an array of plain ASCII (1 byte long) characters, used for identify components. They have only basic functions (equals, concatenation, find, ...) and all hardware environment can support them on hardware level. The Identifier gets a separate Unit apart from String, used by dust core as well.

Running environment capabilities

With a nice declarative framework one heavy-weight problem is when it hits the hardware and must run on it, and somehow meet the promise of being independent from it. Well, it does cause some problems, and it is again with data.

One is the actual coding. We either have a runtime environment, where the runtime declaration contains that "for Java language, the long is 64 bit". Or 128. It has native support. Or not. Depending on the actual hardware and the runtime version, and perhaps the runtime implementation: someone can make a Java runtime with different features: it actually runs Java code, but the code behaves differently. I don't say that this is an issue of a generic programmer - as long as (s)he is working in one environment and comfortably far from its limitations. But when thinking about designing and coding a Unit which is able to do its job in a Dust environment on practically any platform, this is a tough one.

When working with generic data, we must precisely declare the minimum storage requirement, and so the valid value range (of course by using the common sense terms for it, but perhaps going down to the good old assembly notations);and when generating or writing actual code, we must keep the names, but use the generic data types with proper (perhaps larger) capacity. We might also include range checks, and throw runtime exceptions on overusing the variable: that code works in the current environment, but it does not comply with the type declaration. Of course we can't check the temporal local variables in the running code that will fail on a more limited environment, but at least we can do the check when setting a Variant.

The problem arises again when we have to communicate with a running code, exchanging actual data. This happens on persistent data I/O and on sending messages to entities residing on a different node. The channel (either a shared memory area, network, serial, ...) must have portals on all sides, where the node capabilities are available (endianness, encoding support, etc). The negoriation must take place when configuring a static channel (at deployment time) or when building a dynamic channel (like accessing persistent instances on the specified server node). In dynamic case the node performance must also be considered, like a real time embedded node is not able to negotiate on the channel content, the stronger node must format its content as the weaker can handle it.

2012. október 25., csütörtök

Working with data

The keyword here is reusability. I want an environment with totally independent parts, the same components for expression evaluation, interpreting an algorithm or accessing object member values from code; I want both string based access and compile time / run time support for type and nae checking. See how this goes.

Identifier

All starts with this. The Identifier has a short, limited ASCII "name", which must be unique in its context; and a reference to this context, which can either be a type declaration or an actual context (like a code block for interpreter environment).
The Identifier instance can be requested from its context by referring to its name, so it is unique, and adds the context information to the string name, therefore name collisions can be avoided.

Variant

The Variant is the core data element; a wrapper that holds the actual data value. It supports

  • generic values like boolean, integer, floating point values and fixed length ASCII strings;
  • single object reference to other objects;
  • collection of generic values / references. The collection has flags of sorted: if the elements have a fixed enumeration order, and single: one element can appear only once in the collection.
The Variant also has a VariantDeclaration reference, where all meta information of that variant instance is stored. This means that the Variant itself is repeated for all actual values "anywhere"; they can travel through expressions, contexts, etc., but they always hold a reference to a data structure that can define them and the actual value can be understood by them.

Another idea: it holds a reference to an DataObject in which it lives AND a definition index - because in many cases I must go "up" from the Variant to the owner DataObject. And the final blow: the Variant has direct access and modification interface (to be used in expressions and interpreters), but is must invoke the change listeners of the owner DataObject, if exists. This requires DataObject reference in the Variant.

VariantDeclaration

This contains the variant identifier and all other information (type, access, life cycle, etc.). The declaration may come from a type or direct request in an interpreter. The important part is that the declaration is generally repeated for several Variant instances, so it is lifted from them.

The life cycle information (like "already set" or "final") may belong to an object instance - this enforces that the Variant should refer to the DataObject with a declaration index and not the declaration directly.

DataObject

The DataObject contains an array of VariantDeclarations and an array of Variants; it acts as an Aspect instance inside an Entity, but also the context for a running system, or the code block stack in an interpreted algorithm.

To mix flexibility with memory optimization, the most used DataObjects (Aspects) start with their declaration array initialized with the array from their type, which is immutable shared array instance, and sufficient for most cases. However, this instance may be referred from other aspects, resulting a reverse reference to the referring aspects of alien VariantDeclaration. When this thing happens, the array is copied to a mutable declaration array, and the new VariantDeclaration is added to this DataObject together with the new Variant. 

The same applies to the generic DataObjects acting as context: they have no initial declaration array, but extended on each variant declaration request. The only difference: the declaration objects are themselves can be local strings, in this case they must be unique in the actual context. However, types may contain "shared" member declaration, which means they are not contained by the Aspect instance but the identified Context (this feature implements the "static member" feature of the programming language, and extends it by enabling different Context levels like runtime, session, user, ...)

Field

Field is used when we access the Variant from the DataObject; to do so we need the object itself, and an Identifier - which is not just a name, but a context as well. It is also important that the Field itself is more locked to the Identifier than to the object: it is fine to access the same Variant in multiple objects through the same Field instance, but it is not good to switch a Field to access another member Variant of the same object. Consequentially, the Identifier is final, while the object is mutable - although you can get a Field directly from an object by providing the requested identifier, but the field can be reused for other objects that have the same member.

The Field inside is responsible for removing the identifier based string access. It has an object reference, and a VariantDeclaration index inside. When (and only when) you call setObject with a new reference, the identifier is searched in the declaration array of that object, and the index is stored. Whenever you access the content, it is just an indexed access of the variant array of the object behind the field.

Fields are mostly used in declarative "toolkit" components, where the actual context "knows" the required type, the field is identified by the declaration name within the type, and you can manipulate the content through the Field instances. Most of such environments work with multiple object instances of the same type (like a GUI panel, a string template, a table, etc.) for which the Field's final lock to a specific declaration is also a good feature.

FieldSet

A helper component for dynamic access environments: you provide a type and an array of strings, they are internally transferred to an array of identifiers and Field instances, and so you have an indexed access to the values, where the index is in sync with the index of the field name in the string array.

TypeWrapper

The heavy-weight wrapper for an aspect. This is a generated code from the type declaration in the target programming language. It contains a FieldSet by the type, and a reference to an actual Aspect instance, typed get/set functions with type casts by the variant names. The TypeWrapper actually looks like a "normal object" for the programmer. For each Unit declaration, the wrappers can be generated, and used by anyone who wants to use the objects from their native code. The important feature here is that the actual data binding between the wrapper and the data object instance is done runtime, by the declaration and identifiers, not any fompile time fixed tables. This really allows extending the types without breaking the caller code.

It also contains static accessor functions, which are translated to getting and casting the referred items from the declared context (like "Logger.getLog" returns the log object in the closest context: transaction, session, system). The wrapper also incorporates message sending, but this is another story. When working and writing code on this level, it should feel almost like coding without Dust in the background.

2012. október 23., kedd

Dynamic type management and the application

The fundamental structure of any application is the deployment configuration. A GUI panel that is used to communicate with the user; the runtime environment that transfers hardware events (mouse movement, keyboard keys, etc.) to GUI control actions, then data modification - they are just the same kind of "data" and attached business logic components and implementation as the "Person" record displayed on the screen.

So if the application is anything at all, it is a deployment configuration about what components should be initiated and how they should be wired together with message channels to provide the required functionality. How should this deployment look like? (Of course, the kernel part of this deployment should exist in the form of compiled source code to make the kernel work and be able to load the other components.)

Application types

From structural viewpoint, an application can be static, type dynamic and binary dynamic.
  • A static application is one that has all the types and binary codes available compilation time. This application will be able to deal with a fixed set of data and components - like most of current software do. 
  • A type dynamic application can deal with an open set of data, like a generic view that is able to load and display any document in a document management system, without knowing all the document types at compilation time. This can be achieved by a sort of configuration-based data management, and template engines. 
  • A binary dynamic application can integrate software components at run time that were not known at compilation time. This is a plugin based environment, a typical example is the Eclipse plugin framework.

As the other types are limited subsets of binary dynamic, I plan that one; the others are created by replacing dynamic service components with placeholders providing the configured set of data.

There are also types from memory management point of view (instance-based, pooled and free), but that is out of scope here.

Vendors

The fundamental question is: where the types (and the associated business logic) come from?
They come from the vendors. A vendor is a software designer or implementer organization, who analyzes different problems, offers data structures and attached business logic codes bundled into units. These units can be used as building blocks for providing a specific service to a user. Therefore, all deployment configuration starts with a vendor list. The list contains the unique vendor ID, to which later the units refer to; they provide those types and binaries that this application is built upon at compile time.

However, dynamic applications must extend the list of types or even get new unit binaries as they receive corresponding data items. So, exactly one vendor must be identified as vendor provider, and provide a way to access that vendor server, because it will be used to get more vendors (data can refer to vendors unknown to the application at deployment time), and get connection information to them (to reach them for type declarations and perhaps attached business logic binaries).

In this way, the application can start with a single root vendor (in a generic case, a public server of the creator of that software), with a limited set of units enough to boot, and perhaps to provide the basic functionality. The generic usage of any application is browsing and managing a data hierarchy (be it a word processor, a mailer, a company information system, etc.); the root vendor provides the additional components and the referred data, controls the access to the external links, etc.

A generic dust application refers to the public dust server which returns any registered vendor and allows applications to be built on various components created by them. The actual vendor may choose to allow the application link to dust directly, catching only local references; or act as relay to dust and other vendors to control external access from the application. It is important to know and handle the security risk of getting types and more importantly, binaries from external providers - on the other hand, knowing about and generalizing this access may lead to more stable environments.

Units

Units are the building blocks of any service, the smallest coherent component with the type declarations and the attached business logic. The Vendor can work on multiple areas, which here are called Domain, and a domain can contain multiple units. The unit focuses on solving one and only one task, perhaps in collaboration with other units. If the unit has multiple areas of interest, it has to be split by them, because some other service will later require only some of the areas, not the whole package - so the unit is better when smaller. Featuritis is not welcome here.

Having small units, it is easy to extend the system with new functions. If we have a proper minimal raw byte stream implementation with all higher level features (parsing, event management, caching, etc.) implemented in other units, it is very easy to create new stream units that wrap different network protocols, serial I/O, ... audio, ... interfaces.

The application deployment contains a Unit dictionary with a unique identifier and the actual unit information: the Vendor.Domain.Unit access path, and the actual unit version. The rest of the application declaration can refer only to the types available in the dictionary, using their local IDs. In fact, all persistent data collection, from an application configuration to a relational database behind an information system must contain this unit dictionary to be usable. When creating such collections (a saved document, a configuration file), the unit dictionary must exist in it, that allows later reading and resolution of the content.

All Vendors must be able to resolve its own path+version information to a unit declaration containing the external unit references ("imports") and the type declarations, which must be complete, all references resolved either locally or through the import. Of course, the user of the unit must also resolve the referred units, but not limited to the list that the creator used (the unit requires "a binary stream" which is resolved to a console in one and to serial I/O in another case).

The Vendor may provide business logic to the Unit. For Java, this means Java classes that implement the message processing of an Aspect of the specified Type; compiled and packed into the unit jar for the required JRE version. Right now I will only support J2SE6, but for fun or when required, it can be done for other versions. Later on I should also turn to C or other runtime environments; and a fully declarative algorithmic approach. Not right now, and not for production use.

Types

Dust types are created to extract the design knowledge from a particular programming language to a higher declaration level. "Objects" in Dust are split to the hierarchy of one single Entity (which reflects the mere existence of the represented "thing") and a collection of Aspect instances (what is that thing, what service groups it belongs to). The actual data structures and behaviors are associated to the Aspect instances; each Aspect has one Type.

The type is responsible for controlling the memory containing the data of the Aspect, the serialization, the access, rights and life cycle management (protected, final, etc. fields, relations). Therefore, any type is fully functional when the framework has its declaration, with one limitation: it has "variant" interface. The advantage of putting the programming language away (and using Maps and other objects in Java for content management) has this drawback. I should check Java annotation feature if I can get some of this support back, and have compile time type checking for example upon a generic access function.

On the other hand, this generic access allows creating a type dynamic system in environments where binary dynamic solutions are not available. For example, if I would support types through generated Java sources, they can only be accessed by extending the class loader, would need Class.forName() functions and reflection for generic access of the members. These are heavy-weight requirements, and not supported for example in GWT (which is the planned reference web environment for Dust). This is why I focus on "plain" declarative access and generic data container objects. In previous works (LogMon) I could easily avoid using string based maps for attribute access (having index-based mappers instead), with acceptable performance.



These features seem to be enough to initiate a Dust based environment for my current tasks.