We have seen the different components of the KIE workbench throughout the book. This appendix will explain how all its components are bonded together through the UberFire framework, which allows us to have a configurable and extensible workbench environment. We will dedicate this appendix to discussing its structure and use, which will become useful if you wish to extend the tooling provided by jBPM6 for your own personal customization. This is an advanced topic, but will give you a full control over how to use the KIE workbench to fit it best to your company.
UberFire is a JBoss-based framework developed and maintained by the Drools and jBPM team. UberFire creates a rich client platform built on top of GWT (http://www.gwtproject.org) and Errai (http://erraiframework.org). It is also the technology on top of which the KIE workbench project is built. It provides a series of components for a pluggable user administration, virtual file system management, and configurable perspectives and user interfaces. It is thought of as a work on top of an application server, and depends on JEE6 specifications (such as CDI, for dependency injection).
UberFire defines a few default implementations for a few of its services, but they are all highly configurable. For example, for user management, they use a user properties file as default, but the KIE workbench uses Java as a service implementation configured with a file in the classpath at META-INF/services/org.uberfire.security.auth.AuthenticationSource
with the actual implementation to use for authentication.
We will discuss only a few of the components of UberFire here due to the need of perhaps a full book to cover every component. However, if you wish to go deeper into the framework utilities, visit http://www.uberfireframework.org.
Some of the most important functionalities that UberFire provides from our perspective are follows:
As we mentioned before, UberFire is heavily dependent on GWT and Errai, integrated internally through a series of CDI injected events that each component either fires or captures to decide actions that need to be taken.
Context and Dependency Injection (CDI) is a standard defined by Java Enterprise Edition 6 to compose different components based on their types, names, and specific centralized configurations. The idea behind it is remove the need of writing legacy code to initialize and bind together different implementations of components, but allow them to be managed through specific annotations in classes and by configuration files.
Google Web Toolkit (GWT) is a framework created by Google that is used to define smart user interfaces using Java code, which are later (during project compilation) translated into JavaScript in order to run in a web browser without the need of having any plugins installed. Its goal is to enable productive development of high-performance web applications without the developer having to be an expert in browser quirks, Ajax requests, and JavaScript.
The main problem that a GWT translation of Java to JavaScript has is that it doesn't translate everything. There is a point where you have to split which classes run in the client as JavaScript and which classes run in the server as Java. Connectivity between the server and client don't take advantage of other frameworks such as CDI to inject communication stubs.
That's where Errai comes in. Errai provides several GWT extensions for UI templating, binding, and server communication through simple events. Errai allows users to define CDI annotations on GWT code and provides a way to translate those annotations and use them even if the actual component implementations are only server-side (that means, they weren't translated to JavaScript).
This allows components to directly communicate using events irrespective of whether they were server components or client components that will later on be translated to JavaScript. The level of unification in the design that this framework allowed made UberFire an incredibly powerful framework.
Thanks to all the already existing components in the workbench and the fact that all communication can be handled through events, extending components to listen to new events is very simple and new components that interact with other actions taken by the user or the server can be written with very loose coupled code.
There are many existing components in the UberFire framework, and covering them all will take a book by itself. We will explore the most important components from the BPM perspective, and how they help in the generation of a BPM system for jBPM6.
Some of the backend features that UberFire has that are important for jBPM6 are as follows:
org.uberfire.security.auth.AuthenticationSource
interface can tell the framework which credentials are valid and which are not. The framework comes with a starter set of AuthenticationSource
implementations, but you can implement your own, add it to your workbench class path, and configure it using Java's standard ServiceLoader
facility, by simply writing the full class name in the META-INF/services/org.uberfire.security.auth.AuthenticationSource
file. If you want more than one authentication source at a time, list each fully qualified class name on its own line in the file; if your AuthenticationSource
implementation also implements RoleProvider
, then it can also provide role authorization.ServiceLoader
facility by writing content to the META-INF/services/org.uberfire.java.nio.file.spi.FileSystemProvider
file. However, this isn't a recommended practice unless you know exactly what you're doing.Thanks to these backend features, a lot of other features can be easily provided. Among the frontend features, we have the following:
Event intercommunication is a very important and simple-to-use component that generates events that can be shared by the client and server. The first thing we need to do is to define our event objects. Let's examine how we defined NewMessageEvent
in our uberfire-demo-api
project:
@org.jboss.errai.common.client.api.annotations.Portable public class NewMessageEvent implements Serializable { public NewMessageEvent() { … } … }
In the previous code fragment, which we reduced to the most important sections, you can see that our event doesn't have to extend any specific class. All it needs is a @Portable
annotation from Errai to be shared between client and server. Inside the event, any kind of serializable information can be placed to be shared between a client and server.
Later on, these events are captured or fired by specific instances, but the configuration to use them is almost trivial. In the following code fragment, we see how the MessageListViewImpl
class in the uberfire-demo-client
project listens for NewMessageEvent
firings and how it fires another type of event called NotificationEvent
:
public class MessageListViewImpl … { … @javax.inject.Inject public javax.enterprise.event.Event<NotificationEvent> notification; … public void requestCreated(@javax.enterprise.event.Observes NewMessageEvent e ){ … } public void displayNotification( String text ) { notification.fire( new NotificationEvent( text ) ); } … }
As you can see, all it took to listen to event firings was the creation of a method that had a parameter with the @Observes
annotation. In the previous code fragment, the method is called requestCreated
.
Meanwhile, we need two things to fire events:
javax.enterprise.event.Event
objectfire
method needs to be invoked with a new event instanceIn the previous code fragment, the fire
method is invoked from inside the displayNotification
method. Using the Event
object is quite simple. Thanks to CDI and Errai, we don't need to do anything else than to inject the instance with the @Inject
annotation, and then let the framework take care of creating the actual object and setting it to any component.