Errai 2.1.1.final Reference Guide
Errai 2.1.1.final Reference Guide
Errai 2.1.1.final Reference Guide
Preface ............................................................................................................................. ix 1. Document Conventions ......................................................................................... ix 2. Feedback ............................................................................................................. ix 1. Introduction ................................................................................................................. 1 1.1. What is it? .......................................................................................................... 1 1.2. Required software ............................................................................................... 1 2. Messaging ................................................................................................................... 3 2.1. Messaging Overview ........................................................................................... 3 2.2. Messaging API Basics ........................................................................................ 3 2.2.1. Sending Messages with the Client Bus ...................................................... 3 2.2.2. Recieving Messages on the Server Bus / Server Services ........................... 5 2.2.3. Sending Messages with the Server Bus .................................................... 5 2.2.4. Receiving Messages on the Client Bus/ Client Services .............................. 6 2.3. Conversations ..................................................................................................... 7 2.4. Handling Errors .................................................................................................. 7 2.5. Handling Transport Errors ................................................................................... 9 2.6. Single-Response Conversations & Pseudo-Synchronous Messaging .................... 10 2.7. Broadcasting ..................................................................................................... 2.8. Client-to-Client Communication .......................................................................... 2.8.1. Relay Services ....................................................................................... 2.9. Asynchronous Message Tasks .......................................................................... 2.10. Repeating Tasks ............................................................................................. 2.11. Sender Inferred Subjects ................................................................................. 2.12. Message Routing Information .......................................................................... 2.13. Queue Sessions .............................................................................................. 2.13.1. Lifecycle .............................................................................................. 2.13.2. Scopes ................................................................................................ 2.14. Client Logging and Error Handling ................................................................... 2.15. Wire Protocol (J.REP) ..................................................................................... 2.15.1. Payload Structure ................................................................................. 2.15.2. Message Routing ................................................................................. 2.15.3. Bus Management and Handshaking Protocols ........................................ 2.16. WebSockets .................................................................................................... 2.16.1. Configuring the sideband server ............................................................ 2.16.2. Deploying with JBoss AS 7 ................................................................... 3. Dependency Injection ................................................................................................ 3.1. Container Wiring ............................................................................................... 3.2. Wiring server side components .......................................................................... 3.3. Scopes ............................................................................................................. 3.3.1. Dependent Scope .................................................................................. 3.4. Built-in Extensions ............................................................................................ 3.4.1. Bus Services .......................................................................................... 3.4.2. Client Components ................................................................................. 3.4.3. Lifecycle Tools ....................................................................................... 10 10 11 11 12 13 13 14 14 15 16 16 16 18 19 20 20 21 23 24 26 26 26 27 27 28 30
iii
Errai
3.5. Client-Side Bean Manager ................................................................................. 31 3.5.1. Looking up beans .................................................................................. 31 3.5.2. Availability of beans ............................................................................... 3.6. Alternatives and Mocks ..................................................................................... 3.6.1. Alternatives ............................................................................................ 3.6.2. Test Mocks ............................................................................................ 3.7. Bean Lifecycle .................................................................................................. 3.7.1. Destruction of Beans .............................................................................. 4. Errai CDI .................................................................................................................... 4.1. Features and Limitations ................................................................................... 4.1.1. Other features ........................................................................................ 4.2. Events .............................................................................................................. 4.2.1. Conversational events ............................................................................ 4.2.2. Client-Server Event Example .................................................................. 4.3. Producers ......................................................................................................... 4.4. safe dynamic lookup ......................................................................................... 4.5. Deploying Errai CDI .......................................................................................... 4.5.1. Deployment in Development Mode .......................................................... 4.5.2. Deployment to a Servlet Engine .............................................................. 4.5.3. Deployment to an Application Server ....................................................... 5. Marshalling ................................................................................................................ 5.1. Mapping Your Domain ...................................................................................... 5.1.1. @Portable and @NonPortable ................................................................ 5.1.2. Manual Mapping .................................................................................... 5.1.3. Manual Class Mapping ........................................................................... 5.1.4. Custom Marshallers ................................................................................ 6. Remote Procedure Calls (RPC) .................................................................................. 6.1. Making calls ..................................................................................................... 6.1.1. Proxy Injection ....................................................................................... 6.2. Handling exceptions .......................................................................................... 6.3. Client-side Interceptors ...................................................................................... 6.4. Session and request objects in RPC endpoints ................................................... 7. Errai JAX-RS .............................................................................................................. 7.1. Server-Side Prerequisites .................................................................................. 7.1.1. Server-Side JAX-RS Provider ................................................................. 7.1.2. Shared JAX-RS Interface ........................................................................ 7.2. Creating Requests ............................................................................................ 7.2.1. Proxy Injection ....................................................................................... 7.3. Handling Responses ......................................................................................... 7.4. Client-side Interceptors ...................................................................................... 7.5. Wire Format ..................................................................................................... 7.6. Errai JAX-RS Configuration ............................................................................... 7.6.1. Configuring the default root path of JAX-RS endpoints .............................. 7.6.2. Enabling Jackson marshalling ................................................................. 32 33 33 34 35 35 39 39 40 40 41 42 45 46 46 47 48 48 49 49 49 53 55 57 59 59 60 60 61 62 65 65 65 66 67 68 68 70 71 71 71 72
iv
8. Errai JPA ................................................................................................................... 73 8.1. Getting Started ................................................................................................. 74 8.1.1. Compile-time dependency ....................................................................... 8.1.2. GWT Module Descriptor ......................................................................... 8.1.3. INF/persistence.xml ................................................................................ 8.1.4. Declaring an Entity Class ........................................................................ 8.1.5. Entity Lifecycle States ............................................................................ 8.1.6. Obtaining an instance of EntityManager ................................................... 8.1.7. Named Queries ...................................................................................... 8.1.8. Entity Lifecycle Events ............................................................................ 8.1.9. JPA Metamodel ...................................................................................... 8.1.10. JPA Features Not Implemented in Errai 2.1 ............................................ 8.1.11. Other Caveats for Errai 2.1 JPA ............................................................ 9. Data Binding .............................................................................................................. 9.1. Bindable Objects ............................................................................................... 9.2. Initializing a DataBinder ..................................................................................... 9.3. Creating Bindings .............................................................................................. 74 74 74 75 78 79 81 82 84 85 86 87 87 87 88
9.4. Specifying Converters ....................................................................................... 89 9.4.1. Registering a global default converter ...................................................... 89 9.4.2. Providing a binding-specific converter ...................................................... 90 9.5. Property Change Handlers ................................................................................ 90 10. Errai UI ..................................................................................................................... 93 10.1. Get started ..................................................................................................... 93 10.1.1. App.gwt.xml ......................................................................................... 93 10.2. Use Errai UI Composite components ................................................................ 93 10.2.1. Inject a single instance ......................................................................... 93 10.2.2. Inject multiple instances (for iteration) .................................................... 94 10.3. Create a @Templated Composite component ................................................... 94 10.3.1. Basic component .................................................................................. 94 10.3.2. Custom template names ....................................................................... 95 10.4. Create an HTML template ............................................................................... 95 10.4.1. Select a template from a larger HTML file .............................................. 96 10.5. Use other Widgets in a composite component .................................................. 97 10.5.1. Annotate Widgets in the template with @DataField ................................. 97 10.5.2. Add corresponding data-field attributes .................................................. 98 10.6. How HTML templates are merged with Components ......................................... 98 10.6.1. Example .............................................................................................. 99 10.6.2. Element attributes (template wins) ....................................................... 100 10.6.3. DOM Elements (component field wins) ................................................. 100 10.6.4. Inner text and inner HTML (preserved when component implements HasText or HasHTML) ................................................................................... 100 10.7. Event handlers .............................................................................................. 100 10.7.1. Concepts ............................................................................................ 101 10.7.2. GWT events on Widgets ..................................................................... 101
Errai
10.7.3. GWT events on DOM Elements .......................................................... 101 10.7.4. Native DOM events on Elements ......................................................... 102 10.8. Data Binding ................................................................................................. 10.9. Nest Composite components ......................................................................... 10.10. Extend Composite components .................................................................... 10.10.1. Template .......................................................................................... 10.10.2. Parent component ............................................................................ 10.10.3. Child component ............................................................................... 11. Errai UI Navigation ................................................................................................. 11.1. Getting Started .............................................................................................. 11.1.1. Compile-time dependency ................................................................... 11.1.2. GWT Module Descriptor ...................................................................... 11.2. How it Works ................................................................................................ 11.2.1. Declaring a Page ................................................................................ 11.2.2. Declaring a Link ................................................................................. 11.2.3. Following a Link ................................................................................. 11.2.4. Installing the Navigation Panel into the User Interface ........................... 12. 11.2.5. Viewing the Generated Navigation Graph ............................................. Configuration ......................................................................................................... 12.1. Appserver Configuration ................................................................................ 12.2. Client Configuration ....................................................................................... 12.3. ErraiApp.properties ........................................................................................ 12.3.1. As a Marker File ................................................................................. 12.3.2. As a Configuration File ....................................................................... 12.4. ErraiService.properties ................................................................................... 12.4.1. Configuration Properties ...................................................................... 12.4.2. Example Configuration ........................................................................ 12.5. Dispatcher Implementations ........................................................................... 12.5.1. SimpleDispatcher ................................................................................ 12.5.2. AsyncDispatcher ................................................................................. 12.6. Servlet Implementations ................................................................................. 12.6.1. DefaultBlockingServlet ........................................................................ 12.6.2. JBossCometServlet ............................................................................. 12.6.3. JettyContinuationsServlet .................................................................... 12.6.4. StandardAsyncServlet ......................................................................... Debugging Errai Applications ................................................................................ Troubleshooting & FAQ ......................................................................................... 14.1. Why does it seem that Errai can't see my class at compile time? ...................... 14.2. Why am I getting "java.lang.ClassFormatError: Illegal method name "<init>$" in class org/xyz/package/MyClass"? ........................................................................... Upgrade Guide ....................................................................................................... 15.1. Upgrading from 1.* to 2.0 .............................................................................. 15.2. Upgrading from 2.0.Beta to 2.0.*.Final ............................................................ Downloads ............................................................................................................. 103 104 105 105 105 106 107 107 107 107 108 108 109 109 110 112 113 113 114 114 114 114 115 115 116 117 117 118 118 118 118 118 118 119 121 121 121 123 123 124 125
13. 14.
15.
16.
vi
17. Sources .................................................................................................................. 127 18. Reporting problems ............................................................................................... 129 19. Errai License .......................................................................................................... 131 A. Revision History ........................................................................................................ 133
vii
viii
Preface
ix
Chapter 1.
Introduction
1.1. What is it?
Errai is a GWT-based framework for building rich web applications using next-generation web technologies. Built on-top of ErraiBus, the framework provides a unified federation and RPC infrastructure with true, uniform, asynchronous messaging across the client and server.
Chapter 2.
Messaging
This section covers the core messaging concepts of the ErraiBus messaging framework. ErraiBus forms the backbone of the Errai framework's approach to application design. Most importantly, it provides a straight-forward approach to a complex problem space. Providing common APIs across the client and server, developers will have no trouble working with complex messaging scenarios from building instant messaging clients, stock tickers, to monitoring instruments. There's no more messing with RPC APIs, or unweildy AJAX or COMET frameworks. We've built it all in to one, consice messaging framework. It's single-paradigm, and it's fun to work with.
Chapter 2. Messaging
public class HelloWorld implements EntryPoint { // Get an instance of the RequestDispatcher private RequestDispatcher dispatcher = ErraiBus.getDispatcher(); public void onModuleLoad() { Button button = new Button("Send message"); button.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { // Send a message to the 'HelloWorldService'. MessageBuilder.createMessage() .toSubject("HelloWorldService") // (1) .signalling() // (2) .noErrorHandling() // (3) .sendNowWith(dispatcher); // (4) }); [...] } } }
In the above example we build and send a message every time the button is clicked. Here's an explanation of what's going on as annotated above: 1. We specify the subject we wish to send a message to. In this case, " HelloWorldService ". 2. We indicate that we wish to only signal the service, meaning, that we're not sending a qualifying command to the service. For information on this, read the section on Protocols . 3. We indicate that we do not want to provide an ErrorCallback to deal with errors for this message. 4. We transmit the message by providing an instance to the RequestDispatcher
Note
An astute observer will note that access to the RequestDispatcher differs within client code and server code. Because the client code does not run within a container, access to the RequestDispatcher and MessageBus is statically accessed using the ErraiBus.get() and ErraiBus.getDispatcher() methods. The server-side code, conversely, runs inside a dependency container for managing components. See the section on Errai IOC and Errai CDI for using ErraiBus from a client-side container.
@Service public class HelloWorldService implements MessageCallback { public void callback(Message message) { System.out.println("Hello, World!"); } }
He we declare an extremely simple service. The @Service annotation provides a convenient, meta-data based way of having the bus auto-discover and deploy the service.
@Service public class HelloWorldService implements MessageCallback { private RequestDispatcher dispatcher; @Inject public HelloWorldService(RequestDispatcher dispatcher) { dispatcher = dispatcher; } public void callback(CommandMessage message) { // Send a message to the 'HelloWorldClient'. MessageBuilder.createMessage() .toSubject("HelloWorldClient") // (1) .signalling() // (2) .with("text", "Hi There") // (3) .noErrorHandling() // (4) .sendNowWith(dispatcher); // (5) }); }
Chapter 2. Messaging
The above example shows a service which sends a message in response to receiving a message. Here's what's going on: 1. We specify the subject we wish to send a message to. In this case, " HelloWorldClient ". We are sending this message to all clients which are listening in on this subject. For information on how to communicate with a single client, see Section 2.6. 2. We indicate that we wish to only signal the service, meaning that we're not sending a qualifying command to the service. For information on this, read the section on Protocols. 3. We add a message part called "text" which contains the value "Hi there". 4. We indicate that we do not want to provide an ErrorCallback to deal with errors for this message. 5. We transmit the message by providing an instance of the RequestDispatcher .
public class HelloWorld implements EntryPoint { private MessageBus bus = ErraiBus.get(); public void onModuleLoad() { [...] /** * Declare a local service to receive messages on the subject * "BroadcastReceiver". */ bus.subscribe("BroadcastReceiver", new MessageCallback() { public void callback(CommandMessage message) { /** * When a message arrives, extract the "text" field and * do something with it */ String messageText = message.get(String.class, "text"); } });
Conversations
[...] } }
In the above example, we declare a new client service called "BroadcastReceiver" which can now accept both local messages and remote messages from the server bus. The service will be available in the client to receive messages as long the client bus is and the service is not explicitly de-registered.
2.3. Conversations
Conversations are message exchanges which are between a single client and a service. They are a fundmentally important concept in ErraiBus, since by default, a message will be broadcast to all client services listening on a particular channel. When you create a reply with an incoming message, you ensure that the message you are sending back is received by the same client which sent the incoming message. A simple example:
@Service public class HelloWorldService implements MessageCallback { public void callback(CommandMessage message) { // Send a message to the 'HelloWorldClient' on the client that sent us the // the message. MessageBuilder.createConversation(message) .toSubject("HelloWorldClient") .signalling() .with("text", "Hi There! We're having a reply!") .noErrorHandling().reply(); }); } }
Note that the only difference between the example in the previous section and this is the use of the createConversation() method with MessageBuilder .
Chapter 2. Messaging
As a general rule, you should always handle your errors . It will lead to faster and quicker identification of problems with your applications if you have error handlers, and generally help you build more robust code.
MessageBuilder.createMessage() .toSubject("HelloWorldService") .signalling() .with("msg", "Hi there!") .errorsHandledBy(new ErrorCallback() { public boolean error(Message message, Throwable throwable) { throwable.printStackTrace(); return true; } }) .sendNowWith(dispatcher);
The addition of error handling at first may put off developers as it makes code more verbose and less-readable. This is nothing that some good practice can't fix. In fact, you may find cases where the same error handler can appropriately be shared between multiple different calls.
ErrorCallback error = new ErrorCallback() { public boolean error(Message message, Throwable throwable) { throwable.printStackTrace(); return true; } } MessageBuilder.createMessage() .toSubject("HelloWorldService") .signalling() .with("msg", "Hi there!") .errorsHandledBy(error) .sendNowWith(dispatcher);
The error handler is required to return a boolean value. This is to indicate whether or not Errai should perform the default error handling actions it would normally take during a failure. You will almost always want to return true here, unless you are trying to explicitly surpress some undesirably activity by Errai, such as automatic subject-termination in conversations. But this is almost never the case. Errai further provides a subject to subscribe to for handling global errors on the client (such as a disconnected server bus or an invalid response code) that occur outside a regular application message exchange. Subscribing to this subject is useful to detect errors early (e.g. due to failing
heartbeat requests). A use case that comes to mind here is activating your application's offline mode.
bus.subscribe(DefaultErrorCallback.CLIENT_ERROR_SUBJECT, new MessageCallback() { @Override public void callback(Message message) { try { caught = message.get(Throwable.class, MessageParts.Throwable); throw caught; } catch(TransportIOException e) { // thrown in case the server can't be reached or an unexpected status code was returned } catch (Throwable throwable) { // handle system errors (e.g response marshalling errors) - that of course should never happen :) } } });
messageBus.addTransportErrorHandler(new TransportErrorHandler() { public void onError(TransportError error) { // error handling code. } });
The TransportError interface represents the details of an an error from the bus. It contains a set of methods which can be used for determining information on the initial request which triggered the error, if the error occurred over HTTP or WebSockets, status code information, etc. See the JavaDoc for more information.
Chapter 2. Messaging
MessageBuilder.createMessage() .toSubject("ConversationalService").signalling() .with("SomeField", someValue) .noErrorHandling() .repliesTo(new MessageCallback() { public void callback(Message message) { System.out.println("I received a response"); } })
See the next section on how to build conversational services that can respond to such messages.
2.7. Broadcasting
Broadcasting messages to all clients listening on a specific subject is quite simple and involves nothing more than forgoing use of the reply API. For instance:
MessageBuilder.createMessage(). .toSubject("MessageListener") .with("Text", "Hello, from your overlords in the cloud") .noErrorHandling().sendGlobalWith(dispatcher);
If sent from the server, all clients currently connected, who are listening to the subject "MessageListener" will receive the message. It's as simple as that.
10
Relay Services
software engineers will likely find the prospects of such communication appealing, so this section will provide some basic pointers on how to go about accomplishing it.
MessageBuilder.createConversation(msg) .toSubject("FunSubject") .signalling() .noErrorHandling() .replyDelayed(TimeUnit.SECONDS, 5); // sends the message after 5 seconds.
or
MessageBuilder.createMessage() .toSubject("FunSubject") .signalling() .noErrorHandling() .sendDelayed(requestDispatcher, TimeUnit.SECONDS, 5); // sends the message after 5 seconds.
11
Chapter 2. Messaging
MessageBuilder.createMessage() .toSubject("FunSubject") .signalling() .withProvided("time", new ResourceProvider<String>() { SimpleDateFormat fmt = new SimpleDateFormat("hh:mm:ss"); public String get() { return fmt.format(new Date(System.currentTimeMillis()); } } .noErrorHandling() .sendRepeatingWith(requestDispatcher, TimeUnit.SECONDS, 1); //sends a message every 1 second
The above example sends a message very 1 second with a message part called "time" , containing a formatted time string. Note the use of the withProvided() method; a provided message part is calculated at the time of transmission as opposed to when the message is constructed. Cancelling an Asynchronous TaskA delayed or repeating task can be cancelled by calling the cancel() method of the AsyncTask instance which is returned when creating a task. Reference to the AsyncTask object can be retained and cancelled by any other thread.
AsyncTask task = MessageBuilder.createConversation(message) .toSubject("TimeChannel").signalling() .withProvided(TimeServerParts.TimeString, new ResourceProvider<String>() { public String get() { return String.valueOf(System.currentTimeMillis()); } }).defaultErrorHandling().replyRepeating(TimeUnit.MILLISECONDS, 100); ... // cancel the task and interrupt it's thread if necessary. task.cancel(true);
12
In the above examples, assuming that the latter example is inside a service called " ObjectService " and is referencing the incoming message that was sent in the former example, the message created will automatically reference the ReplyTo subject that was provided by the sender, and send the message back to the subject desired by the client on the client that sent the message.
You can extract the SessionID from a message so that you may use it for routing by obtaining the QueueSession resource from the Message . For example:
13
Chapter 2. Messaging
... public void callback(Message message) { QueueSession sess = message.getResource(QueueSession.class, Resources.Session.name()); String sessionId = sess.getSessionId(); // Record this sessionId somewhere. ... }
The SessionID can then be stored in a medium, say a Map, to cross-reference specific users or whatever identifier you wish to allow one client to obtain a reference to the specific SessionID of another client. In which case, you can then provide the SessionID as a MessagePart to indicate to the bus where you want the message to go.
MessageBuilder.createMessage() .toSubject("ClientMessageListener") .signalling() .with(MessageParts.SessionID, sessionId) .with("Message", "We're relaying a message!") .noErrorHandling().sendNowWith(dispatcher);
By providing the SessionID part in the message, the bus will see this and use it for routing the message to the relevant queue. It may be tempting however, to try and include destination SessionIDs at the client level, assuming that this will make the infrastructure simpler. But this will not achieve the desired results, as the bus treats SessionIDs as transient. Meaning, the SessionID information is not ever transmitted from bus-to-bus, and therefore is only directly relevant to the proximate bus.
2.13.1. Lifecycle
The lifescyle of a session is bound by the underlying HTTP session. It is also bound by activity thresholds. Clients are required to send heartbeat messages every once in a while to maintain their sessions with the server. If a heartbeat message is not received after a certain period of time, the session is terminated and any resources are deallocated.
14
Scopes
2.13.2. Scopes
One of the things Errai offers is the concept of session and local scopes.
public class TestService implements MessageCallback { public void callback(final Message message) { // obtain a reference to the session context by referencing the incoming message. SessionContext injectionContext = SessionContext.get(message); // set an attribute. injectionContext.setAttribute("MyAttribute", "Foo"); } }
public class TestService implements MessageCallback { public void callback(final Message message) { // obtain a reference to the local context by referencing the incoming message. LocalContext injectionContext = LocalContext.get(message); // set an attribute. injectionContext.setAttribute("MyAttribute", "Foo"); } }
15
Chapter 2. Messaging
2.14. Client Logging and Error Handling 2.15. Wire Protocol (J.REP)
ErraiBus implements a JSON-based wire protocol which is used for the federated communication between different buses. The protocol specification encompasses a standard JSON payload structure, a set of verbs, and an object marshalling protocol. The protocol is named J.REP. Which stands for JSON Rich Event Protocol.
In Figure 1 , we see an example of a J.REP payload containing two messages. One bound for an endpoint named "SomeEndpoint" and the other bound for the endpoint "SomeOtherEndpoint" . They both include a payload element "Value" which contain strings. Let's take a look at the anatomy of an individual message.
The message shown in Figure 2 shows a very vanilla J.REP message. The keys of the JSON Object represent individual message parts , with the values representing their corresponding values. The standard J.REP protocol encompasses a set of standard message parts and values, which for the purposes of this specification we'll collectively refer to as the protocol verbs. The following table describes all of the message parts that a J.REP capable client is expected to understand:
16
Payload Structure
Part
ToSubject
Required Yes
Description Specifies the subject within the bus, and its federation, which the message should be routed to.
CommandType
No
String
Specifies a command verb to be transmitted to the receiving subject. This is an optional part of a message contract, but is required for using management services
ReplyTo
No
String
Specifies to the receiver what subject it should reply to in response to this message.
Value
No
Any
A recommended but not required standard payload sending services part data for to
PriorityProcessing
No
Number
A processing order salience attribute. Messages which specify priority processing will be processed first if they are competing for resources with other messages in flight. Note: the current version of ErraiBus only supports two salience levels (0 and >1). Any non-zero salience in ErraiBus will be given the same priority relative to 0 salience messages
17
Chapter 2. Messaging
Part
ErrorMessage
Required No
Throwable
No
Object
If applicable, an encoded object representing any remote exception that was thrown while dispatching the specified service
Description The self-hosted message bus endpoint on the client The self-hosted message bus endpoint on the server The standard error receiving service for clients
ServerBus
ClientBusErrors
As this table indicates, the bus management protocols in J.REP are accomplished using selfhosted services. See the section on Bus Management and Handshaking Protocols for details.
18
Description The first message sent by a connecting client to begin the handshaking process. A message sent by one bus to another to notify it of its capabilities during handshake (for instance long polling or websockets)
CapabilitiesNotice
CapabilitiesFlags
FinishStateSync
N/A
A message sent from one bus to another to indicate that it has now provided all necessary information to the counter-party bus to establish the federation. When both buses have sent this message to each other, the federation is considered active.
RemoteSubscribe
Subject or SubjectsList
A message sent to the remote bus to notify it of a service or set of services which it is capable of routing to.
RemoteUnsubscribe
Subject
A message sent to the remote bus to notify it that a service is no longer available. A message sent to a server bus from a client bus to indicate that it wishes to disconnect and defederate. Or, when sent from the client
Disconnect
Reason
19
Chapter 2. Messaging
Command / Verb
Message Parts
SessionExpired
N/A
A message sent to a client bus to indicate that its messages are no longer being routed because it no longer has an active session
Heartbeat
N/A
A message sent from one bus to another periodically to indicate it is still active.
Part
CapabilitiesFlags
Required Yes
Subject
Yes
String
to or
SubjectsList
Yes
Array
2.16. WebSockets
ErraiBus has support for WebSocket-based communication. When WebSockets are enabled, capable web browsers will attempt to upgrade their COMET-based communication with the serverside bus to use a WebSocket channel. There are two different ways the bus can enable WebSockets. The first uses a sideband server, which is a small, lightweight server which runs on a different port from the application server. The second is native JBoss AS 7-based integration.
errai.bus.enable_web_socket_server=true
20
The default port for the sideband server is 8085 . You can change this by specifying a port with the errai.bus.web_socket_port property in the ErraiService.properties file.
default-virtual-server="default-
to:
default-virtual-server="default-
You will then need to configure the servlet in your application's web.xml which will provide WebSocket upgrade support within AS7. Add the following to the web.xml :
This will tell the bus to enable web sockets support. The websocket-path-element specified the path element within a URL which the client bus should request in order to negotiate a websocket connection. For instance, specifying in.erraiBusWS as we have in the snippit above, will result in attempted negotiation at http://<your_server>:<your_port>/<context_path>/ in.erraiBusWS . For this to have any meaningful result, we must add a servlet mapping that will match this pattern:
21
Chapter 2. Messaging
<servlet> <servlet-name>ErraiWSServlet</servlet-name> <servlet-class>org.jboss.errai.bus.server.servlet.JBossAS7WebSocketServlet</ servlet-class> <init-param> <param-name>service-locator</param-name> <param-value>org.jboss.errai.cdi.server.CDIServiceLocator</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>ErraiWSServlet</servlet-name> <url-pattern>*.erraiBusWS</url-pattern> </servlet-mapping>
22
Chapter 3.
Dependency Injection
The core Errai IOC module implements the JSR-330 Dependency Injection [http:// specification for download.oracle.com/otndocs/jcp/dependency_injection-1.0-final-oth-JSpec/] in-client component wiring.
Dependency injection (DI) allows for cleaner and more modular code, by permitting the implementation of decoupled and type-safe components. By using DI, components do not need to be aware of the implementation of provided services. Instead, they merely declare a contract with the container, which in turn provides instances of the services that component depends on.
A simple example:
public class MyLittleClass { private final TimeService timeService; @Inject public MyLittleClass(TimeService timeService) { this.timeService = timeService; } public void printTime() { System.out.println(this.timeService.getTime()); } }
In this example, we create a simple class which declares a dependency using @Inject [http://download.oracle.com/javaee/6/api/javax/inject/Inject.html] for the interface TimeService . In this particular case, we use constructor injection to establish the contract between the container and the component. We can similarly use field injection to the same effect:
23
In order to inject TimeService , you must annotate it with @ApplicationScoped or the Errai DI container will not acknowledge the type as a bean.
Best Practices
Although field injection results in less code, a major disadvantage is that you cannot create immutable classes using the pattern, since the container must first call the default, no argument constructor, and then iterate through its injection tasks, which leaves the potential albeit remote that the object could be left in an partially or improperly initialized state. The advantage of constructor injection is that fields can be immutable (final), and invariance rules applied at construction time, leading to earlier failures, and the guarantee of consistent state.
24
Container Wiring
org.jboss.errai.ioc.client.api.builtin.RequestDispatchProvider instance of the RequestDispatcher available for injection. org.jboss.errai.ioc.client.api.builtin.ConsumerProvider Consumer<?> objects available for injection.
:
: Makes an
Makes
event
Implementing a Provider is relatively straight-forward. Consider the following two classes: TimeService.java
TimeServiceProvider.java
@IOCProvider @Singleton public class TimeServiceProvider implements Provider<TimeService> { @Override public TimeService get() { return new TimeService() { public String getTime() { return "It's midnight somewhere!"; } }; } }
If you are familiar with Guice, this is semantically identical to configuring an injector like so:
As shown in the above example code, the annotation @IOCProvider is used to denote top-level providers. The classpath will be searched for all annotated providers at compile time.
25
Important
Top-level providers are treated as regular beans. And as such may inject dependencies particularly from other top-level providers as necessary.
3.3. Scopes
Out of the box, the IOC container supports three bean scopes, @Dependent , @Singleton and @EntryPoint . The singleton and entry-point scopes are roughly the same semantics.
public void MyDependentScopedBean { private final Date createdDate; public MyDependentScopedBean { createdDate = new Date(); } }
26
Built-in Extensions
Availability of BeanManager
dependent
beans
in
the
client-side
As is mentioned in the bean manager documentation [32] , only beans that are explicitly scoped will be made available to the bean manager for lookup. So while it is not necessary for regular injection, you must annotate your dependent scoped beans with @Dependent if you wish to dynamically lookup these beans at runtime.
3.4.1.1. @Service
The org.jboss.errai.bus.server.annotations.Service annotation is used for binding service endpoints to the bus. Within the Errai IOC container you can annotate services and have them published to the bus on the client (or on the server) in a very straight-forward manner:
@Service public class MyService implements MessageCallback { public void callback(Message message) { // ... // } }
27
Or like so ...
@Singleton public class MyAppBean { @Service("MyService") private final MessageCallback myService = new MesageCallback() { public void callback(Message message) { // ... // } } }
As with server-side use of the annotation, if a service name is not explicitly specified, the underlying class name or field name being annotated will be used as the service name.
3.4.1.2. @Local
The org.jboss.errai.bus.server.api.Local annotation is used in conjunction with the @Service annotation to advertise a service only for visibility on the local bus and thus, cannot receive messages across the wire for the service.
@Service @Local public class MyLocalService implements MessageCallback { public void callback(Message message) { // ... // } }
28
Client Components
3.4.2.1. MessageBus
The type org.jboss.errai.bus.client.framework.MessageBus is globally injectable into any bean. Injecting this type will provide the instance of the active message bus running in the client.
3.4.2.2. RequestDispatcher
The type org.jboss.errai.bus.client.framework.RequestDispatcher is globally injectable into any bean. Injecting this type will provide a RequestDispatcher instance capable of delivering any messages provided to it, to the the MessageBus .
3.4.2.3. Caller<?>
The type org.jboss.errai.ioc.client.api.Caller<?> is a globally injectable RPC proxy. RPC proxies may be provided by various components. For example, JAX-RS or Errai RPC. The proxy itself is agnostic to the underlying RPC mechanism and is qualified by it's type parameterization. For example:
public void MyClientBean { @Inject private Caller<MyRpcInterface> rpcCaller; // ... /// @UiHandler("button") public void onButtonClick(ClickHandler handler) { rpcCaller.call(new RemoteCallback<Void>() { public void callback(Void void) {
29
} ).callSomeMethod(); } }
The above code shows the injection of a proxy for the RPC remote interface, MyRpcInterface . For more information on defining RPC proxies see Chapter 6, Remote Procedure Calls (RPC) and Section 7.2, Creating Requests in Errai JAX-RS.
@Singleton public class MyClientBean { @Inject InitBallot<MyClientBean> ballot; @PostConstruct public void doStuff() { // ... do some work ... ballot.voteForInit(); } }
30
@Singleton public class MyClientBean { @AfterInitialization public void doStuffAfterInit() { // ... do some work ... } }
If you need to access the bean manager outside a managed bean, such as in a unit test, you can access it by calling org.jboss.errai.ioc.client.container.IOC.getBeanManager()
31
public void lookupBean() { IOCBean<SimpleBean> bean = manager.lookupBean(SimpleBean.class); // check to see if the bean exists if (bean != null) { // get the instance of the bean SimpleBean inst = bean.getInstance(); } } }
In this example we lookup a bean class named SimpleBean . This example will succeed assuming that SimpleBean is unambiguous. If the bean is ambiguous and requires qualification, you can do a qualified lookup like so:
MyQualifier qual = new MyQualifier() { public annotationType() { return MyQualifier.class; } } MyOtherQualifier qual2 = new MyOtherQualifier() { public annotationType() { return MyOtherQualifier.class; } } // pass qualifiers to IOCBeanManager.lookupBean IOCBean<SimpleInterface> bean = beanManager.lookupBean(SimpleBean.class, qual, qual2);
In this example we manually construct instances of qualifier annotations in order to pass it to the bean manager for lookup. This is a necessary step since there's currently no support for annotation literals in Errai client code.
32
and
This code is unaware of the implementation of View , which maintains good separation of concerns. However, this of course creates an ambiguous dependency on the View interface as it has two matching subtypes in this case. Thus, we must configure the container to specify which alternative to use. Also note, that the beans in both cases have been annotated with javax.enterprise.inject.Alternative .
33
In your ErraiApp.properties for the module, you can simply specify which active alternative should be used:
errai.ioc.enabled.alternatives=org.foo.MobileView
You can specify multiple alternative classes by white space separating them:
You can only have one enabled alternative for a matching set of alternatives, otherwise you will get ambiguous resolution errors from the container.
@ApplicationScoped public class UserManagementImpl implements UserManagement { public List<User> listUsers() { // do user listy things! } }
You can specify a mock implementation of this class by implementing its common parent type ( UserManagement ) and annotating that class with the @TestMock annotation inside your test package like so:
@TestMock @ApplicationScoped public class MockUserManagementImpl implements UserManagement { public List<User> listUsers() { // return only a test user. return Collections.singletonList(TestUser.INSTANCE);
34
Bean Lifecycle
} }
In
this
case,
the
container
will
replace
the
UserManagementImpl
with
the
The @TestMock annotation can also be used to specify alternative providers during test execution. For example, it can be used to mock a Caller<T> . Callers are used to invoke RPC or JAX-RS endpoints. During tests you might want to replace theses callers with mock implementations. For details on providers see Section 3.1, Container Wiring .
@TestMock @IOCProvider public class MockedHappyServiceCallerProvider implements ContextualTypeProvider<Caller<HappySer @Override public Caller<HappyService> provide(Class<?>[] typeargs, Annotation[] qualifiers) { return new Caller<HappyService>() { ... } }
Important
This cannot be guaranteed when the browser DOM is destroyed prematurely due to: closing the browser window; closing a tab; refreshing the page, etc.
35
public MyManagedBean { @Inject IOCBeanManager manager; public void createABeanThenDestroyIt() { // get a new bean. SimpleBean bean = manager.lookupBean(SimpleBean.class).getInstance(); bean.sendMessage("Sorry, I need to dispose of you now"); // destroy the bean! manager.destroyBean(bean); } }
When the bean manager "destroys" the bean, any pre-destroy methods the bean declares are called, it is taken out of service and no longer tracked by the bean manager. If there are references on the bean by other objects, the bean will continue to be accessible to those objects.
Important
Container managed resources that are dependent on the bean such as bus service endpoints or CDI event observers will also be automatically destroyed when the bean is destroyed.
Another important consideration is the rule, "all beans created together are destroyed together." Consider the following example:
@Dependent public class SimpleBean { @Inject @New AnotherBean anotherBean; public AnotherBean getAnotherBean() { return anotherBean; } @PreDestroy private void cleanUp() { // do some cleanup tasks
36
Destruction of Beans
} }
public MyManagedBean { @Inject IOCBeanManager manager; public void createABeanThenDestroyIt() { // get a new bean. SimpleBean bean = manager.lookupBean(SimpleBean.class).getInstance(); // destroy the AnotherBean reference from inside the bean manager.destroyBean(bean.getAnotherBean()); } }
In this example we pass the instance of AnotherBean, created as a dependency of SimpleBean, to the bean manager for destruction. Because this bean was created at the same time as its parent, its destruction will also result in the destruction of SimpleBean ; thus, this action will result in the @PreDestroy cleanUp() method of SimpleBean being invoked.
3.7.1.1. Disposers
Another way which beans can be destroyed is through the use of the injectable org.jboss.errai.ioc.client.api.Disposer<T> class. The class provides a straight forward way of disposing of bean type. For instance:
public MyManagedBean { @Inject @New SimpleBean myNewSimpleBean; @Inject Disposer<SimpleBean> simpleBeanDisposer; public void destroyMyBean() { simpleBeanDisposer.dispose(myNewSimpleBean); } }
37
38
Chapter 4.
Errai CDI
CDI (Contexts and Dependency Injection) is the Jave EE standard (JSR-299) for handling dependency injection. In addition to dependency injection, the standard encompasses component lifecycle, application configuration, call-interception and a decoupled, type-safe eventing specification. The Errai CDI extension implements a subset of the specification for use inside of client-side applications within Errai, as well as additional capabilities such as distributed eventing. Errai CDI does not currently implement all life cycles specified in JSR-299 or interceptors. These deficiencies may be addressed in future versions.
Important
The Errai CDI extension itself is implemented on top of the Errai IOC Framework (see Chapter 3, Dependency Injection ), which itself implements the JSR-330 specification. Inclusion of the CDI module your GWT project will result in the extensions automatically being loaded and made available to your application.
1. There is no support for CDI interceptors in the client. Although this is planned in a future release. 2. Passivating scopes are not supported.
39
3. The JSR-299 SPI is not supported for client side code. Although writing extensions for the client side container is possible via the Errai IOC Extensions API. 4. The @Typed annotation is unsupported. 5. The @Interceptor annotation is unsupported. 6. The @Decorator annotation is unsupported.
4.2. Events
Any CDI managed component may produce and consume events [http://docs.jboss.org/weld/ reference/latest/en-US/html/events.html] . This allows beans to interact in a completely decoupled fashion. Beans consume events by registering for a particular event type and optional qualifiers. The Errai CDI extension simply extends this concept into the client tier. A GWT client application can simply register an Observer for a particular event type and thus receive events that are produced on the server-side. Likewise and using the same API, GWT clients can produce events that are consumed by a server-side observer. Let's take a look at an example.
public class FraudClient extends LayoutPanel { @Inject private Event<AccountActivity> event; (1) private HTML responsePanel; public FraudClient() { super(new BoxLayout(BoxLayout.Orientation.VERTICAL)); } @PostConstruct public void buildUI() { Button button = new Button("Create activity", new ClickHandler() { public void onClick(ClickEvent clickEvent) { event.fire(new AccountActivity()); } });
40
Conversational events
responsePanel = new HTML(); add(button); add(responsePanel); } public void processFraud(@Observes @Detected Fraud fraudEvent) { (2) responsePanel.setText("Fraud detected: " + fraudEvent.getTimestamp()); } }
Two things are noteworthy in this example: 1. Injection of an Event dispatcher proxy 2. Creation of an Observer method for a particular event type The event dispatcher is responsible for sending events created on the client-side to the serverside event subsystem (CDI container). This means any event that is fired through a dispatcher will eventually be consumed by a CDI managed bean, if there is an corresponding Observer registered for it on the server side. In order to consume events that are created on the server-side you need to declare an client-side observer method for a particular event type. In case an event is fired on the server this method will be invoked with an event instance of type you declared. To complete the example, let's look at the corresponding server-side CDI bean:
@ApplicationScoped public class AccountService { @Inject @Detected private Event<Fraud> event; public void watchActivity(@Observes AccountActivity activity) { Fraud fraud = new Fraud(System.currentTimeMillis()); event.fire(fraud); } }
41
@ApplicationScoped public class SubscriptionService { @Inject private Event<Documents> welcomeEvent; public void onSubscription(@Observes Subscription subscription) { Document docs = createWelcomePackage(subscription); welcomeEvent.fire(docs); } }
As such, when Document events are fired, they will be limited in scope to the initiating conversational contents which are implicitly inferred by the caller. So only the client which fired the Subscription event will receive the fired Document event.
42
public void myClientObserver(@Observes MyRequestEvent event) { MyResponseEvent response; if (event.isThankYou()) { // aww, that's nice! response = new MyResponseEvent("Well, you're welcome!"); } else { // how rude! response = new MyResponseEvent("What? Nobody says 'thank you' anymore?"); } myResponseEvent.fire(response); } }
Domain-model:
@Portable public class MyRequestEvent { private boolean thankYou; public MyRequestEvent(boolean thankYou) { setThankYou(thankYou); } public void setThankYou(boolean thankYou) { this.thankYou = thankYou; } public boolean isThankYou() { return thankYou; } }
43
public MyRequestEvent(String message) { setMessage(message); } public void setMessage(String message) { this.message = message; } public String getMessage() { return message; } }
@EntryPoint public class MyClientBean { @Inject Event<MyRequestEvent> requestEvent; public void myResponseObserver(@Observes MyResponseEvent event) { Window.alert("Server replied: " + event.getMessage()); } @PostConstruct public void init() { Button thankYou = new Button("Say Thank You!"); thankYou.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { requestEvent.fire(new MyRequestEvent(true)); } } Button nothing = new Button("Say nothing!"); nothing.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { requestEvent.fire(new MyRequestEvent(false)); } } VerticalPanel vPanel = new VerticalPanel(); vPanel.add(thankYou); vPanel.add(nothing);
44
Producers
RootPanel.get().add(vPanel); } }
4.3. Producers
Producer methods and fields act as sources of objects to be injected. They are useful when additional control over object creation is needed before injections can take place e.g. when you need to make a decision at runtime before an object can be created and injected.
@EntryPoint public class App { ... @Produces @Supported private MyBaseWidget createWidget() { return (Canvas.isSupported()) ? new MyHtml5Widget() : new MyDefaultWidget(); } }
@ApplicationScoped public class MyComposite extends Composite { @Inject @Supported private MyBaseWidget widget; ... }
Producers can also be scoped themselves. By default, producer methods are dependent-scoped, meaning they get called every time an injection for their provided type is requested. If a producer method is scoped @Singleton for instance, the method will only be called once, and the bean manager will inject the instance from the first invokation of the producer into every matching injection point.
45
public class App { ... @Produces @Singleton private MyBean produceMyBean() { return new MyBean(); } }
For more information on CDI producers, see the CDI specification [http://docs.jboss.org/ cdi/spec/1.0/html/] and the WELD reference documentation [http://seamframework.org/Weld/ WeldDocumentation] .
public class Foo { @Inject Instance<Bar> barInstance; public void pingNewBar() { Bar bar = barInstance.get(); bar.ping(); } }
In this example, calling barInstance.get() returns a new instance of the dependent-scoped bean Bar .
46
Typically a GWT application lifecycle begins in Development Mode [http://code.google.com/ webtoolkit/doc/latest/DevGuideCompilingAndDebugging.html] and finally a web application containing the GWT client code will be deployed to a target container (Servlet Engine, Application Server). This is no way different when working with CDI components to back your application. What's different however is availability of the CDI container across the different runtimes. In GWT development mode and in a pure servlet environment you need to provide and bootstrap the CDI environment on your own. While any Java EE 6 Application Server already provides a preconfigured CDI container. To accomodate these differences, we need to do a little trickery when executing the GWT Development Mode and packaging our application for deployment.
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>gwt-maven plugin</artifactId> <version>${gwt.maven}</version> <configuration> ... <server>org.jboss.errai.cdi.server.gwt.JettyLauncher</server> </configuration> <executions> ... </executions> </plugin>
Once this is set up correctly, we can bootstrap the CDI container through a servlet listener:
<web-app> ...
47
<listener> <listener-class>org.jboss.errai.container.CDIServletStateListener</listenerclass> </listener> <resource-env-ref> <description>Object factory for the CDI Bean Manager</description> <resource-env-ref-name>BeanManager</resource-env-ref-name> <resource-env-ref-type>javax.enterprise.inject.spi.BeanManager</resourceenv-ref-type> </resource-env-ref> ... </web-app>
48
Chapter 5.
Marshalling
Errai includes a comprehensive marshalling framework which permits the serialization of domain objects between the browser and the server. From the perspective of GWT, this is a complete replacement for the provided GWT serialization facilities and offers a great deal more flexibility. You are be able to map both application-specific domain model, as well as preexisting model, including model from third-party libraries using the custom definitions API.
If an entity type has a field called foo , then that entity has a property called foo unless the field is marked static or transient . Note that the existence of methods called getFoo() , setFoo() , or both, does not mean that the entity has a property called foo . Errai Marshalling always works from fields when discovering properties. When reading a field foo , Errai Marshalling will call the method getFoo() in preference to direct field access if the getFoo() method exists. Similarly, when writing a field foo , Errai Marshalling will call the method setFoo() in preference to direct field access if the setFoo() method exists.
49
Chapter 5. Marshalling
The above rules are sufficient for marshalling an existing entity to a JSON representation, but for de-marshalling, Errai must also know how to obtain an instance of a type. The rules that Errai uses for deciding how to create an instance of a @Portable type are as follows: If the entity has a public constructor where every argument is annotated with @MapsTo , and those parameters cover all properties of the entity type, then Errai uses this constructor to create the object, passing in all of the property values. Otherwise, if the entity has a public static method where every argument is annotated with @MapsTo , and those parameters cover all properties of the entity type, then Errai uses this method to create the object. Note that when using this mechanism you are free to create and return a subtype of the marshalled type, or resolve one from a cache. If the entity has a public no-arguments constructor (or no explicit constructors at all), it will be created via that constructor, and the properties will be written to the new object one at a time. Each property will be written by its setter method, or by direct field access if a setter method is not available. Now let's take a look at some common examples of how this works.
@Portable public class Person { private String name; private int age; public Person() { } public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } }
This is a pretty vanilla domain object. Note the default, public, no-argument constructor. In this case, it will be necessary to have one explicitly declared. But notice we have no setters. In
50
this case, the marshaler will rely on private field access to write the values on each side of the marshalling transaction. For simple domain objects, this is both nice and convenient. But you may want to make the class immutable and have a constructor enforce invariance. See the next section for that.
@Portable public class Person { private final String name; private final int age; public Person(@MapsTo("name") String name, @MapsTo("age") int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } }
Here we have set both of the class fields final. By doing so, we had to remove our default constructor. But that's okay, because we have annotated the remaining constructor's parameters using the org.jboss.errai.marshalling.client.api.annotations.MapsTo annotation. By doing this, we have told the marshaling system, for instance, that the first parameter of the constructor maps to the property name . Which in this case, defaults to the name of the corresponding field. This may not always be the case as will be explored in the section on custom definitions. But for now that's a safe assumption.
51
Chapter 5. Marshalling
@Portable public class Person { private final String name; private final int age; private Person(String name, int age) { this.name = name; this.age = age; } public static Person createPerson(@MapsTo("name") String name, @MapsTo("age") int age) { return new Person(name, age); } public String getName() { return name; } public int getAge() { return age; } }
Here we have made our only declared constructor private, and created a static factory method. Notice that we've simply used the same @MapsTo annotation in the same way we did on the constructor from our previous example. The marshaller will see this method and know that it should use it to construct the object.
@Portable public class Person { private final String name; private final int age; private Person(@MapsTo("name") String name, @MapsTo("age") int age) { this.name = name; this.age = age; } public String getName() { return name; }
52
Manual Mapping
public int getAge() { return age; } @NonPortable public static class Builder { private String name; private int age; public Builder name(String name) { this.name = name; return this; } public Builder age(int age) { this.age = age; return this; } public BuilderEntity build() { return new Person(name, age); } } }
In this example, we have a nested Builder class that implements the Builder Pattern and calls the private Person constructor. Hand-written code will always use the builder to create Person instances, but the @MapsTo annotations on the private Person constructor tell Errai Marshalling to bypass the builder and construct instances of Person directly. One final note: as a nested type of Person (which is marked @Portable ), the builder itself would normally be portable. However, we do not intend to move instances of Person.Builder across the network, so we mark Person.Builder as @NonPortable .
53
Chapter 5. Marshalling
If any of the serializable types have nested classes that you wish to make non-portable, you can specify them like this:
errai.marshalling.nonserializableTypes=org.foo.client.UserEntity$Builder \ org.foo.client.GroupEntity$Builder
54
In the case of this example, the marshaller will not attempt to comprehend your class. Instead, it will merely rely on the java.util.List marshaller to dematerialize and serialize instances of this type onto the wire. If for some reason it is not feasible to annotate the class, directly, you may specify the mapping in the ErraiApp.properties file using the errai.marshalling.mappingAliases attribute.
errai.marshalling.mappingAliases=org.foo.client.MyListImpl->java.util.List \ org.foo.client.MyMapImpl->java.util.Map
The list of classes is whitespace-separated so that it may be split across lines. The example above shows the equivalent mapping for the MyListImpl class from the previous example, as well as a mapping of a class to the java.util.Map marshaller. The syntax of the mapping is as follows: <class_to_map> -> <contract_to_map_to> .
5.1.3.1. MappingDefinition
All extend the org.jboss.errai.marshalling.rebind.api.model.MappingDefinition class. This is base metadata class which contains data on exactly how the marshaller can deconstruct and construct objects. Consider the following class: manual mappings should
55
Chapter 5. Marshalling
public class MySuperCustomEntity { private final String mySuperName; private String mySuperNickname; public MySuperCustomEntity(String mySuperName) { this.mySuperName = mySuperName;; } public String getMySuperName() { return this.mySuperName; } public void setMySuperNickname(String mySuperNickname) { this.mySuperNickname = mySuperNickname; } public String getMySuperNickname() { return this.mySuperNickname; } }
It is clear that we may rely on this object's two getter methods to extract the totality of its state. But due to the fact that the mySuperName field is final, the only way to properly construct this object is to call its only public constructor and pass in the desired value of mySuperName . Let us consider how we could go about telling the marshalling framework to pull this off:
@CustomMapping public MySuperCustomEntityMapping extends MappingDefinition { public MySuperCustomEntityMapping() { super(MySuperCustomEntity.class); (1) SimpleConstructorMapping cnsMapping = new SimpleConstructorMapping(); cnsMapping.mapParmToIndex("mySuperName", 0, String.class); (2)
//
//
56
Custom Marshallers
setInstantiationMapping(cnsMapping); addMemberMapping(new WriteMapping("mySuperNickname", String.class"setMySuperNickname")); , // (3) addMemberMapping(newReadMapping("mySuperName",String.class,"getMySuperName")); // (4) addMemberMapping(new ReadMapping("mySuperNickname", String.class"getMySuperNickname")); , // (5) } }
And that's it. This describes to the marshalling framework how it should go about constructing and deconstructing MySuperCustomEntity . Paying attention to our annotating comments, let's describe what we've done here.
1. Call the constructor in MappingDefinition passing our reference to the class we are mapping. 2. Using the SimpleConstructorMapping class, we have indicated that a custom constructor will be needed to instantiate this class. We have called the mapParmToIndex method with three parameters. The first, "mySupername" describes the class field that we are targeting. The second parameter, the integer 0 indicates the parameter index of the constructor arguments that we'll be providing the value for the aforementioned field in this case the first and only, and the final parameter String.class tells the marshalling framework which marshalling contract to use in order to de-marshall the value. 3. Using the WriteMapping class, we have indicated to the marshaller framework how to write the "mySuperNickname" field, using the String.class marshaller, and using the setter method setMySuperNickname . 4. Using the ReadMapping class, we have indicated to the marshaller framework how to read the "mySuperName" field, using the String.class marshaller, and using the getter method getMySuperName . 5. Using the ReadMapping class, we have indicated to the marshaller framework how to read the
"mySuperNickname" field, using the String.class marshaller, and using the getter method getMySuperNickname .
57
Chapter 5. Marshalling
Consider the included java.util.Date marshaller that comes built-in to the marshalling framework:
@ClientMarshaller @ServerMarshaller public class DateMarshaller extends AbstractNullableMarshaller<Date> { @Override public Class<Date> getTypeHandled() { return Date.class; } @Override public Date demarshall(EJValue o, MarshallingSession ctx) { // check if the JSON element is null if (o.isNull() != null) { // if the JSON element is null, so is our object! return null; }
// instantiate our Date! return new Date(Long.parseLong(o.isObject().get(SerializationParts.QUALIFIED_VALUE).isStrin } @Override public String marshall(Date o, MarshallingSession ctx) { // if the object is null, we encode "null" if (o == null) { return "null"; } // return the JSON representation of the object return "{\"" + SerializationParts.ENCODED_TYPE + "\": \"" + Date.class.getName() + "\"," + "\"" + SerializationParts.OBJECT_ID + "\":\"" + o.hashCode() + "\"," + "\"" + SerializationParts.QUALIFIED_VALUE + "\": \"" + o.getTime() + "\"}"; } }
The class is annotated with both @ClientMarshaller and @ServerMarshaller indicating that this class should be used for both marshalling on the client and on the server. The demarshall() method does what its name implies: it is responsible for demarshalling the object from JSON and turning it back into a Java object. The marshall() method does the opposite, and encodes the object into JSON for transmission on the wire.
58
Chapter 6.
The @Remote annotation tells Errai that we'd like to use this interface as a remote interface. The remote interface must be part of of the GWT client code. It cannot be part of the server-side code, since the interface will need to be referenced from both the client and server side code. That said, the implementation of a service is relatively simple to the point:
@Service public class MyRemoteServiceImpl implements MyRemoteService { public boolean isEveryoneHappy() { // blatently lie and say everyone's happy. return true; } }
That's all there is to it. You use the same @Service annotation as described in Section 2.4. The presence of the remote interface tips Errai off as to what you want to do with the class.
59
MessageBuilder.createCall(new RemoteCallback<Boolean>() { public void callback(Boolean isHappy) { if (isHappy) Window.alert("Everyone is happy!"); } }, MyRemoteService.class).isEveryoneHappy();
In the above example, we declare a remote callback that receives a Boolean, to correspond to the return value of the method on the server. We also reference the remote interface we are calling, and directly call the method. However, don't be tempted to write code like this :
The above code will never return a valid result. In fact, it will always return null, false, or 0 depending on the type. This is due to the fact that the method is dispatched asynchronously, as in, it does not wait for a server response before returning control. The reason we chose to do this, as opposed to emulate the native GWT-approach, which requires the implementation of remote and async interfaces, was purely a function of a tradeoff for simplicity.
For calling the remote service, the callback objects need to be provided to the call method before the corresponding interface method is invoked.
remoteService.call(callback).isEveryoneHappy();
MessageBuilder.createCall(
60
Client-side Interceptors
new RemoteCallback<Boolean>() { public void callback(Boolean isHappy) { if (isHappy) Window.alert("Everyone is happy!"); } }, new ErrorCallback() { public boolean error(Message message, Throwable caught) { try { throw caught; } catch (NobodyIsHappyException e) { Window.alert("OK, that's sad!"); } catch (Throwable t) { GWT.log("An unexpected error has occurred", t); } return false; } }, MyRemoteService.class).isEveryoneHappy();
As remote exceptions need to be serialized to be sent to the client, the @Portable annotation needs to be present on the corresponding exception class (see Chapter 5, Marshalling ). Further the exception class needs to be part of the client-side code. For more details on ErrorCallbacks see Section 2.4, Handling Errors .
Note that an ordered list of interceptors can be used for specifying an interceptor chain e.g.
61
public class MyCacheInterceptor implements RpcInterceptor { @Override public void aroundInvoke(final RemoteCallContext context) { // e.g check if the result is cached and carry out the actual call only in case it's not. context.proceed() // executes the next interceptor in the chain or the actual remote call. // context.setResult() // sets the result directly without carrying out the remote call. } }
The RemoteCallContext passed to the aroundInvoke method provides access to the intercepted method's name and read/write access to the parameter values provided at the call site. Calling proceed executes the next interceptor in the chain or the actual remote call if all interceptors have been executed. If access to the result of the (asynchronous) remote call is needed in the interceptor, one of the overloaded versions of this method accepting a RemoteCallback has to be used. The result of the remote call can be manipulated by calling RemoteCallContext.setResult() Not calling proceed in the interceptor bypasses the actual remote call, passing RestCallContext.getResult() to the RemoteCallBack provided at the call site.
@Service public class MyRemoteServiceImpl implements MyRemoteService { public boolean isEveryoneHappy() { HttpSession session = RpcContext.getHttpSession(); ServletRequest request = RpcContext.getServletRequest();
62
63
64
Chapter 7.
Errai JAX-RS
JAX-RS (Java API for RESTful Web Services) is a Java EE standard (JSR-311) for implementing REST-based Web services in Java. Errai JAX-RS brings this standard to the browser and simplifies the integration of REST-based services in GWT client applications. Errai can generate proxies based on JAX-RS interfaces which will handle all the underlying communication and serialization logic. All that's left to do is to invoke a Java method. Errai's JAX-RS support consists of the following: The Caller<T> interface (the same interface used in Errai RPC) A client-side API to communicate with JAX-RS endpoints A code generator that runs at your project's build time, providing proxy implementations for each JAX-RS resource class visible within the GWT module Errai IoC and CDI providers that allow you to @Inject instances of Caller<T> Integration with either Errai Marshalling or Jackson to translate request and response data between Java object and a string-based wire format If you want to get started right away with a working Errai JAX-RS CRUD application, use our Maven archetype to get started. See the Quickstart Guide [https://docs.jboss.org/author/pages/ viewpage.action?pageId=5833096] for details.
65
project src main java com.mycompany.myapp MyApp.gwt.xml [the app's GWT module] com.mycompany.myapp.client.local MyAppClientStuff.java [code that @Injects Caller<MyAppRestResource>] com.mycompany.myapp.client.shared CustomerService.java [the JAX-RS interface] com.mycompany.myapp.server CustomerServiceImpl.java [the server-side JAX-RS resource implementation] The contents of the server-side files would be as follows:
@Path("customers") public interface CustomerService { @GET @Produces("application/json") public List<Customer> listAllCustomers(); @POST @Consumes("application/json") @Produces("text/plain") public long createCustomer(Customer customer); }
66
Creating Requests
The above interface is visible both to server-side code and to client-side code. It is used by clientside code to describe the available operations, their parameter types, and their return types. If you use your IDE's refactoring tools to modify this interface, both the server-side and client-side code will be updated automatically.
public class CustomerServiceImpl implements CustomerService { @Override public List<Customer> listAllCustomers() { // Use a database API to look up all customers in back-end data store // Return the resulting list } @Override public long createCustomer(Customer customer) { // Store new Customer instance in back-end data store } }
The above class implements the shared interface. Since it performs database and/or filesystem operations to manipulate the persistent data store, it is not GWT translatable, and it's therefore kept in a package that is not part of the GWT module.
67
... Button create = new Button("Create", new ClickHandler() { public void onClick(ClickEvent clickEvent) { Customer customer = new Customer(firstName, lastName, postalCode); RestClient.create(CustomerService.class, callback).createCustomer(customer); } }); ...
For details on the callback mechanism see Section 7.3, Handling Responses .
Note
The JAX-RS interfaces need to be visible to the GWT compiler and must therefore reside within the client packages (e.g. client.shared).
To create a request, the callback objects need to be provided to the call method before the corresponding interface method is invoked.
customerService.call(callback).listAllCustomers();
RemoteCallback<Long> callback = new RemoteCallback<Long>() { public void callback(Long id) { Window.alert("Customer created with ID: " + id);
68
Handling Responses
} };
A special case of this RemoteCallback is the ResponseCallback which provides access to the
Response object representing the underlying HTTP response. This is useful when more details of
the HTTP response are needed, such as headers, the status code, etc. This ResponseCallback can be provided as an alternative to the RemoteCallback for the method result.
ResponseCallback callback = new ResponseCallback() { public void callback(Response response) { Window.alert("HTTP status code: " + response.getStatusCode()); Window.alert("HTTP response body: " + response.getText()); } };
For handling errors, Errai's error callback mechanism can be reused and an instance of ErrorCallback can optionally be passed to the RestClient.create() call. In case of an HTTP error, the ResponseException provides access to the Response object. All other Throwables indicate a communication problem.
ErrorCallback errorCallback = new ErrorCallback() { public boolean error(Message message, Throwable throwable) { try { throw throwable; } catch (ResponseException e) { Response response = e.getResponse(); // process unexpected response response.getStatusCode(); } catch (Throwable t) { // process unexpected error (e.g. a network problem) } return false; } };
69
avoiding the request when the data is cached locally adding special HTTP headers or parameters to the request To have a JAX-RS remote call intercepted, either an interface method or the remote interface type has to be annotated with @InterceptedCall . If the type is annotated, all interface methods will be intercepted.
@Path("customers") public interface CustomerService { @GET @Path("/{id}") @Produces("application/json") @InterceptedCall(MyCacheInterceptor.class) public Customer retrieveCustomerById(@PathParam("id") long id); }
Note that an ordered list of interceptors can be used for specifying an interceptor chain e.g.
public class MyCacheInterceptor implements RestClientInterceptor { @Override public void aroundInvoke(final RestCallContext context) { RequestBuilder builder = context.getRequestBuilder(); builder.setHeader("headerName", "value"); context.proceed(); } }
70
Wire Format
The RestCallContext passed to the aroundInvoke method provides access to the context of the intercepted JAX-RS (REST) remote call. It allows to read and write the parameter values provided at the call site and provides read/write access to the RequestBuilder instance which has the URL, HTTP headers and parameters set. Calling proceed executes the next interceptor in the chain or the actual remote call if all interceptors have been executed. If access to the result of the (asynchronous) remote call is needed in the interceptor, one of the overloaded versions of this method accepting a RemoteCallback has to be used. The result of the remote call can be manipulated by calling RestCallContext.setResult() Not calling proceed in the interceptor bypasses the actual remote call, passing RestCallContext.getResult() to the RemoteCallBack provided at the call site.
71
}-*/;
or by simply invoking:
RestClient.setApplicationRoot("/MyJaxRsEndpointPath");
The root path will be prepended to all paths specified on the JAX-RS interfaces. It serves as the base URL for all requests sent from the client.
or by simply invoking:
RestClient.setJacksonMarshallingActive(true);
72
Chapter 8.
Errai JPA
Starting with Errai 2.1, Errai implements a subset of JPA 2.0. With Errai JPA, you can store and retrieve entity objects on the client side, in the browser's local storage. This allows the reuse of JPA-related code (both entity class definitions and procedural logic that uses the EntityManager) between client and server. Errai JPA implements the following subset of JPA 2.0:
Annotation-based configuration Entity Types with Identifiers of any numeric type (int, long, short, etc.) Generated identifiers Regular attributes of any JPA Basic type (Java primitive types, boxed primitives, enums, BigInteger, BigDecimal, String, Date, Time, and Timestamp) Singular and Plural (collection-valued) attributes of other entity types All association types (one-to-one, one-to-many, many-to-one, many-to-many) All association cascade rules (ALL, PERSIST, MERGE, REMOVE, REFRESH, DETACH) Circular and self references work properly Property access by field or get/set methods Named, typed JPQL queries that select exactly one entity type With cascading fetch of related entities With or without WHERE clause All boolean, arithmetic, and string operators supported All String manipulation functions supported With or without ORDER BY clause Lifecycle events and entity lifecycle listeners Much of the Metamodel API ( Metamodel , EntityType , SingularAttribute , PluralAttribute , etc.)
73
If you are not using Maven for dependency management, add errai-jpa-client-version.jar , Hibernate 4.1.1, and Google Guava for GWT 12.0 to your compile-time classpath.
<inherits name="org.jboss.errai.jpa.JPA"/>
8.1.3. INF/persistence.xml
You need to have a META-INF/persistence.xml file on the classpath that defines a persistence unit. This persistence unit should declare every entity class you want to use with the client-side JPA provider. Example:
74
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> <persistence-unit name="ErraiJpaDemo"> <description>Entities used in the browser</description> <class>com.company.app.client.shared.Album</class> <class>com.company.app.client.shared.Artist</class> <class>com.company.app.client.shared.Genre</class> </persistence-unit> </persistence>
http://
@Entity public class Genre { @Id @GeneratedValue private int id; private String name; // This constructor is used by JPA public Genre() {} // This constructor is not used by JPA public Genre(String name) { this();
75
this.name = name; }
// These getter and Setter methods are optional: public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
76
@Entity public class Album { @GeneratedValue @Id private Long id; private String name; @ManyToOne private Artist artist; private Date releaseDate; private Format format; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Artist getArtist() { return artist; } public void setArtist(Artist artist) { this.artist = artist; } public Date getReleaseDate() { return releaseDate; } public void setReleaseDate(Date releaseDate) { this.releaseDate = releaseDate; } public Format getFormat() { return format; } public void setFormat(Format format) { this.format = format; } }
77
@Entity public class Artist { @Id private Long id; private String name; // a two-way relationship (albums refer back to artists) @OneToMany(mappedBy="artist", cascade=CascadeType.ALL) private Set<Album> albums = new HashSet<Album>(); // a one-way relationship (genres don't reference artists) @OneToMany(cascade={CascadeType.PERSIST, CascadeType.MERGE}) private Set<Genre> genres = new HashSet<Genre>(); public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<Album> getAlbums() { return albums; } public void setAlbums(Set<Album> albums) { this.albums = albums; } public Set<Genre> getGenres() { return genres; } public void setGenres(Set<Genre> genres) { this.genres = genres; } }
78
entities. To request cascading of entity state changes, use the cascade attribute on any of the relationship quantifiers @OneToOne , @ManyToOne , @OneToMany , and @ManyToMany .
CascadeType value
PERSIST
Description Persist the related entity object(s) when this entity is persisted Merge the attributes of the related entity object(s) when this entity is merged Remove the related entity object(s) from persistent storage when this one is removed Not applicable in Errai JPA Detach the related entity object(s) from the entity manager when this object is detached Equivalent to specifying all of the above
MERGE
REMOVE
REFRESH DETACH
ALL
For an example of specifying cascade rules, refer to the Artist example above. In that example, the cascade type on albums is ALL . When a particular Artist is persisted or removed, detached, etc., all of that artist's albums will also be persisted or removed, or detached correspondingly. However, the cascade rules for genres are different: we only specify PERSIST and MERGE . Because a Genre instance is reusable and potentially shared between many artists, we do not want to remove or detach these when one artist that references them is removed or detached. However, we still want the convenience of automatic cascading persistence in case we persist an Artist which references a new, unmanaged Genre .
79
If the entity references any related entities, these entities must be in the managed state already, or have cascade-on-persist enabled. If neither of these criteria are met, an IllegalStateException will be thrown. See an example in the following section.
// make it Album album = new Album(); album.setArtist(null); album.setName("Abbey Road"); album.setReleaseDate(new Date(-8366400000L)); // store it EntityManager em = getEntityManager(); em.persist(album); em.flush(); em.detach(album); assertNotNull(album.getId()); // fetch it Album fetchedAlbum = em.find(Album.class, album.getId()); assertNotSame(album, fetchedAlbum); assertEquals(album.toString(), fetchedAlbum.toString());
80
Named Queries
@EntryPoint public class Main { @Inject EntityManager em; void resetJpaStorage() { ((ErraiEntityManager) em).removeAll(); } }
SELECT et FROM EntityType et WHERE [expression with constants, named parameters and attributes
81
@NamedQuery(name="selectAlbumByName", a.name=:name") @Entity public class Album { ... same as before ... }
query="SELECT
FROM
Album
WHERE
To declare more than one query on the same entity, wrap the @NamedQuery annotations in @NamedQueries like this:
@NamedQueries({ @NamedQuery(name="selectAlbumByName", query="SELECT a FROM Album a WHERE a.name = :name"), @NamedQuery(name="selectAlbumsAfter", query="SELECT a FROM Album a WHERE a.releaseDate >= :startDate") }) @Entity public class Album { ... same as before ... }
82
Annotation
@PrePersist
Meaning The entity is about to be persisted or merged into the entity manager. The entity has just been persisted or merged into the entity manager. The entity's state is about to be captured into the browser's localStorage. The entity's state has just been captured into the browser's localStorage. The entity is about to be removed from persistent storage. The entity has just been removed from persistent storage. The entity's state has just been retrieved from the browser's localStorage.
@PostPersist
@PreUpdate
@PostUpdate
@PreRemove
@PostRemove
@PostLoad
JPA lifecycle event annotations can be placed on methods in the entity type itself, or on a method of any type with a public no-args constructor. To receive lifecycle event notifications directly on the affected entity instance, create a no-args method on the entity class and annotate it with one or more of the lifecycle annotations in the above table. For example, here is a variant of the Album class where instances receive notification right after they are loaded from persistent storage:
@Entity public class Album { ... same as before ... @PostLoad public void postLoad() { System.out.println("Album " + getName() + " was just loaded into the entity manager"); } }
To receive lifecycle methods in a different class, declare a method that takes one parameter of the entity type and annotate it with the desired lifecycle annotations. Then name that class in the @EntityListeners annotation on the entity type. The following example produces the same results as the previous example:
83
@Entity @EntityListeners(StandaloneLifecycleListener.class) public class Album { ... same as always ... } public class StandaloneLifecycleListener { @PostLoad public void albumLoaded(Album a) { public void postLoad() { System.out.println("Album " + a.getName() + " was just loaded into the entity manager"); } }
addition
to
84
85
The persistence.xml file is not optional. It must list all the entity types that Errai should know about In Dev Mode, changes to entity classes are not discovered on page refresh. You need to restart Dev Mode. The local data stored in the browser is not encrypted
86
Chapter 9.
Data Binding
Errai's data binding module provides the ability to bind model objects to UI fields/widgets. The bound properties of the model and the UI components will automatically be kept in sync for as long as they are bound. So, there is no need to write code for UI updates in response to model changes and no need to register listeners to update the model in response to UI changes. The data binding module is directly integrated with Chapter 10, Errai UI and Chapter 8, Errai JPA but can also be used as a standalone project in any GWT client application by simply inheriting the Data Binding GWT module:
@Bindable public class Customer { ... private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } ... }
87
or created manually:
In both cases above, the DataBinder instance is associated with a new instance of the model (e.g. a new Customer object). A DataBinder can also be associated with an already existing object:
In case there is existing state in either the model object or the UI components before the they are bound, initial state synchronization can be carried out to align the model and the corresponding UI fields. For using the model object's state to set the initial values in the UI:
For using the UI values to set the initial state in the model object:
88
Specifying Converters
public class CustomerView { @Inject private DataBinder<Customer> dataBinder; private Customer customer; private TextBox nameTextBox = new TextBox(); // more UI widgets... @PostConstruct private void init() { customer = dataBinder .bind(nameTextBox, "name") .bind(idLabel, "id") .getModel(); } }
After the call to dataBinder.bind() in the example above, the customer object's name property and the nameTextBox are kept in sync until either the dataBinder.unbind() method is called or the CustomerView bean is destroyed. That means that a call to customer.setName() will automatically update the value of the TextBox and any change to the TextBox's value in the browser will update the customer object's name property. So, customer.getName() will always reflect the currently displayed value of the TextBox .
Note
It's important to retrieve the model instance using dataBinder.getModel() before making changes to it as the data binder will provide a proxy to the model to ensure that changes will update the corresponding UI components.
89
private static final String DATE_FORMAT = "YY_DD_MM"; @Override public Date toModelValue(String widgetValue) { return DateTimeFormat.getFormat(DATE_FORMAT).parse(widgetValue); } @Override public String toWidgetValue(Date modelValue) { return DateTimeFormat.getFormat(DATE_FORMAT).format((Date) modelValue); } }
All converters annotated with @DefaultConverter will be registered as global defaults calling Convert.registerDefaultConverter() . Note that the Converter interface specifies two type parameters. The first one represents the type of the model field, the second one the type held by the widget (e.g. String for widgets implementing HasValue<String> ). These default converters will be used for all bindings with matching model and widget types.
Converters specified on the binding level take precedence over global default converters with matching types.
dataBinder.addPropertyChangeHandler(new PropertyChangeHandler() { @Override public void onPropertyChange(PropertyChangeEvent event) { Window.alert(event.getPropertyName() + " changed to:" + event.getNewValue()); }
90
});
dataBinder.addPropertyChangeHandler("name", new PropertyChangeHandler() { @Override public void onPropertyChange(PropertyChangeEvent event) { Window.alert("name changed to:" + event.getNewValue()); } });
91
92
Chapter 10.
Errai UI
One of the primary complaints of GWT to date has been that it is difficult to use "pure HTML" when building and skinning widgets. Inevitably one must turn to Java-based configuration in order to finish the job. Errai, however, strives Figure 10.1. TODO Gliffy image to remove the need for Java styling. HTML empty template files are placed in the project source [http://get.adobe.com/flashplayer/] tree, and referenced from custom "Composite components" (Errai UI Widgets) in Java. Since Errai UI depends on Errai IOC and Errai CDI, dependency injection is supported in all custom components. Errai UI provides rapid prototyping and HTML5 templating for GWT.
title
10.1.1. App.gwt.xml
If you work better by playing with a finished product, you can see a simple client-server project implemented using Errai UI here [https://github.com/lincolnthree/errai-ui-demo] .
93
@EntryPoint public class Application { @Inject private ColorComponent comp; @PostConstruct public void init() { comp.setColor("blue"); RootPanel.get().add(comp); } }
@EntryPoint public class Application { private String[] colors = new String[]{"Blue", "Yellow", "Red"}; @Inject private Instance<ColorComponent> instance; # @PostConstruct public void init() { for(String color: colors) { ColorComponent comp = instance.get(); comp.setColor(c); RootPanel.get().add(); } } }
@Templated public class LoginForm extends Composite { /* looks for LoginForm.html in LoginForm's package */ }
94
@Templated("my-template.html") public class LoginForm extends Composite { /* looks for my-template.html in LoginForm's package */ }
Fully qualified template paths are also supported, but must begin with a leading '/':
@Templated("/org/example/my-template.html") public class LoginForm extends Composite { /* looks for my-template.html in package org.example */ }
<form> <legend>Log in to your account</legend> <label for="username">Username</label> <input id="username" type="text" placeholder="Username"> <label for="password">Password</label> <input id="password" type="password" placeholder="Password"> <button>Log in</button> <button>Cancel</button>
95
</form>
@Templated("my-template.html#login-form") public class LoginForm extends Composite { /* Specifies that <... data-field="login-form"> be used as the root Element of this Widget */ }
Notice the corresponding HTML data-field attribute in the form Element below, and also note that multiple components may use the same template provided that they specify a corresponding data-field attribute. Also note that two or more components may share the same template datafield DOM elements; there is no conflict since components each receive a unique copy of the template DOM from the designated data-field at runtime (or from the root element if a fragment is not specified.)
<!DOCTYPE html> <html lang="en"> <head> <title>A full HTML snippit</title> </head> <body> <div> <form data-field="login-form"> <legend>Log in to your account</legend> <label for="username">Username</label> <input id="username" type="text" placeholder="Username"> ### # <label for="username">Password</label> <input id="password" type="password" placeholder="Password"> ## ### ### ### # <button>Log in</button> <button>Cancel</button> </form> </div>
96
For example's sake, the component below could also use the same template. All it needs to do is reference the template name, and specify a fragment.
@Templated("my-template.html#theme-footer") public class Footer extends Composite { /* Specifies that <... data-field="theme-footer"> be used as the root Element of this Widget */ }
@Templated public class LoginForm extends Composite { // This element must be initialized manually because Element is not @Injectable*/ @DataField private Element form = DOM.createForm(); // If not otherwise specified, the data-field name defaults to the name of the field; in this case, the data-field name would be "username" @Inject @DataField private TextBox username;
97
// The data-field name may also be specified manually @Inject @DataField("pass") private PasswordTextBox password; // We can also choose to instantiate our own Widgets. Injection is not required. @DataField private Button submit = new Button(); }
Important
Note: Field, method, and constructor injection are all supported by @DataField.
<form data-field="form"> <legend>Log in to your account</legend> <label for="username">Username</label> <input data-field="username" id="username" type="text" placeholder="Username"> <label for="password">Password</label> <input data-field="pass" id="password" type="password" placeholder="Password"> <button data-field="submit">Log in</button> <button>Cancel</button> </form>
Now, when we run our application, we will be able to interact with these fields in our Widget.
98
Example
2. DOM Elements are merged from the component to the template 3. Template element inner text and inner HTML are preserved when the given @DataField Widget implements HasText or HasHTML
10.6.1. Example
10.6.1.1. Composite component class:
@Templated public class StyledComponent extends Composite { @Inject @DataField("field-1") private Label div = new Label(); public StyledComponent() { div.getElement().setAttribute("style", "position: fixed; top: 0; left: 0;"); this.getElement().setId("outer-id"); } }
10.6.1.2. Template:
<form> <span datafield="field-1" style="display:inline;"> This element will become a div </span> </form> This text will be ignored.
<form id="outer-id"> <div datafield="field-1" style="display:inline;"> This element will become a div </div> </form>
But why does the output look the way it does? Some things happened that may be unsettling at first, but we find that once you understand why these things occur, you'll find the mechanisms extremely powerful.
99
10.6.4. Inner text and inner HTML (preserved when component implements HasText or HasHTML)
Additionally, because Label implements both HasText and HasHTML (only one is required,) the contents of this <span> "field-1" Element in the template were preserved; however, this would not have been the case if the @DataField specified for the element did not implement HasText or HasHTML . In short, if you wish to preserve text or HTML contents of an element in your template, you can do one of two things: do not composite that Element with a @DataField reference, or ensure that the Widget being composited implements HasText or HasHTML .
Important
It is not possible to handle Native DOM events on Widgets because GWT overrides native event handlers when Widgets are added to the DOM. You must
100
Concepts
programatically configure such handlers after the Widget has been added to the DOM.
10.7.1. Concepts
Each of the three supported approaches for event handling function on the same basic programming model. Event handler methods, annotated with @EventHandler("my-datafield") , are created and dynamically wired to the corresponding @DataField("my-datafield") in the same component.
@Templated public class WidgetHandlerComponent extends Composite { @Inject @DataField("b1") private Button button; @EventHandler("b1") public void doSomethingC1(ClickEvent e) { // do something } }
101
@DataField("div-1") private DivElement button = DOM.createDiv(); @EventHandler("div-1") public void doSomethingC1(ClickEvent e) { // do something# } }
<div> <a data-field="link" href="/page" <div data-field="div"> Some content </div> </div>
The @SinkNative annotation is used to select native events (as a bit mask) of which the method should handle; this sink behaves the same as when using DOM.sinkEvents(Element e, int bits) . Note that a @DataField reference in the component class is optional.
Important
Only one @EventHandler may be specified for a given data-field when @SinkNative is used to handle native DOM events.
@Templated public class QuickHandlerComponent extends Composite { @DataField private AnchorElement link = DOM.createAnchor().cast(); @EventHandler("link") @SinkNative(Event.ONCLICK | Event.ONMOUSEOVER)
102
Data Binding
public void doSomething(Event e) { // do something } @EventHandler("div") @SinkNative(Event.ONMOUSEOVER) public void doSomethingElse(Event e) { // do something else } }
@Templated public class LoginForm extends Composite { @Inject @Bound @DataField private TextBox username; @Inject @Bound @DataField private PasswordTextBox password; @DataField private Button submit = new Button(); private User user; @Inject
103
Now the user object and the username and password fields are automatically kept in sync. No event handling code needs to be written for updating the user object in response to input field changes and no code needs to be written for updating the user interface fields when the model object changes (when setUsername or setPassword is called). By default, the bindings are carried out based on the @DataField names. So, in the example above, the @DataField username is automatically bound to the JavaBean property username of the model object. The @Bound annotation also allows for specifying the property to bind to. In the following example, the password field is bound the JavaBean property named pass, assuming such a property exists in the User class.
The @Bound annotation further allows to specify a converter to use for the binding (see Specifying Converters for details). This is how a binding specific converter can be specified on a data field:
Errai's DataBinder also allows to register PropertyChangeHandlers for the cases where keeping the model and UI in sync is not enough and additional logic needs to be executed (see Property Change Handlers for details).
@Templated
104
public class ComponentOne extends Composite { @Inject @DataField("other-comp") private ComponentTwo two; }
10.10.1. Template
Extension templating is particularly useful for creating reusable page layouts with some shared content (navigation menus, side-bars, footers, etc...,) where certain sections will be filled with unique content for each page that extends from the base template; this is commonly seen when combined with the MVP design pattern traditionally used in GWT applications.
<div class="container"> <div data-field="header"> Default header </div> <div data-field="content"> Default content field="footer"> Default footer </div> </div>
</div>
<div
data-
@Templated public class PageLayout extends Composite { @Inject @DataField private HeaderComponent header;
105
@Inject @DataField private FooterComponent footer; @PostConstruct public final void init() { // do some setup } }
@Templated("PageLayout.html") public class LoginLayout extends PageLayout { @Inject @DataField private LoginForm content; }
We could also have chosen to override one or more @DataField references defined in the parent component, simply by specifying a @DataField with the same name in the child component, as is done with the "footer" data-field below.
@Templated("PageLayout.html") public class LoginLayout extends PageLayout { @Inject @DataField private LoginForm content; /* Override footer defined in PageLayout */ @Inject @DataField private CustomFooter footer; }
106
Chapter 11.
Errai UI Navigation
Starting in version 2.1, Errai offers a system for creating applications that have multiple bookmarkable pages. This navigation system has the following features:
Declarative, statically-analyzable configuration of pages and links Compile time referential safety (i.e. no broken links) Can generate storyboard of the applications navigation flow at compile time Decentralized configuration Create a new page by creating a new annotated class. No need to edit a second file. Make navigational changes in the natural place in the code. Integrates cleanly with Errai UI templates, but also works well with other view technologies. Builds on Errai CDI
If you are not using Maven for dependency management, add errai-navigation-version.jar to your classpath.
107
<inherits name="org.jboss.errai.ui.nav.Navigation"/>
By default, the name of a page is the simple name of the class that declares it. In the above example, the ItemListPage will fill the navigation panel whenever the browser's location bar ends with #ItemListPage . If you prefer a different page name, use the @Page annotation's path attribute:
108
Declaring a Link
Pages are looked up as CDI beans, so you can inject other CDI beans into fields or a constructor. Pages can also have @PostConstruct and @PreDestroy CDI methods.
You do not need to implement the TransitionTo interface yourself; the framework creates the appropriate instance for you. You can inject any number of links into a page. The only restriction is that the target of the link must be a Widget type that is annotated with @Page .
109
@Page(startingPage=true) public class WelcomePage extends Composite { @Inject TransitionTo<ItemListPage> startButtonClicked; public void onStartButtonPressed(ClickEvent e) { startButtonClicked.go(); } }
@EntryPoint public class Bootstrap { @Inject private Navigation navigation; @PostConstruct public void clientMain() { RootPanel.get().add(navigation.getContentPanel()); } }
The following example reserves space for header and footer content that is not affected by the navigation system:
110
@PostConstruct public void clientMain() { VerticalPanel vp = new VerticalPanel(); vp.add(new HeaderWidget()); vp.add(navigation.getContentPanel()); vp.add(new FooterWidget()); RootPanel.get().add(vp); } }
This last example demonstrates a simple approach to defining the page structure with an Errai UI template. The final product is identical to the above example, but in this case the overall page structure is declared in an HTML template rather than being defined programmatically in procedural logic:
@Templated @EntryPoint public class OverallPageStrucutre extends Composite { @Inject private Navigation navigation; @Inject @DataField private HeaderWidget header; @Inject @DataField private SimplePanel content; @Inject @DataField private FooterWidget footer; @PostConstruct public void clientMain() { // give over the contents of this.content to the navigation panel content.add(navigation.getContentPanel()); // add this whole templated widget to the root panel RootPanel.get().add(this); } }
111
112
Chapter 12.
Configuration
This section contains information on configuring Errai.
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <servlet> <servlet-name>ErraiServlet</servlet-name> <servlet-class>org.jboss.errai.bus.server.servlet.DefaultBlockingServlet</ servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>ErraiServlet</servlet-name> <url-pattern>*.erraiBus</url-pattern> </servlet-mapping> <context-param> <param-name>errai.properties</param-name> <param-value>/WEB-INF/errai.properties</param-value> </context-param> <context-param> <param-name>login.config</param-name> <param-value>/WEB-INF/login.config</param-value> </context-param> <context-param> <param-name>users.properties</param-name> <param-value>/WEB-INF/users.properties</param-value> </context-param>
113
</web-app>
12.3. ErraiApp.properties
ErraiApp.properties acts both as a marker file for JARs that contain Errai-enabled GWT modules, and as a place to put configuration settings for those modules in the rare case that non-default configuration is necessary.
114
ErraiService.properties
may be made into an error. It's best to avoid specifying the same configuration key in multiple ErraiApp.properties files.
12.4. ErraiService.properties
The ErraiService.properties file contains basic configuration for the bus itself. Unlike ErraiApp.properties, there should be at most one ErraiService.properties file on the classpath of a deployed application. If you do not need to set any properties to their non-default values, this file can be omitted from the deployment entirely.
115
errai.bus.buffer_segment_size The transmission buffer segment size in bytes. This is the minimum amount of memory each message will consume while stored within the buffer. Defualt value: 8.
errai.bus.buffer_segment_count The number of segments in absolute terms. If this attribute is specified in the absence of errai.bus.buffer_size , the buffer size is inferred by the calculation buffer_segment_size / buffer_segment_count .
errai.bus.buffer_allocation_mode Buffer allocation mode. Allowed values are direct and heap . Direct allocation puts buffer memory outside of the JVM heap, while heap allocation uses buffer memory inside the Java heap. For most situations, heap allocation is preferable. However, if the application is data intensive and requires a substantially large buffer, it is preferable to use a direct buffer. From a throughput perspective, current JVM implementations pay about a 20% performance penalty for direct-allocated memory access. However, your application may show better scaling characteristics with direct buffers. Benchmarking under real load conditions is the only way to know the optimal setting for your use case and expected load. Default value: direct .
12.4.1.2. Security
errai.authentication_adapter specifies the authentication modelAdapter the bus should use for determining whether calls should be serviced based on authentication and security principals.
errai.require_authentication_for_all indicates whether or not the bus should always require the use of authentication for all requests inbound for the bus. If this is turned on, an authentication model adapter must be defined, and any user must be authenticated before the bus will deliver any messages from the client to any service.
errai.auto_load_extensions A boolean indicating whether or not the Errai bootstrapper should automatically scan for extensions. The default value is true .
##
116
Dispatcher Implementations
## Request dispatcher implementation (default is SimpleDispatcher) ## #errai.dispatcher_implementation=org.jboss.errai.bus.server.SimpleDispatcher errai.dispatcher_implementation=org.jboss.errai.bus.server.AsyncDispatcher # ## Worker pool size. This is the number of threads the asynchronous worker pool should provide for processing ## incoming messages. This option is only valid when using the AsyncDispatcher implementation. ## errai.async.thread_pool_size=5 ## ## Worker timeout (in seconds). This defines the time that a single asychronous process may run, before the worker pool ## terminates it and reclaims the thread. This option is only valid when using the AsyncDispatcher implementation. ## errai.async.worker.timeout=5
## ## Specify the Authentication/Authorization Adapter to use ## #errai.authentication_adapter=org.jboss.errai.persistence.server.security.HibernateAuthenticati #errai.authentication_adapter=org.jboss.errai.bus.server.security.auth.JAASAdapter ## ## This property indicates whether or not authentication is required for all communication with the bus. Set this ## to 'true' if all access to your application should be secure. ## #errai.require_authentication_for_all=true
12.5.1. SimpleDispatcher
SimpleDispatcher is basic implementation that provides no asychronous delivery mechanism. Rather, when you configure the Errai to use this implementation, messages are delivered to their
117
endpoints synchronously. The incoming HTTP thread will be held open until the messages are delivered. While this sounds like it has almost no advantages, especially in terms of scalablity. Using the SimpleDispatcher can be far preferable when you're developing your application, as any errors and stack traces will be far more easily traced and some cloud services may not permit the use of threads in any case.
12.5.2. AsyncDispatcher
The AsyncDispatcher provides full asynchronous delivery of messages. When this dispatcher is used, HTTP threads will have control immediately returned upon dispatch of the message. This dispatcher provides far more efficient use of resources in high-load applications, and will significantly decrease memory and thread usage overall.
12.6.1. DefaultBlockingServlet
This is a universal, completely servlet spec (2.0) compliant, Servlet implementation. It provides purely synchronous request handling and should work in virtually any servlet container, unless there are restrictions on putting threads into sleep states.
12.6.2. JBossCometServlet
The JBoss Comet support utilizes the JBoss Web AIO APIs (AS 5.0 and AS 6.0) to improve scalability and reduce thread usage. The HTTP, NIO, and AJP connectors are not supported. Use of this implementation requires use of the APR (Apache Portable Runtime).
12.6.3. JettyContinuationsServlet
The Jetty implementation leverages Jetty's continuations support, which allows for threadless pausing of port connections. This servlet implementation should work without any special configuration of Jetty.
12.6.4. StandardAsyncServlet
This implementation leverages asynchronous support in Servlet 3.0 to allow for threadless pausing of port connections. Note that <async-supported>true</async-supported> has to be added to the servlet definition in web.xml .
118
Chapter 13.
119
120
Chapter 14.
14.1. Why does it seem that Errai can't see my class at compile time?
Possible symptoms: uncaught exception: java.lang.RuntimeException: No proxy provider found for type: my.fully.qualified.ServiceName Answer: Make sure the Section 12.3, ErraiApp.properties file is actually making it into your runtime classpath. One common cause of this problem is a <resources> section in pom.xml that includes src/main/ java (to expose .java sources to the GWT compiler) that does not also include src/main/resources as a resource path. You must include both explicitly:
14.2. Why am I getting "java.lang.ClassFormatError: Illegal method name "<init>$" in class org/xyz/package/ MyClass"?
Answer: This error message means that your project has a (direct or indirect) subclass of JavaScriptObject that lacks a protected no-args constructor. All subtypes of JavaScriptObject
121
(also known as overlay types ) must declare a protected no-args constructor, but the error message could be much clearer. There is an issue filed in the GWT project's bug tracker for improving the error message: GWT issue 3383 [http://code.google.com/p/google-web-toolkit/ issues/detail?id=3383] .
122
Chapter 15.
Upgrade Guide
This chapter contains important information for migrating to newer versions of Errai. If you experience any problems, don't hesitate to get in touch with us. See Chapter 18, Reporting problems .
org.jboss.errai.common.client.api.annotations.Portable
Chapter
gwt 2.3.0 or newer must be used and replace older versions. mvel2 2.1.Beta8 or newer must be used and replace older versions. weld 1.1.5.Final or newer must be used and replace older versions. slf4j 1.6.1 or newer must be used and replace older versions. This step can be skipped if Maven is used to build the project. If the project is NOT built using Maven, the following jar files have to be added manually to project's build/class path: erraicommon-2.x.jar, errai-marshalling-2.x.jar, errai-codegen-2.x.jar, netty-4.0.0.Alpha1.errai.r1.jar.
123
If the project was built using an early version of an Errai archetype the configuration of the maven-gwt-plugin has to be modified to contain the <hostedWebapp>path-to-yourstandard-webapp-folder</hostedWebapp> . This is usually either war or src/main/webapp .
Starting with 2.0.CR1 the default for automatic service discovery has been changed in favour of CDI based applications. That means it has to be explicitly turned on for plain bus applications (Errai applications that do not use Errai-CDI). Not doing so will result in NoSubscribersToDeliverTo exceptions. The snippet below shows how to activate automatic service discovery:
<servlet> <servlet-name>ErraiServlet</servlet-name> <servlet-class>org.jboss.errai.bus.server.servlet.DefaultBlockingServlet</ servlet-class> <init-param> <param-name>auto-discover-services</param-name> <param-value>true</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>
124
Chapter 16.
Downloads
The distribution Downloads.html packages can be downloaded from jboss.org http://jboss.org/errai/
125
126
Chapter 17.
Sources
Errai is currently managed using Github. You can clone our repositories from http://github.com/ errai .
127
128
Chapter 18.
Reporting problems
If you run into trouble don't hesitate to get in touch with us: JIRA Issue Tracking: https://jira.jboss.org/jira/browse/ERRAI User Forum: http://community.jboss.org/en/errai?view=discussions Mailing List: http://jboss.org/errai/MailingLists.html IRC: irc://irc.freenode.net/errai
129
130
Chapter 19.
Errai License
Errai is distributed under the terms of the Apache License, Version 2.0. See the full Apache license text [http://www.apache.org/licenses/LICENSE-2.0] .
131
132
133
134