Skip to content

Initial version of sample code to call payments reseller APIs #10146

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

miriyalavignesh
Copy link

@miriyalavignesh miriyalavignesh commented Aug 7, 2025

Description

Initial version of sample code to call payments reseller APIs
https://developers.google.com/payments/reseller/subscription

Checklist

  • I have followed Sample Format Guide
  • pom.xml parent set to latest shared-configuration
  • Appropriate changes to README are included in PR
  • These samples need a new API enabled in testing projects to pass (let us know which ones)
  • These samples need a new/updated env vars in testing projects set to pass (let us know which ones)
  • Tests pass: mvn clean verify required
  • Lint passes: mvn -P lint checkstyle:check required
  • Static Analysis: mvn -P lint clean compile pmd:cpd-check spotbugs:check advisory only
  • This sample adds a new sample directory, and I updated the CODEOWNERS file with the codeowners for this sample
  • This sample adds a new Product API, and I updated the Blunderbuss issue/PR auto-assigner with the codeowners for this sample
  • Please merge this PR for me once it is approved

@miriyalavignesh miriyalavignesh requested review from yoshi-approver and a team as code owners August 7, 2025 21:12
@product-auto-label product-auto-label bot added the samples Issues that are directly related to samples. label Aug 7, 2025
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary of Changes

Hello @miriyalavignesh, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces the initial set of Java sample code for interacting with the Google Payments Reseller Subscription APIs. The samples demonstrate how to provision subscriptions and generate user sessions, leveraging service account impersonation for authentication.

Highlights

  • New Sample Directory: A new directory payments/reseller/subscription/snippets has been added to house the Java samples.
  • API Interaction: Sample code for GenerateUserSession and ProvisionSubscription demonstrates core functionalities of the Payments Reseller Subscription API.
  • Service Account Impersonation: A dedicated utility class ImpersonateServiceAccount is included to manage authentication via service account impersonation, which is crucial for these APIs.
  • Maven Configuration: A pom.xml file is provided to manage project dependencies and define Maven profiles for easy execution of the sample applications.
  • Constants Definition: A Constants.java file centralizes various IDs and configurations required for the API calls, improving maintainability.
  • Setup Instructions: A README file guides users through the prerequisites and steps to set up their environment and run the samples.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments or fill out our survey to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces an initial set of Java sample code for the Payments Reseller Subscription API. The code demonstrates how to provision a subscription and generate a user session using service account impersonation. My review focuses on improving project configuration, error handling, code clarity, and documentation. Key suggestions include correcting the pom.xml to use the required parent POM, fixing a critical error handling issue in the impersonation logic that could lead to NullPointerExceptions, removing dead code and unused imports, and improving the README instructions.

