To program an app, you need a development environment. Use the same environment you would use for other Magnolia development tasks. See Developing for instructions on how to set it up.
Note - The term component is a developer term that here refers to Java objects, not templating components.
A component provides a service such as keeping a registry of templates. Components expose their functionality to other components through an interface or an API. A typical component depends on a number of other components and benefits from dependency injection as Magnolia will connect components to satisfy their dependencies. Components are either singletons, which means that they are around for the lifetime of the server, or they are tied to shorter durations such as the duration of an HTTP request or a user session. The duration is known as scope.
Apps and components
Each app has its own component provider that uses components in the
app-<app name> group. Each subapp has a component provider that uses components described for it. Component providers have the app component provider as their parent:
Defining app components in a module descriptor
Define your components in the module descriptor. Here is a minimal module descriptor that doesn't declare any components yet. It just declares the module name and version.
Defining an app or subapp as a component
Defining something as a component allows other developers quickly change the implementation. For this reason, you should define anything that is likely to be changed or customized later as a component. For example, define your apps and subapps as components. Views are also common customization points so define the views returned by subapps as components. Any components you define are available for injection. This is also true for components further up the hierarchy in parent components.
In the module descriptor file, add a section for each component. Name the components using the following convention:
app-<app name>-<subapp name>
<app name> is the name configured in the app configuration in AdminCentral. For example:
- Use a Maven archetype to get a ready-made Magnolia module structure. An archetype has a top-level project and a webapp configured as a Maven submodule.
- Structure your app project in the IDE as shown in the example below. Put the app and subapp classes in the same folder.
- Export the app configuration and the app launcher configuration into XML and put them in the
resourcesfolder. The module descriptor file goes in
App project structure in your IDE:
Implementing an app
- Create a class that implements the
Appinterface, or extend the
BaseAppclass. The second option is more convenient.
- In your app class, implement any custom methods or functionality you need.
AppViewas a dependency.
Note: This is only needed if you want to extend the App by custom functionality. Otherwise use
info.magnolia.ui.framework.app.BaseApp as the app class in the configuration.
Starting an app
- To start an App you would usually navigate to the group you defined in the
AppLauncherand launch it by clicking on the icon. To do this programmatically you can trigger a
LocationChangeevent by calling
LocationController.goTo()with the location as an argument.
AppControllerwill now take care of opening the correct app and subapp based on the app name and subapp ID as defined in the configuration.
- To hook into the starting cycle or location handling of an app:
Stopping an app
When an app stops, you get a callback to the
stop method to do cleanup. The cleanup can involve closing files, closing network connections and so on.
Handling location changes
When your app is requested with a location fragment, you might need to handle changing the location. In your app class, override the
Remember, if the subapp is requested with a location that is already open in a running subapp, the Magnolia Shell takes care of bringing that subapp to focus instead of starting a new one.
Subapp is an app that runs in its own tab. For example, the Pages app always has the
main subapp open in the first tab and multiple
detail subapps for each page that is edited. The
main subapp has the label “Pages” while the
detail subapps are labeled according to the page title, for example Travel Home.
When the subapp starts it must return a view. The view draws a user interface on the tab so that there is something for the user to interact with. The view takes up the whole tab and adds a caption.
Implementing a SubApp
Create a class that implements the SubApp interface or extend the
BaseSubApp class. The second option is more convenient. In your subApp class, implement any custom methods or functionality you need. Inject the
SubAppContext and a view associated with the subApp as a dependency.
Starting a subApp
The default implementation for starting and changing the location of Apps is being delegated to the actual subApp defined in the
location. If a subApp with the referenced
subApp Id is already running, it will be asked whether it actually supports the
In this case all locations with a reference to its subApp Id will be handled by this subApp instance. By overriding this method and make it return
false you would open a new tab for every location change the AppController gets which is targeted to this subAppId. To open a new tab based on the parameters passed to the subApp, it would look like this:
To hook into the starting cycle or location handling of an App:
You need to declare your dependencies in the module descriptor. You can define runtime or install time dependencies, not build dependencies. If you define a dependency on another module, then this module will be installed and started before your module. In order to develop a basic app, add the following section to your module descriptor:
Hello World example
This is a step-by-step guide on how to implement a basic hello world app. When started, it shows a
main subApp containing two buttons. Clicking on a button should open a new
greeter subApp greeting the user associated with the button.
The logic is taken care of by the
HelloWorldMainSubApp which adds buttons to the view and listens to actions by implementing the
In addition to the
SubAppContext and the
View we also inject the
LocationController which will be used to open the
A simple interface providing methods to add buttons in the view.
The view consists of a VerticalLayout and a Label "Say Hello!".
When the user clicks one of the buttons, a new location is requested. The
AppController will take care of redirecting it to the hello world app and launching the
A simple interface providing a method to set the name.
The view consists of a VerticalLayout and a Label
"Hello " + name + "!".
HelloWorldGreeterSubApp will override the default caption of the tab by the name passed as a parameter and set it on the view.