Re: SAXParseException when Migrating from ReportUtils::downloadReport to ReportDownloader.downloadReport

745 views
Skip to first unread message

Kevin Winter (AdWords API Team)

unread,
Feb 13, 2013, 5:14:10 PM2/13/13
to adwor...@googlegroups.com
Hi Charlie,
  To confirm - you're moving from the old java library using AdWordsUser to the new java library using AdWordsSession, right?  It also looks like you're just using the new library on your classpath (based on the class names in the stack trace).  I could have sworn I added logging for the report download URL endpoint - are you seeing the URL in your logs?  That particular message usually means that the service at the endpoint you're trying to download from is misconfigured.

- Kevin Winter
AdWords API Team

On Friday, February 8, 2013 1:40:40 PM UTC-5, Charlie Saunders wrote:
Hi everyone,

I'm new to this forum and topic, so please forgive me if I have posted this in the wrong location or if this is a very newbie question.

I'm attempting to migrate some Java based tools that use the AdWords API from using AdWordsUser (having the email/password in the source) to OAuth2, getting the credential using setServiceAccountPrivateKeyFromP12File.

Since I no longer have an AdWords user, I was looking to change from this:
ReportDownloadResponse response = ReportUtils.downloadReport(user, reportDefinition, fos);

to this:
ReportDownloadResponse response = new ReportDownloader(adwordsApiSession).downloadReport(reportDefinition);

It seems like my OAuth validation is successful (I can mess up the user name, for example, and I will get a message that validation failed), but my download fails with the following message/stack trace (UrlUpdater is the name of my class):

[Fatal Error] :2:12: Open quote is expected for attribute "{1}" associated with an  element type  "lang".
[08 Feb 2013 13:33:35,331-report_download:ERROR:AWT-EventQueue-0] Couldn't process XML into a Document
HTTP Response Code: 503, ErrorText: <!DOCTYPE html>
org.xml.sax.SAXParseException: Open quote is expected for attribute "{1}" associated with an  element type  "lang".
<html lang=en>
  <meta charset=utf-8>
  <meta name=viewport content="initial-scale=1, minimum-scale=1, width=device-width">
  <title>Error 503 (Server Error)!!1</title>
  <style>
    *{margin:0;padding:0}html,code{font:15px/22px arial,sans-serif}html{background:#fff;color:#222;padding:15px}body{margin:7% auto 0;max-width:390px;min-height:180px;padding:30px 0 15px}* > body{background:url(//www.google.com/images/errors/robot.png) 100% 5px no-repeat;padding-right:205px}p{margin:11px 0 22px;overflow:hidden}ins{color:#777;text-decoration:none}a img{border:0}@media screen and (max-width:772px){body{background:none;margin-top:0;max-width:none;padding-right:0}}
  </style>
  <a href=//www.google.com/><img src=//www.google.com/images/errors/logo_sm.gif alt=Google></a>
  <p><b>503.</b> <ins>That’s an error.</ins>
  <p>The service you requested is not available at this time.<p>Service error -27.  <ins>That’s all we know.</ins>


    at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:246)
    at com.google.api.ads.adwords.lib.utils.v201209.ReportDownloader.handleResponse(ReportDownloader.java:119)
    at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:284)
    at com.google.api.ads.adwords.lib.utils.v201209.ReportDownloader.downloadReport(ReportDownloader.java:93)
    at urlupdater.UrlUpdater.downloadAdHocReport(UrlUpdater.java:487)
    at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:124)
    at urlupdater.UrlUpdater.<init>(UrlUpdater.java:441)
    at com.google.api.ads.adwords.lib.utils.XmlFieldExtractor.getDocument(XmlFieldExtractor.java:124)
    at urlupdater.AccountSelector$2$1.run(AccountSelector.java:86)
    at com.google.api.ads.adwords.lib.utils.XmlFieldExtractor.extract(XmlFieldExtractor.java:80)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
    at com.google.api.ads.adwords.lib.utils.v201209.ReportDownloader.handleResponse(ReportDownloader.java:121)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:702)
    at com.google.api.ads.adwords.lib.utils.v201209.ReportDownloader.downloadReport(ReportDownloader.java:93)

