How to send messages from an app to a user using restfb? - java

I am trying to use restfb to send a message to who likes the page.Using the graph API I got the page access_token and recipient_id.When I try to send it ends in an exception showing
Exception in thread "main" com.restfb.exception.FacebookOAuthException: Received Facebook error response of type OAuthException: Error validating access token: Session has expired on Friday, 03-Feb-17 03:00:00 PST. The current time is Friday, 03-Feb-17 21:20:41 PST. (code 190, subcode 463)
But when I try to access the details of user in graph it is working fine.Am i doing something wrong?..Please help
Thanks in advance....
The java code
import java.util.List;
import com.restfb.*;
import com.restfb.FacebookClient.AccessToken;
import com.restfb.exception.FacebookException;
import com.restfb.json.JsonObject;
import com.restfb.types.Conversation;
import com.restfb.types.Message;
import com.restfb.types.User;
import com.restfb.types.send.IdMessageRecipient;
import com.restfb.types.send.PhoneMessageRecipient;
import com.restfb.types.send.SendResponse;
import facebook4j.Facebook;
public class Fbsample {
public static void main(String[] argv) throws FacebookException
{
FacebookClient facebookClient = new DefaultFacebookClient("***");
User user = facebookClient.fetchObject("me", User.class);
String name=user.getFirstName();
String email=user.getEmail();
String id=user.getId();
System.out.println(name);
System.out.println(id);
JsonObject picture = facebookClient.fetchObject("me/picture",JsonObject.class,Parameter.with("redirect","false"), Parameter.with("type","large"));
System.out.println(picture);
IdMessageRecipient recipient = new IdMessageRecipient("****");
Message msg = new Message();
msg.setMessage("Hello");
String pageAccessToken ="***";
// create a version 2.6 client
FacebookClient pageClient = new DefaultFacebookClient(pageAccessToken, Version.VERSION_2_6);
SendResponse resp = pageClient.publish("me/messages", SendResponse.class,
Parameter.with("recipient", recipient), // the id or phone recipient
Parameter.with("message", msg)); // one of the messages from above
}
}
Here instead of real access token and recipient_id I have given * for now.And one more thing which id should I give the user_id or conversation_id and access token for page or user?...

Related

Reading labels works but reading messages results in ACCESS_TOKEN_SCOPE_INSUFFICIENT

