The good starting point is to look around Wicket documentation and tutorials. There are plenty of them. Just follow the links from the Wicket home page.
MidPoint GUI Extensibility
MidPoint GUI was originally built in quite a monolithic fashion. However, recently we have been refactoring and cleaning up the GUI code and also introducing mechanisms for GUI extensibility. Currently there are several ways how to extend the GUI:
- Customize GUI styles, e.g. color scheme, fonts and so on. (CSS/LESS, see Look & Feel Customization HOWTO)
- Create custom launchers for "home" page in midPoint GUI (declarative, see Admin GUI Configuration Type)
- Create custom menu links (declarative, see Admin GUI Configuration Type)
- Create custom tabs in the object details forms. These are created as Wicket panels (Java development)
In the future we plan the following mechanisms:
- Create custom GUI pages (Java development)
- Use custom GUI forms in existing pages (declarative)
MidPoint GUI API
MidPoint GUI is currently contained in a single component
admin-gui. Some parts of the classes in this component are meant to be used as an API by third-party developers and for the purposes of GUI customization. These classes will be maintained in backward-compatible way. Other classes are considered private implementation and we make no guarantees about their stability. The drawback is that now there is no clear way how to distinguish API classes and implementation classes in the GUI. Other components have a very clear distinction, but as the GUI code was not originally designed for this kind of reuse there is no such distinction in the GUI component. However, we are working on this. There is a new package that contains GUI API classes:
If you use classes and interfaces in this package you should be safe. These classes will only change in backward-compatible manner. If there is something that we would like to remove it will be marked as deprecated several midPoint releases before it is actually removed. The things in this package are considered to be stable. Use them.
The things in
com.evolveum.midpoint.gui.impl are considered to be private implementation. Do not use these. Any class or interface found in this package is considered private and it is subject to change any time without any warning. It you depend on the classes in this package you do it at your own risk. It is likely that midPoint upgrades will fail in a spectacular way and your customizations will not survive. You have been warned. If there is any class or interface in this package that you think may be useful as reusable component please contact the midPoint team. We will consider moving it to the API.
The classes in
com.evolveum.midpoint.web are unsorted. Some of these are API, some of these are implementation. There is no reliable way to tell them apart and this is currently a gray zone. These classes will eventually move either to API or impl (or disappear entirely). Therefore if you depend on them it is sure that you will have to change your code eventually. If you are lucky, you will only have to update package name. If you are not lucky you will have to rewrite the code. Anyway, if you think about using some components in this package it might be a good idea to contact us and discuss it. We might move the class to the API immediately and save you a lot of time in the future.
Base Page and Utility Classes
All midPoint pages share the same things: header, footer, navigation bar, title, stylesheets, ability to display menu, etc. All of these traits are implemented in a common superclass:
All self-respecting midPoint pages should extend this class. This class also contains a lot of utility methods that are available to all subclasses.
There are several general-purpose utility classes and interfaces in package:
Two most prominent classes are:
WebComponentUtil: contains utility methods that are often used in Wicket components (panels, forms, ...)
WebModelServiceUtil: contains utility methods that interact with midPoint IDM Model Interface (
ModelInteractionService) and other midPoint components.
MidPoint GUI Components
Apache Wicket is a component-based framework so naturally midPoint GUI has a lots and lots of components. Some of these components are a special-purpose things meant to do just one job. But most components are meant to be used on many places in the user interface. These reusable components should be part of the GUI API. But currently most of them are still in the gray zone. But we are continually sorting that out. To make the reuse easier, we are keeping a list of components that are already ready for reuse:
The GUI is already several years old and it has been through several redesigns and refactoring. That are some things that we are not entirely proud of but which cannot be completely removed right now. These are marked as deprecated in Java. But there are also associated CSS classes and JS scriptlets and other artifacts. Therefore the following list contains things that should not be used any more:
How To Make a Reusable Component
- Read this guide. Then read it again.
- Make sure you are correctly handling the model, extend BasePanel (if appropriate), etc.
- Make sure that the component is using only the classes from
com.evolveum.midpoint.gui.apipackage. It must not use classes from
com.evolveum.midpoint.gui.implpackage. If it uses classes from the old
com.evolveum.midpoint.webpackage consider cleaning them up and moving them to
- Make sure the component is using styles (CSS classes) that are either pure Bootstrap/AdminLTE or those that are in midpoint-theme.less (and they have appropriate comment).
- Describe the purpose of the component in component class javadoc. Two or three sentences is enough. Describe the purpose, not the implementation. I.e. describe what the component is supposed to do. You may also describe where do you think the component might be useful (why do you think it will be reused).
- Place the component in
com.evolveum.midpoint.gui.api.componentpackage. Each component java class and associated HTML file should be placed in its own sub-package. E.g.
- List the component in List of Reusable GUI Components
Most components in midPoint GUI are panels (sublcasses of
org.apache.wicket.markup.html.panel.Panel class). The basic characteristics are:
- The components usually extends
- Component constructor takes
modelas parameters. These are passed to superclass constructor.
- The component invokes (private) method
initLayout()that creates the structure of the components (adds sub-components).
- WARNING: Do not invoke
model.getObject()in constructor or
initLayout()method. This may cause premature loading of the model (see below). Also, these methods should not invoke
getPage()method, because the component is just being constructed and it is not part of the component tree yet.
- TODO: Passing PageBase to constructor or rather passing the segregated interfaces.
IModel implementation) is one of the fundamental concepts of the Wicket framework. Models hold the information processes by the components. Understanding the models can be a bit tricky, therefore please pay attention to this concept when reading Wicket documentation. The use of models in midPoint GUI is usually quite explicit (they are explicitly passed as parameters of component constructors). This makes it a bit easier to understand which model is used at which place.
MidPoint GUI often works with objects that are expensive to load. Loading a user object from repository might be relatively cheap, but even that we do not want to do unless really necessary. Loading user photo is more expensive. And loading resource objects such as accounts and entitlement associations is very expensive. We want to avoid that if possible. Therefore there is a
com.evolveum.midpoint.gui.api.model.LoadableModel class. This class in an implementation of Wicket
IModel interface that implements lazy loading. Use this class as model when dealing with objects that are expensive to load. Which is basically any midPoint object (
PrismObject) that needs to be retrieved from repository or from the resource. Just implement the
load() method. That's it.
The important thing to keep in mind is that Wicket is processing component in several phases (lifecycle stages). Especially interesting is the phase when component constructor is called, because that's the point where the component layout (sub-components) is constructed. The model object should already exist in this phase. In midPoint GUI the model object is usually passed as an component constructor parameter and stored in the field of
BasePanel class (see above). Then the initLayout() method is called. The model is already present there. But the model may be empty (not yet loaded). Loading the model is often expensive operation. We do not want to load the model unless it is necessary. E.g. we would like to load a model only if an expandable component is expanded, so can usually avoid loading the model entirely for the component that are not visible. If you need to do something with the model value in the subcomponent, do it indirectly through sub-component model and trigger loading only when subcomponent model is used.
TODO: object wrappers
Styles and Stylesheets
TODO: more about less, how it works
The midpoint uses standard Bootstrap and AdminLTE CSS classes whenever possible. If a component needs a custom class, the LESS code for that class should be places in the file:
Each definition that is put into this file should be commented. The comment should at least mention which component uses that definition. While Java has a nice search and refactoring features, LESS has none of that. Therefore maintenance of stylesheets is a major challenge. The comments make it much easier.
There are also old files
midpoint.less. These files are deprecated. Nothing should be added or modified in these files. Nothing. If you need to update any definition in these files move it to
midpoint-theme.less first and comment it, so we know that the definition is still used and where it is used. The
midpoint.less files are going to disappear sooner or later.
- Properly use generics. Using
IModelis bad. Using
IModel<String>is good. This makes the code more readable, especially in places like
List<IModel<ObjectWrapper<OrgType>>>(as opposed to just
List<IModel>which does not really tells anything). Generics might sometimes be painful and sometimes you have to fight them to get what you want. But the benefits are huge. Learn to use generics properly.
- TODO: serialization and serial version ID