Loading Resty-GWT - gwt

How can I show load widget, when client send json on server.
From example in GWTP exmaple I found such method
/**
* We display a short lock message whenever navigation is in progress.
*
* #param event The {#link LockInteractionEvent}.
*/
#ProxyEvent
public void onLockInteraction(LockInteractionEvent event) {
getView().setLoading(event.shouldLock());
}
How do I show in the loading resty-gwt, when it sent the request? Can I use onLockInteraction with resty-gwt?

You can use RestyGWT custom Dispatcher to track request lifecycle. Dispatcher can be configured manually or using annotations (https://resty-gwt.github.io/documentation/restygwt-user-guide.html). Example setting it manually:
RootRestService rest = GWT.create(RootRestService.class);
((RestServiceProxy) rest).setDispatcher(new DefaultDispatcher() {
#Override public Request send(Method m, RequestBuilder rb) throws RequestException {
RequestCallback callback = rb.getCallback();
rb.setCallback(new RequestCallback() {
#Override public void onResponseReceived(Request req, Response res) {
log.info("request success (stop event)");
callback.onResponseReceived(req, res);
}
#Override public void onError(Request req, Throwable ex) {
log.info("request error (stop event)");
callback.onError(req, ex);
}
});
try {
log.info("request initialized (start event)");
return request = super.send(m, rb);
} finally {
log.info("request fail to initialize error (stop event)");
}
}
});
Instead of logging, you can send an event using the eventBus, and use this event to keep track of the number of active request, and finally show a loading indicator if the number of active request is grater than 0.

Related

Best way to handle incoming messages with XMPP

Is there a work-around to get Spring to handle incoming messages from XMPP? I have tried many different configurations to get an inbound-channel-adapter to respond to incoming XMPP messages and nothing happens. I know that they show up at the Spring Integration layer (I can see that in the logs) but they are ignored. Is there any way to get them into my application layer? I hope to avoid needing to make changes to Spring Integration itself if I can.
Here is my integration configuration:
<int-xmpp:inbound-channel-adapter id="gcmIn"
channel="gcmInChannel"
xmpp-connection="gcmConnection"
auto-startup="true"
/>
<bean id="inboundBean" class="example.integration.GcmInputHandler"/>
<int:service-activator input-channel="gcmInChannel" output-channel="nullChannel" ref="inboundBean" method="handle"/>
Using the outbound-channel-adapter works fine. I can send messages over GCM 100% easily. But inbound does nothing, even though I know the messages are coming in.
Thanks
Not a very clean one, you would need to overwrite the ChatMessageListeningEndpoint, which drops all empty body messages.
This one needs then to be used as inbound-channel adapter in your config.
In addition you need to register the GCM package extension on the Smack Provider Manager, otherwise you lose the JSON message.
Working on a sample project -- so if you need more help let me know and I will post a link as soon it works somehow in a understandable way.
Here a sample GCM Input Adapter
public class GcmMessageListeningEndpoint extends ChatMessageListeningEndpoint {
private static final Logger LOG = LoggerFactory.getLogger(GcmMessageListeningEndpoint.class);
#Setter
protected PacketListener packetListener = new GcmPacketListener();
protected XmppHeaderMapper headerMapper = new DefaultXmppHeaderMapper();
public GcmMessageListeningEndpoint(XMPPConnection connection) {
super(connection);
ProviderManager.addExtensionProvider(GcmPacketExtension.GCM_ELEMENT_NAME, GcmPacketExtension.GCM_NAMESPACE,
new PacketExtensionProvider() {
#Override
public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
String json = parser.nextText();
return new GcmPacketExtension(json);
}
});
}
#Override
public void setHeaderMapper(XmppHeaderMapper headerMapper) {
super.setHeaderMapper(headerMapper);
this.headerMapper = headerMapper;
if (this.headerMapper == null) throw new IllegalArgumentException("Null XmppHeaderMapper isn't supported!");
}
public String getComponentType() {
return "xmpp:inbound-channel-adapter-gcm";
}
#Override
protected void doStart() {
Assert.isTrue(this.initialized, this.getComponentName() + " [" + this.getComponentType() + "] must be initialized");
this.xmppConnection.addPacketListener(this.packetListener, null);
}
#Override
protected void doStop() {
if (this.xmppConnection != null) {
this.xmppConnection.removePacketListener(this.packetListener);
}
}
class GcmPacketListener implements PacketListener {
#Override
public void processPacket(Packet packet) throws NotConnectedException {
if (packet instanceof org.jivesoftware.smack.packet.Message) {
org.jivesoftware.smack.packet.Message xmppMessage = (org.jivesoftware.smack.packet.Message) packet;
Map<String, ?> mappedHeaders = headerMapper.toHeadersFromRequest(xmppMessage);
sendMessage(MessageBuilder.withPayload(xmppMessage).copyHeaders(mappedHeaders).build());
} else {
LOG.warn("Unsuported Packet {}", packet);
}
}
}
}
And here the new configuration for the inbound-channel-adapter remove the one in XML:
#Bean
public GcmMessageListeningEndpoint inboundAdpater(XMPPConnection connection, MessageChannel gcmInChannel) {
GcmMessageListeningEndpoint endpoint = new GcmMessageListeningEndpoint(connection);
endpoint.setOutputChannel(gcmInChannel);
return endpoint;
}

