Changes in a nutshell

The configuration mechanisms now reside in a separate project called magnolia_configuration (sub-project of magnolia_main). It contains a set of the new abstractions that have been developed in order to untie configuration from JCR and to allow for other config sources to be implemented with the same API's and abstractions.

A new configuration approach developed - file-based config via YAML (still in works).

In the current paper we will go over what has changed so far and what are the main new concepts and components of the config mechanism.

New concepts

One of the essential changes that was made is the introduction of a sophisticated API and architecture of the definition registries and how they are populated and managed. Let us sneak peek at how they look now and how they are different from before.

Configuration sources, deprecation of ConfiguredManagers

Configured manager objects (e.g. ConfiguredRendererManagerConfiguredAppDescriptorManager etc) were mostly used to monitor the JCR workspaces and update a corresponding definition registry. Since there was no API of registries such managers contained a lot of repeating boilerplate registry update code (e.g. infamous repeating unregisterAndRegister method etc). Since now a Registry is an interface it became possible to reduce the amount of code required to bind a registry to a config source:

  • Concrete/boilerplate Configured<..>Manager classes are now deprecated.
  • info.magnolia.config.source.ConfigurationSource was introduced in order to define a common source-type agnostic interface of raw config data store.
    • JcrConfigurationSource - binds registries to JCR, has a WorkspaceObservingManager inside for workspace monitoring. 
    • YamlConfigurationSource - populates definitions from YAML files, uses Java 7 file system observation utilities for real time updates (still pretty rudimentary).

Definition objects

Definition objects or simply definitions stand for POJO's that carry properties of some Magnolia CMS component (template, dialog, renderer etc). While structure and interface of the definitions used to be completely arbitrary from the programming point of view - there were implicit contracts regarding identification of definitions: they all had a property like name or id or both etc. Such properties were used as references of the definition in registries. How the definition used to be referenced was up to the registry.

Now there is an info.magnolia.config.NamedDefinition interface (still optional) which definitions can implement and make the name property more explicit.

Definition providers

Definition providers - objects capable of converting a piece of raw config data (JCR node/Builder code invocation, ...) into the definition beans. Did not have any common interface. However, most of them would typically have a getter method for underlying definition (e.g. getDialog) and for string identifier (e.g. getId()). There is a common generic interface of definition providers now. Definition is still retrievable with a DefinitionProvider#get(), whereas string id is replaced with a more generic and descriptive DefinitionMetadata. Apart from that the DefinitionProvider now has validation capabilities (isValid()getErrorMessages() methods) and 

DefinitionProvider interface
public interface DefinitionProvider<T> {
    DefinitionMetadata getMetadata();

    T get() throws Registry.InvalidDefinitionException;

    DefinitionRawView getRaw();

    boolean isValid();

    List<String> getErrorMessages();
}

Definition registries

Definition registries - a registry serves as container for a certain type of definition beans like template definitions. Before there was no common implementation nor interface for registries though all looked quite similar. Every registry had methods to register or unregister beans and had methods to retrieve specific or all contained beans. Therefore every registry had its own manager for managing the lifecycle especially the startup including reading the raw information from JCR.

Because of the new common interface for providers and sources it is possible to bind the config sources to a specific registry in the module lifecycle manager. The long time idea is to just use some kind of annotation, or similar automatic binding process, to make it even simpler to add additional registries.

 

Registry interface
public interface Registry<T> {
    DefinitionType type();
 
    DefinitionMetadataBuilder newMetadataBuilder();
 
    void start();
 
    void register(DefinitionProvider<T> definitionProvider);
 
    Set<DefinitionMetadata> unregisterAndRegister(Collection<DefinitionMetadata> toRemove, Collection<DefinitionProvider<T>> toAdd);
 
    DefinitionProvider<T> getProvider(DefinitionMetadata id);

    DefinitionProvider<T> getProvider(String referenceId) throws NoSuchDefinitionException;

    Collection<DefinitionProvider<T>> getAllProviders();

    Collection<T> getAllDefinitions();

    Collection<DefinitionMetadata> getAllMetadata(); // TODO getAllKeys ? getAllIds?


 DefinitionQuery<T> query();
}

Raw definition view

To create a generic config UI it is necessary to have access to a raw view of the configuration data. It would be possible but more error prone to use the definition beans over reflection. But some information might be lost in the transformation from JCR or YAML to beans. Therefore the raw view will be produced as a by product when during the JCR/YAML to bean transformation. The metadata will be the counterpart to it which will deliver even more detail about the configuration than stored in the beans.

DefinitionRawView interface
public interface DefinitionRawView {

    List<Property> properties();

    enum Kind {simple, collection, subBean /*or...*/}

    @Getter
    @RequiredArgsConstructor(access = AccessLevel.PRIVATE)
    @ToString
    @EqualsAndHashCode
    public static class Property {
        private final DefinitionRawView.Kind kind;
        private final String name;
        private final String simpleValue;
        private final Collection<Property> collection;
        private final DefinitionRawView subRawView;

        public static Property simple(String name, String valueStr) {
            return new Property(Kind.simple, name, valueStr, null, null);
        }

        public static Property collection(String name, Collection<Property> collection) {
            return new Property(Kind.collection, name, null, collection, null);
        }

        public static Property subBean(String name, DefinitionRawView subRawView) {
            return new Property(Kind.subBean, name, null, null, subRawView);
        }
    }
}

 

Definition metadata

Definition metadata - the definition metadata contains additional information about a definition. Like its actual type or in which module it resides. Additional information will be from which source it originated or probably how to display it in the configuration app.

DefinitionMetadata interface
public interface DefinitionMetadata {
    DefinitionType getType();

    String getReferenceId();

    String getName();

    String getModule();

    String getLocation();

    String getRelativeLocation();
}

 

Architecture

Next steps

Establish backward compatibility by reviving ConfiguredTemplateDefinitionManager and other deprecated classes and let them use the new registries.

Clean up the current code. There are a lot of TODOs as well as commented code and unused code. So we have to remove obsolete TODOs or implement what is missing, remove commented code (or move it to a special branch or wiki to keep it if worth while) and evaluate the current implement against the vision to clean up unused code and/or interfaces.

Configuration sources should be streamlined, so that not every module should care about each registry times each source type. If possible modules and registries should be agnostic about any configuration source type.

Config files as resources Config files should be loaded over workspaces->modules->webapp like resources and templates. So they can be activated and published. (ResourceLoader)

Extents, decoration and other registry features have to be implemented.

Configuration App should be able to show the complete registry content and maybe reveal some metadata or other additional information. We want at least want to see at some point the source of the configuration (yaml, jcr, ...)

Registry Facade is the idea to have a single point of entry for all registries. This is a must have for the configuration app but could be useful for other scenarios as well. 

Validation is done on a very basic level at the moment. This should be improved in a way to allow the model to store validation error messages as well as invalid values (we don't want typos for example to vanish completely)

Autosuggest

Open questions

Metadata, Id, Provider, Definition, Proxies
There is an open debate about how to merge all the worlds together while keeping in min backward compatibility and low complexity.

 

 

  • No labels