I have created one poc using Gmail API which read all email and print on console. I have take refrence from Gmail api Java quickstart.
I have follows all the steps like create project, Gmail API enable, OAuth credentials in google cloud console
The problem is, when I run the code all the labels are printed successfully but I'm not able to read mail messages. Some an error are getting which are below:
> Task :GmailQuickstart.main()
Labels:
- CHAT
- SENT
- INBOX
- IMPORTANT
- TRASH
- DRAFT
- SPAM
- CATEGORY_FORUMS
- CATEGORY_UPDATES
- CATEGORY_PERSONAL
- CATEGORY_PROMOTIONS
- CATEGORY_SOCIAL
- STARRED
- UNREAD
Exception in thread "main" com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
GET https://gmail.googleapis.com/gmail/v1/users/me/messages
{
"code": 403,
"details": [
{
"#type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "ACCESS_TOKEN_SCOPE_INSUFFICIENT"
}
],
"errors": [
{
"domain": "global",
"message": "Insufficient Permission",
"reason": "insufficientPermissions"
}
],
"message": "Request had insufficient authentication scopes.",
"status": "PERMISSION_DENIED"
}
at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:146)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:118)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:37)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest$1.interceptResponse(AbstractGoogleClientRequest.java:439)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1111)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:525)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:466)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:576)
at GmailQuickstart.main(GmailQuickstart.java:80)
> Task :GmailQuickstart.main() FAILED
Execution failed for task ':GmailQuickstart.main()'.
> Process 'command '/home/bhautik/Downloads/jdk-11.0.15.1_linux-x64_bin/data/usr/lib/jvm/jdk-11/bin/java'' finished with non-zero exit value 1
* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
And my code was below:
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.client.util.store.FileDataStoreFactory;
import com.google.api.services.gmail.Gmail;
import com.google.api.services.gmail.GmailScopes;
import com.google.api.services.gmail.model.Label;
import com.google.api.services.gmail.model.ListLabelsResponse;
import com.google.api.services.gmail.model.ListMessagesResponse;
import com.google.api.services.gmail.model.Message;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/* class to demonstrate use of Gmail list labels API */
public class GmailQuickstart {
private static final String APPLICATION_NAME = "Gmail API Java Quickstart";
private static final JsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance();
private static final String TOKENS_DIRECTORY_PATH = "tokens";
private static final List<String> SCOPES = Collections.singletonList(GmailScopes.GMAIL_LABELS);
private static final String CREDENTIALS_FILE_PATH = "/credentials.json";
private static final String USER_ID = "me";
private static Credential getCredentials(final NetHttpTransport HTTP_TRANSPORT)
throws IOException {
// Load client secrets.
InputStream in = GmailQuickstart.class.getResourceAsStream(CREDENTIALS_FILE_PATH);
if (in == null) {
throw new FileNotFoundException("Resource not found: " + CREDENTIALS_FILE_PATH);
}
GoogleClientSecrets clientSecrets =
GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));
// Build flow and trigger user authorization request.
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
.setDataStoreFactory(new FileDataStoreFactory(new java.io.File(TOKENS_DIRECTORY_PATH)))
.setAccessType("offline")
.build();
LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(8888).build();
Credential credential = new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");
//returns an authorized Credential object.
return credential;
}
public static void main(String... args) throws IOException, GeneralSecurityException {
// Build a new authorized API client service.
final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
Gmail service = new Gmail.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials(HTTP_TRANSPORT))
.setApplicationName(APPLICATION_NAME)
.build();
// Print the labels in the user's account.
String user = "me";
ListLabelsResponse listResponse = service.users().labels().list(user).execute();
List<Label> labels = listResponse.getLabels();
if (labels.isEmpty()) {
System.out.println("No labels found.");
} else {
System.out.println("Labels:");
for (Label label : labels) {
System.out.printf("- %s\n", label.getName());
}
}
// Print the message
ListMessagesResponse response = service.users().messages().list(USER_ID).execute();
// List<Message> messages = response.getMessages();
List<Message> messages = new ArrayList<Message>();
while (response.getMessages() != null) {
messages.addAll(response.getMessages());
if (response.getNextPageToken() != null) {
String pageToken = response.getNextPageToken();
response = service.users().messages().list(USER_ID).setPageToken(pageToken).execute();
} else {
break;
}
}
for (Message message : messages) {
System.out.println(message.getId());
System.out.println(message.getPayload());
Message test = service.users().messages().get("me", message.getId()).execute();
System.out.println(test.getSnippet());
}
}
}
ACCESS_TOKEN_SCOPE_INSUFFICIENT is a very common error message. It comes from copying the example without understanding what its doing. This is googles fault for not explaining things better.
The quick start uses the lables.list method. This method runs on users private data so you used Oauth2 to request permission of the user to access their data.
The method can run with any of the following permissions being requested
Best practice is to only request the permissions you need. So the code is asking for the GmailScopes.GMAIL_LABELS permission which will only give you access to see the lables
Now to read a users messages the messges.listmethod you need to request permission with one of the following scopes
as you can see the label scope is not there. Thats because you need a higher level of permissions to access this data..
Solution:
Change the scope in your code to request one of the scopes needed for messgaes.list.
Then you need to reauthorize your application. YOu can do this in a few was.
delete the file found in TOKENS_DIRECTORY_PATH
change .authorize("user"); the text passed here to something else.
When you run your app again it should prompt you for authorization again.
I would comment but I have too few rep.
I guess you didn't properly set up the permissions of your access token. The error message suggessts, that you need a specific set of permissions to access the ressource

