Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migration of unmigrated content due to installation of a new plugin

(warning) This article refers to components as in java objects that make up the foundation of the system and is not to be confused with "page components" in templating.

Table of Contents

Abstract

Terms

  • Container, responsible for managing components.
  • Component, anything that's configured in and managed by a container.
  • ComponentProvider, is our container abstraction.

...

The key method provided by ComponentProvider is getComponent() which is used to get the component for a specific type.

Code Block

public interface ComponentProvider {
  T getComponentClass<T> type);
}

...

The module descriptor can specify components for different containers. This is done using the id tag. You will rarely use a container other than main. Here is how the XML is structured:

Code Block

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module SYSTEM "module.dtd">
<module>
  ...
  <components>
    <id>main</id>
    <configurer>
      ...
    </configurer>
    <component>
      ...
    </component>
    <type-mapping>
      ...
    </type-mapping>
  </components>
</module>

...

A typical component definition

Code Block

<component>
  <type>info.magnolia.cms.filters.FilterManager</type>
  <implementation>info.magnolia.cms.filters.FilterManagerImpl</implementation>
  <scope>singleton</scope>
  <lazy>true</lazy>
</component>

...

Component via provider

Code Block

<component>
  <type>info.magnolia.cms.beans.config.ServerConfiguration</type>
  <provider>info.magnolia.cms.beans.config.ServerConfiguration$InstanceFactory</provider>
  <scope>singleton</scope>
</component>

...

Components from JCR

Code Block

<component>
  <type>info.magnolia.cms.beans.config.URI2RepositoryManager</type>
  <workspace>config</workspace>
  <path>/server/URI2RepositoryMapping</path>
  <observed>true</observed>
  <scope>singleton</scope>
</component>

...

A type mapping is defined in the module descriptor alongside components:

Code Block

<type-mapping>
  <type>info.magnolia.cms.core.AggregationState</type>
  <implementation>info.magnolia.module.templatingkit.ExtendedAggregationState</implementation>
</type-mapping>

The ComponentProvider has a method for creating instances using these mappings:

Code Block

public interface ComponentProvider {
  T newInstance(Class<T> type);
}

...

ComponentProvider can also take a set of additional arguments that will be used as constructor arguments in addition to those resolved using dependency injection.

Code Block

public interface ComponentProvider {
  T newInstance(Class<T> type, Object... parameters);
}

It is also possible to pass in a list of custom parameter resolvers that will then assist in resolving the parameters to use.

Code Block

public interface ComponentProvider {
  T newInstance(Class<T> type, ParameterResolver... parameters);
}

...

This is an example of what it used to look like:

Code Block

<properties>
  <property>
    <name>info.magnolia.module.templatingkit.sites.SiteManager</name>
    <value>info.magnolia.module.templatingkit.sites.STKSiteManager</value>
  </property>
  <property>
    <name>info.magnolia.cms.core.AggregationState</name>
    <value>info.magnolia.module.templatingkit.ExtendedAggregationState</value>
  </property>
</properties>

The equivalent component definition looks like this:

Code Block

<components>
  <id>main</id>
  <component>
    <type>info.magnolia.module.templatingkit.sites.SiteManager</type>
    <implementation>info.magnolia.module.templatingkit.sites.STKSiteManager</implementation>
    <scope>singleton</scope>
    <lazy>true</lazy>
  </component>
  <type-mapping>
    <type>info.magnolia.cms.core.AggregationState</type>
    <implementation>info.magnolia.module.templatingkit.ExtendedAggregationState</implementation>
  </type-mapping>
</components>

In order to remain fully backwards compatible, Magnolia 4.5 will add both a component definition and a type mapping for AggregationState.

Supported

...

types of dependency injection

Magnolia uses the standardized annotations for dependency injections from JSR-330 which enable all three forms types of dependency injection:

  • Constructor injection
  • Setter Field injectionField
  • Setter injection

This is an example of all three:

Code Block

public class RenderingEngine {

    @Inject
// Dependencies are injected privatein TemplateRegistrythe templateRegistry;constructor

    @Inject
    public SomeComponent(ModuleManager moduleManager) { ... }

    // Fields are set with injected dependencies after construction
    @Inject
    private TemplateRegistry templateRegistry;

    // Setters are called with injected dependencies after construction
    @Inject
    public void setRendererRegistry(RendererRegistry rendererRegistry) { ... }
}

...

It is also possible to inject properties like this:

Code Block

  @Inject
  @Named("magnolia.develop")
  private Provider<String> developmentMode;

...

When accessing an object in a lesser scope, inject a Provider and call it when you need the object. For instance AggregationStateBasedRenderingContext is scoped with @RequestScoped. To access it the rendering engine depends on it like this:

Code Block

public class RenderingEngine {
    public RenderingEngine(Provider<RenderingContext> renderingContextProvider) { ... }
}

...

Magnolia supports life cycle callbacks using the @PostConstruct and @PreDestroy annotations from JSR-250. A method with @PostConstruct will be invoked after a component has been created and had its members injected. Likewise, @PreDestroy will make the method invoked when the component provider is closed down. @PreDestroy is however only called on singletons.

Javadoc for JSR-250

Component life cycle

A component has a life cycle with these steps

  • Instantiation, the constructor annotated with @Inject is called with arguments resolved by the container or the default no-args constructor is used.
  • Fields annotated with @Inject are filled.
  • Methods annotated with @Inject are called with arguments resolved by the container.
  • @PostConstruct is called.
  • Component is in use.@PreDestroy is called when the container is closed down.

Google Guice integration

...

When Magnolia is shutdown it performs the same steps in reverse. First calling ModuleLifecycle.stop() on modules, then it closes Main, then System and finally Platform.

Magnolia ComponentProvider hierarchy

Image AddedComponents with methods annotated with @PreDestroy are called when the step in which they live is closed.