Comment on lines +19 to +38
public ImpersonateServiceAccount(List<String> oauthScopes, String targetServiceAccount) {
try {
// File name output from: $gcloud auth application-default login
GoogleCredentials sourceCredentials = GoogleCredentials.fromStream(new FileInputStream(
USER_HOME.concat("/.config/gcloud/application_default_credentials.json")));

impersonatedCredentials = ImpersonatedCredentials.newBuilder()
.setSourceCredentials(sourceCredentials)
.setTargetPrincipal(targetServiceAccount)
.setScopes(oauthScopes)
.setDelegates(null) //Optional delegation
.setHttpTransportFactory(OAuth2Utils.HTTP_TRANSPORT_FACTORY)
.build();

} catch (IOException e) {
System.err.println("Failed to get impersonated credentials: " + e.getMessage());
System.err.println(
"Ensure your source credentials have the 'Service Account Token Creator' role on the target SA and that ADC is set up correctly.");
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The constructor swallows the IOException and only prints to System.err. If an exception occurs (e.g., credentials file not found), impersonatedCredentials will be null, leading to a NullPointerException when its methods are called later. The constructor should propagate the IOException to the caller to ensure proper error handling. The callers in main methods already declare throws IOException, so this change will not require further modifications there.

  public ImpersonateServiceAccount(List<String> oauthScopes, String targetServiceAccount) throws IOException {
    // File name output from: $gcloud auth application-default login
    GoogleCredentials sourceCredentials = GoogleCredentials.fromStream(new FileInputStream(
        USER_HOME.concat("/.config/gcloud/application_default_credentials.json")));

    impersonatedCredentials = ImpersonatedCredentials.newBuilder()
        .setSourceCredentials(sourceCredentials)
        .setTargetPrincipal(targetServiceAccount)
        .setScopes(oauthScopes)
        .setDelegates(null) //Optional delegation
        .setHttpTransportFactory(OAuth2Utils.HTTP_TRANSPORT_FACTORY)
        .build();
  }

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The PR checklist indicates that the pom.xml parent should be set to the latest shared-configuration, but this is missing. Using the shared parent POM is important for maintaining consistency, managing dependencies, and inheriting standard plugin configurations across samples in the repository. Please add the parent configuration.

Comment on lines +22 to +23
GoogleCredentials sourceCredentials = GoogleCredentials.fromStream(new FileInputStream(
USER_HOME.concat("/.config/gcloud/application_default_credentials.json")));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The path to the application default credentials file is hardcoded. This is not robust as the location can vary, and it's not platform-independent. It's better to use GoogleCredentials.getApplicationDefault() which automatically finds the credentials from the standard locations.

      GoogleCredentials sourceCredentials = GoogleCredentials.getApplicationDefault();

List.of(ELIGIBILITY_ID))
.setPartnerPlanType(PLAN_TYPE)
))
// .setLineItemPromotionSpecs(ImmutableList.of(new GoogleCloudPaymentsResellerSubscriptionV1SubscriptionPromotionSpec().setPromotion("partners/" + PARTNER_ID + "/promotions/" + PROMOTION)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This commented-out code should be removed to improve readability.

You will need to be added to a specific allow list which will allow you to impersonate
the service account `payment-reseller-test-serv-734@eng-diagram-369411.iam.gserviceaccount.com`

<How to verify this as a developer?>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This line appears to be a placeholder comment for the developer. It should be replaced with actual instructions or removed to finalize the documentation.


ImpersonateServiceAccount impersonateServiceAccount = new ImpersonateServiceAccount(scopes, TARGET_SERVICE_ACCOUNT_EMAIL);
impersonateServiceAccount.refreshCredentials();
System.out.println("Testing code " + impersonateServiceAccount.getImpersonatedCredentials());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This appears to be a debug statement and should be removed from the final sample code.

new GoogleCloudPaymentsResellerSubscriptionV1YoutubePayload()
.setPartnerEligibilityIds(List.of(ELIGIBILITY_ID))
.setPartnerPlanType(PLAN_TYPE)))
// .setLineItemPromotionSpecs(ImmutableList.of(new GoogleCloudPaymentsResellerSubscriptionV1SubscriptionPromotionSpec().setPromotion("partners/" + PARTNER_ID + "/promotions/" + PROMOTION)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This commented-out code should be removed to improve readability.

Comment on lines +80 to +81
// .setPromotionSpecs(ImmutableList.of(new GoogleCloudPaymentsResellerSubscriptionV1SubscriptionPromotionSpec().setPromotion(
// "partners/" + PARTNER_ID + "/promotions/" + PROMOTION_SUB_LEVEL)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This commented-out code should be removed.

Comment on lines +88 to +90
} catch (Exception e) {
System.err.println("Failed to provision subscription: " + e.getMessage());
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Catching a generic Exception is generally discouraged. It's better to catch more specific exceptions that you expect, such as IOException. Also, printing just the message (e.getMessage()) can hide important context for debugging. For sample code, consider printing the full stack trace with e.printStackTrace().

Suggested change
} catch (Exception e) {
System.err.println("Failed to provision subscription: " + e.getMessage());
}
} catch (IOException e) {
System.err.println("Failed to provision subscription:");
e.printStackTrace();
}

Comment on lines +95 to +96
// mvn clean compile
// mvn exec:java -Dexec.mainClass="com.google.cloud.reseller.subscription.samples.ProvisionSubscription"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Execution commands should be documented in the README.md file for better visibility and to keep the source code clean of such comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
samples Issues that are directly related to samples.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant