diff --git a/java/src/main/java/DemoEventTicket.java b/java/src/main/java/DemoEventTicket.java index 14c2032..c53d7c6 100644 --- a/java/src/main/java/DemoEventTicket.java +++ b/java/src/main/java/DemoEventTicket.java @@ -14,6 +14,8 @@ * limitations under the License. */ +// [START setup] +// [START imports] import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.google.api.client.googleapis.batch.BatchRequest; @@ -21,897 +23,927 @@ import com.google.api.client.googleapis.batch.json.JsonBatchCallback; import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; import com.google.api.client.googleapis.json.GoogleJsonError; import com.google.api.client.googleapis.json.GoogleJsonResponseException; -import com.google.api.client.http.HttpHeaders; -import com.google.api.client.http.HttpTransport; +import com.google.api.client.http.*; import com.google.api.client.json.gson.GsonFactory; import com.google.api.services.walletobjects.Walletobjects; import com.google.api.services.walletobjects.model.*; import com.google.auth.http.HttpCredentialsAdapter; import com.google.auth.oauth2.GoogleCredentials; import com.google.auth.oauth2.ServiceAccountCredentials; - -import java.io.FileInputStream; -import java.io.IOException; +import java.io.*; import java.security.interfaces.RSAPrivateKey; import java.util.*; +// [END imports] -/** - * Demo class for creating and managing Event tickets in Google Wallet. - */ +/** Demo class for creating and managing Event tickets in Google Wallet. */ public class DemoEventTicket { - /** - * Path to service account key file from Google Cloud Console. Environment variable: - * GOOGLE_APPLICATION_CREDENTIALS. - */ - public static String keyFilePath; + /** + * Path to service account key file from Google Cloud Console. Environment variable: + * GOOGLE_APPLICATION_CREDENTIALS. + */ + public static String keyFilePath; - /** - * Service account credentials for Google Wallet APIs. - */ - public static GoogleCredentials credentials; + /** Service account credentials for Google Wallet APIs. */ + public static GoogleCredentials credentials; - /** - * Google Wallet service client. - */ - public static Walletobjects service; + /** Google Wallet service client. */ + public static Walletobjects service; - public DemoEventTicket() throws Exception { - keyFilePath = - System.getenv().getOrDefault("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/key.json"); + public DemoEventTicket() throws Exception { + keyFilePath = + System.getenv().getOrDefault("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/key.json"); - auth(); - } + Auth(); + } + // [END setup] - /** - * Create authenticated HTTP client using a service account file. - */ - public void auth() throws Exception { - String scope = "https://www.googleapis.com/auth/wallet_object.issuer"; + // [START auth] + /** + * Create authenticated HTTP client using a service account file. + * + * @throws Exception + */ + public void Auth() throws Exception { + String scope = "https://www.googleapis.com/auth/wallet_object.issuer"; - credentials = - GoogleCredentials.fromStream(new FileInputStream(keyFilePath)) - .createScoped(List.of(scope)); - credentials.refresh(); + credentials = + GoogleCredentials.fromStream(new FileInputStream(keyFilePath)) + .createScoped(Arrays.asList(scope)); + credentials.refresh(); - HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport(); + HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport(); - // Initialize Google Wallet API service - service = - new Walletobjects.Builder( - httpTransport, - GsonFactory.getDefaultInstance(), - new HttpCredentialsAdapter(credentials)) - .setApplicationName("APPLICATION_NAME") - .build(); - } + // Initialize Google Wallet API service + service = + new Walletobjects.Builder( + httpTransport, + GsonFactory.getDefaultInstance(), + new HttpCredentialsAdapter(credentials)) + .setApplicationName("APPLICATION_NAME") + .build(); + } + // [END auth] - /** - * Create a class. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @return The pass class ID: "{issuerId}.{classSuffix}" - */ - public String createClass(String issuerId, String classSuffix) throws IOException { - // Check if the class exists - try { - service.eventticketclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); - - System.out.printf("Class %s.%s already exists!%n", issuerId, classSuffix); - return String.format("%s.%s", issuerId, classSuffix); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() != 404) { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, classSuffix); - } - } - - // See link below for more information on required properties - // https://developers.google.com/wallet/tickets/events/rest/v1/eventticketclass - EventTicketClass newClass = - new EventTicketClass() - .setEventId(String.format("%s.%s", issuerId, classSuffix)) - .setEventName( - new LocalizedString() - .setDefaultValue( - new TranslatedString().setLanguage("en-US").setValue("Event name"))) - .setId(String.format("%s.%s", issuerId, classSuffix)) - .setIssuerName("Issuer name") - .setReviewStatus("UNDER_REVIEW"); - - EventTicketClass response = service.eventticketclass().insert(newClass).execute(); - - System.out.println("Class insert response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Update a class. - * - *

