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.