Gwt Logging into Client UI from Server-side

I have created GWT app, in which I have a Vertical Panel where I log the details.
Client side logging I'm doing using logger
sample code is:
public static VerticalPanel customLogArea = new VerticalPanel();
public static Logger rootLogger = Logger.getLogger("");
logerPanel.setTitle("Log");
scrollPanel.add(customLogArea);
logerPanel.add(scrollPanel);
if (LogConfiguration.loggingIsEnabled()) {
rootLogger.addHandler(new HasWidgetsLogHandler(customLogArea));
}
And I'm updating my vertical log panel using this code
rootLogger.log(Level.INFO,
"Already Present in Process Workspace\n");
But now my question is , I have to log server side details also into my vertical log panel.
My serverside GreetingServiceImpl code is:
public boolean createDirectory(String fileName)
throws IllegalArgumentException {
Boolean result = false;
try {
rootLogger.log(Level.INFO,
"I want to log this to my UI vertical log Panel");
system.out.println("log this to UI");
File dir = new File("D:/GenomeSamples/" + fileName);
if (!dir.exists()) {
result = dir.mkdir();
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
Now I want to log sysoutprt statements to my UI from here. How can I achieve this. Now using rootLogger.log(Level.INFO,
"I want to log this to my UI vertical log Panel"); code it is logging this to eclipse console . But how to log this to my UI in client side.
Please let me know If anything wrong in this question.
If I understood you right, you want to see your server log entries in web interface. And of course, java logger and printStackTrace() won't help you in that: your gwt code is compiled to JavaScript and has nothing to do with console and log files. Besides, your server can't "push" log entries to client - it's up to client to make requests. So if you want to track new log entries and move it to client, you need to poll server for new entries. And yet another problem: you may have many clients polling your servlet and you should keep in mind this multi-threading.
This is how I see probable implementation (it's just concept, may contain some errors and misspellings):
Remote interface:
public interface GreetingService extends RemoteService {
List<String> getLogEntries();
boolean createDirectory(String fileName)throws IllegalArgumentException;
}
Remote Servlet:
public class GreetingServiceImpl extends RemoteServiceServlet implements GreetingService {
public static final String LOG_ENTRIES = "LogEntries";
public List<String> getLogEntries() {
List<String> entries = getEntriesFromSession();
List<String>copy = new ArrayList<String>(entries.size());
copy.addAll(entries);
//prevent loading the same entries twice
entries.clear();
return copy;
}
public boolean createDirectory(String fileName)throws IllegalArgumentException {
Boolean result = false;
try {
log("I want to log this to my UI vertical log Panel");
log("log this to UI");
File dir = new File("D:/GenomeSamples/" + fileName);
if (!dir.exists()) {
result = dir.mkdir();
}
} catch (Exception e) {
log("Exception occurred: " + e.getMessage());
}
return result;
}
private List<String> getEntriesFromSession() {
HttpSession session= getThreadLocalRequest().getSession();
List<String>entries = (List<String>)session.getAttribute(LOG_ENTRIES);
if (entries == null) {
entries = new ArrayList<String>();
session.setAttribute(LOG_ENTRIES,entries);
}
return entries;
}
private void log(String message) {
getEntriesFromSession().add(message);
}
Simple implementation of polling (gwt client-side):
Timer t = new Timer() {
#Override
public void run() {
greetingAsyncService.getLogEntries(new AsyncCallBack<List<String>>() {
void onSuccess(List<String>entries) {
//put entries to your vertical panel
}
void onFailure(Throwable caught){
//handle exceptions
}
});
}
};
// Schedule the timer to run once in second.
t.scheduleRepeating(1000);
greetingAsyncService.createDirectory(fileName, new AsyncCallBack<Void>(){
void onSuccess(List<String>entries) {
//no need to poll anymore
t.cancel();
}
void onFailure(Throwable caught){
//handle exceptions
}
});
}
As you can see, I have used session to keep log entries, because session is client-specific and so different clients will receive different logs. It's up to you to decide what to use - you may create your own Logger class that will track users itself and give appropriate logs to appropriate clients.
And also you may want to save level of your messages (INFO,ERROR etc.) and then display messages in different colors (red for ERROR, for instance). To do so, you need to save not List, but some your custom class.
You'd create a logging servlet that has the same methods as your logging framework to send log messages to your server via RPC.
Here are some sample RPC log methods you can use:
public interface LogService extends RemoteService {
public void logException(String logger, String priority, String message, String error, StackTraceElement[] stackTrace, String nativeStack);
}
public interface LogServiceAsync {
public void logException(String logger, String priority, String message, String error, StackTraceElement[] stackTrace, String nativeStack, AsyncCallback<Void> callback);
}
public class LogServiceImpl extends RemoteServiceServlet implements LogService {
public void logException(String loggerName, String priority, String logMessage, String errorMessage, StackTraceElement[] stackTrace, String nativeStack) {
Logger logger = getLogger(loggerName);
Level level = getLevel(priority);
// Create a Throwable to log
Throwable caught = new Throwable();
if (errorMessage != null && stackTrace != null) {
caught = new Throwable(errorMessage);
caught.setStackTrace(stackTrace);
}
//do stuff with the other passed arguments (optional)
logger.log(level, message, caught);
}
}
Although those implementations are very nice, forget about timers and repeated server queries. We've something better now.
It's possible to push data from server to client using Atmosphere which supports WebSockets.

How to resend a GWT RequestFactory request

Is it possible to resend a RequestFactory transmission? I'd like to do the equivalent of this: How to resend a GWT RPC request when using RequestFactory. It is fairly simple to resend the same payload from a previous request, but I also need to place a call to the same method. Here's my RequestTransport class, and I am hoping to just "refire" the original request after taking care of, in this case, a request to the user for login credentials:
package org.greatlogic.rfexample2.client;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.Response;
import com.google.web.bindery.requestfactory.gwt.client.DefaultRequestTransport;
/**
* Every request factory transmission will pass through the single instance of this class. This can
* be used to ensure that when a response is received any global conditions (e.g., the user is no
* longer logged in) can be handled in a consistent manner.
*/
public class RFERequestTransport extends DefaultRequestTransport {
//--------------------------------------------------------------------------------------------------
private IClientFactory _clientFactory;
//==================================================================================================
private final class RFERequestCallback implements RequestCallback {
private RequestCallback _requestCallback;
private RFERequestCallback(final RequestCallback requestCallback) {
_requestCallback = requestCallback;
} // RFERequestCallback()
#Override
public void onError(final Request request, final Throwable exception) {
_requestCallback.onError(request, exception);
} // onError()
#Override
public void onResponseReceived(final Request request, final Response response) {
if (response.getStatusCode() == Response.SC_UNAUTHORIZED) {
_clientFactory.login();
}
else {
_clientFactory.setLastPayload(null);
_clientFactory.setLastReceiver(null);
_requestCallback.onResponseReceived(request, response);
}
} // onResponseReceived()
} // class RFERequestCallback
//==================================================================================================
#Override
protected void configureRequestBuilder(final RequestBuilder builder) {
super.configureRequestBuilder(builder);
} // configureRequestBuilder()
//--------------------------------------------------------------------------------------------------
#Override
protected RequestCallback createRequestCallback(final TransportReceiver receiver) {
return new RFERequestCallback(super.createRequestCallback(receiver));
} // createRequestCallback()
//--------------------------------------------------------------------------------------------------
void initialize(final IClientFactory clientFactory) {
_clientFactory = clientFactory;
} // initialize()
//--------------------------------------------------------------------------------------------------
#Override
public void send(final String payload, final TransportReceiver receiver) {
String actualPayload = _clientFactory.getLastPayload();
TransportReceiver actualReceiver;
if (actualPayload == null) {
actualPayload = payload;
actualReceiver = receiver;
_clientFactory.setLastPayload(payload);
_clientFactory.setLastReceiver(receiver);
}
else {
actualReceiver = _clientFactory.getLastReceiver();
}
super.send(actualPayload, actualReceiver);
} // send()
//--------------------------------------------------------------------------------------------------
}
Based upon Thomas' suggestion I tried sending another request, and just replaced the payload and receiver in the RequestTransport.send() method, and this worked; I guess there is no further context retained by request factory, and that the response from the server is sufficient for RF to determine what needs to be done to unpack the response beyond the request and response that are returned to the RequestCallback.onResponseReceived() method. If anyone is interested in seeing my code then just let me know and I'll post it here.
It's possible, but you have a lot to do.
I had the same idea. And i was searching for a good solution for about 2 days. I tried to intercept the server call on RequestContext.java and on other classes. But if you do that you have to make your own implementation for nearly every class of gwt requestfactories. So i decided to go a much simpler approach.
Everywhere where I fired a Request, i handled the response and fired it again.
Of course you have to take care, that you don't get in to a loop.

Waiting until application return Sucess or Failure(AsyncCallBack)

Just for example, let's check the code below
private void loadUserFromServer() {
dispatchAsync.execute(new FindLoggedUserAction(),
new AsyncCallback<FindLoggerUserResult>() {
#Override
public void onFailure(Throwable caught) {
//do something
}
#Override
public void onSuccess(BuscarUsuarioLogadoResult result) {
//dosomething with user
result.getUser();
}
operationTwo();
}
My problem is, I have to execute operationTwo(); after some result of dipatcher(Success or failure).
This is just an example, let's assume I can't put operationTwo() inside the onSucess or onFailure()
My real PROBLEM
My GateKeeper of presenters that user must be login.
private UserDTO user;
#Override
public boolean canReveal() {
if(getUser() == null){
ShowMsgEvent.fire(eventBus,"Must Login first", AlertType.ERROR);
return false;
}
return true;
}
}
public UserDTO getUser()
{
if(user == null)
{
//call server
loadUserFromServer();
}
return user;
}
private void loadUsuarioFromServer() {
dispatchAsync.execute(new BuscarUsuarioLogadoAction()
,new AsyncCallback<BuscarUsuarioLogadoResult>() {
#Override
public void onFailure(Throwable caught) {
//something
}
#Override
public void onSuccess(BuscarUsuarioLogadoResult result) {
if(!(result.getDto().equals(user)))
{
setUsuario(result.getDto(), false); //Set user UserDTO user
//event for update Presenter Login/Logout
// and Label with username
fireUserUpdateEvents();
}
else
{
setUsuario(result.getDto(), false);
}
}
});
As you can see, when a Presenter with that Gatekeeper is called and user is null,
getUser() is called, but when dispatch executes, the method doesn't wait until the return of Sucess or Failure
Result: getUser() returns null.
After the sucessful result of dispatch, getUser() returns a DTO. But, as you can see canReveal() already returned false.
Do not think that GateKeeper is a good approach to handle security in your case. You will not be able to reach stable work. Problem that you will have:
You are not handling network connection lost. If you code is already cached but you need to reload User it will be a big problem with double checking.
Sync calls are always problematic, specially with bad network connection. You will have tons of not responding messages.
To handle presenter access it will be better to use revealInParent method. Most of your presenter already overrides it and it looks like:
#Override
protected void revealInParent() {
RevealContentEvent.fire(...);
}
So you can just not fire Reveal event before you actually download user data. In your case the code will looks like:
#Override
protected void revealInParent() {
if(getUser() == null){
RevealContentEvent.fire(...);
return;
}
dispatchAsync.execute(new BuscarUsuarioLogadoAction()
,new AsyncCallback<BuscarUsuarioLogadoResult>() {
#Override
public void onFailure(Throwable caught) {
//something
}
#Override
public void onSuccess(BuscarUsuarioLogadoResult result) {
if(!(result.getDto().equals(user)))
{
setUsuario(result.getDto(), false); //Set user UserDTO user
//event for update Presenter Login/Logout
// and Label with username
fireUserUpdateEvents();
}
else
{
setUsuario(result.getDto(), false);
}
RevealContentEvent.fire(...);
}
});
We have also encountered similar problems. Its better to use Async call chaining. Since you can't do that there are two options for your problem
Setup a timer which will check from time to time whether the user is null or not and return only after when user is populated.
Use JSNI (Native code) and make the synchronous call. But beware this is bad practice
Yes, as Abhijith mentioned in previous answer there are 2 options -
1) Synchronous calls - which GWT doesn't support. So it is ruled out.
2) Setting timer - unless user logs in control will not come out of the timer loop. So failed status will never return from the timer. This approach serves only half of your requierment(serving only success state).
To solve your problem you try the following code snippet -
private UserDTO user;
private CanRevealCallBack revealCallBack;
public interface CanRevealCallBack {
returnStatus(boolean status);
}
#Override
public void canReveal(CanRevealCallBack callBack) {
revealCallBack = callBack;
if(user == null){
loadUserFromServer();
}
else{
revealCallBack.returnStatus( true );
}
}
private void loadUsuarioFromServer() {
dispatchAsync.execute(new BuscarUsuarioLogadoAction()
,new AsyncCallback<BuscarUsuarioLogadoResult>() {
#Override
public void onFailure(Throwable caught) {
//something
}
#Override
public void onSuccess(BuscarUsuarioLogadoResult result) {
if(!(result.getDto().equals(user)))
{
setUsuario(result.getDto(), false); //Set user UserDTO user
//event for update Presenter Login/Logout
// and Label with username
fireUserUpdateEvents();
}
else
{
setUsuario(result.getDto(), false);
}
if(result.getDto() == null){
revealCallBack.returnStatus( true );
}
else{
revealCallBack.returnStatus( false );
}
}
});
So, you have to pass a revealCallback to the canReveal method. CallBack gets executed and returns u the status on success of the async call. In returnStatus method of the callback you can program the logic with the correct user log-in status.

How can i get the edited proxy from RequestFactoryEditorDriver

I can't figure out how to update my celltable after changes have been made using an editor. If I could get the edited proxy then I can use the dataprovider to update my celltable.
public void saveCampaign() {
driver.flush();
// the problem. proxy at this point should have the new values?....
context.persist().using(proxy).fire(new Receiver<Void>() {
#Override
public void onSuccess(Void response) {
showListView();
}
});
}
The proxy in .using(proxy) does not contain the changes made on the editor. However the persist method on the server gets the updated values. If I reload the data from the server I get the correct values to the celltable.
public void editCampaign(CampaignProxy proxy) {
this.proxy = proxy;
if (proxy != null) {
context = AEHOME.requestFactory.campaignRequest();
showEditView();
}
}
private void showEditView() {
driver.initialize(eventBus, AEHOME.requestFactory, editView);
driver.edit(proxy, context);
deckPanel.showWidget(deckPanel.getWidgetIndex(editView));
}
Proxy is set in the list view: configurationPageView.proxy = selectionModel.getSelectedObject();
Any advice would be greatly appreciated. Thank you.
You can change how the request is built by doing the following:
private void showEditView() {
driver.initialize(eventBus, AEHOME.requestFactory, editView);
driver.edit(proxy, context);
// Set up method invocation and callback in advance
context.persist().using(proxy).to(new Receiver<Void>() {
#Override
public void onSuccess(Void response) {
showListView();
}
}););
deckPanel.showWidget(deckPanel.getWidgetIndex(editView));
}
public void saveCampaign() {
driver.flush().fire();
}
In GWT 2.4 it will be possible to keep your current code organization and use RequestContext.append():
public void saveCampaign() {
// Returns the context passed to edit()
RequestContext ctx = driver.flush();
// append() is generic and returns the type returned by myProxyContext();
ctx.append(requestFactory.myProxyContext()).persist().using(proxy).fire(....);
}