Warning: This replaces all existing class attributes! - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @return The pass class ID: "{issuerId}.{classSuffix}" - */ - public String updateClass(String issuerId, String classSuffix) throws IOException { - EventTicketClass updatedClass; - - // Check if the class exists - try { - updatedClass = - service.eventticketclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Class does not exist - System.out.printf("Class %s.%s not found!%n", issuerId, classSuffix); - return String.format("%s.%s", issuerId, classSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, classSuffix); - } - } - - // Class exists - // Update the class by adding a homepage - updatedClass.setHomepageUri( - new Uri() - .setUri("https://developers.google.com/wallet") - .setDescription("Homepage description")); - - // Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates - updatedClass.setReviewStatus("UNDER_REVIEW"); - - EventTicketClass response = - service - .eventticketclass() - .update(String.format("%s.%s", issuerId, classSuffix), updatedClass) - .execute(); - - System.out.println("Class update response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Patch a class. - * - *

The PATCH method supports patch semantics. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @return The pass class ID: "{issuerId}.{classSuffix}" - */ - public String patchClass(String issuerId, String classSuffix) throws IOException { - // Check if the class exists - try { - service.eventticketclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Class does not exist - System.out.printf("Class %s.%s not found!%n", issuerId, classSuffix); - return String.format("%s.%s", issuerId, classSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, classSuffix); - } - } - - // Class exists - // Patch the class by adding a homepage - EventTicketClass patchBody = - new EventTicketClass() - .setHomepageUri( - new Uri() - .setUri("https://developers.google.com/wallet") - .setDescription("Homepage description")) - - // Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates - .setReviewStatus("UNDER_REVIEW"); - - EventTicketClass response = - service - .eventticketclass() - .patch(String.format("%s.%s", issuerId, classSuffix), patchBody) - .execute(); - - System.out.println("Class patch response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Add a message to a pass class. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @param header The message header. - * @param body The message body. - * @return The pass class ID: "{issuerId}.{classSuffix}" - */ - public String addClassMessage(String issuerId, String classSuffix, String header, String body) - throws IOException { - // Check if the class exists - try { - service.eventticketclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Class does not exist - System.out.printf("Class %s.%s not found!%n", issuerId, classSuffix); - return String.format("%s.%s", issuerId, classSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, classSuffix); - } - } - - AddMessageRequest message = - new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body)); - - EventTicketClassAddMessageResponse response = - service - .eventticketclass() - .addmessage(String.format("%s.%s", issuerId, classSuffix), message) - .execute(); - - System.out.println("Class addMessage response"); - System.out.println(response.toPrettyString()); + // [START createClass] + /** + * Create a class. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @return The pass class ID: "{issuerId}.{classSuffix}" + * @throws IOException + */ + public String CreateClass(String issuerId, String classSuffix) throws IOException { + // Check if the class exists + try { + service.eventticketclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); + System.out.println(String.format("Class %s.%s already exists!", issuerId, classSuffix)); + return String.format("%s.%s", issuerId, classSuffix); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() != 404) { + // Something else went wrong... + ex.printStackTrace(); return String.format("%s.%s", issuerId, classSuffix); + } } - /** - * Create an object. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String createObject(String issuerId, String classSuffix, String objectSuffix) - throws IOException { - // Check if the object exists - try { - service.eventticketobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + // See link below for more information on required properties + // https://developers.google.com/wallet/tickets/events/rest/v1/eventticketclass + EventTicketClass newClass = + new EventTicketClass() + .setEventId(String.format("%s.%s", issuerId, classSuffix)) + .setEventName( + new LocalizedString() + .setDefaultValue( + new TranslatedString().setLanguage("en-US").setValue("Event name"))) + .setId(String.format("%s.%s", issuerId, classSuffix)) + .setIssuerName("Issuer name") + .setReviewStatus("UNDER_REVIEW"); - System.out.printf("Object %s.%s already exists!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() != 404) { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } + EventTicketClass response = service.eventticketclass().insert(newClass).execute(); - // See link below for more information on required properties - // https://developers.google.com/wallet/tickets/events/rest/v1/eventticketobject - EventTicketObject newObject = - new EventTicketObject() - .setId(String.format("%s.%s", issuerId, objectSuffix)) - .setClassId(String.format("%s.%s", issuerId, classSuffix)) - .setState("ACTIVE") - .setHeroImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Hero image description")))) - .setTextModulesData( - List.of( - new TextModuleData() - .setHeader("Text module header") - .setBody("Text module body") - .setId("TEXT_MODULE_ID"))) - .setLinksModuleData( - new LinksModuleData() - .setUris( - Arrays.asList( - new Uri() - .setUri("http://maps.google.com/") - .setDescription("Link module URI description") - .setId("LINK_MODULE_URI_ID"), - new Uri() - .setUri("tel:6505555555") - .setDescription("Link module tel description") - .setId("LINK_MODULE_TEL_ID")))) - .setImageModulesData( - List.of( - new ImageModuleData() - .setMainImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Image module description")))) - .setId("IMAGE_MODULE_ID"))) - .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) - .setLocations( - List.of( - new LatLongPoint() - .setLatitude(37.424015499999996) - .setLongitude(-122.09259560000001))) - .setSeatInfo( - new EventSeat() - .setSeat( - new LocalizedString() - .setDefaultValue( - new TranslatedString().setLanguage("en-US").setValue("42"))) - .setRow( - new LocalizedString() - .setDefaultValue( - new TranslatedString().setLanguage("en-US").setValue("G3"))) - .setSection( - new LocalizedString() - .setDefaultValue( - new TranslatedString().setLanguage("en-US").setValue("5"))) - .setGate( - new LocalizedString() - .setDefaultValue( - new TranslatedString().setLanguage("en-US").setValue("A")))) - .setTicketHolderName("Ticket holder name") - .setTicketNumber("Ticket number"); + System.out.println("Class insert response"); + System.out.println(response.toPrettyString()); - EventTicketObject response = service.eventticketobject().insert(newObject).execute(); + return response.getId(); + } + // [END createClass] - System.out.println("Object insert response"); - System.out.println(response.toPrettyString()); + // [START updateClass] + /** + * Update a class. + * + *

Warning: This replaces all existing class attributes! + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @return The pass class ID: "{issuerId}.{classSuffix}" + * @throws IOException + */ + public String UpdateClass(String issuerId, String classSuffix) throws IOException { + EventTicketClass updatedClass; - return response.getId(); + // Check if the class exists + try { + updatedClass = + service.eventticketclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Class does not exist + System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix)); + return String.format("%s.%s", issuerId, classSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, classSuffix); + } } - /** - * Update an object. - * - *

Warning: This replaces all existing object attributes! - * - * @param issuerId The issuer ID being used for this request. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String updateObject(String issuerId, String objectSuffix) throws IOException { - EventTicketObject updatedObject; + // Class exists + // Update the class by adding a homepage + updatedClass.setHomepageUri( + new Uri() + .setUri("https://developers.google.com/wallet") + .setDescription("Homepage description")); - // Check if the object exists - try { - updatedObject = - service.eventticketobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Object does not exist - System.out.printf("Object %s.%s not found!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } + // Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates + updatedClass.setReviewStatus("UNDER_REVIEW"); - // Object exists - // Update the object by adding a link - Uri newLink = + EventTicketClass response = + service + .eventticketclass() + .update(String.format("%s.%s", issuerId, classSuffix), updatedClass) + .execute(); + + System.out.println("Class update response"); + System.out.println(response.toPrettyString()); + + return response.getId(); + } + // [END updateClass] + + // [START patchClass] + /** + * Patch a class. + * + *

The PATCH method supports patch semantics. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @return The pass class ID: "{issuerId}.{classSuffix}" + * @throws IOException + */ + public String PatchClass(String issuerId, String classSuffix) throws IOException { + // Check if the class exists + try { + service.eventticketclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Class does not exist + System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix)); + return String.format("%s.%s", issuerId, classSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, classSuffix); + } + } + + // Class exists + // Patch the class by adding a homepage + EventTicketClass patchBody = + new EventTicketClass() + .setHomepageUri( new Uri() - .setUri("https://developers.google.com/wallet") - .setDescription("New link description"); + .setUri("https://developers.google.com/wallet") + .setDescription("Homepage description")) - if (updatedObject.getLinksModuleData() == null) { - // LinksModuleData was not set on the original object - updatedObject.setLinksModuleData(new LinksModuleData().setUris(List.of(newLink))); - } else { - updatedObject.getLinksModuleData().getUris().add(newLink); - } + // Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates + .setReviewStatus("UNDER_REVIEW"); - EventTicketObject response = - service - .eventticketobject() - .update(String.format("%s.%s", issuerId, objectSuffix), updatedObject) - .execute(); + EventTicketClass response = + service + .eventticketclass() + .patch(String.format("%s.%s", issuerId, classSuffix), patchBody) + .execute(); - System.out.println("Object update response"); - System.out.println(response.toPrettyString()); + System.out.println("Class patch response"); + System.out.println(response.toPrettyString()); - return response.getId(); + return response.getId(); + } + // [END patchClass] + + // [START addMessageClass] + /** + * Add a message to a pass class. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @param header The message header. + * @param body The message body. + * @return The pass class ID: "{issuerId}.{classSuffix}" + * @throws IOException + */ + public String AddClassMessage(String issuerId, String classSuffix, String header, String body) + throws IOException { + // Check if the class exists + try { + service.eventticketclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Class does not exist + System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix)); + return String.format("%s.%s", issuerId, classSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, classSuffix); + } } - /** - * Patch an object. - * - * @param issuerId The issuer ID being used for this request. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String patchObject(String issuerId, String objectSuffix) throws IOException { - EventTicketObject existingObject; + AddMessageRequest message = + new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body)); - // Check if the object exists - try { - existingObject = - service.eventticketobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Object does not exist - System.out.printf("Object %s.%s not found!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } + EventTicketClassAddMessageResponse response = + service + .eventticketclass() + .addmessage(String.format("%s.%s", issuerId, classSuffix), message) + .execute(); - // Object exists - // Patch the object by adding a link - Uri newLink = - new Uri() - .setUri("https://developers.google.com/wallet") - .setDescription("New link description"); + System.out.println("Class addMessage response"); + System.out.println(response.toPrettyString()); - EventTicketObject patchBody = new EventTicketObject(); + return String.format("%s.%s", issuerId, classSuffix); + } + // [END addMessageClass] - if (existingObject.getLinksModuleData() == null) { - // LinksModuleData was not set on the original object - patchBody.setLinksModuleData(new LinksModuleData().setUris(new ArrayList())); - } else { - patchBody.setLinksModuleData(existingObject.getLinksModuleData()); - } - patchBody.getLinksModuleData().getUris().add(newLink); - - EventTicketObject response = - service - .eventticketobject() - .patch(String.format("%s.%s", issuerId, objectSuffix), patchBody) - .execute(); - - System.out.println("Object patch response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Expire an object. - * - *

Sets the object's state to Expired. If the valid time interval is already set, the pass will - * expire automatically up to 24 hours after. - * - * @param issuerId The issuer ID being used for this request. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String expireObject(String issuerId, String objectSuffix) throws IOException { - // Check if the object exists - try { - service.eventticketobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Object does not exist - System.out.printf("Object %s.%s not found!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } - - // Patch the object, setting the pass as expired - EventTicketObject patchBody = new EventTicketObject().setState("EXPIRED"); - - EventTicketObject response = - service - .eventticketobject() - .patch(String.format("%s.%s", issuerId, objectSuffix), patchBody) - .execute(); - - System.out.println("Object expiration response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Add a message to a pass object. - * - * @param issuerId The issuer ID being used for this request. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @param header The message header. - * @param body The message body. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String addObjectMessage(String issuerId, String objectSuffix, String header, String body) - throws IOException { - // Check if the object exists - try { - service.eventticketobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Object does not exist - System.out.printf("Object %s.%s not found!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } - - AddMessageRequest message = - new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body)); - - EventTicketObjectAddMessageResponse response = - service - .eventticketobject() - .addmessage(String.format("%s.%s", issuerId, objectSuffix), message) - .execute(); - - System.out.println("Object addMessage response"); - System.out.println(response.toPrettyString()); + // [START createObject] + /** + * Create an object. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String CreateObject(String issuerId, String classSuffix, String objectSuffix) + throws IOException { + // Check if the object exists + try { + service.eventticketobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + System.out.println(String.format("Object %s.%s already exists!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() != 404) { + // Something else went wrong... + ex.printStackTrace(); return String.format("%s.%s", issuerId, objectSuffix); + } } - /** - * Generate a signed JWT that creates a new pass class and object. - * - *

When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the - * pass class and object defined in the JWT are created. This allows you to create multiple pass - * classes and objects in one API call when the user saves the pass to their wallet. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @param objectSuffix Developer-defined unique ID for the pass object. - * @return An "Add to Google Wallet" link. - */ - public String createJWTNewObjects(String issuerId, String classSuffix, String objectSuffix) { - // See link below for more information on required properties - // https://developers.google.com/wallet/tickets/events/rest/v1/eventticketclass - EventTicketClass newClass = - new EventTicketClass() - .setId(String.format("%s.%s", issuerId, classSuffix)) - .setIssuerName("Issuer name") - .setReviewStatus("UNDER_REVIEW") - .setEventName( - new LocalizedString() + // See link below for more information on required properties + // https://developers.google.com/wallet/tickets/events/rest/v1/eventticketobject + EventTicketObject newObject = + new EventTicketObject() + .setId(String.format("%s.%s", issuerId, objectSuffix)) + .setClassId(String.format("%s.%s", issuerId, classSuffix)) + .setState("ACTIVE") + .setHeroImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Hero image description")))) + .setTextModulesData( + Arrays.asList( + new TextModuleData() + .setHeader("Text module header") + .setBody("Text module body") + .setId("TEXT_MODULE_ID"))) + .setLinksModuleData( + new LinksModuleData() + .setUris( + Arrays.asList( + new Uri() + .setUri("http://maps.google.com/") + .setDescription("Link module URI description") + .setId("LINK_MODULE_URI_ID"), + new Uri() + .setUri("tel:6505555555") + .setDescription("Link module tel description") + .setId("LINK_MODULE_TEL_ID")))) + .setImageModulesData( + Arrays.asList( + new ImageModuleData() + .setMainImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) + .setContentDescription( + new LocalizedString() .setDefaultValue( - new TranslatedString().setLanguage("en-US").setValue("Event name"))); + new TranslatedString() + .setLanguage("en-US") + .setValue("Image module description")))) + .setId("IMAGE_MODULE_ID"))) + .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) + .setLocations( + Arrays.asList( + new LatLongPoint() + .setLatitude(37.424015499999996) + .setLongitude(-122.09259560000001))) + .setSeatInfo( + new EventSeat() + .setSeat( + new LocalizedString() + .setDefaultValue( + new TranslatedString().setLanguage("en-US").setValue("42"))) + .setRow( + new LocalizedString() + .setDefaultValue( + new TranslatedString().setLanguage("en-US").setValue("G3"))) + .setSection( + new LocalizedString() + .setDefaultValue( + new TranslatedString().setLanguage("en-US").setValue("5"))) + .setGate( + new LocalizedString() + .setDefaultValue( + new TranslatedString().setLanguage("en-US").setValue("A")))) + .setTicketHolderName("Ticket holder name") + .setTicketNumber("Ticket number"); - // See link below for more information on required properties - // https://developers.google.com/wallet/tickets/events/rest/v1/eventticketobject - EventTicketObject newObject = - new EventTicketObject() - .setId(String.format("%s.%s", issuerId, objectSuffix)) - .setClassId(String.format("%s.%s", issuerId, classSuffix)) - .setState("ACTIVE") - .setHeroImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Hero image description")))) - .setTextModulesData( - List.of( - new TextModuleData() - .setHeader("Text module header") - .setBody("Text module body") - .setId("TEXT_MODULE_ID"))) - .setLinksModuleData( - new LinksModuleData() - .setUris( - Arrays.asList( - new Uri() - .setUri("http://maps.google.com/") - .setDescription("Link module URI description") - .setId("LINK_MODULE_URI_ID"), - new Uri() - .setUri("tel:6505555555") - .setDescription("Link module tel description") - .setId("LINK_MODULE_TEL_ID")))) - .setImageModulesData( - List.of( - new ImageModuleData() - .setMainImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Image module description")))) - .setId("IMAGE_MODULE_ID"))) - .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) - .setLocations( - List.of( - new LatLongPoint() - .setLatitude(37.424015499999996) - .setLongitude(-122.09259560000001))) - .setSeatInfo( - new EventSeat() - .setSeat( - new LocalizedString() - .setDefaultValue( - new TranslatedString().setLanguage("en-US").setValue("42"))) - .setRow( - new LocalizedString() - .setDefaultValue( - new TranslatedString().setLanguage("en-US").setValue("G3"))) - .setSection( - new LocalizedString() - .setDefaultValue( - new TranslatedString().setLanguage("en-US").setValue("5"))) - .setGate( - new LocalizedString() - .setDefaultValue( - new TranslatedString().setLanguage("en-US").setValue("A")))) - .setTicketHolderName("Ticket holder name") - .setTicketNumber("Ticket number"); + EventTicketObject response = service.eventticketobject().insert(newObject).execute(); - // Create the JWT as a HashMap object - HashMap claims = new HashMap(); - claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail()); - claims.put("aud", "google"); - claims.put("origins", List.of("www.example.com")); - claims.put("typ", "savetowallet"); + System.out.println("Object insert response"); + System.out.println(response.toPrettyString()); - // Create the Google Wallet payload and add to the JWT - HashMap payload = new HashMap(); - payload.put("eventTicketClasses", List.of(newClass)); - payload.put("eventTicketObjects", List.of(newObject)); - claims.put("payload", payload); + return response.getId(); + } + // [END createObject] - // The service account credentials are used to sign the JWT - Algorithm algorithm = - Algorithm.RSA256( - null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); - String token = JWT.create().withPayload(claims).sign(algorithm); + // [START updateObject] + /** + * Update an object. + * + *

Warning: This replaces all existing object attributes! + * + * @param issuerId The issuer ID being used for this request. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String UpdateObject(String issuerId, String objectSuffix) throws IOException { + EventTicketObject updatedObject; - System.out.println("Add to Google Wallet link"); - System.out.printf("https://pay.google.com/gp/v/save/%s%n", token); - - return String.format("https://pay.google.com/gp/v/save/%s", token); + // Check if the object exists + try { + updatedObject = + service.eventticketobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Object does not exist + System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, objectSuffix); + } } - /** - * Generate a signed JWT that references an existing pass object. - * - *

When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the - * pass objects defined in the JWT are added to the user's Google Wallet app. This allows the user - * to save multiple pass objects in one API call. - * - *

The objects to add must follow the below format: - * - *

{ 'id': 'ISSUER_ID.OBJECT_SUFFIX', 'classId': 'ISSUER_ID.CLASS_SUFFIX' } - * - * @param issuerId The issuer ID being used for this request. - * @return An "Add to Google Wallet" link. - */ - public String createJWTExistingObjects(String issuerId) { - // Multiple pass types can be added at the same time - // At least one type must be specified in the JWT claims - // Note: Make sure to replace the placeholder class and object suffixes - HashMap objectsToAdd = new HashMap(); + // Object exists + // Update the object by adding a link + Uri newLink = + new Uri() + .setUri("https://developers.google.com/wallet") + .setDescription("New link description"); - // Event tickets - objectsToAdd.put( - "eventTicketObjects", - List.of( - new EventTicketObject() - .setId(String.format("%s.%s", issuerId, "EVENT_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "EVENT_CLASS_SUFFIX")))); - - // Boarding passes - objectsToAdd.put( - "flightObjects", - List.of( - new FlightObject() - .setId(String.format("%s.%s", issuerId, "FLIGHT_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "FLIGHT_CLASS_SUFFIX")))); - - // Generic passes - objectsToAdd.put( - "genericObjects", - List.of( - new GenericObject() - .setId(String.format("%s.%s", issuerId, "GENERIC_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "GENERIC_CLASS_SUFFIX")))); - - // Gift cards - objectsToAdd.put( - "giftCardObjects", - List.of( - new GiftCardObject() - .setId(String.format("%s.%s", issuerId, "GIFT_CARD_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "GIFT_CARD_CLASS_SUFFIX")))); - - // Loyalty cards - objectsToAdd.put( - "loyaltyObjects", - List.of( - new LoyaltyObject() - .setId(String.format("%s.%s", issuerId, "LOYALTY_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "LOYALTY_CLASS_SUFFIX")))); - - // Offers - objectsToAdd.put( - "offerObjects", - List.of( - new OfferObject() - .setId(String.format("%s.%s", issuerId, "OFFER_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "OFFER_CLASS_SUFFIX")))); - - // Transit passes - objectsToAdd.put( - "transitObjects", - List.of( - new TransitObject() - .setId(String.format("%s.%s", issuerId, "TRANSIT_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "TRANSIT_CLASS_SUFFIX")))); - - // Create the JWT as a HashMap object - HashMap claims = new HashMap(); - claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail()); - claims.put("aud", "google"); - claims.put("origins", List.of("www.example.com")); - claims.put("typ", "savetowallet"); - claims.put("payload", objectsToAdd); - - // The service account credentials are used to sign the JWT - Algorithm algorithm = - Algorithm.RSA256( - null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); - String token = JWT.create().withPayload(claims).sign(algorithm); - - System.out.println("Add to Google Wallet link"); - System.out.printf("https://pay.google.com/gp/v/save/%s%n", token); - - return String.format("https://pay.google.com/gp/v/save/%s", token); + if (updatedObject.getLinksModuleData() == null) { + // LinksModuleData was not set on the original object + updatedObject.setLinksModuleData(new LinksModuleData().setUris(Arrays.asList(newLink))); + } else { + updatedObject.getLinksModuleData().getUris().add(newLink); } - /** - * Batch create Google Wallet objects from an existing class. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - */ - public void batchCreateObjects(String issuerId, String classSuffix) throws IOException { - // Create the batch request client - BatchRequest batch = service.batch(new HttpCredentialsAdapter(credentials)); + EventTicketObject response = + service + .eventticketobject() + .update(String.format("%s.%s", issuerId, objectSuffix), updatedObject) + .execute(); - // The callback will be invoked for each request in the batch - JsonBatchCallback callback = - new JsonBatchCallback() { - // Invoked if the request was successful - public void onSuccess(EventTicketObject response, HttpHeaders responseHeaders) { - System.out.println("Batch insert response"); - System.out.println(response.toString()); - } + System.out.println("Object update response"); + System.out.println(response.toPrettyString()); - // Invoked if the request failed - public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) { - System.out.println("Error Message: " + e.getMessage()); - } - }; + return response.getId(); + } + // [END updateObject] - // Example: Generate three new pass objects - for (int i = 0; i < 3; i++) { - // Generate a random object suffix - String objectSuffix = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_"); + // [START patchObject] + /** + * Patch an object. + * + * @param issuerId The issuer ID being used for this request. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String PatchObject(String issuerId, String objectSuffix) throws IOException { + EventTicketObject existingObject; - // See link below for more information on required properties - // https://developers.google.com/wallet/tickets/events/rest/v1/eventticketobject - EventTicketObject batchObject = - new EventTicketObject() - .setId(String.format("%s.%s", issuerId, objectSuffix)) - .setClassId(String.format("%s.%s", issuerId, classSuffix)) - .setState("ACTIVE") - .setHeroImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Hero image description")))) - .setTextModulesData( - List.of( - new TextModuleData() - .setHeader("Text module header") - .setBody("Text module body") - .setId("TEXT_MODULE_ID"))) - .setLinksModuleData( - new LinksModuleData() - .setUris( - Arrays.asList( - new Uri() - .setUri("http://maps.google.com/") - .setDescription("Link module URI description") - .setId("LINK_MODULE_URI_ID"), - new Uri() - .setUri("tel:6505555555") - .setDescription("Link module tel description") - .setId("LINK_MODULE_TEL_ID")))) - .setImageModulesData( - List.of( - new ImageModuleData() - .setMainImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Image module description")))) - .setId("IMAGE_MODULE_ID"))) - .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) - .setLocations( - List.of( - new LatLongPoint() - .setLatitude(37.424015499999996) - .setLongitude(-122.09259560000001))) - .setSeatInfo( - new EventSeat() - .setSeat( - new LocalizedString() - .setDefaultValue( - new TranslatedString().setLanguage("en-US").setValue("42"))) - .setRow( - new LocalizedString() - .setDefaultValue( - new TranslatedString().setLanguage("en-US").setValue("G3"))) - .setSection( - new LocalizedString() - .setDefaultValue( - new TranslatedString().setLanguage("en-US").setValue("5"))) - .setGate( - new LocalizedString() - .setDefaultValue( - new TranslatedString().setLanguage("en-US").setValue("A")))) - .setTicketHolderName("Ticket holder name") - .setTicketNumber("Ticket number"); - - service.eventticketobject().insert(batchObject).queue(batch, callback); - } - - // Invoke the batch API calls - batch.execute(); + // Check if the object exists + try { + existingObject = + service.eventticketobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Object does not exist + System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, objectSuffix); + } } + // Object exists + // Patch the object by adding a link + Uri newLink = + new Uri() + .setUri("https://developers.google.com/wallet") + .setDescription("New link description"); + + EventTicketObject patchBody = new EventTicketObject(); + + if (existingObject.getLinksModuleData() == null) { + // LinksModuleData was not set on the original object + patchBody.setLinksModuleData(new LinksModuleData().setUris(new ArrayList())); + } else { + patchBody.setLinksModuleData(existingObject.getLinksModuleData()); + } + patchBody.getLinksModuleData().getUris().add(newLink); + + EventTicketObject response = + service + .eventticketobject() + .patch(String.format("%s.%s", issuerId, objectSuffix), patchBody) + .execute(); + + System.out.println("Object patch response"); + System.out.println(response.toPrettyString()); + + return response.getId(); + } + // [END patchObject] + + // [START expireObject] + /** + * Expire an object. + * + *

Sets the object's state to Expired. If the valid time interval is already set, the pass will + * expire automatically up to 24 hours after. + * + * @param issuerId The issuer ID being used for this request. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String ExpireObject(String issuerId, String objectSuffix) throws IOException { + // Check if the object exists + try { + service.eventticketobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Object does not exist + System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, objectSuffix); + } + } + + // Patch the object, setting the pass as expired + EventTicketObject patchBody = new EventTicketObject().setState("EXPIRED"); + + EventTicketObject response = + service + .eventticketobject() + .patch(String.format("%s.%s", issuerId, objectSuffix), patchBody) + .execute(); + + System.out.println("Object expiration response"); + System.out.println(response.toPrettyString()); + + return response.getId(); + } + // [END expireObject] + + // [START addMessageObject] + /** + * Add a message to a pass object. + * + * @param issuerId The issuer ID being used for this request. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @param header The message header. + * @param body The message body. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String AddObjectMessage(String issuerId, String objectSuffix, String header, String body) + throws IOException { + // Check if the object exists + try { + service.eventticketobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Object does not exist + System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, objectSuffix); + } + } + + AddMessageRequest message = + new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body)); + + EventTicketObjectAddMessageResponse response = + service + .eventticketobject() + .addmessage(String.format("%s.%s", issuerId, objectSuffix), message) + .execute(); + + System.out.println("Object addMessage response"); + System.out.println(response.toPrettyString()); + + return String.format("%s.%s", issuerId, objectSuffix); + } + // [END addMessageObject] + + // [START jwtNew] + /** + * Generate a signed JWT that creates a new pass class and object. + * + *

When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the + * pass class and object defined in the JWT are created. This allows you to create multiple pass + * classes and objects in one API call when the user saves the pass to their wallet. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @param objectSuffix Developer-defined unique ID for the pass object. + * @return An "Add to Google Wallet" link. + */ + public String CreateJWTNewObjects(String issuerId, String classSuffix, String objectSuffix) { + // See link below for more information on required properties + // https://developers.google.com/wallet/tickets/events/rest/v1/eventticketclass + EventTicketClass newClass = + new EventTicketClass() + .setId(String.format("%s.%s", issuerId, classSuffix)) + .setIssuerName("Issuer name") + .setReviewStatus("UNDER_REVIEW") + .setEventName( + new LocalizedString() + .setDefaultValue( + new TranslatedString().setLanguage("en-US").setValue("Event name"))); + + // See link below for more information on required properties + // https://developers.google.com/wallet/tickets/events/rest/v1/eventticketobject + EventTicketObject newObject = + new EventTicketObject() + .setId(String.format("%s.%s", issuerId, objectSuffix)) + .setClassId(String.format("%s.%s", issuerId, classSuffix)) + .setState("ACTIVE") + .setHeroImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Hero image description")))) + .setTextModulesData( + Arrays.asList( + new TextModuleData() + .setHeader("Text module header") + .setBody("Text module body") + .setId("TEXT_MODULE_ID"))) + .setLinksModuleData( + new LinksModuleData() + .setUris( + Arrays.asList( + new Uri() + .setUri("http://maps.google.com/") + .setDescription("Link module URI description") + .setId("LINK_MODULE_URI_ID"), + new Uri() + .setUri("tel:6505555555") + .setDescription("Link module tel description") + .setId("LINK_MODULE_TEL_ID")))) + .setImageModulesData( + Arrays.asList( + new ImageModuleData() + .setMainImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Image module description")))) + .setId("IMAGE_MODULE_ID"))) + .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) + .setLocations( + Arrays.asList( + new LatLongPoint() + .setLatitude(37.424015499999996) + .setLongitude(-122.09259560000001))) + .setSeatInfo( + new EventSeat() + .setSeat( + new LocalizedString() + .setDefaultValue( + new TranslatedString().setLanguage("en-US").setValue("42"))) + .setRow( + new LocalizedString() + .setDefaultValue( + new TranslatedString().setLanguage("en-US").setValue("G3"))) + .setSection( + new LocalizedString() + .setDefaultValue( + new TranslatedString().setLanguage("en-US").setValue("5"))) + .setGate( + new LocalizedString() + .setDefaultValue( + new TranslatedString().setLanguage("en-US").setValue("A")))) + .setTicketHolderName("Ticket holder name") + .setTicketNumber("Ticket number"); + + // Create the JWT as a HashMap object + HashMap claims = new HashMap(); + claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail()); + claims.put("aud", "google"); + claims.put("origins", Arrays.asList("www.example.com")); + claims.put("typ", "savetowallet"); + + // Create the Google Wallet payload and add to the JWT + HashMap payload = new HashMap(); + payload.put("eventTicketClasses", Arrays.asList(newClass)); + payload.put("eventTicketObjects", Arrays.asList(newObject)); + claims.put("payload", payload); + + // The service account credentials are used to sign the JWT + Algorithm algorithm = + Algorithm.RSA256( + null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); + String token = JWT.create().withPayload(claims).sign(algorithm); + + System.out.println("Add to Google Wallet link"); + System.out.println(String.format("https://pay.google.com/gp/v/save/%s", token)); + + return String.format("https://pay.google.com/gp/v/save/%s", token); + } + // [END jwtNew] + + // [START jwtExisting] + /** + * Generate a signed JWT that references an existing pass object. + * + *

When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the + * pass objects defined in the JWT are added to the user's Google Wallet app. This allows the user + * to save multiple pass objects in one API call. + * + *

The objects to add must follow the below format: + * + *

{ 'id': 'ISSUER_ID.OBJECT_SUFFIX', 'classId': 'ISSUER_ID.CLASS_SUFFIX' } + * + * @param issuerId The issuer ID being used for this request. + * @return An "Add to Google Wallet" link. + */ + public String CreateJWTExistingObjects(String issuerId) { + // Multiple pass types can be added at the same time + // At least one type must be specified in the JWT claims + // Note: Make sure to replace the placeholder class and object suffixes + HashMap objectsToAdd = new HashMap(); + + // Event tickets + objectsToAdd.put( + "eventTicketObjects", + Arrays.asList( + new EventTicketObject() + .setId(String.format("%s.%s", issuerId, "EVENT_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "EVENT_CLASS_SUFFIX")))); + + // Boarding passes + objectsToAdd.put( + "flightObjects", + Arrays.asList( + new FlightObject() + .setId(String.format("%s.%s", issuerId, "FLIGHT_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "FLIGHT_CLASS_SUFFIX")))); + + // Generic passes + objectsToAdd.put( + "genericObjects", + Arrays.asList( + new GenericObject() + .setId(String.format("%s.%s", issuerId, "GENERIC_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "GENERIC_CLASS_SUFFIX")))); + + // Gift cards + objectsToAdd.put( + "giftCardObjects", + Arrays.asList( + new GiftCardObject() + .setId(String.format("%s.%s", issuerId, "GIFT_CARD_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "GIFT_CARD_CLASS_SUFFIX")))); + + // Loyalty cards + objectsToAdd.put( + "loyaltyObjects", + Arrays.asList( + new LoyaltyObject() + .setId(String.format("%s.%s", issuerId, "LOYALTY_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "LOYALTY_CLASS_SUFFIX")))); + + // Offers + objectsToAdd.put( + "offerObjects", + Arrays.asList( + new OfferObject() + .setId(String.format("%s.%s", issuerId, "OFFER_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "OFFER_CLASS_SUFFIX")))); + + // Transit passes + objectsToAdd.put( + "transitObjects", + Arrays.asList( + new TransitObject() + .setId(String.format("%s.%s", issuerId, "TRANSIT_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "TRANSIT_CLASS_SUFFIX")))); + + // Create the JWT as a HashMap object + HashMap claims = new HashMap(); + claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail()); + claims.put("aud", "google"); + claims.put("origins", Arrays.asList("www.example.com")); + claims.put("typ", "savetowallet"); + claims.put("payload", objectsToAdd); + + // The service account credentials are used to sign the JWT + Algorithm algorithm = + Algorithm.RSA256( + null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); + String token = JWT.create().withPayload(claims).sign(algorithm); + + System.out.println("Add to Google Wallet link"); + System.out.println(String.format("https://pay.google.com/gp/v/save/%s", token)); + + return String.format("https://pay.google.com/gp/v/save/%s", token); + } + // [END jwtExisting] + + // [START batch] + /** + * Batch create Google Wallet objects from an existing class. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @throws IOException + */ + public void BatchCreateObjects(String issuerId, String classSuffix) throws IOException { + // Create the batch request client + BatchRequest batch = service.batch(new HttpCredentialsAdapter(credentials)); + + // The callback will be invoked for each request in the batch + JsonBatchCallback callback = + new JsonBatchCallback() { + // Invoked if the request was successful + public void onSuccess(EventTicketObject response, HttpHeaders responseHeaders) { + System.out.println("Batch insert response"); + System.out.println(response.toString()); + } + + // Invoked if the request failed + public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) { + System.out.println("Error Message: " + e.getMessage()); + } + }; + + // Example: Generate three new pass objects + for (int i = 0; i < 3; i++) { + // Generate a random object suffix + String objectSuffix = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_"); + + // See link below for more information on required properties + // https://developers.google.com/wallet/tickets/events/rest/v1/eventticketobject + EventTicketObject batchObject = + new EventTicketObject() + .setId(String.format("%s.%s", issuerId, objectSuffix)) + .setClassId(String.format("%s.%s", issuerId, classSuffix)) + .setState("ACTIVE") + .setHeroImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Hero image description")))) + .setTextModulesData( + Arrays.asList( + new TextModuleData() + .setHeader("Text module header") + .setBody("Text module body") + .setId("TEXT_MODULE_ID"))) + .setLinksModuleData( + new LinksModuleData() + .setUris( + Arrays.asList( + new Uri() + .setUri("http://maps.google.com/") + .setDescription("Link module URI description") + .setId("LINK_MODULE_URI_ID"), + new Uri() + .setUri("tel:6505555555") + .setDescription("Link module tel description") + .setId("LINK_MODULE_TEL_ID")))) + .setImageModulesData( + Arrays.asList( + new ImageModuleData() + .setMainImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Image module description")))) + .setId("IMAGE_MODULE_ID"))) + .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) + .setLocations( + Arrays.asList( + new LatLongPoint() + .setLatitude(37.424015499999996) + .setLongitude(-122.09259560000001))) + .setSeatInfo( + new EventSeat() + .setSeat( + new LocalizedString() + .setDefaultValue( + new TranslatedString().setLanguage("en-US").setValue("42"))) + .setRow( + new LocalizedString() + .setDefaultValue( + new TranslatedString().setLanguage("en-US").setValue("G3"))) + .setSection( + new LocalizedString() + .setDefaultValue( + new TranslatedString().setLanguage("en-US").setValue("5"))) + .setGate( + new LocalizedString() + .setDefaultValue( + new TranslatedString().setLanguage("en-US").setValue("A")))) + .setTicketHolderName("Ticket holder name") + .setTicketNumber("Ticket number"); + + service.eventticketobject().insert(batchObject).queue(batch, callback); + } + + // Invoke the batch API calls + batch.execute(); + } + // [END batch] } diff --git a/java/src/main/java/DemoFlight.java b/java/src/main/java/DemoFlight.java index c4b15c0..60e391a 100644 --- a/java/src/main/java/DemoFlight.java +++ b/java/src/main/java/DemoFlight.java @@ -14,6 +14,8 @@ * limitations under the License. */ +// [START setup] +// [START imports] import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.google.api.client.googleapis.batch.BatchRequest; @@ -21,856 +23,886 @@ import com.google.api.client.googleapis.batch.json.JsonBatchCallback; import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; import com.google.api.client.googleapis.json.GoogleJsonError; import com.google.api.client.googleapis.json.GoogleJsonResponseException; -import com.google.api.client.http.HttpHeaders; -import com.google.api.client.http.HttpTransport; +import com.google.api.client.http.*; import com.google.api.client.json.gson.GsonFactory; import com.google.api.services.walletobjects.Walletobjects; import com.google.api.services.walletobjects.model.*; import com.google.auth.http.HttpCredentialsAdapter; import com.google.auth.oauth2.GoogleCredentials; import com.google.auth.oauth2.ServiceAccountCredentials; - -import java.io.FileInputStream; -import java.io.IOException; +import java.io.*; import java.security.interfaces.RSAPrivateKey; import java.util.*; +// [END imports] -/** - * Demo class for creating and managing Flights in Google Wallet. - */ +/** Demo class for creating and managing Flights in Google Wallet. */ public class DemoFlight { - /** - * Path to service account key file from Google Cloud Console. Environment variable: - * GOOGLE_APPLICATION_CREDENTIALS. - */ - public static String keyFilePath; + /** + * Path to service account key file from Google Cloud Console. Environment variable: + * GOOGLE_APPLICATION_CREDENTIALS. + */ + public static String keyFilePath; - /** - * Service account credentials for Google Wallet APIs. - */ - public static GoogleCredentials credentials; + /** Service account credentials for Google Wallet APIs. */ + public static GoogleCredentials credentials; - /** - * Google Wallet service client. - */ - public static Walletobjects service; + /** Google Wallet service client. */ + public static Walletobjects service; - public DemoFlight() throws Exception { - keyFilePath = - System.getenv().getOrDefault("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/key.json"); + public DemoFlight() throws Exception { + keyFilePath = + System.getenv().getOrDefault("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/key.json"); - auth(); - } + Auth(); + } + // [END setup] - /** - * Create authenticated HTTP client using a service account file. - */ - public void auth() throws Exception { - String scope = "https://www.googleapis.com/auth/wallet_object.issuer"; + // [START auth] + /** + * Create authenticated HTTP client using a service account file. + * + * @throws Exception + */ + public void Auth() throws Exception { + String scope = "https://www.googleapis.com/auth/wallet_object.issuer"; - credentials = - GoogleCredentials.fromStream(new FileInputStream(keyFilePath)) - .createScoped(List.of(scope)); - credentials.refresh(); + credentials = + GoogleCredentials.fromStream(new FileInputStream(keyFilePath)) + .createScoped(Arrays.asList(scope)); + credentials.refresh(); - HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport(); + HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport(); - // Initialize Google Wallet API service - service = - new Walletobjects.Builder( - httpTransport, - GsonFactory.getDefaultInstance(), - new HttpCredentialsAdapter(credentials)) - .setApplicationName("APPLICATION_NAME") - .build(); - } + // Initialize Google Wallet API service + service = + new Walletobjects.Builder( + httpTransport, + GsonFactory.getDefaultInstance(), + new HttpCredentialsAdapter(credentials)) + .setApplicationName("APPLICATION_NAME") + .build(); + } + // [END auth] - /** - * Create a class. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @return The pass class ID: "{issuerId}.{classSuffix}" - */ - public String createClass(String issuerId, String classSuffix) throws IOException { - // Check if the class exists - try { - service.flightclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); - - System.out.printf("Class %s.%s already exists!%n", issuerId, classSuffix); - return String.format("%s.%s", issuerId, classSuffix); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() != 404) { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, classSuffix); - } - } - - // See link below for more information on required properties - // https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightclass - FlightClass newClass = - new FlightClass() - .setId(String.format("%s.%s", issuerId, classSuffix)) - .setIssuerName("Issuer name") - .setReviewStatus("UNDER_REVIEW") - .setLocalScheduledDepartureDateTime("2023-07-02T15:30:00") - .setFlightHeader( - new FlightHeader() - .setCarrier(new FlightCarrier().setCarrierIataCode("LX")) - .setFlightNumber("123")) - .setOrigin(new AirportInfo().setAirportIataCode("LAX").setTerminal("1").setGate("A2")) - .setDestination( - new AirportInfo().setAirportIataCode("SFO").setTerminal("2").setGate("C3")); - - FlightClass response = service.flightclass().insert(newClass).execute(); - - System.out.println("Class insert response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Update a class. - * - *

Warning: This replaces all existing class attributes! - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @return The pass class ID: "{issuerId}.{classSuffix}" - */ - public String updateClass(String issuerId, String classSuffix) throws IOException { - FlightClass updatedClass; - - // Check if the class exists - try { - updatedClass = - service.flightclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Class does not exist - System.out.printf("Class %s.%s not found!%n", issuerId, classSuffix); - return String.format("%s.%s", issuerId, classSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, classSuffix); - } - } - - // Class exists - // Update the class by adding a homepage - updatedClass.setHomepageUri( - new Uri() - .setUri("https://developers.google.com/wallet") - .setDescription("Homepage description")); - - // Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates - updatedClass.setReviewStatus("UNDER_REVIEW"); - - FlightClass response = - service - .flightclass() - .update(String.format("%s.%s", issuerId, classSuffix), updatedClass) - .execute(); - - System.out.println("Class update response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Patch a class. - * - *

The PATCH method supports patch semantics. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @return The pass class ID: "{issuerId}.{classSuffix}" - */ - public String patchClass(String issuerId, String classSuffix) throws IOException { - // Check if the class exists - try { - service.flightclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Class does not exist - System.out.printf("Class %s.%s not found!%n", issuerId, classSuffix); - return String.format("%s.%s", issuerId, classSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, classSuffix); - } - } - - // Class exists - // Patch the class by adding a homepage - FlightClass patchBody = - new FlightClass() - .setHomepageUri( - new Uri() - .setUri("https://developers.google.com/wallet") - .setDescription("Homepage description")) - - // Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates - .setReviewStatus("UNDER_REVIEW"); - - FlightClass response = - service - .flightclass() - .patch(String.format("%s.%s", issuerId, classSuffix), patchBody) - .execute(); - - System.out.println("Class patch response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Add a message to a pass class. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @param header The message header. - * @param body The message body. - * @return The pass class ID: "{issuerId}.{classSuffix}" - */ - public String addClassMessage(String issuerId, String classSuffix, String header, String body) - throws IOException { - // Check if the class exists - try { - service.flightclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Class does not exist - System.out.printf("Class %s.%s not found!%n", issuerId, classSuffix); - return String.format("%s.%s", issuerId, classSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, classSuffix); - } - } - - AddMessageRequest message = - new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body)); - - FlightClassAddMessageResponse response = - service - .flightclass() - .addmessage(String.format("%s.%s", issuerId, classSuffix), message) - .execute(); - - System.out.println("Class addMessage response"); - System.out.println(response.toPrettyString()); + // [START createClass] + /** + * Create a class. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @return The pass class ID: "{issuerId}.{classSuffix}" + * @throws IOException + */ + public String CreateClass(String issuerId, String classSuffix) throws IOException { + // Check if the class exists + try { + service.flightclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); + System.out.println(String.format("Class %s.%s already exists!", issuerId, classSuffix)); + return String.format("%s.%s", issuerId, classSuffix); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() != 404) { + // Something else went wrong... + ex.printStackTrace(); return String.format("%s.%s", issuerId, classSuffix); + } } - /** - * Create an object. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String createObject(String issuerId, String classSuffix, String objectSuffix) - throws IOException { - // Check if the object exists - try { - service.flightobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + // See link below for more information on required properties + // https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightclass + FlightClass newClass = + new FlightClass() + .setId(String.format("%s.%s", issuerId, classSuffix)) + .setIssuerName("Issuer name") + .setReviewStatus("UNDER_REVIEW") + .setLocalScheduledDepartureDateTime("2023-07-02T15:30:00") + .setFlightHeader( + new FlightHeader() + .setCarrier(new FlightCarrier().setCarrierIataCode("LX")) + .setFlightNumber("123")) + .setOrigin(new AirportInfo().setAirportIataCode("LAX").setTerminal("1").setGate("A2")) + .setDestination( + new AirportInfo().setAirportIataCode("SFO").setTerminal("2").setGate("C3")); - System.out.printf("Object %s.%s already exists!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() != 404) { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } + FlightClass response = service.flightclass().insert(newClass).execute(); - // See link below for more information on required properties - // https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightobject - FlightObject newObject = - new FlightObject() - .setId(String.format("%s.%s", issuerId, objectSuffix)) - .setClassId(String.format("%s.%s", issuerId, classSuffix)) - .setState("ACTIVE") - .setHeroImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Hero image description")))) - .setTextModulesData( - List.of( - new TextModuleData() - .setHeader("Text module header") - .setBody("Text module body") - .setId("TEXT_MODULE_ID"))) - .setLinksModuleData( - new LinksModuleData() - .setUris( - Arrays.asList( - new Uri() - .setUri("http://maps.google.com/") - .setDescription("Link module URI description") - .setId("LINK_MODULE_URI_ID"), - new Uri() - .setUri("tel:6505555555") - .setDescription("Link module tel description") - .setId("LINK_MODULE_TEL_ID")))) - .setImageModulesData( - List.of( - new ImageModuleData() - .setMainImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Image module description")))) - .setId("IMAGE_MODULE_ID"))) - .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) - .setLocations( - List.of( - new LatLongPoint() - .setLatitude(37.424015499999996) - .setLongitude(-122.09259560000001))) - .setPassengerName("Passenger name") - .setBoardingAndSeatingInfo( - new BoardingAndSeatingInfo().setBoardingGroup("B").setSeatNumber("42")) - .setReservationInfo(new ReservationInfo().setConfirmationCode("Confirmation code")); + System.out.println("Class insert response"); + System.out.println(response.toPrettyString()); - FlightObject response = service.flightobject().insert(newObject).execute(); + return response.getId(); + } + // [END createClass] - System.out.println("Object insert response"); - System.out.println(response.toPrettyString()); + // [START updateClass] + /** + * Update a class. + * + *

Warning: This replaces all existing class attributes! + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @return The pass class ID: "{issuerId}.{classSuffix}" + * @throws IOException + */ + public String UpdateClass(String issuerId, String classSuffix) throws IOException { + FlightClass updatedClass; - return response.getId(); + // Check if the class exists + try { + updatedClass = + service.flightclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Class does not exist + System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix)); + return String.format("%s.%s", issuerId, classSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, classSuffix); + } } - /** - * Update an object. - * - *

Warning: This replaces all existing object attributes! - * - * @param issuerId The issuer ID being used for this request. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String updateObject(String issuerId, String objectSuffix) throws IOException { - FlightObject updatedObject; + // Class exists + // Update the class by adding a homepage + updatedClass.setHomepageUri( + new Uri() + .setUri("https://developers.google.com/wallet") + .setDescription("Homepage description")); - // Check if the object exists - try { - updatedObject = - service.flightobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Object does not exist - System.out.printf("Object %s.%s not found!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } + // Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates + updatedClass.setReviewStatus("UNDER_REVIEW"); - // Object exists - // Update the object by adding a link - Uri newLink = + FlightClass response = + service + .flightclass() + .update(String.format("%s.%s", issuerId, classSuffix), updatedClass) + .execute(); + + System.out.println("Class update response"); + System.out.println(response.toPrettyString()); + + return response.getId(); + } + // [END updateClass] + + // [START patchClass] + /** + * Patch a class. + * + *

The PATCH method supports patch semantics. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @return The pass class ID: "{issuerId}.{classSuffix}" + * @throws IOException + */ + public String PatchClass(String issuerId, String classSuffix) throws IOException { + // Check if the class exists + try { + service.flightclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Class does not exist + System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix)); + return String.format("%s.%s", issuerId, classSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, classSuffix); + } + } + + // Class exists + // Patch the class by adding a homepage + FlightClass patchBody = + new FlightClass() + .setHomepageUri( new Uri() - .setUri("https://developers.google.com/wallet") - .setDescription("New link description"); + .setUri("https://developers.google.com/wallet") + .setDescription("Homepage description")) - if (updatedObject.getLinksModuleData() == null) { - // LinksModuleData was not set on the original object - updatedObject.setLinksModuleData(new LinksModuleData().setUris(List.of(newLink))); - } else { - updatedObject.getLinksModuleData().getUris().add(newLink); - } + // Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates + .setReviewStatus("UNDER_REVIEW"); - FlightObject response = - service - .flightobject() - .update(String.format("%s.%s", issuerId, objectSuffix), updatedObject) - .execute(); + FlightClass response = + service + .flightclass() + .patch(String.format("%s.%s", issuerId, classSuffix), patchBody) + .execute(); - System.out.println("Object update response"); - System.out.println(response.toPrettyString()); + System.out.println("Class patch response"); + System.out.println(response.toPrettyString()); - return response.getId(); + return response.getId(); + } + // [END patchClass] + + // [START addMessageClass] + /** + * Add a message to a pass class. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @param header The message header. + * @param body The message body. + * @return The pass class ID: "{issuerId}.{classSuffix}" + * @throws IOException + */ + public String AddClassMessage(String issuerId, String classSuffix, String header, String body) + throws IOException { + // Check if the class exists + try { + service.flightclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Class does not exist + System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix)); + return String.format("%s.%s", issuerId, classSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, classSuffix); + } } - /** - * Patch an object. - * - * @param issuerId The issuer ID being used for this request. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String patchObject(String issuerId, String objectSuffix) throws IOException { - FlightObject existingObject; + AddMessageRequest message = + new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body)); - // Check if the object exists - try { - existingObject = - service.flightobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Object does not exist - System.out.printf("Object %s.%s not found!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } + FlightClassAddMessageResponse response = + service + .flightclass() + .addmessage(String.format("%s.%s", issuerId, classSuffix), message) + .execute(); - // Object exists - // Patch the object by adding a link - Uri newLink = - new Uri() - .setUri("https://developers.google.com/wallet") - .setDescription("New link description"); + System.out.println("Class addMessage response"); + System.out.println(response.toPrettyString()); - FlightObject patchBody = new FlightObject(); + return String.format("%s.%s", issuerId, classSuffix); + } + // [END addMessageClass] - if (existingObject.getLinksModuleData() == null) { - // LinksModuleData was not set on the original object - patchBody.setLinksModuleData(new LinksModuleData().setUris(new ArrayList())); - } else { - patchBody.setLinksModuleData(existingObject.getLinksModuleData()); - } - patchBody.getLinksModuleData().getUris().add(newLink); - - FlightObject response = - service - .flightobject() - .patch(String.format("%s.%s", issuerId, objectSuffix), patchBody) - .execute(); - - System.out.println("Object patch response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Expire an object. - * - *

Sets the object's state to Expired. If the valid time interval is already set, the pass will - * expire automatically up to 24 hours after. - * - * @param issuerId The issuer ID being used for this request. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String expireObject(String issuerId, String objectSuffix) throws IOException { - // Check if the object exists - try { - service.flightobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Object does not exist - System.out.printf("Object %s.%s not found!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } - - // Patch the object, setting the pass as expired - FlightObject patchBody = new FlightObject().setState("EXPIRED"); - - FlightObject response = - service - .flightobject() - .patch(String.format("%s.%s", issuerId, objectSuffix), patchBody) - .execute(); - - System.out.println("Object expiration response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Add a message to a pass object. - * - * @param issuerId The issuer ID being used for this request. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @param header The message header. - * @param body The message body. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String addObjectMessage(String issuerId, String objectSuffix, String header, String body) - throws IOException { - // Check if the object exists - try { - service.flightobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Object does not exist - System.out.printf("Object %s.%s not found!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } - - AddMessageRequest message = - new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body)); - - FlightObjectAddMessageResponse response = - service - .flightobject() - .addmessage(String.format("%s.%s", issuerId, objectSuffix), message) - .execute(); - - System.out.println("Object addMessage response"); - System.out.println(response.toPrettyString()); + // [START createObject] + /** + * Create an object. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String CreateObject(String issuerId, String classSuffix, String objectSuffix) + throws IOException { + // Check if the object exists + try { + service.flightobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + System.out.println(String.format("Object %s.%s already exists!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() != 404) { + // Something else went wrong... + ex.printStackTrace(); return String.format("%s.%s", issuerId, objectSuffix); + } } - /** - * Generate a signed JWT that creates a new pass class and object. - * - *

When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the - * pass class and object defined in the JWT are created. This allows you to create multiple pass - * classes and objects in one API call when the user saves the pass to their wallet. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @param objectSuffix Developer-defined unique ID for the pass object. - * @return An "Add to Google Wallet" link. - */ - public String createJWTNewObjects(String issuerId, String classSuffix, String objectSuffix) { - // See link below for more information on required properties - // https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightclass - FlightClass newClass = - new FlightClass() - .setId(String.format("%s.%s", issuerId, classSuffix)) - .setIssuerName("Issuer name") - .setReviewStatus("UNDER_REVIEW") - .setLocalScheduledDepartureDateTime("2023-07-02T15:30:00") - .setFlightHeader( - new FlightHeader() - .setCarrier(new FlightCarrier().setCarrierIataCode("LX")) - .setFlightNumber("123")) - .setOrigin(new AirportInfo().setAirportIataCode("LAX").setTerminal("1").setGate("A2")) - .setDestination( - new AirportInfo().setAirportIataCode("SFO").setTerminal("2").setGate("C3")); + // See link below for more information on required properties + // https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightobject + FlightObject newObject = + new FlightObject() + .setId(String.format("%s.%s", issuerId, objectSuffix)) + .setClassId(String.format("%s.%s", issuerId, classSuffix)) + .setState("ACTIVE") + .setHeroImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Hero image description")))) + .setTextModulesData( + Arrays.asList( + new TextModuleData() + .setHeader("Text module header") + .setBody("Text module body") + .setId("TEXT_MODULE_ID"))) + .setLinksModuleData( + new LinksModuleData() + .setUris( + Arrays.asList( + new Uri() + .setUri("http://maps.google.com/") + .setDescription("Link module URI description") + .setId("LINK_MODULE_URI_ID"), + new Uri() + .setUri("tel:6505555555") + .setDescription("Link module tel description") + .setId("LINK_MODULE_TEL_ID")))) + .setImageModulesData( + Arrays.asList( + new ImageModuleData() + .setMainImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Image module description")))) + .setId("IMAGE_MODULE_ID"))) + .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) + .setLocations( + Arrays.asList( + new LatLongPoint() + .setLatitude(37.424015499999996) + .setLongitude(-122.09259560000001))) + .setPassengerName("Passenger name") + .setBoardingAndSeatingInfo( + new BoardingAndSeatingInfo().setBoardingGroup("B").setSeatNumber("42")) + .setReservationInfo(new ReservationInfo().setConfirmationCode("Confirmation code")); - // See link below for more information on required properties - // https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightobject - FlightObject newObject = - new FlightObject() - .setId(String.format("%s.%s", issuerId, objectSuffix)) - .setClassId(String.format("%s.%s", issuerId, classSuffix)) - .setState("ACTIVE") - .setHeroImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Hero image description")))) - .setTextModulesData( - List.of( - new TextModuleData() - .setHeader("Text module header") - .setBody("Text module body") - .setId("TEXT_MODULE_ID"))) - .setLinksModuleData( - new LinksModuleData() - .setUris( - Arrays.asList( - new Uri() - .setUri("http://maps.google.com/") - .setDescription("Link module URI description") - .setId("LINK_MODULE_URI_ID"), - new Uri() - .setUri("tel:6505555555") - .setDescription("Link module tel description") - .setId("LINK_MODULE_TEL_ID")))) - .setImageModulesData( - List.of( - new ImageModuleData() - .setMainImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Image module description")))) - .setId("IMAGE_MODULE_ID"))) - .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) - .setLocations( - List.of( - new LatLongPoint() - .setLatitude(37.424015499999996) - .setLongitude(-122.09259560000001))) - .setPassengerName("Passenger name") - .setBoardingAndSeatingInfo( - new BoardingAndSeatingInfo().setBoardingGroup("B").setSeatNumber("42")) - .setReservationInfo(new ReservationInfo().setConfirmationCode("Confirmation code")); + FlightObject response = service.flightobject().insert(newObject).execute(); - // Create the JWT as a HashMap object - HashMap claims = new HashMap(); - claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail()); - claims.put("aud", "google"); - claims.put("origins", List.of("www.example.com")); - claims.put("typ", "savetowallet"); + System.out.println("Object insert response"); + System.out.println(response.toPrettyString()); - // Create the Google Wallet payload and add to the JWT - HashMap payload = new HashMap(); - payload.put("flightClasses", List.of(newClass)); - payload.put("flightObjects", List.of(newObject)); - claims.put("payload", payload); + return response.getId(); + } + // [END createObject] - // The service account credentials are used to sign the JWT - Algorithm algorithm = - Algorithm.RSA256( - null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); - String token = JWT.create().withPayload(claims).sign(algorithm); + // [START updateObject] + /** + * Update an object. + * + *

Warning: This replaces all existing object attributes! + * + * @param issuerId The issuer ID being used for this request. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String UpdateObject(String issuerId, String objectSuffix) throws IOException { + FlightObject updatedObject; - System.out.println("Add to Google Wallet link"); - System.out.printf("https://pay.google.com/gp/v/save/%s%n", token); - - return String.format("https://pay.google.com/gp/v/save/%s", token); + // Check if the object exists + try { + updatedObject = + service.flightobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Object does not exist + System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, objectSuffix); + } } - /** - * Generate a signed JWT that references an existing pass object. - * - *

When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the - * pass objects defined in the JWT are added to the user's Google Wallet app. This allows the user - * to save multiple pass objects in one API call. - * - *

The objects to add must follow the below format: - * - *

{ 'id': 'ISSUER_ID.OBJECT_SUFFIX', 'classId': 'ISSUER_ID.CLASS_SUFFIX' } - * - * @param issuerId The issuer ID being used for this request. - * @return An "Add to Google Wallet" link. - */ - public String createJWTExistingObjects(String issuerId) { - // Multiple pass types can be added at the same time - // At least one type must be specified in the JWT claims - // Note: Make sure to replace the placeholder class and object suffixes - HashMap objectsToAdd = new HashMap(); + // Object exists + // Update the object by adding a link + Uri newLink = + new Uri() + .setUri("https://developers.google.com/wallet") + .setDescription("New link description"); - // Event tickets - objectsToAdd.put( - "eventTicketObjects", - List.of( - new EventTicketObject() - .setId(String.format("%s.%s", issuerId, "EVENT_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "EVENT_CLASS_SUFFIX")))); - - // Boarding passes - objectsToAdd.put( - "flightObjects", - List.of( - new FlightObject() - .setId(String.format("%s.%s", issuerId, "FLIGHT_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "FLIGHT_CLASS_SUFFIX")))); - - // Generic passes - objectsToAdd.put( - "genericObjects", - List.of( - new GenericObject() - .setId(String.format("%s.%s", issuerId, "GENERIC_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "GENERIC_CLASS_SUFFIX")))); - - // Gift cards - objectsToAdd.put( - "giftCardObjects", - List.of( - new GiftCardObject() - .setId(String.format("%s.%s", issuerId, "GIFT_CARD_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "GIFT_CARD_CLASS_SUFFIX")))); - - // Loyalty cards - objectsToAdd.put( - "loyaltyObjects", - List.of( - new LoyaltyObject() - .setId(String.format("%s.%s", issuerId, "LOYALTY_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "LOYALTY_CLASS_SUFFIX")))); - - // Offers - objectsToAdd.put( - "offerObjects", - List.of( - new OfferObject() - .setId(String.format("%s.%s", issuerId, "OFFER_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "OFFER_CLASS_SUFFIX")))); - - // Transit passes - objectsToAdd.put( - "transitObjects", - List.of( - new TransitObject() - .setId(String.format("%s.%s", issuerId, "TRANSIT_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "TRANSIT_CLASS_SUFFIX")))); - - // Create the JWT as a HashMap object - HashMap claims = new HashMap(); - claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail()); - claims.put("aud", "google"); - claims.put("origins", List.of("www.example.com")); - claims.put("typ", "savetowallet"); - claims.put("payload", objectsToAdd); - - // The service account credentials are used to sign the JWT - Algorithm algorithm = - Algorithm.RSA256( - null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); - String token = JWT.create().withPayload(claims).sign(algorithm); - - System.out.println("Add to Google Wallet link"); - System.out.printf("https://pay.google.com/gp/v/save/%s%n", token); - - return String.format("https://pay.google.com/gp/v/save/%s", token); + if (updatedObject.getLinksModuleData() == null) { + // LinksModuleData was not set on the original object + updatedObject.setLinksModuleData(new LinksModuleData().setUris(Arrays.asList(newLink))); + } else { + updatedObject.getLinksModuleData().getUris().add(newLink); } - /** - * Batch create Google Wallet objects from an existing class. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - */ - public void batchCreateObjects(String issuerId, String classSuffix) throws IOException { - // Create the batch request client - BatchRequest batch = service.batch(new HttpCredentialsAdapter(credentials)); + FlightObject response = + service + .flightobject() + .update(String.format("%s.%s", issuerId, objectSuffix), updatedObject) + .execute(); - // The callback will be invoked for each request in the batch - JsonBatchCallback callback = - new JsonBatchCallback() { - // Invoked if the request was successful - public void onSuccess(FlightObject response, HttpHeaders responseHeaders) { - System.out.println("Batch insert response"); - System.out.println(response.toString()); - } + System.out.println("Object update response"); + System.out.println(response.toPrettyString()); - // Invoked if the request failed - public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) { - System.out.println("Error Message: " + e.getMessage()); - } - }; + return response.getId(); + } + // [END updateObject] - // Example: Generate three new pass objects - for (int i = 0; i < 3; i++) { - // Generate a random object suffix - String objectSuffix = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_"); + // [START patchObject] + /** + * Patch an object. + * + * @param issuerId The issuer ID being used for this request. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String PatchObject(String issuerId, String objectSuffix) throws IOException { + FlightObject existingObject; - // See link below for more information on required properties - // https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightobject - FlightObject batchObject = - new FlightObject() - .setId(String.format("%s.%s", issuerId, objectSuffix)) - .setClassId(String.format("%s.%s", issuerId, classSuffix)) - .setState("ACTIVE") - .setHeroImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Hero image description")))) - .setTextModulesData( - List.of( - new TextModuleData() - .setHeader("Text module header") - .setBody("Text module body") - .setId("TEXT_MODULE_ID"))) - .setLinksModuleData( - new LinksModuleData() - .setUris( - Arrays.asList( - new Uri() - .setUri("http://maps.google.com/") - .setDescription("Link module URI description") - .setId("LINK_MODULE_URI_ID"), - new Uri() - .setUri("tel:6505555555") - .setDescription("Link module tel description") - .setId("LINK_MODULE_TEL_ID")))) - .setImageModulesData( - List.of( - new ImageModuleData() - .setMainImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Image module description")))) - .setId("IMAGE_MODULE_ID"))) - .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) - .setLocations( - List.of( - new LatLongPoint() - .setLatitude(37.424015499999996) - .setLongitude(-122.09259560000001))) - .setPassengerName("Passenger name") - .setBoardingAndSeatingInfo( - new BoardingAndSeatingInfo().setBoardingGroup("B").setSeatNumber("42")) - .setReservationInfo(new ReservationInfo().setConfirmationCode("Confirmation code")); - - service.flightobject().insert(batchObject).queue(batch, callback); - } - - // Invoke the batch API calls - batch.execute(); + // Check if the object exists + try { + existingObject = + service.flightobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Object does not exist + System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, objectSuffix); + } } + // Object exists + // Patch the object by adding a link + Uri newLink = + new Uri() + .setUri("https://developers.google.com/wallet") + .setDescription("New link description"); + + FlightObject patchBody = new FlightObject(); + + if (existingObject.getLinksModuleData() == null) { + // LinksModuleData was not set on the original object + patchBody.setLinksModuleData(new LinksModuleData().setUris(new ArrayList())); + } else { + patchBody.setLinksModuleData(existingObject.getLinksModuleData()); + } + patchBody.getLinksModuleData().getUris().add(newLink); + + FlightObject response = + service + .flightobject() + .patch(String.format("%s.%s", issuerId, objectSuffix), patchBody) + .execute(); + + System.out.println("Object patch response"); + System.out.println(response.toPrettyString()); + + return response.getId(); + } + // [END patchObject] + + // [START expireObject] + /** + * Expire an object. + * + *

Sets the object's state to Expired. If the valid time interval is already set, the pass will + * expire automatically up to 24 hours after. + * + * @param issuerId The issuer ID being used for this request. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String ExpireObject(String issuerId, String objectSuffix) throws IOException { + // Check if the object exists + try { + service.flightobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Object does not exist + System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, objectSuffix); + } + } + + // Patch the object, setting the pass as expired + FlightObject patchBody = new FlightObject().setState("EXPIRED"); + + FlightObject response = + service + .flightobject() + .patch(String.format("%s.%s", issuerId, objectSuffix), patchBody) + .execute(); + + System.out.println("Object expiration response"); + System.out.println(response.toPrettyString()); + + return response.getId(); + } + // [END expireObject] + + // [START addMessageObject] + /** + * Add a message to a pass object. + * + * @param issuerId The issuer ID being used for this request. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @param header The message header. + * @param body The message body. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String AddObjectMessage(String issuerId, String objectSuffix, String header, String body) + throws IOException { + // Check if the object exists + try { + service.flightobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Object does not exist + System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, objectSuffix); + } + } + + AddMessageRequest message = + new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body)); + + FlightObjectAddMessageResponse response = + service + .flightobject() + .addmessage(String.format("%s.%s", issuerId, objectSuffix), message) + .execute(); + + System.out.println("Object addMessage response"); + System.out.println(response.toPrettyString()); + + return String.format("%s.%s", issuerId, objectSuffix); + } + // [END addMessageObject] + + // [START jwtNew] + /** + * Generate a signed JWT that creates a new pass class and object. + * + *

When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the + * pass class and object defined in the JWT are created. This allows you to create multiple pass + * classes and objects in one API call when the user saves the pass to their wallet. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @param objectSuffix Developer-defined unique ID for the pass object. + * @return An "Add to Google Wallet" link. + */ + public String CreateJWTNewObjects(String issuerId, String classSuffix, String objectSuffix) { + // See link below for more information on required properties + // https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightclass + FlightClass newClass = + new FlightClass() + .setId(String.format("%s.%s", issuerId, classSuffix)) + .setIssuerName("Issuer name") + .setReviewStatus("UNDER_REVIEW") + .setLocalScheduledDepartureDateTime("2023-07-02T15:30:00") + .setFlightHeader( + new FlightHeader() + .setCarrier(new FlightCarrier().setCarrierIataCode("LX")) + .setFlightNumber("123")) + .setOrigin(new AirportInfo().setAirportIataCode("LAX").setTerminal("1").setGate("A2")) + .setDestination( + new AirportInfo().setAirportIataCode("SFO").setTerminal("2").setGate("C3")); + + // See link below for more information on required properties + // https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightobject + FlightObject newObject = + new FlightObject() + .setId(String.format("%s.%s", issuerId, objectSuffix)) + .setClassId(String.format("%s.%s", issuerId, classSuffix)) + .setState("ACTIVE") + .setHeroImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Hero image description")))) + .setTextModulesData( + Arrays.asList( + new TextModuleData() + .setHeader("Text module header") + .setBody("Text module body") + .setId("TEXT_MODULE_ID"))) + .setLinksModuleData( + new LinksModuleData() + .setUris( + Arrays.asList( + new Uri() + .setUri("http://maps.google.com/") + .setDescription("Link module URI description") + .setId("LINK_MODULE_URI_ID"), + new Uri() + .setUri("tel:6505555555") + .setDescription("Link module tel description") + .setId("LINK_MODULE_TEL_ID")))) + .setImageModulesData( + Arrays.asList( + new ImageModuleData() + .setMainImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Image module description")))) + .setId("IMAGE_MODULE_ID"))) + .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) + .setLocations( + Arrays.asList( + new LatLongPoint() + .setLatitude(37.424015499999996) + .setLongitude(-122.09259560000001))) + .setPassengerName("Passenger name") + .setBoardingAndSeatingInfo( + new BoardingAndSeatingInfo().setBoardingGroup("B").setSeatNumber("42")) + .setReservationInfo(new ReservationInfo().setConfirmationCode("Confirmation code")); + + // Create the JWT as a HashMap object + HashMap claims = new HashMap(); + claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail()); + claims.put("aud", "google"); + claims.put("origins", Arrays.asList("www.example.com")); + claims.put("typ", "savetowallet"); + + // Create the Google Wallet payload and add to the JWT + HashMap payload = new HashMap(); + payload.put("flightClasses", Arrays.asList(newClass)); + payload.put("flightObjects", Arrays.asList(newObject)); + claims.put("payload", payload); + + // The service account credentials are used to sign the JWT + Algorithm algorithm = + Algorithm.RSA256( + null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); + String token = JWT.create().withPayload(claims).sign(algorithm); + + System.out.println("Add to Google Wallet link"); + System.out.println(String.format("https://pay.google.com/gp/v/save/%s", token)); + + return String.format("https://pay.google.com/gp/v/save/%s", token); + } + // [END jwtNew] + + // [START jwtExisting] + /** + * Generate a signed JWT that references an existing pass object. + * + *

When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the + * pass objects defined in the JWT are added to the user's Google Wallet app. This allows the user + * to save multiple pass objects in one API call. + * + *

The objects to add must follow the below format: + * + *

{ 'id': 'ISSUER_ID.OBJECT_SUFFIX', 'classId': 'ISSUER_ID.CLASS_SUFFIX' } + * + * @param issuerId The issuer ID being used for this request. + * @return An "Add to Google Wallet" link. + */ + public String CreateJWTExistingObjects(String issuerId) { + // Multiple pass types can be added at the same time + // At least one type must be specified in the JWT claims + // Note: Make sure to replace the placeholder class and object suffixes + HashMap objectsToAdd = new HashMap(); + + // Event tickets + objectsToAdd.put( + "eventTicketObjects", + Arrays.asList( + new EventTicketObject() + .setId(String.format("%s.%s", issuerId, "EVENT_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "EVENT_CLASS_SUFFIX")))); + + // Boarding passes + objectsToAdd.put( + "flightObjects", + Arrays.asList( + new FlightObject() + .setId(String.format("%s.%s", issuerId, "FLIGHT_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "FLIGHT_CLASS_SUFFIX")))); + + // Generic passes + objectsToAdd.put( + "genericObjects", + Arrays.asList( + new GenericObject() + .setId(String.format("%s.%s", issuerId, "GENERIC_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "GENERIC_CLASS_SUFFIX")))); + + // Gift cards + objectsToAdd.put( + "giftCardObjects", + Arrays.asList( + new GiftCardObject() + .setId(String.format("%s.%s", issuerId, "GIFT_CARD_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "GIFT_CARD_CLASS_SUFFIX")))); + + // Loyalty cards + objectsToAdd.put( + "loyaltyObjects", + Arrays.asList( + new LoyaltyObject() + .setId(String.format("%s.%s", issuerId, "LOYALTY_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "LOYALTY_CLASS_SUFFIX")))); + + // Offers + objectsToAdd.put( + "offerObjects", + Arrays.asList( + new OfferObject() + .setId(String.format("%s.%s", issuerId, "OFFER_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "OFFER_CLASS_SUFFIX")))); + + // Transit passes + objectsToAdd.put( + "transitObjects", + Arrays.asList( + new TransitObject() + .setId(String.format("%s.%s", issuerId, "TRANSIT_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "TRANSIT_CLASS_SUFFIX")))); + + // Create the JWT as a HashMap object + HashMap claims = new HashMap(); + claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail()); + claims.put("aud", "google"); + claims.put("origins", Arrays.asList("www.example.com")); + claims.put("typ", "savetowallet"); + claims.put("payload", objectsToAdd); + + // The service account credentials are used to sign the JWT + Algorithm algorithm = + Algorithm.RSA256( + null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); + String token = JWT.create().withPayload(claims).sign(algorithm); + + System.out.println("Add to Google Wallet link"); + System.out.println(String.format("https://pay.google.com/gp/v/save/%s", token)); + + return String.format("https://pay.google.com/gp/v/save/%s", token); + } + // [END jwtExisting] + + // [START batch] + /** + * Batch create Google Wallet objects from an existing class. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @throws IOException + */ + public void BatchCreateObjects(String issuerId, String classSuffix) throws IOException { + // Create the batch request client + BatchRequest batch = service.batch(new HttpCredentialsAdapter(credentials)); + + // The callback will be invoked for each request in the batch + JsonBatchCallback callback = + new JsonBatchCallback() { + // Invoked if the request was successful + public void onSuccess(FlightObject response, HttpHeaders responseHeaders) { + System.out.println("Batch insert response"); + System.out.println(response.toString()); + } + + // Invoked if the request failed + public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) { + System.out.println("Error Message: " + e.getMessage()); + } + }; + + // Example: Generate three new pass objects + for (int i = 0; i < 3; i++) { + // Generate a random object suffix + String objectSuffix = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_"); + + // See link below for more information on required properties + // https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightobject + FlightObject batchObject = + new FlightObject() + .setId(String.format("%s.%s", issuerId, objectSuffix)) + .setClassId(String.format("%s.%s", issuerId, classSuffix)) + .setState("ACTIVE") + .setHeroImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Hero image description")))) + .setTextModulesData( + Arrays.asList( + new TextModuleData() + .setHeader("Text module header") + .setBody("Text module body") + .setId("TEXT_MODULE_ID"))) + .setLinksModuleData( + new LinksModuleData() + .setUris( + Arrays.asList( + new Uri() + .setUri("http://maps.google.com/") + .setDescription("Link module URI description") + .setId("LINK_MODULE_URI_ID"), + new Uri() + .setUri("tel:6505555555") + .setDescription("Link module tel description") + .setId("LINK_MODULE_TEL_ID")))) + .setImageModulesData( + Arrays.asList( + new ImageModuleData() + .setMainImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Image module description")))) + .setId("IMAGE_MODULE_ID"))) + .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) + .setLocations( + Arrays.asList( + new LatLongPoint() + .setLatitude(37.424015499999996) + .setLongitude(-122.09259560000001))) + .setPassengerName("Passenger name") + .setBoardingAndSeatingInfo( + new BoardingAndSeatingInfo().setBoardingGroup("B").setSeatNumber("42")) + .setReservationInfo(new ReservationInfo().setConfirmationCode("Confirmation code")); + + service.flightobject().insert(batchObject).queue(batch, callback); + } + + // Invoke the batch API calls + batch.execute(); + } + // [END batch] } diff --git a/java/src/main/java/DemoGeneric.java b/java/src/main/java/DemoGeneric.java index 8d2ce73..14f5b13 100644 --- a/java/src/main/java/DemoGeneric.java +++ b/java/src/main/java/DemoGeneric.java @@ -14,6 +14,8 @@ * limitations under the License. */ +// [START setup] +// [START imports] import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.google.api.client.googleapis.batch.BatchRequest; @@ -21,801 +23,825 @@ import com.google.api.client.googleapis.batch.json.JsonBatchCallback; import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; import com.google.api.client.googleapis.json.GoogleJsonError; import com.google.api.client.googleapis.json.GoogleJsonResponseException; -import com.google.api.client.http.HttpHeaders; -import com.google.api.client.http.HttpTransport; +import com.google.api.client.http.*; import com.google.api.client.json.gson.GsonFactory; import com.google.api.services.walletobjects.Walletobjects; import com.google.api.services.walletobjects.model.*; import com.google.auth.http.HttpCredentialsAdapter; import com.google.auth.oauth2.GoogleCredentials; import com.google.auth.oauth2.ServiceAccountCredentials; - -import java.io.FileInputStream; -import java.io.IOException; +import java.io.*; import java.security.interfaces.RSAPrivateKey; import java.util.*; +// [END imports] -/** - * Demo class for creating and managing Generic passes in Google Wallet. - */ +/** Demo class for creating and managing Generic passes in Google Wallet. */ public class DemoGeneric { - /** - * Path to service account key file from Google Cloud Console. Environment variable: - * GOOGLE_APPLICATION_CREDENTIALS. - */ - public static String keyFilePath; + /** + * Path to service account key file from Google Cloud Console. Environment variable: + * GOOGLE_APPLICATION_CREDENTIALS. + */ + public static String keyFilePath; - /** - * Service account credentials for Google Wallet APIs. - */ - public static GoogleCredentials credentials; + /** Service account credentials for Google Wallet APIs. */ + public static GoogleCredentials credentials; - /** - * Google Wallet service client. - */ - public static Walletobjects service; + /** Google Wallet service client. */ + public static Walletobjects service; - public DemoGeneric() throws Exception { - keyFilePath = - System.getenv().getOrDefault("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/key.json"); + public DemoGeneric() throws Exception { + keyFilePath = + System.getenv().getOrDefault("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/key.json"); - auth(); + Auth(); + } + // [END setup] + + // [START auth] + /** + * Create authenticated HTTP client using a service account file. + * + * @throws Exception + */ + public void Auth() throws Exception { + String scope = "https://www.googleapis.com/auth/wallet_object.issuer"; + + credentials = + GoogleCredentials.fromStream(new FileInputStream(keyFilePath)) + .createScoped(Arrays.asList(scope)); + credentials.refresh(); + + HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport(); + + // Initialize Google Wallet API service + service = + new Walletobjects.Builder( + httpTransport, + GsonFactory.getDefaultInstance(), + new HttpCredentialsAdapter(credentials)) + .setApplicationName("APPLICATION_NAME") + .build(); + } + // [END auth] + + // [START createClass] + /** + * Create a class. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @return The pass class ID: "{issuerId}.{classSuffix}" + * @throws IOException + */ + public String CreateClass(String issuerId, String classSuffix) throws IOException { + // Check if the class exists + try { + service.genericclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); + + System.out.println(String.format("Class %s.%s already exists!", issuerId, classSuffix)); + return String.format("%s.%s", issuerId, classSuffix); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() != 404) { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, classSuffix); + } } - /** - * Create authenticated HTTP client using a service account file. - */ - public void auth() throws Exception { - String scope = "https://www.googleapis.com/auth/wallet_object.issuer"; + // See link below for more information on required properties + // https://developers.google.com/wallet/generic/rest/v1/genericclass + GenericClass newClass = new GenericClass().setId(String.format("%s.%s", issuerId, classSuffix)); - credentials = - GoogleCredentials.fromStream(new FileInputStream(keyFilePath)) - .createScoped(List.of(scope)); - credentials.refresh(); + GenericClass response = service.genericclass().insert(newClass).execute(); - HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport(); + System.out.println("Class insert response"); + System.out.println(response.toPrettyString()); - // Initialize Google Wallet API service - service = - new Walletobjects.Builder( - httpTransport, - GsonFactory.getDefaultInstance(), - new HttpCredentialsAdapter(credentials)) - .setApplicationName("APPLICATION_NAME") - .build(); + return response.getId(); + } + // [END createClass] + + // [START updateClass] + /** + * Update a class. + * + *

Warning: This replaces all existing class attributes! + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @return The pass class ID: "{issuerId}.{classSuffix}" + * @throws IOException + */ + public String UpdateClass(String issuerId, String classSuffix) throws IOException { + GenericClass updatedClass; + + // Check if the class exists + try { + updatedClass = + service.genericclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Class does not exist + System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix)); + return String.format("%s.%s", issuerId, classSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, classSuffix); + } } - /** - * Create a class. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @return The pass class ID: "{issuerId}.{classSuffix}" - */ - public String createClass(String issuerId, String classSuffix) throws IOException { - // Check if the class exists - try { - service.genericclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); + // Class exists + // Update the class by adding a link + Uri newLink = + new Uri() + .setUri("https://developers.google.com/wallet") + .setDescription("New link description"); - System.out.printf("Class %s.%s already exists!%n", issuerId, classSuffix); - return String.format("%s.%s", issuerId, classSuffix); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() != 404) { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, classSuffix); - } - } + if (updatedClass.getLinksModuleData() == null) { + // LinksModuleData was not set on the original object + updatedClass.setLinksModuleData(new LinksModuleData().setUris(new ArrayList())); + } + updatedClass.getLinksModuleData().getUris().add(newLink); - // See link below for more information on required properties - // https://developers.google.com/wallet/generic/rest/v1/genericclass - GenericClass newClass = new GenericClass().setId(String.format("%s.%s", issuerId, classSuffix)); + GenericClass response = + service + .genericclass() + .update(String.format("%s.%s", issuerId, classSuffix), updatedClass) + .execute(); - GenericClass response = service.genericclass().insert(newClass).execute(); + System.out.println("Class update response"); + System.out.println(response.toPrettyString()); - System.out.println("Class insert response"); - System.out.println(response.toPrettyString()); + return response.getId(); + } + // [END updateClass] - return response.getId(); + // [START patchClass] + /** + * Patch a class. + * + *

The PATCH method supports patch semantics. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @return The pass class ID: "{issuerId}.{classSuffix}" + * @throws IOException + */ + public String PatchClass(String issuerId, String classSuffix) throws IOException { + GenericClass existingClass; + + // Check if the class exists + try { + existingClass = + service.genericclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Class does not exist + System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix)); + return String.format("%s.%s", issuerId, classSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, classSuffix); + } } - /** - * Update a class. - * - *

Warning: This replaces all existing class attributes! - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @return The pass class ID: "{issuerId}.{classSuffix}" - */ - public String updateClass(String issuerId, String classSuffix) throws IOException { - GenericClass updatedClass; + // Class exists + // Patch the class by adding a homepage + GenericClass patchBody = new GenericClass(); - // Check if the class exists - try { - updatedClass = - service.genericclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Class does not exist - System.out.printf("Class %s.%s not found!%n", issuerId, classSuffix); - return String.format("%s.%s", issuerId, classSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, classSuffix); - } - } + // Class exists + // Update the class by adding a link + Uri newLink = + new Uri() + .setUri("https://developers.google.com/wallet") + .setDescription("New link description"); - // Class exists - // Update the class by adding a link - Uri newLink = - new Uri() - .setUri("https://developers.google.com/wallet") - .setDescription("New link description"); + if (existingClass.getLinksModuleData() == null) { + // LinksModuleData was not set on the original object + patchBody.setLinksModuleData(new LinksModuleData().setUris(new ArrayList())); + } else { + patchBody.setLinksModuleData(existingClass.getLinksModuleData()); + } + patchBody.getLinksModuleData().getUris().add(newLink); - if (updatedClass.getLinksModuleData() == null) { - // LinksModuleData was not set on the original object - updatedClass.setLinksModuleData(new LinksModuleData().setUris(new ArrayList())); - } - updatedClass.getLinksModuleData().getUris().add(newLink); + GenericClass response = + service + .genericclass() + .patch(String.format("%s.%s", issuerId, classSuffix), patchBody) + .execute(); - GenericClass response = - service - .genericclass() - .update(String.format("%s.%s", issuerId, classSuffix), updatedClass) - .execute(); + System.out.println("Class patch response"); + System.out.println(response.toPrettyString()); - System.out.println("Class update response"); - System.out.println(response.toPrettyString()); + return response.getId(); + } + // [END patchClass] - return response.getId(); + // [START createObject] + /** + * Create an object. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String CreateObject(String issuerId, String classSuffix, String objectSuffix) + throws IOException { + // Check if the object exists + try { + service.genericobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + + System.out.println(String.format("Object %s.%s already exists!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() != 404) { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, objectSuffix); + } } - /** - * Patch a class. - * - *

The PATCH method supports patch semantics. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @return The pass class ID: "{issuerId}.{classSuffix}" - */ - public String patchClass(String issuerId, String classSuffix) throws IOException { - GenericClass existingClass; - - // Check if the class exists - try { - existingClass = - service.genericclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Class does not exist - System.out.printf("Class %s.%s not found!%n", issuerId, classSuffix); - return String.format("%s.%s", issuerId, classSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, classSuffix); - } - } - - // Class exists - // Patch the class by adding a homepage - GenericClass patchBody = new GenericClass(); - - // Class exists - // Update the class by adding a link - Uri newLink = - new Uri() - .setUri("https://developers.google.com/wallet") - .setDescription("New link description"); - - if (existingClass.getLinksModuleData() == null) { - // LinksModuleData was not set on the original object - patchBody.setLinksModuleData(new LinksModuleData().setUris(new ArrayList())); - } else { - patchBody.setLinksModuleData(existingClass.getLinksModuleData()); - } - patchBody.getLinksModuleData().getUris().add(newLink); - - GenericClass response = - service - .genericclass() - .patch(String.format("%s.%s", issuerId, classSuffix), patchBody) - .execute(); - - System.out.println("Class patch response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Create an object. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String createObject(String issuerId, String classSuffix, String objectSuffix) - throws IOException { - // Check if the object exists - try { - service.genericobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); - - System.out.printf("Object %s.%s already exists!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() != 404) { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } - - // See link below for more information on required properties - // https://developers.google.com/wallet/generic/rest/v1/genericobject - GenericObject newObject = - new GenericObject() - .setId(String.format("%s.%s", issuerId, objectSuffix)) - .setClassId(String.format("%s.%s", issuerId, classSuffix)) - .setState("ACTIVE") - .setHeroImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Hero image description")))) - .setTextModulesData( - List.of( - new TextModuleData() - .setHeader("Text module header") - .setBody("Text module body") - .setId("TEXT_MODULE_ID"))) - .setLinksModuleData( - new LinksModuleData() - .setUris( - Arrays.asList( - new Uri() - .setUri("http://maps.google.com/") - .setDescription("Link module URI description") - .setId("LINK_MODULE_URI_ID"), - new Uri() - .setUri("tel:6505555555") - .setDescription("Link module tel description") - .setId("LINK_MODULE_TEL_ID")))) - .setImageModulesData( - List.of( - new ImageModuleData() - .setMainImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Image module description")))) - .setId("IMAGE_MODULE_ID"))) - .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) - .setCardTitle( - new LocalizedString() - .setDefaultValue( - new TranslatedString().setLanguage("en-US").setValue("Generic card title"))) - .setHeader( - new LocalizedString() - .setDefaultValue( - new TranslatedString().setLanguage("en-US").setValue("Generic header"))) - .setHexBackgroundColor("#4285f4") - .setLogo( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Generic card logo")))); - - GenericObject response = service.genericobject().insert(newObject).execute(); - - System.out.println("Object insert response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Update an object. - * - *

Warning: This replaces all existing object attributes! - * - * @param issuerId The issuer ID being used for this request. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String updateObject(String issuerId, String objectSuffix) throws IOException { - GenericObject updatedObject; - - // Check if the object exists - try { - updatedObject = - service.genericobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Object does not exist - System.out.printf("Object %s.%s not found!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } - - // Object exists - // Update the object by adding a link - Uri newLink = - new Uri() - .setUri("https://developers.google.com/wallet") - .setDescription("New link description"); - - if (updatedObject.getLinksModuleData() == null) { - // LinksModuleData was not set on the original object - updatedObject.setLinksModuleData(new LinksModuleData().setUris(List.of(newLink))); - } else { - updatedObject.getLinksModuleData().getUris().add(newLink); - } - - GenericObject response = - service - .genericobject() - .update(String.format("%s.%s", issuerId, objectSuffix), updatedObject) - .execute(); - - System.out.println("Object update response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Patch an object. - * - * @param issuerId The issuer ID being used for this request. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String patchObject(String issuerId, String objectSuffix) throws IOException { - GenericObject existingObject; - - // Check if the object exists - try { - existingObject = - service.genericobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Object does not exist - System.out.printf("Object %s.%s not found!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } - - // Object exists - // Patch the object by adding a link - Uri newLink = - new Uri() - .setUri("https://developers.google.com/wallet") - .setDescription("New link description"); - - GenericObject patchBody = new GenericObject(); - - if (existingObject.getLinksModuleData() == null) { - // LinksModuleData was not set on the original object - patchBody.setLinksModuleData(new LinksModuleData().setUris(new ArrayList())); - } else { - patchBody.setLinksModuleData(existingObject.getLinksModuleData()); - } - patchBody.getLinksModuleData().getUris().add(newLink); - - GenericObject response = - service - .genericobject() - .patch(String.format("%s.%s", issuerId, objectSuffix), patchBody) - .execute(); - - System.out.println("Object patch response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Expire an object. - * - *

Sets the object's state to Expired. If the valid time interval is already set, the pass will - * expire automatically up to 24 hours after. - * - * @param issuerId The issuer ID being used for this request. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String expireObject(String issuerId, String objectSuffix) throws IOException { - // Check if the object exists - try { - service.genericobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Object does not exist - System.out.printf("Object %s.%s not found!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } - - // Patch the object, setting the pass as expired - GenericObject patchBody = new GenericObject().setState("EXPIRED"); - - GenericObject response = - service - .genericobject() - .patch(String.format("%s.%s", issuerId, objectSuffix), patchBody) - .execute(); - - System.out.println("Object expiration response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Generate a signed JWT that creates a new pass class and object. - * - *

When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the - * pass class and object defined in the JWT are created. This allows you to create multiple pass - * classes and objects in one API call when the user saves the pass to their wallet. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @param objectSuffix Developer-defined unique ID for the pass object. - * @return An "Add to Google Wallet" link. - */ - public String createJWTNewObjects(String issuerId, String classSuffix, String objectSuffix) { - // See link below for more information on required properties - // https://developers.google.com/wallet/generic/rest/v1/genericclass - GenericClass newClass = new GenericClass().setId(String.format("%s.%s", issuerId, classSuffix)); - - // See link below for more information on required properties - // https://developers.google.com/wallet/generic/rest/v1/genericobject - GenericObject newObject = - new GenericObject() - .setId(String.format("%s.%s", issuerId, objectSuffix)) - .setClassId(String.format("%s.%s", issuerId, classSuffix)) - .setState("ACTIVE") - .setHeroImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Hero image description")))) - .setTextModulesData( - List.of( - new TextModuleData() - .setHeader("Text module header") - .setBody("Text module body") - .setId("TEXT_MODULE_ID"))) - .setLinksModuleData( - new LinksModuleData() - .setUris( - Arrays.asList( - new Uri() - .setUri("http://maps.google.com/") - .setDescription("Link module URI description") - .setId("LINK_MODULE_URI_ID"), - new Uri() - .setUri("tel:6505555555") - .setDescription("Link module tel description") - .setId("LINK_MODULE_TEL_ID")))) - .setImageModulesData( - List.of( - new ImageModuleData() - .setMainImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Image module description")))) - .setId("IMAGE_MODULE_ID"))) - .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) - .setCardTitle( - new LocalizedString() - .setDefaultValue( - new TranslatedString().setLanguage("en-US").setValue("Generic card title"))) - .setHeader( - new LocalizedString() - .setDefaultValue( - new TranslatedString().setLanguage("en-US").setValue("Generic header"))) - .setHexBackgroundColor("#4285f4") - .setLogo( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Generic card logo")))); - - // Create the JWT as a HashMap object - HashMap claims = new HashMap(); - claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail()); - claims.put("aud", "google"); - claims.put("origins", List.of("www.example.com")); - claims.put("typ", "savetowallet"); - - // Create the Google Wallet payload and add to the JWT - HashMap payload = new HashMap(); - payload.put("genericClasses", List.of(newClass)); - payload.put("genericObjects", List.of(newObject)); - claims.put("payload", payload); - - // The service account credentials are used to sign the JWT - Algorithm algorithm = - Algorithm.RSA256( - null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); - String token = JWT.create().withPayload(claims).sign(algorithm); - - System.out.println("Add to Google Wallet link"); - System.out.printf("https://pay.google.com/gp/v/save/%s%n", token); - - return String.format("https://pay.google.com/gp/v/save/%s", token); - } - - /** - * Generate a signed JWT that references an existing pass object. - * - *

When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the - * pass objects defined in the JWT are added to the user's Google Wallet app. This allows the user - * to save multiple pass objects in one API call. - * - *

The objects to add must follow the below format: - * - *

{ 'id': 'ISSUER_ID.OBJECT_SUFFIX', 'classId': 'ISSUER_ID.CLASS_SUFFIX' } - * - * @param issuerId The issuer ID being used for this request. - * @return An "Add to Google Wallet" link. - */ - public String createJWTExistingObjects(String issuerId) { - // Multiple pass types can be added at the same time - // At least one type must be specified in the JWT claims - // Note: Make sure to replace the placeholder class and object suffixes - HashMap objectsToAdd = new HashMap(); - - // Event tickets - objectsToAdd.put( - "eventTicketObjects", - List.of( - new EventTicketObject() - .setId(String.format("%s.%s", issuerId, "EVENT_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "EVENT_CLASS_SUFFIX")))); - - // Boarding passes - objectsToAdd.put( - "flightObjects", - List.of( - new FlightObject() - .setId(String.format("%s.%s", issuerId, "FLIGHT_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "FLIGHT_CLASS_SUFFIX")))); - - // Generic passes - objectsToAdd.put( - "genericObjects", - List.of( - new GenericObject() - .setId(String.format("%s.%s", issuerId, "GENERIC_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "GENERIC_CLASS_SUFFIX")))); - - // Gift cards - objectsToAdd.put( - "giftCardObjects", - List.of( - new GiftCardObject() - .setId(String.format("%s.%s", issuerId, "GIFT_CARD_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "GIFT_CARD_CLASS_SUFFIX")))); - - // Loyalty cards - objectsToAdd.put( - "loyaltyObjects", - List.of( - new LoyaltyObject() - .setId(String.format("%s.%s", issuerId, "LOYALTY_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "LOYALTY_CLASS_SUFFIX")))); - - // Offers - objectsToAdd.put( - "offerObjects", - List.of( - new OfferObject() - .setId(String.format("%s.%s", issuerId, "OFFER_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "OFFER_CLASS_SUFFIX")))); - - // Transit passes - objectsToAdd.put( - "transitObjects", - List.of( - new TransitObject() - .setId(String.format("%s.%s", issuerId, "TRANSIT_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "TRANSIT_CLASS_SUFFIX")))); - - // Create the JWT as a HashMap object - HashMap claims = new HashMap(); - claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail()); - claims.put("aud", "google"); - claims.put("origins", List.of("www.example.com")); - claims.put("typ", "savetowallet"); - claims.put("payload", objectsToAdd); - - // The service account credentials are used to sign the JWT - Algorithm algorithm = - Algorithm.RSA256( - null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); - String token = JWT.create().withPayload(claims).sign(algorithm); - - System.out.println("Add to Google Wallet link"); - System.out.printf("https://pay.google.com/gp/v/save/%s%n", token); - - return String.format("https://pay.google.com/gp/v/save/%s", token); - } - - /** - * Batch create Google Wallet objects from an existing class. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - */ - public void batchCreateObjects(String issuerId, String classSuffix) throws IOException { - // Create the batch request client - BatchRequest batch = service.batch(new HttpCredentialsAdapter(credentials)); - - // The callback will be invoked for each request in the batch - JsonBatchCallback callback = - new JsonBatchCallback() { - // Invoked if the request was successful - public void onSuccess(GenericObject response, HttpHeaders responseHeaders) { - System.out.println("Batch insert response"); - System.out.println(response.toString()); - } - - // Invoked if the request failed - public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) { - System.out.println("Error Message: " + e.getMessage()); - } - }; - - // Example: Generate three new pass objects - for (int i = 0; i < 3; i++) { - // Generate a random object suffix - String objectSuffix = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_"); - - // See link below for more information on required properties - // https://developers.google.com/wallet/generic/rest/v1/genericobject - GenericObject batchObject = - new GenericObject() - .setId(String.format("%s.%s", issuerId, objectSuffix)) - .setClassId(String.format("%s.%s", issuerId, classSuffix)) - .setState("ACTIVE") - .setHeroImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Hero image description")))) - .setTextModulesData( - List.of( - new TextModuleData() - .setHeader("Text module header") - .setBody("Text module body") - .setId("TEXT_MODULE_ID"))) - .setLinksModuleData( - new LinksModuleData() - .setUris( - Arrays.asList( - new Uri() - .setUri("http://maps.google.com/") - .setDescription("Link module URI description") - .setId("LINK_MODULE_URI_ID"), - new Uri() - .setUri("tel:6505555555") - .setDescription("Link module tel description") - .setId("LINK_MODULE_TEL_ID")))) - .setImageModulesData( - List.of( - new ImageModuleData() - .setMainImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Image module description")))) - .setId("IMAGE_MODULE_ID"))) - .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) - .setCardTitle( + // See link below for more information on required properties + // https://developers.google.com/wallet/generic/rest/v1/genericobject + GenericObject newObject = + new GenericObject() + .setId(String.format("%s.%s", issuerId, objectSuffix)) + .setClassId(String.format("%s.%s", issuerId, classSuffix)) + .setState("ACTIVE") + .setHeroImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Hero image description")))) + .setTextModulesData( + Arrays.asList( + new TextModuleData() + .setHeader("Text module header") + .setBody("Text module body") + .setId("TEXT_MODULE_ID"))) + .setLinksModuleData( + new LinksModuleData() + .setUris( + Arrays.asList( + new Uri() + .setUri("http://maps.google.com/") + .setDescription("Link module URI description") + .setId("LINK_MODULE_URI_ID"), + new Uri() + .setUri("tel:6505555555") + .setDescription("Link module tel description") + .setId("LINK_MODULE_TEL_ID")))) + .setImageModulesData( + Arrays.asList( + new ImageModuleData() + .setMainImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) + .setContentDescription( new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Generic card title"))) - .setHeader( - new LocalizedString() - .setDefaultValue( - new TranslatedString().setLanguage("en-US").setValue("Generic header"))) - .setHexBackgroundColor("#4285f4") - .setLogo( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Generic card logo")))); + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Image module description")))) + .setId("IMAGE_MODULE_ID"))) + .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) + .setCardTitle( + new LocalizedString() + .setDefaultValue( + new TranslatedString().setLanguage("en-US").setValue("Generic card title"))) + .setHeader( + new LocalizedString() + .setDefaultValue( + new TranslatedString().setLanguage("en-US").setValue("Generic header"))) + .setHexBackgroundColor("#4285f4") + .setLogo( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Generic card logo")))); - service.genericobject().insert(batchObject).queue(batch, callback); - } + GenericObject response = service.genericobject().insert(newObject).execute(); - // Invoke the batch API calls - batch.execute(); + System.out.println("Object insert response"); + System.out.println(response.toPrettyString()); + + return response.getId(); + } + // [END createObject] + + // [START updateObject] + /** + * Update an object. + * + *

Warning: This replaces all existing object attributes! + * + * @param issuerId The issuer ID being used for this request. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String UpdateObject(String issuerId, String objectSuffix) throws IOException { + GenericObject updatedObject; + + // Check if the object exists + try { + updatedObject = + service.genericobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Object does not exist + System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, objectSuffix); + } } + // Object exists + // Update the object by adding a link + Uri newLink = + new Uri() + .setUri("https://developers.google.com/wallet") + .setDescription("New link description"); + + if (updatedObject.getLinksModuleData() == null) { + // LinksModuleData was not set on the original object + updatedObject.setLinksModuleData(new LinksModuleData().setUris(Arrays.asList(newLink))); + } else { + updatedObject.getLinksModuleData().getUris().add(newLink); + } + + GenericObject response = + service + .genericobject() + .update(String.format("%s.%s", issuerId, objectSuffix), updatedObject) + .execute(); + + System.out.println("Object update response"); + System.out.println(response.toPrettyString()); + + return response.getId(); + } + // [END updateObject] + + // [START patchObject] + /** + * Patch an object. + * + * @param issuerId The issuer ID being used for this request. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String PatchObject(String issuerId, String objectSuffix) throws IOException { + GenericObject existingObject; + + // Check if the object exists + try { + existingObject = + service.genericobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Object does not exist + System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, objectSuffix); + } + } + + // Object exists + // Patch the object by adding a link + Uri newLink = + new Uri() + .setUri("https://developers.google.com/wallet") + .setDescription("New link description"); + + GenericObject patchBody = new GenericObject(); + + if (existingObject.getLinksModuleData() == null) { + // LinksModuleData was not set on the original object + patchBody.setLinksModuleData(new LinksModuleData().setUris(new ArrayList())); + } else { + patchBody.setLinksModuleData(existingObject.getLinksModuleData()); + } + patchBody.getLinksModuleData().getUris().add(newLink); + + GenericObject response = + service + .genericobject() + .patch(String.format("%s.%s", issuerId, objectSuffix), patchBody) + .execute(); + + System.out.println("Object patch response"); + System.out.println(response.toPrettyString()); + + return response.getId(); + } + // [END patchObject] + + // [START expireObject] + /** + * Expire an object. + * + *

Sets the object's state to Expired. If the valid time interval is already set, the pass will + * expire automatically up to 24 hours after. + * + * @param issuerId The issuer ID being used for this request. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String ExpireObject(String issuerId, String objectSuffix) throws IOException { + // Check if the object exists + try { + service.genericobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Object does not exist + System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, objectSuffix); + } + } + + // Patch the object, setting the pass as expired + GenericObject patchBody = new GenericObject().setState("EXPIRED"); + + GenericObject response = + service + .genericobject() + .patch(String.format("%s.%s", issuerId, objectSuffix), patchBody) + .execute(); + + System.out.println("Object expiration response"); + System.out.println(response.toPrettyString()); + + return response.getId(); + } + // [END expireObject] + + // [START jwtNew] + /** + * Generate a signed JWT that creates a new pass class and object. + * + *

When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the + * pass class and object defined in the JWT are created. This allows you to create multiple pass + * classes and objects in one API call when the user saves the pass to their wallet. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @param objectSuffix Developer-defined unique ID for the pass object. + * @return An "Add to Google Wallet" link. + */ + public String CreateJWTNewObjects(String issuerId, String classSuffix, String objectSuffix) { + // See link below for more information on required properties + // https://developers.google.com/wallet/generic/rest/v1/genericclass + GenericClass newClass = new GenericClass().setId(String.format("%s.%s", issuerId, classSuffix)); + + // See link below for more information on required properties + // https://developers.google.com/wallet/generic/rest/v1/genericobject + GenericObject newObject = + new GenericObject() + .setId(String.format("%s.%s", issuerId, objectSuffix)) + .setClassId(String.format("%s.%s", issuerId, classSuffix)) + .setState("ACTIVE") + .setHeroImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Hero image description")))) + .setTextModulesData( + Arrays.asList( + new TextModuleData() + .setHeader("Text module header") + .setBody("Text module body") + .setId("TEXT_MODULE_ID"))) + .setLinksModuleData( + new LinksModuleData() + .setUris( + Arrays.asList( + new Uri() + .setUri("http://maps.google.com/") + .setDescription("Link module URI description") + .setId("LINK_MODULE_URI_ID"), + new Uri() + .setUri("tel:6505555555") + .setDescription("Link module tel description") + .setId("LINK_MODULE_TEL_ID")))) + .setImageModulesData( + Arrays.asList( + new ImageModuleData() + .setMainImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Image module description")))) + .setId("IMAGE_MODULE_ID"))) + .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) + .setCardTitle( + new LocalizedString() + .setDefaultValue( + new TranslatedString().setLanguage("en-US").setValue("Generic card title"))) + .setHeader( + new LocalizedString() + .setDefaultValue( + new TranslatedString().setLanguage("en-US").setValue("Generic header"))) + .setHexBackgroundColor("#4285f4") + .setLogo( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Generic card logo")))); + + // Create the JWT as a HashMap object + HashMap claims = new HashMap(); + claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail()); + claims.put("aud", "google"); + claims.put("origins", Arrays.asList("www.example.com")); + claims.put("typ", "savetowallet"); + + // Create the Google Wallet payload and add to the JWT + HashMap payload = new HashMap(); + payload.put("genericClasses", Arrays.asList(newClass)); + payload.put("genericObjects", Arrays.asList(newObject)); + claims.put("payload", payload); + + // The service account credentials are used to sign the JWT + Algorithm algorithm = + Algorithm.RSA256( + null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); + String token = JWT.create().withPayload(claims).sign(algorithm); + + System.out.println("Add to Google Wallet link"); + System.out.println(String.format("https://pay.google.com/gp/v/save/%s", token)); + + return String.format("https://pay.google.com/gp/v/save/%s", token); + } + // [END jwtNew] + + // [START jwtExisting] + /** + * Generate a signed JWT that references an existing pass object. + * + *

When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the + * pass objects defined in the JWT are added to the user's Google Wallet app. This allows the user + * to save multiple pass objects in one API call. + * + *

The objects to add must follow the below format: + * + *

{ 'id': 'ISSUER_ID.OBJECT_SUFFIX', 'classId': 'ISSUER_ID.CLASS_SUFFIX' } + * + * @param issuerId The issuer ID being used for this request. + * @return An "Add to Google Wallet" link. + */ + public String CreateJWTExistingObjects(String issuerId) { + // Multiple pass types can be added at the same time + // At least one type must be specified in the JWT claims + // Note: Make sure to replace the placeholder class and object suffixes + HashMap objectsToAdd = new HashMap(); + + // Event tickets + objectsToAdd.put( + "eventTicketObjects", + Arrays.asList( + new EventTicketObject() + .setId(String.format("%s.%s", issuerId, "EVENT_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "EVENT_CLASS_SUFFIX")))); + + // Boarding passes + objectsToAdd.put( + "flightObjects", + Arrays.asList( + new FlightObject() + .setId(String.format("%s.%s", issuerId, "FLIGHT_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "FLIGHT_CLASS_SUFFIX")))); + + // Generic passes + objectsToAdd.put( + "genericObjects", + Arrays.asList( + new GenericObject() + .setId(String.format("%s.%s", issuerId, "GENERIC_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "GENERIC_CLASS_SUFFIX")))); + + // Gift cards + objectsToAdd.put( + "giftCardObjects", + Arrays.asList( + new GiftCardObject() + .setId(String.format("%s.%s", issuerId, "GIFT_CARD_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "GIFT_CARD_CLASS_SUFFIX")))); + + // Loyalty cards + objectsToAdd.put( + "loyaltyObjects", + Arrays.asList( + new LoyaltyObject() + .setId(String.format("%s.%s", issuerId, "LOYALTY_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "LOYALTY_CLASS_SUFFIX")))); + + // Offers + objectsToAdd.put( + "offerObjects", + Arrays.asList( + new OfferObject() + .setId(String.format("%s.%s", issuerId, "OFFER_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "OFFER_CLASS_SUFFIX")))); + + // Transit passes + objectsToAdd.put( + "transitObjects", + Arrays.asList( + new TransitObject() + .setId(String.format("%s.%s", issuerId, "TRANSIT_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "TRANSIT_CLASS_SUFFIX")))); + + // Create the JWT as a HashMap object + HashMap claims = new HashMap(); + claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail()); + claims.put("aud", "google"); + claims.put("origins", Arrays.asList("www.example.com")); + claims.put("typ", "savetowallet"); + claims.put("payload", objectsToAdd); + + // The service account credentials are used to sign the JWT + Algorithm algorithm = + Algorithm.RSA256( + null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); + String token = JWT.create().withPayload(claims).sign(algorithm); + + System.out.println("Add to Google Wallet link"); + System.out.println(String.format("https://pay.google.com/gp/v/save/%s", token)); + + return String.format("https://pay.google.com/gp/v/save/%s", token); + } + // [END jwtExisting] + + // [START batch] + /** + * Batch create Google Wallet objects from an existing class. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @throws IOException + */ + public void BatchCreateObjects(String issuerId, String classSuffix) throws IOException { + // Create the batch request client + BatchRequest batch = service.batch(new HttpCredentialsAdapter(credentials)); + + // The callback will be invoked for each request in the batch + JsonBatchCallback callback = + new JsonBatchCallback() { + // Invoked if the request was successful + public void onSuccess(GenericObject response, HttpHeaders responseHeaders) { + System.out.println("Batch insert response"); + System.out.println(response.toString()); + } + + // Invoked if the request failed + public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) { + System.out.println("Error Message: " + e.getMessage()); + } + }; + + // Example: Generate three new pass objects + for (int i = 0; i < 3; i++) { + // Generate a random object suffix + String objectSuffix = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_"); + + // See link below for more information on required properties + // https://developers.google.com/wallet/generic/rest/v1/genericobject + GenericObject batchObject = + new GenericObject() + .setId(String.format("%s.%s", issuerId, objectSuffix)) + .setClassId(String.format("%s.%s", issuerId, classSuffix)) + .setState("ACTIVE") + .setHeroImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Hero image description")))) + .setTextModulesData( + Arrays.asList( + new TextModuleData() + .setHeader("Text module header") + .setBody("Text module body") + .setId("TEXT_MODULE_ID"))) + .setLinksModuleData( + new LinksModuleData() + .setUris( + Arrays.asList( + new Uri() + .setUri("http://maps.google.com/") + .setDescription("Link module URI description") + .setId("LINK_MODULE_URI_ID"), + new Uri() + .setUri("tel:6505555555") + .setDescription("Link module tel description") + .setId("LINK_MODULE_TEL_ID")))) + .setImageModulesData( + Arrays.asList( + new ImageModuleData() + .setMainImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Image module description")))) + .setId("IMAGE_MODULE_ID"))) + .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) + .setCardTitle( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Generic card title"))) + .setHeader( + new LocalizedString() + .setDefaultValue( + new TranslatedString().setLanguage("en-US").setValue("Generic header"))) + .setHexBackgroundColor("#4285f4") + .setLogo( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Generic card logo")))); + + service.genericobject().insert(batchObject).queue(batch, callback); + } + + // Invoke the batch API calls + batch.execute(); + } + // [END batch] } diff --git a/java/src/main/java/DemoGiftCard.java b/java/src/main/java/DemoGiftCard.java index c7dd869..38d61ba 100644 --- a/java/src/main/java/DemoGiftCard.java +++ b/java/src/main/java/DemoGiftCard.java @@ -14,7 +14,8 @@ * limitations under the License. */ - +// [START setup] +// [START imports] import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.google.api.client.googleapis.batch.BatchRequest; @@ -22,854 +23,870 @@ import com.google.api.client.googleapis.batch.json.JsonBatchCallback; import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; import com.google.api.client.googleapis.json.GoogleJsonError; import com.google.api.client.googleapis.json.GoogleJsonResponseException; -import com.google.api.client.http.HttpHeaders; -import com.google.api.client.http.HttpTransport; +import com.google.api.client.http.*; import com.google.api.client.json.gson.GsonFactory; import com.google.api.services.walletobjects.Walletobjects; import com.google.api.services.walletobjects.model.*; import com.google.auth.http.HttpCredentialsAdapter; import com.google.auth.oauth2.GoogleCredentials; import com.google.auth.oauth2.ServiceAccountCredentials; - -import java.io.FileInputStream; -import java.io.IOException; +import java.io.*; import java.security.interfaces.RSAPrivateKey; import java.util.*; +// [END imports] - -/** - * Demo class for creating and managing Gift cards in Google Wallet. - */ +/** Demo class for creating and managing Gift cards in Google Wallet. */ public class DemoGiftCard { - /** - * Path to service account key file from Google Cloud Console. Environment variable: - * GOOGLE_APPLICATION_CREDENTIALS. - */ - public static String keyFilePath; + /** + * Path to service account key file from Google Cloud Console. Environment variable: + * GOOGLE_APPLICATION_CREDENTIALS. + */ + public static String keyFilePath; - /** - * Service account credentials for Google Wallet APIs. - */ - public static GoogleCredentials credentials; + /** Service account credentials for Google Wallet APIs. */ + public static GoogleCredentials credentials; - /** - * Google Wallet service client. - */ - public static Walletobjects service; + /** Google Wallet service client. */ + public static Walletobjects service; - public DemoGiftCard() throws Exception { - keyFilePath = - System.getenv().getOrDefault("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/key.json"); + public DemoGiftCard() throws Exception { + keyFilePath = + System.getenv().getOrDefault("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/key.json"); - auth(); - } + Auth(); + } + // [END setup] + // [START auth] + /** + * Create authenticated HTTP client using a service account file. + * + * @throws Exception + */ + public void Auth() throws Exception { + String scope = "https://www.googleapis.com/auth/wallet_object.issuer"; - /** - * Create authenticated HTTP client using a service account file. - */ - public void auth() throws Exception { - String scope = "https://www.googleapis.com/auth/wallet_object.issuer"; + credentials = + GoogleCredentials.fromStream(new FileInputStream(keyFilePath)) + .createScoped(Arrays.asList(scope)); + credentials.refresh(); - credentials = - GoogleCredentials.fromStream(new FileInputStream(keyFilePath)) - .createScoped(List.of(scope)); - credentials.refresh(); + HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport(); - HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport(); + // Initialize Google Wallet API service + service = + new Walletobjects.Builder( + httpTransport, + GsonFactory.getDefaultInstance(), + new HttpCredentialsAdapter(credentials)) + .setApplicationName("APPLICATION_NAME") + .build(); + } + // [END auth] - // Initialize Google Wallet API service - service = - new Walletobjects.Builder( - httpTransport, - GsonFactory.getDefaultInstance(), - new HttpCredentialsAdapter(credentials)) - .setApplicationName("APPLICATION_NAME") - .build(); - } - - - /** - * Create a class. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @return The pass class ID: "{issuerId}.{classSuffix}" - */ - public String createClass(String issuerId, String classSuffix) throws IOException { - // Check if the class exists - try { - service.giftcardclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); - - System.out.printf("Class %s.%s already exists!%n", issuerId, classSuffix); - return String.format("%s.%s", issuerId, classSuffix); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() != 404) { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, classSuffix); - } - } - - // See link below for more information on required properties - // https://developers.google.com/wallet/retail/gift-cards/rest/v1/giftcardclass - GiftCardClass newClass = - new GiftCardClass() - .setId(String.format("%s.%s", issuerId, classSuffix)) - .setIssuerName("Issuer name") - .setReviewStatus("UNDER_REVIEW"); - - GiftCardClass response = service.giftcardclass().insert(newClass).execute(); - - System.out.println("Class insert response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - - /** - * Update a class. - * - *

Warning: This replaces all existing class attributes! - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @return The pass class ID: "{issuerId}.{classSuffix}" - */ - public String updateClass(String issuerId, String classSuffix) throws IOException { - GiftCardClass updatedClass; - - // Check if the class exists - try { - updatedClass = - service.giftcardclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Class does not exist - System.out.printf("Class %s.%s not found!%n", issuerId, classSuffix); - return String.format("%s.%s", issuerId, classSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, classSuffix); - } - } - - // Class exists - // Update the class by adding a homepage - updatedClass.setHomepageUri( - new Uri() - .setUri("https://developers.google.com/wallet") - .setDescription("Homepage description")); - - // Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates - updatedClass.setReviewStatus("UNDER_REVIEW"); - - GiftCardClass response = - service - .giftcardclass() - .update(String.format("%s.%s", issuerId, classSuffix), updatedClass) - .execute(); - - System.out.println("Class update response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - - /** - * Patch a class. - * - *

The PATCH method supports patch semantics. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @return The pass class ID: "{issuerId}.{classSuffix}" - */ - public String patchClass(String issuerId, String classSuffix) throws IOException { - // Check if the class exists - try { - service.giftcardclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Class does not exist - System.out.printf("Class %s.%s not found!%n", issuerId, classSuffix); - return String.format("%s.%s", issuerId, classSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, classSuffix); - } - } - - // Class exists - // Patch the class by adding a homepage - GiftCardClass patchBody = - new GiftCardClass() - .setHomepageUri( - new Uri() - .setUri("https://developers.google.com/wallet") - .setDescription("Homepage description")) - - // Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates - .setReviewStatus("UNDER_REVIEW"); - - GiftCardClass response = - service - .giftcardclass() - .patch(String.format("%s.%s", issuerId, classSuffix), patchBody) - .execute(); - - System.out.println("Class patch response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - - /** - * Add a message to a pass class. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @param header The message header. - * @param body The message body. - * @return The pass class ID: "{issuerId}.{classSuffix}" - */ - public String addClassMessage(String issuerId, String classSuffix, String header, String body) - throws IOException { - // Check if the class exists - try { - service.giftcardclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Class does not exist - System.out.printf("Class %s.%s not found!%n", issuerId, classSuffix); - return String.format("%s.%s", issuerId, classSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, classSuffix); - } - } - - AddMessageRequest message = - new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body)); - - GiftCardClassAddMessageResponse response = - service - .giftcardclass() - .addmessage(String.format("%s.%s", issuerId, classSuffix), message) - .execute(); - - System.out.println("Class addMessage response"); - System.out.println(response.toPrettyString()); + // [START createClass] + /** + * Create a class. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @return The pass class ID: "{issuerId}.{classSuffix}" + * @throws IOException + */ + public String CreateClass(String issuerId, String classSuffix) throws IOException { + // Check if the class exists + try { + service.giftcardclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); + System.out.println(String.format("Class %s.%s already exists!", issuerId, classSuffix)); + return String.format("%s.%s", issuerId, classSuffix); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() != 404) { + // Something else went wrong... + ex.printStackTrace(); return String.format("%s.%s", issuerId, classSuffix); + } } + // See link below for more information on required properties + // https://developers.google.com/wallet/retail/gift-cards/rest/v1/giftcardclass + GiftCardClass newClass = + new GiftCardClass() + .setId(String.format("%s.%s", issuerId, classSuffix)) + .setIssuerName("Issuer name") + .setReviewStatus("UNDER_REVIEW"); - /** - * Create an object. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String createObject(String issuerId, String classSuffix, String objectSuffix) - throws IOException { - // Check if the object exists - try { - service.giftcardobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + GiftCardClass response = service.giftcardclass().insert(newClass).execute(); - System.out.printf("Object %s.%s already exists!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() != 404) { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } + System.out.println("Class insert response"); + System.out.println(response.toPrettyString()); - // See link below for more information on required properties - // https://developers.google.com/wallet/retail/gift-cards/rest/v1/giftcardobject - GiftCardObject newObject = - new GiftCardObject() - .setId(String.format("%s.%s", issuerId, objectSuffix)) - .setClassId(String.format("%s.%s", issuerId, classSuffix)) - .setState("ACTIVE") - .setHeroImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Hero image description")))) - .setTextModulesData( - List.of( - new TextModuleData() - .setHeader("Text module header") - .setBody("Text module body") - .setId("TEXT_MODULE_ID"))) - .setLinksModuleData( - new LinksModuleData() - .setUris( - Arrays.asList( - new Uri() - .setUri("http://maps.google.com/") - .setDescription("Link module URI description") - .setId("LINK_MODULE_URI_ID"), - new Uri() - .setUri("tel:6505555555") - .setDescription("Link module tel description") - .setId("LINK_MODULE_TEL_ID")))) - .setImageModulesData( - List.of( - new ImageModuleData() - .setMainImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Image module description")))) - .setId("IMAGE_MODULE_ID"))) - .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) - .setLocations( - List.of( - new LatLongPoint() - .setLatitude(37.424015499999996) - .setLongitude(-122.09259560000001))) - .setCardNumber("Card number") - .setPin("1234") - .setBalance(new Money().setMicros(20000000L).setCurrencyCode("USD")) - .setBalanceUpdateTime(new DateTime().setDate("2020-04-12T16:20:50.52-04:00")); + return response.getId(); + } + // [END createClass] - GiftCardObject response = service.giftcardobject().insert(newObject).execute(); + // [START updateClass] + /** + * Update a class. + * + *

Warning: This replaces all existing class attributes! + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @return The pass class ID: "{issuerId}.{classSuffix}" + * @throws IOException + */ + public String UpdateClass(String issuerId, String classSuffix) throws IOException { + GiftCardClass updatedClass; - System.out.println("Object insert response"); - System.out.println(response.toPrettyString()); - - return response.getId(); + // Check if the class exists + try { + updatedClass = + service.giftcardclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Class does not exist + System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix)); + return String.format("%s.%s", issuerId, classSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, classSuffix); + } } + // Class exists + // Update the class by adding a homepage + updatedClass.setHomepageUri( + new Uri() + .setUri("https://developers.google.com/wallet") + .setDescription("Homepage description")); - /** - * Update an object. - * - *

Warning: This replaces all existing object attributes! - * - * @param issuerId The issuer ID being used for this request. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String updateObject(String issuerId, String objectSuffix) throws IOException { - GiftCardObject updatedObject; + // Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates + updatedClass.setReviewStatus("UNDER_REVIEW"); - // Check if the object exists - try { - updatedObject = - service.giftcardobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Object does not exist - System.out.printf("Object %s.%s not found!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } + GiftCardClass response = + service + .giftcardclass() + .update(String.format("%s.%s", issuerId, classSuffix), updatedClass) + .execute(); - // Object exists - // Update the object by adding a link - Uri newLink = + System.out.println("Class update response"); + System.out.println(response.toPrettyString()); + + return response.getId(); + } + // [END updateClass] + + // [START patchClass] + /** + * Patch a class. + * + *

The PATCH method supports patch semantics. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @return The pass class ID: "{issuerId}.{classSuffix}" + * @throws IOException + */ + public String PatchClass(String issuerId, String classSuffix) throws IOException { + // Check if the class exists + try { + service.giftcardclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Class does not exist + System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix)); + return String.format("%s.%s", issuerId, classSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, classSuffix); + } + } + + // Class exists + // Patch the class by adding a homepage + GiftCardClass patchBody = + new GiftCardClass() + .setHomepageUri( new Uri() - .setUri("https://developers.google.com/wallet") - .setDescription("New link description"); + .setUri("https://developers.google.com/wallet") + .setDescription("Homepage description")) - if (updatedObject.getLinksModuleData() == null) { - // LinksModuleData was not set on the original object - updatedObject.setLinksModuleData(new LinksModuleData().setUris(List.of(newLink))); - } else { - updatedObject.getLinksModuleData().getUris().add(newLink); - } + // Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates + .setReviewStatus("UNDER_REVIEW"); - GiftCardObject response = - service - .giftcardobject() - .update(String.format("%s.%s", issuerId, objectSuffix), updatedObject) - .execute(); + GiftCardClass response = + service + .giftcardclass() + .patch(String.format("%s.%s", issuerId, classSuffix), patchBody) + .execute(); - System.out.println("Object update response"); - System.out.println(response.toPrettyString()); + System.out.println("Class patch response"); + System.out.println(response.toPrettyString()); - return response.getId(); + return response.getId(); + } + // [END patchClass] + + // [START addMessageClass] + /** + * Add a message to a pass class. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @param header The message header. + * @param body The message body. + * @return The pass class ID: "{issuerId}.{classSuffix}" + * @throws IOException + */ + public String AddClassMessage(String issuerId, String classSuffix, String header, String body) + throws IOException { + // Check if the class exists + try { + service.giftcardclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Class does not exist + System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix)); + return String.format("%s.%s", issuerId, classSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, classSuffix); + } } + AddMessageRequest message = + new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body)); - /** - * Patch an object. - * - * @param issuerId The issuer ID being used for this request. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String patchObject(String issuerId, String objectSuffix) throws IOException { - GiftCardObject existingObject; + GiftCardClassAddMessageResponse response = + service + .giftcardclass() + .addmessage(String.format("%s.%s", issuerId, classSuffix), message) + .execute(); - // Check if the object exists - try { - existingObject = - service.giftcardobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Object does not exist - System.out.printf("Object %s.%s not found!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } + System.out.println("Class addMessage response"); + System.out.println(response.toPrettyString()); - // Object exists - // Patch the object by adding a link - Uri newLink = - new Uri() - .setUri("https://developers.google.com/wallet") - .setDescription("New link description"); + return String.format("%s.%s", issuerId, classSuffix); + } + // [END addMessageClass] - GiftCardObject patchBody = new GiftCardObject(); - - if (existingObject.getLinksModuleData() == null) { - // LinksModuleData was not set on the original object - patchBody.setLinksModuleData(new LinksModuleData().setUris(new ArrayList())); - } else { - patchBody.setLinksModuleData(existingObject.getLinksModuleData()); - } - patchBody.getLinksModuleData().getUris().add(newLink); - - GiftCardObject response = - service - .giftcardobject() - .patch(String.format("%s.%s", issuerId, objectSuffix), patchBody) - .execute(); - - System.out.println("Object patch response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - - /** - * Expire an object. - * - *

Sets the object's state to Expired. If the valid time interval is already set, the pass will - * expire automatically up to 24 hours after. - * - * @param issuerId The issuer ID being used for this request. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String expireObject(String issuerId, String objectSuffix) throws IOException { - // Check if the object exists - try { - service.giftcardobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Object does not exist - System.out.printf("Object %s.%s not found!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } - - // Patch the object, setting the pass as expired - GiftCardObject patchBody = new GiftCardObject().setState("EXPIRED"); - - GiftCardObject response = - service - .giftcardobject() - .patch(String.format("%s.%s", issuerId, objectSuffix), patchBody) - .execute(); - - System.out.println("Object expiration response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - - /** - * Add a message to a pass object. - * - * @param issuerId The issuer ID being used for this request. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @param header The message header. - * @param body The message body. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String addObjectMessage(String issuerId, String objectSuffix, String header, String body) - throws IOException { - // Check if the object exists - try { - service.giftcardobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Object does not exist - System.out.printf("Object %s.%s not found!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } - - AddMessageRequest message = - new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body)); - - GiftCardObjectAddMessageResponse response = - service - .giftcardobject() - .addmessage(String.format("%s.%s", issuerId, objectSuffix), message) - .execute(); - - System.out.println("Object addMessage response"); - System.out.println(response.toPrettyString()); + // [START createObject] + /** + * Create an object. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String CreateObject(String issuerId, String classSuffix, String objectSuffix) + throws IOException { + // Check if the object exists + try { + service.giftcardobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + System.out.println(String.format("Object %s.%s already exists!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() != 404) { + // Something else went wrong... + ex.printStackTrace(); return String.format("%s.%s", issuerId, objectSuffix); + } } + // See link below for more information on required properties + // https://developers.google.com/wallet/retail/gift-cards/rest/v1/giftcardobject + GiftCardObject newObject = + new GiftCardObject() + .setId(String.format("%s.%s", issuerId, objectSuffix)) + .setClassId(String.format("%s.%s", issuerId, classSuffix)) + .setState("ACTIVE") + .setHeroImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Hero image description")))) + .setTextModulesData( + Arrays.asList( + new TextModuleData() + .setHeader("Text module header") + .setBody("Text module body") + .setId("TEXT_MODULE_ID"))) + .setLinksModuleData( + new LinksModuleData() + .setUris( + Arrays.asList( + new Uri() + .setUri("http://maps.google.com/") + .setDescription("Link module URI description") + .setId("LINK_MODULE_URI_ID"), + new Uri() + .setUri("tel:6505555555") + .setDescription("Link module tel description") + .setId("LINK_MODULE_TEL_ID")))) + .setImageModulesData( + Arrays.asList( + new ImageModuleData() + .setMainImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Image module description")))) + .setId("IMAGE_MODULE_ID"))) + .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) + .setLocations( + Arrays.asList( + new LatLongPoint() + .setLatitude(37.424015499999996) + .setLongitude(-122.09259560000001))) + .setCardNumber("Card number") + .setPin("1234") + .setBalance(new Money().setMicros(20000000L).setCurrencyCode("USD")) + .setBalanceUpdateTime(new DateTime().setDate("2020-04-12T16:20:50.52-04:00")); - /** - * Generate a signed JWT that creates a new pass class and object. - * - *

When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the - * pass class and object defined in the JWT are created. This allows you to create multiple pass - * classes and objects in one API call when the user saves the pass to their wallet. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @param objectSuffix Developer-defined unique ID for the pass object. - * @return An "Add to Google Wallet" link. - */ - public String createJWTNewObjects(String issuerId, String classSuffix, String objectSuffix) { - // See link below for more information on required properties - // https://developers.google.com/wallet/retail/gift-cards/rest/v1/giftcardclass - GiftCardClass newClass = - new GiftCardClass() - .setId(String.format("%s.%s", issuerId, classSuffix)) - .setIssuerName("Issuer name") - .setReviewStatus("UNDER_REVIEW"); + GiftCardObject response = service.giftcardobject().insert(newObject).execute(); - // See link below for more information on required properties - // https://developers.google.com/wallet/retail/gift-cards/rest/v1/giftcardobject - GiftCardObject newObject = - new GiftCardObject() - .setId(String.format("%s.%s", issuerId, objectSuffix)) - .setClassId(String.format("%s.%s", issuerId, classSuffix)) - .setState("ACTIVE") - .setHeroImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Hero image description")))) - .setTextModulesData( - List.of( - new TextModuleData() - .setHeader("Text module header") - .setBody("Text module body") - .setId("TEXT_MODULE_ID"))) - .setLinksModuleData( - new LinksModuleData() - .setUris( - Arrays.asList( - new Uri() - .setUri("http://maps.google.com/") - .setDescription("Link module URI description") - .setId("LINK_MODULE_URI_ID"), - new Uri() - .setUri("tel:6505555555") - .setDescription("Link module tel description") - .setId("LINK_MODULE_TEL_ID")))) - .setImageModulesData( - List.of( - new ImageModuleData() - .setMainImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Image module description")))) - .setId("IMAGE_MODULE_ID"))) - .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) - .setLocations( - List.of( - new LatLongPoint() - .setLatitude(37.424015499999996) - .setLongitude(-122.09259560000001))) - .setCardNumber("Card number") - .setPin("1234") - .setBalance(new Money().setMicros(20000000L).setCurrencyCode("USD")) - .setBalanceUpdateTime(new DateTime().setDate("2020-04-12T16:20:50.52-04:00")); + System.out.println("Object insert response"); + System.out.println(response.toPrettyString()); - // Create the JWT as a HashMap object - HashMap claims = new HashMap(); - claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail()); - claims.put("aud", "google"); - claims.put("origins", List.of("www.example.com")); - claims.put("typ", "savetowallet"); + return response.getId(); + } + // [END createObject] - // Create the Google Wallet payload and add to the JWT - HashMap payload = new HashMap(); - payload.put("giftCardClasses", List.of(newClass)); - payload.put("giftCardObjects", List.of(newObject)); - claims.put("payload", payload); + // [START updateObject] + /** + * Update an object. + * + *

Warning: This replaces all existing object attributes! + * + * @param issuerId The issuer ID being used for this request. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String UpdateObject(String issuerId, String objectSuffix) throws IOException { + GiftCardObject updatedObject; - // The service account credentials are used to sign the JWT - Algorithm algorithm = - Algorithm.RSA256( - null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); - String token = JWT.create().withPayload(claims).sign(algorithm); - - System.out.println("Add to Google Wallet link"); - System.out.printf("https://pay.google.com/gp/v/save/%s%n", token); - - return String.format("https://pay.google.com/gp/v/save/%s", token); + // Check if the object exists + try { + updatedObject = + service.giftcardobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Object does not exist + System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, objectSuffix); + } } + // Object exists + // Update the object by adding a link + Uri newLink = + new Uri() + .setUri("https://developers.google.com/wallet") + .setDescription("New link description"); - /** - * Generate a signed JWT that references an existing pass object. - * - *

When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the - * pass objects defined in the JWT are added to the user's Google Wallet app. This allows the user - * to save multiple pass objects in one API call. - * - *

The objects to add must follow the below format: - * - *

{ 'id': 'ISSUER_ID.OBJECT_SUFFIX', 'classId': 'ISSUER_ID.CLASS_SUFFIX' } - * - * @param issuerId The issuer ID being used for this request. - * @return An "Add to Google Wallet" link. - */ - public String createJWTExistingObjects(String issuerId) { - // Multiple pass types can be added at the same time - // At least one type must be specified in the JWT claims - // Note: Make sure to replace the placeholder class and object suffixes - HashMap objectsToAdd = new HashMap(); - - // Event tickets - objectsToAdd.put( - "eventTicketObjects", - List.of( - new EventTicketObject() - .setId(String.format("%s.%s", issuerId, "EVENT_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "EVENT_CLASS_SUFFIX")))); - - // Boarding passes - objectsToAdd.put( - "flightObjects", - List.of( - new FlightObject() - .setId(String.format("%s.%s", issuerId, "FLIGHT_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "FLIGHT_CLASS_SUFFIX")))); - - // Generic passes - objectsToAdd.put( - "genericObjects", - List.of( - new GenericObject() - .setId(String.format("%s.%s", issuerId, "GENERIC_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "GENERIC_CLASS_SUFFIX")))); - - // Gift cards - objectsToAdd.put( - "giftCardObjects", - List.of( - new GiftCardObject() - .setId(String.format("%s.%s", issuerId, "GIFT_CARD_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "GIFT_CARD_CLASS_SUFFIX")))); - - // Loyalty cards - objectsToAdd.put( - "loyaltyObjects", - List.of( - new LoyaltyObject() - .setId(String.format("%s.%s", issuerId, "LOYALTY_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "LOYALTY_CLASS_SUFFIX")))); - - // Offers - objectsToAdd.put( - "offerObjects", - List.of( - new OfferObject() - .setId(String.format("%s.%s", issuerId, "OFFER_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "OFFER_CLASS_SUFFIX")))); - - // Transit passes - objectsToAdd.put( - "transitObjects", - List.of( - new TransitObject() - .setId(String.format("%s.%s", issuerId, "TRANSIT_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "TRANSIT_CLASS_SUFFIX")))); - - // Create the JWT as a HashMap object - HashMap claims = new HashMap(); - claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail()); - claims.put("aud", "google"); - claims.put("origins", List.of("www.example.com")); - claims.put("typ", "savetowallet"); - claims.put("payload", objectsToAdd); - - // The service account credentials are used to sign the JWT - Algorithm algorithm = - Algorithm.RSA256( - null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); - String token = JWT.create().withPayload(claims).sign(algorithm); - - System.out.println("Add to Google Wallet link"); - System.out.printf("https://pay.google.com/gp/v/save/%s%n", token); - - return String.format("https://pay.google.com/gp/v/save/%s", token); + if (updatedObject.getLinksModuleData() == null) { + // LinksModuleData was not set on the original object + updatedObject.setLinksModuleData(new LinksModuleData().setUris(Arrays.asList(newLink))); + } else { + updatedObject.getLinksModuleData().getUris().add(newLink); } + GiftCardObject response = + service + .giftcardobject() + .update(String.format("%s.%s", issuerId, objectSuffix), updatedObject) + .execute(); - /** - * Batch create Google Wallet objects from an existing class. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - */ - public void batchCreateObjects(String issuerId, String classSuffix) throws IOException { - // Create the batch request client - BatchRequest batch = service.batch(new HttpCredentialsAdapter(credentials)); + System.out.println("Object update response"); + System.out.println(response.toPrettyString()); - // The callback will be invoked for each request in the batch - JsonBatchCallback callback = - new JsonBatchCallback() { - // Invoked if the request was successful - public void onSuccess(GiftCardObject response, HttpHeaders responseHeaders) { - System.out.println("Batch insert response"); - System.out.println(response.toString()); - } + return response.getId(); + } + // [END updateObject] - // Invoked if the request failed - public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) { - System.out.println("Error Message: " + e.getMessage()); - } - }; + // [START patchObject] + /** + * Patch an object. + * + * @param issuerId The issuer ID being used for this request. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String PatchObject(String issuerId, String objectSuffix) throws IOException { + GiftCardObject existingObject; - // Example: Generate three new pass objects - for (int i = 0; i < 3; i++) { - // Generate a random object suffix - String objectSuffix = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_"); - - // See link below for more information on required properties - // https://developers.google.com/wallet/retail/gift-cards/rest/v1/giftcardobject - GiftCardObject batchObject = - new GiftCardObject() - .setId(String.format("%s.%s", issuerId, objectSuffix)) - .setClassId(String.format("%s.%s", issuerId, classSuffix)) - .setState("ACTIVE") - .setHeroImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Hero image description")))) - .setTextModulesData( - List.of( - new TextModuleData() - .setHeader("Text module header") - .setBody("Text module body") - .setId("TEXT_MODULE_ID"))) - .setLinksModuleData( - new LinksModuleData() - .setUris( - Arrays.asList( - new Uri() - .setUri("http://maps.google.com/") - .setDescription("Link module URI description") - .setId("LINK_MODULE_URI_ID"), - new Uri() - .setUri("tel:6505555555") - .setDescription("Link module tel description") - .setId("LINK_MODULE_TEL_ID")))) - .setImageModulesData( - List.of( - new ImageModuleData() - .setMainImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Image module description")))) - .setId("IMAGE_MODULE_ID"))) - .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) - .setLocations( - List.of( - new LatLongPoint() - .setLatitude(37.424015499999996) - .setLongitude(-122.09259560000001))) - .setCardNumber("Card number") - .setPin("1234") - .setBalance(new Money().setMicros(20000000L).setCurrencyCode("USD")) - .setBalanceUpdateTime(new DateTime().setDate("2020-04-12T16:20:50.52-04:00")); - - service.giftcardobject().insert(batchObject).queue(batch, callback); - } - - // Invoke the batch API calls - batch.execute(); + // Check if the object exists + try { + existingObject = + service.giftcardobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Object does not exist + System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, objectSuffix); + } } + // Object exists + // Patch the object by adding a link + Uri newLink = + new Uri() + .setUri("https://developers.google.com/wallet") + .setDescription("New link description"); + + GiftCardObject patchBody = new GiftCardObject(); + + if (existingObject.getLinksModuleData() == null) { + // LinksModuleData was not set on the original object + patchBody.setLinksModuleData(new LinksModuleData().setUris(new ArrayList())); + } else { + patchBody.setLinksModuleData(existingObject.getLinksModuleData()); + } + patchBody.getLinksModuleData().getUris().add(newLink); + + GiftCardObject response = + service + .giftcardobject() + .patch(String.format("%s.%s", issuerId, objectSuffix), patchBody) + .execute(); + + System.out.println("Object patch response"); + System.out.println(response.toPrettyString()); + + return response.getId(); + } + // [END patchObject] + + // [START expireObject] + /** + * Expire an object. + * + *

Sets the object's state to Expired. If the valid time interval is already set, the pass will + * expire automatically up to 24 hours after. + * + * @param issuerId The issuer ID being used for this request. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String ExpireObject(String issuerId, String objectSuffix) throws IOException { + // Check if the object exists + try { + service.giftcardobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Object does not exist + System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, objectSuffix); + } + } + + // Patch the object, setting the pass as expired + GiftCardObject patchBody = new GiftCardObject().setState("EXPIRED"); + + GiftCardObject response = + service + .giftcardobject() + .patch(String.format("%s.%s", issuerId, objectSuffix), patchBody) + .execute(); + + System.out.println("Object expiration response"); + System.out.println(response.toPrettyString()); + + return response.getId(); + } + // [END expireObject] + + // [START addMessageObject] + /** + * Add a message to a pass object. + * + * @param issuerId The issuer ID being used for this request. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @param header The message header. + * @param body The message body. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String AddObjectMessage(String issuerId, String objectSuffix, String header, String body) + throws IOException { + // Check if the object exists + try { + service.giftcardobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Object does not exist + System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, objectSuffix); + } + } + + AddMessageRequest message = + new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body)); + + GiftCardObjectAddMessageResponse response = + service + .giftcardobject() + .addmessage(String.format("%s.%s", issuerId, objectSuffix), message) + .execute(); + + System.out.println("Object addMessage response"); + System.out.println(response.toPrettyString()); + + return String.format("%s.%s", issuerId, objectSuffix); + } + // [END addMessageObject] + + // [START jwtNew] + /** + * Generate a signed JWT that creates a new pass class and object. + * + *

When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the + * pass class and object defined in the JWT are created. This allows you to create multiple pass + * classes and objects in one API call when the user saves the pass to their wallet. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @param objectSuffix Developer-defined unique ID for the pass object. + * @return An "Add to Google Wallet" link. + */ + public String CreateJWTNewObjects(String issuerId, String classSuffix, String objectSuffix) { + // See link below for more information on required properties + // https://developers.google.com/wallet/retail/gift-cards/rest/v1/giftcardclass + GiftCardClass newClass = + new GiftCardClass() + .setId(String.format("%s.%s", issuerId, classSuffix)) + .setIssuerName("Issuer name") + .setReviewStatus("UNDER_REVIEW"); + + // See link below for more information on required properties + // https://developers.google.com/wallet/retail/gift-cards/rest/v1/giftcardobject + GiftCardObject newObject = + new GiftCardObject() + .setId(String.format("%s.%s", issuerId, objectSuffix)) + .setClassId(String.format("%s.%s", issuerId, classSuffix)) + .setState("ACTIVE") + .setHeroImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Hero image description")))) + .setTextModulesData( + Arrays.asList( + new TextModuleData() + .setHeader("Text module header") + .setBody("Text module body") + .setId("TEXT_MODULE_ID"))) + .setLinksModuleData( + new LinksModuleData() + .setUris( + Arrays.asList( + new Uri() + .setUri("http://maps.google.com/") + .setDescription("Link module URI description") + .setId("LINK_MODULE_URI_ID"), + new Uri() + .setUri("tel:6505555555") + .setDescription("Link module tel description") + .setId("LINK_MODULE_TEL_ID")))) + .setImageModulesData( + Arrays.asList( + new ImageModuleData() + .setMainImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Image module description")))) + .setId("IMAGE_MODULE_ID"))) + .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) + .setLocations( + Arrays.asList( + new LatLongPoint() + .setLatitude(37.424015499999996) + .setLongitude(-122.09259560000001))) + .setCardNumber("Card number") + .setPin("1234") + .setBalance(new Money().setMicros(20000000L).setCurrencyCode("USD")) + .setBalanceUpdateTime(new DateTime().setDate("2020-04-12T16:20:50.52-04:00")); + + // Create the JWT as a HashMap object + HashMap claims = new HashMap(); + claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail()); + claims.put("aud", "google"); + claims.put("origins", Arrays.asList("www.example.com")); + claims.put("typ", "savetowallet"); + + // Create the Google Wallet payload and add to the JWT + HashMap payload = new HashMap(); + payload.put("giftCardClasses", Arrays.asList(newClass)); + payload.put("giftCardObjects", Arrays.asList(newObject)); + claims.put("payload", payload); + + // The service account credentials are used to sign the JWT + Algorithm algorithm = + Algorithm.RSA256( + null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); + String token = JWT.create().withPayload(claims).sign(algorithm); + + System.out.println("Add to Google Wallet link"); + System.out.println(String.format("https://pay.google.com/gp/v/save/%s", token)); + + return String.format("https://pay.google.com/gp/v/save/%s", token); + } + // [END jwtNew] + + // [START jwtExisting] + /** + * Generate a signed JWT that references an existing pass object. + * + *

When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the + * pass objects defined in the JWT are added to the user's Google Wallet app. This allows the user + * to save multiple pass objects in one API call. + * + *

The objects to add must follow the below format: + * + *

{ 'id': 'ISSUER_ID.OBJECT_SUFFIX', 'classId': 'ISSUER_ID.CLASS_SUFFIX' } + * + * @param issuerId The issuer ID being used for this request. + * @return An "Add to Google Wallet" link. + */ + public String CreateJWTExistingObjects(String issuerId) { + // Multiple pass types can be added at the same time + // At least one type must be specified in the JWT claims + // Note: Make sure to replace the placeholder class and object suffixes + HashMap objectsToAdd = new HashMap(); + + // Event tickets + objectsToAdd.put( + "eventTicketObjects", + Arrays.asList( + new EventTicketObject() + .setId(String.format("%s.%s", issuerId, "EVENT_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "EVENT_CLASS_SUFFIX")))); + + // Boarding passes + objectsToAdd.put( + "flightObjects", + Arrays.asList( + new FlightObject() + .setId(String.format("%s.%s", issuerId, "FLIGHT_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "FLIGHT_CLASS_SUFFIX")))); + + // Generic passes + objectsToAdd.put( + "genericObjects", + Arrays.asList( + new GenericObject() + .setId(String.format("%s.%s", issuerId, "GENERIC_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "GENERIC_CLASS_SUFFIX")))); + + // Gift cards + objectsToAdd.put( + "giftCardObjects", + Arrays.asList( + new GiftCardObject() + .setId(String.format("%s.%s", issuerId, "GIFT_CARD_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "GIFT_CARD_CLASS_SUFFIX")))); + + // Loyalty cards + objectsToAdd.put( + "loyaltyObjects", + Arrays.asList( + new LoyaltyObject() + .setId(String.format("%s.%s", issuerId, "LOYALTY_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "LOYALTY_CLASS_SUFFIX")))); + + // Offers + objectsToAdd.put( + "offerObjects", + Arrays.asList( + new OfferObject() + .setId(String.format("%s.%s", issuerId, "OFFER_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "OFFER_CLASS_SUFFIX")))); + + // Transit passes + objectsToAdd.put( + "transitObjects", + Arrays.asList( + new TransitObject() + .setId(String.format("%s.%s", issuerId, "TRANSIT_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "TRANSIT_CLASS_SUFFIX")))); + + // Create the JWT as a HashMap object + HashMap claims = new HashMap(); + claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail()); + claims.put("aud", "google"); + claims.put("origins", Arrays.asList("www.example.com")); + claims.put("typ", "savetowallet"); + claims.put("payload", objectsToAdd); + + // The service account credentials are used to sign the JWT + Algorithm algorithm = + Algorithm.RSA256( + null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); + String token = JWT.create().withPayload(claims).sign(algorithm); + + System.out.println("Add to Google Wallet link"); + System.out.println(String.format("https://pay.google.com/gp/v/save/%s", token)); + + return String.format("https://pay.google.com/gp/v/save/%s", token); + } + // [END jwtExisting] + + // [START batch] + /** + * Batch create Google Wallet objects from an existing class. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @throws IOException + */ + public void BatchCreateObjects(String issuerId, String classSuffix) throws IOException { + // Create the batch request client + BatchRequest batch = service.batch(new HttpCredentialsAdapter(credentials)); + + // The callback will be invoked for each request in the batch + JsonBatchCallback callback = + new JsonBatchCallback() { + // Invoked if the request was successful + public void onSuccess(GiftCardObject response, HttpHeaders responseHeaders) { + System.out.println("Batch insert response"); + System.out.println(response.toString()); + } + + // Invoked if the request failed + public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) { + System.out.println("Error Message: " + e.getMessage()); + } + }; + + // Example: Generate three new pass objects + for (int i = 0; i < 3; i++) { + // Generate a random object suffix + String objectSuffix = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_"); + + // See link below for more information on required properties + // https://developers.google.com/wallet/retail/gift-cards/rest/v1/giftcardobject + GiftCardObject batchObject = + new GiftCardObject() + .setId(String.format("%s.%s", issuerId, objectSuffix)) + .setClassId(String.format("%s.%s", issuerId, classSuffix)) + .setState("ACTIVE") + .setHeroImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Hero image description")))) + .setTextModulesData( + Arrays.asList( + new TextModuleData() + .setHeader("Text module header") + .setBody("Text module body") + .setId("TEXT_MODULE_ID"))) + .setLinksModuleData( + new LinksModuleData() + .setUris( + Arrays.asList( + new Uri() + .setUri("http://maps.google.com/") + .setDescription("Link module URI description") + .setId("LINK_MODULE_URI_ID"), + new Uri() + .setUri("tel:6505555555") + .setDescription("Link module tel description") + .setId("LINK_MODULE_TEL_ID")))) + .setImageModulesData( + Arrays.asList( + new ImageModuleData() + .setMainImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Image module description")))) + .setId("IMAGE_MODULE_ID"))) + .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) + .setLocations( + Arrays.asList( + new LatLongPoint() + .setLatitude(37.424015499999996) + .setLongitude(-122.09259560000001))) + .setCardNumber("Card number") + .setPin("1234") + .setBalance(new Money().setMicros(20000000L).setCurrencyCode("USD")) + .setBalanceUpdateTime(new DateTime().setDate("2020-04-12T16:20:50.52-04:00")); + + service.giftcardobject().insert(batchObject).queue(batch, callback); + } + + // Invoke the batch API calls + batch.execute(); + } + // [END batch] } diff --git a/java/src/main/java/DemoLoyalty.java b/java/src/main/java/DemoLoyalty.java index 8c914e3..2ef3b34 100644 --- a/java/src/main/java/DemoLoyalty.java +++ b/java/src/main/java/DemoLoyalty.java @@ -14,6 +14,8 @@ * limitations under the License. */ +// [START setup] +// [START imports] import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.google.api.client.googleapis.batch.BatchRequest; @@ -21,872 +23,902 @@ import com.google.api.client.googleapis.batch.json.JsonBatchCallback; import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; import com.google.api.client.googleapis.json.GoogleJsonError; import com.google.api.client.googleapis.json.GoogleJsonResponseException; -import com.google.api.client.http.HttpHeaders; -import com.google.api.client.http.HttpTransport; +import com.google.api.client.http.*; import com.google.api.client.json.gson.GsonFactory; import com.google.api.services.walletobjects.Walletobjects; import com.google.api.services.walletobjects.model.*; import com.google.auth.http.HttpCredentialsAdapter; import com.google.auth.oauth2.GoogleCredentials; import com.google.auth.oauth2.ServiceAccountCredentials; - -import java.io.FileInputStream; -import java.io.IOException; +import java.io.*; import java.security.interfaces.RSAPrivateKey; import java.util.*; +// [END imports] -/** - * Demo class for creating and managing Loyalty cards in Google Wallet. - */ +/** Demo class for creating and managing Loyalty cards in Google Wallet. */ public class DemoLoyalty { - /** - * Path to service account key file from Google Cloud Console. Environment variable: - * GOOGLE_APPLICATION_CREDENTIALS. - */ - public static String keyFilePath; + /** + * Path to service account key file from Google Cloud Console. Environment variable: + * GOOGLE_APPLICATION_CREDENTIALS. + */ + public static String keyFilePath; - /** - * Service account credentials for Google Wallet APIs. - */ - public static GoogleCredentials credentials; + /** Service account credentials for Google Wallet APIs. */ + public static GoogleCredentials credentials; - /** - * Google Wallet service client. - */ - public static Walletobjects service; + /** Google Wallet service client. */ + public static Walletobjects service; - public DemoLoyalty() throws Exception { - keyFilePath = - System.getenv().getOrDefault("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/key.json"); + public DemoLoyalty() throws Exception { + keyFilePath = + System.getenv().getOrDefault("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/key.json"); - auth(); - } + Auth(); + } + // [END setup] - /** - * Create authenticated HTTP client using a service account file. - */ - public void auth() throws Exception { - String scope = "https://www.googleapis.com/auth/wallet_object.issuer"; + // [START auth] + /** + * Create authenticated HTTP client using a service account file. + * + * @throws Exception + */ + public void Auth() throws Exception { + String scope = "https://www.googleapis.com/auth/wallet_object.issuer"; - credentials = - GoogleCredentials.fromStream(new FileInputStream(keyFilePath)) - .createScoped(List.of(scope)); - credentials.refresh(); + credentials = + GoogleCredentials.fromStream(new FileInputStream(keyFilePath)) + .createScoped(Arrays.asList(scope)); + credentials.refresh(); - HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport(); + HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport(); - // Initialize Google Wallet API service - service = - new Walletobjects.Builder( - httpTransport, - GsonFactory.getDefaultInstance(), - new HttpCredentialsAdapter(credentials)) - .setApplicationName("APPLICATION_NAME") - .build(); - } + // Initialize Google Wallet API service + service = + new Walletobjects.Builder( + httpTransport, + GsonFactory.getDefaultInstance(), + new HttpCredentialsAdapter(credentials)) + .setApplicationName("APPLICATION_NAME") + .build(); + } + // [END auth] - /** - * Create a class. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @return The pass class ID: "{issuerId}.{classSuffix}" - */ - public String createClass(String issuerId, String classSuffix) throws IOException { - // Check if the class exists - try { - service.loyaltyclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); - - System.out.printf("Class %s.%s already exists!%n", issuerId, classSuffix); - return String.format("%s.%s", issuerId, classSuffix); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() != 404) { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, classSuffix); - } - } - - // See link below for more information on required properties - // https://developers.google.com/wallet/retail/loyalty-cards/rest/v1/loyaltyclass - LoyaltyClass newClass = - new LoyaltyClass() - .setId(String.format("%s.%s", issuerId, classSuffix)) - .setIssuerName("Issuer name") - .setReviewStatus("UNDER_REVIEW") - .setProgramName("Program name") - .setProgramLogo( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Logo description")))); - - LoyaltyClass response = service.loyaltyclass().insert(newClass).execute(); - - System.out.println("Class insert response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Update a class. - * - *

Warning: This replaces all existing class attributes! - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @return The pass class ID: "{issuerId}.{classSuffix}" - */ - public String updateClass(String issuerId, String classSuffix) throws IOException { - LoyaltyClass updatedClass; - - // Check if the class exists - try { - updatedClass = - service.loyaltyclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Class does not exist - System.out.printf("Class %s.%s not found!%n", issuerId, classSuffix); - return String.format("%s.%s", issuerId, classSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, classSuffix); - } - } - - // Class exists - // Update the class by adding a homepage - updatedClass.setHomepageUri( - new Uri() - .setUri("https://developers.google.com/wallet") - .setDescription("Homepage description")); - - // Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates - updatedClass.setReviewStatus("UNDER_REVIEW"); - - LoyaltyClass response = - service - .loyaltyclass() - .update(String.format("%s.%s", issuerId, classSuffix), updatedClass) - .execute(); - - System.out.println("Class update response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Patch a class. - * - *

The PATCH method supports patch semantics. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @return The pass class ID: "{issuerId}.{classSuffix}" - */ - public String patchClass(String issuerId, String classSuffix) throws IOException { - // Check if the class exists - try { - service.loyaltyclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Class does not exist - System.out.printf("Class %s.%s not found!%n", issuerId, classSuffix); - return String.format("%s.%s", issuerId, classSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, classSuffix); - } - } - - // Class exists - // Patch the class by adding a homepage - LoyaltyClass patchBody = - new LoyaltyClass() - .setHomepageUri( - new Uri() - .setUri("https://developers.google.com/wallet") - .setDescription("Homepage description")) - - // Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates - .setReviewStatus("UNDER_REVIEW"); - - LoyaltyClass response = - service - .loyaltyclass() - .patch(String.format("%s.%s", issuerId, classSuffix), patchBody) - .execute(); - - System.out.println("Class patch response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Add a message to a pass class. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @param header The message header. - * @param body The message body. - * @return The pass class ID: "{issuerId}.{classSuffix}" - */ - public String addClassMessage(String issuerId, String classSuffix, String header, String body) - throws IOException { - // Check if the class exists - try { - service.loyaltyclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Class does not exist - System.out.printf("Class %s.%s not found!%n", issuerId, classSuffix); - return String.format("%s.%s", issuerId, classSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, classSuffix); - } - } - - AddMessageRequest message = - new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body)); - - LoyaltyClassAddMessageResponse response = - service - .loyaltyclass() - .addmessage(String.format("%s.%s", issuerId, classSuffix), message) - .execute(); - - System.out.println("Class addMessage response"); - System.out.println(response.toPrettyString()); + // [START createClass] + /** + * Create a class. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @return The pass class ID: "{issuerId}.{classSuffix}" + * @throws IOException + */ + public String CreateClass(String issuerId, String classSuffix) throws IOException { + // Check if the class exists + try { + service.loyaltyclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); + System.out.println(String.format("Class %s.%s already exists!", issuerId, classSuffix)); + return String.format("%s.%s", issuerId, classSuffix); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() != 404) { + // Something else went wrong... + ex.printStackTrace(); return String.format("%s.%s", issuerId, classSuffix); + } } - /** - * Create an object. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String createObject(String issuerId, String classSuffix, String objectSuffix) - throws IOException { - // Check if the object exists - try { - service.loyaltyobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + // See link below for more information on required properties + // https://developers.google.com/wallet/retail/loyalty-cards/rest/v1/loyaltyclass + LoyaltyClass newClass = + new LoyaltyClass() + .setId(String.format("%s.%s", issuerId, classSuffix)) + .setIssuerName("Issuer name") + .setReviewStatus("UNDER_REVIEW") + .setProgramName("Program name") + .setProgramLogo( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Logo description")))); - System.out.printf("Object %s.%s already exists!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() != 404) { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } + LoyaltyClass response = service.loyaltyclass().insert(newClass).execute(); - // See link below for more information on required properties - // https://developers.google.com/wallet/retail/loyalty-cards/rest/v1/loyaltyobject - LoyaltyObject newObject = - new LoyaltyObject() - .setId(String.format("%s.%s", issuerId, objectSuffix)) - .setClassId(String.format("%s.%s", issuerId, classSuffix)) - .setState("ACTIVE") - .setHeroImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Hero image description")))) - .setTextModulesData( - List.of( - new TextModuleData() - .setHeader("Text module header") - .setBody("Text module body") - .setId("TEXT_MODULE_ID"))) - .setLinksModuleData( - new LinksModuleData() - .setUris( - Arrays.asList( - new Uri() - .setUri("http://maps.google.com/") - .setDescription("Link module URI description") - .setId("LINK_MODULE_URI_ID"), - new Uri() - .setUri("tel:6505555555") - .setDescription("Link module tel description") - .setId("LINK_MODULE_TEL_ID")))) - .setImageModulesData( - List.of( - new ImageModuleData() - .setMainImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Image module description")))) - .setId("IMAGE_MODULE_ID"))) - .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) - .setLocations( - List.of( - new LatLongPoint() - .setLatitude(37.424015499999996) - .setLongitude(-122.09259560000001))) - .setAccountId("Account ID") - .setAccountName("Account name") - .setLoyaltyPoints( - new LoyaltyPoints() - .setLabel("Points") - .setBalance(new LoyaltyPointsBalance().setInt(800))); + System.out.println("Class insert response"); + System.out.println(response.toPrettyString()); - LoyaltyObject response = service.loyaltyobject().insert(newObject).execute(); + return response.getId(); + } + // [END createClass] - System.out.println("Object insert response"); - System.out.println(response.toPrettyString()); + // [START updateClass] + /** + * Update a class. + * + *

Warning: This replaces all existing class attributes! + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @return The pass class ID: "{issuerId}.{classSuffix}" + * @throws IOException + */ + public String UpdateClass(String issuerId, String classSuffix) throws IOException { + LoyaltyClass updatedClass; - return response.getId(); + // Check if the class exists + try { + updatedClass = + service.loyaltyclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Class does not exist + System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix)); + return String.format("%s.%s", issuerId, classSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, classSuffix); + } } - /** - * Update an object. - * - *

Warning: This replaces all existing object attributes! - * - * @param issuerId The issuer ID being used for this request. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String updateObject(String issuerId, String objectSuffix) throws IOException { - LoyaltyObject updatedObject; + // Class exists + // Update the class by adding a homepage + updatedClass.setHomepageUri( + new Uri() + .setUri("https://developers.google.com/wallet") + .setDescription("Homepage description")); - // Check if the object exists - try { - updatedObject = - service.loyaltyobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Object does not exist - System.out.printf("Object %s.%s not found!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } + // Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates + updatedClass.setReviewStatus("UNDER_REVIEW"); - // Object exists - // Update the object by adding a link - Uri newLink = + LoyaltyClass response = + service + .loyaltyclass() + .update(String.format("%s.%s", issuerId, classSuffix), updatedClass) + .execute(); + + System.out.println("Class update response"); + System.out.println(response.toPrettyString()); + + return response.getId(); + } + // [END updateClass] + + // [START patchClass] + /** + * Patch a class. + * + *

The PATCH method supports patch semantics. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @return The pass class ID: "{issuerId}.{classSuffix}" + * @throws IOException + */ + public String PatchClass(String issuerId, String classSuffix) throws IOException { + // Check if the class exists + try { + service.loyaltyclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Class does not exist + System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix)); + return String.format("%s.%s", issuerId, classSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, classSuffix); + } + } + + // Class exists + // Patch the class by adding a homepage + LoyaltyClass patchBody = + new LoyaltyClass() + .setHomepageUri( new Uri() - .setUri("https://developers.google.com/wallet") - .setDescription("New link description"); + .setUri("https://developers.google.com/wallet") + .setDescription("Homepage description")) - if (updatedObject.getLinksModuleData() == null) { - // LinksModuleData was not set on the original object - updatedObject.setLinksModuleData(new LinksModuleData().setUris(List.of(newLink))); - } else { - updatedObject.getLinksModuleData().getUris().add(newLink); - } + // Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates + .setReviewStatus("UNDER_REVIEW"); - LoyaltyObject response = - service - .loyaltyobject() - .update(String.format("%s.%s", issuerId, objectSuffix), updatedObject) - .execute(); + LoyaltyClass response = + service + .loyaltyclass() + .patch(String.format("%s.%s", issuerId, classSuffix), patchBody) + .execute(); - System.out.println("Object update response"); - System.out.println(response.toPrettyString()); + System.out.println("Class patch response"); + System.out.println(response.toPrettyString()); - return response.getId(); + return response.getId(); + } + // [END patchClass] + + // [START addMessageClass] + /** + * Add a message to a pass class. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @param header The message header. + * @param body The message body. + * @return The pass class ID: "{issuerId}.{classSuffix}" + * @throws IOException + */ + public String AddClassMessage(String issuerId, String classSuffix, String header, String body) + throws IOException { + // Check if the class exists + try { + service.loyaltyclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Class does not exist + System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix)); + return String.format("%s.%s", issuerId, classSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, classSuffix); + } } - /** - * Patch an object. - * - * @param issuerId The issuer ID being used for this request. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String patchObject(String issuerId, String objectSuffix) throws IOException { - LoyaltyObject existingObject; + AddMessageRequest message = + new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body)); - // Check if the object exists - try { - existingObject = - service.loyaltyobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Object does not exist - System.out.printf("Object %s.%s not found!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } + LoyaltyClassAddMessageResponse response = + service + .loyaltyclass() + .addmessage(String.format("%s.%s", issuerId, classSuffix), message) + .execute(); - // Object exists - // Patch the object by adding a link - Uri newLink = - new Uri() - .setUri("https://developers.google.com/wallet") - .setDescription("New link description"); + System.out.println("Class addMessage response"); + System.out.println(response.toPrettyString()); - LoyaltyObject patchBody = new LoyaltyObject(); + return String.format("%s.%s", issuerId, classSuffix); + } + // [END addMessageClass] - if (existingObject.getLinksModuleData() == null) { - // LinksModuleData was not set on the original object - patchBody.setLinksModuleData(new LinksModuleData().setUris(new ArrayList())); - } else { - patchBody.setLinksModuleData(existingObject.getLinksModuleData()); - } - patchBody.getLinksModuleData().getUris().add(newLink); - - LoyaltyObject response = - service - .loyaltyobject() - .patch(String.format("%s.%s", issuerId, objectSuffix), patchBody) - .execute(); - - System.out.println("Object patch response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Expire an object. - * - *

Sets the object's state to Expired. If the valid time interval is already set, the pass will - * expire automatically up to 24 hours after. - * - * @param issuerId The issuer ID being used for this request. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String expireObject(String issuerId, String objectSuffix) throws IOException { - // Check if the object exists - try { - service.loyaltyobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Object does not exist - System.out.printf("Object %s.%s not found!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } - - // Patch the object, setting the pass as expired - LoyaltyObject patchBody = new LoyaltyObject().setState("EXPIRED"); - - LoyaltyObject response = - service - .loyaltyobject() - .patch(String.format("%s.%s", issuerId, objectSuffix), patchBody) - .execute(); - - System.out.println("Object expiration response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Add a message to a pass object. - * - * @param issuerId The issuer ID being used for this request. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @param header The message header. - * @param body The message body. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String addObjectMessage(String issuerId, String objectSuffix, String header, String body) - throws IOException { - // Check if the object exists - try { - service.loyaltyobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Object does not exist - System.out.printf("Object %s.%s not found!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } - - AddMessageRequest message = - new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body)); - - LoyaltyObjectAddMessageResponse response = - service - .loyaltyobject() - .addmessage(String.format("%s.%s", issuerId, objectSuffix), message) - .execute(); - - System.out.println("Object addMessage response"); - System.out.println(response.toPrettyString()); + // [START createObject] + /** + * Create an object. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String CreateObject(String issuerId, String classSuffix, String objectSuffix) + throws IOException { + // Check if the object exists + try { + service.loyaltyobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + System.out.println(String.format("Object %s.%s already exists!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() != 404) { + // Something else went wrong... + ex.printStackTrace(); return String.format("%s.%s", issuerId, objectSuffix); + } } - /** - * Generate a signed JWT that creates a new pass class and object. - * - *

When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the - * pass class and object defined in the JWT are created. This allows you to create multiple pass - * classes and objects in one API call when the user saves the pass to their wallet. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @param objectSuffix Developer-defined unique ID for the pass object. - * @return An "Add to Google Wallet" link. - */ - public String createJWTNewObjects(String issuerId, String classSuffix, String objectSuffix) { - // See link below for more information on required properties - // https://developers.google.com/wallet/retail/loyalty-cards/rest/v1/loyaltyclass - LoyaltyClass newClass = - new LoyaltyClass() - .setId(String.format("%s.%s", issuerId, classSuffix)) - .setIssuerName("Issuer name") - .setReviewStatus("UNDER_REVIEW") - .setProgramName("Program name") - .setProgramLogo( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Logo description")))); + // See link below for more information on required properties + // https://developers.google.com/wallet/retail/loyalty-cards/rest/v1/loyaltyobject + LoyaltyObject newObject = + new LoyaltyObject() + .setId(String.format("%s.%s", issuerId, objectSuffix)) + .setClassId(String.format("%s.%s", issuerId, classSuffix)) + .setState("ACTIVE") + .setHeroImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Hero image description")))) + .setTextModulesData( + Arrays.asList( + new TextModuleData() + .setHeader("Text module header") + .setBody("Text module body") + .setId("TEXT_MODULE_ID"))) + .setLinksModuleData( + new LinksModuleData() + .setUris( + Arrays.asList( + new Uri() + .setUri("http://maps.google.com/") + .setDescription("Link module URI description") + .setId("LINK_MODULE_URI_ID"), + new Uri() + .setUri("tel:6505555555") + .setDescription("Link module tel description") + .setId("LINK_MODULE_TEL_ID")))) + .setImageModulesData( + Arrays.asList( + new ImageModuleData() + .setMainImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Image module description")))) + .setId("IMAGE_MODULE_ID"))) + .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) + .setLocations( + Arrays.asList( + new LatLongPoint() + .setLatitude(37.424015499999996) + .setLongitude(-122.09259560000001))) + .setAccountId("Account ID") + .setAccountName("Account name") + .setLoyaltyPoints( + new LoyaltyPoints() + .setLabel("Points") + .setBalance(new LoyaltyPointsBalance().setInt(800))); - // See link below for more information on required properties - // https://developers.google.com/wallet/retail/loyalty-cards/rest/v1/loyaltyobject - LoyaltyObject newObject = - new LoyaltyObject() - .setId(String.format("%s.%s", issuerId, objectSuffix)) - .setClassId(String.format("%s.%s", issuerId, classSuffix)) - .setState("ACTIVE") - .setHeroImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Hero image description")))) - .setTextModulesData( - List.of( - new TextModuleData() - .setHeader("Text module header") - .setBody("Text module body") - .setId("TEXT_MODULE_ID"))) - .setLinksModuleData( - new LinksModuleData() - .setUris( - Arrays.asList( - new Uri() - .setUri("http://maps.google.com/") - .setDescription("Link module URI description") - .setId("LINK_MODULE_URI_ID"), - new Uri() - .setUri("tel:6505555555") - .setDescription("Link module tel description") - .setId("LINK_MODULE_TEL_ID")))) - .setImageModulesData( - List.of( - new ImageModuleData() - .setMainImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Image module description")))) - .setId("IMAGE_MODULE_ID"))) - .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) - .setLocations( - List.of( - new LatLongPoint() - .setLatitude(37.424015499999996) - .setLongitude(-122.09259560000001))) - .setAccountId("Account ID") - .setAccountName("Account name") - .setLoyaltyPoints( - new LoyaltyPoints() - .setLabel("Points") - .setBalance(new LoyaltyPointsBalance().setInt(800))); + LoyaltyObject response = service.loyaltyobject().insert(newObject).execute(); - // Create the JWT as a HashMap object - HashMap claims = new HashMap(); - claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail()); - claims.put("aud", "google"); - claims.put("origins", List.of("www.example.com")); - claims.put("typ", "savetowallet"); + System.out.println("Object insert response"); + System.out.println(response.toPrettyString()); - // Create the Google Wallet payload and add to the JWT - HashMap payload = new HashMap(); - payload.put("loyaltyClasses", List.of(newClass)); - payload.put("loyaltyObjects", List.of(newObject)); - claims.put("payload", payload); + return response.getId(); + } + // [END createObject] - // The service account credentials are used to sign the JWT - Algorithm algorithm = - Algorithm.RSA256( - null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); - String token = JWT.create().withPayload(claims).sign(algorithm); + // [START updateObject] + /** + * Update an object. + * + *

Warning: This replaces all existing object attributes! + * + * @param issuerId The issuer ID being used for this request. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String UpdateObject(String issuerId, String objectSuffix) throws IOException { + LoyaltyObject updatedObject; - System.out.println("Add to Google Wallet link"); - System.out.printf("https://pay.google.com/gp/v/save/%s%n", token); - - return String.format("https://pay.google.com/gp/v/save/%s", token); + // Check if the object exists + try { + updatedObject = + service.loyaltyobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Object does not exist + System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, objectSuffix); + } } - /** - * Generate a signed JWT that references an existing pass object. - * - *

When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the - * pass objects defined in the JWT are added to the user's Google Wallet app. This allows the user - * to save multiple pass objects in one API call. - * - *

The objects to add must follow the below format: - * - *

{ 'id': 'ISSUER_ID.OBJECT_SUFFIX', 'classId': 'ISSUER_ID.CLASS_SUFFIX' } - * - * @param issuerId The issuer ID being used for this request. - * @return An "Add to Google Wallet" link. - */ - public String createJWTExistingObjects(String issuerId) { - // Multiple pass types can be added at the same time - // At least one type must be specified in the JWT claims - // Note: Make sure to replace the placeholder class and object suffixes - HashMap objectsToAdd = new HashMap(); + // Object exists + // Update the object by adding a link + Uri newLink = + new Uri() + .setUri("https://developers.google.com/wallet") + .setDescription("New link description"); - // Event tickets - objectsToAdd.put( - "eventTicketObjects", - List.of( - new EventTicketObject() - .setId(String.format("%s.%s", issuerId, "EVENT_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "EVENT_CLASS_SUFFIX")))); - - // Boarding passes - objectsToAdd.put( - "flightObjects", - List.of( - new FlightObject() - .setId(String.format("%s.%s", issuerId, "FLIGHT_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "FLIGHT_CLASS_SUFFIX")))); - - // Generic passes - objectsToAdd.put( - "genericObjects", - List.of( - new GenericObject() - .setId(String.format("%s.%s", issuerId, "GENERIC_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "GENERIC_CLASS_SUFFIX")))); - - // Gift cards - objectsToAdd.put( - "giftCardObjects", - List.of( - new GiftCardObject() - .setId(String.format("%s.%s", issuerId, "GIFT_CARD_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "GIFT_CARD_CLASS_SUFFIX")))); - - // Loyalty cards - objectsToAdd.put( - "loyaltyObjects", - List.of( - new LoyaltyObject() - .setId(String.format("%s.%s", issuerId, "LOYALTY_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "LOYALTY_CLASS_SUFFIX")))); - - // Offers - objectsToAdd.put( - "offerObjects", - List.of( - new OfferObject() - .setId(String.format("%s.%s", issuerId, "OFFER_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "OFFER_CLASS_SUFFIX")))); - - // Transit passes - objectsToAdd.put( - "transitObjects", - List.of( - new TransitObject() - .setId(String.format("%s.%s", issuerId, "TRANSIT_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "TRANSIT_CLASS_SUFFIX")))); - - // Create the JWT as a HashMap object - HashMap claims = new HashMap(); - claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail()); - claims.put("aud", "google"); - claims.put("origins", List.of("www.example.com")); - claims.put("typ", "savetowallet"); - claims.put("payload", objectsToAdd); - - // The service account credentials are used to sign the JWT - Algorithm algorithm = - Algorithm.RSA256( - null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); - String token = JWT.create().withPayload(claims).sign(algorithm); - - System.out.println("Add to Google Wallet link"); - System.out.printf("https://pay.google.com/gp/v/save/%s%n", token); - - return String.format("https://pay.google.com/gp/v/save/%s", token); + if (updatedObject.getLinksModuleData() == null) { + // LinksModuleData was not set on the original object + updatedObject.setLinksModuleData(new LinksModuleData().setUris(Arrays.asList(newLink))); + } else { + updatedObject.getLinksModuleData().getUris().add(newLink); } - /** - * Batch create Google Wallet objects from an existing class. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - */ - public void batchCreateObjects(String issuerId, String classSuffix) throws IOException { - // Create the batch request client - BatchRequest batch = service.batch(new HttpCredentialsAdapter(credentials)); + LoyaltyObject response = + service + .loyaltyobject() + .update(String.format("%s.%s", issuerId, objectSuffix), updatedObject) + .execute(); - // The callback will be invoked for each request in the batch - JsonBatchCallback callback = - new JsonBatchCallback() { - // Invoked if the request was successful - public void onSuccess(LoyaltyObject response, HttpHeaders responseHeaders) { - System.out.println("Batch insert response"); - System.out.println(response.toString()); - } + System.out.println("Object update response"); + System.out.println(response.toPrettyString()); - // Invoked if the request failed - public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) { - System.out.println("Error Message: " + e.getMessage()); - } - }; + return response.getId(); + } + // [END updateObject] - // Example: Generate three new pass objects - for (int i = 0; i < 3; i++) { - // Generate a random object suffix - String objectSuffix = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_"); + // [START patchObject] + /** + * Patch an object. + * + * @param issuerId The issuer ID being used for this request. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String PatchObject(String issuerId, String objectSuffix) throws IOException { + LoyaltyObject existingObject; - // See link below for more information on required properties - // https://developers.google.com/wallet/retail/loyalty-cards/rest/v1/loyaltyobject - LoyaltyObject batchObject = - new LoyaltyObject() - .setId(String.format("%s.%s", issuerId, objectSuffix)) - .setClassId(String.format("%s.%s", issuerId, classSuffix)) - .setState("ACTIVE") - .setHeroImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Hero image description")))) - .setTextModulesData( - List.of( - new TextModuleData() - .setHeader("Text module header") - .setBody("Text module body") - .setId("TEXT_MODULE_ID"))) - .setLinksModuleData( - new LinksModuleData() - .setUris( - Arrays.asList( - new Uri() - .setUri("http://maps.google.com/") - .setDescription("Link module URI description") - .setId("LINK_MODULE_URI_ID"), - new Uri() - .setUri("tel:6505555555") - .setDescription("Link module tel description") - .setId("LINK_MODULE_TEL_ID")))) - .setImageModulesData( - List.of( - new ImageModuleData() - .setMainImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Image module description")))) - .setId("IMAGE_MODULE_ID"))) - .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) - .setLocations( - List.of( - new LatLongPoint() - .setLatitude(37.424015499999996) - .setLongitude(-122.09259560000001))) - .setAccountId("Account ID") - .setAccountName("Account name") - .setLoyaltyPoints( - new LoyaltyPoints() - .setLabel("Points") - .setBalance(new LoyaltyPointsBalance().setInt(800))); - - service.loyaltyobject().insert(batchObject).queue(batch, callback); - } - - // Invoke the batch API calls - batch.execute(); + // Check if the object exists + try { + existingObject = + service.loyaltyobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Object does not exist + System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, objectSuffix); + } } + // Object exists + // Patch the object by adding a link + Uri newLink = + new Uri() + .setUri("https://developers.google.com/wallet") + .setDescription("New link description"); + + LoyaltyObject patchBody = new LoyaltyObject(); + + if (existingObject.getLinksModuleData() == null) { + // LinksModuleData was not set on the original object + patchBody.setLinksModuleData(new LinksModuleData().setUris(new ArrayList())); + } else { + patchBody.setLinksModuleData(existingObject.getLinksModuleData()); + } + patchBody.getLinksModuleData().getUris().add(newLink); + + LoyaltyObject response = + service + .loyaltyobject() + .patch(String.format("%s.%s", issuerId, objectSuffix), patchBody) + .execute(); + + System.out.println("Object patch response"); + System.out.println(response.toPrettyString()); + + return response.getId(); + } + // [END patchObject] + + // [START expireObject] + /** + * Expire an object. + * + *

Sets the object's state to Expired. If the valid time interval is already set, the pass will + * expire automatically up to 24 hours after. + * + * @param issuerId The issuer ID being used for this request. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String ExpireObject(String issuerId, String objectSuffix) throws IOException { + // Check if the object exists + try { + service.loyaltyobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Object does not exist + System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, objectSuffix); + } + } + + // Patch the object, setting the pass as expired + LoyaltyObject patchBody = new LoyaltyObject().setState("EXPIRED"); + + LoyaltyObject response = + service + .loyaltyobject() + .patch(String.format("%s.%s", issuerId, objectSuffix), patchBody) + .execute(); + + System.out.println("Object expiration response"); + System.out.println(response.toPrettyString()); + + return response.getId(); + } + // [END expireObject] + + // [START addMessageObject] + /** + * Add a message to a pass object. + * + * @param issuerId The issuer ID being used for this request. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @param header The message header. + * @param body The message body. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String AddObjectMessage(String issuerId, String objectSuffix, String header, String body) + throws IOException { + // Check if the object exists + try { + service.loyaltyobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Object does not exist + System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, objectSuffix); + } + } + + AddMessageRequest message = + new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body)); + + LoyaltyObjectAddMessageResponse response = + service + .loyaltyobject() + .addmessage(String.format("%s.%s", issuerId, objectSuffix), message) + .execute(); + + System.out.println("Object addMessage response"); + System.out.println(response.toPrettyString()); + + return String.format("%s.%s", issuerId, objectSuffix); + } + // [END addMessageObject] + + // [START jwtNew] + /** + * Generate a signed JWT that creates a new pass class and object. + * + *

When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the + * pass class and object defined in the JWT are created. This allows you to create multiple pass + * classes and objects in one API call when the user saves the pass to their wallet. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @param objectSuffix Developer-defined unique ID for the pass object. + * @return An "Add to Google Wallet" link. + */ + public String CreateJWTNewObjects(String issuerId, String classSuffix, String objectSuffix) { + // See link below for more information on required properties + // https://developers.google.com/wallet/retail/loyalty-cards/rest/v1/loyaltyclass + LoyaltyClass newClass = + new LoyaltyClass() + .setId(String.format("%s.%s", issuerId, classSuffix)) + .setIssuerName("Issuer name") + .setReviewStatus("UNDER_REVIEW") + .setProgramName("Program name") + .setProgramLogo( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Logo description")))); + + // See link below for more information on required properties + // https://developers.google.com/wallet/retail/loyalty-cards/rest/v1/loyaltyobject + LoyaltyObject newObject = + new LoyaltyObject() + .setId(String.format("%s.%s", issuerId, objectSuffix)) + .setClassId(String.format("%s.%s", issuerId, classSuffix)) + .setState("ACTIVE") + .setHeroImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Hero image description")))) + .setTextModulesData( + Arrays.asList( + new TextModuleData() + .setHeader("Text module header") + .setBody("Text module body") + .setId("TEXT_MODULE_ID"))) + .setLinksModuleData( + new LinksModuleData() + .setUris( + Arrays.asList( + new Uri() + .setUri("http://maps.google.com/") + .setDescription("Link module URI description") + .setId("LINK_MODULE_URI_ID"), + new Uri() + .setUri("tel:6505555555") + .setDescription("Link module tel description") + .setId("LINK_MODULE_TEL_ID")))) + .setImageModulesData( + Arrays.asList( + new ImageModuleData() + .setMainImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Image module description")))) + .setId("IMAGE_MODULE_ID"))) + .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) + .setLocations( + Arrays.asList( + new LatLongPoint() + .setLatitude(37.424015499999996) + .setLongitude(-122.09259560000001))) + .setAccountId("Account ID") + .setAccountName("Account name") + .setLoyaltyPoints( + new LoyaltyPoints() + .setLabel("Points") + .setBalance(new LoyaltyPointsBalance().setInt(800))); + + // Create the JWT as a HashMap object + HashMap claims = new HashMap(); + claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail()); + claims.put("aud", "google"); + claims.put("origins", Arrays.asList("www.example.com")); + claims.put("typ", "savetowallet"); + + // Create the Google Wallet payload and add to the JWT + HashMap payload = new HashMap(); + payload.put("loyaltyClasses", Arrays.asList(newClass)); + payload.put("loyaltyObjects", Arrays.asList(newObject)); + claims.put("payload", payload); + + // The service account credentials are used to sign the JWT + Algorithm algorithm = + Algorithm.RSA256( + null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); + String token = JWT.create().withPayload(claims).sign(algorithm); + + System.out.println("Add to Google Wallet link"); + System.out.println(String.format("https://pay.google.com/gp/v/save/%s", token)); + + return String.format("https://pay.google.com/gp/v/save/%s", token); + } + // [END jwtNew] + + // [START jwtExisting] + /** + * Generate a signed JWT that references an existing pass object. + * + *

When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the + * pass objects defined in the JWT are added to the user's Google Wallet app. This allows the user + * to save multiple pass objects in one API call. + * + *

The objects to add must follow the below format: + * + *

{ 'id': 'ISSUER_ID.OBJECT_SUFFIX', 'classId': 'ISSUER_ID.CLASS_SUFFIX' } + * + * @param issuerId The issuer ID being used for this request. + * @return An "Add to Google Wallet" link. + */ + public String CreateJWTExistingObjects(String issuerId) { + // Multiple pass types can be added at the same time + // At least one type must be specified in the JWT claims + // Note: Make sure to replace the placeholder class and object suffixes + HashMap objectsToAdd = new HashMap(); + + // Event tickets + objectsToAdd.put( + "eventTicketObjects", + Arrays.asList( + new EventTicketObject() + .setId(String.format("%s.%s", issuerId, "EVENT_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "EVENT_CLASS_SUFFIX")))); + + // Boarding passes + objectsToAdd.put( + "flightObjects", + Arrays.asList( + new FlightObject() + .setId(String.format("%s.%s", issuerId, "FLIGHT_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "FLIGHT_CLASS_SUFFIX")))); + + // Generic passes + objectsToAdd.put( + "genericObjects", + Arrays.asList( + new GenericObject() + .setId(String.format("%s.%s", issuerId, "GENERIC_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "GENERIC_CLASS_SUFFIX")))); + + // Gift cards + objectsToAdd.put( + "giftCardObjects", + Arrays.asList( + new GiftCardObject() + .setId(String.format("%s.%s", issuerId, "GIFT_CARD_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "GIFT_CARD_CLASS_SUFFIX")))); + + // Loyalty cards + objectsToAdd.put( + "loyaltyObjects", + Arrays.asList( + new LoyaltyObject() + .setId(String.format("%s.%s", issuerId, "LOYALTY_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "LOYALTY_CLASS_SUFFIX")))); + + // Offers + objectsToAdd.put( + "offerObjects", + Arrays.asList( + new OfferObject() + .setId(String.format("%s.%s", issuerId, "OFFER_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "OFFER_CLASS_SUFFIX")))); + + // Transit passes + objectsToAdd.put( + "transitObjects", + Arrays.asList( + new TransitObject() + .setId(String.format("%s.%s", issuerId, "TRANSIT_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "TRANSIT_CLASS_SUFFIX")))); + + // Create the JWT as a HashMap object + HashMap claims = new HashMap(); + claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail()); + claims.put("aud", "google"); + claims.put("origins", Arrays.asList("www.example.com")); + claims.put("typ", "savetowallet"); + claims.put("payload", objectsToAdd); + + // The service account credentials are used to sign the JWT + Algorithm algorithm = + Algorithm.RSA256( + null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); + String token = JWT.create().withPayload(claims).sign(algorithm); + + System.out.println("Add to Google Wallet link"); + System.out.println(String.format("https://pay.google.com/gp/v/save/%s", token)); + + return String.format("https://pay.google.com/gp/v/save/%s", token); + } + // [END jwtExisting] + + // [START batch] + /** + * Batch create Google Wallet objects from an existing class. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @throws IOException + */ + public void BatchCreateObjects(String issuerId, String classSuffix) throws IOException { + // Create the batch request client + BatchRequest batch = service.batch(new HttpCredentialsAdapter(credentials)); + + // The callback will be invoked for each request in the batch + JsonBatchCallback callback = + new JsonBatchCallback() { + // Invoked if the request was successful + public void onSuccess(LoyaltyObject response, HttpHeaders responseHeaders) { + System.out.println("Batch insert response"); + System.out.println(response.toString()); + } + + // Invoked if the request failed + public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) { + System.out.println("Error Message: " + e.getMessage()); + } + }; + + // Example: Generate three new pass objects + for (int i = 0; i < 3; i++) { + // Generate a random object suffix + String objectSuffix = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_"); + + // See link below for more information on required properties + // https://developers.google.com/wallet/retail/loyalty-cards/rest/v1/loyaltyobject + LoyaltyObject batchObject = + new LoyaltyObject() + .setId(String.format("%s.%s", issuerId, objectSuffix)) + .setClassId(String.format("%s.%s", issuerId, classSuffix)) + .setState("ACTIVE") + .setHeroImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Hero image description")))) + .setTextModulesData( + Arrays.asList( + new TextModuleData() + .setHeader("Text module header") + .setBody("Text module body") + .setId("TEXT_MODULE_ID"))) + .setLinksModuleData( + new LinksModuleData() + .setUris( + Arrays.asList( + new Uri() + .setUri("http://maps.google.com/") + .setDescription("Link module URI description") + .setId("LINK_MODULE_URI_ID"), + new Uri() + .setUri("tel:6505555555") + .setDescription("Link module tel description") + .setId("LINK_MODULE_TEL_ID")))) + .setImageModulesData( + Arrays.asList( + new ImageModuleData() + .setMainImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Image module description")))) + .setId("IMAGE_MODULE_ID"))) + .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) + .setLocations( + Arrays.asList( + new LatLongPoint() + .setLatitude(37.424015499999996) + .setLongitude(-122.09259560000001))) + .setAccountId("Account ID") + .setAccountName("Account name") + .setLoyaltyPoints( + new LoyaltyPoints() + .setLabel("Points") + .setBalance(new LoyaltyPointsBalance().setInt(800))); + + service.loyaltyobject().insert(batchObject).queue(batch, callback); + } + + // Invoke the batch API calls + batch.execute(); + } + // [END batch] } diff --git a/java/src/main/java/DemoOffer.java b/java/src/main/java/DemoOffer.java index e4b7028..8da00f7 100644 --- a/java/src/main/java/DemoOffer.java +++ b/java/src/main/java/DemoOffer.java @@ -14,6 +14,8 @@ * limitations under the License. */ +// [START setup] +// [START imports] import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.google.api.client.googleapis.batch.BatchRequest; @@ -21,849 +23,879 @@ import com.google.api.client.googleapis.batch.json.JsonBatchCallback; import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; import com.google.api.client.googleapis.json.GoogleJsonError; import com.google.api.client.googleapis.json.GoogleJsonResponseException; -import com.google.api.client.http.HttpHeaders; -import com.google.api.client.http.HttpTransport; +import com.google.api.client.http.*; import com.google.api.client.json.gson.GsonFactory; import com.google.api.services.walletobjects.Walletobjects; import com.google.api.services.walletobjects.model.*; import com.google.auth.http.HttpCredentialsAdapter; import com.google.auth.oauth2.GoogleCredentials; import com.google.auth.oauth2.ServiceAccountCredentials; - -import java.io.FileInputStream; -import java.io.IOException; +import java.io.*; import java.security.interfaces.RSAPrivateKey; import java.util.*; +// [END imports] -/** - * Demo class for creating and managing Offers in Google Wallet. - */ +/** Demo class for creating and managing Offers in Google Wallet. */ public class DemoOffer { - /** - * Path to service account key file from Google Cloud Console. Environment variable: - * GOOGLE_APPLICATION_CREDENTIALS. - */ - public static String keyFilePath; + /** + * Path to service account key file from Google Cloud Console. Environment variable: + * GOOGLE_APPLICATION_CREDENTIALS. + */ + public static String keyFilePath; - /** - * Service account credentials for Google Wallet APIs. - */ - public static GoogleCredentials credentials; + /** Service account credentials for Google Wallet APIs. */ + public static GoogleCredentials credentials; - /** - * Google Wallet service client. - */ - public static Walletobjects service; + /** Google Wallet service client. */ + public static Walletobjects service; - public DemoOffer() throws Exception { - keyFilePath = - System.getenv().getOrDefault("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/key.json"); + public DemoOffer() throws Exception { + keyFilePath = + System.getenv().getOrDefault("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/key.json"); - auth(); - } + Auth(); + } + // [END setup] - /** - * Create authenticated HTTP client using a service account file. - */ - public void auth() throws Exception { - String scope = "https://www.googleapis.com/auth/wallet_object.issuer"; + // [START auth] + /** + * Create authenticated HTTP client using a service account file. + * + * @throws Exception + */ + public void Auth() throws Exception { + String scope = "https://www.googleapis.com/auth/wallet_object.issuer"; - credentials = - GoogleCredentials.fromStream(new FileInputStream(keyFilePath)) - .createScoped(List.of(scope)); - credentials.refresh(); + credentials = + GoogleCredentials.fromStream(new FileInputStream(keyFilePath)) + .createScoped(Arrays.asList(scope)); + credentials.refresh(); - HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport(); + HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport(); - // Initialize Google Wallet API service - service = - new Walletobjects.Builder( - httpTransport, - GsonFactory.getDefaultInstance(), - new HttpCredentialsAdapter(credentials)) - .setApplicationName("APPLICATION_NAME") - .build(); - } + // Initialize Google Wallet API service + service = + new Walletobjects.Builder( + httpTransport, + GsonFactory.getDefaultInstance(), + new HttpCredentialsAdapter(credentials)) + .setApplicationName("APPLICATION_NAME") + .build(); + } + // [END auth] - /** - * Create a class. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @return The pass class ID: "{issuerId}.{classSuffix}" - */ - public String createClass(String issuerId, String classSuffix) throws IOException { - // Check if the class exists - try { - service.offerclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); - - System.out.printf("Class %s.%s already exists!%n", issuerId, classSuffix); - return String.format("%s.%s", issuerId, classSuffix); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() != 404) { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, classSuffix); - } - } - - // See link below for more information on required properties - // https://developers.google.com/wallet/retail/offers/rest/v1/offerclass - OfferClass newClass = - new OfferClass() - .setId(String.format("%s.%s", issuerId, classSuffix)) - .setIssuerName("Issuer name") - .setReviewStatus("UNDER_REVIEW") - .setProvider("Provider name") - .setTitle("Offer title") - .setRedemptionChannel("ONLINE"); - - OfferClass response = service.offerclass().insert(newClass).execute(); - - System.out.println("Class insert response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Update a class. - * - *

Warning: This replaces all existing class attributes! - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @return The pass class ID: "{issuerId}.{classSuffix}" - */ - public String updateClass(String issuerId, String classSuffix) throws IOException { - OfferClass updatedClass; - - // Check if the class exists - try { - updatedClass = - service.offerclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Class does not exist - System.out.printf("Class %s.%s not found!%n", issuerId, classSuffix); - return String.format("%s.%s", issuerId, classSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, classSuffix); - } - } - - // Class exists - // Update the class by adding a homepage - updatedClass.setHomepageUri( - new Uri() - .setUri("https://developers.google.com/wallet") - .setDescription("Homepage description")); - - // Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates - updatedClass.setReviewStatus("UNDER_REVIEW"); - - OfferClass response = - service - .offerclass() - .update(String.format("%s.%s", issuerId, classSuffix), updatedClass) - .execute(); - - System.out.println("Class update response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Patch a class. - * - *

The PATCH method supports patch semantics. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @return The pass class ID: "{issuerId}.{classSuffix}" - */ - public String patchClass(String issuerId, String classSuffix) throws IOException { - // Check if the class exists - try { - service.offerclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Class does not exist - System.out.printf("Class %s.%s not found!%n", issuerId, classSuffix); - return String.format("%s.%s", issuerId, classSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, classSuffix); - } - } - - // Class exists - // Patch the class by adding a homepage - OfferClass patchBody = - new OfferClass() - .setHomepageUri( - new Uri() - .setUri("https://developers.google.com/wallet") - .setDescription("Homepage description")) - - // Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates - .setReviewStatus("UNDER_REVIEW"); - - OfferClass response = - service - .offerclass() - .patch(String.format("%s.%s", issuerId, classSuffix), patchBody) - .execute(); - - System.out.println("Class patch response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Add a message to a pass class. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @param header The message header. - * @param body The message body. - * @return The pass class ID: "{issuerId}.{classSuffix}" - */ - public String addClassMessage(String issuerId, String classSuffix, String header, String body) - throws IOException { - // Check if the class exists - try { - service.offerclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Class does not exist - System.out.printf("Class %s.%s not found!%n", issuerId, classSuffix); - return String.format("%s.%s", issuerId, classSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, classSuffix); - } - } - - AddMessageRequest message = - new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body)); - - OfferClassAddMessageResponse response = - service - .offerclass() - .addmessage(String.format("%s.%s", issuerId, classSuffix), message) - .execute(); - - System.out.println("Class addMessage response"); - System.out.println(response.toPrettyString()); + // [START createClass] + /** + * Create a class. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @return The pass class ID: "{issuerId}.{classSuffix}" + * @throws IOException + */ + public String CreateClass(String issuerId, String classSuffix) throws IOException { + // Check if the class exists + try { + service.offerclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); + System.out.println(String.format("Class %s.%s already exists!", issuerId, classSuffix)); + return String.format("%s.%s", issuerId, classSuffix); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() != 404) { + // Something else went wrong... + ex.printStackTrace(); return String.format("%s.%s", issuerId, classSuffix); + } } - /** - * Create an object. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String createObject(String issuerId, String classSuffix, String objectSuffix) - throws IOException { - // Check if the object exists - try { - service.offerobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + // See link below for more information on required properties + // https://developers.google.com/wallet/retail/offers/rest/v1/offerclass + OfferClass newClass = + new OfferClass() + .setId(String.format("%s.%s", issuerId, classSuffix)) + .setIssuerName("Issuer name") + .setReviewStatus("UNDER_REVIEW") + .setProvider("Provider name") + .setTitle("Offer title") + .setRedemptionChannel("ONLINE"); - System.out.printf("Object %s.%s already exists!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Object does not exist - // Do nothing - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } + OfferClass response = service.offerclass().insert(newClass).execute(); - // See link below for more information on required properties - // https://developers.google.com/wallet/retail/offers/rest/v1/offerobject - OfferObject newObject = - new OfferObject() - .setId(String.format("%s.%s", issuerId, objectSuffix)) - .setClassId(String.format("%s.%s", issuerId, classSuffix)) - .setState("ACTIVE") - .setHeroImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Hero image description")))) - .setTextModulesData( - List.of( - new TextModuleData() - .setHeader("Text module header") - .setBody("Text module body") - .setId("TEXT_MODULE_ID"))) - .setLinksModuleData( - new LinksModuleData() - .setUris( - Arrays.asList( - new Uri() - .setUri("http://maps.google.com/") - .setDescription("Link module URI description") - .setId("LINK_MODULE_URI_ID"), - new Uri() - .setUri("tel:6505555555") - .setDescription("Link module tel description") - .setId("LINK_MODULE_TEL_ID")))) - .setImageModulesData( - List.of( - new ImageModuleData() - .setMainImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Image module description")))) - .setId("IMAGE_MODULE_ID"))) - .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) - .setLocations( - List.of( - new LatLongPoint() - .setLatitude(37.424015499999996) - .setLongitude(-122.09259560000001))) - .setValidTimeInterval( - new TimeInterval() - .setStart(new DateTime().setDate("2023-06-12T23:20:50.52Z")) - .setEnd(new DateTime().setDate("2023-12-12T23:20:50.52Z"))); + System.out.println("Class insert response"); + System.out.println(response.toPrettyString()); - OfferObject response = service.offerobject().insert(newObject).execute(); + return response.getId(); + } + // [END createClass] - System.out.println("Object insert response"); - System.out.println(response.toPrettyString()); + // [START updateClass] + /** + * Update a class. + * + *

Warning: This replaces all existing class attributes! + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @return The pass class ID: "{issuerId}.{classSuffix}" + * @throws IOException + */ + public String UpdateClass(String issuerId, String classSuffix) throws IOException { + OfferClass updatedClass; - return response.getId(); + // Check if the class exists + try { + updatedClass = + service.offerclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Class does not exist + System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix)); + return String.format("%s.%s", issuerId, classSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, classSuffix); + } } - /** - * Update an object. - * - *

Warning: This replaces all existing object attributes! - * - * @param issuerId The issuer ID being used for this request. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String updateObject(String issuerId, String objectSuffix) throws IOException { - OfferObject updatedObject; + // Class exists + // Update the class by adding a homepage + updatedClass.setHomepageUri( + new Uri() + .setUri("https://developers.google.com/wallet") + .setDescription("Homepage description")); - // Check if the object exists - try { - updatedObject = - service.offerobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Object does not exist - System.out.printf("Object %s.%s not found!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } + // Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates + updatedClass.setReviewStatus("UNDER_REVIEW"); - // Object exists - // Update the object by adding a link - Uri newLink = + OfferClass response = + service + .offerclass() + .update(String.format("%s.%s", issuerId, classSuffix), updatedClass) + .execute(); + + System.out.println("Class update response"); + System.out.println(response.toPrettyString()); + + return response.getId(); + } + // [END updateClass] + + // [START patchClass] + /** + * Patch a class. + * + *

The PATCH method supports patch semantics. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @return The pass class ID: "{issuerId}.{classSuffix}" + * @throws IOException + */ + public String PatchClass(String issuerId, String classSuffix) throws IOException { + // Check if the class exists + try { + service.offerclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Class does not exist + System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix)); + return String.format("%s.%s", issuerId, classSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, classSuffix); + } + } + + // Class exists + // Patch the class by adding a homepage + OfferClass patchBody = + new OfferClass() + .setHomepageUri( new Uri() - .setUri("https://developers.google.com/wallet") - .setDescription("New link description"); + .setUri("https://developers.google.com/wallet") + .setDescription("Homepage description")) - if (updatedObject.getLinksModuleData() == null) { - // LinksModuleData was not set on the original object - updatedObject.setLinksModuleData(new LinksModuleData().setUris(List.of(newLink))); - } else { - updatedObject.getLinksModuleData().getUris().add(newLink); - } + // Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates + .setReviewStatus("UNDER_REVIEW"); - OfferObject response = - service - .offerobject() - .update(String.format("%s.%s", issuerId, objectSuffix), updatedObject) - .execute(); + OfferClass response = + service + .offerclass() + .patch(String.format("%s.%s", issuerId, classSuffix), patchBody) + .execute(); - System.out.println("Object update response"); - System.out.println(response.toPrettyString()); + System.out.println("Class patch response"); + System.out.println(response.toPrettyString()); - return response.getId(); + return response.getId(); + } + // [END patchClass] + + // [START addMessageClass] + /** + * Add a message to a pass class. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @param header The message header. + * @param body The message body. + * @return The pass class ID: "{issuerId}.{classSuffix}" + * @throws IOException + */ + public String AddClassMessage(String issuerId, String classSuffix, String header, String body) + throws IOException { + // Check if the class exists + try { + service.offerclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Class does not exist + System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix)); + return String.format("%s.%s", issuerId, classSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, classSuffix); + } } - /** - * Patch an object. - * - * @param issuerId The issuer ID being used for this request. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String patchObject(String issuerId, String objectSuffix) throws IOException { - OfferObject existingObject; + AddMessageRequest message = + new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body)); - // Check if the object exists - try { - existingObject = - service.offerobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Object does not exist - System.out.printf("Object %s.%s not found!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } + OfferClassAddMessageResponse response = + service + .offerclass() + .addmessage(String.format("%s.%s", issuerId, classSuffix), message) + .execute(); - // Object exists - // Patch the object by adding a link - Uri newLink = - new Uri() - .setUri("https://developers.google.com/wallet") - .setDescription("New link description"); + System.out.println("Class addMessage response"); + System.out.println(response.toPrettyString()); - OfferObject patchBody = new OfferObject(); + return String.format("%s.%s", issuerId, classSuffix); + } + // [END addMessageClass] - if (existingObject.getLinksModuleData() == null) { - // LinksModuleData was not set on the original object - patchBody.setLinksModuleData(new LinksModuleData().setUris(new ArrayList())); - } else { - patchBody.setLinksModuleData(existingObject.getLinksModuleData()); - } - patchBody.getLinksModuleData().getUris().add(newLink); - - OfferObject response = - service - .offerobject() - .patch(String.format("%s.%s", issuerId, objectSuffix), patchBody) - .execute(); - - System.out.println("Object patch response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Expire an object. - * - *

Sets the object's state to Expired. If the valid time interval is already set, the pass will - * expire automatically up to 24 hours after. - * - * @param issuerId The issuer ID being used for this request. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String expireObject(String issuerId, String objectSuffix) throws IOException { - // Check if the object exists - try { - service.offerobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Object does not exist - System.out.printf("Object %s.%s not found!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } - - // Patch the object, setting the pass as expired - OfferObject patchBody = new OfferObject().setState("EXPIRED"); - - OfferObject response = - service - .offerobject() - .patch(String.format("%s.%s", issuerId, objectSuffix), patchBody) - .execute(); - - System.out.println("Object expiration response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Add a message to a pass object. - * - * @param issuerId The issuer ID being used for this request. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @param header The message header. - * @param body The message body. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String addObjectMessage(String issuerId, String objectSuffix, String header, String body) - throws IOException { - // Check if the object exists - try { - service.offerobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Object does not exist - System.out.printf("Object %s.%s not found!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } - - AddMessageRequest message = - new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body)); - - OfferObjectAddMessageResponse response = - service - .offerobject() - .addmessage(String.format("%s.%s", issuerId, objectSuffix), message) - .execute(); - - System.out.println("Object addMessage response"); - System.out.println(response.toPrettyString()); + // [START createObject] + /** + * Create an object. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String CreateObject(String issuerId, String classSuffix, String objectSuffix) + throws IOException { + // Check if the object exists + try { + service.offerobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + System.out.println(String.format("Object %s.%s already exists!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Object does not exist + // Do nothing + } else { + // Something else went wrong... + ex.printStackTrace(); return String.format("%s.%s", issuerId, objectSuffix); + } } - /** - * Generate a signed JWT that creates a new pass class and object. - * - *

When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the - * pass class and object defined in the JWT are created. This allows you to create multiple pass - * classes and objects in one API call when the user saves the pass to their wallet. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @param objectSuffix Developer-defined unique ID for the pass object. - * @return An "Add to Google Wallet" link. - */ - public String createJWTNewObjects(String issuerId, String classSuffix, String objectSuffix) { - // See link below for more information on required properties - // https://developers.google.com/wallet/retail/offers/rest/v1/offerclass - OfferClass newClass = - new OfferClass() - .setId(String.format("%s.%s", issuerId, classSuffix)) - .setIssuerName("Issuer name") - .setReviewStatus("UNDER_REVIEW") - .setProvider("Provider name") - .setTitle("Offer title") - .setRedemptionChannel("ONLINE"); + // See link below for more information on required properties + // https://developers.google.com/wallet/retail/offers/rest/v1/offerobject + OfferObject newObject = + new OfferObject() + .setId(String.format("%s.%s", issuerId, objectSuffix)) + .setClassId(String.format("%s.%s", issuerId, classSuffix)) + .setState("ACTIVE") + .setHeroImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Hero image description")))) + .setTextModulesData( + Arrays.asList( + new TextModuleData() + .setHeader("Text module header") + .setBody("Text module body") + .setId("TEXT_MODULE_ID"))) + .setLinksModuleData( + new LinksModuleData() + .setUris( + Arrays.asList( + new Uri() + .setUri("http://maps.google.com/") + .setDescription("Link module URI description") + .setId("LINK_MODULE_URI_ID"), + new Uri() + .setUri("tel:6505555555") + .setDescription("Link module tel description") + .setId("LINK_MODULE_TEL_ID")))) + .setImageModulesData( + Arrays.asList( + new ImageModuleData() + .setMainImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Image module description")))) + .setId("IMAGE_MODULE_ID"))) + .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) + .setLocations( + Arrays.asList( + new LatLongPoint() + .setLatitude(37.424015499999996) + .setLongitude(-122.09259560000001))) + .setValidTimeInterval( + new TimeInterval() + .setStart(new DateTime().setDate("2023-06-12T23:20:50.52Z")) + .setEnd(new DateTime().setDate("2023-12-12T23:20:50.52Z"))); - // See link below for more information on required properties - // https://developers.google.com/wallet/retail/offers/rest/v1/offerobject - OfferObject newObject = - new OfferObject() - .setId(String.format("%s.%s", issuerId, objectSuffix)) - .setClassId(String.format("%s.%s", issuerId, classSuffix)) - .setState("ACTIVE") - .setHeroImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Hero image description")))) - .setTextModulesData( - List.of( - new TextModuleData() - .setHeader("Text module header") - .setBody("Text module body") - .setId("TEXT_MODULE_ID"))) - .setLinksModuleData( - new LinksModuleData() - .setUris( - Arrays.asList( - new Uri() - .setUri("http://maps.google.com/") - .setDescription("Link module URI description") - .setId("LINK_MODULE_URI_ID"), - new Uri() - .setUri("tel:6505555555") - .setDescription("Link module tel description") - .setId("LINK_MODULE_TEL_ID")))) - .setImageModulesData( - List.of( - new ImageModuleData() - .setMainImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Image module description")))) - .setId("IMAGE_MODULE_ID"))) - .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) - .setLocations( - List.of( - new LatLongPoint() - .setLatitude(37.424015499999996) - .setLongitude(-122.09259560000001))) - .setValidTimeInterval( - new TimeInterval() - .setStart(new DateTime().setDate("2023-06-12T23:20:50.52Z")) - .setEnd(new DateTime().setDate("2023-12-12T23:20:50.52Z"))); + OfferObject response = service.offerobject().insert(newObject).execute(); - // Create the JWT as a HashMap object - HashMap claims = new HashMap(); - claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail()); - claims.put("aud", "google"); - claims.put("origins", List.of("www.example.com")); - claims.put("typ", "savetowallet"); + System.out.println("Object insert response"); + System.out.println(response.toPrettyString()); - // Create the Google Wallet payload and add to the JWT - HashMap payload = new HashMap(); - payload.put("offerClasses", List.of(newClass)); - payload.put("offerObjects", List.of(newObject)); - claims.put("payload", payload); + return response.getId(); + } + // [END createObject] - // The service account credentials are used to sign the JWT - Algorithm algorithm = - Algorithm.RSA256( - null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); - String token = JWT.create().withPayload(claims).sign(algorithm); + // [START updateObject] + /** + * Update an object. + * + *

Warning: This replaces all existing object attributes! + * + * @param issuerId The issuer ID being used for this request. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String UpdateObject(String issuerId, String objectSuffix) throws IOException { + OfferObject updatedObject; - System.out.println("Add to Google Wallet link"); - System.out.printf("https://pay.google.com/gp/v/save/%s%n", token); - - return String.format("https://pay.google.com/gp/v/save/%s", token); + // Check if the object exists + try { + updatedObject = + service.offerobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Object does not exist + System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, objectSuffix); + } } - /** - * Generate a signed JWT that references an existing pass object. - * - *

When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the - * pass objects defined in the JWT are added to the user's Google Wallet app. This allows the user - * to save multiple pass objects in one API call. - * - *

The objects to add must follow the below format: - * - *

{ 'id': 'ISSUER_ID.OBJECT_SUFFIX', 'classId': 'ISSUER_ID.CLASS_SUFFIX' } - * - * @param issuerId The issuer ID being used for this request. - * @return An "Add to Google Wallet" link. - */ - public String createJWTExistingObjects(String issuerId) { - // Multiple pass types can be added at the same time - // At least one type must be specified in the JWT claims - // Note: Make sure to replace the placeholder class and object suffixes - HashMap objectsToAdd = new HashMap(); + // Object exists + // Update the object by adding a link + Uri newLink = + new Uri() + .setUri("https://developers.google.com/wallet") + .setDescription("New link description"); - // Event tickets - objectsToAdd.put( - "eventTicketObjects", - List.of( - new EventTicketObject() - .setId(String.format("%s.%s", issuerId, "EVENT_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "EVENT_CLASS_SUFFIX")))); - - // Boarding passes - objectsToAdd.put( - "flightObjects", - List.of( - new FlightObject() - .setId(String.format("%s.%s", issuerId, "FLIGHT_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "FLIGHT_CLASS_SUFFIX")))); - - // Generic passes - objectsToAdd.put( - "genericObjects", - List.of( - new GenericObject() - .setId(String.format("%s.%s", issuerId, "GENERIC_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "GENERIC_CLASS_SUFFIX")))); - - // Gift cards - objectsToAdd.put( - "giftCardObjects", - List.of( - new GiftCardObject() - .setId(String.format("%s.%s", issuerId, "GIFT_CARD_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "GIFT_CARD_CLASS_SUFFIX")))); - - // Loyalty cards - objectsToAdd.put( - "loyaltyObjects", - List.of( - new LoyaltyObject() - .setId(String.format("%s.%s", issuerId, "LOYALTY_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "LOYALTY_CLASS_SUFFIX")))); - - // Offers - objectsToAdd.put( - "offerObjects", - List.of( - new OfferObject() - .setId(String.format("%s.%s", issuerId, "OFFER_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "OFFER_CLASS_SUFFIX")))); - - // Transit passes - objectsToAdd.put( - "transitObjects", - List.of( - new TransitObject() - .setId(String.format("%s.%s", issuerId, "TRANSIT_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "TRANSIT_CLASS_SUFFIX")))); - - // Create the JWT as a HashMap object - HashMap claims = new HashMap(); - claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail()); - claims.put("aud", "google"); - claims.put("origins", List.of("www.example.com")); - claims.put("typ", "savetowallet"); - claims.put("payload", objectsToAdd); - - // The service account credentials are used to sign the JWT - Algorithm algorithm = - Algorithm.RSA256( - null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); - String token = JWT.create().withPayload(claims).sign(algorithm); - - System.out.println("Add to Google Wallet link"); - System.out.printf("https://pay.google.com/gp/v/save/%s%n", token); - - return String.format("https://pay.google.com/gp/v/save/%s", token); + if (updatedObject.getLinksModuleData() == null) { + // LinksModuleData was not set on the original object + updatedObject.setLinksModuleData(new LinksModuleData().setUris(Arrays.asList(newLink))); + } else { + updatedObject.getLinksModuleData().getUris().add(newLink); } - /** - * Batch create Google Wallet objects from an existing class. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - */ - public void batchCreateObjects(String issuerId, String classSuffix) throws IOException { - // Create the batch request client - BatchRequest batch = service.batch(new HttpCredentialsAdapter(credentials)); + OfferObject response = + service + .offerobject() + .update(String.format("%s.%s", issuerId, objectSuffix), updatedObject) + .execute(); - // The callback will be invoked for each request in the batch - JsonBatchCallback callback = - new JsonBatchCallback() { - // Invoked if the request was successful - public void onSuccess(OfferObject response, HttpHeaders responseHeaders) { - System.out.println("Batch insert response"); - System.out.println(response.toString()); - } + System.out.println("Object update response"); + System.out.println(response.toPrettyString()); - // Invoked if the request failed - public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) { - System.out.println("Error Message: " + e.getMessage()); - } - }; + return response.getId(); + } + // [END updateObject] - // Example: Generate three new pass objects - for (int i = 0; i < 3; i++) { - // Generate a random object suffix - String objectSuffix = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_"); + // [START patchObject] + /** + * Patch an object. + * + * @param issuerId The issuer ID being used for this request. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String PatchObject(String issuerId, String objectSuffix) throws IOException { + OfferObject existingObject; - // See link below for more information on required properties - // https://developers.google.com/wallet/retail/offers/rest/v1/offerobject - OfferObject batchObject = - new OfferObject() - .setId(String.format("%s.%s", issuerId, objectSuffix)) - .setClassId(String.format("%s.%s", issuerId, classSuffix)) - .setState("ACTIVE") - .setHeroImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Hero image description")))) - .setTextModulesData( - List.of( - new TextModuleData() - .setHeader("Text module header") - .setBody("Text module body") - .setId("TEXT_MODULE_ID"))) - .setLinksModuleData( - new LinksModuleData() - .setUris( - Arrays.asList( - new Uri() - .setUri("http://maps.google.com/") - .setDescription("Link module URI description") - .setId("LINK_MODULE_URI_ID"), - new Uri() - .setUri("tel:6505555555") - .setDescription("Link module tel description") - .setId("LINK_MODULE_TEL_ID")))) - .setImageModulesData( - List.of( - new ImageModuleData() - .setMainImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Image module description")))) - .setId("IMAGE_MODULE_ID"))) - .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) - .setLocations( - List.of( - new LatLongPoint() - .setLatitude(37.424015499999996) - .setLongitude(-122.09259560000001))) - .setValidTimeInterval( - new TimeInterval() - .setStart(new DateTime().setDate("2023-06-12T23:20:50.52Z")) - .setEnd(new DateTime().setDate("2023-12-12T23:20:50.52Z"))); - - service.offerobject().insert(batchObject).queue(batch, callback); - } - - // Invoke the batch API calls - batch.execute(); + // Check if the object exists + try { + existingObject = + service.offerobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Object does not exist + System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, objectSuffix); + } } + // Object exists + // Patch the object by adding a link + Uri newLink = + new Uri() + .setUri("https://developers.google.com/wallet") + .setDescription("New link description"); + + OfferObject patchBody = new OfferObject(); + + if (existingObject.getLinksModuleData() == null) { + // LinksModuleData was not set on the original object + patchBody.setLinksModuleData(new LinksModuleData().setUris(new ArrayList())); + } else { + patchBody.setLinksModuleData(existingObject.getLinksModuleData()); + } + patchBody.getLinksModuleData().getUris().add(newLink); + + OfferObject response = + service + .offerobject() + .patch(String.format("%s.%s", issuerId, objectSuffix), patchBody) + .execute(); + + System.out.println("Object patch response"); + System.out.println(response.toPrettyString()); + + return response.getId(); + } + // [END patchObject] + + // [START expireObject] + /** + * Expire an object. + * + *

Sets the object's state to Expired. If the valid time interval is already set, the pass will + * expire automatically up to 24 hours after. + * + * @param issuerId The issuer ID being used for this request. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String ExpireObject(String issuerId, String objectSuffix) throws IOException { + // Check if the object exists + try { + service.offerobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Object does not exist + System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, objectSuffix); + } + } + + // Patch the object, setting the pass as expired + OfferObject patchBody = new OfferObject().setState("EXPIRED"); + + OfferObject response = + service + .offerobject() + .patch(String.format("%s.%s", issuerId, objectSuffix), patchBody) + .execute(); + + System.out.println("Object expiration response"); + System.out.println(response.toPrettyString()); + + return response.getId(); + } + // [END expireObject] + + // [START addMessageObject] + /** + * Add a message to a pass object. + * + * @param issuerId The issuer ID being used for this request. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @param header The message header. + * @param body The message body. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String AddObjectMessage(String issuerId, String objectSuffix, String header, String body) + throws IOException { + // Check if the object exists + try { + service.offerobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Object does not exist + System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, objectSuffix); + } + } + + AddMessageRequest message = + new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body)); + + OfferObjectAddMessageResponse response = + service + .offerobject() + .addmessage(String.format("%s.%s", issuerId, objectSuffix), message) + .execute(); + + System.out.println("Object addMessage response"); + System.out.println(response.toPrettyString()); + + return String.format("%s.%s", issuerId, objectSuffix); + } + // [END addMessageObject] + + // [START jwtNew] + /** + * Generate a signed JWT that creates a new pass class and object. + * + *

When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the + * pass class and object defined in the JWT are created. This allows you to create multiple pass + * classes and objects in one API call when the user saves the pass to their wallet. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @param objectSuffix Developer-defined unique ID for the pass object. + * @return An "Add to Google Wallet" link. + */ + public String CreateJWTNewObjects(String issuerId, String classSuffix, String objectSuffix) { + // See link below for more information on required properties + // https://developers.google.com/wallet/retail/offers/rest/v1/offerclass + OfferClass newClass = + new OfferClass() + .setId(String.format("%s.%s", issuerId, classSuffix)) + .setIssuerName("Issuer name") + .setReviewStatus("UNDER_REVIEW") + .setProvider("Provider name") + .setTitle("Offer title") + .setRedemptionChannel("ONLINE"); + + // See link below for more information on required properties + // https://developers.google.com/wallet/retail/offers/rest/v1/offerobject + OfferObject newObject = + new OfferObject() + .setId(String.format("%s.%s", issuerId, objectSuffix)) + .setClassId(String.format("%s.%s", issuerId, classSuffix)) + .setState("ACTIVE") + .setHeroImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Hero image description")))) + .setTextModulesData( + Arrays.asList( + new TextModuleData() + .setHeader("Text module header") + .setBody("Text module body") + .setId("TEXT_MODULE_ID"))) + .setLinksModuleData( + new LinksModuleData() + .setUris( + Arrays.asList( + new Uri() + .setUri("http://maps.google.com/") + .setDescription("Link module URI description") + .setId("LINK_MODULE_URI_ID"), + new Uri() + .setUri("tel:6505555555") + .setDescription("Link module tel description") + .setId("LINK_MODULE_TEL_ID")))) + .setImageModulesData( + Arrays.asList( + new ImageModuleData() + .setMainImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Image module description")))) + .setId("IMAGE_MODULE_ID"))) + .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) + .setLocations( + Arrays.asList( + new LatLongPoint() + .setLatitude(37.424015499999996) + .setLongitude(-122.09259560000001))) + .setValidTimeInterval( + new TimeInterval() + .setStart(new DateTime().setDate("2023-06-12T23:20:50.52Z")) + .setEnd(new DateTime().setDate("2023-12-12T23:20:50.52Z"))); + + // Create the JWT as a HashMap object + HashMap claims = new HashMap(); + claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail()); + claims.put("aud", "google"); + claims.put("origins", Arrays.asList("www.example.com")); + claims.put("typ", "savetowallet"); + + // Create the Google Wallet payload and add to the JWT + HashMap payload = new HashMap(); + payload.put("offerClasses", Arrays.asList(newClass)); + payload.put("offerObjects", Arrays.asList(newObject)); + claims.put("payload", payload); + + // The service account credentials are used to sign the JWT + Algorithm algorithm = + Algorithm.RSA256( + null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); + String token = JWT.create().withPayload(claims).sign(algorithm); + + System.out.println("Add to Google Wallet link"); + System.out.println(String.format("https://pay.google.com/gp/v/save/%s", token)); + + return String.format("https://pay.google.com/gp/v/save/%s", token); + } + // [END jwtNew] + + // [START jwtExisting] + /** + * Generate a signed JWT that references an existing pass object. + * + *

When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the + * pass objects defined in the JWT are added to the user's Google Wallet app. This allows the user + * to save multiple pass objects in one API call. + * + *

The objects to add must follow the below format: + * + *

{ 'id': 'ISSUER_ID.OBJECT_SUFFIX', 'classId': 'ISSUER_ID.CLASS_SUFFIX' } + * + * @param issuerId The issuer ID being used for this request. + * @return An "Add to Google Wallet" link. + */ + public String CreateJWTExistingObjects(String issuerId) { + // Multiple pass types can be added at the same time + // At least one type must be specified in the JWT claims + // Note: Make sure to replace the placeholder class and object suffixes + HashMap objectsToAdd = new HashMap(); + + // Event tickets + objectsToAdd.put( + "eventTicketObjects", + Arrays.asList( + new EventTicketObject() + .setId(String.format("%s.%s", issuerId, "EVENT_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "EVENT_CLASS_SUFFIX")))); + + // Boarding passes + objectsToAdd.put( + "flightObjects", + Arrays.asList( + new FlightObject() + .setId(String.format("%s.%s", issuerId, "FLIGHT_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "FLIGHT_CLASS_SUFFIX")))); + + // Generic passes + objectsToAdd.put( + "genericObjects", + Arrays.asList( + new GenericObject() + .setId(String.format("%s.%s", issuerId, "GENERIC_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "GENERIC_CLASS_SUFFIX")))); + + // Gift cards + objectsToAdd.put( + "giftCardObjects", + Arrays.asList( + new GiftCardObject() + .setId(String.format("%s.%s", issuerId, "GIFT_CARD_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "GIFT_CARD_CLASS_SUFFIX")))); + + // Loyalty cards + objectsToAdd.put( + "loyaltyObjects", + Arrays.asList( + new LoyaltyObject() + .setId(String.format("%s.%s", issuerId, "LOYALTY_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "LOYALTY_CLASS_SUFFIX")))); + + // Offers + objectsToAdd.put( + "offerObjects", + Arrays.asList( + new OfferObject() + .setId(String.format("%s.%s", issuerId, "OFFER_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "OFFER_CLASS_SUFFIX")))); + + // Transit passes + objectsToAdd.put( + "transitObjects", + Arrays.asList( + new TransitObject() + .setId(String.format("%s.%s", issuerId, "TRANSIT_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "TRANSIT_CLASS_SUFFIX")))); + + // Create the JWT as a HashMap object + HashMap claims = new HashMap(); + claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail()); + claims.put("aud", "google"); + claims.put("origins", Arrays.asList("www.example.com")); + claims.put("typ", "savetowallet"); + claims.put("payload", objectsToAdd); + + // The service account credentials are used to sign the JWT + Algorithm algorithm = + Algorithm.RSA256( + null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); + String token = JWT.create().withPayload(claims).sign(algorithm); + + System.out.println("Add to Google Wallet link"); + System.out.println(String.format("https://pay.google.com/gp/v/save/%s", token)); + + return String.format("https://pay.google.com/gp/v/save/%s", token); + } + // [END jwtExisting] + + // [START batch] + /** + * Batch create Google Wallet objects from an existing class. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @throws IOException + */ + public void BatchCreateObjects(String issuerId, String classSuffix) throws IOException { + // Create the batch request client + BatchRequest batch = service.batch(new HttpCredentialsAdapter(credentials)); + + // The callback will be invoked for each request in the batch + JsonBatchCallback callback = + new JsonBatchCallback() { + // Invoked if the request was successful + public void onSuccess(OfferObject response, HttpHeaders responseHeaders) { + System.out.println("Batch insert response"); + System.out.println(response.toString()); + } + + // Invoked if the request failed + public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) { + System.out.println("Error Message: " + e.getMessage()); + } + }; + + // Example: Generate three new pass objects + for (int i = 0; i < 3; i++) { + // Generate a random object suffix + String objectSuffix = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_"); + + // See link below for more information on required properties + // https://developers.google.com/wallet/retail/offers/rest/v1/offerobject + OfferObject batchObject = + new OfferObject() + .setId(String.format("%s.%s", issuerId, objectSuffix)) + .setClassId(String.format("%s.%s", issuerId, classSuffix)) + .setState("ACTIVE") + .setHeroImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Hero image description")))) + .setTextModulesData( + Arrays.asList( + new TextModuleData() + .setHeader("Text module header") + .setBody("Text module body") + .setId("TEXT_MODULE_ID"))) + .setLinksModuleData( + new LinksModuleData() + .setUris( + Arrays.asList( + new Uri() + .setUri("http://maps.google.com/") + .setDescription("Link module URI description") + .setId("LINK_MODULE_URI_ID"), + new Uri() + .setUri("tel:6505555555") + .setDescription("Link module tel description") + .setId("LINK_MODULE_TEL_ID")))) + .setImageModulesData( + Arrays.asList( + new ImageModuleData() + .setMainImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Image module description")))) + .setId("IMAGE_MODULE_ID"))) + .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) + .setLocations( + Arrays.asList( + new LatLongPoint() + .setLatitude(37.424015499999996) + .setLongitude(-122.09259560000001))) + .setValidTimeInterval( + new TimeInterval() + .setStart(new DateTime().setDate("2023-06-12T23:20:50.52Z")) + .setEnd(new DateTime().setDate("2023-12-12T23:20:50.52Z"))); + + service.offerobject().insert(batchObject).queue(batch, callback); + } + + // Invoke the batch API calls + batch.execute(); + } + // [END batch] } diff --git a/java/src/main/java/DemoTransit.java b/java/src/main/java/DemoTransit.java index 6d3491f..381b65f 100644 --- a/java/src/main/java/DemoTransit.java +++ b/java/src/main/java/DemoTransit.java @@ -14,6 +14,8 @@ * limitations under the License. */ +// [START setup] +// [START imports] import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.google.api.client.googleapis.batch.BatchRequest; @@ -21,937 +23,967 @@ import com.google.api.client.googleapis.batch.json.JsonBatchCallback; import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; import com.google.api.client.googleapis.json.GoogleJsonError; import com.google.api.client.googleapis.json.GoogleJsonResponseException; -import com.google.api.client.http.HttpHeaders; -import com.google.api.client.http.HttpTransport; +import com.google.api.client.http.*; import com.google.api.client.json.gson.GsonFactory; import com.google.api.services.walletobjects.Walletobjects; import com.google.api.services.walletobjects.model.*; import com.google.auth.http.HttpCredentialsAdapter; import com.google.auth.oauth2.GoogleCredentials; import com.google.auth.oauth2.ServiceAccountCredentials; - -import java.io.FileInputStream; -import java.io.IOException; +import java.io.*; import java.security.interfaces.RSAPrivateKey; import java.util.*; +// [END imports] public class DemoTransit { - /** - * Path to service account key file from Google Cloud Console. Environment variable: - * GOOGLE_APPLICATION_CREDENTIALS. - */ - public static String keyFilePath; + /** + * Path to service account key file from Google Cloud Console. Environment variable: + * GOOGLE_APPLICATION_CREDENTIALS. + */ + public static String keyFilePath; - /** - * Service account credentials for Google Wallet APIs. - */ - public static GoogleCredentials credentials; + /** Service account credentials for Google Wallet APIs. */ + public static GoogleCredentials credentials; - /** - * Google Wallet service client. - */ - public static Walletobjects service; + /** Google Wallet service client. */ + public static Walletobjects service; - public DemoTransit() throws Exception { - keyFilePath = - System.getenv().getOrDefault("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/key.json"); + public DemoTransit() throws Exception { + keyFilePath = + System.getenv().getOrDefault("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/key.json"); - auth(); - } + Auth(); + } + // [END setup] - /** - * Create authenticated HTTP client using a service account file. - */ - public void auth() throws Exception { - String scope = "https://www.googleapis.com/auth/wallet_object.issuer"; + // [START auth] + /** + * Create authenticated HTTP client using a service account file. + * + * @throws Exception + */ + public void Auth() throws Exception { + String scope = "https://www.googleapis.com/auth/wallet_object.issuer"; - credentials = - GoogleCredentials.fromStream(new FileInputStream(keyFilePath)) - .createScoped(List.of(scope)); - credentials.refresh(); + credentials = + GoogleCredentials.fromStream(new FileInputStream(keyFilePath)) + .createScoped(Arrays.asList(scope)); + credentials.refresh(); - HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport(); + HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport(); - // Initialize Google Wallet API service - service = - new Walletobjects.Builder( - httpTransport, - GsonFactory.getDefaultInstance(), - new HttpCredentialsAdapter(credentials)) - .setApplicationName("APPLICATION_NAME") - .build(); - } + // Initialize Google Wallet API service + service = + new Walletobjects.Builder( + httpTransport, + GsonFactory.getDefaultInstance(), + new HttpCredentialsAdapter(credentials)) + .setApplicationName("APPLICATION_NAME") + .build(); + } + // [END auth] - /** - * Create a class. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @return The pass class ID: "{issuerId}.{classSuffix}" - */ - public String createClass(String issuerId, String classSuffix) throws IOException { - // Check if the class exists - try { - service.transitclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); - - System.out.printf("Class %s.%s already exists!%n", issuerId, classSuffix); - return String.format("%s.%s", issuerId, classSuffix); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() != 404) { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, classSuffix); - } - } - - // See link below for more information on required properties - // https://developers.google.com/wallet/tickets/transit-passes/qr-code/rest/v1/transitclass - TransitClass newClass = - new TransitClass() - .setId(String.format("%s.%s", issuerId, classSuffix)) - .setIssuerName("Issuer name") - .setReviewStatus("UNDER_REVIEW") - .setLogo( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "https://live.staticflickr.com/65535/48690277162_cd05f03f4d_o.png")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Logo description")))) - .setTransitType("BUS"); - - TransitClass response = service.transitclass().insert(newClass).execute(); - - System.out.println("Class insert response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Update a class. - * - *

Warning: This replaces all existing class attributes! - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @return The pass class ID: "{issuerId}.{classSuffix}" - */ - public String updateClass(String issuerId, String classSuffix) throws IOException { - TransitClass updatedClass; - - // Check if the class exists - try { - updatedClass = - service.transitclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Class does not exist - System.out.printf("Class %s.%s not found!%n", issuerId, classSuffix); - return String.format("%s.%s", issuerId, classSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, classSuffix); - } - } - - // Class exists - // Update the class by adding a homepage - updatedClass.setHomepageUri( - new Uri() - .setUri("https://developers.google.com/wallet") - .setDescription("Homepage description")); - - // Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates - updatedClass.setReviewStatus("UNDER_REVIEW"); - - TransitClass response = - service - .transitclass() - .update(String.format("%s.%s", issuerId, classSuffix), updatedClass) - .execute(); - - System.out.println("Class update response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Patch a class. - * - *

The PATCH method supports patch semantics. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @return The pass class ID: "{issuerId}.{classSuffix}" - */ - public String patchClass(String issuerId, String classSuffix) throws IOException { - // Check if the class exists - try { - service.transitclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Class does not exist - System.out.printf("Class %s.%s not found!%n", issuerId, classSuffix); - return String.format("%s.%s", issuerId, classSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, classSuffix); - } - } - - // Class exists - // Patch the class by adding a homepage - TransitClass patchBody = - new TransitClass() - .setHomepageUri( - new Uri() - .setUri("https://developers.google.com/wallet") - .setDescription("Homepage description")) - - // Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates - .setReviewStatus("UNDER_REVIEW"); - - TransitClass response = - service - .transitclass() - .patch(String.format("%s.%s", issuerId, classSuffix), patchBody) - .execute(); - - System.out.println("Class patch response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Add a message to a pass class. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @param header The message header. - * @param body The message body. - * @return The pass class ID: "{issuerId}.{classSuffix}" - */ - public String addClassMessage(String issuerId, String classSuffix, String header, String body) - throws IOException { - // Check if the class exists - try { - service.transitclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Class does not exist - System.out.printf("Class %s.%s not found!%n", issuerId, classSuffix); - return String.format("%s.%s", issuerId, classSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, classSuffix); - } - } - - AddMessageRequest message = - new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body)); - - TransitClassAddMessageResponse response = - service - .transitclass() - .addmessage(String.format("%s.%s", issuerId, classSuffix), message) - .execute(); - - System.out.println("Class addMessage response"); - System.out.println(response.toPrettyString()); + // [START createClass] + /** + * Create a class. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @return The pass class ID: "{issuerId}.{classSuffix}" + * @throws IOException + */ + public String CreateClass(String issuerId, String classSuffix) throws IOException { + // Check if the class exists + try { + service.transitclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); + System.out.println(String.format("Class %s.%s already exists!", issuerId, classSuffix)); + return String.format("%s.%s", issuerId, classSuffix); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() != 404) { + // Something else went wrong... + ex.printStackTrace(); return String.format("%s.%s", issuerId, classSuffix); + } } + // See link below for more information on required properties + // https://developers.google.com/wallet/tickets/transit-passes/qr-code/rest/v1/transitclass + TransitClass newClass = + new TransitClass() + .setId(String.format("%s.%s", issuerId, classSuffix)) + .setIssuerName("Issuer name") + .setReviewStatus("UNDER_REVIEW") + .setLogo( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "https://live.staticflickr.com/65535/48690277162_cd05f03f4d_o.png")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Logo description")))) + .setTransitType("BUS"); - /** - * Create an object. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String createObject(String issuerId, String classSuffix, String objectSuffix) - throws IOException { - // Check if the object exists - try { - service.transitobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + TransitClass response = service.transitclass().insert(newClass).execute(); - System.out.printf("Object %s.%s already exists!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Object does not exist - // Do nothing - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } + System.out.println("Class insert response"); + System.out.println(response.toPrettyString()); - // See link below for more information on required properties - // https://developers.google.com/wallet/tickets/transit-passes/qr-code/rest/v1/transitobject - TransitObject newObject = - new TransitObject() - .setId(String.format("%s.%s", issuerId, objectSuffix)) - .setClassId(String.format("%s.%s", issuerId, classSuffix)) - .setState("ACTIVE") - .setHeroImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Hero image description")))) - .setTextModulesData( - List.of( - new TextModuleData() - .setHeader("Text module header") - .setBody("Text module body") - .setId("TEXT_MODULE_ID"))) - .setLinksModuleData( - new LinksModuleData() - .setUris( - Arrays.asList( - new Uri() - .setUri("http://maps.google.com/") - .setDescription("Link module URI description") - .setId("LINK_MODULE_URI_ID"), - new Uri() - .setUri("tel:6505555555") - .setDescription("Link module tel description") - .setId("LINK_MODULE_TEL_ID")))) - .setImageModulesData( - List.of( - new ImageModuleData() - .setMainImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Image module description")))) - .setId("IMAGE_MODULE_ID"))) - .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) - .setLocations( - List.of( - new LatLongPoint() - .setLatitude(37.424015499999996) - .setLongitude(-122.09259560000001))) - .setPassengerType("SINGLE_PASSENGER") - .setPassengerNames("Passenger names") - .setTripType("ONE_WAY") - .setTicketLeg( - new TicketLeg() - .setOriginStationCode("LA") - .setOriginName( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Origin name"))) - .setDestinationStationCode("SFO") - .setDestinationName( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Origin name"))) - .setDepartureDateTime("2020-04-12T16:20:50.52Z") - .setArrivalDateTime("2020-04-12T20:20:50.52Z") - .setFareName( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Fare name")))); + return response.getId(); + } + // [END createClass] - TransitObject response = service.transitobject().insert(newObject).execute(); + // [START updateClass] + /** + * Update a class. + * + *

Warning: This replaces all existing class attributes! + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @return The pass class ID: "{issuerId}.{classSuffix}" + * @throws IOException + */ + public String UpdateClass(String issuerId, String classSuffix) throws IOException { + TransitClass updatedClass; - System.out.println("Object insert response"); - System.out.println(response.toPrettyString()); - - return response.getId(); + // Check if the class exists + try { + updatedClass = + service.transitclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Class does not exist + System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix)); + return String.format("%s.%s", issuerId, classSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, classSuffix); + } } + // Class exists + // Update the class by adding a homepage + updatedClass.setHomepageUri( + new Uri() + .setUri("https://developers.google.com/wallet") + .setDescription("Homepage description")); - /** - * Update an object. - * - *

Warning: This replaces all existing object attributes! - * - * @param issuerId The issuer ID being used for this request. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String updateObject(String issuerId, String objectSuffix) throws IOException { - TransitObject updatedObject; + // Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates + updatedClass.setReviewStatus("UNDER_REVIEW"); - // Check if the object exists - try { - updatedObject = - service.transitobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Object does not exist - System.out.printf("Object %s.%s not found!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } + TransitClass response = + service + .transitclass() + .update(String.format("%s.%s", issuerId, classSuffix), updatedClass) + .execute(); - // Object exists - // Update the object by adding a link - Uri newLink = + System.out.println("Class update response"); + System.out.println(response.toPrettyString()); + + return response.getId(); + } + // [END updateClass] + + // [START patchClass] + /** + * Patch a class. + * + *

The PATCH method supports patch semantics. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @return The pass class ID: "{issuerId}.{classSuffix}" + * @throws IOException + */ + public String PatchClass(String issuerId, String classSuffix) throws IOException { + // Check if the class exists + try { + service.transitclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Class does not exist + System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix)); + return String.format("%s.%s", issuerId, classSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, classSuffix); + } + } + + // Class exists + // Patch the class by adding a homepage + TransitClass patchBody = + new TransitClass() + .setHomepageUri( new Uri() - .setUri("https://developers.google.com/wallet") - .setDescription("New link description"); + .setUri("https://developers.google.com/wallet") + .setDescription("Homepage description")) - if (updatedObject.getLinksModuleData() == null) { - // LinksModuleData was not set on the original object - updatedObject.setLinksModuleData(new LinksModuleData().setUris(List.of(newLink))); - } else { - updatedObject.getLinksModuleData().getUris().add(newLink); - } + // Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates + .setReviewStatus("UNDER_REVIEW"); - TransitObject response = - service - .transitobject() - .update(String.format("%s.%s", issuerId, objectSuffix), updatedObject) - .execute(); + TransitClass response = + service + .transitclass() + .patch(String.format("%s.%s", issuerId, classSuffix), patchBody) + .execute(); - System.out.println("Object update response"); - System.out.println(response.toPrettyString()); + System.out.println("Class patch response"); + System.out.println(response.toPrettyString()); - return response.getId(); + return response.getId(); + } + // [END patchClass] + + // [START addMessageClass] + /** + * Add a message to a pass class. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @param header The message header. + * @param body The message body. + * @return The pass class ID: "{issuerId}.{classSuffix}" + * @throws IOException + */ + public String AddClassMessage(String issuerId, String classSuffix, String header, String body) + throws IOException { + // Check if the class exists + try { + service.transitclass().get(String.format("%s.%s", issuerId, classSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Class does not exist + System.out.println(String.format("Class %s.%s not found!", issuerId, classSuffix)); + return String.format("%s.%s", issuerId, classSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, classSuffix); + } } - /** - * Patch an object. - * - * @param issuerId The issuer ID being used for this request. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String patchObject(String issuerId, String objectSuffix) throws IOException { - TransitObject existingObject; + AddMessageRequest message = + new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body)); - // Check if the object exists - try { - existingObject = - service.transitobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Object does not exist - System.out.printf("Object %s.%s not found!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } + TransitClassAddMessageResponse response = + service + .transitclass() + .addmessage(String.format("%s.%s", issuerId, classSuffix), message) + .execute(); - // Object exists - // Patch the object by adding a link - Uri newLink = - new Uri() - .setUri("https://developers.google.com/wallet") - .setDescription("New link description"); + System.out.println("Class addMessage response"); + System.out.println(response.toPrettyString()); - TransitObject patchBody = new TransitObject(); + return String.format("%s.%s", issuerId, classSuffix); + } + // [END addMessageClass] - if (existingObject.getLinksModuleData() == null) { - // LinksModuleData was not set on the original object - patchBody.setLinksModuleData(new LinksModuleData().setUris(new ArrayList())); - } else { - patchBody.setLinksModuleData(existingObject.getLinksModuleData()); - } - patchBody.getLinksModuleData().getUris().add(newLink); - - TransitObject response = - service - .transitobject() - .patch(String.format("%s.%s", issuerId, objectSuffix), patchBody) - .execute(); - - System.out.println("Object patch response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Expire an object. - * - *

Sets the object's state to Expired. If the valid time interval is already set, the pass will - * expire automatically up to 24 hours after. - * - * @param issuerId The issuer ID being used for this request. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String expireObject(String issuerId, String objectSuffix) throws IOException { - // Check if the object exists - try { - service.transitobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Object does not exist - System.out.printf("Object %s.%s not found!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } - - // Patch the object, setting the pass as expired - TransitObject patchBody = new TransitObject().setState("EXPIRED"); - - TransitObject response = - service - .transitobject() - .patch(String.format("%s.%s", issuerId, objectSuffix), patchBody) - .execute(); - - System.out.println("Object expiration response"); - System.out.println(response.toPrettyString()); - - return response.getId(); - } - - /** - * Add a message to a pass object. - * - * @param issuerId The issuer ID being used for this request. - * @param objectSuffix Developer-defined unique ID for this pass object. - * @param header The message header. - * @param body The message body. - * @return The pass object ID: "{issuerId}.{objectSuffix}" - */ - public String addObjectMessage(String issuerId, String objectSuffix, String header, String body) - throws IOException { - // Check if the object exists - try { - service.transitobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); - } catch (GoogleJsonResponseException ex) { - if (ex.getStatusCode() == 404) { - // Object does not exist - System.out.printf("Object %s.%s not found!%n", issuerId, objectSuffix); - return String.format("%s.%s", issuerId, objectSuffix); - } else { - // Something else went wrong... - ex.printStackTrace(); - return String.format("%s.%s", issuerId, objectSuffix); - } - } - - AddMessageRequest message = - new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body)); - - TransitObjectAddMessageResponse response = - service - .transitobject() - .addmessage(String.format("%s.%s", issuerId, objectSuffix), message) - .execute(); - - System.out.println("Object addMessage response"); - System.out.println(response.toPrettyString()); + // [START createObject] + /** + * Create an object. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String CreateObject(String issuerId, String classSuffix, String objectSuffix) + throws IOException { + // Check if the object exists + try { + service.transitobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + System.out.println(String.format("Object %s.%s already exists!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Object does not exist + // Do nothing + } else { + // Something else went wrong... + ex.printStackTrace(); return String.format("%s.%s", issuerId, objectSuffix); + } } - /** - * Generate a signed JWT that creates a new pass class and object. - * - *

When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the - * pass class and object defined in the JWT are created. This allows you to create multiple pass - * classes and objects in one API call when the user saves the pass to their wallet. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - * @param objectSuffix Developer-defined unique ID for the pass object. - * @return An "Add to Google Wallet" link. - */ - public String createJWTNewObjects(String issuerId, String classSuffix, String objectSuffix) { - // See link below for more information on required properties - // https://developers.google.com/wallet/tickets/transit-passes/qr-code/rest/v1/transitclass - TransitClass newClass = - new TransitClass() - .setId(String.format("%s.%s", issuerId, classSuffix)) - .setIssuerName("Issuer name") - .setReviewStatus("UNDER_REVIEW") - .setLogo( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "https://live.staticflickr.com/65535/48690277162_cd05f03f4d_o.png")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Logo description")))) - .setTransitType("BUS"); + // See link below for more information on required properties + // https://developers.google.com/wallet/tickets/transit-passes/qr-code/rest/v1/transitobject + TransitObject newObject = + new TransitObject() + .setId(String.format("%s.%s", issuerId, objectSuffix)) + .setClassId(String.format("%s.%s", issuerId, classSuffix)) + .setState("ACTIVE") + .setHeroImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Hero image description")))) + .setTextModulesData( + Arrays.asList( + new TextModuleData() + .setHeader("Text module header") + .setBody("Text module body") + .setId("TEXT_MODULE_ID"))) + .setLinksModuleData( + new LinksModuleData() + .setUris( + Arrays.asList( + new Uri() + .setUri("http://maps.google.com/") + .setDescription("Link module URI description") + .setId("LINK_MODULE_URI_ID"), + new Uri() + .setUri("tel:6505555555") + .setDescription("Link module tel description") + .setId("LINK_MODULE_TEL_ID")))) + .setImageModulesData( + Arrays.asList( + new ImageModuleData() + .setMainImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Image module description")))) + .setId("IMAGE_MODULE_ID"))) + .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) + .setLocations( + Arrays.asList( + new LatLongPoint() + .setLatitude(37.424015499999996) + .setLongitude(-122.09259560000001))) + .setPassengerType("SINGLE_PASSENGER") + .setPassengerNames("Passenger names") + .setTripType("ONE_WAY") + .setTicketLeg( + new TicketLeg() + .setOriginStationCode("LA") + .setOriginName( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Origin name"))) + .setDestinationStationCode("SFO") + .setDestinationName( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Origin name"))) + .setDepartureDateTime("2020-04-12T16:20:50.52Z") + .setArrivalDateTime("2020-04-12T20:20:50.52Z") + .setFareName( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Fare name")))); - // See link below for more information on required properties - // https://developers.google.com/wallet/tickets/transit-passes/qr-code/rest/v1/transitobject - TransitObject newObject = - new TransitObject() - .setId(String.format("%s.%s", issuerId, objectSuffix)) - .setClassId(String.format("%s.%s", issuerId, classSuffix)) - .setState("ACTIVE") - .setHeroImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Hero image description")))) - .setTextModulesData( - List.of( - new TextModuleData() - .setHeader("Text module header") - .setBody("Text module body") - .setId("TEXT_MODULE_ID"))) - .setLinksModuleData( - new LinksModuleData() - .setUris( - Arrays.asList( - new Uri() - .setUri("http://maps.google.com/") - .setDescription("Link module URI description") - .setId("LINK_MODULE_URI_ID"), - new Uri() - .setUri("tel:6505555555") - .setDescription("Link module tel description") - .setId("LINK_MODULE_TEL_ID")))) - .setImageModulesData( - List.of( - new ImageModuleData() - .setMainImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Image module description")))) - .setId("IMAGE_MODULE_ID"))) - .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) - .setLocations( - List.of( - new LatLongPoint() - .setLatitude(37.424015499999996) - .setLongitude(-122.09259560000001))) - .setPassengerType("SINGLE_PASSENGER") - .setPassengerNames("Passenger names") - .setTripType("ONE_WAY") - .setTicketLeg( - new TicketLeg() - .setOriginStationCode("LA") - .setOriginName( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Origin name"))) - .setDestinationStationCode("SFO") - .setDestinationName( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Origin name"))) - .setDepartureDateTime("2020-04-12T16:20:50.52Z") - .setArrivalDateTime("2020-04-12T20:20:50.52Z") - .setFareName( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Fare name")))); + TransitObject response = service.transitobject().insert(newObject).execute(); - // Create the JWT as a HashMap object - HashMap claims = new HashMap(); - claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail()); - claims.put("aud", "google"); - claims.put("origins", List.of("www.example.com")); - claims.put("typ", "savetowallet"); + System.out.println("Object insert response"); + System.out.println(response.toPrettyString()); - // Create the Google Wallet payload and add to the JWT - HashMap payload = new HashMap(); - payload.put("transitClasses", List.of(newClass)); - payload.put("transitObjects", List.of(newObject)); - claims.put("payload", payload); + return response.getId(); + } + // [END createObject] - // The service account credentials are used to sign the JWT - Algorithm algorithm = - Algorithm.RSA256( - null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); - String token = JWT.create().withPayload(claims).sign(algorithm); + // [START updateObject] + /** + * Update an object. + * + *

Warning: This replaces all existing object attributes! + * + * @param issuerId The issuer ID being used for this request. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String UpdateObject(String issuerId, String objectSuffix) throws IOException { + TransitObject updatedObject; - System.out.println("Add to Google Wallet link"); - System.out.printf("https://pay.google.com/gp/v/save/%s%n", token); - - return String.format("https://pay.google.com/gp/v/save/%s", token); + // Check if the object exists + try { + updatedObject = + service.transitobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Object does not exist + System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, objectSuffix); + } } - /** - * Generate a signed JWT that references an existing pass object. - * - *

When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the - * pass objects defined in the JWT are added to the user's Google Wallet app. This allows the user - * to save multiple pass objects in one API call. - * - *

The objects to add must follow the below format: - * - *

{ 'id': 'ISSUER_ID.OBJECT_SUFFIX', 'classId': 'ISSUER_ID.CLASS_SUFFIX' } - * - * @param issuerId The issuer ID being used for this request. - * @return An "Add to Google Wallet" link. - */ - public String createJWTExistingObjects(String issuerId) { - // Multiple pass types can be added at the same time - // At least one type must be specified in the JWT claims - // Note: Make sure to replace the placeholder class and object suffixes - HashMap objectsToAdd = new HashMap(); + // Object exists + // Update the object by adding a link + Uri newLink = + new Uri() + .setUri("https://developers.google.com/wallet") + .setDescription("New link description"); - // Event tickets - objectsToAdd.put( - "eventTicketObjects", - List.of( - new EventTicketObject() - .setId(String.format("%s.%s", issuerId, "EVENT_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "EVENT_CLASS_SUFFIX")))); - - // Boarding passes - objectsToAdd.put( - "flightObjects", - List.of( - new FlightObject() - .setId(String.format("%s.%s", issuerId, "FLIGHT_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "FLIGHT_CLASS_SUFFIX")))); - - // Generic passes - objectsToAdd.put( - "genericObjects", - List.of( - new GenericObject() - .setId(String.format("%s.%s", issuerId, "GENERIC_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "GENERIC_CLASS_SUFFIX")))); - - // Gift cards - objectsToAdd.put( - "giftCardObjects", - List.of( - new GiftCardObject() - .setId(String.format("%s.%s", issuerId, "GIFT_CARD_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "GIFT_CARD_CLASS_SUFFIX")))); - - // Loyalty cards - objectsToAdd.put( - "loyaltyObjects", - List.of( - new LoyaltyObject() - .setId(String.format("%s.%s", issuerId, "LOYALTY_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "LOYALTY_CLASS_SUFFIX")))); - - // Offers - objectsToAdd.put( - "offerObjects", - List.of( - new OfferObject() - .setId(String.format("%s.%s", issuerId, "OFFER_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "OFFER_CLASS_SUFFIX")))); - - // Transit passes - objectsToAdd.put( - "transitObjects", - List.of( - new TransitObject() - .setId(String.format("%s.%s", issuerId, "TRANSIT_OBJECT_SUFFIX")) - .setClassId(String.format("%s.%s", issuerId, "TRANSIT_CLASS_SUFFIX")))); - - // Create the JWT as a HashMap object - HashMap claims = new HashMap(); - claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail()); - claims.put("aud", "google"); - claims.put("origins", List.of("www.example.com")); - claims.put("typ", "savetowallet"); - claims.put("payload", objectsToAdd); - - // The service account credentials are used to sign the JWT - Algorithm algorithm = - Algorithm.RSA256( - null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); - String token = JWT.create().withPayload(claims).sign(algorithm); - - System.out.println("Add to Google Wallet link"); - System.out.printf("https://pay.google.com/gp/v/save/%s%n", token); - - return String.format("https://pay.google.com/gp/v/save/%s", token); + if (updatedObject.getLinksModuleData() == null) { + // LinksModuleData was not set on the original object + updatedObject.setLinksModuleData(new LinksModuleData().setUris(Arrays.asList(newLink))); + } else { + updatedObject.getLinksModuleData().getUris().add(newLink); } - /** - * Batch create Google Wallet objects from an existing class. - * - * @param issuerId The issuer ID being used for this request. - * @param classSuffix Developer-defined unique ID for this pass class. - */ - public void batchCreateObjects(String issuerId, String classSuffix) throws IOException { - // Create the batch request client - BatchRequest batch = service.batch(new HttpCredentialsAdapter(credentials)); + TransitObject response = + service + .transitobject() + .update(String.format("%s.%s", issuerId, objectSuffix), updatedObject) + .execute(); - // The callback will be invoked for each request in the batch - JsonBatchCallback callback = - new JsonBatchCallback() { - // Invoked if the request was successful - public void onSuccess(TransitObject response, HttpHeaders responseHeaders) { - System.out.println("Batch insert response"); - System.out.println(response.toString()); - } + System.out.println("Object update response"); + System.out.println(response.toPrettyString()); - // Invoked if the request failed - public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) { - System.out.println("Error Message: " + e.getMessage()); - } - }; + return response.getId(); + } + // [END updateObject] - // Example: Generate three new pass objects - for (int i = 0; i < 3; i++) { - // Generate a random object suffix - String objectSuffix = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_"); + // [START patchObject] + /** + * Patch an object. + * + * @param issuerId The issuer ID being used for this request. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String PatchObject(String issuerId, String objectSuffix) throws IOException { + TransitObject existingObject; - // See link below for more information on required properties - // https://developers.google.com/wallet/tickets/transit-passes/qr-code/rest/v1/transitobject - TransitObject batchObject = - new TransitObject() - .setId(String.format("%s.%s", issuerId, objectSuffix)) - .setClassId(String.format("%s.%s", issuerId, classSuffix)) - .setState("ACTIVE") - .setHeroImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Hero image description")))) - .setTextModulesData( - List.of( - new TextModuleData() - .setHeader("Text module header") - .setBody("Text module body") - .setId("TEXT_MODULE_ID"))) - .setLinksModuleData( - new LinksModuleData() - .setUris( - Arrays.asList( - new Uri() - .setUri("http://maps.google.com/") - .setDescription("Link module URI description") - .setId("LINK_MODULE_URI_ID"), - new Uri() - .setUri("tel:6505555555") - .setDescription("Link module tel description") - .setId("LINK_MODULE_TEL_ID")))) - .setImageModulesData( - List.of( - new ImageModuleData() - .setMainImage( - new Image() - .setSourceUri( - new ImageUri() - .setUri( - "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) - .setContentDescription( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Image module description")))) - .setId("IMAGE_MODULE_ID"))) - .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) - .setLocations( - List.of( - new LatLongPoint() - .setLatitude(37.424015499999996) - .setLongitude(-122.09259560000001))) - .setPassengerType("SINGLE_PASSENGER") - .setPassengerNames("Passenger names") - .setTripType("ONE_WAY") - .setTicketLeg( - new TicketLeg() - .setOriginStationCode("LA") - .setOriginName( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Origin name"))) - .setDestinationStationCode("SFO") - .setDestinationName( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Origin name"))) - .setDepartureDateTime("2020-04-12T16:20:50.52Z") - .setArrivalDateTime("2020-04-12T20:20:50.52Z") - .setFareName( - new LocalizedString() - .setDefaultValue( - new TranslatedString() - .setLanguage("en-US") - .setValue("Fare name")))); - - service.transitobject().insert(batchObject).queue(batch, callback); - } - - // Invoke the batch API calls - batch.execute(); + // Check if the object exists + try { + existingObject = + service.transitobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Object does not exist + System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, objectSuffix); + } } + // Object exists + // Patch the object by adding a link + Uri newLink = + new Uri() + .setUri("https://developers.google.com/wallet") + .setDescription("New link description"); + + TransitObject patchBody = new TransitObject(); + + if (existingObject.getLinksModuleData() == null) { + // LinksModuleData was not set on the original object + patchBody.setLinksModuleData(new LinksModuleData().setUris(new ArrayList())); + } else { + patchBody.setLinksModuleData(existingObject.getLinksModuleData()); + } + patchBody.getLinksModuleData().getUris().add(newLink); + + TransitObject response = + service + .transitobject() + .patch(String.format("%s.%s", issuerId, objectSuffix), patchBody) + .execute(); + + System.out.println("Object patch response"); + System.out.println(response.toPrettyString()); + + return response.getId(); + } + // [END patchObject] + + // [START expireObject] + /** + * Expire an object. + * + *

Sets the object's state to Expired. If the valid time interval is already set, the pass will + * expire automatically up to 24 hours after. + * + * @param issuerId The issuer ID being used for this request. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String ExpireObject(String issuerId, String objectSuffix) throws IOException { + // Check if the object exists + try { + service.transitobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Object does not exist + System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, objectSuffix); + } + } + + // Patch the object, setting the pass as expired + TransitObject patchBody = new TransitObject().setState("EXPIRED"); + + TransitObject response = + service + .transitobject() + .patch(String.format("%s.%s", issuerId, objectSuffix), patchBody) + .execute(); + + System.out.println("Object expiration response"); + System.out.println(response.toPrettyString()); + + return response.getId(); + } + // [END expireObject] + + // [START addMessageObject] + /** + * Add a message to a pass object. + * + * @param issuerId The issuer ID being used for this request. + * @param objectSuffix Developer-defined unique ID for this pass object. + * @param header The message header. + * @param body The message body. + * @return The pass object ID: "{issuerId}.{objectSuffix}" + * @throws IOException + */ + public String AddObjectMessage(String issuerId, String objectSuffix, String header, String body) + throws IOException { + // Check if the object exists + try { + service.transitobject().get(String.format("%s.%s", issuerId, objectSuffix)).execute(); + } catch (GoogleJsonResponseException ex) { + if (ex.getStatusCode() == 404) { + // Object does not exist + System.out.println(String.format("Object %s.%s not found!", issuerId, objectSuffix)); + return String.format("%s.%s", issuerId, objectSuffix); + } else { + // Something else went wrong... + ex.printStackTrace(); + return String.format("%s.%s", issuerId, objectSuffix); + } + } + + AddMessageRequest message = + new AddMessageRequest().setMessage(new Message().setHeader(header).setBody(body)); + + TransitObjectAddMessageResponse response = + service + .transitobject() + .addmessage(String.format("%s.%s", issuerId, objectSuffix), message) + .execute(); + + System.out.println("Object addMessage response"); + System.out.println(response.toPrettyString()); + + return String.format("%s.%s", issuerId, objectSuffix); + } + // [END addMessageObject] + + // [START jwtNew] + /** + * Generate a signed JWT that creates a new pass class and object. + * + *

When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the + * pass class and object defined in the JWT are created. This allows you to create multiple pass + * classes and objects in one API call when the user saves the pass to their wallet. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @param objectSuffix Developer-defined unique ID for the pass object. + * @return An "Add to Google Wallet" link. + */ + public String CreateJWTNewObjects(String issuerId, String classSuffix, String objectSuffix) { + // See link below for more information on required properties + // https://developers.google.com/wallet/tickets/transit-passes/qr-code/rest/v1/transitclass + TransitClass newClass = + new TransitClass() + .setId(String.format("%s.%s", issuerId, classSuffix)) + .setIssuerName("Issuer name") + .setReviewStatus("UNDER_REVIEW") + .setLogo( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "https://live.staticflickr.com/65535/48690277162_cd05f03f4d_o.png")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Logo description")))) + .setTransitType("BUS"); + + // See link below for more information on required properties + // https://developers.google.com/wallet/tickets/transit-passes/qr-code/rest/v1/transitobject + TransitObject newObject = + new TransitObject() + .setId(String.format("%s.%s", issuerId, objectSuffix)) + .setClassId(String.format("%s.%s", issuerId, classSuffix)) + .setState("ACTIVE") + .setHeroImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Hero image description")))) + .setTextModulesData( + Arrays.asList( + new TextModuleData() + .setHeader("Text module header") + .setBody("Text module body") + .setId("TEXT_MODULE_ID"))) + .setLinksModuleData( + new LinksModuleData() + .setUris( + Arrays.asList( + new Uri() + .setUri("http://maps.google.com/") + .setDescription("Link module URI description") + .setId("LINK_MODULE_URI_ID"), + new Uri() + .setUri("tel:6505555555") + .setDescription("Link module tel description") + .setId("LINK_MODULE_TEL_ID")))) + .setImageModulesData( + Arrays.asList( + new ImageModuleData() + .setMainImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Image module description")))) + .setId("IMAGE_MODULE_ID"))) + .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) + .setLocations( + Arrays.asList( + new LatLongPoint() + .setLatitude(37.424015499999996) + .setLongitude(-122.09259560000001))) + .setPassengerType("SINGLE_PASSENGER") + .setPassengerNames("Passenger names") + .setTripType("ONE_WAY") + .setTicketLeg( + new TicketLeg() + .setOriginStationCode("LA") + .setOriginName( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Origin name"))) + .setDestinationStationCode("SFO") + .setDestinationName( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Origin name"))) + .setDepartureDateTime("2020-04-12T16:20:50.52Z") + .setArrivalDateTime("2020-04-12T20:20:50.52Z") + .setFareName( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Fare name")))); + + // Create the JWT as a HashMap object + HashMap claims = new HashMap(); + claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail()); + claims.put("aud", "google"); + claims.put("origins", Arrays.asList("www.example.com")); + claims.put("typ", "savetowallet"); + + // Create the Google Wallet payload and add to the JWT + HashMap payload = new HashMap(); + payload.put("transitClasses", Arrays.asList(newClass)); + payload.put("transitObjects", Arrays.asList(newObject)); + claims.put("payload", payload); + + // The service account credentials are used to sign the JWT + Algorithm algorithm = + Algorithm.RSA256( + null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); + String token = JWT.create().withPayload(claims).sign(algorithm); + + System.out.println("Add to Google Wallet link"); + System.out.println(String.format("https://pay.google.com/gp/v/save/%s", token)); + + return String.format("https://pay.google.com/gp/v/save/%s", token); + } + // [END jwtNew] + + // [START jwtExisting] + /** + * Generate a signed JWT that references an existing pass object. + * + *

When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the + * pass objects defined in the JWT are added to the user's Google Wallet app. This allows the user + * to save multiple pass objects in one API call. + * + *

The objects to add must follow the below format: + * + *

{ 'id': 'ISSUER_ID.OBJECT_SUFFIX', 'classId': 'ISSUER_ID.CLASS_SUFFIX' } + * + * @param issuerId The issuer ID being used for this request. + * @return An "Add to Google Wallet" link. + */ + public String CreateJWTExistingObjects(String issuerId) { + // Multiple pass types can be added at the same time + // At least one type must be specified in the JWT claims + // Note: Make sure to replace the placeholder class and object suffixes + HashMap objectsToAdd = new HashMap(); + + // Event tickets + objectsToAdd.put( + "eventTicketObjects", + Arrays.asList( + new EventTicketObject() + .setId(String.format("%s.%s", issuerId, "EVENT_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "EVENT_CLASS_SUFFIX")))); + + // Boarding passes + objectsToAdd.put( + "flightObjects", + Arrays.asList( + new FlightObject() + .setId(String.format("%s.%s", issuerId, "FLIGHT_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "FLIGHT_CLASS_SUFFIX")))); + + // Generic passes + objectsToAdd.put( + "genericObjects", + Arrays.asList( + new GenericObject() + .setId(String.format("%s.%s", issuerId, "GENERIC_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "GENERIC_CLASS_SUFFIX")))); + + // Gift cards + objectsToAdd.put( + "giftCardObjects", + Arrays.asList( + new GiftCardObject() + .setId(String.format("%s.%s", issuerId, "GIFT_CARD_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "GIFT_CARD_CLASS_SUFFIX")))); + + // Loyalty cards + objectsToAdd.put( + "loyaltyObjects", + Arrays.asList( + new LoyaltyObject() + .setId(String.format("%s.%s", issuerId, "LOYALTY_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "LOYALTY_CLASS_SUFFIX")))); + + // Offers + objectsToAdd.put( + "offerObjects", + Arrays.asList( + new OfferObject() + .setId(String.format("%s.%s", issuerId, "OFFER_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "OFFER_CLASS_SUFFIX")))); + + // Transit passes + objectsToAdd.put( + "transitObjects", + Arrays.asList( + new TransitObject() + .setId(String.format("%s.%s", issuerId, "TRANSIT_OBJECT_SUFFIX")) + .setClassId(String.format("%s.%s", issuerId, "TRANSIT_CLASS_SUFFIX")))); + + // Create the JWT as a HashMap object + HashMap claims = new HashMap(); + claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail()); + claims.put("aud", "google"); + claims.put("origins", Arrays.asList("www.example.com")); + claims.put("typ", "savetowallet"); + claims.put("payload", objectsToAdd); + + // The service account credentials are used to sign the JWT + Algorithm algorithm = + Algorithm.RSA256( + null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); + String token = JWT.create().withPayload(claims).sign(algorithm); + + System.out.println("Add to Google Wallet link"); + System.out.println(String.format("https://pay.google.com/gp/v/save/%s", token)); + + return String.format("https://pay.google.com/gp/v/save/%s", token); + } + // [END jwtExisting] + + // [START batch] + /** + * Batch create Google Wallet objects from an existing class. + * + * @param issuerId The issuer ID being used for this request. + * @param classSuffix Developer-defined unique ID for this pass class. + * @throws IOException + */ + public void BatchCreateObjects(String issuerId, String classSuffix) throws IOException { + // Create the batch request client + BatchRequest batch = service.batch(new HttpCredentialsAdapter(credentials)); + + // The callback will be invoked for each request in the batch + JsonBatchCallback callback = + new JsonBatchCallback() { + // Invoked if the request was successful + public void onSuccess(TransitObject response, HttpHeaders responseHeaders) { + System.out.println("Batch insert response"); + System.out.println(response.toString()); + } + + // Invoked if the request failed + public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) { + System.out.println("Error Message: " + e.getMessage()); + } + }; + + // Example: Generate three new pass objects + for (int i = 0; i < 3; i++) { + // Generate a random object suffix + String objectSuffix = UUID.randomUUID().toString().replaceAll("[^\\w.-]", "_"); + + // See link below for more information on required properties + // https://developers.google.com/wallet/tickets/transit-passes/qr-code/rest/v1/transitobject + TransitObject batchObject = + new TransitObject() + .setId(String.format("%s.%s", issuerId, objectSuffix)) + .setClassId(String.format("%s.%s", issuerId, classSuffix)) + .setState("ACTIVE") + .setHeroImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Hero image description")))) + .setTextModulesData( + Arrays.asList( + new TextModuleData() + .setHeader("Text module header") + .setBody("Text module body") + .setId("TEXT_MODULE_ID"))) + .setLinksModuleData( + new LinksModuleData() + .setUris( + Arrays.asList( + new Uri() + .setUri("http://maps.google.com/") + .setDescription("Link module URI description") + .setId("LINK_MODULE_URI_ID"), + new Uri() + .setUri("tel:6505555555") + .setDescription("Link module tel description") + .setId("LINK_MODULE_TEL_ID")))) + .setImageModulesData( + Arrays.asList( + new ImageModuleData() + .setMainImage( + new Image() + .setSourceUri( + new ImageUri() + .setUri( + "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) + .setContentDescription( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Image module description")))) + .setId("IMAGE_MODULE_ID"))) + .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) + .setLocations( + Arrays.asList( + new LatLongPoint() + .setLatitude(37.424015499999996) + .setLongitude(-122.09259560000001))) + .setPassengerType("SINGLE_PASSENGER") + .setPassengerNames("Passenger names") + .setTripType("ONE_WAY") + .setTicketLeg( + new TicketLeg() + .setOriginStationCode("LA") + .setOriginName( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Origin name"))) + .setDestinationStationCode("SFO") + .setDestinationName( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Origin name"))) + .setDepartureDateTime("2020-04-12T16:20:50.52Z") + .setArrivalDateTime("2020-04-12T20:20:50.52Z") + .setFareName( + new LocalizedString() + .setDefaultValue( + new TranslatedString() + .setLanguage("en-US") + .setValue("Fare name")))); + + service.transitobject().insert(batchObject).queue(batch, callback); + } + + // Invoke the batch API calls + batch.execute(); + } + // [END batch] }