Get post form twitter public profile in java

I am trying to review twitter public profile using twitter4J.
I tried the examples on twitter4j git location but it did not worked.
import java.util.ArrayList;
import java.util.List;
import twitter4j.Paging;
import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.conf.ConfigurationBuilder;
public class TwitterTimeLine {
public static void main(String[] args) {
ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setOAuthConsumerKey("");
cb.setOAuthConsumerSecret("");
cb.setOAuthAccessToken("");
cb.setOAuthAccessTokenSecret("");
Twitter twitter = new TwitterFactory(cb.build()).getInstance();
int pageno = 1;
String user = "google";
List<Status> statuses = new ArrayList<Status>();
while (true) {
try {
int size = statuses.size();
Paging page = new Paging(pageno++, 100);
statuses.addAll(twitter.getUserTimeline(user, page));
if (statuses.size() == size)
break;
}
catch(TwitterException e) {
e.printStackTrace();
}
}
System.out.println("Total: "+statuses.size());
}
}
But it always gives me error
400:The request was invalid. An accompanying error message will explain why. This is the status code will be returned during version 1.0 rate limiting(https://dev.twitter.com/pages/rate-limiting). In API v1.1, a request without authentication is considered invalid and you will get this response.
message - Bad Authentication data.
code - 215
Relevant discussions can be found on the Internet at:
http://www.google.co.jp/search?q=4be80492 or
http://www.google.co.jp/search?q=0a6306df
TwitterException{exceptionCode=[4be80492-0a6306df], statusCode=400, message=Bad Authentication data., code=215, retryAfter=-1, rateLimitStatus=null, version=4.0.4}
at twitter4j.HttpClientImpl.handleRequest(HttpClientImpl.java:164)
at twitter4j.HttpClientBase.request(HttpClientBase.java:57)
at twitter4j.HttpClientBase.get(HttpClientBase.java:75)
at twitter4j.TwitterImpl.get(TwitterImpl.java:1786)
at twitter4j.TwitterImpl.getUserTimeline(TwitterImpl.java:131)
at com.twitter.ibeat.iBeatTwitter.TwitterTimeLine.main(TwitterTimeLine.java:33)
400:The request was invalid. An accompanying error message will explain why. This is the status code will be returned during version 1.0 rate limiting(https://dev.twitter.com/pages/rate-limiting). In API v1.1, a request without authentication is considered invalid and you will get this response.
message - Bad Authentication data.
code - 215
Could you please help me to get this working.
Regards
Virendra Agarwal
Problem was solved using oAuth token and Query API from twitter4J.

Need help on Google API Calendar V3 Java and OAUTH2

i'm trying to handle my Google Agenda by using the Google Calendar APi V3( Java ).
However, i'm quite new to this and to OAUTH2 .. then i've searched for examples and i found one here :
Google Calendar API V3 Java: Unable to use 'primary' for Calendars:get
Here is the code :
import java.io.IOException;
import java.util.Collections;
import java.util.Scanner;
import java.util.Set;
import com.google.api.client.auth.oauth2.AuthorizationCodeFlow;
import com.google.api.client.auth.oauth2.AuthorizationCodeRequestUrl;
import com.google.api.client.auth.oauth2.AuthorizationCodeTokenRequest;
import com.google.api.client.auth.oauth2.TokenResponse;
import com.google.api.client.extensions.auth.helpers.Credential;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.calendar.Calendar;
import com.google.api.services.calendar.Calendar.CalendarList;
import com.google.api.services.calendar.CalendarScopes;
import com.google.api.services.calendar.model.CalendarListEntry;
public class App {
public static void main(String[] args) throws IOException{
//Two globals that will be used in each step.
HttpTransport httpTransport = new NetHttpTransport();
JsonFactory jsonFactory = new JacksonFactory();
//Create the authorization code flow manager
Set<String> scope = Collections.singleton(CalendarScopes.CALENDAR);
String clientId = "xxxxxx.apps.googleusercontent.com";
String clientSecret = "xxxxxxxxxxx";
//Use a factory pattern to create the code flow
AuthorizationCodeFlow.Builder codeFlowBuilder =
new GoogleAuthorizationCodeFlow.Builder(
httpTransport,
jsonFactory,
clientId,
clientSecret,
scope
);
AuthorizationCodeFlow codeFlow = codeFlowBuilder.build();
//set the code flow to use a dummy user
//in a servlet, this could be the session id
String userId = "ipeech";
//"redirect" to the authentication url
String redirectUri = "https://www.example.com/oauth2callback";
AuthorizationCodeRequestUrl authorizationUrl = codeFlow.newAuthorizationUrl();
authorizationUrl.setRedirectUri(redirectUri);
System.out.println("Go to the following address:");
System.out.println(authorizationUrl);
//use the code that is returned as a url parameter
//to request an authorization token
System.out.println("What is the 'code' url parameter?");
String code = new Scanner(System.in).nextLine();
AuthorizationCodeTokenRequest tokenRequest = codeFlow.newTokenRequest(code);
tokenRequest.setRedirectUri(redirectUri);
TokenResponse tokenResponse = tokenRequest.execute();
//Now, with the token and user id, we have credentials
com.google.api.client.auth.oauth2.Credential credential = codeFlow.createAndStoreCredential(tokenResponse, userId);
//Credentials may be used to initialize http requests
HttpRequestInitializer initializer = credential;
//and thus are used to initialize the calendar service
Calendar.Builder serviceBuilder = new Calendar.Builder(
httpTransport, jsonFactory, initializer);
serviceBuilder.setApplicationName("Example");
Calendar calendar = serviceBuilder.build();
//get some data
String calendarID = "xxxxxxxxxxx";
getCalendarListSummary(calendarID,calendar);
getAllCalendarListSummary(calendar);
//getCalendarSummary(calendarID,calendar);
}
public static void getCalendarListSummary(String calendarID, Calendar calendar) throws IOException{
CalendarListEntry calendarListEntry = calendar.calendarList().get(calendarID).execute();
System.out.println(calendarListEntry.getSummary());
}
public static void getAllCalendarListSummary (Calendar calendar) throws IOException{
Calendar.CalendarList.List listRequest = calendar.calendarList().list();
com.google.api.services.calendar.model.CalendarList feed = listRequest.execute();
for(CalendarListEntry entry:feed.getItems()){
System.out.println("ID: " + entry.getId());
System.out.println("Summary: " + entry.getSummary());
}
}
When i launch the programm, it asks me to give the authorization code ("What is the 'code' url parameter?") but i don't know where to find it .. Any ideas ?
In this example, there is a part that says "Go to the following address:" you have to copy that url, paste it in the browser and then you will receive the authorization code. Copy that code and paste it after "What is the 'code' url parameter?" and press "Enter" so the program can continue.
This is a basic example and that why the OAuth 2 flow is done that way.
Here is a complete example of a Google calendar java program. I would suggest to first understand how OAuth 2 works, how to create projects in the Developer console and how to create credentials for those projects. Then it would be easier to understand and use the complete example.

cannot parse headers to create MIME message

I'm trying to send messages only to myself, not out to or through the intertubes, based on the Apache NNTP API. The particular class involved takes an NNTP message and attempts to parse it into a regular MIME type message as so:
package net.bounceme.dur.nntp;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.Properties;
import javax.mail.Address;
import javax.mail.Header;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.NoSuchProviderException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
public class MessageSender {
private final static Logger LOG = Logger.getLogger(MessageSender.class.getName());
private String header;
private String body;
private Properties p;
private Session session;
private MimeMessage message;
private MessageSender() {
}
public MessageSender(Properties p, String... s) throws Exception {
header = s[0];
body = s[1];
this.p = p;
populate();
}
private void populate() throws Exception {
String lines[] = header.split("\\n");
session = Session.getDefaultInstance(p, null);
message = new MimeMessage(session);
LOG.fine("\n\n\n\nnew message************\n\n\n\n");
for (String s : lines) {
if (!s.contains("comp.lang.java.help")) {
message.addHeaderLine(s);
}
}
message.setContent(message, body);
String recipient = p.getProperty("recipient");
message.setRecipients(Message.RecipientType.TO,
InternetAddress.parse(recipient));
try {
send();
} catch (javax.mail.internet.ParseException e) {
LOG.warning(e.toString());
} catch (com.sun.mail.smtp.SMTPAddressFailedException e) {
LOG.warning(e.toString());
List<Address> addresses = Arrays.asList(message.getAllRecipients());
for (Address a : addresses) {
LOG.info(a.toString());
}
}
}
private void send() throws Exception {
String protocol = p.getProperty("protocol");
String host = p.getProperty("host");
int port = Integer.valueOf(p.getProperty("port"));
String username = p.getProperty("username");
String password = p.getProperty("password");
Transport transport = session.getTransport(protocol);
LOG.log(Level.FINE, "{0}{1}{2}{3}{4}", new Object[]{protocol, host, port, username, password});
Enumeration enumOfHeaders = message.getAllHeaders();
while (enumOfHeaders.hasMoreElements()) {
Header h = (Header) enumOfHeaders.nextElement();
LOG.log(Level.FINE, "\n\n\nHEADER\n{0}\n{1}", new Object[]{h.getName(), h.getValue()});
}
transport.connect(host, port, username, password);
transport.sendMessage(message, message.getAllRecipients());
}
}
But I'm having trouble with the headers:
init:
Deleting: /home/thufir/NetBeansProjects/apache_nntp/build/built-jar.properties
deps-jar:
Updating property file: /home/thufir/NetBeansProjects/apache_nntp/build/built-jar.properties
Compiling 1 source file to /home/thufir/NetBeansProjects/apache_nntp/build/classes
compile:
run:
200 Leafnode NNTP Daemon, version 1.11.8 running at localhost (my fqdn: dur.bounceme.net)
GROUP comp.lang.java.help
211 35 3 37 comp.lang.java.help group selected
HEAD 3
221 3 <7e60dce5-09d7-4cee-bbc1-137207f03dd0#googlegroups.com> article retrieved - head follows
BODY 3
222 3 <7e60dce5-09d7-4cee-bbc1-137207f03dd0#googlegroups.com> article retrieved - body follows
Feb 24, 2013 3:05:04 AM net.bounceme.dur.nntp.MessageSender populate
WARNING: javax.mail.internet.ParseException: Expected '/', got wrote
HEAD 4
221 4 <kfpdt3$5g9$1#dont-email.me> article retrieved - head follows
BODY 4
222 4 <kfpdt3$5g9$1#dont-email.me> article retrieved - body follows
Exception in thread "main" javax.mail.SendFailedException: Invalid Addresses;
nested exception is:
com.sun.mail.smtp.SMTPAddressFailedException: 450 4.1.8 <markspace#nospam.nospam>: Sender address rejected: Domain not found
at com.sun.mail.smtp.SMTPTransport.rcptTo(SMTPTransport.java:1863)
at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1119)
at net.bounceme.dur.nntp.MessageSender.send(MessageSender.java:80)
at net.bounceme.dur.nntp.MessageSender.populate(MessageSender.java:54)
at net.bounceme.dur.nntp.MessageSender.<init>(MessageSender.java:35)
at net.bounceme.dur.nntp.ArticleReader.<init>(ArticleReader.java:28)
at net.bounceme.dur.nntp.Driver.<init>(Driver.java:13)
at net.bounceme.dur.nntp.Driver.main(Driver.java:17)
Caused by: com.sun.mail.smtp.SMTPAddressFailedException: 450 4.1.8 <markspace#nospam.nospam>: Sender address rejected: Domain not found
at com.sun.mail.smtp.SMTPTransport.rcptTo(SMTPTransport.java:1730)
... 7 more
Java Result: 1
BUILD SUCCESSFUL (total time: 6 seconds)
Now, I appreciate that there's no domain for the sender. Nonetheless, I want to go ahead and send the message. Do I need to change the sender? I'd like to muck with the headers as little as possible.
If there's a better way to convert NNTP --> MIME Message I'm certainly open to suggestions. I'm already dropping the newsgroup header as that seems problematic for reasons I don't understand. Basically, I just can't figure out how to parse these headers so that they create a valid message to send.
Yes, you need to fix the sender info. The issue is not (quite) your code. Your MTA is rejecting the e-mail. Sendmail is often configured to not allow a "from" address that appears invalid. In this case, it's telling you that a DNS lookup fails for "nospam.nospam".
Your envelope should reflect a sender of something like news2mail#myhost.org instead of trying to use the address of the usenet article poster.
There are multiple usenet news to e-mail gateways available; you might want to look at using one of them instead of rolling your own.

BigQuery and OAuth2

I'm trying to access Google BigQuery using Service Account approach. My code is as follows:
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
private static final JsonFactory JSON_FACTORY = new JacksonFactory();
GoogleCredential credentials = new GoogleCredential.Builder()
.setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId("XXXXX#developer.gserviceaccount.com")
.setServiceAccountScopes(BigqueryScopes.BIGQUERY)
.setServiceAccountPrivateKeyFromP12File(
new File("PATH-TO-privatekey.p12"))
.build();
Bigquery bigquery = Bigquery.builder(HTTP_TRANSPORT, JSON_FACTORY).setHttpRequestInitializer(credentials)
.build();
com.google.api.services.bigquery.Bigquery.Datasets.List datasetRequest = bigquery.datasets().list(
"PROJECT_ID");
DatasetList datasetList = datasetRequest.execute();
if (datasetList.getDatasets() != null) {
java.util.List<Datasets> datasets = datasetList.getDatasets();
System.out.println("Available datasets\n----------------");
for (Datasets dataset : datasets) {
System.out.format("%s\n", dataset.getDatasetReference().getDatasetId());
}
}
But it throws the following exception:
Exception in thread "main" com.google.api.client.googleapis.json.GoogleJsonResponseException: 401 Unauthorized
{
"code" : 401,
"errors" : [ {
"domain" : "global",
"location" : "Authorization",
"locationType" : "header",
"message" : "Authorization required",
"reason" : "required"
} ],
"message" : "Authorization required"
}
at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:159)
at com.google.api.client.googleapis.json.GoogleJsonResponseException.execute(GoogleJsonResponseException.java:187)
at com.google.api.client.googleapis.services.GoogleClient.executeUnparsed(GoogleClient.java:115)
at com.google.api.client.http.json.JsonHttpRequest.executeUnparsed(JsonHttpRequest.java:112)
at com.google.api.services.bigquery.Bigquery$Datasets$List.execute(Bigquery.java:979)
The exception is fired on this line:
DatasetList datasetList = datasetRequest.execute();
I'm getting the account ID from Google's API console from the second line on the section that looks like this:
Client ID: XXXXX.apps.googleusercontent.com
Email address: XXXXX#developer.gserviceaccount.com
What am I missing?
Eureka! Both Eric's and Michael's code works well.
The error posted in the question can be reproduced by setting the time on the client machine incorrectly. Fortunately, it can be solved by setting the time on the client machine correctly.
Note: For what it's worth, I synchronized the time on a Windows 7 box using the "Update now" button in the "Internet Time Settings" dialog. I figured that should be pretty idiot-proof... but I guess I beat the system. It corrected the seconds but left the machine off by exactly one minute. The BigQuery call failed after that. It succeeded after I manually changed the time.
Our error handling code in the Java library needs to be improved a bit!
It looks like the signed JWT for requesting an OAuth access token is failing. You can see this by enabling the logs that #MichaelManoochehri mentioned above.
There's only a few things that I think could be causing this failure:
Invalid signature (using the wrong key)
Invalid e-mail address for the service account (I think that's been ruled out)
Invalid date/time stamp used for generating the signed blob (an issue date, and an expiration date)
Invalid scope (I think that's been ruled out)
You should check that your date/time is properly set on your server with the proper timezone -- sync'd to NTP. You can use time.gov to see the official US atomic clock time.
EDIT: The answer I gave below is relevant to using Google App Engine Service Accounts - leaving here for reference.
Double check that you have added your service account address to your project's team page as an owner.
I'd recommend using the AppIdentityCredential class to handle service account auth. Here's a small snippet that demonstrates this, and I'll add additional documentation about this on the BigQuery API developer page.
Also, make sure that you are using the latest version of the Google Java API client (as of today, it's version "v2-rev5-1.5.0-beta" here).
import java.io.IOException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.api.client.googleapis.extensions.appengine.auth.oauth2.AppIdentityCredential;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.http.json.JsonHttpRequest;
import com.google.api.client.http.json.JsonHttpRequestInitializer;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson.JacksonFactory;
import com.google.api.services.bigquery.Bigquery;
import com.google.api.services.bigquery.BigqueryRequest;
#SuppressWarnings("serial")
public class Bigquery_service_accounts_demoServlet<TRANSPORT> extends HttpServlet {
// ENTER YOUR PROJECT ID HERE
private static final String PROJECT_ID = "";
private static final HttpTransport TRANSPORT = new NetHttpTransport();
private static final JsonFactory JSON_FACTORY = new JacksonFactory();
private static final String BIGQUERY_SCOPE = "https://www.googleapis.com/auth/bigquery";
AppIdentityCredential credential = new AppIdentityCredential(BIGQUERY_SCOPE);
Bigquery bigquery = Bigquery.builder(TRANSPORT,JSON_FACTORY)
.setHttpRequestInitializer(credential)
.setJsonHttpRequestInitializer(new JsonHttpRequestInitializer() {
public void initialize(JsonHttpRequest request) {
BigqueryRequest bigqueryRequest = (BigqueryRequest) request;
bigqueryRequest.setPrettyPrint(true);
}
}).build();
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("text/plain");
resp.getWriter().println(bigquery.datasets()
.list(PROJECT_ID)
.execute().toString());
}
}
Here is a complete snippet for reference:
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson.JacksonFactory;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.services.bigquery.Bigquery;
import com.google.api.services.bigquery.Bigquery.Datasets;
import com.google.api.services.bigquery.model.DatasetList;
import java.io.File;
import java.io.IOException;
import java.security.GeneralSecurityException;
public class BigQueryJavaServiceAccount {
private static final String SCOPE = "https://www.googleapis.com/auth/bigquery";
private static final HttpTransport TRANSPORT = new NetHttpTransport();
private static final JsonFactory JSON_FACTORY = new JacksonFactory();
public static void main(String[] args) throws IOException, GeneralSecurityException {
GoogleCredential credential = new GoogleCredential.Builder().setTransport(TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId("XXXXXXX#developer.gserviceaccount.com")
.setServiceAccountScopes(SCOPE)
.setServiceAccountPrivateKeyFromP12File(new File("my_file.p12"))
.build();
Bigquery bigquery = Bigquery.builder(TRANSPORT, JSON_FACTORY)
.setApplicationName("Google-BigQuery-App/1.0")
.setHttpRequestInitializer(credential).build();
Datasets.List datasetRequest = bigquery.datasets().list("publicdata");
DatasetList datasetList = datasetRequest.execute();
System.out.format("%s\n", datasetList.toPrettyString());
}

Categories