Does anyone know what I might be doing wrong?  I can post more details about my reportDefinition if it seems necessary.

Thank you!

Charlie

Charlie Saunders

unread,
Feb 15, 2013, 10:10:47 AM2/15/13
to adwor...@googlegroups.com
Hi Kevin,

Thanks for your response.

Yes- specifically adwords-api-8.8.0.jar, using the packages in v201209.

In terms of the endpoint- it looks like only report.log is getting appended to when I try to access the API; soap.log and request.log aren't changing.  I don't see something that looks to be the endpoint in any of the log files, but based on the fact that the other log files aren't changing, chances are that I have that set up incorrectly.  I'll have to look into this more.

Using a local network sniffer, I wasn't able to find much of value, other than the server endpoint IP of 74.125.140.84:443.  I'm not sure why, but I couldn't even see the request data get sent.  Could be an issue or could just be how my sniffer is configured.

Thanks again.

Kevin Winter (AdWords API Team)

unread,
Feb 15, 2013, 12:56:03 PM2/15/13
to adwor...@googlegroups.com
Hi,
  Could you do me a favor and show me the code snippet you're using to download the report (as well as the library-specific imports) ?  adwords-api-8.8.0.jar is the old library and does reports differently from the new library.

By the way, I was wrong about adding the logging myself for report download endpoint in the new library - we rely on com.google.api.client.http which logs the request: http://javadoc.google-api-java-client.googlecode.com/hg/1.0.10-alpha/com/google/api/client/http/HttpRequest.html#execute()

If you are using the new library, you should be able to turn up your log level and get more details about the report download.

- Kevin Winter
AdWords API Team

Charlie Saunders

unread,
Feb 15, 2013, 2:40:42 PM2/15/13
to adwor...@googlegroups.com
Hi Kevin,

Thanks again for your help.

Here are the Google API imports I have.

import com.google.api.ads.adwords.axis.factory.AdWordsServices;
import com.google.api.ads.adwords.axis.v201209.cm.AdGroupAd;
import com.google.api.ads.adwords.axis.v201209.cm.AdGroupAdOperation;
import com.google.api.ads.adwords.axis.v201209.cm.AdGroupAdPage;
import com.google.api.ads.adwords.axis.v201209.cm.AdGroupAdReturnValue;
import com.google.api.ads.adwords.axis.v201209.cm.AdGroupAdServiceInterface;
import com.google.api.ads.adwords.axis.v201209.cm.ApiError;
import com.google.api.ads.adwords.axis.v201209.cm.ApiException;
import com.google.api.ads.adwords.axis.v201209.cm.ExemptionRequest;
import com.google.api.ads.adwords.axis.v201209.cm.Operator;
import com.google.api.ads.adwords.axis.v201209.cm.OrderBy;
import com.google.api.ads.adwords.axis.v201209.cm.PolicyViolationError;
import com.google.api.ads.adwords.axis.v201209.cm.SortOrder;
import com.google.api.ads.adwords.axis.v201209.cm.TextAd;
import com.google.api.ads.adwords.lib.client.AdWordsSession;
import com.google.api.ads.adwords.lib.jaxb.v201209.DownloadFormat;
import com.google.api.ads.adwords.lib.jaxb.v201209.Predicate;
import com.google.api.ads.adwords.lib.jaxb.v201209.PredicateOperator;
import com.google.api.ads.adwords.lib.jaxb.v201209.ReportDefinition;
import com.google.api.ads.adwords.lib.jaxb.v201209.ReportDefinitionDateRangeType;
import com.google.api.ads.adwords.lib.jaxb.v201209.ReportDefinitionReportType;
import com.google.api.ads.adwords.lib.jaxb.v201209.Selector;
import com.google.api.ads.adwords.lib.utils.ReportDownloadResponse;
import com.google.api.ads.adwords.lib.utils.v201209.ReportDownloader;
import com.google.api.ads.common.lib.utils.Streams;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
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;

Here is the code, sorry about the formatting!

