-
1. Re: Errai Newbie - Quick Q
jfuerth May 31, 2013 10:04 AM (in response to thewebman2002)1 of 1 people found this helpfulHi Mike,
I see a few things you might want to look at:
First, you're mixing levels of abstraction in this example. Although it's totally fine to write an app that uses the low-level MessageBuilder and MessageCallback API in some places, Errai RPC in other places, and CDI events and observers in other places yet, I can't recommend mixing and matching these levels of abstraction within the same use case (for example, responding to an RPC call using the MessageBuilder).
So in the case, above, I'd recommend that you choose either to return a value from your Errai RPC method, and receive that value in a RemoteCallback on the client:
@Inject Caller<MyRpcService> myRpcService; public void doRpcCall() { myRpcService.call(new RemoteCallback<String>() { @Override public void callback(String response) { System.out.println("Got RPC response from server: " + response); } }).doLogin(username, password); }
Or if you do prefer to work directly with the low-level bus API, do something like this on the server:
@Service public void doLogin(Message message) { // dig out message parts for username and password ... MessageBuilder.createConversation(message) .toSubject("Login") .with("text", "Hello, World!") .done().reply(); }
One final note: in your example server-side code, the message you're sending would be a broadcast message to the Login topic. Note that the code above sends a private reply just to the one client who invoked your service method.
Hope that helps!
Jonathan
-
2. Re: Errai Newbie - Quick Q
thewebman2002 May 31, 2013 12:45 PM (in response to jfuerth)Thanks Jonathan - I appreciate the feedback on not mixing - makes sense. We will probably go down the route of the low-level bus api to start with as that would help us refactor in pieces amongst several developers. If I can bug you with a follow-up question.
When you put the @Service annotation, what jars do I need to bring in and do I need to initialize any provider or injector for it to be picked up?
Thanks much,
Mike
-
3. Re: Errai Newbie - Quick Q
jfuerth May 31, 2013 2:05 PM (in response to thewebman2002)1 of 1 people found this helpfulThe helloworld bus demo has this dependency tree:
org.jboss.errai:errai-bus-demos-helloworld:war:2.3.1.Final +- org.jboss.errai:errai-common:jar:2.3.1.Final:compile | \- org.jboss.errai.reflections:reflections:jar:2.3.1.Final:compile | \- dom4j:dom4j:jar:1.6.1:compile | \- xml-apis:xml-apis:jar:1.0.b2:compile +- org.jboss.errai:errai-bus:jar:2.3.1.Final:compile | +- org.jboss.errai:errai-config:jar:2.3.1.Final:compile | +- org.jboss.errai:errai-marshalling:jar:2.3.1.Final:compile | | \- org.jboss.errai:errai-codegen-gwt:jar:2.3.1.Final:compile | +- javax.validation:validation-api:jar:1.0.0.GA:compile | +- javax.validation:validation-api:jar:sources:1.0.0.GA:compile | +- com.google.inject:guice:jar:3.0:compile | | \- aopalliance:aopalliance:jar:1.0:compile | +- javax.inject:javax.inject:jar:1:compile | +- org.mvel:mvel2:jar:2.1.Beta8:compile | +- org.slf4j:slf4j-api:jar:1.6.1:compile | +- org.javassist:javassist:jar:3.15.0-GA:compile | +- org.jboss.errai.io.netty:netty:jar:4.0.0.Alpha1.errai.r1:compile | \- com.google.guava:guava:jar:12.0:compile | \- com.google.code.findbugs:jsr305:jar:1.3.9:compile +- org.jboss.errai:errai-ioc:jar:2.3.1.Final:compile | +- org.jboss.errai:errai-codegen:jar:2.3.1.Final:compile | +- org.jboss.errai:errai-javax-enterprise:jar:2.3.1.Final:compile | +- javax.annotation:jsr250-api:jar:1.0:compile | \- javax.enterprise:cdi-api:jar:1.0-SP4:compile | \- org.jboss.spec.javax.interceptor:jboss-interceptors-api_1.1_spec:jar:1.0.0.Beta1:compile +- org.jboss.errai:errai-tools:jar:2.3.1.Final:compile | \- hsqldb:hsqldb:jar:1.8.0.7:compile +- com.google.gwt:gwt-user:jar:2.5.1:provided | \- org.json:json:jar:20090211:provided \- junit:junit:jar:4.8.1:test (scope not updated to compile)
For those not familiar with Maven scopes, "provided" means that jar is on the classpath at compile time and when running GWT Dev Mode, but the "provided" jars are not bundled in the .war file that's deployed to the server.
"compile" scope, somewhat counterintuitively, is always on the classpath and is deployed to the server.
"test" scope is on the classpath only when compiling and running the tests.
On the GWT side, you need to depend on ErraiBus and Errai's IOC container:
<module rename-to="MyApp"> <inherits name="org.jboss.errai.bus.ErraiBus"/> <inherits name="org.jboss.errai.ioc.Container"/> </module>
The dependency structure for Errai 3.0 is a bit different (we fixed some dependencies we felt were pointing the wrong way). Let me know if you're using the 3.0 snapshots and I can produce that dependency tree for you as it stands today.
-
4. Re: Errai Newbie - Quick Q
thewebman2002 May 31, 2013 2:23 PM (in response to jfuerth)Great Jonathan!! This will definitely help in our process. We use maven extensively and that should help us as well. We are not using 3.0 snapshot at the moment.
And I am assuming that the developer doesnt need to specifically involve guice and bind - that should be taken care of by the Errai IOC etc.
Btw - can I ask a fundamental question: how does Errai ensure that the Client Bus talks to the correct Server Bus (I believe it uses socket underneath - could be mistaken; but since it has been encapsulated, what things need to be taken care of from a developer standpoint to ensure that the client bus and the server bus can communicate with each other).
Thanks much!
Mike
-
5. Re: Errai Newbie - Quick Q
thewebman2002 May 31, 2013 4:15 PM (in response to jfuerth)Hey Jonathan - another quick Q:
When I am using and trying the HelloWorldService, I get an exception:
no subscribers to deliver to for subject: HelloWorldService -- Additional Details: none
org.jboss.errai.bus.client.api.base.NoSubscribersToDeliverTo: no subscribers to deliver to for subject: HelloWorldService
org.jboss.errai.bus.client.framework.ClientMessageBusImpl.send(ClientMessageBusImpl.java:485)
org.jboss.errai.bus.client.api.base.CommandMessage.sendNowWith(CommandMessage.java:328)
org.jboss.errai.bus.client.api.base.DefaultMessageBuilder$1.sendNowWith(DefaultMessageBuilder.java:78)Do I need to follow any structural pattern - such as it has to reside in certain package etc.
in the client package (com.mytest.client) I have the EBus class (a client class with @Entrypoint annotation):
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import org.jboss.errai.bus.client.api.Message;
import org.jboss.errai.bus.client.api.MessageCallback;
import org.jboss.errai.bus.client.api.base.MessageBuilder;
import org.jboss.errai.bus.client.framework.MessageBus;
import org.jboss.errai.common.client.protocols.MessageParts;
import org.jboss.errai.ioc.client.api.EntryPoint;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
@EntryPoint
public class EBus {
@Inject
private MessageBus bus;
private final Label responseLabel = new Label();
private final Button button = new Button("Send");
private final TextBox message = new TextBox();
@PostConstruct
public void buildUI() {
button.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
System.out.println("Handling click event!");
sendMessage();
}
});
HorizontalPanel horizontalPanel = new HorizontalPanel();
horizontalPanel.add(message);
horizontalPanel.add(button);
horizontalPanel.add(responseLabel);
RootPanel.get().add(horizontalPanel);
System.out.println("UI Constructed!");
}
void sendMessage() {
MessageBuilder.createMessage()
.toSubject("HelloWorldService")
.withValue("Hello, There!")
.done()
.repliesTo(new MessageCallback() {
public void callback(Message message) {
System.out.println("Got a Response!");
responseLabel.setText("Message from Server: " + message.get(String.class, MessageParts.Value));
}
})
.sendNowWith(bus);
}
}
in the server package (com.mytest.server), I have a HelloWorldService (with @Service annotation) :
import java.util.Date;
import org.jboss.errai.bus.client.api.Message;
import org.jboss.errai.bus.client.api.MessageCallback;
import org.jboss.errai.bus.client.api.base.MessageBuilder;
import org.jboss.errai.bus.server.annotations.Service;
@Service
public class HelloWorldService implements MessageCallback {
public void callback(Message message) {
MessageBuilder.createConversation(message)
.subjectProvided()
.withValue("Hello, World! The server's time is now " + new Date() + ".")
.done().reply();
}
}
Based on the documentation, I have placed the ErraiApp and ErraiService.properties file in src/main/resources.
Do I need to do anything else?
Thanks,
Mike.
-
6. Re: Errai Newbie - Quick Q
jfuerth May 31, 2013 4:37 PM (in response to thewebman2002)And I am assuming that the developer doesnt need to specifically involve guice and bind - that should be taken care of by the Errai IOC etc.
That's right, server-side Errai will find your services on its own. You don't have to write any code to do this, but you do have to be somewhat careful to configure it properly. The mechanism to use depends on whether or not Errai's CDI integration jar is deployed on the server. You configure this setting in ErraiService.properties. From the reference guide:
- errai.auto_discover_services A boolean indicating whether or not the Errai bootstrapper should automatically scan for services. This property must be set to true if and only if Errai CDI is not on the classpath. The default value is false.
Btw - can I ask a fundamental question: how does Errai ensure that the Client Bus talks to the correct Server Bus (I believe it uses socket underneath - could be mistaken; but since it has been encapsulated, what things need to be taken care of from a developer standpoint to ensure that the client bus and the server bus can communicate with each other).
The client bus automatically attempts to establish an HTTP connection to the server bus when the ErraiBus module loads. It also handles upgrade to Server-Sent Events and Web Sockets if the browser is capable and the server reports it is also capable.
-Jonathan
-
7. Re: Errai Newbie - Quick Q
jfuerth May 31, 2013 4:41 PM (in response to thewebman2002)Based on the documentation, I have placed the ErraiApp and ErraiService.properties file in src/main/resources.
Do I need to do anything else?
If you're not using Errai's CDI integration on the server side, you will need to set errai.auto_discover_services=true in the ErraiService.properties file. Otherwise, the code you've posted looks good to me on first inspection.
-Jonathan
-
8. Re: Errai Newbie - Quick Q
thewebman2002 May 31, 2013 4:42 PM (in response to thewebman2002)Figured it Jonathan - since I am not using CDI, I need to explicitly set auto-discover services in the web.xml. Hope that helps anyone stuck ...
thanks!
Mike.
-
9. Re: Errai Newbie - Quick Q
thewebman2002 May 31, 2013 5:55 PM (in response to jfuerth)Hey Jonathan - The HelloWorldService is now working and sending back a response to the conversation message.
When I try not to respond as a conversation message but send it to a specific subject (as you mentioned - broadcast), it doesnt appear to be coming to the client.... my code below...
I have
initListener() mehod in my
@PostConstruct
public void buildUI() method
and in initListener ...
bus.subscribe("HelloWorldClient", new MessageCallback() {
public void callback(CommandMessage message) {
String messageText = message.get(String.class, "text");
System.out.println("Message Text: " + messageText);
}
@Override
public void callback(Message message) {
// TODO Auto-generated method stub
String messageText = message.get(String.class, "text");
System.out.println("Message Text: " + messageText);
}
});
The button click still sends a message to the server which I receive .. it prints that it received a message...
@Inject MessageBus msgBus; public void callback(Message message) {
System.out.println("Received message from client"); MessageBuilder.createMessage() .toSubject("HelloWorldClient") // (1) .signalling() // (2) .with("text", "Hi There - This is from HelloWorldService") // (3) .noErrorHandling() // (4) .sendNowWith(msgBus); }
but the client never receives the message - do I need to do something differently than whats done for the conversational interaction - I didnt see any difference in the docs.
Thanks much!
Mike
-
10. Re: Errai Newbie - Quick Q
thewebman2002 Jun 1, 2013 8:50 AM (in response to thewebman2002)Hey Jonathan etal - I think I figured it. For some reason, when you are running errai via eclipse, things are not cleaned up properly - I could see some processes running that were probably tied to the original conversation context. The moment I cleaned up everything, restarted eclipse and killed zombie errai java processes, it picked up the boradcast callback and the client was able to get the new message.
Hope that helps anyone else who may have faced this issue.
Thanks,
Mike
-
11. Re: Errai Newbie - Quick Q
jfuerth Jun 7, 2013 12:56 PM (in response to thewebman2002)A followup for anyone who runs into a similar problem with Errai 2.3.x or the 3.0 snapshots before today: we've just found and fixed a slippery bug in the way the bus expires abandoned queues on the server side. If you observe an HTTP "401 Unauthorized" error in the browser's network monitor right around the time the client misses a broadcast from the server, then you have been affected by this bug.
The fix is in the 3.0.0.20130604-M1 release ("3.0 Milestone 1") that came out yesterday.
-Jonathan