Java Bot SDK throws 401 error for proactive message - java

I'm trying to implement a bot to send proactive messages. I made a proof of concept in NodeJS that works:
const { BotFrameworkAdapter } = require('botbuilder');
const adapter = new BotFrameworkAdapter({
appId: process.env.MicrosoftAppId,
appPassword: process.env.MicrosoftAppPassword
});
adapter.onTurnError = async (error) => {
console.error(error);
};
const cr = require('./test_cr.json');
adapter.continueConversation(cr, async (turnContext) => {
await turnContext.sendActivity('Node SDK proactive message')
});
Yet when I try to recreate this example using the Java SDK, I get com.microsoft.bot.connector.rest.ErrorResponseException: Status code 401, {"message":"Authorization has been denied for this request."}.
String appId = System.getenv("MicrosoftAppId");
String appPassword = System.getenv("MicrosoftAppPassword");
BotFrameworkAdapter bot = new BotFrameworkAdapter(new SimpleCredentialProvider(appId, appPassword));
ConversationReference cr = mapper.readValue(new File("test_cr.json"), ConversationReference.class);
CompletableFuture<Void> cf = bot.continueConversation(appId, cr, turnContext -> turnContext.sendActivity("Java SDK proactive message").thenApply(resourceResponse -> null));
cf.get();
The conversation reference and app credentials should be the same for both examples. Am I not setting up the Java bot correctly? For reference, I'm using a pretty barebones conversation reference:
{
"channelId":"msteams",
"serviceUrl":"https://smba.trafficmanager.net/amer/",
"conversation":{
"isGroup":true,
"conversationType":"channel",
"tenantId":"xxxxxx",
"id":"xxxxxx"
}
}

It sounds like it could be an issue with BotTrustServiceUrl. I can't explain it but in one of my bots, I had to add this additional code to get proactive messages to work (specifically after a restart). Not sure if this is your same issue but it helped me.
const { MicrosoftAppCredentials } = require('botframework-connector');
// Then in your proactive message section...
const conversationReference = req.body.conversationReference;
await adapter.continueConversation(conversationReference, async turnContext => {
// If you encounter permission-related errors when sending this message, see
// https://aka.ms/BotTrustServiceUrl
MicrosoftAppCredentials.trustServiceUrl(conversationReference.serviceUrl);
await turnContext.sendActivity(req.body.message);
});
Now I've also got two other bots where I didn't need to do this. The one that isn't working wihtout this code is using an older SDK so that could be it, both otherwise the proactive message functions are identical so I'm not sure.
EDIT: I misread the question and didn't notice that you were having trouble with Java SDK, not JavaScript SDK. But perhaps you could use the same method to see if this resolves your issue in Java as well.

Related

Vertx.io GET silently fails