private static final String[] ADWORDS_FIELDS = {"CampaignStatus", "AdGroupStatus", "Status", "CreativeApprovalStatus", "AdGroupId", "Id", "CampaignName", "AdGroupName", "Headline", "Description1", "Description2", "DisplayUrl", "Url"};
private static final ReportDefinitionReportType REPORT_DEFINITION_REPORT_SERVICE = ReportDefinitionReportType.AD_PERFORMANCE_REPORT;
private static final String REPORT_NAME = "Ad Performance Report";
.......
String fileName = "ad.tsv";
.......

private Predicate generatePredicate(String field, PredicateOperator operator, String[] values) {
Predicate constructedPredicate = new Predicate();
constructedPredicate.setField(field);
constructedPredicate.setOperator(operator);

List<String> predicateValues = constructedPredicate.getValues();
predicateValues.addAll(Arrays.asList(values));

return constructedPredicate;
}

...

private void downloadAdHocReport() {
... try ...
Selector selector = new Selector();
List<String> selectorFields = selector.getFields();
selectorFields.addAll(Arrays.asList(ADWORDS_FIELDS));

Predicate campaignStatusPredicate = generatePredicate("CampaignStatus", PredicateOperator.NOT_IN, new String[]{"DELETED"});
Predicate adGroupStatusPredicate = generatePredicate("AdGroupStatus", PredicateOperator.NOT_IN, new String[]{"DELETED"});
Predicate statusPredicate = generatePredicate("Status", PredicateOperator.NOT_IN, new String[]{"DISABLED"});
Predicate adTypePredicate = generatePredicate("AdType", PredicateOperator.IN, new String[]{"TEXT_AD"});

// add predicates to selector
List<Predicate> predicatesList = selector.getPredicates();
predicatesList.addAll(Arrays.asList(new Predicate[]{campaignStatusPredicate, adGroupStatusPredicate, statusPredicate, adTypePredicate}));

ReportDefinition reportDefinition = new ReportDefinition();
reportDefinition.setReportName(REPORT_NAME + " #" + System.currentTimeMillis());
reportDefinition.setDateRangeType(ReportDefinitionDateRangeType.TODAY);
reportDefinition.setReportType(REPORT_DEFINITION_REPORT_SERVICE);
reportDefinition.setDownloadFormat(DownloadFormat.TSV);
reportDefinition.setIncludeZeroImpressions(true);
reportDefinition.setSelector(selector);

FileOutputStream fos = new FileOutputStream(new File(fileName));
ReportDownloadResponse response = new ReportDownloader(adwordsApiSession).downloadReport(reportDefinition);

if (response.getHttpStatus() == HttpURLConnection.HTTP_OK) {
Streams.copy(response.getInputStream(), fos);
System.out.println("Report successfully downloaded: " + fileName);
} else {
System.out.println("Report was not downloaded. " + response.getHttpStatus() + ": "
+ response.getHttpResponseMessage());
}
... catch ...

Kevin Winter (AdWords API Team)

unread,
Feb 15, 2013, 3:40:29 PM2/15/13
to adwor...@googlegroups.com
OK, so you are using the new java library for the report download.  In that case, the code making the actual request is from the Google Java APIs client library.  Specifically, we're using com.google.api.client.http.HttpRequest.execute().  You should be able to increase the logging level for this package (Logging.ALL should force content logging) and see what is being sent and to where.

However, I copy-pasted all the code above and was able to successfully download the report for my own test account.  Can you run this example successfully?  Does this happen for all your report download attempts?  Is it repeatable?

- Kevin Winter
AdWords API Team

Charlie Saunders

unread,
Feb 15, 2013, 5:22:13 PM2/15/13
to adwor...@googlegroups.com
Hi Kevin,

I couldn't run the example right away because I didn't have a developer token in my ads.properties- I was/am planning on using the service account p12 file key style of authentication (is this called JWT?).  This led me to try changing my environment.  It was "sandbox" so I changed it to "production" and now I'm no longer getting these SAXParseExceptions!

I'm instead getting AuthenticationError.NOT_ADS_USER, but it looks like there are some other threads that discuss this issue, so I'll go through those.

Thank you again for your help!

Charlie
Reply all
Reply to author
Forward
0 new messages