I have a dialogflow project that I'm trying to access from Java with a rest call.
It is giving me an authentication issue.
I have followed all online instructions (and many forum suggestions) to no avail.
I have tried generating the key json, as per the instructions here:
https://dialogflow.com/docs/reference/v2-auth-setup
and setting my environment variable as described, but nothing seems to work.
I have checked my projectID, and am running off the same machine with the environment variable, and have double, triple and quadruple checked it's name and location, but I still get the following error:
java.net.HttpRetryException: cannot retry due to server authentication, in streaming mode
Here is my code (though it's a REST call, so I don't know if it's so relevant):
String url = https://dialogflow.googleapis.com/v2/projects/MYPROJECT/agent/sessions/SESSION_NUM:detectIntent
URL url = new URL(full_url);
String inText = "Hello World";
String outText = "";
HttpURLConnection con = (HttpURLConnection) url.openConnection();
try {
con.setDoOutput(true);
con.setRequestMethod("POST");
// set body of http post
Map<String,String> arguments = new HashMap<>();
JSONObject inTextJsn = new JSONObject();
inTextJsn.append("text",inText);
inTextJsn.append("languageCode","en");
JSONObject fieldJsn = new JSONObject();
fieldJsn.append("text", inTextJsn);
arguments.put("queryInput", fieldJsn.toString());
StringJoiner sj = new StringJoiner("&");
for(Map.Entry<String,String> entry : arguments.entrySet())
sj.add(URLEncoder.encode(entry.getKey(), "UTF-8") + "="
+ URLEncoder.encode(entry.getValue(), "UTF-8"));
// post http post as bytes
byte[] bytes_out = sj.toString().getBytes(StandardCharsets.UTF_8);
con.setFixedLengthStreamingMode(bytes_out.length);
con.connect();
try (OutputStream os = con.getOutputStream()) {
os.write(bytes_out);
}
BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream(),
"UTF-8"));
// read all lines to a string
String line;
String response = "";
while ((line = reader.readLine()) != null) {
response += line;
}
JSONObject responseJsn = new JSONObject(response);
outText = responseJsn.get("fulfillmentText").toString();
} catch (Exception e) {
System.err.println(e);
} finally {
con.disconnect();
}
return restResponse;
The gist of the code is to simply send a message ("Hello World!") to my dialogflow, and get back my agent's response (the code may have bugs - it's a bit hard to test when I can't get passed this authentication issue, so please help with the authentication, not code bugs).
Thanks all!
The directions at that page assume you're going to use the gcloud program to generate a currently valid bearer token, which is then sent along with the HTTP headers. That page illustrates
Your code doesn't seem to be generating an Authorization HTTP header at all, which is why you're getting the error you do.
Since you're using Java, you should look at the google-auth-library-java library, which will give you the tools to generate the token you need to provide in the Authorization header.
You may also wish to check out the google-cloud-java library. This contains Java classes to directly perform operations against Dialogflow instead of coding the REST/HTTP calls yourself. (However, it is still at an Alpha level for Dialogflow, so may not be stable or forwards compatible.)
Related
I am trying to build a Java code to create users in AAD using MSAL and MS Graph API. Below is the code that I am using to create the user. I am able to retrieve the token successfully, however getting exception while trying to POST the request. What am I doing wrong?
public static void main(String[] args) throws Exception {
Map<String,Object> params = new LinkedHashMap<>();
params.put("givenName", "Test");
params.put("displayName", "ABC");
params.put("accountEnabled", true);
params.put("mailNickname","abc");
params.put("userPrincipalName","jcooper#demo.onmicrosoft.com");
StringBuilder postData = new StringBuilder();
for (Map.Entry<String,Object> param : params.entrySet()) {
if (postData.length() != 0) postData.append('&');
postData.append(URLEncoder.encode(param.getKey(), "UTF-8"));
postData.append('=');
postData.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
}
byte[] postDataBytes = postData.toString().getBytes("UTF-8");
int length =postDataBytes.length;
URL url = new URL("https://graph.microsoft.com/v1.0/users");
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type","application/json");
conn.setRequestProperty("Authorization", "Bearer "+accessToken);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setInstanceFollowRedirects(false);
conn.setRequestProperty("Content-Length",Integer.toString(length));
conn.connect();
conn.getInputStream();
try (var wr = new DataOutputStream(conn.getOutputStream())) {
wr.write(postDataBytes);
}
StringBuilder content;
System.out.println(postDataBytes+" "+postData);
try (var br = new BufferedReader(
new InputStreamReader(conn.getInputStream()))) {
String line;
content = new StringBuilder();
while ((line = br.readLine()) != null) {
content.append(line);
content.append(System.lineSeparator());
}
}
System.out.println(content.toString());
}
Exception : Exception in thread "main" java.io.IOException: Server returned HTTP response code: 411 for URL: https://graph.microsoft.com/v1.0/users
According to some test, I met the same issue with yours. It seems the code is correct but do not know why it still show 411 error. It may be caused by the graph api can just accept json request body but you convert the request body to application/x-www-form-urlencoded in your first part of code(I'm not sure because I test the code with json request body but still show 411).
Since you mentioned use MSAL to get access token, you can also continue to use MSAL to create the user. Please refer to this example:
GraphServiceClient graphClient = GraphServiceClient.builder().authenticationProvider( authProvider ).buildClient();
User user = new User();
user.accountEnabled = true;
user.displayName = "Adele Vance";
user.mailNickname = "AdeleV";
user.userPrincipalName = "AdeleV#contoso.onmicrosoft.com";
PasswordProfile passwordProfile = new PasswordProfile();
passwordProfile.forceChangePasswordNextSignIn = true;
passwordProfile.password = "xWwvJ]6NMw+bWH-d";
user.passwordProfile = passwordProfile;
graphClient.users()
.buildRequest()
.post(user);
For accessing Microsoft Graph from a desktop app, I'd use the InteractiveBrowserCredentialBuilder() with the TokenCredentialAuthProvider that comes with GraphSDK to get the Graph token. Check out the great sample code here. All you'd need to do to customize this is to change the last line and set the scopes differently based on what Graph API you need to call. There's a link on the bottom of that page that'll teach you to register your app properly.
The simplest way in a web app is to use Azure AD Spring Boot Starter to get an access token for a logged-in user, and use GraphSDK to call Graph in a Spring 5 web app. See this sample that demonstrates this along with full instructions (Relevant Graph code is is in SampleController.java and Utilities.java)
I added an open extension to an event in a calendar and am trying to read it back.
Here is the url:
https://graph.microsoft.com/v1.0/users/{userid}/calendars/{calendarId}=/events?$expand=Extensions($filter=Id eq 'c.i.m.p.server.entities.outlook.Event')
I cannot get this to work in a Java program. The following combinations do work:
It works my Java program if I remove the $expand... parameter. I can also ask for certain fields, that works too.
The request works in Postman (I just have to set the token)
The request works in Graph Explorer when I log in as the owner of the calendar
Here is the extension (inside one of the events) when I use Postman to read the event. It is the last item in the event:
"extensions#odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('{userid}')/calendars('{calendarId}')/events('{eventId})/extensions",
"extensions": [
{
"#odata.type": "#microsoft.graph.openTypeExtension",
"id": "Microsoft.OutlookServices.OpenTypeExtension.c.i.m.p.server.entities.outlook.Event",
"extensionName": "c.i.m.p.server.entities.outlook.Event",
"adherentId": "12346",
"timeSlotID": "346463"
}
]
Here is the Java code (Java 8, using java.io and java.net libraries):
private static void doSomething(String _accessToken) throws IOException {
String urlString = "https://graph.microsoft.com/v1.0/users/{userId}/calendars/{calendarId}/events?$expand=Extensions($filter=Id eq 'c.i.m.p.server.entities.outlook.Event')";
URL url = new URL(urlString);
Proxy webProxy
= new Proxy(Proxy.Type.HTTP, new InetSocketAddress({proxy-address}, {port}));
HttpURLConnection connection = (HttpURLConnection) url.openConnection(webProxy);
// Set the appropriate header fields in the request header.
connection.setRequestProperty("Authorization", "Bearer " + _accessToken);
connection.setRequestProperty("Accept", "application/json");
connection.setDoOutput(true);
connection.setReadTimeout(5000);
connection.setRequestMethod(HttpMethod.GET);
try {
connection.connect();
int responseCode = connection.getResponseCode();
System.out.println("execute(), response code = " + responseCode);
String responseMessage = connection.getResponseMessage();
System.out.println("execute(), response Message = " + responseMessage);
String responseString = null;
try {
InputStream ins = connection.getInputStream();
BufferedReader br=new BufferedReader(new InputStreamReader(ins));
StringBuffer sb=new StringBuffer();
String line;
while ((line=br.readLine()) != null) {
sb.append(line);
}
responseString = sb.toString();
} catch (Exception e) {
System.out.println("Could not get input stream from response, error is " + e.toString());
}
System.out.println("execute(), httpResult = " + responseString);
} catch (IOException e) {
System.out.println(".execute(), IOException : " + e.toString());
} finally {
connection.disconnect();
}
}
How do I fix this? Thanks!
400 means bad request. It could be because of url encoding. Url encode the query string.
Something like
String query = "Extensions($filter=Id eq 'c.i.m.p.server.entities.outlook.Event'";
String url = "https://graph.microsoft.com/v1.0/users/{userId}/calendars/{calendarId}/events?
$expand=" + URLEncoder.encode(query, StandardCharsets.UTF_8.name());
Alternatively you could use graph service java api based on your need which will help abstract all the interactions for you or you could use any of the rest clients available.
First of all, you should provide more info on the error - Stacktrace and error message. But 400 code indicates that was a user mistake, meaning that you are sending an invalid request. Since you say that postman request works then compare all the headers that are sent by postman and see if your code misses some hearer. As for the code, instead of coding your own Http client functionality I would suggest using 3d party Http client. Here are a few suggestions:
Apache Http client - very popular and well known 3d party Http Client
OK Http client - Open-source Http client. Here is tutorial
MgntUtils Http client - very simple 3d party HttpClient: Provided in MgntUtils Open source library (written by me). Very simple in use. Take a look at Javadoc. Library itself provided as Maven artifacts and on Git (including source code and Javadoc).
I'm using HttpURLConnection to send JSON data from an Android Application to my Tomcat Server.
The POST works fine with small sized JSONs. On bigger data sets it fails with a FileNotFoundException.
What can it be?
Here's the code:
try {
URL url = new URL(urlIn);
strOut = "";
huc = (HttpURLConnection) url.openConnection();
huc.setRequestProperty("Connection", "Close");
huc.setRequestMethod("POST");
huc.setRequestProperty("User", userId);
huc.setRequestProperty("Action", action);
huc.setRequestProperty("JSON", jsonData);
huc.setConnectTimeout(10000);
in = new BufferedReader(new InputStreamReader(huc.getInputStream()));
while ((inputLine = in.readLine()) != null){
if (strOut.equalsIgnoreCase("")){
strOut = inputLine;
} else {
strOut = strOut + inputLine;
}
}
} catch (Exception e) {
strOut = "";
e.printStackTrace();
}
When jsonData get to a certain size (arround 10000 chars), the POST fails with the error mentioned. The content of the JSON does not have any special character.
Thanks in advance.
Best regards, Federico.
HTTPUrlConnection throws a FileNotFoundException if the server responds with a 404 response code, so the reason why this happens seems to be located on the server side rather than the client side. Most likely the server is configured to accept request headers up to a particular length and will return an error if that size is exceeded. A short Google-search brought up a couple of results, sizes of 16 KB are mentioned but shorter values are also reasonable.
As I mentioned in my comment to your question, you should change your process to receive the JSON-data (and the other values for User and Action as well BTW) as part of the request body, e.g. as url-encoded query string or as multipart formdata. Both ways are supported by HTTP client libraries you can use or are easily built manually.
After lots of reading and trying I gave up with configuring Tomcat to accept larger headers.
So I convinced the team in charge of the Tomcat app to make a servlet that is able to receive this data in the body, just as Lothar suggested.
Thanks!
I'm trying to make a webservice call where I have to pass
login.php?message=[{"email":"mikeymike#mouse.com","password":"tiger"}]
I've use backslash to escape the double quotes like this
String weblink = "login.php?message=[{\"email\":\"mikeymike#mouse.com\",\"password\":\"tiger\"}]";
But I'm still getting errors. I've tried making calls to other webservices which don't have require data with any double quotes and they work fine so I'm quite sure the problem is from this. Also I get a java.lang Exception saying
java.lang.Exception Indicates a serious configuration error.DateParseException An exception to indicate an error parsing a date string. DestroyFailedException Signals that the destroy() method failed
EDIT:
I've tried using URLEncoder and JSON object but still get an error
Here is the rest of the code
String HOST = "http://62.285.107.329/disaster/webservices/";
String weblink = "login.php?message=[{\"email\":\"mikeymike#mouse.com\",\"password\":\"tiger\"}]";
String result = callWebservice(weblink);
public String callWebservice(String weblink) {
String result = "";
try {
HttpParams httpParameters = new BasicHttpParams();
int timeoutConnection = 7500;
HttpConnectionParams.setConnectionTimeout(httpParameters,
timeoutConnection);
int timeoutSocket = 7500;
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
HttpClient client = new DefaultHttpClient(httpParameters);
HttpGet request = new HttpGet();
URI link = new URI(HOST + weblink);
request.setURI(link);
HttpResponse response = client.execute(request);
BufferedReader rd = new BufferedReader(new InputStreamReader(
response.getEntity().getContent()));
result = rd.readLine();
} catch (Exception e1) {
e1.printStackTrace();
result = "timeout";
}
return result;
}
Also the webservice returns a JSON object so could this also be a reason for the error?
Instead of trying this by hand and getting errors, why don't use use a combination of the JSONObject class and UrlEncoder.
JSONObject json = new JSONObject();
json.put("email","mikeymike#mouse.com" );
json.put("password", "tiger");
String s = "login.php?message=" + UrlEncoder.encode(json.toString());
You have to use %22 in place of " as in: login.php?message=[{%22email%22:%22mikeymike#mouse.com%22,%22password%22:%22tiger%22}]
" is not a valid character in an URL.
A more general solution is to use URLEncoder.encode("login.php?message=[{\"email\":\"mikeymike#mouse.com\",\"password\":\"tiger\"}]", "UTF8")
When you communicate with web services you need to URL encode your data. In your case, the url encoding would replace " with %22, but if you were to add other special characters, such as %, the encoding would capture these as well. There is a java class in the JDK for this, called URLEncoder.
So, basically, what you would do is to prepare your string using URLEncoder.encode(), like so:
String weblink = URLEncoder.encode("login.php?message=[{\"email\":\"mikeymike#mouse.com\",\"password\":\"tiger\"}]");
Now that the string is encoded, you should be able to send it along to the server and have it understand what you mean.
Apologies to all but it seems the problem was that I was trying to consume the webservice in the wrong way as it returns a JSON object.
The proper way to do this for anyone who might come across this is in the code below
String str="url";
try{
URL url=new URL(str);
URLConnection urlc=url.openConnection();
BufferedReader bfr=new BufferedReader(new InputStreamReader(urlc.getInputStream()));
String line;
while((line=bfr.readLine())!=null)
{
JSONArray jsa=new JSONArray(line);
for(int i=0;i<jsa.length();i++)
{
JSONObject jo=(JSONObject)jsa.get(i);
title=jo.getString("deal_title"); //tag name "deal_title",will return value that we save in title string
des=jo.getString("deal_description");
}
}
catch(Exeption e){
}
This answer was gotten from
How to call a json webservice through android
I have a Servlet that sends back a JSON Object and I would like to use this servlet in another Java project. I have this method that gets me the results:
public JSONArray getSQL(String aServletURL)
{
JSONArray toReturn = null;
String returnString = "";
try
{
URL myUrl = new URL(aServletURL);
URLConnection conn = myUrl.openConnection();
conn.setDoOutput(true);
BufferedReader in = new BufferedReader( new InputStreamReader( conn.getInputStream() ) );
String s;
while ((s = in.readLine()) != null )
returnString += s;
in.close();
toReturn = new JSONArray(returnString);
}
catch(Exception e)
{
return new JSONArray();
}
return toReturn;
}
This works pretty will, but the problem I am facing is the following:
When I do several simultaneous requests, the results get mixed up and I sometimes get a Response that does not match the request I send.
I suspect the problem to be related to the way I get the response back: The Reader reading a String from the InputStream of the connection.
How can I make sure that I get one reques -> one corresponding reply ?
Is there a better way to retrieve my JSON object from my servlet ?
Cheers,
Tim
When I do several simultaneous requests, the results get mixed up and I sometimes get a Response that does not match the request I send.
Your servlet is not thread safe. I'd bet that you've improperly assigned request scoped data either directly or indirectly as instance or class variables of the servlet. This is a common beginner's mistake.
Carefully read this How do servlets work? Instantiation, sessions, shared variables and multithreading and fix your servlet code accordingly. The problem is not in the URLConnection code shown so far, although it indicates that you're doing exactly the same job in both doGet() and doPost(), which in turn is already a smell as to how the servlet is designed.
Try removing setDoOutput(true), you are using the connection only for input and so you shouldn't use it.
Edit: alternatively try using HttpClient, it's much nicer that using "raw" Java.