2

I'm trying to create a dashboard, including showing some analytics report from Google Analytics. After searching, I found the following SO topic: Google Analytics authorization in java

In one of the answers, I found the following Service Account example:

private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
private static final JsonFactory JSON_FACTORY = new JacksonFactory();

public static Result index() {
   GoogleCredential credential = null;
   try {
        credential = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
              .setJsonFactory(JSON_FACTORY)
              .setServiceAccountId("2363XXXXXXX@developer.gserviceaccount.com")
              .setServiceAccountScopes(AnalyticsScopes.ANALYTICS_READONLY)
              .setServiceAccountPrivateKeyFromP12File(new File("/your/path/to/privatekey/privatekey.p12"))                          
              .build();
     } catch (GeneralSecurityException e) {
         e.printStackTrace();
     } catch (IOException e) {
         e.printStackTrace();  
     }

     // Set up and return Google Analytics API client.
     Analytics analytics = new Analytics.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential).setApplicationName(
          "Google-Analytics-Hello-Analytics-API-Sample").build();

     String profileId = "";
     try {
         profileId = getFirstProfileId(analytics);
     } catch (IOException e) {
        e.printStackTrace(); 
     }

     GaData gaData = null;
     try {
        gaData = executeDataQuery(analytics, profileId);
     } catch (IOException e) {
        e.printStackTrace();
     }
     printGaData(gaData);

     return ok(index.render("Your new application is ready."));
}

private static String getFirstProfileId(Analytics analytics) throws IOException {
    String profileId = null;

    // Query accounts collection.
    Accounts accounts = analytics.management().accounts().list().execute();

    if (accounts.getItems().isEmpty()) {
        System.err.println("No accounts found");
    } else {
        String firstAccountId = accounts.getItems().get(0).getId();

        // Query webproperties collection.
        Webproperties webproperties =
                analytics.management().webproperties().list(firstAccountId).execute();

        if (webproperties.getItems().isEmpty()) {
            System.err.println("No Webproperties found");
        } else {
            String firstWebpropertyId = webproperties.getItems().get(0).getId();

            // Query profiles collection.
            Profiles profiles =
                    analytics.management().profiles().list(firstAccountId, firstWebpropertyId).execute();

            if (profiles.getItems().isEmpty()) {
                System.err.println("No profiles found");
            } else {
                profileId = profiles.getItems().get(0).getId();
            }
        }
    }
    return profileId;
}

/**
 * Returns the top 25 organic search keywords and traffic source by visits. The Core Reporting API
 * is used to retrieve this data.
 *
 * @param analytics the analytics service object used to access the API.
 * @param profileId the profile ID from which to retrieve data.
 * @return the response from the API.
 * @throws IOException tf an API error occured.
 */
private static GaData executeDataQuery(Analytics analytics, String profileId) throws IOException {
    return analytics.data().ga().get("ga:" + profileId, // Table Id. ga: + profile id.
            "2012-01-01", // Start date.
            "2012-01-14", // End date.
            "ga:visits") // Metrics.
            .setDimensions("ga:source,ga:keyword")
            .setSort("-ga:visits,ga:source")
            .setFilters("ga:medium==organic")
            .setMaxResults(25)
            .execute();
}

/**
 * Prints the output from the Core Reporting API. The profile name is printed along with each
 * column name and all the data in the rows.
 *
 * @param results data returned from the Core Reporting API.
 */
private static void printGaData(GaData results) {
    System.out.println("printing results for profile: " + results.getProfileInfo().getProfileName());

    if (results.getRows() == null || results.getRows().isEmpty()) {
        System.out.println("No results Found.");
    } else {

        // Print column headers.
        for (GaData.ColumnHeaders header : results.getColumnHeaders()) {
            System.out.printf("%30s", header.getName());
        }
        System.out.println();

        // Print actual data.
        for (List<String> row : results.getRows()) {
            for (String column : row) {
                System.out.printf("%30s", column);
            }
            System.out.println();
        }

        System.out.println();
    }
}

Unfortunately, I can't seem to make it work.. I end up with the following exception:

Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:385)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
at sun.security.validator.Validator.validate(Validator.java:260)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:326)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:231)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:126)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1320)
... 175 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:196)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:268)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:380)
... 181 more

The exception occurs one the following line:

analytics.management().accounts().list().execute();

I'm pretty sure, I used the right configuration and set the right path to the generated private key..

When using the OAuth playground (https://developers.google.com/oauthplayground/), it al seems pretty simple:

  • Authorize the application
  • Exchange the Authorization code for a 'Refresh' and 'Access' token

But the found documentation is all over the place, and not pretty clear (to me anyway)..

Any ideas how to fix this? Any help is much appreciated!

Community
  • 1
  • 1
NickGreen
  • 1,742
  • 16
  • 36

1 Answers1

1

See a previous answer on this type of problem. This looks to be an SSL/truststore issue, not anything with OAuth.

Community
  • 1
  • 1
Mark S.
  • 3,849
  • 4
  • 20
  • 22
  • It was indeed a trustStore issue. I imported the needed certificates with InstallCert (see: http://stackoverflow.com/questions/3685548/java-keytool-easy-way-to-add-server-cert-from-url-port). As host I used, https://www.googleapis.com. After that I had all the needed certificates and the exception was resolved:). Thanks! – NickGreen Mar 22 '13 at 08:39