I'm writing a POC using vertx, looking for alternatives when we have to migrate Spring Web from 4.x to 5 to be java 9 compliant.
I've written a simple client, just a GET towards a publicly available server just to get something working but it silently fails me.
public List<String> pull() {
Vertx vertx = Vertx.vertx();
HttpClientOptions options = new HttpClientOptions().setLogActivity(true);
HttpClient hc = vertx.createHttpClient(options);
hc.getNow(80, "http://sunet.se", "/",r -> {
System.out.println("\n****** Handler called! ***\n");
});
return new ArrayList<>();
}
This will silently fail and I cannot understand why.
As far as I can tell, I do exactly as in the examples given in the docs.
In desperation I fired up wire shark and according to WS, there is no actual call (when I use the browser WS captures that). So, it seems my call is never actually done. I don't get any exceptions or anything. Setting the log level to debug gives nothing noteworthy other than
Failed to get SOMAXCONN from sysctl and file /proc/sys/net/core/somaxconn. Default: 128
And that should not fail the call.
I've also tried using vertx.io WebClient but that fails also, in the same manner.
UPDATE
I've managed to get it to work but with a caveat.
As #tsegismont states in his answer, the protocol part of the URI shouldn't be there, that was not in the examples, I just missed it myself.
I ran my example as a stand-alone and then it worked.
My original example was run as a junit test (it's an easy way to test code and I usually try to write the test code first) and when it's run as a junit test it still doesn't work. Why that is, I have no idea. I would greatly appreciate if someone could tell me how to get that to work.
The getNow variant you use expects the server host, not a URL. It should be:
hc.getNow(80, "sunet.se", "/",r -> {
System.out.println("\n****** Handler called! ***\n");
}
If you found a snippet like this in the Vert.x docs it's a bug. Would you mind to report it?
Now a few comments.
1/ The HttpClient is a low-level client.
Most users should prefer the Vert.x Web Client
Here's an example for your use case:
WebClient client = WebClient.create(vertx);
client
.get(80, "sunet.se", "/")
.send(ar -> {
if (ar.succeeded()) {
// Obtain response
HttpResponse<Buffer> response = ar.result();
System.out.println("Received response with status code" + response.statusCode());
} else {
System.out.println("Something went wrong " + ar.cause().getMessage());
}
});
2/ Create a single Vert.x and WebClient instance
Do not create a Vert.x and WebClient instance on every method call.
It wastes resources and is inefficient.

Java websocket draft refuses handshake

I am working on android(Java) using TooTallNate's java websockets from this tutorial to consume websockets on android to connect with ws:// but I am getting error draft org.java_websocket.drafts.Draft_10#4560b1d0 refuses handshake. I tried their other draft versions but none of them worked either.
First of all, you want to use the Draft_6455, it is the current spec, the rest may or may not work on different servers reliably. There are constructors for the draft object which take a List<IProtocol>. If no protocol specified matches one offered by the server, the handshake will be refused.
public Draft_6455( List<IExtension> inputExtensions , List<IProtocol> inputProtocols )
public Draft_6455( List<IExtension> inputExtensions , List<IProtocol> inputProtocols, int inputMaxFrameSize )
I ran into a similar issue to yours with the newest version of TooTallNate's Java Websockets, my code was like so:
knownExtensions = new java.util.ArrayList();
knownProtocols = new java.util.ArrayList();
if(this._protocol){
knownProtocols.add(new org.java_websocket.protocols.Protocol(this._protocol));
}
this._socket = new _WebSocket(uri, new org.java_websocket.drafts.Draft_6455(knownExtensions, knownProtocols), toHashMap(this._headers), this._timeout);
You MUST have at least one valid protocol (even if it is a empty string), or you get the above error you referenced. So I changed my code to be:
...
if(this._protocol){
knownProtocols.add(new org.java_websocket.protocols.Protocol(this._protocol));
}
/* -=-=-=- NEW ADDED CODE -=-=-=- */
else {
knownProtocols.add(new org.java_websocket.protocols.Protocol(""));
}
/* -=-=-=- END NEW ADDED CODE -=-=-=- */
...
This is what broke, no protocol specified caused the "refuses handshake" error message for me.
Please note there are a couple of reasons for the above "refuses handshake", but in my case it was the missing empty protocol...
Did you try this on broswer? You will get a err code on the broswer.
You can write a simple js file to start and test whether this problem is on the server or is on the app.
Here is a demo,it won't take you too much time.
<script type="text/javascript">
function send() {
var url = 'ws://192.168.1.101:8080/WebSocket/echo';
var vs = new WebSocket(url);
vs.onopen = function(evt){
vs.send(te.value)
};
vs.onmessage = function(evt){
alert(evt.data);
};
}
Basically if you have for example a protocol "my-protocol"
ArrayList<IProtocol> protocols = new ArrayList<IProtocol>();
protocols.add(new Protocol("my-protocol"));
//Uncomment below if you want to have a fallback
//protocols.add(new Protocol(""));
Draft_6455 my_draft = new Draft_6455(Collections.<IExtension>emptyList(), protocols);
Taken from here

Use of eventBus in vertx

I am using vertx in my project and I have problems with eventBus. If I understood right, it ables several languages to communicate using one string representing a server route. I have this code in my Server.java:
vertx.eventBus().registerHandler("getTree", new Handler<Message<String>>() {
public void handle(Message<String> e) {
// e.reply(call of function returning a json string);
}
});
In a javascript file, I need to get that json string just to print it for the moment. I have:
var eventBus = require('vertx/event_bus');
eventBus.send('getTree', '', function(reply) {
console.log('I received a reply ' + reply);
});
}
But nothing happens. Does anyone know why ?
I assume that you would like to see something like I received a reply in your console.
In order to be able to receive anything back to your JavaScript reply handler, you will need to change your Java message handler and call reply method on the incoming message e.g.
vertx.eventBus().registerHandler("getTree", new Handler<Message<String>>() {
public void handle(Message<String> msg) {
msg.reply("message from Java handler");
}
});
Without calling a reply method, nothing will happen in your JavaScript sender / reply receiver code.
After adding the mentioned change to your Java code you should be able to see following logs in console:
I received a reply message from Java handler
Note that even though you use different languages with Vert.x, entire logic is executed by JVM (JavaScript by Rhino open-source implementation).

Adding API method to App Engine causes NullPointerException

I'm using the local App Engine and I have a working Endpoint, but when I add the following API, the API Explorer (https://developers.google.com/apis-explorer/?base=http://localhost:8888/_ah/api#p/) doesn't load while the JavaScript console has an unhandled exception.
#ApiMethod(name = "getClientByPublicId")
public Client getClientByPublicId(#Named("publicId") String publicId) {
EntityManager mgr = getEntityManager();
Client client = null;
client = mgr.find(Client.class, publicId);
mgr.close();
return client;
}
Within the Chrome JavaScript console, it doesn't give anything useful because it's minimized
Uncaught java.lang.NullPointerException
(anonymous function)
(anonymous function)
h
(anonymous function)
F.(anonymous function).z.(anonymous function).z.(anonymous function)
_.T.K.__cb
h
c
The whole API Explorer page comes up blank.
I've ran this in debug mode and set a breakpoint within the added API, but it isn't triggered.
If I load the discovery document at http://localhost:8888/_ah/api/discovery/v1/apis/clientendpoint/v1/rest, it fails with the following response.
{
"error" : {
"message" : ""
}
}
If I remove this new API it all works fine, albeit without having the new API.
Anyone know what is causing this?
Update
I stumbled across Google APis Explorer didn't found my available ApiMethod from my app-engine app and it sounds like there may be a path collision, which I don't understand yet but I'm going to try to work on this idea now.
If this may be the issue, the related API is
#ApiMethod(name = "getClient")
public Client getClient(#Named("id") Long id) {
EntityManager mgr = getEntityManager();
Client client = null;
try {
client = mgr.find(Client.class, id);
} finally {
mgr.close();
}
return client;
}
I'll give this a shot and answer my question, unless someone knows different.
After finding Google APis Explorer didn't found my available ApiMethod from my app-engine app I learned that you must include a new path.
For example, I was able to alter the ApiMethod to
#ApiMethod(
name = "getClientByPublicId",
path = "client/publicId/{publicId}",
httpMethod = "GET"
)
Works great now.

GAE/J Channel API exception even though messages go through?

I open a channel during the app initialization through a series of ajax calls:
getToken = function () {
xhr = new XMLHttpRequest();
xhr.open("GET", "/game?action=getChannelToken", true);
xhr.send(null);
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status==200) {
connect(xhr.responseText);
}
};
};
Servlet:
ChannelService channelService = ChannelServiceFactory.getChannelService();
channelToken = channelService.createChannel(uid);
The token is then returned to the javascript for:
connect = function (token) {
// alert ("connect");
var channel = new goog.appengine.Channel(token);
var socket = channel.open();
socket.onopen = onOpened;
socket.onmessage = onMessage;
socket.onerror = onError;
socket.onclose = onClose;
};
I'm getting this error:
WARNING: /_ah/channel/dev
com.google.appengine.api.channel.dev.LocalChannelFailureException:
Channel for application key null not
found.
The channel creation part is very simple, so I do not understand where is the problem.
System.out.println (channelToken); returns something like
channel--rrmk8i-100002139544068
(100002139544068 is the uid I used to create the channel), so it seems to return a real token. Moreover, channelService.sendMessage(msg); (using the same uid as before), sends the message without any problem.
Does anyone have any idea why this is happening?
I'm using eclipse 3.5.2, GAE/J 1.4.2 and ubuntu 10.10
Googling for that exception I found only one discussion here:
http://groups.google.com/group/google-appengine-java/browse_thread/thread/19f250b1ff0e4342
but changing var channel = new goog.appengine.Channel(token); to var channel = new goog.appengine.Channel(uid); did not solve anything (and, from what I understand, it shouldn't)
I can think of two reasons this could be happening:
You're restarting the dev_appserver.py while your client is still running. Because the client will be polling with an "old" token that the dev_appserver doesn't know about, it will throw this error. If this is the case, just refresh your client page after restarting the dev_appserver (or otherwise force it to request a new token).
connect() is being called with an invalid token. It sounds like you've ruled that out but if the above isn't true it might be worth double-checking.
You can see what token the client is polling with you can open up Firebug or the Chrome dev console and look for requests to a path like this:
http://localhost:8080/_ah/channel/dev?command=poll&channel=channel-1503856530-alpha-token&client=1
The channel-1503856530-alpha-token part of that URL is the token passed to "new goog.appengine.Channel()".

Categories