From eadbe0c43abbdce67057a3df8a9ab3ac5285f728 Mon Sep 17 00:00:00 2001 From: Matthew Podwysocki Date: Tue, 13 Oct 2020 18:05:26 -0400 Subject: [PATCH 1/7] Updating to 0.4 --- .gitattributes | 29 +++++++++++++++++++++++++++++ CONTRIBUTING.md | 35 +++++++++++++++++++++++++++++++++++ NotificationHubs/.classpath | 2 +- NotificationHubs/.project | 11 +++++++++++ NotificationHubs/pom.xml | 8 ++++++-- README.md | 22 +++++++++++++--------- 6 files changed, 95 insertions(+), 12 deletions(-) create mode 100644 .gitattributes create mode 100644 CONTRIBUTING.md diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..e6fd581 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,29 @@ +# Handle line endings automatically for files detected as text +# and leave all files detected as binary untouched. +* text=auto + +# These files are text and should be normalized (Convert crlf => lf) +*.css text +*.htm text +*.html text +*.java text +*.js text +*.json text +*.jsp text +*.jspf text +*.jspx text +*.properties text +*.sh text +*.txt text +*.xml text +*.yml text + +# These files are binary and should be left untouched +# (binary is a macro for -text -diff) +*.class binary +*.dll binary +*.ear binary +*.ico binary +*.jar binary +*.so binary +*.war binary diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..344d741 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,35 @@ +Azure Notification Hubs for Java SDK Contributing Guide +------------------------------------- + +Thank you for your interest in contributing to Azure Notification Hubs for Java SDK C. + +- For reporting bugs, requesting features, or asking for support, please file an issue in the [issues](https://github.com/Azure/azure-sdk-for-java/issues) section of the project. + +- If you would like to become an active contributor to this project please follow the instructions provided in [Microsoft Azure Projects Contribution Guidelines](http://azure.github.com/guidelines.html). + +- To make code changes, or contribute something new, please follow the [GitHub Forks / Pull requests model](https://help.github.com/articles/fork-a-repo/): Fork the repo, make the change and propose it back by submitting a pull request. + +Pull Requests +------------- + +- **DO** submit all code changes via pull requests (PRs) rather than through a direct commit. PRs will be reviewed and potentially merged by the repo maintainers after a peer review that includes at least one maintainer. +- **DO NOT** submit "work in progress" PRs. A PR should only be submitted when it is considered ready for review and subsequent merging by the contributor. +- **DO** give PRs short-but-descriptive names (e.g. "Improve code coverage for Azure.Core by 10%", not "Fix #1234") +- **DO** refer to any relevant issues, and include [keywords](https://help.github.com/articles/closing-issues-via-commit-messages/) that automatically close issues when the PR is merged. +- **DO** tag any users that should know about and/or review the change. +- **DO** ensure each commit successfully builds. The entire PR must pass all tests in the Continuous Integration (CI) system before it'll be merged. +- **DO** address PR feedback in an additional commit(s) rather than amending the existing commits, and only rebase/squash them when necessary. This makes it easier for reviewers to track changes. +- **DO** assume that ["Squash and Merge"](https://github.com/blog/2141-squash-your-commits) will be used to merge your commit unless you request otherwise in the PR. +- **DO NOT** fix merge conflicts using a merge commit. Prefer `git rebase`. +- **DO NOT** mix independent, unrelated changes in one PR. Separate real product/test code changes from larger code formatting/dead code removal changes. Separate unrelated fixes into separate PRs, especially if they are in different assemblies. + +Merging Pull Requests (for project contributors with write access) +---------------------------------------------------------- + +- **DO** use ["Squash and Merge"](https://github.com/blog/2141-squash-your-commits) by default for individual contributions unless requested by the PR author. + Do so, even if the PR contains only one commit. It creates a simpler history than "Create a Merge Commit". + Reasons that PR authors may request "Merge and Commit" may include (but are not limited to): + + - The change is easier to understand as a series of focused commits. Each commit in the series must be buildable so as not to break `git bisect`. + - Contributor is using an e-mail address other than the primary GitHub address and wants that preserved in the history. Contributor must be willing to squash + the commits manually before acceptance. diff --git a/NotificationHubs/.classpath b/NotificationHubs/.classpath index f9a09e3..5bc3156 100644 --- a/NotificationHubs/.classpath +++ b/NotificationHubs/.classpath @@ -14,7 +14,7 @@ - + diff --git a/NotificationHubs/.project b/NotificationHubs/.project index 6605d62..52dcd26 100644 --- a/NotificationHubs/.project +++ b/NotificationHubs/.project @@ -20,4 +20,15 @@ org.eclipse.m2e.core.maven2Nature org.eclipse.jdt.core.javanature + + + 1602612759974 + + 30 + + org.eclipse.core.resources.regexFilterMatcher + node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + + + diff --git a/NotificationHubs/pom.xml b/NotificationHubs/pom.xml index 9b8b572..dee695c 100644 --- a/NotificationHubs/pom.xml +++ b/NotificationHubs/pom.xml @@ -3,8 +3,11 @@ 4.0.0 com.windowsazure Notification-Hubs-java-sdk - 0.3.0 + 0.4.0 Windows Azure Notification Hubs Java SDK + + UTF-8 + src test @@ -35,7 +38,6 @@ - enforce @@ -52,6 +54,7 @@ org.apache.maven.plugins maven-dependency-plugin + 3.1.2 analyze-dependencies @@ -68,6 +71,7 @@ org.apache.maven.plugins maven-compiler-plugin + 3.8.1 8 8 diff --git a/README.md b/README.md index 00e5dbc..e0d88a4 100644 --- a/README.md +++ b/README.md @@ -394,14 +394,18 @@ List allJobs = hub.getAllNotificationHubJobs() ## Contributing -This project welcomes contributions and suggestions. Most contributions require you to agree to a -Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us -the rights to use your contribution. For details, visit https://cla.microsoft.com. +For details on contributing to this repository, see the [contributing guide](https://github.com/Azure/azure-notificationhubs-java-backend/blob/main/CONTRIBUTING.md). -When you submit a pull request, a CLA-bot will automatically determine whether you need to provide -a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions -provided by the bot. You will only need to do this once across all repos using our CLA. +This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, view [Microsoft's CLA](https://cla.microsoft.com). -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). -For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or -contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. +When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repositories using our CLA. + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. + +## Reporting security issues and security bugs + +Security issues and bugs should be reported privately, via email, to the Microsoft Security Response Center (MSRC) . You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Further information, including the MSRC PGP key, can be found in the [Security TechCenter](https://www.microsoft.com/msrc/faqs-report-an-issue). + +## License + +Azure SDK for Java is licensed under the [Apache 2.0](https://github.com/Azure/azure-notificationhubs-java-backend/blob/main/LICENSE) license. From f36a77e6e22f7b37ffa5a1b06b0e7e7fe4e8a340 Mon Sep 17 00:00:00 2001 From: Matthew Podwysocki Date: Thu, 12 Aug 2021 15:45:36 -0400 Subject: [PATCH 2/7] Updatng to v0.5 --- NotificationHubs/pom.xml | 2 +- .../windowsazure/messaging/AdmCredential.java | 49 +- .../messaging/AdmNotification.java | 20 + .../messaging/AdmRegistration.java | 59 +- .../messaging/AdmTemplateRegistration.java | 46 +- .../messaging/ApnsCredential.java | 95 +-- .../messaging/AppleNotification.java | 70 ++ .../messaging/AppleRegistration.java | 54 +- .../messaging/AppleTemplateRegistration.java | 95 ++- .../messaging/BaiduCredential.java | 69 +- .../messaging/BaiduNotification.java | 20 + .../messaging/BaiduRegistration.java | 81 +- .../messaging/BaiduTemplateRegistration.java | 82 +- .../messaging/BaseInstallation.java | 310 +++++++ .../BaseInstallationDeserializer.java | 29 + .../messaging/BaseInstallationFactory.java | 38 + .../messaging/BrowserCredential.java | 86 ++ .../messaging/BrowserInstallation.java | 91 ++ .../messaging/BrowserNotification.java | 4 + .../messaging/BrowserPushChannel.java | 84 ++ .../messaging/BrowserRegistration.java | 119 +++ .../BrowserTemplateRegistration.java | 87 ++ .../messaging/CollectionResult.java | 30 +- .../windowsazure/messaging/FcmCredential.java | 33 +- .../messaging/FcmNotification.java | 19 + .../messaging/FcmRegistration.java | 60 +- .../messaging/FcmTemplateRegistration.java | 79 +- .../windowsazure/messaging/GcmCredential.java | 29 +- .../messaging/GcmRegistration.java | 61 +- .../messaging/GcmTemplateRegistration.java | 92 +- .../messaging/INotificationHub.java | 667 --------------- .../windowsazure/messaging/Installation.java | 299 +------ .../messaging/InstallationTemplate.java | 15 +- .../messaging/MpnsCredential.java | 49 +- .../messaging/MpnsNotification.java | 32 + .../messaging/MpnsRegistration.java | 55 +- .../messaging/MpnsTemplateRegistration.java | 144 +++- .../messaging/NamespaceManager.java | 135 +-- .../windowsazure/messaging/Notification.java | 208 +---- .../messaging/NotificationHub.java | 796 ++++++++++++++++-- .../messaging/NotificationHubClient.java | 723 +++++++++++++++- .../messaging/NotificationHubDescription.java | 186 ++-- .../messaging/NotificationHubJob.java | 15 +- .../messaging/NotificationHubsException.java | 6 +- .../NotificationHubsExceptionFactory.java | 41 +- .../messaging/NotificationOutcome.java | 8 +- .../messaging/NotificationPlatform.java | 5 + .../messaging/NotificationStatus.java | 2 +- .../messaging/NotificationTelemetry.java | 7 + .../messaging/PartialUpdateOperation.java | 70 +- .../windowsazure/messaging/PnsCredential.java | 10 +- .../windowsazure/messaging/Registration.java | 180 ++-- .../messaging/RuntimeTypeAdapterFactory.java | 276 ++++++ .../messaging/SasTokenProvider.java | 68 ++ .../windowsazure/messaging/SyncCallback.java | 24 +- .../messaging/TemplateNotification.java | 33 + .../messaging/TemplateRegistration.java | 18 + .../messaging/UpdateOperationType.java | 2 +- .../messaging/WindowsCredential.java | 45 +- .../messaging/WindowsNotification.java | 28 + .../messaging/WindowsRawNotification.java | 20 + .../messaging/WindowsRegistration.java | 55 +- .../WindowsTemplateRegistration.java | 149 +++- .../messaging/WnsSecondaryTile.java | 121 ++- .../messaging/InstallationBrowserMinimal | 9 + .../messaging/InstallationMinimal | 6 +- .../messaging/InstallationMinimalNoSpaces | 1 - .../messaging/InstallationParseTest.java | 24 +- .../messaging/e2e/InstallationCrudsE2E.java | 2 +- 69 files changed, 4413 insertions(+), 2114 deletions(-) create mode 100644 NotificationHubs/src/com/windowsazure/messaging/AdmNotification.java create mode 100644 NotificationHubs/src/com/windowsazure/messaging/AppleNotification.java create mode 100644 NotificationHubs/src/com/windowsazure/messaging/BaiduNotification.java create mode 100644 NotificationHubs/src/com/windowsazure/messaging/BaseInstallation.java create mode 100644 NotificationHubs/src/com/windowsazure/messaging/BaseInstallationDeserializer.java create mode 100644 NotificationHubs/src/com/windowsazure/messaging/BaseInstallationFactory.java create mode 100644 NotificationHubs/src/com/windowsazure/messaging/BrowserCredential.java create mode 100644 NotificationHubs/src/com/windowsazure/messaging/BrowserInstallation.java create mode 100644 NotificationHubs/src/com/windowsazure/messaging/BrowserNotification.java create mode 100644 NotificationHubs/src/com/windowsazure/messaging/BrowserPushChannel.java create mode 100644 NotificationHubs/src/com/windowsazure/messaging/BrowserRegistration.java create mode 100644 NotificationHubs/src/com/windowsazure/messaging/BrowserTemplateRegistration.java create mode 100644 NotificationHubs/src/com/windowsazure/messaging/FcmNotification.java delete mode 100644 NotificationHubs/src/com/windowsazure/messaging/INotificationHub.java create mode 100644 NotificationHubs/src/com/windowsazure/messaging/MpnsNotification.java create mode 100644 NotificationHubs/src/com/windowsazure/messaging/RuntimeTypeAdapterFactory.java create mode 100644 NotificationHubs/src/com/windowsazure/messaging/SasTokenProvider.java create mode 100644 NotificationHubs/src/com/windowsazure/messaging/TemplateNotification.java create mode 100644 NotificationHubs/src/com/windowsazure/messaging/TemplateRegistration.java create mode 100644 NotificationHubs/src/com/windowsazure/messaging/WindowsNotification.java create mode 100644 NotificationHubs/src/com/windowsazure/messaging/WindowsRawNotification.java create mode 100644 NotificationHubs/test/com/windowsazure/messaging/InstallationBrowserMinimal delete mode 100644 NotificationHubs/test/com/windowsazure/messaging/InstallationMinimalNoSpaces diff --git a/NotificationHubs/pom.xml b/NotificationHubs/pom.xml index dee695c..9f20f87 100644 --- a/NotificationHubs/pom.xml +++ b/NotificationHubs/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.windowsazure Notification-Hubs-java-sdk - 0.4.0 + 0.5.0 Windows Azure Notification Hubs Java SDK UTF-8 diff --git a/NotificationHubs/src/com/windowsazure/messaging/AdmCredential.java b/NotificationHubs/src/com/windowsazure/messaging/AdmCredential.java index d679124..463f12f 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/AdmCredential.java +++ b/NotificationHubs/src/com/windowsazure/messaging/AdmCredential.java @@ -8,41 +8,60 @@ import java.util.ArrayList; import java.util.List; +/** + * This class represents Amazon PNS credentials. + */ public final class AdmCredential extends PnsCredential { private String clientId; private String clientSecret; + /** + * Creates a new instance of the AdmCredential class. + */ public AdmCredential() { - this(null, null); + super(); } + /** + * Creates a new instance of the AdmCredential class. + * @param clientId The Amazon client ID. + * @param clientSecret The Amazon client secret. + */ public AdmCredential(String clientId, String clientSecret) { super(); this.setClientId(clientId); this.setClientSecret(clientSecret); } - public String getClientId() { - return clientId; - } + /** + * Gets the Amazon client ID. + * @return The Amazon client ID. + */ + public String getClientId() { return clientId; } - public void setClientId(String clientId) { - this.clientId = clientId; - } + /** + * Gets the Amazon client ID. + * @param value THe Amazon client ID to set. + */ + public void setClientId(String value) { clientId = value; } - public String getClientSecret() { - return clientSecret; - } + /** + * Gets the Amazon client secret. + * @return The Amazon client secret. + */ + public String getClientSecret() { return clientSecret; } - public void setClientSecret(String clientSecret) { - this.clientSecret = clientSecret; - } + /** + * Sets the Amazon client secret. + * @param value The Amazon client secret to set. + */ + public void setClientSecret(String value) { clientSecret = value; } @Override public List> getProperties() { ArrayList> result = new ArrayList<>(); - result.add(new SimpleEntry<>("ClientId", getClientId())); - result.add(new SimpleEntry<>("ClientSecret", getClientSecret())); + result.add(new SimpleEntry<>("ClientId", clientId)); + result.add(new SimpleEntry<>("ClientSecret", clientSecret)); return result; } diff --git a/NotificationHubs/src/com/windowsazure/messaging/AdmNotification.java b/NotificationHubs/src/com/windowsazure/messaging/AdmNotification.java new file mode 100644 index 0000000..ebe44f2 --- /dev/null +++ b/NotificationHubs/src/com/windowsazure/messaging/AdmNotification.java @@ -0,0 +1,20 @@ +package com.windowsazure.messaging; + +import org.apache.http.entity.ContentType; + +/** + * This class represents a notification to the Amazon PNS. + */ +public class AdmNotification extends Notification { + + /** + * Creates a new instance of the AdmNotification class. + * @param body The JSON body for the Amazon PNS. + */ + public AdmNotification(String body) { + this.body = body; + this.contentType = ContentType.APPLICATION_JSON; + + this.headers.put("ServiceBusNotification-Format", "adm"); + } +} diff --git a/NotificationHubs/src/com/windowsazure/messaging/AdmRegistration.java b/NotificationHubs/src/com/windowsazure/messaging/AdmRegistration.java index 0b2aa05..592d599 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/AdmRegistration.java +++ b/NotificationHubs/src/com/windowsazure/messaging/AdmRegistration.java @@ -4,6 +4,11 @@ package com.windowsazure.messaging; +import java.util.Objects; + +/** + * This class represents an Amazon device registration. + */ public class AdmRegistration extends Registration { private static final String ADM_NATIVE_REGISTRATION1 = ""; private static final String ADM_NATIVE_REGISTRATION2 = ""; @@ -11,54 +16,60 @@ public class AdmRegistration extends Registration { protected String admRegistrationId; + /** + * Creates a new instance of the AdmRegistration class. + */ public AdmRegistration() { super(); } + /** + * Creates a new instance of the AdmRegistration class. + * @param registrationId The Azure Notification Hubs registration ID for the device. + * @param admRegistrationId The Amazon device registration ID. + */ public AdmRegistration(String registrationId, String admRegistrationId) { super(registrationId); this.admRegistrationId = admRegistrationId; } + /** + * Creates a new instance of the AdmRegistration class. + * @param admRegistrationId The Amazon device registration ID. + */ public AdmRegistration(String admRegistrationId) { super(); this.admRegistrationId = admRegistrationId; } + /** + * Gets the Amazon registration ID for the device. + * @return The Amazon registration ID for the device. + */ public String getAdmRegistrationId() { return admRegistrationId; } - public void setAdmRegistrationId(String admRegistrationId) { - this.admRegistrationId = admRegistrationId; + /** + * Sets the Amazon registration ID for the device. + * @param value The Amazon registration ID for the device to set. + */ + public void setAdmRegistrationId(String value) { + admRegistrationId = value; } @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime - * result - + ((admRegistrationId == null) ? 0 : admRegistrationId - .hashCode()); - return result; + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + AdmRegistration that = (AdmRegistration) o; + return Objects.equals(getAdmRegistrationId(), that.getAdmRegistrationId()); } @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (!super.equals(obj)) - return false; - if (getClass() != obj.getClass()) - return false; - AdmRegistration other = (AdmRegistration) obj; - if (admRegistrationId == null) { - if (other.admRegistrationId != null) - return false; - } else if (!admRegistrationId.equals(other.admRegistrationId)) - return false; - return true; + public int hashCode() { + return Objects.hash(super.hashCode(), getAdmRegistrationId()); } @Override diff --git a/NotificationHubs/src/com/windowsazure/messaging/AdmTemplateRegistration.java b/NotificationHubs/src/com/windowsazure/messaging/AdmTemplateRegistration.java index 6f6b725..2ade1db 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/AdmTemplateRegistration.java +++ b/NotificationHubs/src/com/windowsazure/messaging/AdmTemplateRegistration.java @@ -4,7 +4,10 @@ package com.windowsazure.messaging; -public class AdmTemplateRegistration extends AdmRegistration { +/** + * This class represents an Amazon device template registration. + */ +public class AdmTemplateRegistration extends AdmRegistration implements TemplateRegistration { private static final String ADM_TEMPLATE_REGISTRATION1 = ""; private static final String ADM_TEMPLATE_REGISTRATION2 = ""; private static final String ADM_TEMPLATE_REGISTRATION3 = "> getProperties() { diff --git a/NotificationHubs/src/com/windowsazure/messaging/AppleNotification.java b/NotificationHubs/src/com/windowsazure/messaging/AppleNotification.java new file mode 100644 index 0000000..2d31413 --- /dev/null +++ b/NotificationHubs/src/com/windowsazure/messaging/AppleNotification.java @@ -0,0 +1,70 @@ +package com.windowsazure.messaging; + +import org.apache.http.entity.ContentType; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Map; +import java.util.TimeZone; + +/** + * This class represents an Apple APNS notification. + */ +public class AppleNotification extends Notification { + + /** + * Creates a new instance of the AppleNotification class. + * @param body The JSON body for the notification. + */ + public AppleNotification(String body) { + this(body, getTomorrow(), null); + } + + /** + * Creates a new instance of the AppleNotification class. + * @param body The JSON body for the notification. + * @param headers The headers for the notification. + */ + public AppleNotification(String body, Map headers) { + this(body, getTomorrow(), headers); + } + + /** + * Creates a new instance of the AppleNotification class. + * @param body The JSON body for the notification. + * @param expiry The expiration date of the notification. + */ + public AppleNotification(String body, Date expiry) { + this(body, expiry, null); + } + + /** + * Creates a new instance of the AppleNotification class. + * @param body The JSON body for the notification. + * @param expiry The expiration date of the notification. + * @param headers The headers for the notification. + */ + public AppleNotification(String body, Date expiry, Map headers) { + this.body = body; + this.contentType = ContentType.APPLICATION_JSON; + + this.headers.put("ServiceBusNotification-Format", "apple"); + + if (expiry != null) { + SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy hh:mm:ss"); + formatter.setTimeZone(TimeZone.getTimeZone("UTC")); + String expiryString = formatter.format(expiry.getTime()); + + this.headers.put("ServiceBusNotification-Apns-Expiry", expiryString); + } + + if (headers != null) { + this.headers = headers; + } + } + + private static Date getTomorrow() { + Date now = new Date(); + return new Date(now.getTime() + 24 * 60 * 60 * 1000); + } +} diff --git a/NotificationHubs/src/com/windowsazure/messaging/AppleRegistration.java b/NotificationHubs/src/com/windowsazure/messaging/AppleRegistration.java index 5b259ff..0e4d03a 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/AppleRegistration.java +++ b/NotificationHubs/src/com/windowsazure/messaging/AppleRegistration.java @@ -4,6 +4,8 @@ package com.windowsazure.messaging; +import java.util.Objects; + /** * Class representing a native registration for a device using APNs. */ @@ -14,52 +16,58 @@ public class AppleRegistration extends Registration { protected String deviceToken; + /** + * Creates a new instance of the AppleRegistration class. + */ public AppleRegistration() { super(); } + /** + * Creates a new instance of the AppleRegistration class. + * @param deviceToken The APNS device token for the registration. + */ public AppleRegistration(String deviceToken) { super(); this.deviceToken = deviceToken; } + /** + * Creates a new instance of the AppleRegistration class. + * @param registrationId The registration ID for the device. + * @param deviceToken The APNS device token for the registration. + */ public AppleRegistration(String registrationId, String deviceToken) { super(registrationId); this.deviceToken = deviceToken; } + /** + * Gets the APNS device token for the registration. + * @return The APNS device token for the registration. + */ public String getDeviceToken() { return deviceToken; } - public void setDeviceToken(String deviceToken) { - this.deviceToken = deviceToken; - } + /** + * Sets the APNS device token for the registration. + * @param value The APNS device token for the registration to set. + */ + public void setDeviceToken(String value) { deviceToken = value; } @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result - + ((deviceToken == null) ? 0 : deviceToken.hashCode()); - return result; + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + AppleRegistration that = (AppleRegistration) o; + return Objects.equals(getDeviceToken(), that.getDeviceToken()); } @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (!super.equals(obj)) - return false; - if (getClass() != obj.getClass()) - return false; - AppleRegistration other = (AppleRegistration) obj; - if (deviceToken == null) { - if (other.deviceToken != null) - return false; - } else if (!deviceToken.equals(other.deviceToken)) - return false; - return true; + public int hashCode() { + return Objects.hash(super.hashCode(), getDeviceToken()); } @Override diff --git a/NotificationHubs/src/com/windowsazure/messaging/AppleTemplateRegistration.java b/NotificationHubs/src/com/windowsazure/messaging/AppleTemplateRegistration.java index 26ab63a..e3cc43c 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/AppleTemplateRegistration.java +++ b/NotificationHubs/src/com/windowsazure/messaging/AppleTemplateRegistration.java @@ -4,82 +4,91 @@ package com.windowsazure.messaging; +import java.util.Objects; + /** * Class representing a registration for template notifications for devices using APNs. */ -public class AppleTemplateRegistration extends AppleRegistration { +public class AppleTemplateRegistration extends AppleRegistration implements TemplateRegistration { private static final String APNS_TEMPLATE_REGISTRATION1 = ""; private static final String APNS_TEMPLATE_REGISTRATION2 = ""; private static final String APNS_TEMPLATE_REGISTRATION3 = ""; private static final String APNS_TEMPLATE_REGISTRATION5 = ""; - private String bodyTemplate; private String expiry; + /** + * Creates a new instance of the AppleTemplateRegistration class. + */ public AppleTemplateRegistration() { super(); } - public AppleTemplateRegistration(String registrationId, String deviceToken, - String bodyTemplate) { + /** + * Creates a new instance of the AppleTemplateRegistration class. + * @param registrationId The registration ID for the device. + * @param deviceToken The APNS device token for the registration. + * @param bodyTemplate The template body for the registration. + */ + public AppleTemplateRegistration( + String registrationId, + String deviceToken, + String bodyTemplate + ) { super(registrationId, deviceToken); this.bodyTemplate = bodyTemplate; } + /** + * Creates a new instance of the AppleTemplateRegistration class. + * @param deviceToken The APNS device token for the registration + * @param bodyTemplate The template body for the registration. + */ public AppleTemplateRegistration(String deviceToken, String bodyTemplate) { super(deviceToken); this.bodyTemplate = bodyTemplate; } - public String getBodyTemplate() { - return bodyTemplate; - } - - public void setBodyTemplate(String bodyTemplate) { - this.bodyTemplate = bodyTemplate; - } + /** + * Gets the registration template body. + * @return The registration template body. + */ + @Override + public String getBodyTemplate() { return bodyTemplate; } - public String getExpiry() { - return expiry; - } + /** + * Sets the registration template body. + * @param value The registration template body to set. + */ + @Override + public void setBodyTemplate(String value) { this.bodyTemplate = value; } - public void setExpiry(String expiry) { - this.expiry = expiry; - } + /** + * Gets the expiration for the template registration. + * @return The expiration for the template registration. + */ + public String getExpiry() { return expiry; } + /** + * Sets the expiration for the template registration. + * @param value The expiration for the template registration to set. + */ + public void setExpiry(String value) { expiry = value; } @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result - + ((bodyTemplate == null) ? 0 : bodyTemplate.hashCode()); - result = prime * result + ((expiry == null) ? 0 : expiry.hashCode()); - return result; + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + AppleTemplateRegistration that = (AppleTemplateRegistration) o; + return Objects.equals(getBodyTemplate(), that.getBodyTemplate()) && Objects.equals(getExpiry(), that.getExpiry()); } @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (!super.equals(obj)) - return false; - if (getClass() != obj.getClass()) - return false; - AppleTemplateRegistration other = (AppleTemplateRegistration) obj; - if (bodyTemplate == null) { - if (other.bodyTemplate != null) - return false; - } else if (!bodyTemplate.equals(other.bodyTemplate)) - return false; - if (expiry == null) { - if (other.expiry != null) - return false; - } else if (!expiry.equals(other.expiry)) - return false; - return true; + public int hashCode() { + return Objects.hash(super.hashCode(), getBodyTemplate(), getExpiry()); } @Override diff --git a/NotificationHubs/src/com/windowsazure/messaging/BaiduCredential.java b/NotificationHubs/src/com/windowsazure/messaging/BaiduCredential.java index d1358e7..9fca826 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/BaiduCredential.java +++ b/NotificationHubs/src/com/windowsazure/messaging/BaiduCredential.java @@ -8,50 +8,71 @@ import java.util.ArrayList; import java.util.List; +/** + * This class represents Baidu PNS credentials for Azure Notification Hubs. + */ public final class BaiduCredential extends PnsCredential { private String baiduApiKey; private String baiduSecretKey; private String baiduEndPoint; + /** + * Creates a new instance of the BaiduCredential class. + */ public BaiduCredential() { - this(null, null); } + /** + * Creates a new instance of the BaiduCredential class with the Baidu API key and secret key. + * @param baiduApiKey The Baidu API key. + * @param baiduSecretKey The Baidu secret key. + */ public BaiduCredential(String baiduApiKey, String baiduSecretKey) { - this.setBaiduApiKey(baiduApiKey); - this.setBaiduSecretKey(baiduSecretKey); - } - - public String getBaiduApiKey() { - return this.baiduApiKey; - } - - public void setBaiduApiKey(String baiduApiKey) { this.baiduApiKey = baiduApiKey; + this.baiduSecretKey = baiduSecretKey; } + /** + * Gets the Baidu API key. + * @return The Baidu API key. + */ + public String getBaiduApiKey() { return this.baiduApiKey; } - public String getBaiduSecretKey() { - return baiduSecretKey; - } + /** + * Sets the Baidu API key. + * @param value The Baidu API key to set. + */ + public void setBaiduApiKey(String value) { baiduApiKey = value; } - public void setBaiduSecretKey(String baiduSecretKey) { - this.baiduSecretKey = baiduSecretKey; - } + /** + * Gets the Baidu secret key. + * @return The Baidu secret key. + */ + public String getBaiduSecretKey() { return baiduSecretKey; } - public String getBaiduEndPoint() { - return baiduEndPoint; - } + /** + * Sets the Baidu secret key. + * @param value The Baidu secret key to set. + */ + public void setBaiduSecretKey(String value) { baiduSecretKey = value; } - public void setBaiduEndPoint(String baiduEndPoint) { - this.baiduEndPoint = baiduEndPoint; - } + /** + * Gets the Baidu URL endpoint. + * @return The Baidu URL endpoint. + */ + public String getBaiduEndPoint() { return baiduEndPoint; } + + /** + * Sets the Baidu URL endpoint. + * @param value The Baidu URL endpoint to set. + */ + public void setBaiduEndPoint(String value) { baiduEndPoint = value; } @Override public List> getProperties() { ArrayList> result = new ArrayList<>(); - result.add(new SimpleEntry<>("BaiduApiKey", getBaiduApiKey())); - result.add(new SimpleEntry<>("BaiduSecretKey", getBaiduSecretKey())); + result.add(new SimpleEntry<>("BaiduApiKey", baiduApiKey)); + result.add(new SimpleEntry<>("BaiduSecretKey", baiduSecretKey)); return result; } diff --git a/NotificationHubs/src/com/windowsazure/messaging/BaiduNotification.java b/NotificationHubs/src/com/windowsazure/messaging/BaiduNotification.java new file mode 100644 index 0000000..ba0e7e9 --- /dev/null +++ b/NotificationHubs/src/com/windowsazure/messaging/BaiduNotification.java @@ -0,0 +1,20 @@ +package com.windowsazure.messaging; + +import org.apache.http.entity.ContentType; + +/** + * This class represents a notification for the Baidu PNS. + */ +public class BaiduNotification extends Notification { + + /** + * Creates a new instance of the BaiduNotification class. + * @param body The JSON body for the Baidu notification. + */ + public BaiduNotification(String body) { + this.body = body; + this.contentType = ContentType.APPLICATION_JSON; + + this.headers.put("ServiceBusNotification-Format", "baidu"); + } +} diff --git a/NotificationHubs/src/com/windowsazure/messaging/BaiduRegistration.java b/NotificationHubs/src/com/windowsazure/messaging/BaiduRegistration.java index ddd17ec..9f3d0a6 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/BaiduRegistration.java +++ b/NotificationHubs/src/com/windowsazure/messaging/BaiduRegistration.java @@ -4,6 +4,8 @@ package com.windowsazure.messaging; +import java.util.Objects; + /** * Class representing a native registration for devices using Baidu PNS. */ @@ -16,58 +18,72 @@ public class BaiduRegistration extends Registration { protected String baiduUserId; protected String baiduChannelId; + /** + * Creates a new instance of the BaiduRegistration class. + */ public BaiduRegistration() { - this(null, null); + super(); } + /** + * Creates a new instance of the BaiduRegistration class. + * @param baiduUserId The Baidu user ID for the device. + * @param baiduChannelId The Baidu channel ID for the device. + */ public BaiduRegistration(String baiduUserId, String baiduChannelId) { - this(null, baiduUserId, baiduChannelId); + super(); + this.baiduUserId = baiduUserId; + this.baiduChannelId = baiduChannelId; } + /** + * Creates a new instance of the BaiduRegistration class. + * @param registrationId The Azure Notification Hubs registration ID. + * @param baiduUserId The Baidu user ID for the device. + * @param baiduChannelId The Baidu channel ID for the device. + */ public BaiduRegistration(String registrationId, String baiduUserId, String baiduChannelId) { super(registrationId); this.baiduUserId = baiduUserId; this.baiduChannelId = baiduChannelId; } - public String getBaiduUserId() { - return baiduUserId; - } + /** + * Gets the Baidu user ID for the device. + * @return The Baidu user ID for the device. + */ + public String getBaiduUserId() { return baiduUserId; } - public void setBaiduUserId(String baiduUserId) { - this.baiduUserId = baiduUserId; - } + /** + * Sets the Baidu user ID for the device. + * @param value The Baidu user ID for the device to set. + */ + public void setBaiduUserId(String value) { baiduUserId = value; } - public String getBaiduChannelId() { - return baiduChannelId; - } + /** + * Gets the Baidu channel ID for the device. + * @return The Baidu channel ID for the device. + */ + public String getBaiduChannelId() { return baiduChannelId; } - public void setBaiduChannelId(String baiduChannelId) { - this.baiduChannelId = baiduChannelId; - } + /** + * Sets the Baidu channel ID for the device. + * @param value The Baidu channel ID for the device to set. + */ + public void setBaiduChannelId(String value) { baiduChannelId = value; } @Override - public int hashCode() { - String channel = (baiduUserId == null ? "" : baiduUserId) + "-" + (baiduChannelId == null ? "" : baiduChannelId); - final int prime = 31; - int result = super.hashCode(); - result = prime - * result - + ((baiduUserId == null && baiduChannelId == null) ? 0 : channel.hashCode()); - return result; + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + BaiduRegistration that = (BaiduRegistration) o; + return Objects.equals(getBaiduUserId(), that.getBaiduUserId()) && Objects.equals(getBaiduChannelId(), that.getBaiduChannelId()); } @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (!super.equals(obj)) - return false; - if (getClass() != obj.getClass()) - return false; - - BaiduRegistration other = (BaiduRegistration) obj; - return baiduUserId.equals(other.baiduUserId) && baiduChannelId.equals(other.baiduChannelId); + public int hashCode() { + return Objects.hash(super.hashCode(), getBaiduUserId(), getBaiduChannelId()); } @Override @@ -80,5 +96,4 @@ public String getXml() { baiduChannelId + BAIDU_NATIVE_REGISTRATION4; } - } diff --git a/NotificationHubs/src/com/windowsazure/messaging/BaiduTemplateRegistration.java b/NotificationHubs/src/com/windowsazure/messaging/BaiduTemplateRegistration.java index 054827b..58d3586 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/BaiduTemplateRegistration.java +++ b/NotificationHubs/src/com/windowsazure/messaging/BaiduTemplateRegistration.java @@ -4,7 +4,12 @@ package com.windowsazure.messaging; -public class BaiduTemplateRegistration extends BaiduRegistration { +import java.util.Objects; + +/** + * Class representing a template registration for devices using Baidu PNS. + */ +public class BaiduTemplateRegistration extends BaiduRegistration implements TemplateRegistration { private static final String BAIDU_NATIVE_REGISTRATION1 = ""; private static final String BAIDU_NATIVE_REGISTRATION2 = ""; private static final String BAIDU_NATIVE_REGISTRATION3 = ""; @@ -13,51 +18,67 @@ public class BaiduTemplateRegistration extends BaiduRegistration { private String bodyTemplate; + /** + * Creates a new instance of the BaiduTemplateRegistration class. + */ public BaiduTemplateRegistration() { - this(null, null, null); + super(); } + /** + * Creates a new instance of the BaiduTemplateRegistration class. + * @param baiduUserId The Baidu user ID for the device. + * @param baiduChannelId The Baidu channel ID for the device. + * @param bodyTemplate The browser push registration template body. + */ public BaiduTemplateRegistration(String baiduUserId, String baiduChannelId, String bodyTemplate) { - this(null, baiduUserId, baiduChannelId, bodyTemplate); + super(baiduUserId, baiduChannelId); + this.bodyTemplate = bodyTemplate; } - public BaiduTemplateRegistration(String registrationId, String baiduUserId, String baiduChannelId, String bodyTemplate) { + /** + * Creates a new instance of the BaiduTemplateRegistration class. + * @param registrationId The Azure Notification Hubs registration ID. + * @param baiduUserId The Baidu user ID for the device. + * @param baiduChannelId The Baidu channel ID for the device. + * @param bodyTemplate The browser push registration template body. + */ + public BaiduTemplateRegistration( + String registrationId, + String baiduUserId, + String baiduChannelId, + String bodyTemplate + ) { super(registrationId, baiduUserId, baiduChannelId); this.bodyTemplate = bodyTemplate; } - public String getBodyTemplate() { - return bodyTemplate; - } + /** + * Gets the registration template body. + * @return The registration template body. + */ + @Override + public String getBodyTemplate() { return bodyTemplate; } - public void setBodyTemplate(String bodyTemplate) { - this.bodyTemplate = bodyTemplate; - } + /** + * Sets the registration template body. + * @param value The registration template body to set. + */ + @Override + public void setBodyTemplate(String value) { this.bodyTemplate = value; } @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result - + ((bodyTemplate == null) ? 0 : bodyTemplate.hashCode()); - return result; + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + BaiduTemplateRegistration that = (BaiduTemplateRegistration) o; + return Objects.equals(getBodyTemplate(), that.getBodyTemplate()); } @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (!super.equals(obj)) - return false; - if (getClass() != obj.getClass()) - return false; - BaiduTemplateRegistration other = (BaiduTemplateRegistration) obj; - if (bodyTemplate == null) { - if (other.bodyTemplate != null) - return false; - } else if (!bodyTemplate.equals(other.bodyTemplate)) - return false; - return true; + public int hashCode() { + return Objects.hash(super.hashCode(), getBodyTemplate()); } @Override @@ -72,5 +93,4 @@ public String getXml() { bodyTemplate + BAIDU_NATIVE_REGISTRATION5; } - } diff --git a/NotificationHubs/src/com/windowsazure/messaging/BaseInstallation.java b/NotificationHubs/src/com/windowsazure/messaging/BaseInstallation.java new file mode 100644 index 0000000..4101b94 --- /dev/null +++ b/NotificationHubs/src/com/windowsazure/messaging/BaseInstallation.java @@ -0,0 +1,310 @@ +package com.windowsazure.messaging; + +import com.google.gson.GsonBuilder; + +import java.text.SimpleDateFormat; +import java.util.*; + +public abstract class BaseInstallation { + private String installationId; + private String userId; + private NotificationPlatform platform; + private boolean pushChannelExpired; + private String expirationTime; + private List tags; + private Map templates; + private Map secondaryTiles; + + /** + * Creates a new installation. + */ + public BaseInstallation() {} + + /** + * Creates a new installation with the given installation ID. + * + * @param installationId The ID for the installation. + */ + public BaseInstallation(String installationId) { + this(installationId, (String[]) null); + } + + /** + * Creates an installation from the Installation ID and tags. + * + * @param installationId The ID for the installation. + * @param tags The tags for the installation. + */ + public BaseInstallation(String installationId, String... tags) { + this(installationId, null, tags); + } + + /** + * Creates an installation with an installation ID, platform and push channel. + * + * @param installationId The ID for the installation. + * @param platform The platform for the installation. + */ + public BaseInstallation(String installationId, NotificationPlatform platform) { + this(installationId, platform, (String[]) null); + } + + public BaseInstallation(String installationId, NotificationPlatform platform, String... tags) { + // Validate that this is not FCM + validateNotificationPlatform(platform); + + this.installationId = installationId; + this.platform = platform; + if (tags != null) { + for (String tag : tags) { + this.addTag(tag); + } + } + } + + /** + * Validates that the platform is not FCM. Currently, Notification Hubs supports + * FCM Legacy as NotificationPlatform.Gcm Full support for FCM is not currently + * supported. See https://aka.ms/AA9dpaz + * + * @param notificationPlatform The notification platform to verify that it is + * not FCM. + */ + private static void validateNotificationPlatform(NotificationPlatform notificationPlatform) { + if (notificationPlatform == NotificationPlatform.Fcm) { + throw new RuntimeException( + "FCM is currently not supported, use NotificationPlatform.Gcm which uses FCM Legacy Mode. See https://aka.ms/AA9dpaz"); + } + } + + /** + * Gets the ID for the installation. + * + * @return The ID for the installation. + */ + public String getInstallationId() { + return installationId; + } + + /** + * Sets the ID for the installation. + * + * @param value The ID for the installation. + */ + public void setInstallationId(String value) { + installationId = value; + } + + /** + * Gets whether the push channel has expired + * + * @return Returns true if expired, false otherwise. + */ + public boolean isPushChannelExpired() { + return pushChannelExpired; + } + + /** + * Gets the expiration time for the installation. + * + * @return The installation expiration time. + */ + public Date getExpirationTime() { + return javax.xml.bind.DatatypeConverter.parseDateTime(expirationTime).getTime(); + } + + /** + * Sets the expiration time for the installation. + * + * @param value The expiration time for the installation. + */ + public void setExpirationTime(Date value) { + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'.'SSS'Z'"); + expirationTime = formatter.format(value); + } + + /** + * Gets the platform for the installation. + * + * @return The platform for the installation. + */ + public NotificationPlatform getPlatform() { + return platform; + } + + /** + * Sets the platform for the installation. Note that FCM is currently not + * supported, only GCM which is FCM Legacy. See https://aka.ms/AA9dpaz + * for more details. + * + * @param value The platform for the installation. + */ + public void setPlatform(NotificationPlatform value) { + // Validate that this is not FCM + validateNotificationPlatform(value); + + platform = value; + } + + /** + * Gets the user ID for the installation. + * + * @return The user ID for the installation. + */ + public String getUserId() { + return userId; + } + + /** + * Sets the user ID for the installation. + * + * @param value The user ID for the installation. + */ + public void setUserId(String value) { + userId = value; + } + + /** + * Gets the tags for the installation. + * + * @return The tags for the installation. + */ + public List getTags() { + return tags; + } + + /** + * Adds a tag to the installation. + * + * @param tag The tag to add to the installation; + */ + public void addTag(String tag) { + if (tags == null) { + tags = new ArrayList<>(); + } + + tags.add(tag); + } + + /** + * Removes a tag from the installation. + * + * @param tag The tag to remove from the installation. + */ + public void removeTag(String tag) { + if (tags == null) { + return; + } + + tags.remove(tag); + } + + /** + * Clears the tags for the installation. + */ + public void clearTags() { + if (tags == null) { + return; + } + + tags.clear(); + } + + /** + * Gets the installation templates for the installation. + * + * @return The installation templates for the installation. + */ + public Map getTemplates() { + return templates; + } + + /** + * Adds an installation template by name to the installation. + * + * @param templateName The name for the installation template. + * @param template The template to add to the installation. + */ + public void addTemplate(String templateName, InstallationTemplate template) { + if (templates == null) { + templates = new HashMap<>(); + } + + templates.put(templateName, template); + } + + /** + * Removes an installation template based upon the template name. + * + * @param templateName The name of the installation template to remove. + */ + public void removeTemplate(String templateName) { + if (templates == null) { + return; + } + + templates.remove(templateName); + } + + /** + * Clears the installation templates. + */ + public void clearTemplates() { + if (templates == null) { + return; + } + + templates.clear(); + } + + /** + * Gets the secondary tiles for WNS + * + * @return The secondary tiles for WNS. + */ + public Map getSecondaryTiles() { + return secondaryTiles; + } + + /** + * Adds a secondary tile to the installation template. + * + * @param tileName The name for the tile. + * @param tile THe WNS secondary tile. + */ + public void addSecondaryTile(String tileName, WnsSecondaryTile tile) { + if (templates == null) { + secondaryTiles = new HashMap<>(); + } + + secondaryTiles.put(tileName, tile); + } + + public void removeSecondaryTile(String tileName) { + if (templates == null) { + return; + } + + secondaryTiles.remove(tileName); + } + + /** + * Clears the WNS secondary tiles. + */ + public void clearSecondaryTiles() { + if (templates == null) { + return; + } + + secondaryTiles.clear(); + } + + /** + * Converts the installation to a JSON string. + * + * @return The JSON string representation of the installation. + */ + public String toJson() { + return new GsonBuilder().disableHtmlEscaping().create().toJson(this); + } +} diff --git a/NotificationHubs/src/com/windowsazure/messaging/BaseInstallationDeserializer.java b/NotificationHubs/src/com/windowsazure/messaging/BaseInstallationDeserializer.java new file mode 100644 index 0000000..d7236d8 --- /dev/null +++ b/NotificationHubs/src/com/windowsazure/messaging/BaseInstallationDeserializer.java @@ -0,0 +1,29 @@ +package com.windowsazure.messaging; + +import com.google.gson.JsonObject; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; + +import java.lang.reflect.Type; + +public class BaseInstallationDeserializer implements JsonDeserializer { + + @Override + public BaseInstallation deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { + JsonObject jsonObject = jsonElement.getAsJsonObject(); + JsonElement jsonType = jsonObject.get("platform"); + String platformString = jsonType.getAsString(); + + BaseInstallation installation; + + if (platformString.equalsIgnoreCase("browser")) { + installation = jsonDeserializationContext.deserialize(jsonElement, BrowserInstallation.class); + } else { + installation = jsonDeserializationContext.deserialize(jsonElement, Installation.class); + } + + return installation; + } +} diff --git a/NotificationHubs/src/com/windowsazure/messaging/BaseInstallationFactory.java b/NotificationHubs/src/com/windowsazure/messaging/BaseInstallationFactory.java new file mode 100644 index 0000000..f7663f5 --- /dev/null +++ b/NotificationHubs/src/com/windowsazure/messaging/BaseInstallationFactory.java @@ -0,0 +1,38 @@ +package com.windowsazure.messaging; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import org.apache.commons.io.IOUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +public class BaseInstallationFactory { + + /** + * Creates an installation from the JSON string. + * + * @param jsonString The JSON string that represents the installation. + * @return An installation created from the JSON string. + */ + public static BaseInstallation createInstallation(String jsonString) { + + Gson gson = new GsonBuilder() + .registerTypeAdapter(BaseInstallation.class, new BaseInstallationDeserializer()) + .create(); + + return gson.fromJson(jsonString, BaseInstallation.class); + } + + /** + * Creates an installation from the JSON stream. + * + * @param json The JSON string that represents the installation. + * @return An installation created from the JSON stream. + * @throws IOException An exception reading from the stream occurred. + */ + public static BaseInstallation createInstallation(InputStream json) throws IOException { + return createInstallation(IOUtils.toString(json, StandardCharsets.UTF_8)); + } +} diff --git a/NotificationHubs/src/com/windowsazure/messaging/BrowserCredential.java b/NotificationHubs/src/com/windowsazure/messaging/BrowserCredential.java new file mode 100644 index 0000000..4d99b7d --- /dev/null +++ b/NotificationHubs/src/com/windowsazure/messaging/BrowserCredential.java @@ -0,0 +1,86 @@ +//---------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +//---------------------------------------------------------------- + +package com.windowsazure.messaging; + +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.List; + +/** + * This class represents Browser Push PNS credentials for Azure Notification Hubs. + */ +public final class BrowserCredential extends PnsCredential { + private String subject; + private String vapidPublicKey; + private String vapidPrivateKey; + + /** + * Creates a new BrowserCredential with default values. + */ + public BrowserCredential() { + } + + /** + * Creates a BrowserCredential with subject, VAPID public key and private key. + * @param subject The subject in mailto: or http:// form. + * @param vapidPublicKey The VAPID public key. + * @param vapidPrivateKey The VAPID private key. + */ + public BrowserCredential(String subject, String vapidPublicKey, String vapidPrivateKey) { + this.subject = subject; + this.vapidPublicKey = vapidPublicKey; + this.vapidPrivateKey = vapidPrivateKey; + } + + /** + * Gets the browser credential subject. + * @return The browser credential subject. + */ + public String getSubject() { return subject; } + + /** + * Sets the browser credential subject. + * @param value The new browser credential subject to set. + */ + public void setSubject(String value) { subject = value; } + + /** + * Gets the browser credential VAPID public key. + * @return The browser credential VAPID public key. + */ + public String getVapidPublicKey() { return vapidPublicKey; } + + /** + * Sets the browser credential VAPID public key. + * @param value The browser credential VAPID public key to set. + */ + public void setVapidPublicKey(String value) { vapidPublicKey = value; } + + /** + * Gets the browser credential VAPID private key. + * @return The browser credential VAPID private key. + */ + public String getVapidPrivateKey() { return vapidPrivateKey; } + + /** + * Sets the browser credential VAPID private key. + * @param value The browser credential VAPID private key to set. + */ + public void setVapidPrivateKey(String value) { vapidPrivateKey = value; } + + @Override + public List> getProperties() { + ArrayList> result = new ArrayList<>(); + result.add(new AbstractMap.SimpleEntry<>("Subject", subject)); + result.add(new AbstractMap.SimpleEntry<>("VapidPublicKey", vapidPublicKey)); + result.add(new AbstractMap.SimpleEntry<>("VapidPrivateKey", vapidPrivateKey)); + return result; + } + + @Override + public String getRootTagName() { + return "BrowserCredential"; + } +} diff --git a/NotificationHubs/src/com/windowsazure/messaging/BrowserInstallation.java b/NotificationHubs/src/com/windowsazure/messaging/BrowserInstallation.java new file mode 100644 index 0000000..c207c5b --- /dev/null +++ b/NotificationHubs/src/com/windowsazure/messaging/BrowserInstallation.java @@ -0,0 +1,91 @@ +package com.windowsazure.messaging; + +import com.google.gson.Gson; +import org.apache.commons.io.IOUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +/** + * This class represents an installation for browser push. + */ +public class BrowserInstallation extends BaseInstallation { + private BrowserPushChannel pushChannel; + + /** + * Creates a new instance of the BrowserInstallation class. + * + * @param installationId The ID for the installation. + */ + public BrowserInstallation(String installationId) { + this(installationId, (String[]) null); + } + + /** + * Creates a new instance of the BrowserInstallation class. + * + * @param installationId The ID for the installation. + * @param tags The tags for the installation. + */ + public BrowserInstallation(String installationId, String... tags) { + this(installationId, null, null, tags); + } + + /** + * Creates a new instance of the Installation class. + * + * @param installationId The ID for the installation. + * @param platform The platform for the installation. + */ + public BrowserInstallation(String installationId, NotificationPlatform platform, BrowserPushChannel pushChannel) { + this(installationId, platform, pushChannel, (String[]) null); + } + + /** + * Creates a new instance of the Installation class. + * @param installationId The ID for the installation. + * @param platform The platform for the installation + * @param pushChannel The device specific push channel for the installation. + * @param tags The tags for the installation. + */ + public BrowserInstallation(String installationId, NotificationPlatform platform, BrowserPushChannel pushChannel, String... tags) { + super(installationId, platform, tags); + this.pushChannel = pushChannel; + } + + /** + * Gets the PNS specific push channel for the installation. + * + * @return The PNS specific push channel for the installation. + */ + public BrowserPushChannel getPushChannel() { return pushChannel; } + + /** + * Sets the PNS specific push channel for the installation. + * + * @param value The PNS specific push channel for the installation + */ + public void setPushChannel(BrowserPushChannel value) { pushChannel = value; } + + /** + * Creates an installation from the JSON string. + * + * @param json The JSON string that represents the installation. + * @return An installation created from the JSON string. + */ + public static BrowserInstallation fromJson(String json) { + return new Gson().fromJson(json, BrowserInstallation.class); + } + + /** + * Creates an installation from the JSON stream. + * + * @param json The JSON string that represents the installation. + * @return An installation created from the JSON stream. + * @throws IOException An exception reading from the stream occurred. + */ + public static BrowserInstallation fromJson(InputStream json) throws IOException { + return BrowserInstallation.fromJson(IOUtils.toString(json, StandardCharsets.UTF_8)); + } +} diff --git a/NotificationHubs/src/com/windowsazure/messaging/BrowserNotification.java b/NotificationHubs/src/com/windowsazure/messaging/BrowserNotification.java new file mode 100644 index 0000000..410a810 --- /dev/null +++ b/NotificationHubs/src/com/windowsazure/messaging/BrowserNotification.java @@ -0,0 +1,4 @@ +package com.windowsazure.messaging; + +public class BrowserNotification extends Notification { +} diff --git a/NotificationHubs/src/com/windowsazure/messaging/BrowserPushChannel.java b/NotificationHubs/src/com/windowsazure/messaging/BrowserPushChannel.java new file mode 100644 index 0000000..77b09cd --- /dev/null +++ b/NotificationHubs/src/com/windowsazure/messaging/BrowserPushChannel.java @@ -0,0 +1,84 @@ +package com.windowsazure.messaging; + +import java.util.Objects; + +/** + * This class represents + */ +public class BrowserPushChannel { + private String endpoint; + private String p256dh; + private String auth; + + /** + * Creates a new instance of the BrowserPushChannel class. + */ + public BrowserPushChannel() { + + } + + /** + * Creates a new instance of the BrowserPushChannel class. + * @param endpoint The browser PNS endpoint URL. + * @param p256dh The P256DH key from the browser registration. + * @param auth The auth secret from the browser registration. + */ + public BrowserPushChannel( + String endpoint, + String p256dh, + String auth + ) { + this.endpoint = endpoint; + this.p256dh = p256dh; + this.auth = auth; + } + + /** + * Gets the browser PNS endpoint URL. + * @return The browser PNS endpoint URL. + */ + public String getEndpoint() { return endpoint; } + + /** + * Sets the browser PNS endpoint URL. + * @param value The browser PNS endpoint URL. + */ + public void setEndpoint(String value) { endpoint = value; } + + /** + * Gets the browser subscription p256dh key. + * @return The browser subscription p256dh key. + */ + public String getP256dh() { return p256dh; } + + /** + * Sets the browser subscription p256dh key. + * @param value The browser subscription p256dh key. + */ + public void setP256dh(String value) { p256dh = value; } + + /** + * Gets the browser subscription auth secret. + * @return The browser subscription auth secret. + */ + public String getAuth() { return auth; } + + /** + * Sets the browser subscription auth secret. + * @param value The browser subscription auth secret. + */ + public void setAuth(String value) { auth = value; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + BrowserPushChannel that = (BrowserPushChannel) o; + return Objects.equals(getEndpoint(), that.getEndpoint()) && Objects.equals(getP256dh(), that.getP256dh()) && Objects.equals(getAuth(), that.getAuth()); + } + + @Override + public int hashCode() { + return Objects.hash(getEndpoint(), getP256dh(), getAuth()); + } +} diff --git a/NotificationHubs/src/com/windowsazure/messaging/BrowserRegistration.java b/NotificationHubs/src/com/windowsazure/messaging/BrowserRegistration.java new file mode 100644 index 0000000..d799af2 --- /dev/null +++ b/NotificationHubs/src/com/windowsazure/messaging/BrowserRegistration.java @@ -0,0 +1,119 @@ +//---------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +//---------------------------------------------------------------- + +package com.windowsazure.messaging; + +import java.util.Objects; + +/** + * This class represents a Browser Push device registration. + */ +public class BrowserRegistration extends Registration { + private static final String BROWSER_NATIVE_REGISTRATION1 = ""; + private static final String BROWSER_NATIVE_REGISTRATION2 = ""; + private static final String BROWSER_NATIVE_REGISTRATION3 = ""; + private static final String BROWSER_NATIVE_REGISTRATION4 = ""; + private static final String BROWSER_NATIVE_REGISTRATION5 = ""; + + protected String endpoint; + protected String p256dh; + protected String auth; + + /** + * Creates a new instance of the BrowserRegistration class. + */ + public BrowserRegistration() { + super(); + } + + /** + * Creates a new instance of the BrowserRegistration class with endpoint, p256dh and auth secret. + * @param endpoint The browser PNS endpoint URL. + * @param p256dh The P256DH key from the browser registration. + * @param auth The auth secret from the browser registration. + */ + public BrowserRegistration(String endpoint, String p256dh, String auth) { + super(); + this.endpoint = endpoint; + this.p256dh = p256dh; + this.auth = auth; + } + + /** + * Creates a new instance of the BrowserRegistration class with endpoint, p256dh and auth secret. + * @param registrationId The Azure Notification Hubs registration ID. + * @param endpoint The browser PNS endpoint URL. + * @param p256dh The P256DH key from the browser registration. + * @param auth The auth secret from the browser registration. + */ + public BrowserRegistration(String registrationId, String endpoint, String p256dh, String auth) { + super(registrationId); + this.endpoint = endpoint; + this.p256dh = p256dh; + this.auth = auth; + } + + /** + * Gets the browser PNS endpoint URL. + * @return The browser PNS endpoint URL. + */ + public String getEndpoint() { return endpoint; } + + /** + * Sets the browser PNS endpoint URL. + * @param value The browser PNS endpoint URL. + */ + public void setEndpoint(String value) { endpoint = value; } + + /** + * Gets the browser subscription p256dh key. + * @return The browser subscription p256dh key. + */ + public String getP256dh() { return p256dh; } + + /** + * Sets the browser subscription p256dh key. + * @param value The browser subscription p256dh key. + */ + public void setP256dh(String value) { p256dh = value; } + + /** + * Gets the browser subscription auth secret. + * @return The browser subscription auth secret. + */ + public String getAuth() { return auth; } + + /** + * Sets the browser subscription auth secret. + * @param value The browser subscription auth secret. + */ + public void setAuth(String value) { auth = value; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + BrowserRegistration that = (BrowserRegistration) o; + return Objects.equals(getEndpoint(), that.getEndpoint()) && Objects.equals(getP256dh(), that.getP256dh()) && Objects.equals(getAuth(), that.getAuth()); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), getEndpoint(), getP256dh(), getAuth()); + } + + @Override + public String getXml() { + return BROWSER_NATIVE_REGISTRATION1 + + getTagsXml() + + BROWSER_NATIVE_REGISTRATION2 + + endpoint + + BROWSER_NATIVE_REGISTRATION3 + + p256dh + + BROWSER_NATIVE_REGISTRATION4 + + auth + + BROWSER_NATIVE_REGISTRATION5; + } +} diff --git a/NotificationHubs/src/com/windowsazure/messaging/BrowserTemplateRegistration.java b/NotificationHubs/src/com/windowsazure/messaging/BrowserTemplateRegistration.java new file mode 100644 index 0000000..bd7ba35 --- /dev/null +++ b/NotificationHubs/src/com/windowsazure/messaging/BrowserTemplateRegistration.java @@ -0,0 +1,87 @@ +package com.windowsazure.messaging; + +/** + * This class represents a Browser Push device template registration. + */ +public class BrowserTemplateRegistration extends BrowserRegistration implements TemplateRegistration { + private static final String BROWSER_TEMPLATE_REGISTRATION1 = ""; + private static final String BROWSER_TEMPLATE_REGISTRATION2 = ""; + private static final String BROWSER_TEMPLATE_REGISTRATION3 = ""; + private static final String BROWSER_TEMPLATE_REGISTRATION4 = ""; + private static final String BROWSER_TEMPLATE_REGISTRATION5 = ""; + + private String bodyTemplate; + + /** + * Creates a new instance of the BrowserTemplateRegistration class. + */ + public BrowserTemplateRegistration() { + super(); + } + + /** + * Creates a new instance of the BrowserTemplateRegistration class. + * @param registrationId The Azure Notification Hubs registration ID. + * @param endpoint The browser push registration endpoint URL. + * @param p256dh The browser push registration P256DH. + * @param auth The browser push registration auth secret. + * @param bodyTemplate The browser push registration template body. + */ + public BrowserTemplateRegistration( + String registrationId, + String endpoint, + String p256dh, + String auth, + String bodyTemplate + ) { + super(registrationId, endpoint, p256dh, auth); + this.bodyTemplate = bodyTemplate; + } + + /** + * Creates a new instance of the BrowserTemplateRegistration class. + * @param endpoint The browser push registration endpoint URL. + * @param p256dh The browser push registration P256DH. + * @param auth The browser push registration auth secret. + * @param bodyTemplate The browser push registration template body. + */ + public BrowserTemplateRegistration( + String endpoint, + String p256dh, + String auth, + String bodyTemplate + ) { + super(endpoint, p256dh, auth); + this.bodyTemplate = bodyTemplate; + } + + /** + * Gets the registration template body. + * @return The registration template body. + */ + @Override + public String getBodyTemplate() { return bodyTemplate; } + + /** + * Sets the registration template body. + * @param value The registration template body to set. + */ + @Override + public void setBodyTemplate(String value) { this.bodyTemplate = value; } + + @Override + public String getXml() { + return BROWSER_TEMPLATE_REGISTRATION1 + + getTagsXml() + + BROWSER_TEMPLATE_REGISTRATION2 + + endpoint + + BROWSER_TEMPLATE_REGISTRATION3 + + p256dh + + BROWSER_TEMPLATE_REGISTRATION4 + + auth + + BROWSER_TEMPLATE_REGISTRATION5 + + bodyTemplate + + BROWSER_TEMPLATE_REGISTRATION6; + } +} diff --git a/NotificationHubs/src/com/windowsazure/messaging/CollectionResult.java b/NotificationHubs/src/com/windowsazure/messaging/CollectionResult.java index 49316ac..6cab296 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/CollectionResult.java +++ b/NotificationHubs/src/com/windowsazure/messaging/CollectionResult.java @@ -14,29 +14,41 @@ public class CollectionResult { private String continuationToken; private final List registrations = new LinkedList<>(); + /** + * Creates a new instance of the CollectionResult class. + */ public CollectionResult() { - // TODO Auto-generated constructor stub - } - public void addRegistration(Registration registration) { - registrations.add(registration); } - public List getRegistrations() { - return registrations; + CollectionResult(List registrations, String continuationToken) { + this.registrations.addAll(registrations); + this.continuationToken = continuationToken; } + /** + * Gets the registrations from the list. + * @return The registrations from the list. + */ + public List getRegistrations() { return registrations; } + /** * Gets the continuation token for this result. If the continuation is null, * then there are no more registration in this result set. * - * @return continuation token + * @return The continuation token */ public String getContinuationToken() { return continuationToken; } - public void setContinuationToken(String continuationToken) { - this.continuationToken = continuationToken; + /** + * Sets the continuation token. + * @param value The continuation token. + */ + void setContinuationToken(String value) { + continuationToken = value; } + + public void addRegistration(Registration registration) { registrations.add(registration); } } diff --git a/NotificationHubs/src/com/windowsazure/messaging/FcmCredential.java b/NotificationHubs/src/com/windowsazure/messaging/FcmCredential.java index 698135e..0d243a3 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/FcmCredential.java +++ b/NotificationHubs/src/com/windowsazure/messaging/FcmCredential.java @@ -8,26 +8,41 @@ import java.util.ArrayList; import java.util.List; +/** + * This class represents Azure Notification Hubs credentials for Firebase Messaging. + */ public final class FcmCredential extends PnsCredential { + private String googleApiKey; + /** + * Creates a new instance of the FcmCredential class. + */ public FcmCredential() { - this(null); + } + /** + * Creates a new instance of the FcmCredential class. + * @param googleApiKey The Google API key from Firebase. + */ public FcmCredential(String googleApiKey) { super(); - this.setGoogleApiKey(googleApiKey); - } - - public String getGoogleApiKey() { - return googleApiKey; - } - - public void setGoogleApiKey(String googleApiKey) { this.googleApiKey = googleApiKey; } + /** + * Gets the Google API key for Firebase Messaging. + * @return The Google API key for Firebase Messaging. + */ + public String getGoogleApiKey() { return googleApiKey; } + + /** + * Sets the Google API key for Firebase Messaging. + * @param value The Google API key for Firebase Messaging to set. + */ + public void setGoogleApiKey(String value) { googleApiKey = value; } + @Override public List> getProperties() { ArrayList> result = new ArrayList<>(); diff --git a/NotificationHubs/src/com/windowsazure/messaging/FcmNotification.java b/NotificationHubs/src/com/windowsazure/messaging/FcmNotification.java new file mode 100644 index 0000000..4baac87 --- /dev/null +++ b/NotificationHubs/src/com/windowsazure/messaging/FcmNotification.java @@ -0,0 +1,19 @@ +package com.windowsazure.messaging; + +import org.apache.http.entity.ContentType; + +/** + * This class represents a notification to the Firebase Cloud Messaging service. + */ +public class FcmNotification extends Notification { + + /** + * Creates a new instance of the FcmNotification class. + * @param body The JSON body for the Firebase Cloud Messaging service. + */ + public FcmNotification(String body) { + this.body = body; + this.contentType = ContentType.APPLICATION_JSON; + this.headers.put("ServiceBusNotification-Format", "gcm"); + } +} diff --git a/NotificationHubs/src/com/windowsazure/messaging/FcmRegistration.java b/NotificationHubs/src/com/windowsazure/messaging/FcmRegistration.java index 36cca78..61a092c 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/FcmRegistration.java +++ b/NotificationHubs/src/com/windowsazure/messaging/FcmRegistration.java @@ -4,6 +4,8 @@ package com.windowsazure.messaging; +import java.util.Objects; + /** * Class representing a native registration for devices using FCM. */ @@ -14,54 +16,56 @@ public class FcmRegistration extends Registration { protected String fcmRegistrationId; + /** + * Creates a new instance of the FcmRegistration class. + */ public FcmRegistration() { super(); } + /** + * Creates a new instance of the FcmRegistration with a registration ID and FCM registration ID. + * @param registrationId The Azure Notification Hubs registration ID. + * @param fcmRegistrationId The Firebase Cloud Messaging registration ID. + */ public FcmRegistration(String registrationId, String fcmRegistrationId) { super(registrationId); this.fcmRegistrationId = fcmRegistrationId; } + /** + * Creates a new instance of the FcmRegistration with a Firebase Cloud Messaging registration ID. + * @param fcmRegistrationId The Firebase Cloud Messaging registration ID. + */ public FcmRegistration(String fcmRegistrationId) { super(); this.fcmRegistrationId = fcmRegistrationId; } - public String getFcmRegistrationId() { - return fcmRegistrationId; - } + /** + * Gets the Firebase Messaging registration ID. + * @return The Firebase Messaging registration ID. + */ + public String getFcmRegistrationId() { return fcmRegistrationId; } - public void setFcmRegistrationId(String fcmRegistrationId) { - this.fcmRegistrationId = fcmRegistrationId; - } + /** + * Sets the Firebase Messaging registration ID. + * @param value The Firebase Messaging registration ID to set. + */ + public void setFcmRegistrationId(String value) { fcmRegistrationId = value; } @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime - * result - + ((fcmRegistrationId == null) ? 0 : fcmRegistrationId - .hashCode()); - return result; + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + FcmRegistration that = (FcmRegistration) o; + return Objects.equals(getFcmRegistrationId(), that.getFcmRegistrationId()); } @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (!super.equals(obj)) - return false; - if (getClass() != obj.getClass()) - return false; - FcmRegistration other = (FcmRegistration) obj; - if (fcmRegistrationId == null) { - if (other.fcmRegistrationId != null) - return false; - } else if (!fcmRegistrationId.equals(other.fcmRegistrationId)) - return false; - return true; + public int hashCode() { + return Objects.hash(super.hashCode(), getFcmRegistrationId()); } @Override diff --git a/NotificationHubs/src/com/windowsazure/messaging/FcmTemplateRegistration.java b/NotificationHubs/src/com/windowsazure/messaging/FcmTemplateRegistration.java index 420fc25..90ffeab 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/FcmTemplateRegistration.java +++ b/NotificationHubs/src/com/windowsazure/messaging/FcmTemplateRegistration.java @@ -4,7 +4,12 @@ package com.windowsazure.messaging; -public class FcmTemplateRegistration extends FcmRegistration { +import java.util.Objects; + +/** + * This class represents a Firebase Messaging device template registration. + */ +public class FcmTemplateRegistration extends FcmRegistration implements TemplateRegistration { private static final String FCM_TEMPLATE_REGISTRATION1 = ""; private static final String FCM_TEMPLATE_REGISTRATION2 = ""; private static final String FCM_TEMPLATE_REGISTRATION3 = "> getProperties() { - ArrayList> result = new ArrayList>(); + ArrayList> result = new ArrayList<>(); result.add(new SimpleEntry<>("GoogleApiKey", getGoogleApiKey())); return result; } diff --git a/NotificationHubs/src/com/windowsazure/messaging/GcmRegistration.java b/NotificationHubs/src/com/windowsazure/messaging/GcmRegistration.java index ac67f15..1336807 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/GcmRegistration.java +++ b/NotificationHubs/src/com/windowsazure/messaging/GcmRegistration.java @@ -4,6 +4,8 @@ package com.windowsazure.messaging; +import java.util.Objects; + /** * Class representing a native registration for devices using GCM. * @@ -18,54 +20,56 @@ public class GcmRegistration extends Registration { protected String gcmRegistrationId; + /** + * Creates a new instance of the GcmRegistration class. + */ public GcmRegistration() { super(); } + /** + * Creates a new instance of the GcmRegistration class. + * @param registrationId The Azure Notification Hubs registration ID. + * @param gcmRegistrationId The Google Cloud Messaging registration ID. + */ public GcmRegistration(String registrationId, String gcmRegistrationId) { super(registrationId); this.gcmRegistrationId = gcmRegistrationId; } + /** + * Creates a new instance of the GcmRegistration class. + * @param gcmRegistrationId The Google Cloud Messaging registration ID. + */ public GcmRegistration(String gcmRegistrationId) { super(); this.gcmRegistrationId = gcmRegistrationId; } - public String getGcmRegistrationId() { - return gcmRegistrationId; - } + /** + * Gets the Google Cloud Messaging registration ID. + * @return The Google Cloud Messaging registration ID. + */ + public String getGcmRegistrationId() { return gcmRegistrationId; } - public void setGcmRegistrationId(String gcmRegistrationId) { - this.gcmRegistrationId = gcmRegistrationId; - } + /** + * Sets the Google Cloud Messaging registration ID. + * @param value The Google Cloud Messaging registration ID to set. + */ + public void setGcmRegistrationId(String value) { gcmRegistrationId = value; } @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime - * result - + ((gcmRegistrationId == null) ? 0 : gcmRegistrationId - .hashCode()); - return result; + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + GcmRegistration that = (GcmRegistration) o; + return Objects.equals(getGcmRegistrationId(), that.getGcmRegistrationId()); } @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (!super.equals(obj)) - return false; - if (getClass() != obj.getClass()) - return false; - GcmRegistration other = (GcmRegistration) obj; - if (gcmRegistrationId == null) { - if (other.gcmRegistrationId != null) - return false; - } else if (!gcmRegistrationId.equals(other.gcmRegistrationId)) - return false; - return true; + public int hashCode() { + return Objects.hash(super.hashCode(), getGcmRegistrationId()); } @Override @@ -76,5 +80,4 @@ public String getXml() { gcmRegistrationId + GCM_NATIVE_REGISTRATION3; } - } diff --git a/NotificationHubs/src/com/windowsazure/messaging/GcmTemplateRegistration.java b/NotificationHubs/src/com/windowsazure/messaging/GcmTemplateRegistration.java index 712b3a7..2218b9d 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/GcmTemplateRegistration.java +++ b/NotificationHubs/src/com/windowsazure/messaging/GcmTemplateRegistration.java @@ -4,11 +4,13 @@ package com.windowsazure.messaging; +import java.util.Objects; + /** * @deprecated use {@link com.windowsazure.messaging.FcmTemplateRegistration#FcmTemplateRegistration()} instead. */ @Deprecated -public class GcmTemplateRegistration extends GcmRegistration { +public class GcmTemplateRegistration extends GcmRegistration implements TemplateRegistration { private static final String GCM_TEMPLATE_REGISTRATION1 = ""; private static final String GCM_TEMPLATE_REGISTRATION2 = ""; private static final String GCM_TEMPLATE_REGISTRATION3 = " callback); - - /** - * Patches an installation with the given installation ID. - * - * @param installationId The installation ID to patch. - * @param operations The list of operations to perform on the installation. - * @throws NotificationHubsException Thrown if there is a client error. - */ - void patchInstallation(String installationId, PartialUpdateOperation... operations) - throws NotificationHubsException; - - /** - * Patches an installation with the given installation ID. - * - * @param installationId The installation ID to patch. - * @param callback A callback, when invoked, returns nothing. - * @param operations The list of operations to perform on the installation. - */ - void patchInstallationAsync(String installationId, FutureCallback callback, - PartialUpdateOperation... operations); - - /** - * Patches an installation with the given installation ID. - * - * @param installationId The installation ID to patch. - * @param operations The list of operations to perform on the installation. - * @throws NotificationHubsException Thrown if there is a client error. - */ - void patchInstallation(String installationId, List operations) - throws NotificationHubsException; - - /** - * Patches an installation with the given installation ID. - * - * @param installationId The installation ID to patch. - * @param operations The list of operations to perform on the installation. - * @param callback A callback, when invoked, returns nothing. - */ - void patchInstallationAsync(String installationId, List operations, - FutureCallback callback); - - /** - * Deletes an installation with the given installation ID. - * - * @param installationId The installation ID. - * @throws NotificationHubsException Thrown if there is a client error. - */ - void deleteInstallation(String installationId) throws NotificationHubsException; - - /** - * Deletes an installation with the given installation ID. - * - * @param installationId The installation ID. - * @param callback A callback, when invoked, returns nothing. - */ - void deleteInstallationAsync(String installationId, FutureCallback callback); - - /** - * Gets an installation by the given installation ID. - * - * @param installationId The installation ID for the installation to get. - * @return The matching installation by the installation ID. - * @throws NotificationHubsException Thrown if there is a client error. - */ - Installation getInstallation(String installationId) throws NotificationHubsException; - - /** - * Gets an installation by the given installation ID. - * - * @param installationId The installation ID for the installation to get. - * @param callback A callback, when invoked, returns the matching - * installation by the installation ID. - */ - void getInstallationAsync(String installationId, FutureCallback callback); - - /** - * Submits a notification hub job such as import or export. - * - * @param job The notification hubs job to submit. - * @return The notification job with status. - * @throws NotificationHubsException Thrown if there is a client error. - */ - NotificationHubJob submitNotificationHubJob(NotificationHubJob job) throws NotificationHubsException; - - /** - * Submits a notification hub job such as import or export. - * - * @param job The notification hubs job to submit. - * @param callback A callback, when invoked, returns the notification job with - * status. - */ - void submitNotificationHubJobAsync(NotificationHubJob job, FutureCallback callback); - - /** - * Gets a notification hub job by the job ID. - * - * @param jobId The job ID of the notification hub job to get. - * @return The notification hub job with the matching job ID. - * @throws NotificationHubsException Thrown if there is a client error. - */ - NotificationHubJob getNotificationHubJob(String jobId) throws NotificationHubsException; - - /** - * Gets a notification hub job by the job ID. - * - * @param jobId The job ID of the notification hub job to get. - * @param callback A callback, when invoked, returns the notification hub job - * with the matching job ID. - */ - void getNotificationHubJobAsync(String jobId, FutureCallback callback); - - /** - * Gets all notification hub jobs for this namespace. - * - * @return All notification hub jobs for this namespace. - * @throws NotificationHubsException Thrown if there is a client error. - */ - List getAllNotificationHubJobs() throws NotificationHubsException; - - /** - * Gets all notification hub jobs for this namespace. - * - * @param callback A callback, when invoked, returns all notification hub jobs - * for this namespace. - */ - void getAllNotificationHubJobsAsync(FutureCallback> callback); - - /** - * Gets notification telemetry by the notification ID. - * - * @param notificationId The notification ID for the telemetry. - * @return The notification telemetry for the given notification. - * @throws NotificationHubsException Thrown if there is a client error. - */ - NotificationTelemetry getNotificationTelemetry(String notificationId) throws NotificationHubsException; - - /** - * Gets notification telemetry by the notification ID. - * - * @param notificationId The notification ID for the telemetry. - * @param callback A callback, when invoked, returns the notification - * telemetry for the given notification. - */ - void getNotificationTelemetryAsync(String notificationId, FutureCallback callback); - - /** - * Create a registrationId, without creating an actual registration. To create - * use upsert. This method is used when the registration id is stored only on - * the device. - * - * @return The newly created registration ID. - * @throws NotificationHubsException Thrown if there is a client error. - */ - String createRegistrationId() throws NotificationHubsException; - - /** - * Create a registrationId, without creating an actual registration. To create - * use upsert. This method is used when the registration id is stored only on - * the device. - * - * @param callback A callback with the newly created registration ID. - */ - void createRegistrationIdAsync(FutureCallback callback); - - /** - * This method creates a new registration - * - * @param registration A registration object containing the description of the - * registration to create. ETag and registration ID are - * ignored - * @return The created registration containing the read-only parameters - * (registration ID, ETag, and expiration time). - * @throws NotificationHubsException Thrown if there is a client error. - */ - Registration createRegistration(Registration registration) throws NotificationHubsException; - - /** - * This method creates a new registration - * - * @param registration A registration object containing the description of the - * registration to create. ETag and registration ID are - * ignored - * @param callback A callback when invoked returns created registration - * containing the read-only parameters (registration ID, - * ETag, and expiration time) - */ - void createRegistrationAsync(Registration registration, FutureCallback callback); - - /** - * This methods updates an existing registration - * - * @param registration A registration object containing the description of the - * registration to update. The registration ID has to be - * populated. - * @return The updated registration containing the read-only parameters - * (registration ID, ETag, and expiration time). - * @throws NotificationHubsException Thrown if there is a client error. - */ - Registration updateRegistration(Registration registration) throws NotificationHubsException; - - /** - * This methods updates an existing registration - * - * @param registration A registration object containing the description of the - * registration to update. The registration ID must be - * populated. - * @param callback A callback when invoked, returns the updated registration - * containing the read-only parameters (registration ID, - * ETag, and expiration time). - */ - void updateRegistrationAsync(Registration registration, FutureCallback callback); - - /** - * This method updates or creates a new registration with the registration ID - * specified. - * - * @param registration A registration object containing the description of the - * registration to create or update. The registration ID - * must be populated. - * @return The updated registration containing the read-only parameters - * (registration ID, ETag, and expiration time). - * @throws NotificationHubsException Thrown if there is a client error. - */ - Registration upsertRegistration(Registration registration) throws NotificationHubsException; - - /** - * This method updates or creates a new registration with the registration id - * specified. - * - * @param registration A registration object containing the description of the - * registration to create or update. The registration ID - * must be populated. - * @param callback A callback, when invoked, returns the updated - * registration containing the read-only parameters - * (registration ID, ETag, and expiration time). - */ - void upsertRegistrationAsync(Registration registration, FutureCallback callback); - - /** - * Deletes a registration with the given registration containing a populated - * registrationId. - * - * @param registration The registration containing the registrationId field - * populated. - * @throws NotificationHubsException Thrown if there is a client error. - */ - void deleteRegistration(Registration registration) throws NotificationHubsException; - - /** - * Deletes a registration with the given registration containing a populated - * registrationId. - * - * @param registration The registration containing the registrationId field - * populated. - * @param callback A callback when invoked returns nothing. - */ - void deleteRegistrationAsync(Registration registration, FutureCallback callback); - - /** - * Deletes a registration by the given registration ID. - * - * @param registrationId The registration ID for the registration to delete. - * @throws NotificationHubsException Thrown if there is a client error. - */ - void deleteRegistration(String registrationId) throws NotificationHubsException; - - /** - * Deletes a registration by the given registration ID. - * - * @param registrationId The registration ID for the registration to delete. - * @param callback A callback when invoked returns nothing. - */ - void deleteRegistrationAsync(String registrationId, FutureCallback callback); - - /** - * Retrieves the description of a registration based on the ID. - * - * @param registrationId The ID for the registration to retrieve. - * @return The registration with the ID matching the given registration ID. - * @throws NotificationHubsException Thrown if there is a client error. - */ - Registration getRegistration(String registrationId) throws NotificationHubsException; - - /** - * Retrieves the description of a registration based on the ID. - * - * @param registrationId The ID for the registration to retrieve. - * @param callback A callback, when invoked, returns the registration with - * the ID matching the given registration ID. - */ - void getRegistrationAsync(String registrationId, FutureCallback callback); - - /** - * Return all registrations in the current notification hub. - * - * @return Collection containing the registrations. - * @throws NotificationHubsException Thrown if there is a client error. - */ - CollectionResult getRegistrations() throws NotificationHubsException; - - /** - * Return all registrations in the current notification hub. - * - * @param callback The callback when invoked, returns a collection containing - * registrations. - */ - void getRegistrationsAsync(FutureCallback callback); - - /** - * Returns all registrations in this hub - * - * @param top The maximum number of registrations to return (max - * 100) - * @param continuationToken If not-null, continues iterating through a - * previously requested query. - * @return A collection containing the registrations. - * @throws NotificationHubsException Thrown if there is a client error. - */ - CollectionResult getRegistrations(int top, String continuationToken) throws NotificationHubsException; - - /** - * Returns all registrations in this hub - * - * @param top The maximum number of registrations to return (max - * 100) - * @param continuationToken If not-null, continues iterating through a - * previously requested query. - * @param callback A callback when invoked returns a collection - * containing the registrations. - */ - void getRegistrationsAsync(int top, String continuationToken, FutureCallback callback); - - /** - * Returns all registrations with a specific tag - * - * @param tag The tag to search for registrations. - * @return A collection of registrations with the given tag. - * @throws NotificationHubsException Thrown if there is a client error. - */ - CollectionResult getRegistrationsByTag(String tag) throws NotificationHubsException; - - /** - * Returns all registrations with a specific tag - * - * @param tag The tag to search for registrations. - * @param callback A callback, when invoked, returns a collection of - * registrations with the given tag. - */ - void getRegistrationsByTagAsync(String tag, FutureCallback callback); - - /** - * Returns all registrations with a specific tag - * - * @param tag The tag to search for registrations. - * @param top The maximum number of registrations to return (max - * 100) - * @param continuationToken If not-null, continues iterating through a - * previously requested query. - * @return A collection of registrations with the given tag. - * @throws NotificationHubsException Thrown if there is a client error. - */ - CollectionResult getRegistrationsByTag(String tag, int top, String continuationToken) - throws NotificationHubsException; - - /** - * Returns all registrations with a specific tag - * - * @param tag The tag to search for registrations. - * @param top The maximum number of registrations to return (max - * 100) - * @param continuationToken If not-null, continues iterating through a - * previously requested query. - * @param callback A callback when invoked, returns a collection of - * registrations with the given tag. - */ - void getRegistrationsByTagAsync(String tag, int top, String continuationToken, - FutureCallback callback); - - /** - * Returns all registration with a specific channel (e.g. ChannelURI, device - * token) - * - * @param channel The channel URI, device token or other unique PNS identifier. - * @return A collection of registrations with matching channels. - * @throws NotificationHubsException Thrown if there is a client error. - */ - CollectionResult getRegistrationsByChannel(String channel) throws NotificationHubsException; - - /** - * Returns all registration with a specific channel (e.g. ChannelURI, device - * token) - * - * @param channel The channel URI, device token or other unique PNS identifier. - * @param callback A callback, when invoked, returns a collection of - * registrations with matching channels. - */ - void getRegistrationsByChannelAsync(String channel, FutureCallback callback); - - /** - * Returns all registration with a specific channel (e.g. ChannelURI, device - * token) - * - * @param channel The channel URI, device token or other unique PNS - * identifier. - * @param top The maximum number of registrations to return (max - * 100) - * @param continuationToken If not-null, continues iterating through a - * previously requested query. - * @return A collection of registrations with matching channels. - * @throws NotificationHubsException Thrown if there is a client error. - */ - CollectionResult getRegistrationsByChannel(String channel, int top, String continuationToken) - throws NotificationHubsException; - - /** - * Returns all registration with a specific channel (e.g. ChannelURI, device - * token) - * - * @param channel The channel URI, device token or other unique PNS - * identifier. - * @param top The maximum number of registrations to return (max - * 100) - * @param continuationToken If not-null, continues iterating through a - * previously requested query. - * @param callback A callback, when invoked, returns a collection of - * registrations with matching channels. - */ - void getRegistrationsByChannelAsync(String channel, int top, String continuationToken, - FutureCallback callback); - - /** - * Sends a notification to all eligible registrations (i.e. only correct - * platform, if notification is platform specific) - * - * @param notification The notification to send to all eligible registrations. - * @return A notification outcome with the tracking ID and notification ID. - * @throws NotificationHubsException Thrown if there is a client error. - */ - NotificationOutcome sendNotification(Notification notification) throws NotificationHubsException; - - /** - * Sends a notification to all eligible registrations (i.e. only correct - * platform, if notification is platform specific) - * - * @param notification The notification to send to all eligible registrations. - * @param callback A callback, when invoked, returns a notification outcome - * with the tracking ID and notification ID. - */ - void sendNotificationAsync(Notification notification, FutureCallback callback); - - /** - * Sends a notifications to all eligible registrations with at least one of the - * specified tags - * - * @param notification The notification to send to the audience with the - * specified tags. - * @param tags The tags for targeting the notifications. - * @return A notification outcome with the tracking ID and notification ID. - * @throws NotificationHubsException Thrown if there is a client error. - */ - NotificationOutcome sendNotification(Notification notification, Set tags) throws NotificationHubsException; - - /** - * Sends a notifications to all eligible registrations with at least one of the - * specified tags - * - * @param notification The notification to send to the audience with the - * specified tags. - * @param tags The tags for targeting the notifications. - * @param callback A callback, when invoked, returns a notification outcome - * with the tracking ID and notification ID. - */ - void sendNotificationAsync(Notification notification, Set tags, - FutureCallback callback); - - /** - * Sends a notifications to all eligible registrations that satisfy the provided - * tag expression. - * - * @param notification The notification to send to the audience that matches - * the specified tag expression. - * @param tagExpression The tag expression for targeting the notifications. - * @return A notification outcome with the tracking ID and notification ID. - * @throws NotificationHubsException Thrown if there is a client error. - */ - NotificationOutcome sendNotification(Notification notification, String tagExpression) - throws NotificationHubsException; - - /** - * Sends a notifications to all eligible registrations that satisfy the provided - * tag expression. - * - * @param notification The notification to send to the audience that matches - * the specified tag expression. - * @param tagExpression The tag expression for targeting the notifications. - * @param callback A callback, when invoked, returns a notification outcome - * with the tracking ID and notification ID. - */ - void sendNotificationAsync(Notification notification, String tagExpression, - FutureCallback callback); - - /** - * Schedules a notification at the given scheduled time. - * - * @param notification The notification to send at the scheduled time. - * @param scheduledTime The scheduled time for the notification. - * @return A notification outcome with the tracking ID and notification ID. - * @throws NotificationHubsException Thrown if there is a client error. - */ - NotificationOutcome scheduleNotification(Notification notification, Date scheduledTime) - throws NotificationHubsException; - - /** - * Schedules a notification at the given scheduled time. - * - * @param notification The notification to send at the scheduled time. - * @param scheduledTime The scheduled time for the notification. - * @param callback A callback, when invoked, returns a notification outcome - * with the tracking ID and notification ID. - */ - void scheduleNotificationAsync(Notification notification, Date scheduledTime, - FutureCallback callback); - - /** - * Schedules a notification at the given time with a set of tags. - * - * @param notification The notification to send at the given time. - * @param tags The tags associated with the notification targeting. - * @param scheduledTime The scheduled time for the notification. - * @return A notification outcome with the tracking ID and notification ID. - * @throws NotificationHubsException Thrown if there is a client error. - */ - NotificationOutcome scheduleNotification(Notification notification, Set tags, Date scheduledTime) - throws NotificationHubsException; - - /** - * Schedules a notification at the given time with a set of tags. - * - * @param notification The notification to send at the given time. - * @param tags The tags associated with the notification targeting. - * @param scheduledTime The scheduled time for the notification. - * @param callback A callback, when invoked, returns a notification outcome - * with the tracking ID and notification ID. - */ - void scheduleNotificationAsync(Notification notification, Set tags, Date scheduledTime, - FutureCallback callback); - - /** - * Schedules a notification at the given time with a tag expression. - * - * @param notification The notification to send at the given time. - * @param tagExpression The tag expression associated with the notification - * targeting. - * @param scheduledTime The scheduled time for the notification. - * @return A notification outcome with the tracking ID and notification ID. - * @throws NotificationHubsException Thrown if there is a client error. - */ - NotificationOutcome scheduleNotification(Notification notification, String tagExpression, Date scheduledTime) - throws NotificationHubsException; - - /** - * Schedules a notification at the given time with a tag expression. - * - * @param notification The notification to send at the given time. - * @param tagExpression The tag expression associated with the notification - * targeting. - * @param scheduledTime The scheduled time for the notification. - * @param callback A callback, when invoked, returns a notification outcome - * with the tracking ID and notification ID. - */ - void scheduleNotificationAsync(Notification notification, String tagExpression, Date scheduledTime, - FutureCallback callback); - - /** - * Sends a direct notification to a given device handle. - * - * @param notification The notification to send directly to the device handle. - * @param deviceHandle The device handle to target for the notification. - * @return A notification outcome with the tracking ID and notification ID. - * @throws NotificationHubsException Thrown if there is a client error. - */ - NotificationOutcome sendDirectNotification(Notification notification, String deviceHandle) - throws NotificationHubsException; - - /** - * Sends a direct notification to a given device handle. - * - * @param notification The notification to send directly to the device handle. - * @param deviceHandle The device handle to target for the notification. - * @param callback A callback, when invoked, returns a notification outcome - * with the tracking ID and notification ID. - */ - void sendDirectNotificationAsync(Notification notification, String deviceHandle, - FutureCallback callback); - - /** - * Sends a direct notification to the given device handles. - * - * @param notification The notification to send directly to the device handles. - * @param deviceHandles The device handles to target for the notification. - * @return A notification outcome with the tracking ID and notification ID. - * @throws NotificationHubsException Thrown if there is a client error. - */ - NotificationOutcome sendDirectNotification(Notification notification, List deviceHandles) - throws NotificationHubsException; - - /** - * Sends a direct notification to the given device handles. - * - * @param notification The notification to send directly to the device handles. - * @param deviceHandles The device handles to target for the notification. - * @param callback A callback, when invoked, returns a notification outcome - * with the tracking ID and notification ID. - */ - void sendDirectNotificationAsync(Notification notification, List deviceHandles, - FutureCallback callback); - - /** - * Cancels the scheduled notification with the given notification ID. - * - * @param notificationId The notification ID of the notification to cancel. - * @throws NotificationHubsException Thrown if there is a client error. - */ - void cancelScheduledNotification(String notificationId) throws NotificationHubsException; - - /** - * Cancels the scheduled notification with the given notification ID. - * - * @param notificationId The notification ID of the notification to cancel. - * @param callback A callback, when invoked, returns nothing. - */ - void cancelScheduledNotificationAsync(String notificationId, FutureCallback callback); -} diff --git a/NotificationHubs/src/com/windowsazure/messaging/Installation.java b/NotificationHubs/src/com/windowsazure/messaging/Installation.java index 10bc538..889ebda 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/Installation.java +++ b/NotificationHubs/src/com/windowsazure/messaging/Installation.java @@ -5,39 +5,21 @@ package com.windowsazure.messaging; import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import org.apache.commons.io.IOUtils; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; -import java.text.SimpleDateFormat; -import java.util.*; /** * Represents an installation for Azure Notification Hubs */ -public class Installation { +public class Installation extends BaseInstallation { - private String installationId; - private String userId; - private NotificationPlatform platform; private String pushChannel; - private boolean pushChannelExpired; - private String expirationTime; - private List tags; - private Map templates; - private Map secondaryTiles; /** - * Creates a new installation. - */ - public Installation() { - this(null); - } - - /** - * Creates a new installation with the given installation ID. + * Creates a new instance of the Installation class. * * @param installationId The ID for the installation. */ @@ -46,7 +28,7 @@ public Installation(String installationId) { } /** - * Creates an installation from the Installation ID and tags. + * Creates a new instance of the Installation class. * * @param installationId The ID for the installation. * @param tags The tags for the installation. @@ -56,61 +38,25 @@ public Installation(String installationId, String... tags) { } /** - * Creates an installation with an installation ID, platform and push channel. + * Creates a new instance of the Installation class. * * @param installationId The ID for the installation. * @param platform The platform for the installation. - * @param pushChannel The PNS specific channel for device. */ public Installation(String installationId, NotificationPlatform platform, String pushChannel) { this(installationId, platform, pushChannel, (String[]) null); } - public Installation(String installationId, NotificationPlatform platform, String pushChannel, String... tags) { - // Validate that this is not FCM - validateNotificationPlatform(platform); - - this.installationId = installationId; - this.platform = platform; - this.pushChannel = pushChannel; - if (tags != null) { - for (String tag : tags) { - this.addTag(tag); - } - } - } - /** - * Validates that the platform is not FCM. Currently Notification Hubs supports - * FCM Legacy as NotificationPlatform.Gcm Full support for FCM is not currently - * supported. See https://aka.ms/AA9dpaz - * - * @param notificationPlatform The notification platform to verify that it is - * not FCM. - */ - private static void validateNotificationPlatform(NotificationPlatform notificationPlatform) { - if (notificationPlatform == NotificationPlatform.Fcm) { - throw new RuntimeException( - "FCM is currently not supported, use NotificationPlatform.Gcm which uses FCM Legacy Mode. See https://aka.ms/AA9dpaz"); - } - } - - /** - * Gets the ID for the installation. - * - * @return The ID for the installation. - */ - public String getInstallationId() { - return installationId; - } - - /** - * Sets the ID for the installation. - * + * Creates a new instance of the Installation class. * @param installationId The ID for the installation. + * @param platform The platform for the installation + * @param pushChannel The device specific push channel for the installation. + * @param tags The tags for the installation. */ - public void setInstallationId(String installationId) { - this.installationId = installationId; + public Installation(String installationId, NotificationPlatform platform, String pushChannel, String... tags) { + super(installationId, platform, tags); + this.pushChannel = pushChannel; } /** @@ -118,222 +64,14 @@ public void setInstallationId(String installationId) { * * @return The PNS specific push channel for the installation. */ - public String getPushChannel() { - return pushChannel; - } + public String getPushChannel() { return pushChannel; } /** * Sets the PNS specific push channel for the installation. * - * @param pushChannel The PNS specific push channel for the installation - */ - public void setPushChannel(String pushChannel) { - this.pushChannel = pushChannel; - } - - /** - * Gets whether the push channel has expired - * - * @return Returns true if expired, false otherwise. + * @param value The PNS specific push channel for the installation */ - public boolean isPushChannelExpired() { - return pushChannelExpired; - } - - /** - * Gets the expiration time for the installation. - * - * @return The installation expiration time. - */ - public Date getExpirationTime() { - return javax.xml.bind.DatatypeConverter.parseDateTime(expirationTime).getTime(); - } - - /** - * Sets the expiration time for the installation. - * - * @param expirationTime The expiration time for the installation. - */ - public void setExpirationTime(Date expirationTime) { - SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'.'SSS'Z'"); - this.expirationTime = formatter.format(expirationTime); - } - - /** - * Gets the platform for the installation. - * - * @return The platform for the installation. - */ - public NotificationPlatform getPlatform() { - return platform; - } - - /** - * Sets the platform for the installation. Note that FCM is currently not - * supported, only GCM which is FCM Legacy. See https://aka.ms/AA9dpaz - * for more details. - * - * @param platform The platform for the installation. - */ - public void setPlatform(NotificationPlatform platform) { - // Validate that this is not FCM - validateNotificationPlatform(platform); - - this.platform = platform; - } - - /** - * Gets the user ID for the installation. - * - * @return The user ID for the installation. - */ - public String getUserId() { - return userId; - } - - /** - * Sets the user ID for the installation. - * - * @param userId The user ID for the installation. - */ - public void setUserId(String userId) { - this.userId = userId; - } - - /** - * Gets the tags for the installation. - * - * @return The tags for the installation. - */ - public List getTags() { - return tags; - } - - /** - * Adds a tag to the installation. - * - * @param tag The tag to add to the installation; - */ - public void addTag(String tag) { - if (this.tags == null) { - this.tags = new ArrayList<>(); - } - - this.tags.add(tag); - } - - /** - * Removes a tag from the installation. - * - * @param tag The tag to remove from the installation. - */ - public void removeTag(String tag) { - if (this.tags == null) { - return; - } - - this.tags.remove(tag); - } - - /** - * Clears the tags for the installation. - */ - public void clearTags() { - if (this.tags == null) { - return; - } - - this.tags.clear(); - } - - /** - * Gets the installation templates for the installation. - * - * @return The installation templates for the installation. - */ - public Map getTemplates() { - return templates; - } - - /** - * Adds an installation template by name to the installation. - * - * @param templateName The name for the installation template. - * @param template The template to add to the installation. - */ - public void addTemplate(String templateName, InstallationTemplate template) { - if (this.templates == null) { - this.templates = new HashMap<>(); - } - - this.templates.put(templateName, template); - } - - /** - * Removes an installation template based upon the template name. - * - * @param templateName The name of the installation template to remove. - */ - public void removeTemplate(String templateName) { - if (this.templates == null) { - return; - } - - this.templates.remove(templateName); - } - - /** - * Clears the installation templates. - */ - public void clearTemplates() { - if (this.templates == null) { - return; - } - - this.templates.clear(); - } - - /** - * Gets the secondary tiles for WNS - * - * @return The secondary tiles for WNS. - */ - public Map getSecondaryTiles() { - return secondaryTiles; - } - - /** - * Adds a secondary tile to the installation template. - * - * @param tileName The name for the tile. - * @param tile THe WNS secondary tile. - */ - public void addSecondaryTile(String tileName, WnsSecondaryTile tile) { - if (this.templates == null) { - this.secondaryTiles = new HashMap<>(); - } - - this.secondaryTiles.put(tileName, tile); - } - - public void removeSecondaryTile(String tileName) { - if (this.templates == null) { - return; - } - - this.secondaryTiles.remove(tileName); - } - - /** - * Clears the WNS secondary tiles. - */ - public void clearSecondaryTiles() { - if (this.templates == null) { - return; - } - - this.secondaryTiles.clear(); - } + public void setPushChannel(String value) { pushChannel = value; } /** * Creates an installation from the JSON string. @@ -355,13 +93,4 @@ public static Installation fromJson(String json) { public static Installation fromJson(InputStream json) throws IOException { return Installation.fromJson(IOUtils.toString(json, StandardCharsets.UTF_8)); } - - /** - * Converts the installation to a JSON string. - * - * @return The JSON string representation of the installation. - */ - public String toJson() { - return new GsonBuilder().disableHtmlEscaping().create().toJson(this); - } } diff --git a/NotificationHubs/src/com/windowsazure/messaging/InstallationTemplate.java b/NotificationHubs/src/com/windowsazure/messaging/InstallationTemplate.java index 928a843..7bf0fda 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/InstallationTemplate.java +++ b/NotificationHubs/src/com/windowsazure/messaging/InstallationTemplate.java @@ -6,6 +6,7 @@ import java.io.IOException; import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -29,7 +30,6 @@ public class InstallationTemplate { * Initializes a new installation template. */ public InstallationTemplate() { - this(null); } /** @@ -38,7 +38,7 @@ public InstallationTemplate() { * @param body The body for the installation template. */ public InstallationTemplate(String body) { - this(body, null); + this.body = body; } /** @@ -192,17 +192,6 @@ public static InstallationTemplate fromJson(String json) { return new Gson().fromJson(json, InstallationTemplate.class); } - /** - * Creates an installation template from the JSON input stream. - * - * @param json The JSON input stream. - * @return An installation template created from the JSON stream. - * @throws IOException If there was an issue with the Stream. - */ - public static Installation fromJson(InputStream json) throws IOException { - return Installation.fromJson(IOUtils.toString(json)); - } - /** * Converts the installation template to JSON. * diff --git a/NotificationHubs/src/com/windowsazure/messaging/MpnsCredential.java b/NotificationHubs/src/com/windowsazure/messaging/MpnsCredential.java index 221c276..91e7ee8 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/MpnsCredential.java +++ b/NotificationHubs/src/com/windowsazure/messaging/MpnsCredential.java @@ -8,35 +8,54 @@ import java.util.ArrayList; import java.util.List; +/** + * This class represents Windows Phone credentials for Azure Notification Hubs. + */ public final class MpnsCredential extends PnsCredential { private String mpnsCertificate; private String certificateKey; + /** + * Creates a new instance of the MpnsCredential class. + */ public MpnsCredential() { - this(null, null); + super(); } + /** + * Creates a new instance of the MpnsCredential class with certificate and certificate key. + * @param mpnsCertificate The Windows Phone PNS certificate. + * @param certificateKey THe Windows Phone PNS certificate key. + */ public MpnsCredential(String mpnsCertificate, String certificateKey) { super(); - this.setMpnsCertificate(mpnsCertificate); - this.setCertificateKey(certificateKey); + this.mpnsCertificate = mpnsCertificate; + this.certificateKey = certificateKey; } - public String getMpnsCertificate() { - return mpnsCertificate; - } + /** + * Gets the Windows Phone PNS certificate. + * @return The Windows Phone PNS certificate. + */ + public String getMpnsCertificate() { return mpnsCertificate; } - public void setMpnsCertificate(String mpnsCertificate) { - this.mpnsCertificate = mpnsCertificate; - } + /** + * Sets the Windows Phone PNS certificate. + * @param value The Windows Phone PNS certificate to set. + */ + public void setMpnsCertificate(String value) { mpnsCertificate = value; } - public String getCertificateKey() { - return certificateKey; - } + /** + * Gets the Windows Phone PNS certificate key. + * @return The Windows Phone PNS certificate key. + */ + public String getCertificateKey() { return certificateKey; } - public void setCertificateKey(String certificateKey) { - this.certificateKey = certificateKey; - } + /** + * Sets the Windows Phone PNS certificate key. + * @param value THe Windows Phone PNS certificate key. + */ + public void setCertificateKey(String value) { certificateKey = value; } @Override public List> getProperties() { diff --git a/NotificationHubs/src/com/windowsazure/messaging/MpnsNotification.java b/NotificationHubs/src/com/windowsazure/messaging/MpnsNotification.java new file mode 100644 index 0000000..73a4f27 --- /dev/null +++ b/NotificationHubs/src/com/windowsazure/messaging/MpnsNotification.java @@ -0,0 +1,32 @@ +package com.windowsazure.messaging; + +import org.apache.http.entity.ContentType; + +/** + * This class represents a Windows Phone notification. + */ +public class MpnsNotification extends Notification { + + /** + * Creates a new instance of the MpnsNotification class. + * @param body The XML body for the Windows Phone PNS. + */ + public MpnsNotification(String body) { + this.body = body; + + this.headers.put("ServiceBusNotification-Format", "windowsphone"); + + if (body.contains("")) { + this.headers.put("X-WindowsPhone-Target", "toast"); + this.headers.put("X-NotificationClass", "2"); + } + if (body.contains("")) { + this.headers.put("X-WindowsPhone-Target", "tile"); + this.headers.put("X-NotificationClass", "1"); + } + + if (body.startsWith("<")) { + this.contentType = ContentType.APPLICATION_XML; + } + } +} diff --git a/NotificationHubs/src/com/windowsazure/messaging/MpnsRegistration.java b/NotificationHubs/src/com/windowsazure/messaging/MpnsRegistration.java index bfc52fc..0fff9bc 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/MpnsRegistration.java +++ b/NotificationHubs/src/com/windowsazure/messaging/MpnsRegistration.java @@ -6,6 +6,7 @@ import java.net.URI; import java.net.URISyntaxException; +import java.util.Objects; /** * Class representing a native registration for a device using MPNS. @@ -17,23 +18,41 @@ public class MpnsRegistration extends Registration { protected URI channelUri; + /** + * Creates a new instance of the MpnsRegistration class. + */ public MpnsRegistration() { } + /** + * Creates a new instance of the MpnsRegistration class. + * @param channelUri The Windows Phone PNS channel URI. + */ public MpnsRegistration(URI channelUri) { super(); this.channelUri = channelUri; } + /** + * Creates a new instance of the MpnsRegistration class. + * @param registrationId The Azure Notification Hubs registration ID. + * @param channelUri The Windows Phone PNS channel URI. + */ public MpnsRegistration(String registrationId, URI channelUri) { super(registrationId); this.channelUri = channelUri; } - public URI getChannelUri() { - return channelUri; - } + /** + * Gets the Windows Phone PNS channel URI. + * @return The Windows Phone PNS channel URI. + */ + public URI getChannelUri() { return channelUri; } + /** + * Sets the Windows Phone PNS channel URI. + * @param channelUri The Windows Phone PNS channel URI to set. + */ public void setChannelUri(String channelUri) { try { this.channelUri = new URI(channelUri); @@ -42,31 +61,18 @@ public void setChannelUri(String channelUri) { } } - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result - + ((channelUri == null) ? 0 : channelUri.hashCode()); - return result; + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + MpnsRegistration that = (MpnsRegistration) o; + return Objects.equals(getChannelUri(), that.getChannelUri()); } @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (!super.equals(obj)) - return false; - if (getClass() != obj.getClass()) - return false; - MpnsRegistration other = (MpnsRegistration) obj; - if (channelUri == null) { - if (other.channelUri != null) - return false; - } else if (!channelUri.equals(other.channelUri)) - return false; - return true; + public int hashCode() { + return Objects.hash(super.hashCode(), getChannelUri()); } @Override @@ -77,5 +83,4 @@ public String getXml() { channelUri.toString() + MPNS_NATIVE_REGISTRATION3; } - } diff --git a/NotificationHubs/src/com/windowsazure/messaging/MpnsTemplateRegistration.java b/NotificationHubs/src/com/windowsazure/messaging/MpnsTemplateRegistration.java index 624fcba..a74dabc 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/MpnsTemplateRegistration.java +++ b/NotificationHubs/src/com/windowsazure/messaging/MpnsTemplateRegistration.java @@ -7,11 +7,12 @@ import java.net.URI; import java.util.HashMap; import java.util.Map; +import java.util.Objects; /** * Class representing a registration for template notifications for devices using MPNS. */ -public class MpnsTemplateRegistration extends MpnsRegistration { +public class MpnsTemplateRegistration extends MpnsRegistration implements TemplateRegistration { private static final String MPNS_TEMPLATE_REGISTRATION1 = ""; private static final String MPNS_TEMPLATE_REGISTRATION2 = ""; private static final String MPNS_TEMPLATE_REGISTRATION3 = ""; private String bodyTemplate; - private Map headers = new HashMap(); + private Map headers = new HashMap<>(); + /** + * Creates a new instance of the MpnsTemplateRegistration class. + */ public MpnsTemplateRegistration() { } - public MpnsTemplateRegistration(URI channelUri, String bodyTemplate, - Map headers) { + /** + * Creates a new instance of the MpnsTemplateRegistration class. + * @param channelUri The Windows Phone PNS channel URI. + * @param bodyTemplate The registration template body. + * @param headers The Windows Phone PNS headers. + */ + public MpnsTemplateRegistration( + URI channelUri, + String bodyTemplate, + Map headers + ) { super(channelUri); this.bodyTemplate = bodyTemplate; this.headers = headers; } - public MpnsTemplateRegistration(URI channelUri, - String bodyTemplate) { - super(channelUri); + /** + * Creates a new instance of the MpnsTemplateRegistration class. + * @param registrationId The Azure Notification Hubs registration ID. + * @param channelUri The Windows Phone PNS channel URI. + * @param bodyTemplate The registration template body. + * @param headers The Windows Phone PNS headers. + */ + public MpnsTemplateRegistration( + String registrationId, + URI channelUri, + String bodyTemplate, + Map headers + ) { + super(registrationId, channelUri); this.bodyTemplate = bodyTemplate; + this.headers = headers; } - public String getBodyTemplate() { - return bodyTemplate; - } - - public void setBodyTemplate(String bodyTemplate) { + /** + * Creates a new instance of the MpnsTemplateRegistration class. + * @param channelUri The Windows Phone PNS channel URI. + * @param bodyTemplate The registration template body. + */ + public MpnsTemplateRegistration( + URI channelUri, + String bodyTemplate + ) { + super(channelUri); this.bodyTemplate = bodyTemplate; } - public Map getHeaders() { - return headers; + /** + * Creates a new instance of the MpnsTemplateRegistration class. + * @param registrationId The Azure Notification Hubs registration ID. + * @param channelUri The Windows Phone PNS channel URI. + * @param bodyTemplate The registration template body. + */ + public MpnsTemplateRegistration( + String registrationId, + URI channelUri, + String bodyTemplate + ) { + super(registrationId, channelUri); + this.bodyTemplate = bodyTemplate; } - public void addHeader(String name, String value) { - headers.put(name, value); - } + /** + * Gets the registration template body. + * @return The registration template body. + */ + @Override + public String getBodyTemplate() { return bodyTemplate; } + /** + * Sets the registration template body. + * @param value The registration template body to set. + */ + @Override + public void setBodyTemplate(String value) { this.bodyTemplate = value; } + + /** + * Gets the Windows Phone PNS headers for the template registration. + * @return The Windows Phone PNS headers for the template registration. + */ + public Map getHeaders() { return headers; } + + /** + * Adds a header to the Windows Phone PNS headers for the template registration. + * @param name The name of the header to add. + * @param value The value of the header to add. + */ + public void addHeader(String name, String value) { headers.put(name, value); } + + /** + * Removes a header from the Windows Phone PNS headers for the template registration. + * @param name + */ + public void removeHeader(String name) { headers.remove(name); } + + /** + * Clears the Windows Phone PNS headers for the template registration. + */ + public void clearHeaders() { headers.clear(); } @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result - + ((bodyTemplate == null) ? 0 : bodyTemplate.hashCode()); - result = prime * result + ((headers == null) ? 0 : headers.hashCode()); - return result; + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + MpnsTemplateRegistration that = (MpnsTemplateRegistration) o; + return Objects.equals(getBodyTemplate(), that.getBodyTemplate()) && Objects.equals(getHeaders(), that.getHeaders()); } - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (!super.equals(obj)) - return false; - if (getClass() != obj.getClass()) - return false; - MpnsTemplateRegistration other = (MpnsTemplateRegistration) obj; - if (bodyTemplate == null) { - if (other.bodyTemplate != null) - return false; - } else if (!bodyTemplate.equals(other.bodyTemplate)) - return false; - if (headers == null) { - if (other.headers != null) - return false; - } else if (!headers.equals(other.headers)) - return false; - return true; + public int hashCode() { + return Objects.hash(super.hashCode(), getBodyTemplate(), getHeaders()); } - @Override public String getXml() { return MPNS_TEMPLATE_REGISTRATION1 + diff --git a/NotificationHubs/src/com/windowsazure/messaging/NamespaceManager.java b/NotificationHubs/src/com/windowsazure/messaging/NamespaceManager.java index f82c358..6f882a1 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/NamespaceManager.java +++ b/NotificationHubs/src/com/windowsazure/messaging/NamespaceManager.java @@ -4,7 +4,6 @@ package com.windowsazure.messaging; -import org.apache.commons.codec.binary.Base64; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; @@ -13,13 +12,13 @@ import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; import java.net.URI; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; import java.util.List; +/** + * This interface represents the operations that can be performed by the Azure + * Notification Hub management API. + */ public class NamespaceManager implements NamespaceManagerClient { private static final String IF_MATCH_HEADER_NAME = "If-Match"; private static final String AUTHORIZATION_HEADER_NAME = "Authorization"; @@ -27,10 +26,16 @@ public class NamespaceManager implements NamespaceManagerClient { private static final String API_VERSION = "?api-version=2014-09"; private static final String SKIP_TOP_PARAM = "&$skip=0&$top=2147483647"; private String endpoint; - private String SasKeyName; - private String SasKeyValue; + private final SasTokenProvider tokenProvider; + /** + * Creates a new instance of the NamespaceManager class. + * @param connectionString The connection string from the Azure Notification Hubs namespace access policies. + */ public NamespaceManager(String connectionString) { + String sasKeyName = null; + String sasKeyValue = null; + String[] parts = connectionString.split(";"); if (parts.length != 3) throw new RuntimeException("Error parsing connection string: " @@ -40,19 +45,27 @@ public NamespaceManager(String connectionString) { if (part.startsWith("Endpoint")) { this.endpoint = "https" + part.substring(11); } else if (part.startsWith("SharedAccessKeyName")) { - this.SasKeyName = part.substring(20); + sasKeyName = part.substring(20); } else if (part.startsWith("SharedAccessKey")) { - this.SasKeyValue = part.substring(16); + sasKeyValue = part.substring(16); } } + + tokenProvider = new SasTokenProvider(sasKeyName, sasKeyValue); } + /** + * Gets a notification hub by the hub path asynchronously. + * + * @param hubPath The path of the notification hub. + * @param callback A callback that returns the notification hub description. + */ @Override public void getNotificationHubAsync(String hubPath, final FutureCallback callback) { try { URI uri = new URI(endpoint + hubPath + API_VERSION); final HttpGet get = new HttpGet(uri); - get.setHeader(AUTHORIZATION_HEADER_NAME, generateSasToken(uri)); + get.setHeader(AUTHORIZATION_HEADER_NAME, tokenProvider.generateSasToken(uri)); HttpClientManager.getHttpAsyncClient().execute(get, new FutureCallback() { public void completed(final HttpResponse response) { @@ -87,6 +100,13 @@ public void cancelled() { } } + /** + * Gets a notification hub by the hub path. + * + * @param hubPath The path of the notification hub. + * @return The notification hub description. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public NotificationHubDescription getNotificationHub(String hubPath) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -94,12 +114,18 @@ public NotificationHubDescription getNotificationHub(String hubPath) throws Noti return callback.getResult(); } + /** + * Gets all notification hubs for the namespace. + * + * @param callback A callback, when invoked, returns a list of all the + * namespace's registration descriptions. + */ @Override public void getNotificationHubsAsync(final FutureCallback> callback) { try { URI uri = new URI(endpoint + HUBS_COLLECTION_PATH + API_VERSION + SKIP_TOP_PARAM); final HttpGet get = new HttpGet(uri); - get.setHeader(AUTHORIZATION_HEADER_NAME, generateSasToken(uri)); + get.setHeader(AUTHORIZATION_HEADER_NAME, tokenProvider.generateSasToken(uri)); HttpClientManager.getHttpAsyncClient().execute(get, new FutureCallback() { public void completed(final HttpResponse response) { @@ -134,6 +160,12 @@ public void cancelled() { } } + /** + * Gets all notification hubs for the namespace. + * + * @return A list of all the namespace's registration descriptions. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public List getNotificationHubs() throws NotificationHubsException { SyncCallback> callback = new SyncCallback<>(); @@ -141,11 +173,27 @@ public List getNotificationHubs() throws Notificatio return callback.getResult(); } + /** + * Creates a notification hub with the given notification hub description. + * + * @param hubDescription The notification hub description containing the + * information for the notification hub. + * @param callback A callback, when invoked, returns the populated + * notification hub description. + */ @Override public void createNotificationHubAsync(NotificationHubDescription hubDescription, final FutureCallback callback) { createOrUpdateNotificationHubAsync(hubDescription, false, callback); } + /** + * Creates a notification hub with the given notification hub description. + * + * @param hubDescription The notification hub description containing the + * information for the notification hub. + * @return The populated notification hub description + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public NotificationHubDescription createNotificationHub(NotificationHubDescription hubDescription) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -153,11 +201,25 @@ public NotificationHubDescription createNotificationHub(NotificationHubDescripti return callback.getResult(); } + /** + * Updates a notification hub via the notification hub description. + * + * @param hubDescription The notification hub description to update. + * @param callback A callback, when invoked, returns the populated + * notification hub description. + */ @Override public void updateNotificationHubAsync(NotificationHubDescription hubDescription, FutureCallback callback) { createOrUpdateNotificationHubAsync(hubDescription, true, callback); } + /** + * Updates a notification hub via the notification hub description. + * + * @param hubDescription The notification hub description to update. + * @return Returns the populated notification hub description. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public NotificationHubDescription updateNotificationHub(NotificationHubDescription hubDescription) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -169,7 +231,7 @@ private void createOrUpdateNotificationHubAsync(NotificationHubDescription hubDe try { URI uri = new URI(endpoint + hubDescription.getPath() + API_VERSION); final HttpPut put = new HttpPut(uri); - put.setHeader(AUTHORIZATION_HEADER_NAME, generateSasToken(uri)); + put.setHeader(AUTHORIZATION_HEADER_NAME, tokenProvider.generateSasToken(uri)); if (isUpdate) { put.setHeader(IF_MATCH_HEADER_NAME, "*"); } @@ -211,12 +273,18 @@ public void cancelled() { } } + /** + * Deletes the notification hub with the given hub name. + * + * @param hubPath The name of the notification hub. + * @param callback A callback, when invoked, returns nothing. + */ @Override public void deleteNotificationHubAsync(String hubPath, final FutureCallback callback) { try { URI uri = new URI(endpoint + hubPath + API_VERSION); final HttpDelete delete = new HttpDelete(uri); - delete.setHeader(AUTHORIZATION_HEADER_NAME, generateSasToken(uri)); + delete.setHeader(AUTHORIZATION_HEADER_NAME, tokenProvider.generateSasToken(uri)); HttpClientManager.getHttpAsyncClient().execute(delete, new FutureCallback() { public void completed(final HttpResponse response) { @@ -251,45 +319,16 @@ public void cancelled() { } } + /** + * Deletes the notification hub with the given hub name. + * + * @param hubPath The name of the notification hub. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public void deleteNotificationHub(String hubPath) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); deleteNotificationHubAsync(hubPath, callback); callback.getResult(); } - - private String generateSasToken(URI uri) { - String targetUri; - try { - targetUri = URLEncoder - .encode(uri.toString().toLowerCase(), "UTF-8") - .toLowerCase(); - - long expiresOnDate = System.currentTimeMillis(); - expiresOnDate += SdkGlobalSettings.getAuthorizationTokenExpirationInMinutes() * 60 * 1000; - long expires = expiresOnDate / 1000; - String toSign = targetUri + "\n" + expires; - - // Get an hmac_sha1 key from the raw key bytes - byte[] keyBytes = SasKeyValue.getBytes(StandardCharsets.UTF_8); - SecretKeySpec signingKey = new SecretKeySpec(keyBytes, "HmacSHA256"); - - // Get an hmac_sha1 Mac instance and initialize with the signing key - Mac mac = Mac.getInstance("HmacSHA256"); - mac.init(signingKey); - - // Compute the hmac on input data bytes - byte[] rawHmac = mac.doFinal(toSign.getBytes(StandardCharsets.UTF_8)); - - // Convert raw bytes to Hex - String signature = URLEncoder.encode( - Base64.encodeBase64String(rawHmac), "UTF-8"); - - // construct authorization string - return "SharedAccessSignature sr=" + targetUri + "&sig=" - + signature + "&se=" + expires + "&skn=" + SasKeyName; - } catch (Exception e) { - throw new RuntimeException(e); - } - } } diff --git a/NotificationHubs/src/com/windowsazure/messaging/Notification.java b/NotificationHubs/src/com/windowsazure/messaging/Notification.java index 283d4b8..7dd0697 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/Notification.java +++ b/NotificationHubs/src/com/windowsazure/messaging/Notification.java @@ -4,11 +4,12 @@ package com.windowsazure.messaging; -import java.text.SimpleDateFormat; -import java.util.*; - import org.apache.http.entity.ContentType; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + /** * Class representing a generic notification. */ @@ -28,23 +29,7 @@ public class Notification { * @return a new Windows Notification. */ public static Notification createWindowsNotification(String body) { - Notification n = new Notification(); - n.body = body; - - n.headers.put("ServiceBusNotification-Format", "windows"); - - if (body.matches("^[\\s\\S]+$")) - n.headers.put("X-WNS-Type", "wns/toast"); - if (body.matches("^[\\s\\S]+$")) - n.headers.put("X-WNS-Type", "wns/tile"); - if (body.matches("^[\\s\\S]+$")) - n.headers.put("X-WNS-Type", "wns/badge"); - - if (body.startsWith("<")) { - n.contentType = ContentType.APPLICATION_XML; - } - - return n; + return new WindowsNotification(body); } /** @@ -55,24 +40,7 @@ public static Notification createWindowsNotification(String body) { * @return A native notification for WNS. */ public static Notification createWindowsRawNotification(String body) { - Notification n = new Notification(); - n.body = body; - n.headers.put("ServiceBusNotification-Format", "windows"); - n.headers.put("X-WNS-Type", "wns/raw"); - n.contentType = ContentType.APPLICATION_OCTET_STREAM; - return n; - } - - /** - * @param body the body for the Apple notification - * @return A native notification for APNS. - * @deprecated Typo in name, use createAppleNotification instead. - * Utility method to set up a native notification for APNs. An expiry Date of 1 - * day is set by default. - */ - @Deprecated - public static Notification createAppleNotifiation(String body) { - return createAppleNotification(body); + return new WindowsRawNotification(body); } /** @@ -83,9 +51,7 @@ public static Notification createAppleNotifiation(String body) { * @return A native notification for APNS. */ public static Notification createAppleNotification(String body) { - Date now = new Date(); - Date tomorrow = new Date(now.getTime() + 24 * 60 * 60 * 1000); - return createAppleNotification(body, tomorrow); + return new AppleNotification(body); } /** @@ -97,9 +63,7 @@ public static Notification createAppleNotification(String body) { * @return a native APNS notification */ public static Notification createAppleNotification(String body, Map headers) { - Date now = new Date(); - Date tomorrow = new Date(now.getTime() + 24 * 60 * 60 * 1000); - return createAppleNotification(body, tomorrow, headers); + return new AppleNotification(body, headers); } /** @@ -112,7 +76,7 @@ public static Notification createAppleNotification(String body, Map headers) { - Notification n = new Notification(); - n.body = body; - n.contentType = ContentType.APPLICATION_JSON; - - n.headers.put("ServiceBusNotification-Format", "apple"); - - if (expiry != null) { - SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy hh:mm:ss"); - formatter.setTimeZone(TimeZone.getTimeZone("UTC")); - String expiryString = formatter.format(expiry.getTime()); - - n.headers.put("ServiceBusNotification-Apns-Expiry", expiryString); - } - - if (headers != null) { - n.headers = headers; - } - - return n; + public static AppleNotification createAppleNotification(String body, Date expiry, Map headers) { + return new AppleNotification(body, expiry, headers); } - /** - * Utility method to set up a native notification for GCM. - * - * @param body the body for the GCM message. - * @return a GCM notification with the body - * @deprecated use {@link #createFcmNotification(String)} instead. - */ - @Deprecated - public static Notification createGcmNotifiation(String body) { - return createGcmNotification(body); - } - - /** + /** * Utility method to set up a native notification for GCM. * * @param body the body for the GCM message. @@ -168,25 +102,7 @@ public static Notification createGcmNotifiation(String body) { */ @Deprecated public static Notification createGcmNotification(String body) { - Notification n = new Notification(); - n.body = body; - n.contentType = ContentType.APPLICATION_JSON; - - n.headers.put("ServiceBusNotification-Format", "gcm"); - - return n; - } - - /** - * Utility method to set up a native notification for FCM. - * - * @param body the body for the FCM message. - * @return a FCM notification with the body - * @deprecated use {@link #createFcmNotification(String)} instead. - */ - @Deprecated - public static Notification createFcmNotifiation(String body) { - return createFcmNotification(body); + return new FcmNotification(body); } /** @@ -196,23 +112,7 @@ public static Notification createFcmNotifiation(String body) { * @return an FCM notification */ public static Notification createFcmNotification(String body) { - Notification n = new Notification(); - n.body = body; - n.contentType = ContentType.APPLICATION_JSON; - n.headers.put("ServiceBusNotification-Format", "gcm"); - return n; - } - - /** - * Utility method to set up a native notification for ADM. - * - * @param body The body for the ADM notification. - * @return an ADM notification with the given body. - * @deprecated use {@link #createAdmNotification(String)} instead. - */ - @Deprecated - public static Notification createAdmNotifiation(String body) { - return createAdmNotification(body); + return new FcmNotification(body); } /** @@ -222,25 +122,7 @@ public static Notification createAdmNotifiation(String body) { * @return an ADM notification with the given body. */ public static Notification createAdmNotification(String body) { - Notification n = new Notification(); - n.body = body; - n.contentType = ContentType.APPLICATION_JSON; - - n.headers.put("ServiceBusNotification-Format", "adm"); - - return n; - } - - /** - * Utility method to set up a native notification for Baidu PNS. - * - * @param body the body for the Baidu notification - * @return a Baidu notification with the given body. - * @deprecated use {@link #createBaiduNotification(String)} instead. - */ - @Deprecated - public static Notification createBaiduNotifiation(String body) { - return createBaiduNotification(body); + return new AdmNotification(body); } /** @@ -250,27 +132,7 @@ public static Notification createBaiduNotifiation(String body) { * @return a Baidu notification with the given body. */ public static Notification createBaiduNotification(String body) { - Notification n = new Notification(); - n.body = body; - n.contentType = ContentType.APPLICATION_JSON; - - n.headers.put("ServiceBusNotification-Format", "baidu"); - - return n; - } - - /** - * Utility method to set up a native notification for MPNS. Sets the - * X-WindowsPhone-Target and X-NotificationClass headers based on the body - * provided. Raw notifications are not supported for MPNS. - * - * @param body the body for the MPNS notification. - * @return an initialized MPNS notification - * @deprecated use {@link #createMpnsNotification(String)} instead. - */ - @Deprecated - public static Notification createMpnsNotifiation(String body) { - return createMpnsNotification(body); + return new BaiduNotification(body); } /** @@ -282,25 +144,7 @@ public static Notification createMpnsNotifiation(String body) { * @return an initialized MPNS notification */ public static Notification createMpnsNotification(String body) { - Notification n = new Notification(); - n.body = body; - - n.headers.put("ServiceBusNotification-Format", "windowsphone"); - - if (body.contains("")) { - n.headers.put("X-WindowsPhone-Target", "toast"); - n.headers.put("X-NotificationClass", "2"); - } - if (body.contains("")) { - n.headers.put("X-WindowsPhone-Target", "tile"); - n.headers.put("X-NotificationClass", "1"); - } - - if (body.startsWith("<")) { - n.contentType = ContentType.APPLICATION_XML; - } - - return n; + return new MpnsNotification(body); } /** @@ -311,23 +155,7 @@ public static Notification createMpnsNotification(String body) { * @return a template notification with the associated properties. */ public static Notification createTemplateNotification(Map properties) { - Notification n = new Notification(); - StringBuilder buf = new StringBuilder(); - buf.append("{"); - for (Iterator iterator = properties.keySet().iterator(); iterator.hasNext(); ) { - String key = iterator.next(); - buf.append("\"").append(key).append("\":\"").append(properties.get(key)).append("\""); - if (iterator.hasNext()) - buf.append(","); - } - buf.append("}"); - n.body = buf.toString(); - - n.contentType = ContentType.APPLICATION_JSON; - - n.headers.put("ServiceBusNotification-Format", "template"); - - return n; + return new TemplateNotification(properties); } /** diff --git a/NotificationHubs/src/com/windowsazure/messaging/NotificationHub.java b/NotificationHubs/src/com/windowsazure/messaging/NotificationHub.java index 41a8d0d..9dbcca7 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/NotificationHub.java +++ b/NotificationHubs/src/com/windowsazure/messaging/NotificationHub.java @@ -4,6 +4,20 @@ package com.windowsazure.messaging; +import com.google.gson.GsonBuilder; +import org.apache.commons.io.IOUtils; +import org.apache.http.Header; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.*; +import org.apache.http.concurrent.FutureCallback; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.entity.mime.FormBodyPart; +import org.apache.http.entity.mime.FormBodyPartBuilder; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.entity.mime.content.StringBody; + import java.io.IOException; import java.io.StringWriter; import java.io.UnsupportedEncodingException; @@ -12,37 +26,12 @@ import java.nio.charset.StandardCharsets; import java.text.DateFormat; import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import java.util.TimeZone; +import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; - -import org.apache.commons.codec.binary.Base64; -import org.apache.commons.io.IOUtils; -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.client.methods.HttpDelete; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPatch; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.methods.HttpPut; -import org.apache.http.concurrent.FutureCallback; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.StringEntity; -import org.apache.http.entity.mime.*; -import org.apache.http.entity.mime.content.StringBody; - -import com.google.gson.GsonBuilder; - /** - * Class implementing the INotificationHub interface. + * This class represents all actions that can be done on an Azure Notification Hub. */ public class NotificationHub implements NotificationHubClient { @@ -52,12 +41,19 @@ public class NotificationHub implements NotificationHubClient { private static final String TRACKING_ID_HEADER = "TrackingId"; private String endpoint; private final String hubPath; - private String SasKeyName; - private String SasKeyValue; + private final SasTokenProvider tokenProvider; + /** + * Creates a new instance of the NotificationHub class with connection string and hub path. + * @param connectionString The connection string from the Azure Notification Hub access policies. + * @param hubPath The name of the Azure Notification Hub name. + */ public NotificationHub(String connectionString, String hubPath) { this.hubPath = hubPath; + String sasKeyName = null; + String sasKeyValue = null; + String[] parts = connectionString.split(";"); if (parts.length != 3) throw new RuntimeException("Error parsing connection string: " @@ -67,19 +63,31 @@ public NotificationHub(String connectionString, String hubPath) { if (part.startsWith("Endpoint")) { this.endpoint = "https" + part.substring(11); } else if (part.startsWith("SharedAccessKeyName")) { - this.SasKeyName = part.substring(20); + sasKeyName = part.substring(20); } else if (part.startsWith("SharedAccessKey")) { - this.SasKeyValue = part.substring(16); + sasKeyValue = part.substring(16); } } + + tokenProvider = new SasTokenProvider(sasKeyName, sasKeyValue); } + /** + * This method creates a new registration + * + * @param registration A registration object containing the description of the + * registration to create. ETag and registration ID are + * ignored + * @param callback A callback when invoked returns created registration + * containing the read-only parameters (registration ID, + * ETag, and expiration time) + */ @Override public void createRegistrationAsync(Registration registration, final FutureCallback callback) { try { URI uri = new URI(endpoint + hubPath + "/registrations" + API_VERSION); final HttpPost post = new HttpPost(uri); - post.setHeader("Authorization", generateSasToken(uri)); + post.setHeader("Authorization", tokenProvider.generateSasToken(uri)); post.setHeader("User-Agent", getUserAgent()); StringEntity entity = new StringEntity(registration.getXml(), ContentType.APPLICATION_ATOM_XML); @@ -119,6 +127,16 @@ public void cancelled() { } } + /** + * This method creates a new registration + * + * @param registration A registration object containing the description of the + * registration to create. ETag and registration ID are + * ignored + * @return The created registration containing the read-only parameters + * (registration ID, ETag, and expiration time). + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public Registration createRegistration(Registration registration) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -126,12 +144,19 @@ public Registration createRegistration(Registration registration) throws Notific return callback.getResult(); } + /** + * Create a registrationId, without creating an actual registration. To create + * use upsert. This method is used when the registration id is stored only on + * the device. + * + * @param callback A callback with the newly created registration ID. + */ @Override public void createRegistrationIdAsync(final FutureCallback callback) { try { URI uri = new URI(endpoint + hubPath + "/registrationids" + API_VERSION); final HttpPost post = new HttpPost(uri); - post.setHeader("Authorization", generateSasToken(uri)); + post.setHeader("Authorization", tokenProvider.generateSasToken(uri)); post.setHeader("User-Agent", getUserAgent()); HttpClientManager.getHttpAsyncClient().execute(post, new FutureCallback() { @@ -147,9 +172,13 @@ public void completed(final HttpResponse response) { String location = response.getFirstHeader(CONTENT_LOCATION_HEADER).getValue(); Pattern extractId = Pattern.compile("(\\S+)/registrationids/([^?]+).*"); Matcher m = extractId.matcher(location); - m.matches(); - String id = m.group(2); - callback.completed(id); + + if (m.matches()) { + String id = m.group(2); + callback.completed(id); + } else { + callback.completed(null); + } } catch (Exception e) { callback.failed(e); } finally { @@ -172,6 +201,14 @@ public void cancelled() { } } + /** + * Create a registrationId, without creating an actual registration. To create + * use upsert. This method is used when the registration id is stored only on + * the device. + * + * @return The newly created registration ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public String createRegistrationId() throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -179,12 +216,22 @@ public String createRegistrationId() throws NotificationHubsException { return callback.getResult(); } + /** + * This method updates an existing registration + * + * @param registration A registration object containing the description of the + * registration to update. The registration ID must be + * populated. + * @param callback A callback when invoked, returns the updated registration + * containing the read-only parameters (registration ID, + * ETag, and expiration time). + */ @Override public void updateRegistrationAsync(Registration registration, final FutureCallback callback) { try { URI uri = new URI(endpoint + hubPath + "/registrations/" + registration.getRegistrationId() + API_VERSION); final HttpPut put = new HttpPut(uri); - put.setHeader("Authorization", generateSasToken(uri)); + put.setHeader("Authorization", tokenProvider.generateSasToken(uri)); put.setHeader("If-Match", registration.getEtag() == null ? "*" : "W/\"" + registration.getEtag() + "\""); put.setHeader("User-Agent", getUserAgent()); put.setEntity(new StringEntity(registration.getXml(), ContentType.APPLICATION_ATOM_XML)); @@ -222,6 +269,16 @@ public void cancelled() { } } + /** + * This method updates an existing registration + * + * @param registration A registration object containing the description of the + * registration to update. The registration ID has to be + * populated. + * @return The updated registration containing the read-only parameters + * (registration ID, ETag, and expiration time). + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public Registration updateRegistration(Registration registration) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -229,12 +286,23 @@ public Registration updateRegistration(Registration registration) throws Notific return callback.getResult(); } + /** + * This method updates or creates a new registration with the registration id + * specified. + * + * @param registration A registration object containing the description of the + * registration to create or update. The registration ID + * must be populated. + * @param callback A callback, when invoked, returns the updated + * registration containing the read-only parameters + * (registration ID, ETag, and expiration time). + */ @Override public void upsertRegistrationAsync(Registration registration, final FutureCallback callback) { try { URI uri = new URI(endpoint + hubPath + "/registrations/" + registration.getRegistrationId() + API_VERSION); final HttpPut put = new HttpPut(uri); - put.setHeader("Authorization", generateSasToken(uri)); + put.setHeader("Authorization", tokenProvider.generateSasToken(uri)); put.setHeader("User-Agent", getUserAgent()); put.setEntity(new StringEntity(registration.getXml(), ContentType.APPLICATION_ATOM_XML)); @@ -271,6 +339,17 @@ public void cancelled() { } } + /** + * This method updates or creates a new registration with the registration ID + * specified. + * + * @param registration A registration object containing the description of the + * registration to create or update. The registration ID + * must be populated. + * @return The updated registration containing the read-only parameters + * (registration ID, ETag, and expiration time). + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public Registration upsertRegistration(Registration registration) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -278,11 +357,27 @@ public Registration upsertRegistration(Registration registration) throws Notific return callback.getResult(); } + /** + * Deletes a registration with the given registration containing a populated + * registrationId. + * + * @param registration The registration containing the registrationId field + * populated. + * @param callback A callback when invoked returns nothing. + */ @Override public void deleteRegistrationAsync(Registration registration, final FutureCallback callback) { deleteRegistrationAsync(registration.getRegistrationId(), callback); } + /** + * Deletes a registration with the given registration containing a populated + * registrationId. + * + * @param registration The registration containing the registrationId field + * populated. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public void deleteRegistration(Registration registration) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -290,12 +385,18 @@ public void deleteRegistration(Registration registration) throws NotificationHub callback.getResult(); } + /** + * Deletes a registration by the given registration ID. + * + * @param registrationId The registration ID for the registration to delete. + * @param callback A callback when invoked returns nothing. + */ @Override public void deleteRegistrationAsync(String registrationId, final FutureCallback callback) { try { URI uri = new URI(endpoint + hubPath + "/registrations/" + registrationId + API_VERSION); final HttpDelete delete = new HttpDelete(uri); - delete.setHeader("Authorization", generateSasToken(uri)); + delete.setHeader("Authorization", tokenProvider.generateSasToken(uri)); delete.setHeader("If-Match", "*"); delete.setHeader("User-Agent", getUserAgent()); @@ -332,6 +433,12 @@ public void cancelled() { } } + /** + * Deletes a registration by the given registration ID. + * + * @param registrationId The registration ID for the registration to delete. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public void deleteRegistration(String registrationId) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -339,12 +446,19 @@ public void deleteRegistration(String registrationId) throws NotificationHubsExc callback.getResult(); } + /** + * Retrieves the description of a registration based on the ID. + * + * @param registrationId The ID for the registration to retrieve. + * @param callback A callback, when invoked, returns the registration with + * the ID matching the given registration ID. + */ @Override public void getRegistrationAsync(String registrationId, final FutureCallback callback) { try { URI uri = new URI(endpoint + hubPath + "/registrations/" + registrationId + API_VERSION); final HttpGet get = new HttpGet(uri); - get.setHeader("Authorization", generateSasToken(uri)); + get.setHeader("Authorization", tokenProvider.generateSasToken(uri)); get.setHeader("User-Agent", getUserAgent()); HttpClientManager.getHttpAsyncClient().execute(get, new FutureCallback() { @@ -380,6 +494,13 @@ public void cancelled() { } } + /** + * Retrieves the description of a registration based on the ID. + * + * @param registrationId The ID for the registration to retrieve. + * @return The registration with the ID matching the given registration ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public Registration getRegistration(String registrationId) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -387,17 +508,43 @@ public Registration getRegistration(String registrationId) throws NotificationHu return callback.getResult(); } + /** + * Return all registrations in the current notification hub. + * + * @param callback The callback when invoked, returns a collection containing + * registrations. + */ @Override public void getRegistrationsAsync(FutureCallback callback) { getRegistrationsAsync(0, null, callback); } + /** + * Returns all registrations in this hub + * + * @param top The maximum number of registrations to return (max + * 100) + * @param continuationToken If not-null, continues iterating through a + * previously requested query. + * @param callback A callback when invoked returns a collection + * containing the registrations. + */ @Override public void getRegistrationsAsync(int top, String continuationToken, final FutureCallback callback) { String queryUri = endpoint + hubPath + "/registrations" + API_VERSION + getQueryString(top, continuationToken); retrieveRegistrationCollectionAsync(queryUri, callback); } + /** + * Returns all registrations in this hub + * + * @param top The maximum number of registrations to return (max + * 100) + * @param continuationToken If not-null, continues iterating through a + * previously requested query. + * @return A collection containing the registrations. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public CollectionResult getRegistrations(int top, String continuationToken) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -405,11 +552,28 @@ public CollectionResult getRegistrations(int top, String continuationToken) thro return callback.getResult(); } + /** + * Return all registrations in the current notification hub. + * + * @return Collection containing the registrations. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public CollectionResult getRegistrations() throws NotificationHubsException { return getRegistrations(0, null); } + /** + * Returns all registrations with a specific tag + * + * @param tag The tag to search for registrations. + * @param top The maximum number of registrations to return (max + * 100) + * @param continuationToken If not-null, continues iterating through a + * previously requested query. + * @param callback A callback when invoked, returns a collection of + * registrations with the given tag. + */ @Override public void getRegistrationsByTagAsync(String tag, int top, String continuationToken, final FutureCallback callback) { String queryUri = endpoint + hubPath + "/tags/" + tag @@ -418,6 +582,17 @@ public void getRegistrationsByTagAsync(String tag, int top, String continuationT retrieveRegistrationCollectionAsync(queryUri, callback); } + /** + * Returns all registrations with a specific tag + * + * @param tag The tag to search for registrations. + * @param top The maximum number of registrations to return (max + * 100) + * @param continuationToken If not-null, continues iterating through a + * previously requested query. + * @return A collection of registrations with the given tag. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public CollectionResult getRegistrationsByTag(String tag, int top, String continuationToken) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -425,11 +600,25 @@ public CollectionResult getRegistrationsByTag(String tag, int top, String contin return callback.getResult(); } + /** + * Returns all registrations with a specific tag + * + * @param tag The tag to search for registrations. + * @param callback A callback, when invoked, returns a collection of + * registrations with the given tag. + */ @Override public void getRegistrationsByTagAsync(String tag, final FutureCallback callback) { getRegistrationsByTagAsync(tag, 0, null, callback); } + /** + * Returns all registrations with a specific tag + * + * @param tag The tag to search for registrations. + * @return A collection of registrations with the given tag. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public CollectionResult getRegistrationsByTag(String tag) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -437,6 +626,19 @@ public CollectionResult getRegistrationsByTag(String tag) throws NotificationHub return callback.getResult(); } + /** + * Returns all registration with a specific channel (e.g. ChannelURI, device + * token) + * + * @param channel The channel URI, device token or other unique PNS + * identifier. + * @param top The maximum number of registrations to return (max + * 100) + * @param continuationToken If not-null, continues iterating through a + * previously requested query. + * @param callback A callback, when invoked, returns a collection of + * registrations with matching channels. + */ @Override public void getRegistrationsByChannelAsync(String channel, int top, String continuationToken, final FutureCallback callback) { String queryUri; @@ -451,6 +653,19 @@ public void getRegistrationsByChannelAsync(String channel, int top, String conti retrieveRegistrationCollectionAsync(queryUri, callback); } + /** + * Returns all registration with a specific channel (e.g. ChannelURI, device + * token) + * + * @param channel The channel URI, device token or other unique PNS + * identifier. + * @param top The maximum number of registrations to return (max + * 100) + * @param continuationToken If not-null, continues iterating through a + * previously requested query. + * @return A collection of registrations with matching channels. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public CollectionResult getRegistrationsByChannel(String channel, int top, String continuationToken) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -458,11 +673,27 @@ public CollectionResult getRegistrationsByChannel(String channel, int top, Strin return callback.getResult(); } + /** + * Returns all registration with a specific channel (e.g. ChannelURI, device + * token) + * + * @param channel The channel URI, device token or other unique PNS identifier. + * @param callback A callback, when invoked, returns a collection of + * registrations with matching channels. + */ @Override public void getRegistrationsByChannelAsync(String channel, final FutureCallback callback) { getRegistrationsByChannelAsync(channel, 0, null, callback); } + /** + * Returns all registration with a specific channel (e.g. ChannelURI, device + * token) + * + * @param channel The channel URI, device token or other unique PNS identifier. + * @return A collection of registrations with matching channels. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public CollectionResult getRegistrationsByChannel(String channel) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -485,7 +716,7 @@ private void retrieveRegistrationCollectionAsync(String queryUri, final FutureCa try { URI uri = new URI(queryUri); final HttpGet get = new HttpGet(uri); - get.setHeader("Authorization", generateSasToken(uri)); + get.setHeader("Authorization", tokenProvider.generateSasToken(uri)); get.setHeader("User-Agent", getUserAgent()); HttpClientManager.getHttpAsyncClient().execute(get, new FutureCallback() { @@ -527,11 +758,27 @@ public void cancelled() { } } + /** + * Sends a notification to all eligible registrations (i.e. only correct + * platform, if notification is platform specific) + * + * @param notification The notification to send to all eligible registrations. + * @param callback A callback, when invoked, returns a notification outcome + * with the tracking ID and notification ID. + */ @Override public void sendNotificationAsync(Notification notification, FutureCallback callback) { scheduleNotificationAsync(notification, "", null, callback); } + /** + * Sends a notification to all eligible registrations (i.e. only correct + * platform, if notification is platform specific) + * + * @param notification The notification to send to all eligible registrations. + * @return A notification outcome with the tracking ID and notification ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public NotificationOutcome sendNotification(Notification notification) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -539,11 +786,31 @@ public NotificationOutcome sendNotification(Notification notification) throws No return callback.getResult(); } + /** + * Sends a notifications to all eligible registrations with at least one of the + * specified tags + * + * @param notification The notification to send to the audience with the + * specified tags. + * @param tags The tags for targeting the notifications. + * @param callback A callback, when invoked, returns a notification outcome + * with the tracking ID and notification ID. + */ @Override public void sendNotificationAsync(Notification notification, Set tags, FutureCallback callback) { scheduleNotificationAsync(notification, tags, null, callback); } + /** + * Sends a notifications to all eligible registrations with at least one of the + * specified tags + * + * @param notification The notification to send to the audience with the + * specified tags. + * @param tags The tags for targeting the notifications. + * @return A notification outcome with the tracking ID and notification ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public NotificationOutcome sendNotification(Notification notification, Set tags) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -551,11 +818,31 @@ public NotificationOutcome sendNotification(Notification notification, Set callback) { scheduleNotificationAsync(notification, tagExpression, null, callback); } + /** + * Sends a notifications to all eligible registrations that satisfy the provided + * tag expression. + * + * @param notification The notification to send to the audience that matches + * the specified tag expression. + * @param tagExpression The tag expression for targeting the notifications. + * @return A notification outcome with the tracking ID and notification ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public NotificationOutcome sendNotification(Notification notification, String tagExpression) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -563,11 +850,27 @@ public NotificationOutcome sendNotification(Notification notification, String ta return callback.getResult(); } + /** + * Schedules a notification at the given scheduled time. + * + * @param notification The notification to send at the scheduled time. + * @param scheduledTime The scheduled time for the notification. + * @param callback A callback, when invoked, returns a notification outcome + * with the tracking ID and notification ID. + */ @Override public void scheduleNotificationAsync(Notification notification, Date scheduledTime, FutureCallback callback) { scheduleNotificationAsync(notification, "", scheduledTime, callback); } + /** + * Schedules a notification at the given scheduled time. + * + * @param notification The notification to send at the scheduled time. + * @param scheduledTime The scheduled time for the notification. + * @return A notification outcome with the tracking ID and notification ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public NotificationOutcome scheduleNotification(Notification notification, Date scheduledTime) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -575,6 +878,15 @@ public NotificationOutcome scheduleNotification(Notification notification, Date return callback.getResult(); } + /** + * Schedules a notification at the given time with a set of tags. + * + * @param notification The notification to send at the given time. + * @param tags The tags associated with the notification targeting. + * @param scheduledTime The scheduled time for the notification. + * @param callback A callback, when invoked, returns a notification outcome + * with the tracking ID and notification ID. + */ @Override public void scheduleNotificationAsync(Notification notification, Set tags, Date scheduledTime, FutureCallback callback) { if (tags.isEmpty()) @@ -591,6 +903,15 @@ public void scheduleNotificationAsync(Notification notification, Set tag scheduleNotificationAsync(notification, exp.toString(), scheduledTime, callback); } + /** + * Schedules a notification at the given time with a set of tags. + * + * @param notification The notification to send at the given time. + * @param tags The tags associated with the notification targeting. + * @param scheduledTime The scheduled time for the notification. + * @return A notification outcome with the tracking ID and notification ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public NotificationOutcome scheduleNotification(Notification notification, Set tags, Date scheduledTime) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -598,13 +919,23 @@ public NotificationOutcome scheduleNotification(Notification notification, Set callback) { try { URI uri = new URI(endpoint + hubPath + (scheduledTime == null ? "/messages" : "/schedulednotifications") + API_VERSION); final HttpPost post = new HttpPost(uri); final String trackingId = java.util.UUID.randomUUID().toString(); - post.setHeader("Authorization", generateSasToken(uri)); + post.setHeader("Authorization", tokenProvider.generateSasToken(uri)); post.setHeader(TRACKING_ID_HEADER, trackingId); post.setHeader("User-Agent", getUserAgent()); @@ -670,6 +1001,16 @@ public void cancelled() { } } + /** + * Schedules a notification at the given time with a tag expression. + * + * @param notification The notification to send at the given time. + * @param tagExpression The tag expression associated with the notification + * targeting. + * @param scheduledTime The scheduled time for the notification. + * @return A notification outcome with the tracking ID and notification ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public NotificationOutcome scheduleNotification(Notification notification, String tagExpression, Date scheduledTime) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -677,6 +1018,12 @@ public NotificationOutcome scheduleNotification(Notification notification, Strin return callback.getResult(); } + /** + * Cancels the scheduled notification with the given notification ID. + * + * @param notificationId The notification ID of the notification to cancel. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public void cancelScheduledNotification(String notificationId) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -684,12 +1031,18 @@ public void cancelScheduledNotification(String notificationId) throws Notificati callback.getResult(); } + /** + * Cancels the scheduled notification with the given notification ID. + * + * @param notificationId The notification ID of the notification to cancel. + * @param callback A callback, when invoked, returns nothing. + */ @Override public void cancelScheduledNotificationAsync(String notificationId, final FutureCallback callback) { try { URI uri = new URI(endpoint + hubPath + "/schedulednotifications/" + notificationId + API_VERSION); final HttpDelete delete = new HttpDelete(uri); - delete.setHeader("Authorization", generateSasToken(uri)); + delete.setHeader("Authorization", tokenProvider.generateSasToken(uri)); delete.setHeader("User-Agent", getUserAgent()); HttpClientManager.getHttpAsyncClient().execute(delete, new FutureCallback() { @@ -725,6 +1078,14 @@ public void cancelled() { } } + /** + * Sends a direct notification to a given device handle. + * + * @param notification The notification to send directly to the device handle. + * @param deviceHandle The device handle to target for the notification. + * @return A notification outcome with the tracking ID and notification ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public NotificationOutcome sendDirectNotification(Notification notification, String deviceHandle) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -732,6 +1093,29 @@ public NotificationOutcome sendDirectNotification(Notification notification, Str return callback.getResult(); } + /** + * Sends a direct notification to a given browser push channel. + * + * @param notification The notification to send directly to the browser push channel. + * @param pushChannel The browser push channel to target for the notification. + * @return A notification outcome with the tracking ID and notification ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ + @Override + public NotificationOutcome sendDirectNotification(BrowserNotification notification, BrowserPushChannel pushChannel) throws NotificationHubsException { + SyncCallback callback = new SyncCallback<>(); + sendDirectNotificationAsync(notification, pushChannel, callback); + return callback.getResult(); + } + + /** + * Sends a direct notification to the given device handles. + * + * @param notification The notification to send directly to the device handles. + * @param deviceHandles The device handles to target for the notification. + * @return A notification outcome with the tracking ID and notification ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public NotificationOutcome sendDirectNotification(Notification notification, List deviceHandles) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -739,15 +1123,26 @@ public NotificationOutcome sendDirectNotification(Notification notification, Lis return callback.getResult(); } + /** + * Sends a direct notification to a given device handle. + * + * @param notification The notification to send directly to the device handle. + * @param deviceHandle The device handle to target for the notification. + * @param callback A callback, when invoked, returns a notification outcome + * with the tracking ID and notification ID. + */ @Override - public void sendDirectNotificationAsync(Notification notification, - String deviceHandle, final FutureCallback callback) { + public void sendDirectNotificationAsync( + Notification notification, + String deviceHandle, + final FutureCallback callback + ) { try { URI uri = new URI(endpoint + hubPath + "/messages" + API_VERSION + "&direct"); final HttpPost post = new HttpPost(uri); final String trackingId = java.util.UUID.randomUUID().toString(); post.setHeader("ServiceBusNotification-DeviceHandle", deviceHandle); - post.setHeader("Authorization", generateSasToken(uri)); + post.setHeader("Authorization", tokenProvider.generateSasToken(uri)); post.setHeader(TRACKING_ID_HEADER, trackingId); post.setHeader("User-Agent", getUserAgent()); @@ -802,13 +1197,96 @@ public void cancelled() { } } + /** + * Sends a direct notification to a given browser push channel. + * + * @param notification The notification to send directly to the push channel. + * @param pushChannel The browser push channel to send directly to. + * @param callback A callback, when invoked, returns a notification outcome + */ + @Override + public void sendDirectNotificationAsync( + BrowserNotification notification, + BrowserPushChannel pushChannel, + FutureCallback callback + ) { + try { + URI uri = new URI(endpoint + hubPath + "/messages" + API_VERSION + "&direct"); + final HttpPost post = new HttpPost(uri); + final String trackingId = java.util.UUID.randomUUID().toString(); + post.setHeader("ServiceBusNotification-DeviceHandle", pushChannel.getEndpoint()); + post.setHeader("P256DH", pushChannel.getP256dh()); + post.setHeader("Auth", pushChannel.getAuth()); + post.setHeader("Authorization", tokenProvider.generateSasToken(uri)); + post.setHeader(TRACKING_ID_HEADER, trackingId); + post.setHeader("User-Agent", getUserAgent()); + + for (String header : notification.getHeaders().keySet()) { + post.setHeader(header, notification.getHeaders().get(header)); + } + + post.setEntity(new StringEntity(notification.getBody(), notification.getContentType())); + + HttpClientManager.getHttpAsyncClient().execute(post, new FutureCallback() { + public void completed(final HttpResponse response) { + try { + int httpStatusCode = response.getStatusLine().getStatusCode(); + if (httpStatusCode != 201) { + String msg = ""; + if (response.getEntity() != null && response.getEntity().getContent() != null) { + msg = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8); + } + msg = "Error: " + response.getStatusLine() + " body: " + msg; + callback.failed(NotificationHubsExceptionFactory.createNotificationHubException(response, httpStatusCode, msg)); + return; + } + + String notificationId = null; + Header locationHeader = response.getFirstHeader(CONTENT_LOCATION_HEADER); + if (locationHeader != null) { + URI location = new URI(locationHeader.getValue()); + String[] segments = location.getPath().split("/"); + notificationId = segments[segments.length - 1]; + } + + callback.completed(new NotificationOutcome(trackingId, notificationId)); + } catch (Exception e) { + callback.failed(e); + } finally { + post.releaseConnection(); + } + } + + public void failed(final Exception ex) { + post.releaseConnection(); + callback.failed(ex); + } + + public void cancelled() { + post.releaseConnection(); + callback.cancelled(); + } + }); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Sends a direct notification to the given device handles. + * + * @param notification The notification to send directly to the device handles. + * @param deviceHandles The device handles to target for the notification. + * @param callback A callback, when invoked, returns a notification outcome + * with the tracking ID and notification ID. + */ @Override public void sendDirectNotificationAsync(Notification notification, List deviceHandles, final FutureCallback callback) { try { URI uri = new URI(endpoint + hubPath + "/messages/$batch" + API_VERSION + "&direct"); final HttpPost post = new HttpPost(uri); final String trackingId = java.util.UUID.randomUUID().toString(); - post.setHeader("Authorization", generateSasToken(uri)); + post.setHeader("Authorization", tokenProvider.generateSasToken(uri)); post.setHeader(TRACKING_ID_HEADER, trackingId); post.setHeader("User-Agent", getUserAgent()); @@ -879,7 +1357,6 @@ public void cancelled() { } catch (Exception e) { throw new RuntimeException(e); } - } @Override @@ -895,7 +1372,7 @@ public void getNotificationTelemetryAsync(String notificationId, final FutureCal try { URI uri = new URI(endpoint + hubPath + "/messages/" + notificationId + API_VERSION); final HttpGet get = new HttpGet(uri); - get.setHeader("Authorization", generateSasToken(uri)); + get.setHeader("Authorization", tokenProvider.generateSasToken(uri)); get.setHeader("User-Agent", getUserAgent()); HttpClientManager.getHttpAsyncClient().execute(get, new FutureCallback() { @@ -931,12 +1408,18 @@ public void cancelled() { } } + /** + * Creates or updates an installation. + * + * @param installation The installation to create or update. + * @param callback A callback, when invoked, returns nothing. + */ @Override - public void createOrUpdateInstallationAsync(Installation installation, final FutureCallback callback) { + public void createOrUpdateInstallationAsync(BaseInstallation installation, final FutureCallback callback) { try { URI uri = new URI(endpoint + hubPath + "/installations/" + installation.getInstallationId() + API_VERSION); final HttpPut put = new HttpPut(uri); - put.setHeader("Authorization", generateSasToken(uri)); + put.setHeader("Authorization", tokenProvider.generateSasToken(uri)); put.setHeader("User-Agent", getUserAgent()); StringEntity entity = new StringEntity(installation.toJson(), ContentType.APPLICATION_JSON); @@ -976,18 +1459,38 @@ public void cancelled() { } } + /** + * Creates or updates an installation. + * + * @param installation The installation to create or update. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override - public void createOrUpdateInstallation(Installation installation) throws NotificationHubsException { + public void createOrUpdateInstallation(BaseInstallation installation) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); createOrUpdateInstallationAsync(installation, callback); callback.getResult(); } + /** + * Patches an installation with the given installation ID. + * + * @param installationId The installation ID to patch. + * @param callback A callback, when invoked, returns nothing. + * @param operations The list of operations to perform on the installation. + */ @Override public void patchInstallationAsync(String installationId, FutureCallback callback, PartialUpdateOperation... operations) { patchInstallationInternalAsync(installationId, PartialUpdateOperation.toJson(operations), callback); } + /** + * Patches an installation with the given installation ID. + * + * @param installationId The installation ID to patch. + * @param operations The list of operations to perform on the installation. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public void patchInstallation(String installationId, PartialUpdateOperation... operations) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -995,11 +1498,25 @@ public void patchInstallation(String installationId, PartialUpdateOperation... o callback.getResult(); } + /** + * Patches an installation with the given installation ID. + * + * @param installationId The installation ID to patch. + * @param operations The list of operations to perform on the installation. + * @param callback A callback, when invoked, returns nothing. + */ @Override public void patchInstallationAsync(String installationId, List operations, FutureCallback callback) { patchInstallationInternalAsync(installationId, PartialUpdateOperation.toJson(operations), callback); } + /** + * Patches an installation with the given installation ID. + * + * @param installationId The installation ID to patch. + * @param operations The list of operations to perform on the installation. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public void patchInstallation(String installationId, List operations) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -1011,7 +1528,7 @@ private void patchInstallationInternalAsync(String installationId, String operat try { URI uri = new URI(endpoint + hubPath + "/installations/" + installationId + API_VERSION); final HttpPatch patch = new HttpPatch(uri); - patch.setHeader("Authorization", generateSasToken(uri)); + patch.setHeader("Authorization", tokenProvider.generateSasToken(uri)); patch.setHeader("User-Agent", getUserAgent()); StringEntity entity = new StringEntity(operationsJson, ContentType.APPLICATION_JSON); @@ -1051,12 +1568,18 @@ public void cancelled() { } } + /** + * Deletes an installation with the given installation ID. + * + * @param installationId The installation ID. + * @param callback A callback, when invoked, returns nothing. + */ @Override public void deleteInstallationAsync(String installationId, final FutureCallback callback) { try { URI uri = new URI(endpoint + hubPath + "/installations/" + installationId + API_VERSION); final HttpDelete delete = new HttpDelete(uri); - delete.setHeader("Authorization", generateSasToken(uri)); + delete.setHeader("Authorization", tokenProvider.generateSasToken(uri)); delete.setHeader("User-Agent", getUserAgent()); HttpClientManager.getHttpAsyncClient().execute(delete, new FutureCallback() { @@ -1092,6 +1615,12 @@ public void cancelled() { } } + /** + * Deletes an installation with the given installation ID. + * + * @param installationId The installation ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public void deleteInstallation(String installationId) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -1099,12 +1628,19 @@ public void deleteInstallation(String installationId) throws NotificationHubsExc callback.getResult(); } + /** + * Gets an installation by the given installation ID. + * + * @param installationId The installation ID for the installation to get. + * @param callback A callback, when invoked, returns the matching + * installation by the installation ID. + */ @Override public void getInstallationAsync(String installationId, final FutureCallback callback) { try { URI uri = new URI(endpoint + hubPath + "/installations/" + installationId + API_VERSION); final HttpGet get = new HttpGet(uri); - get.setHeader("Authorization", generateSasToken(uri)); + get.setHeader("Authorization", tokenProvider.generateSasToken(uri)); get.setHeader("User-Agent", getUserAgent()); HttpClientManager.getHttpAsyncClient().execute(get, new FutureCallback() { @@ -1140,6 +1676,13 @@ public void cancelled() { } } + /** + * Gets an installation by the given installation ID. + * + * @param installationId The installation ID for the installation to get. + * @return The matching installation by the installation ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public Installation getInstallation(String installationId) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -1147,12 +1690,81 @@ public Installation getInstallation(String installationId) throws NotificationHu return callback.getResult(); } + /** + * Gets a browser installation by the given installation ID. + * + * @param installationId The installation ID for the installation to get. + * @param callback A callback, when invoked, returns the matching + * installation by the installation ID. + */ + @Override + public void getBrowserInstallationAsync(String installationId, final FutureCallback callback) { + try { + URI uri = new URI(endpoint + hubPath + "/installations/" + installationId + API_VERSION); + final HttpGet get = new HttpGet(uri); + get.setHeader("Authorization", tokenProvider.generateSasToken(uri)); + get.setHeader("User-Agent", getUserAgent()); + + HttpClientManager.getHttpAsyncClient().execute(get, new FutureCallback() { + public void completed(final HttpResponse response) { + try { + int httpStatusCode = response.getStatusLine().getStatusCode(); + if (httpStatusCode != 200) { + callback.failed(NotificationHubsExceptionFactory.createNotificationHubException(response, + httpStatusCode)); + return; + } + + callback.completed(BrowserInstallation.fromJson(response.getEntity().getContent())); + } catch (Exception e) { + callback.failed(e); + } finally { + get.releaseConnection(); + } + } + + public void failed(final Exception ex) { + get.releaseConnection(); + callback.failed(ex); + } + + public void cancelled() { + get.releaseConnection(); + callback.cancelled(); + } + }); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Gets an installation by the given installation ID. + * + * @param installationId The installation ID for the installation to get. + * @return The matching installation by the installation ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ + @Override + public BrowserInstallation getBrowserInstallation(String installationId) throws NotificationHubsException { + SyncCallback callback = new SyncCallback<>(); + getBrowserInstallationAsync(installationId, callback); + return callback.getResult(); + } + + /** + * Submits a notification hub job such as import or export. + * + * @param job The notification hubs job to submit. + * @param callback A callback, when invoked, returns the notification job with + * status. + */ @Override public void submitNotificationHubJobAsync(NotificationHubJob job, final FutureCallback callback) { try { URI uri = new URI(endpoint + hubPath + "/jobs" + API_VERSION); final HttpPost post = new HttpPost(uri); - post.setHeader("Authorization", generateSasToken(uri)); + post.setHeader("Authorization", tokenProvider.generateSasToken(uri)); post.setHeader("User-Agent", getUserAgent()); StringEntity entity = new StringEntity(job.getXml(), ContentType.APPLICATION_ATOM_XML); @@ -1192,6 +1804,13 @@ public void cancelled() { } } + /** + * Submits a notification hub job such as import or export. + * + * @param job The notification hubs job to submit. + * @return The notification job with status. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public NotificationHubJob submitNotificationHubJob(NotificationHubJob job) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -1199,12 +1818,19 @@ public NotificationHubJob submitNotificationHubJob(NotificationHubJob job) throw return callback.getResult(); } + /** + * Gets a notification hub job by the job ID. + * + * @param jobId The job ID of the notification hub job to get. + * @param callback A callback, when invoked, returns the notification hub job + * with the matching job ID. + */ @Override public void getNotificationHubJobAsync(String jobId, final FutureCallback callback) { try { URI uri = new URI(endpoint + hubPath + "/jobs/" + jobId + API_VERSION); final HttpGet get = new HttpGet(uri); - get.setHeader("Authorization", generateSasToken(uri)); + get.setHeader("Authorization", tokenProvider.generateSasToken(uri)); get.setHeader("User-Agent", getUserAgent()); HttpClientManager.getHttpAsyncClient().execute(get, new FutureCallback() { @@ -1240,6 +1866,13 @@ public void cancelled() { } } + /** + * Gets a notification hub job by the job ID. + * + * @param jobId The job ID of the notification hub job to get. + * @return The notification hub job with the matching job ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public NotificationHubJob getNotificationHubJob(String jobId) throws NotificationHubsException { SyncCallback callback = new SyncCallback<>(); @@ -1247,12 +1880,18 @@ public NotificationHubJob getNotificationHubJob(String jobId) throws Notificatio return callback.getResult(); } + /** + * Gets all notification hub jobs for this namespace. + * + * @param callback A callback, when invoked, returns all notification hub jobs + * for this namespace. + */ @Override public void getAllNotificationHubJobsAsync(final FutureCallback> callback) { try { URI uri = new URI(endpoint + hubPath + "/jobs" + API_VERSION); final HttpGet get = new HttpGet(uri); - get.setHeader("Authorization", generateSasToken(uri)); + get.setHeader("Authorization", tokenProvider.generateSasToken(uri)); get.setHeader("User-Agent", getUserAgent()); HttpClientManager.getHttpAsyncClient().execute(get, new FutureCallback() { @@ -1288,6 +1927,12 @@ public void cancelled() { } } + /** + * Gets all notification hub jobs for this namespace. + * + * @return All notification hub jobs for this namespace. + * @throws NotificationHubsException Thrown if there is a client error. + */ @Override public List getAllNotificationHubJobs() throws NotificationHubsException { SyncCallback> callback = new SyncCallback<>(); @@ -1303,41 +1948,6 @@ private String getErrorString(HttpResponse response) return "Error: " + response.getStatusLine() + " - " + body; } - private String generateSasToken(URI uri) { - String targetUri; - try { - targetUri = URLEncoder - .encode(uri.toString().toLowerCase(), "UTF-8") - .toLowerCase(); - - long expiresOnDate = System.currentTimeMillis(); - expiresOnDate += SdkGlobalSettings.getAuthorizationTokenExpirationInMinutes() * 60 * 1000; - long expires = expiresOnDate / 1000; - String toSign = targetUri + "\n" + expires; - - // Get an hmac_sha1 key from the raw key bytes - byte[] keyBytes = SasKeyValue.getBytes(StandardCharsets.UTF_8); - SecretKeySpec signingKey = new SecretKeySpec(keyBytes, "HmacSHA256"); - - // Get an hmac_sha1 Mac instance and initialize with the signing key - Mac mac = Mac.getInstance("HmacSHA256"); - mac.init(signingKey); - - // Compute the hmac on input data bytes - byte[] rawHmac = mac.doFinal(toSign.getBytes(StandardCharsets.UTF_8)); - - // Convert raw bytes to Hex - String signature = URLEncoder.encode( - Base64.encodeBase64String(rawHmac), "UTF-8"); - - // construct authorization string - return "SharedAccessSignature sr=" + targetUri + "&sig=" - + signature + "&se=" + expires + "&skn=" + SasKeyName; - } catch (Exception e) { - throw new RuntimeException(e); - } - } - private static String getUserAgent() { String os = System.getProperty("os.name"); String osVersion = System.getProperty("os.version"); diff --git a/NotificationHubs/src/com/windowsazure/messaging/NotificationHubClient.java b/NotificationHubs/src/com/windowsazure/messaging/NotificationHubClient.java index 686aa05..4707067 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/NotificationHubClient.java +++ b/NotificationHubs/src/com/windowsazure/messaging/NotificationHubClient.java @@ -4,9 +4,726 @@ package com.windowsazure.messaging; +import org.apache.http.concurrent.FutureCallback; + +import java.util.Date; +import java.util.List; +import java.util.Set; + /** - * This interface represents all actions that can be done on an Azure - * Notification Hub. + * This interface represents all actions that can be done on an Azure Notification Hub. */ -public interface NotificationHubClient extends INotificationHub { +public interface NotificationHubClient { + /** + * Creates or updates an installation. + * + * @param installation The installation to create or update. + * @throws NotificationHubsException Thrown if there is a client error. + */ + void createOrUpdateInstallation(BaseInstallation installation) throws NotificationHubsException; + + /** + * Creates or updates an installation. + * + * @param installation The installation to create or update. + * @param callback A callback, when invoked, returns nothing. + */ + void createOrUpdateInstallationAsync(BaseInstallation installation, FutureCallback callback); + + /** + * Patches an installation with the given installation ID. + * + * @param installationId The installation ID to patch. + * @param operations The list of operations to perform on the installation. + * @throws NotificationHubsException Thrown if there is a client error. + */ + void patchInstallation(String installationId, PartialUpdateOperation... operations) + throws NotificationHubsException; + + /** + * Patches an installation with the given installation ID. + * + * @param installationId The installation ID to patch. + * @param callback A callback, when invoked, returns nothing. + * @param operations The list of operations to perform on the installation. + */ + void patchInstallationAsync( + String installationId, + FutureCallback callback, + PartialUpdateOperation... operations + ); + + /** + * Patches an installation with the given installation ID. + * + * @param installationId The installation ID to patch. + * @param operations The list of operations to perform on the installation. + * @throws NotificationHubsException Thrown if there is a client error. + */ + void patchInstallation(String installationId, List operations) + throws NotificationHubsException; + + /** + * Patches an installation with the given installation ID. + * + * @param installationId The installation ID to patch. + * @param operations The list of operations to perform on the installation. + * @param callback A callback, when invoked, returns nothing. + */ + void patchInstallationAsync( + String installationId, + List operations, + FutureCallback callback + ); + + /** + * Deletes an installation with the given installation ID. + * + * @param installationId The installation ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ + void deleteInstallation(String installationId) throws NotificationHubsException; + + /** + * Deletes an installation with the given installation ID. + * + * @param installationId The installation ID. + * @param callback A callback, when invoked, returns nothing. + */ + void deleteInstallationAsync(String installationId, FutureCallback callback); + + /** + * Gets an installation by the given installation ID. + * + * @param installationId The installation ID for the installation to get. + * @return The matching installation by the installation ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ + Installation getInstallation(String installationId) throws NotificationHubsException; + + /** + * Gets an installation by the given installation ID. + * + * @param installationId The installation ID for the installation to get. + * @return The matching installation by the installation ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ + BrowserInstallation getBrowserInstallation(String installationId) throws NotificationHubsException; + + /** + * Gets an installation by the given installation ID. + * + * @param installationId The installation ID for the installation to get. + * @param callback A callback, when invoked, returns the matching + * installation by the installation ID. + */ + void getInstallationAsync(String installationId, FutureCallback callback); + + /** + * Gets a browser installation by the given installation ID. + * + * @param installationId The installation ID for the installation to get. + * @param callback A callback, when invoked, returns the matching + * installation by the installation ID. + */ + void getBrowserInstallationAsync(String installationId, FutureCallback callback); + + /** + * Submits a notification hub job such as import or export. + * + * @param job The notification hubs job to submit. + * @return The notification job with status. + * @throws NotificationHubsException Thrown if there is a client error. + */ + NotificationHubJob submitNotificationHubJob(NotificationHubJob job) throws NotificationHubsException; + + /** + * Submits a notification hub job such as import or export. + * + * @param job The notification hubs job to submit. + * @param callback A callback, when invoked, returns the notification job with + * status. + */ + void submitNotificationHubJobAsync(NotificationHubJob job, FutureCallback callback); + + /** + * Gets a notification hub job by the job ID. + * + * @param jobId The job ID of the notification hub job to get. + * @return The notification hub job with the matching job ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ + NotificationHubJob getNotificationHubJob(String jobId) throws NotificationHubsException; + + /** + * Gets a notification hub job by the job ID. + * + * @param jobId The job ID of the notification hub job to get. + * @param callback A callback, when invoked, returns the notification hub job + * with the matching job ID. + */ + void getNotificationHubJobAsync(String jobId, FutureCallback callback); + + /** + * Gets all notification hub jobs for this namespace. + * + * @return All notification hub jobs for this namespace. + * @throws NotificationHubsException Thrown if there is a client error. + */ + List getAllNotificationHubJobs() throws NotificationHubsException; + + /** + * Gets all notification hub jobs for this namespace. + * + * @param callback A callback, when invoked, returns all notification hub jobs + * for this namespace. + */ + void getAllNotificationHubJobsAsync(FutureCallback> callback); + + /** + * Gets notification telemetry by the notification ID. + * + * @param notificationId The notification ID for the telemetry. + * @return The notification telemetry for the given notification. + * @throws NotificationHubsException Thrown if there is a client error. + */ + NotificationTelemetry getNotificationTelemetry(String notificationId) throws NotificationHubsException; + + /** + * Gets notification telemetry by the notification ID. + * + * @param notificationId The notification ID for the telemetry. + * @param callback A callback, when invoked, returns the notification + * telemetry for the given notification. + */ + void getNotificationTelemetryAsync(String notificationId, FutureCallback callback); + + /** + * Create a registrationId, without creating an actual registration. To create + * use upsert. This method is used when the registration id is stored only on + * the device. + * + * @return The newly created registration ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ + String createRegistrationId() throws NotificationHubsException; + + /** + * Create a registrationId, without creating an actual registration. To create + * use upsert. This method is used when the registration id is stored only on + * the device. + * + * @param callback A callback with the newly created registration ID. + */ + void createRegistrationIdAsync(FutureCallback callback); + + /** + * This method creates a new registration + * + * @param registration A registration object containing the description of the + * registration to create. ETag and registration ID are + * ignored + * @return The created registration containing the read-only parameters + * (registration ID, ETag, and expiration time). + * @throws NotificationHubsException Thrown if there is a client error. + */ + Registration createRegistration(Registration registration) throws NotificationHubsException; + + /** + * This method creates a new registration + * + * @param registration A registration object containing the description of the + * registration to create. ETag and registration ID are + * ignored + * @param callback A callback when invoked returns created registration + * containing the read-only parameters (registration ID, + * ETag, and expiration time) + */ + void createRegistrationAsync(Registration registration, FutureCallback callback); + + /** + * This method updates an existing registration + * + * @param registration A registration object containing the description of the + * registration to update. The registration ID has to be + * populated. + * @return The updated registration containing the read-only parameters + * (registration ID, ETag, and expiration time). + * @throws NotificationHubsException Thrown if there is a client error. + */ + Registration updateRegistration(Registration registration) throws NotificationHubsException; + + /** + * This method updates an existing registration + * + * @param registration A registration object containing the description of the + * registration to update. The registration ID must be + * populated. + * @param callback A callback when invoked, returns the updated registration + * containing the read-only parameters (registration ID, + * ETag, and expiration time). + */ + void updateRegistrationAsync(Registration registration, FutureCallback callback); + + /** + * This method updates or creates a new registration with the registration ID + * specified. + * + * @param registration A registration object containing the description of the + * registration to create or update. The registration ID + * must be populated. + * @return The updated registration containing the read-only parameters + * (registration ID, ETag, and expiration time). + * @throws NotificationHubsException Thrown if there is a client error. + */ + Registration upsertRegistration(Registration registration) throws NotificationHubsException; + + /** + * This method updates or creates a new registration with the registration id + * specified. + * + * @param registration A registration object containing the description of the + * registration to create or update. The registration ID + * must be populated. + * @param callback A callback, when invoked, returns the updated + * registration containing the read-only parameters + * (registration ID, ETag, and expiration time). + */ + void upsertRegistrationAsync(Registration registration, FutureCallback callback); + + /** + * Deletes a registration with the given registration containing a populated + * registrationId. + * + * @param registration The registration containing the registrationId field + * populated. + * @throws NotificationHubsException Thrown if there is a client error. + */ + void deleteRegistration(Registration registration) throws NotificationHubsException; + + /** + * Deletes a registration with the given registration containing a populated + * registrationId. + * + * @param registration The registration containing the registrationId field + * populated. + * @param callback A callback when invoked returns nothing. + */ + void deleteRegistrationAsync(Registration registration, FutureCallback callback); + + /** + * Deletes a registration by the given registration ID. + * + * @param registrationId The registration ID for the registration to delete. + * @throws NotificationHubsException Thrown if there is a client error. + */ + void deleteRegistration(String registrationId) throws NotificationHubsException; + + /** + * Deletes a registration by the given registration ID. + * + * @param registrationId The registration ID for the registration to delete. + * @param callback A callback when invoked returns nothing. + */ + void deleteRegistrationAsync(String registrationId, FutureCallback callback); + + /** + * Retrieves the description of a registration based on the ID. + * + * @param registrationId The ID for the registration to retrieve. + * @return The registration with the ID matching the given registration ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ + Registration getRegistration(String registrationId) throws NotificationHubsException; + + /** + * Retrieves the description of a registration based on the ID. + * + * @param registrationId The ID for the registration to retrieve. + * @param callback A callback, when invoked, returns the registration with + * the ID matching the given registration ID. + */ + void getRegistrationAsync(String registrationId, FutureCallback callback); + + /** + * Return all registrations in the current notification hub. + * + * @return Collection containing the registrations. + * @throws NotificationHubsException Thrown if there is a client error. + */ + CollectionResult getRegistrations() throws NotificationHubsException; + + /** + * Return all registrations in the current notification hub. + * + * @param callback The callback when invoked, returns a collection containing + * registrations. + */ + void getRegistrationsAsync(FutureCallback callback); + + /** + * Returns all registrations in this hub + * + * @param top The maximum number of registrations to return (max + * 100) + * @param continuationToken If not-null, continues iterating through a + * previously requested query. + * @return A collection containing the registrations. + * @throws NotificationHubsException Thrown if there is a client error. + */ + CollectionResult getRegistrations(int top, String continuationToken) throws NotificationHubsException; + + /** + * Returns all registrations in this hub + * + * @param top The maximum number of registrations to return (max + * 100) + * @param continuationToken If not-null, continues iterating through a + * previously requested query. + * @param callback A callback when invoked returns a collection + * containing the registrations. + */ + void getRegistrationsAsync(int top, String continuationToken, FutureCallback callback); + + /** + * Returns all registrations with a specific tag + * + * @param tag The tag to search for registrations. + * @return A collection of registrations with the given tag. + * @throws NotificationHubsException Thrown if there is a client error. + */ + CollectionResult getRegistrationsByTag(String tag) throws NotificationHubsException; + + /** + * Returns all registrations with a specific tag + * + * @param tag The tag to search for registrations. + * @param callback A callback, when invoked, returns a collection of + * registrations with the given tag. + */ + void getRegistrationsByTagAsync(String tag, FutureCallback callback); + + /** + * Returns all registrations with a specific tag + * + * @param tag The tag to search for registrations. + * @param top The maximum number of registrations to return (max + * 100) + * @param continuationToken If not-null, continues iterating through a + * previously requested query. + * @return A collection of registrations with the given tag. + * @throws NotificationHubsException Thrown if there is a client error. + */ + CollectionResult getRegistrationsByTag(String tag, int top, String continuationToken) + throws NotificationHubsException; + + /** + * Returns all registrations with a specific tag + * + * @param tag The tag to search for registrations. + * @param top The maximum number of registrations to return (max + * 100) + * @param continuationToken If not-null, continues iterating through a + * previously requested query. + * @param callback A callback when invoked, returns a collection of + * registrations with the given tag. + */ + void getRegistrationsByTagAsync(String tag, int top, String continuationToken, + FutureCallback callback); + + /** + * Returns all registration with a specific channel (e.g. ChannelURI, device + * token) + * + * @param channel The channel URI, device token or other unique PNS identifier. + * @return A collection of registrations with matching channels. + * @throws NotificationHubsException Thrown if there is a client error. + */ + CollectionResult getRegistrationsByChannel(String channel) throws NotificationHubsException; + + /** + * Returns all registration with a specific channel (e.g. ChannelURI, device + * token) + * + * @param channel The channel URI, device token or other unique PNS identifier. + * @param callback A callback, when invoked, returns a collection of + * registrations with matching channels. + */ + void getRegistrationsByChannelAsync(String channel, FutureCallback callback); + + /** + * Returns all registration with a specific channel (e.g. ChannelURI, device + * token) + * + * @param channel The channel URI, device token or other unique PNS + * identifier. + * @param top The maximum number of registrations to return (max + * 100) + * @param continuationToken If not-null, continues iterating through a + * previously requested query. + * @return A collection of registrations with matching channels. + * @throws NotificationHubsException Thrown if there is a client error. + */ + CollectionResult getRegistrationsByChannel(String channel, int top, String continuationToken) + throws NotificationHubsException; + + /** + * Returns all registration with a specific channel (e.g. ChannelURI, device + * token) + * + * @param channel The channel URI, device token or other unique PNS + * identifier. + * @param top The maximum number of registrations to return (max + * 100) + * @param continuationToken If not-null, continues iterating through a + * previously requested query. + * @param callback A callback, when invoked, returns a collection of + * registrations with matching channels. + */ + void getRegistrationsByChannelAsync(String channel, int top, String continuationToken, + FutureCallback callback); + + /** + * Sends a notification to all eligible registrations (i.e. only correct + * platform, if notification is platform specific) + * + * @param notification The notification to send to all eligible registrations. + * @return A notification outcome with the tracking ID and notification ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ + NotificationOutcome sendNotification(Notification notification) throws NotificationHubsException; + + /** + * Sends a notification to all eligible registrations (i.e. only correct + * platform, if notification is platform specific) + * + * @param notification The notification to send to all eligible registrations. + * @param callback A callback, when invoked, returns a notification outcome + * with the tracking ID and notification ID. + */ + void sendNotificationAsync(Notification notification, FutureCallback callback); + + /** + * Sends a notifications to all eligible registrations with at least one of the + * specified tags + * + * @param notification The notification to send to the audience with the + * specified tags. + * @param tags The tags for targeting the notifications. + * @return A notification outcome with the tracking ID and notification ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ + NotificationOutcome sendNotification(Notification notification, Set tags) throws NotificationHubsException; + + /** + * Sends a notifications to all eligible registrations with at least one of the + * specified tags + * + * @param notification The notification to send to the audience with the + * specified tags. + * @param tags The tags for targeting the notifications. + * @param callback A callback, when invoked, returns a notification outcome + * with the tracking ID and notification ID. + */ + void sendNotificationAsync(Notification notification, Set tags, + FutureCallback callback); + + /** + * Sends a notifications to all eligible registrations that satisfy the provided + * tag expression. + * + * @param notification The notification to send to the audience that matches + * the specified tag expression. + * @param tagExpression The tag expression for targeting the notifications. + * @return A notification outcome with the tracking ID and notification ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ + NotificationOutcome sendNotification(Notification notification, String tagExpression) + throws NotificationHubsException; + + /** + * Sends a notifications to all eligible registrations that satisfy the provided + * tag expression. + * + * @param notification The notification to send to the audience that matches + * the specified tag expression. + * @param tagExpression The tag expression for targeting the notifications. + * @param callback A callback, when invoked, returns a notification outcome + * with the tracking ID and notification ID. + */ + void sendNotificationAsync(Notification notification, String tagExpression, + FutureCallback callback); + + /** + * Schedules a notification at the given scheduled time. + * + * @param notification The notification to send at the scheduled time. + * @param scheduledTime The scheduled time for the notification. + * @return A notification outcome with the tracking ID and notification ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ + NotificationOutcome scheduleNotification(Notification notification, Date scheduledTime) + throws NotificationHubsException; + + /** + * Schedules a notification at the given scheduled time. + * + * @param notification The notification to send at the scheduled time. + * @param scheduledTime The scheduled time for the notification. + * @param callback A callback, when invoked, returns a notification outcome + * with the tracking ID and notification ID. + */ + void scheduleNotificationAsync( + Notification notification, + Date scheduledTime, + FutureCallback callback); + + /** + * Schedules a notification at the given time with a set of tags. + * + * @param notification The notification to send at the given time. + * @param tags The tags associated with the notification targeting. + * @param scheduledTime The scheduled time for the notification. + * @return A notification outcome with the tracking ID and notification ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ + NotificationOutcome scheduleNotification(Notification notification, Set tags, Date scheduledTime) + throws NotificationHubsException; + + /** + * Schedules a notification at the given time with a set of tags. + * + * @param notification The notification to send at the given time. + * @param tags The tags associated with the notification targeting. + * @param scheduledTime The scheduled time for the notification. + * @param callback A callback, when invoked, returns a notification outcome + * with the tracking ID and notification ID. + */ + void scheduleNotificationAsync(Notification notification, Set tags, Date scheduledTime, + FutureCallback callback); + + /** + * Schedules a notification at the given time with a tag expression. + * + * @param notification The notification to send at the given time. + * @param tagExpression The tag expression associated with the notification + * targeting. + * @param scheduledTime The scheduled time for the notification. + * @return A notification outcome with the tracking ID and notification ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ + NotificationOutcome scheduleNotification(Notification notification, String tagExpression, Date scheduledTime) + throws NotificationHubsException; + + /** + * Schedules a notification at the given time with a tag expression. + * + * @param notification The notification to send at the given time. + * @param tagExpression The tag expression associated with the notification + * targeting. + * @param scheduledTime The scheduled time for the notification. + * @param callback A callback, when invoked, returns a notification outcome + * with the tracking ID and notification ID. + */ + void scheduleNotificationAsync( + Notification notification, + String tagExpression, + Date scheduledTime, + FutureCallback callback + ); + + /** + * Sends a direct notification to a given device handle. + * + * @param notification The notification to send directly to the device handle. + * @param deviceHandle The device handle to target for the notification. + * @return A notification outcome with the tracking ID and notification ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ + NotificationOutcome sendDirectNotification(Notification notification, String deviceHandle) + throws NotificationHubsException; + + /** + * Sends a direct notification to a given browser push channel. + * + * @param notification The notification to send directly to the browser push channel. + * @param pushChannel The browser push channel to target for the notification. + * @return A notification outcome with the tracking ID and notification ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ + NotificationOutcome sendDirectNotification( + BrowserNotification notification, + BrowserPushChannel pushChannel + ) throws NotificationHubsException; + + /** + * Sends a direct notification to a given device handle. + * + * @param notification The notification to send directly to the device handle. + * @param deviceHandle The device handle to target for the notification. + * @param callback A callback, when invoked, returns a notification outcome + * with the tracking ID and notification ID. + */ + void sendDirectNotificationAsync( + Notification notification, + String deviceHandle, + FutureCallback callback + ); + + /** + * Sends a direct notification to a given browser push channel. + * + * @param notification The notification to send directly to the push channel. + * @param pushChannel The browser push channel to send directly to. + * @param callback A callback, when invoked, returns a notification outcome + * with the tracking ID and notification ID. + */ + void sendDirectNotificationAsync( + BrowserNotification notification, + BrowserPushChannel pushChannel, + FutureCallback callback + ); + + /** + * Sends a direct notification to the given device handles. + * + * @param notification The notification to send directly to the device handles. + * @param deviceHandles The device handles to target for the notification. + * @return A notification outcome with the tracking ID and notification ID. + * @throws NotificationHubsException Thrown if there is a client error. + */ + NotificationOutcome sendDirectNotification( + Notification notification, + List deviceHandles + ) throws NotificationHubsException; + + /** + * Sends a direct notification to the given device handles. + * + * @param notification The notification to send directly to the device handles. + * @param deviceHandles The device handles to target for the notification. + * @param callback A callback, when invoked, returns a notification outcome + * with the tracking ID and notification ID. + */ + void sendDirectNotificationAsync( + Notification notification, + List deviceHandles, + FutureCallback callback + ); + + /** + * Cancels the scheduled notification with the given notification ID. + * + * @param notificationId The notification ID of the notification to cancel. + * @throws NotificationHubsException Thrown if there is a client error. + */ + void cancelScheduledNotification(String notificationId) throws NotificationHubsException; + + /** + * Cancels the scheduled notification with the given notification ID. + * + * @param notificationId The notification ID of the notification to cancel. + * @param callback A callback, when invoked, returns nothing. + */ + void cancelScheduledNotificationAsync(String notificationId, FutureCallback callback); } diff --git a/NotificationHubs/src/com/windowsazure/messaging/NotificationHubDescription.java b/NotificationHubs/src/com/windowsazure/messaging/NotificationHubDescription.java index f36c73f..5113b2d 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/NotificationHubDescription.java +++ b/NotificationHubs/src/com/windowsazure/messaging/NotificationHubDescription.java @@ -12,6 +12,9 @@ import org.apache.commons.digester3.Digester; import org.xml.sax.SAXException; +/** + * This class represents a notification hub description. + */ public class NotificationHubDescription { private static final String XML_HEADER = ""; private static final String XML_FOOTER = ""; @@ -23,6 +26,7 @@ public class NotificationHubDescription { private GcmCredential gcmCredential; private FcmCredential fcmCredential; private BaiduCredential baiduCredential; + private BrowserCredential browserCredential; private static final ThreadLocal singleEntryParser; private static final ThreadLocal collectionParser; @@ -41,77 +45,144 @@ public class NotificationHubDescription { }); } + /** + * Creates a new instance of the NotificationHubDescription class. + */ public NotificationHubDescription() { - this(null); } + /** + * Creates a new instance of the NotificationHubDescription class. + * @param path The notification hub path. + */ public NotificationHubDescription(String path) { - super(); this.path = path; } + /** + * Gets the notification hub path. + * @return The notification hub path. + */ public String getPath() { return path; } - public void setPath(String path) { - this.path = path; + /** + * Sets the notification hub path. + * @param value The notification hub path to set. + */ + public void setPath(String value) { + path = value; } + /** + * Gets the Amazon PNS credentials for the notification hub. + * @return The Amazon PNS credentials for the notification hub. + */ public AdmCredential getAdmCredential() { return admCredential; } - public void setAdmCredential(AdmCredential admCredential) { - this.admCredential = admCredential; - } - - public ApnsCredential getApnsCredential() { - return apnsCredential; - } - - public void setApnsCredential(ApnsCredential apnsCredential) { - this.apnsCredential = apnsCredential; - } - - public WindowsCredential getWindowsCredential() { - return windowsCredential; - } - - public void setWindowsCredential(WindowsCredential windowsCredential) { - this.windowsCredential = windowsCredential; - } - - public MpnsCredential getMpnsCredential() { - return mpnsCredential; - } - - public void setMpnsCredential(MpnsCredential mpnsCredential) { - this.mpnsCredential = mpnsCredential; - } - + /** + * Sets the Amazon PNS credentials for the notification hub. + * @param value The Amazon PNS credentials for the notification hub to set. + */ + public void setAdmCredential(AdmCredential value) { + admCredential = value; + } + + /** + * Sets the Apple PNS credentials for the notification hub. + * @return The Apple PNS credentials for the notification hub. + */ + public ApnsCredential getApnsCredential() { return apnsCredential; } + + /** + * Sets the Apple PNS credentials for the notification hub. + * @param value The Apple PNS credentials for the notification hub to set. + */ + public void setApnsCredential(ApnsCredential value) { apnsCredential = value; } + + /** + * Gets the Windows PNS credentials for the notification hub. + * @return The Windows PNS credentials for the notification hub. + */ + public WindowsCredential getWindowsCredential() { return windowsCredential; } + + /** + * Sets the Windows PNS credentials for the notification hub. + * @param value The Windows PNS credentials for the notification hub to set. + */ + public void setWindowsCredential(WindowsCredential value) { windowsCredential = value; } + + /** + * Gets the Windows Phone PNS credentials for the notification hub. + * @return The Windows Phone PNS credentials for the notification hub. + */ + public MpnsCredential getMpnsCredential() { return mpnsCredential; } + + /** + * Sets the Windows Phone PNS credentials for the notification hub. + * @param value The Windows Phone PNS credentials for the notification hub to set. + */ + public void setMpnsCredential(MpnsCredential value) { mpnsCredential = value; } + + /** + * Gets the Firebase PNS credentials for the notification hub. + * @return The Firebase PNS credentials for the notification hub. + */ + public FcmCredential getFcmCredential() { return fcmCredential; } + + /** + * Sets the Firebase PNS credentials for the notification hub. + * @param value The Firebase PNS credentials for the notification hub to set. + */ + public void setFcmCredential(FcmCredential value) { fcmCredential = value; } + + /** + * Gets the Baidu PNS credentials for the notification hub. + * @return The Baidu PNS credentials for the notification hub. + */ + public BaiduCredential getBaiduCredential() { return baiduCredential; } + + /** + * Sets the Baidu PNS credentials for the notification hub. + * @param value The Baidu PNS credentials for the notification hub to set. + */ + public void setBaiduCredential(BaiduCredential value) { baiduCredential = value; } + + /** + * Gets the Browser PNS credentials for the notification hub. + * @return The Browser PNS credentials for the notification hub. + */ + public BrowserCredential getBrowserCredential() { return browserCredential; } + + /** + * Sets the Browser PNS credentials for the notification hub. + * @param value The Browser PNS credentials for the notification hub to set. + */ + public void setBrowserCredential(BrowserCredential value) { browserCredential = value; } + + /** + * Gets the Google Cloud Messaging PNS credentials for the notification hub. + * @return The Google Cloud Messaging PNS credentials for the notification hub. + * @deprecated GCM is deprecated. Use getFcmCredential instead. + */ + @Deprecated public GcmCredential getGcmCredential() { return gcmCredential; } - public void setGcmCredential(GcmCredential gcmCredential) { - this.gcmCredential = gcmCredential; - } - - public FcmCredential getFcmCredential() { - return fcmCredential; - } - - public void setFcmCredential(FcmCredential fcmCredential) { - this.fcmCredential = fcmCredential; - } - - public BaiduCredential getBaiduCredential() { - return baiduCredential; - } + /** + * Sets the Google Cloud Messaging credentials for the notification hub. + * @param value The Browser PNS credentials for the notification hub to set. + * @deprecated Use GCM is deprecated, use setFcmCredential. + */ + @Deprecated + public void setGcmCredential(GcmCredential value) { gcmCredential = value; } - public void setBaiduCredential(BaiduCredential baiduCredential) { - this.baiduCredential = baiduCredential; + public void setProperty(String propertyName, String propertyValue) throws Exception { + this.getClass().getMethod("set" + propertyName, String.class).invoke(this, propertyValue); } public static NotificationHubDescription parseOne(InputStream content) throws IOException, SAXException { @@ -125,13 +196,14 @@ public static List parseCollection(InputStream conte public String getXml() { StringBuilder buf = new StringBuilder(); buf.append(XML_HEADER); - if (this.apnsCredential != null) buf.append(this.apnsCredential.getXml()); - if (this.windowsCredential != null) buf.append(this.windowsCredential.getXml()); + if (apnsCredential != null) buf.append(apnsCredential.getXml()); + if (windowsCredential != null) buf.append(windowsCredential.getXml()); + if (fcmCredential != null) buf.append(fcmCredential.getXml()); if (this.gcmCredential != null) buf.append(this.gcmCredential.getXml()); - if (this.fcmCredential != null) buf.append(this.fcmCredential.getXml()); - if (this.mpnsCredential != null) buf.append(this.mpnsCredential.getXml()); - if (this.admCredential != null) buf.append(this.admCredential.getXml()); - if (this.baiduCredential != null) buf.append(this.baiduCredential.getXml()); + if (mpnsCredential != null) buf.append(mpnsCredential.getXml()); + if (admCredential != null) buf.append(admCredential.getXml()); + if (baiduCredential != null) buf.append(baiduCredential.getXml()); + if (browserCredential != null) buf.append(browserCredential.getXml()); buf.append(XML_FOOTER); return buf.toString(); } @@ -153,7 +225,8 @@ private static void setupSingleEntryParser(Digester digester) { digester.addObjectCreate("*/GcmCredential", GcmCredential.class); digester.addObjectCreate("*/FcmCredential", FcmCredential.class); digester.addObjectCreate("*/BaiduCredential", BaiduCredential.class); - PnsCredential.setupDigister(digester); + digester.addObjectCreate("*/BrowserCredential", BrowserCredential.class); + PnsCredential.setupDigester(digester); digester.addSetNext("*/ApnsCredential", "setApnsCredential", ApnsCredential.class.getName()); digester.addSetNext("*/AdmCredential", "setAdmCredential", AdmCredential.class.getName()); digester.addSetNext("*/WnsCredential", "setWindowsCredential", WindowsCredential.class.getName()); @@ -161,5 +234,6 @@ private static void setupSingleEntryParser(Digester digester) { digester.addSetNext("*/GcmCredential", "setGcmCredential", GcmCredential.class.getName()); digester.addSetNext("*/FcmCredential", "setFcmCredential", FcmCredential.class.getName()); digester.addSetNext("*/BaiduCredential", "setBaiduCredential", BaiduCredential.class.getName()); + digester.addSetNext("*/BrowserCredential", "setBrowserCredential", BrowserCredential.class.getName()); } } diff --git a/NotificationHubs/src/com/windowsazure/messaging/NotificationHubJob.java b/NotificationHubs/src/com/windowsazure/messaging/NotificationHubJob.java index a20cc0b..cb65fe0 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/NotificationHubJob.java +++ b/NotificationHubs/src/com/windowsazure/messaging/NotificationHubJob.java @@ -15,6 +15,9 @@ import org.apache.commons.digester3.Digester; import org.xml.sax.SAXException; +/** + * This class represents an Azure Notification Hubs job. + */ public class NotificationHubJob { private static final String XML_HEADER = ""; private static final String XML_FOOTER = ""; @@ -47,12 +50,20 @@ public class NotificationHubJob { }); } + /** + * Gets the Azure Notification Hubs job ID. + * @return The Azure Notification Hubs job ID. + */ public String getJobId() { return jobId; } - public void setJobId(String jobId) { - this.jobId = jobId; + /** + * Sets the Azure Notification Hubs job ID. + * @param value The Azure Notification Hubs job ID to set. + */ + public void setJobId(String value) { + jobId = value; } public double getProgress() { diff --git a/NotificationHubs/src/com/windowsazure/messaging/NotificationHubsException.java b/NotificationHubs/src/com/windowsazure/messaging/NotificationHubsException.java index e82d935..24706b8 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/NotificationHubsException.java +++ b/NotificationHubs/src/com/windowsazure/messaging/NotificationHubsException.java @@ -39,7 +39,7 @@ public NotificationHubsException(String message, int httpStatusCode, boolean isT * @return The HTTP status code for the exception. */ public int httpStatusCode() { - return this.httpStatusCode; + return httpStatusCode; } /** @@ -48,7 +48,7 @@ public int httpStatusCode() { * @return True if transient and can be retried. */ public boolean isTransient() { - return this.isTransient; + return isTransient; } /** @@ -57,6 +57,6 @@ public boolean isTransient() { * @return The duration for when the operation should be tried again. */ public Optional retryAfter() { - return Optional.ofNullable(this.retryAfter); + return Optional.ofNullable(retryAfter); } } diff --git a/NotificationHubs/src/com/windowsazure/messaging/NotificationHubsExceptionFactory.java b/NotificationHubs/src/com/windowsazure/messaging/NotificationHubsExceptionFactory.java index 2be11e2..2f6891e 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/NotificationHubsExceptionFactory.java +++ b/NotificationHubs/src/com/windowsazure/messaging/NotificationHubsExceptionFactory.java @@ -9,11 +9,13 @@ import org.apache.http.HttpHeaders; import org.apache.http.HttpResponse; -import java.io.IOException; import java.io.StringWriter; import java.time.Duration; import java.util.Optional; +/** + * This class creates NotificationHubException classes based upon the HTTP response. + */ public class NotificationHubsExceptionFactory { static boolean isTransientStatusCode(int httpStatusCode) { @@ -40,15 +42,26 @@ static Optional parseRetryAfter(HttpResponse response) { } } - static String getErrorString(HttpResponse response) throws IllegalStateException, IOException { + static String getErrorString(HttpResponse response) { StringWriter writer = new StringWriter(); - IOUtils.copy(response.getEntity().getContent(), writer, "UTF-8"); - String body = writer.toString(); - return "Error: " + response.getStatusLine() + " - " + body; + try{ + IOUtils.copy(response.getEntity().getContent(), writer, "UTF-8"); + String body = writer.toString(); + return "Error: " + response.getStatusLine() + " - " + body; + } catch (Exception e) { + throw new RuntimeException("Cannot get the HTTP response error string"); + } + } - public static NotificationHubsException createNotificationHubException(HttpResponse response, int httpStatusCode) - throws IOException { + /** + /** + * Creates a NotificationHubsException instance based upon the HTTP response and status code. + * @param response The HTTP response. + * @param httpStatusCode The HTTP status code from the response. + * @return A new NotificationHubsException instance based upon the HTTP response data. + */ + public static NotificationHubsException createNotificationHubException(HttpResponse response, int httpStatusCode) { Optional retryAfter = parseRetryAfter(response); boolean isTransient = isTransientStatusCode(httpStatusCode); if (retryAfter.isPresent()) { @@ -59,8 +72,18 @@ public static NotificationHubsException createNotificationHubException(HttpRespo } } - public static NotificationHubsException createNotificationHubException(HttpResponse response, int httpStatusCode, - String message) { + /** + * Creates a NotificationHubsException instance based upon the HTTP response and status code. + * @param response The HTTP response. + * @param httpStatusCode The HTTP status code from the response. + * @param message A message for the NotificationHubsException instance. + * @return A new NotificationHubsException instance based upon the HTTP response data. + */ + public static NotificationHubsException createNotificationHubException( + HttpResponse response, + int httpStatusCode, + String message + ) { Optional retryAfter = parseRetryAfter(response); boolean isTransient = isTransientStatusCode(httpStatusCode); if (retryAfter.isPresent()) { diff --git a/NotificationHubs/src/com/windowsazure/messaging/NotificationOutcome.java b/NotificationHubs/src/com/windowsazure/messaging/NotificationOutcome.java index 7e59e66..c276260 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/NotificationOutcome.java +++ b/NotificationHubs/src/com/windowsazure/messaging/NotificationOutcome.java @@ -27,16 +27,12 @@ public NotificationOutcome(String trackingId, String notificationId) { * * @return The tracking ID for the notification outcome. */ - public String getTrackingId() { - return this.trackingId; - } + public String getTrackingId() { return trackingId; } /** * Gets the notification ID from the notification outcome. * * @return The notification ID from the notification outcome. */ - public String getNotificationId() { - return this.notificationId; - } + public String getNotificationId() { return notificationId; } } diff --git a/NotificationHubs/src/com/windowsazure/messaging/NotificationPlatform.java b/NotificationHubs/src/com/windowsazure/messaging/NotificationPlatform.java index b9daf0e..5d213ec 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/NotificationPlatform.java +++ b/NotificationHubs/src/com/windowsazure/messaging/NotificationPlatform.java @@ -40,4 +40,9 @@ public enum NotificationPlatform { */ @SerializedName("adm") Adm, + /** + * The Browser Push platform. + */ + @SerializedName("browser") + Browser } diff --git a/NotificationHubs/src/com/windowsazure/messaging/NotificationStatus.java b/NotificationHubs/src/com/windowsazure/messaging/NotificationStatus.java index c4765a6..ac43fe4 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/NotificationStatus.java +++ b/NotificationHubs/src/com/windowsazure/messaging/NotificationStatus.java @@ -40,5 +40,5 @@ public enum NotificationStatus { /** * The notification has an unknown status. */ - Unknown, + Unknown } diff --git a/NotificationHubs/src/com/windowsazure/messaging/NotificationTelemetry.java b/NotificationHubs/src/com/windowsazure/messaging/NotificationTelemetry.java index 30ee3b2..b52a647 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/NotificationTelemetry.java +++ b/NotificationHubs/src/com/windowsazure/messaging/NotificationTelemetry.java @@ -30,6 +30,7 @@ public class NotificationTelemetry { private Map fcmOutcomeCounts; private Map admOutcomeCounts; private Map baiduOutcomeCounts; + private Map browserOutcomeCounts; private String pnsErrorDetailsUri; private static final ThreadLocal parser; @@ -252,5 +253,11 @@ private static void setupParser(Digester digester) { digester.addCallParam("*/Name", 0); digester.addCallParam("*/Count", 1); digester.addSetNext("*/BaiduOutcomeCounts", "setBaiduOutcomeCounts", Map.class.getName()); + + digester.addObjectCreate("*/BrowserOutcomeCounts", HashMap.class); + digester.addCallMethod("*/Outcome", "put", 2, new Class[]{String.class, Integer.class}); + digester.addCallParam("*/Name", 0); + digester.addCallParam("*/Count", 1); + digester.addSetNext("*/BrowserOutcomeCounts", "setBrowserOutcomeCounts", Map.class.getName()); } } diff --git a/NotificationHubs/src/com/windowsazure/messaging/PartialUpdateOperation.java b/NotificationHubs/src/com/windowsazure/messaging/PartialUpdateOperation.java index 1e8639e..c629e73 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/PartialUpdateOperation.java +++ b/NotificationHubs/src/com/windowsazure/messaging/PartialUpdateOperation.java @@ -9,49 +9,79 @@ import com.google.gson.GsonBuilder; import com.google.gson.annotations.SerializedName; +/** + * This class represents a partial update for patch operations. + */ public class PartialUpdateOperation { @SerializedName("op") private UpdateOperationType operation; private String path; private String value; + /** + * Creates a new instance of the PartialUpdateOperation class. + */ public PartialUpdateOperation() { - this(null, null, null); + } + /** + * Creates a new instance of the PartialUpdateOperation class with operation type and path. + * @param operation The operation type. + * @param path The path to perform the operation. + */ public PartialUpdateOperation(UpdateOperationType operation, String path) { - this(operation, path, null); + this.operation = operation; + this.path = path; } + /** + * Creates a new instance of the PartialUpdateOperation class with operation type, path and value. + * @param operation The operation type. + * @param path The path to perform the operation. + * @param value The value to set for the operation. + */ public PartialUpdateOperation(UpdateOperationType operation, String path, String value) { this.operation = operation; this.path = path; this.value = value; } - public UpdateOperationType getOperation() { - return operation; - } + /** + * Gets the partial update operation type. + * @return The partial update operation type. + */ + public UpdateOperationType getOperation() { return operation; } - public void setOperation(UpdateOperationType operation) { - this.operation = operation; - } + /** + * Sets the partial update operation type. + * @param value The partial update operation type to set. + */ + public void setOperation(UpdateOperationType value) { operation = value; } - public String getPath() { - return path; - } + /** + * Gets the partial update operation path. + * @return The partial update operation path. + */ + public String getPath() { return path; } - public void setPath(String path) { - this.path = path; - } + /** + * Sets the partial update operation path. + * @param value The partial update operation path. + */ + public void setPath(String value) { path = value; } - public String getValue() { - return value; - } + /** + * Gets the partial update operation value. + * @return The partial update operation value. + */ + public String getValue() { return value; } - public void setValue(String value) { - this.value = value; - } + /** + * Sets the partiaul update operation value. + * @param value The partial update operation value. + */ + public void setValue(String value) { this.value = value; } public static String toJson(PartialUpdateOperation... operations) { return new GsonBuilder().disableHtmlEscaping().create().toJson(operations); diff --git a/NotificationHubs/src/com/windowsazure/messaging/PnsCredential.java b/NotificationHubs/src/com/windowsazure/messaging/PnsCredential.java index b006541..8a5bd66 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/PnsCredential.java +++ b/NotificationHubs/src/com/windowsazure/messaging/PnsCredential.java @@ -16,16 +16,16 @@ public abstract class PnsCredential { private static final String PROPERTY_END = ""; private static final String PROPERTIES_END = ""; - public static void setupDigister(Digester digester) { + public void setProperty(String propertyName, String propertyValue) throws Exception { + this.getClass().getMethod("set" + propertyName, String.class).invoke(this, propertyValue); + } + + public static void setupDigester(Digester digester) { digester.addCallMethod("*/Property", "setProperty", 2); digester.addCallParam("*/Name", 0); digester.addCallParam("*/Value", 1); } - public void setProperty(String propertyName, String propertyValue) throws Exception { - this.getClass().getMethod("set" + propertyName, String.class).invoke(this, propertyValue); - } - public String getXml() { StringBuilder buf = new StringBuilder(); buf.append("<"); diff --git a/NotificationHubs/src/com/windowsazure/messaging/Registration.java b/NotificationHubs/src/com/windowsazure/messaging/Registration.java index 4b71026..f922979 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/Registration.java +++ b/NotificationHubs/src/com/windowsazure/messaging/Registration.java @@ -11,10 +11,7 @@ import java.io.IOException; import java.io.InputStream; -import java.util.Date; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; +import java.util.*; /** * Abstract class representing a registration. @@ -43,9 +40,16 @@ public abstract class Registration implements Cloneable { }); } + /** + * Creates a new instance of the Registration class. + */ public Registration() { } + /** + * Clones the current registration. + * @return A clone of the current registration. + */ public Registration clone() { try { return (Registration) super.clone(); @@ -54,42 +58,52 @@ public Registration clone() { } } + /** + * Creates a new instance of the Registration class with the registration ID. + * @param registrationId The registration ID. + */ public Registration(String registrationId) { super(); this.registrationId = registrationId; } + /** + * Creates a new instance of the Registration class with a set of tags. + * @param tags The tags for the registration. + */ public Registration(Set tags) { super(); this.tags = tags; } - public abstract String getXml(); - - public String getRegistrationId() { - return registrationId; - } - - public void setRegistrationId(String registrationId) { - this.registrationId = registrationId; - } - - public Set getTags() { - return tags; - } - - public void setTags(Set tags) { - this.tags = tags; - } - - public String getEtag() { - return etag; - } - - public void setEtag(String etag) { - this.etag = etag; - } - + /** + * Gets the registration ID. + * @return The registration ID. + */ + public String getRegistrationId() { return registrationId; } + + /** + * Sets the registration ID. + * @param value The registration ID to set. + */ + public void setRegistrationId(String value) { registrationId = value; } + + /** + * Gets the tags for the registration. + * @return The tags for the registration. + */ + public Set getTags() { return tags; } + + /** + * Sets the tags for the registration. + * @param value The tags for the registration to set. + */ + public void setTags(Set value) { this.tags = value; } + + /** + * Sets the tags from a comma separated string. + * @param string The comma separated string containing the tags. + */ public void setTagsFromString(String string) { tags = new HashSet<>(); String[] tagsArray = string.split(","); @@ -98,6 +112,44 @@ public void setTagsFromString(String string) { } } + /** + * Gets the etag for the registration. + * @return The etag for the registration. + */ + public String getEtag() { return etag; } + + /** + * Sets the etag for the registration. + * @param value The etag for the registration to set. + */ + public void setEtag(String value) { etag = value; } + + /** + * Gets the expiration time for the registration. + * @return The expiration time for the registration. + */ + public Date getExpirationTime() { return expirationTime; } + + /** + * Sets the expiration time for the registration. + * @param value The expiration time for the registration. + */ + public void setExpirationTime(Date value) { expirationTime = value; } + + /** + * Sets the expiration time for the registration from a string value. + * @param expirationTimeString The expiration time for the registration string to be parsed. + */ + public void setExpirationTimeFromString(String expirationTimeString) { + this.expirationTime = javax.xml.bind.DatatypeConverter.parseDateTime(expirationTimeString).getTime(); + } + + /** + * Gets an XML representation of the current object. + * @return The XML representation of the current object. + */ + public abstract String getXml(); + protected String getTagsXml() { StringBuilder buf = new StringBuilder(); if (!tags.isEmpty()) { @@ -112,61 +164,17 @@ protected String getTagsXml() { return buf.toString(); } - public Date getExpirationTime() { - return expirationTime; - } - - public void setExpirationTime(Date expirationTime) { - this.expirationTime = expirationTime; - } - - public void setExpirationTimeFromString(String expirationTimeString) { - this.expirationTime = javax.xml.bind.DatatypeConverter.parseDateTime(expirationTimeString).getTime(); - } - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((etag == null) ? 0 : etag.hashCode()); - result = prime * result - + ((expirationTime == null) ? 0 : expirationTime.hashCode()); - result = prime * result - + ((registrationId == null) ? 0 : registrationId.hashCode()); - result = prime * result + ((tags == null) ? 0 : tags.hashCode()); - return result; + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Registration that = (Registration) o; + return Objects.equals(getRegistrationId(), that.getRegistrationId()) && Objects.equals(getTags(), that.getTags()) && Objects.equals(getEtag(), that.getEtag()) && Objects.equals(getExpirationTime(), that.getExpirationTime()); } @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - Registration other = (Registration) obj; - if (etag == null) { - if (other.etag != null) - return false; - } else if (!etag.equals(other.etag)) - return false; - if (expirationTime == null) { - if (other.expirationTime != null) - return false; - } else if (!expirationTime.equals(other.expirationTime)) - return false; - if (registrationId == null) { - if (other.registrationId != null) - return false; - } else if (!registrationId.equals(other.registrationId)) - return false; - if (tags == null) { - if (other.tags != null) - return false; - } else if (!tags.equals(other.tags)) - return false; - return true; + public int hashCode() { + return Objects.hash(getRegistrationId(), getTags(), getEtag(), getExpirationTime()); } public static Registration parse(InputStream content) throws IOException, @@ -205,6 +213,10 @@ private static void addRegistrationRules(Digester digester) { BaiduRegistration.class); digester.addObjectCreate("*/BaiduTemplateRegistrationDescription", BaiduTemplateRegistration.class); + digester.addObjectCreate("*/BrowserRegistrationDescription", + BrowserRegistration.class); + digester.addObjectCreate("*/BrowserTemplateRegistrationDescription", + BrowserTemplateRegistration.class); digester.addCallMethod("*/RegistrationId", "setRegistrationId", 1); digester.addCallParam("*/RegistrationId", 0); digester.addCallMethod("*/ETag", "setEtag", 1); @@ -237,6 +249,12 @@ private static void addRegistrationRules(Digester digester) { digester.addCallParam("*/BaiduUserId", 0); digester.addCallMethod("*/BaiduChannelId", "setBaiduChannelId", 1); digester.addCallParam("*/BaiduChannelId", 0); + digester.addCallMethod("*/Endpoint", "setEndpoint", 1); + digester.addCallParam("*/Endpoint", 0); + digester.addCallMethod("*/P256DH", "setP256dh", 1); + digester.addCallParam("*/P256DH", 0); + digester.addCallMethod("*/Auth", "setAuth", 1); + digester.addCallParam("*/Auth", 0); } public static CollectionResult parseRegistrations(InputStream content) diff --git a/NotificationHubs/src/com/windowsazure/messaging/RuntimeTypeAdapterFactory.java b/NotificationHubs/src/com/windowsazure/messaging/RuntimeTypeAdapterFactory.java new file mode 100644 index 0000000..3b271fa --- /dev/null +++ b/NotificationHubs/src/com/windowsazure/messaging/RuntimeTypeAdapterFactory.java @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2011 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.windowsazure.messaging; + +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.internal.Streams; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +/** + * Adapts values whose runtime type may differ from their declaration type. This + * is necessary when a field's type is not the same type that GSON should create + * when deserializing that field. For example, consider these types: + *
   {@code
+ *   abstract class Shape {
+ *     int x;
+ *     int y;
+ *   }
+ *   class Circle extends Shape {
+ *     int radius;
+ *   }
+ *   class Rectangle extends Shape {
+ *     int width;
+ *     int height;
+ *   }
+ *   class Diamond extends Shape {
+ *     int width;
+ *     int height;
+ *   }
+ *   class Drawing {
+ *     Shape bottomShape;
+ *     Shape topShape;
+ *   }
+ * }
+ *

Without additional type information, the serialized JSON is ambiguous. Is + * the bottom shape in this drawing a rectangle or a diamond?

   {@code
+ *   {
+ *     "bottomShape": {
+ *       "width": 10,
+ *       "height": 5,
+ *       "x": 0,
+ *       "y": 0
+ *     },
+ *     "topShape": {
+ *       "radius": 2,
+ *       "x": 4,
+ *       "y": 1
+ *     }
+ *   }}
+ * This class addresses this problem by adding type information to the + * serialized JSON and honoring that type information when the JSON is + * deserialized:
   {@code
+ *   {
+ *     "bottomShape": {
+ *       "type": "Diamond",
+ *       "width": 10,
+ *       "height": 5,
+ *       "x": 0,
+ *       "y": 0
+ *     },
+ *     "topShape": {
+ *       "type": "Circle",
+ *       "radius": 2,
+ *       "x": 4,
+ *       "y": 1
+ *     }
+ *   }}
+ * Both the type field name ({@code "type"}) and the type labels ({@code + * "Rectangle"}) are configurable. + * + *

Registering Types

+ * Create a {@code RuntimeTypeAdapterFactory} by passing the base type and type field + * name to the {@link #of} factory method. If you don't supply an explicit type + * field name, {@code "type"} will be used.
   {@code
+ *   RuntimeTypeAdapterFactory shapeAdapterFactory
+ *       = RuntimeTypeAdapterFactory.of(Shape.class, "type");
+ * }
+ * Next register all of your subtypes. Every subtype must be explicitly + * registered. This protects your application from injection attacks. If you + * don't supply an explicit type label, the type's simple name will be used. + *
   {@code
+ *   shapeAdapterFactory.registerSubtype(Rectangle.class, "Rectangle");
+ *   shapeAdapterFactory.registerSubtype(Circle.class, "Circle");
+ *   shapeAdapterFactory.registerSubtype(Diamond.class, "Diamond");
+ * }
+ * Finally, register the type adapter factory in your application's GSON builder: + *
   {@code
+ *   Gson gson = new GsonBuilder()
+ *       .registerTypeAdapterFactory(shapeAdapterFactory)
+ *       .create();
+ * }
+ * Like {@code GsonBuilder}, this API supports chaining:
   {@code
+ *   RuntimeTypeAdapterFactory shapeAdapterFactory = RuntimeTypeAdapterFactory.of(Shape.class)
+ *       .registerSubtype(Rectangle.class)
+ *       .registerSubtype(Circle.class)
+ *       .registerSubtype(Diamond.class);
+ * }
+ * + *

Serialization and deserialization

+ * In order to serialize and deserialize a polymorphic object, + * you must specify the base type explicitly. + *
   {@code
+ *   Diamond diamond = new Diamond();
+ *   String json = gson.toJson(diamond, Shape.class);
+ * }
+ * And then: + *
   {@code
+ *   Shape shape = gson.fromJson(json, Shape.class);
+ * }
+ */ +public final class RuntimeTypeAdapterFactory implements TypeAdapterFactory { + private final Class baseType; + private final String typeFieldName; + private final Map> labelToSubtype = new LinkedHashMap<>(); + private final Map, String> subtypeToLabel = new LinkedHashMap<>(); + private final boolean maintainType; + + private RuntimeTypeAdapterFactory(Class baseType, String typeFieldName, boolean maintainType) { + if (typeFieldName == null || baseType == null) { + throw new NullPointerException(); + } + this.baseType = baseType; + this.typeFieldName = typeFieldName; + this.maintainType = maintainType; + } + + /** + * Creates a new runtime type adapter using for {@code baseType} using {@code + * typeFieldName} as the type field name. Type field names are case-sensitive. + * {@code maintainType} flag decide if the type will be stored in pojo or not. + */ + public static RuntimeTypeAdapterFactory of(Class baseType, String typeFieldName, boolean maintainType) { + return new RuntimeTypeAdapterFactory<>(baseType, typeFieldName, maintainType); + } + + /** + * Creates a new runtime type adapter using for {@code baseType} using {@code + * typeFieldName} as the type field name. Type field names are case-sensitive. + */ + public static RuntimeTypeAdapterFactory of(Class baseType, String typeFieldName) { + return new RuntimeTypeAdapterFactory<>(baseType, typeFieldName, false); + } + + /** + * Creates a new runtime type adapter for {@code baseType} using {@code "type"} as + * the type field name. + */ + public static RuntimeTypeAdapterFactory of(Class baseType) { + return new RuntimeTypeAdapterFactory<>(baseType, "type", false); + } + + /** + * Registers {@code type} identified by {@code label}. Labels are case-sensitive. + * + * @throws IllegalArgumentException if either {@code type} or {@code label} + * have already been registered on this type adapter. + */ + public RuntimeTypeAdapterFactory registerSubtype(Class type, String label) { + if (type == null || label == null) { + throw new NullPointerException(); + } + if (subtypeToLabel.containsKey(type) || labelToSubtype.containsKey(label)) { + throw new IllegalArgumentException("types and labels must be unique"); + } + labelToSubtype.put(label, type); + subtypeToLabel.put(type, label); + return this; + } + + /** + * Registers {@code type} identified by its {@link Class#getSimpleName simple + * name}. Labels are case-sensitive. + * + * @throws IllegalArgumentException if either {@code type} or its simple name + * have already been registered on this type adapter. + */ + public RuntimeTypeAdapterFactory registerSubtype(Class type) { + return registerSubtype(type, type.getSimpleName()); + } + + public TypeAdapter create(Gson gson, TypeToken type) { + if (type.getRawType() != baseType) { + return null; + } + + final Map> labelToDelegate + = new LinkedHashMap<>(); + final Map, TypeAdapter> subtypeToDelegate + = new LinkedHashMap<>(); + for (Map.Entry> entry : labelToSubtype.entrySet()) { + TypeAdapter delegate = gson.getDelegateAdapter(this, TypeToken.get(entry.getValue())); + labelToDelegate.put(entry.getKey(), delegate); + subtypeToDelegate.put(entry.getValue(), delegate); + } + + return new TypeAdapter() { + @Override public R read(JsonReader in) { + JsonElement jsonElement = Streams.parse(in); + JsonElement labelJsonElement; + if (maintainType) { + labelJsonElement = jsonElement.getAsJsonObject().get(typeFieldName); + } else { + labelJsonElement = jsonElement.getAsJsonObject().remove(typeFieldName); + } + + if (labelJsonElement == null) { + throw new JsonParseException("cannot deserialize " + baseType + + " because it does not define a field named " + typeFieldName); + } + String label = labelJsonElement.getAsString(); + @SuppressWarnings("unchecked") // registration requires that subtype extends T + TypeAdapter delegate = (TypeAdapter) labelToDelegate.get(label); + if (delegate == null) { + throw new JsonParseException("cannot deserialize " + baseType + " subtype named " + + label + "; did you forget to register a subtype?"); + } + return delegate.fromJsonTree(jsonElement); + } + + @Override public void write(JsonWriter out, R value) throws IOException { + Class srcType = value.getClass(); + String label = subtypeToLabel.get(srcType); + @SuppressWarnings("unchecked") // registration requires that subtype extends T + TypeAdapter delegate = (TypeAdapter) subtypeToDelegate.get(srcType); + if (delegate == null) { + throw new JsonParseException("cannot serialize " + srcType.getName() + + "; did you forget to register a subtype?"); + } + JsonObject jsonObject = delegate.toJsonTree(value).getAsJsonObject(); + + if (maintainType) { + Streams.write(jsonObject, out); + return; + } + + JsonObject clone = new JsonObject(); + + if (jsonObject.has(typeFieldName)) { + throw new JsonParseException("cannot serialize " + srcType.getName() + + " because it already defines a field named " + typeFieldName); + } + clone.add(typeFieldName, new JsonPrimitive(label)); + + for (Map.Entry e : jsonObject.entrySet()) { + clone.add(e.getKey(), e.getValue()); + } + Streams.write(clone, out); + } + }.nullSafe(); + } +} diff --git a/NotificationHubs/src/com/windowsazure/messaging/SasTokenProvider.java b/NotificationHubs/src/com/windowsazure/messaging/SasTokenProvider.java new file mode 100644 index 0000000..0b9ddca --- /dev/null +++ b/NotificationHubs/src/com/windowsazure/messaging/SasTokenProvider.java @@ -0,0 +1,68 @@ +package com.windowsazure.messaging; + +import org.apache.commons.codec.binary.Base64; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.net.URI; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +/** + * This class handles the creation of the SAS tokens. + */ +public class SasTokenProvider { + + private final String sasKeyName; + private final String sasKeyValue; + + /** + * Creates a new instance of the SasTokenProvider class. + * @param sasKeyName The SAS key name from the access policy connection string. + * @param sasKeyValue The SAS key value from the access policy connection string. + */ + public SasTokenProvider(String sasKeyName, String sasKeyValue) { + this.sasKeyName = sasKeyName; + this.sasKeyValue = sasKeyValue; + } + + /** + * Creates a SAS token based upon the target URI and SAS key name and SAS key value. + * @param uri The target URI for the SAS token. + * @return The SAS token which is good for one hour. + */ + public String generateSasToken(URI uri) { + String targetUri; + try { + targetUri = URLEncoder + .encode(uri.toString().toLowerCase(), "UTF-8") + .toLowerCase(); + + long expiresOnDate = System.currentTimeMillis(); + expiresOnDate += (long)SdkGlobalSettings.getAuthorizationTokenExpirationInMinutes() * 60 * 1000; + long expires = expiresOnDate / 1000; + String toSign = targetUri + "\n" + expires; + + // Get a hmac_sha1 key from the raw key bytes + byte[] keyBytes = sasKeyValue.getBytes(StandardCharsets.UTF_8); + SecretKeySpec signingKey = new SecretKeySpec(keyBytes, "HmacSHA256"); + + // Get a hmac_sha1 Mac instance and initialize with the signing key + Mac mac = Mac.getInstance("HmacSHA256"); + mac.init(signingKey); + + // Compute the hmac on input data bytes + byte[] rawHmac = mac.doFinal(toSign.getBytes(StandardCharsets.UTF_8)); + + // Convert raw bytes to Hex + String signature = URLEncoder.encode( + Base64.encodeBase64String(rawHmac), "UTF-8"); + + // construct authorization string + return "SharedAccessSignature sr=" + targetUri + "&sig=" + + signature + "&se=" + expires + "&skn=" + sasKeyName; + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/NotificationHubs/src/com/windowsazure/messaging/SyncCallback.java b/NotificationHubs/src/com/windowsazure/messaging/SyncCallback.java index 058913e..1c2e5cd 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/SyncCallback.java +++ b/NotificationHubs/src/com/windowsazure/messaging/SyncCallback.java @@ -8,24 +8,33 @@ import org.apache.http.concurrent.FutureCallback; +/** + * This class represents getting a synchronous value from an asynchronous operation. + * @param The type returned from the asynchronous operation. + */ public class SyncCallback implements FutureCallback { private T result; private RuntimeException runtimeException; private NotificationHubsException nhException; private final CountDownLatch waitLatch = new CountDownLatch(1); + /** + * Gets a synchronous value from an asynchronous operation. + * @return The synchronous value from an asynchronous operation. + * @throws NotificationHubsException If there is an error with the operation. + */ public T getResult() throws NotificationHubsException { try { - this.waitLatch.await(); + waitLatch.await(); } catch (InterruptedException e) { throw new RuntimeException(e); } - if (this.runtimeException != null) - throw this.runtimeException; + if (runtimeException != null) + throw runtimeException; - if (this.nhException != null) - throw this.nhException; + if (nhException != null) + throw nhException; return result; } @@ -39,15 +48,14 @@ public void completed(T result) { @Override public void failed(final Exception ex) { if (ex instanceof NotificationHubsException) { - this.nhException = (NotificationHubsException) ex; + nhException = (NotificationHubsException) ex; } else { - this.runtimeException = new RuntimeException(ex); + runtimeException = new RuntimeException(ex); } this.waitLatch.countDown(); } - @Override public void cancelled() { runtimeException = new RuntimeException("Operation was cancelled."); diff --git a/NotificationHubs/src/com/windowsazure/messaging/TemplateNotification.java b/NotificationHubs/src/com/windowsazure/messaging/TemplateNotification.java new file mode 100644 index 0000000..2c018e5 --- /dev/null +++ b/NotificationHubs/src/com/windowsazure/messaging/TemplateNotification.java @@ -0,0 +1,33 @@ +package com.windowsazure.messaging; + +import org.apache.http.entity.ContentType; + +import java.util.Map; +import java.util.Iterator; + +/** + * This class represents a template notification. + */ +public class TemplateNotification extends Notification { + + /** + * Creates a new instance of the TemplateNotification class. + * @param properties The properties for the template notification. + */ + public TemplateNotification(Map properties) { + StringBuilder buf = new StringBuilder(); + buf.append("{"); + for (Iterator iterator = properties.keySet().iterator(); iterator.hasNext(); ) { + String key = iterator.next(); + buf.append("\"").append(key).append("\":\"").append(properties.get(key)).append("\""); + if (iterator.hasNext()) + buf.append(","); + } + buf.append("}"); + this.body = buf.toString(); + + this.contentType = ContentType.APPLICATION_JSON; + + this.headers.put("ServiceBusNotification-Format", "template"); + } +} diff --git a/NotificationHubs/src/com/windowsazure/messaging/TemplateRegistration.java b/NotificationHubs/src/com/windowsazure/messaging/TemplateRegistration.java new file mode 100644 index 0000000..d065457 --- /dev/null +++ b/NotificationHubs/src/com/windowsazure/messaging/TemplateRegistration.java @@ -0,0 +1,18 @@ +package com.windowsazure.messaging; + +/** + * This interface represents a template registration. + */ +public interface TemplateRegistration { + /** + * Gets the registration template body. + * @return The registration template body. + */ + String getBodyTemplate(); + + /** + * Sets the registration template body. + * @param value The registration template body to set. + */ + void setBodyTemplate(String value); +} diff --git a/NotificationHubs/src/com/windowsazure/messaging/UpdateOperationType.java b/NotificationHubs/src/com/windowsazure/messaging/UpdateOperationType.java index 13f8097..e9c5d11 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/UpdateOperationType.java +++ b/NotificationHubs/src/com/windowsazure/messaging/UpdateOperationType.java @@ -24,5 +24,5 @@ public enum UpdateOperationType { * The replace update operation type. */ @SerializedName("replace") - Replace, + Replace } diff --git a/NotificationHubs/src/com/windowsazure/messaging/WindowsCredential.java b/NotificationHubs/src/com/windowsazure/messaging/WindowsCredential.java index c7149e7..3ab2a64 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/WindowsCredential.java +++ b/NotificationHubs/src/com/windowsazure/messaging/WindowsCredential.java @@ -8,35 +8,54 @@ import java.util.ArrayList; import java.util.List; +/** + * This class represents Azure Notification Hubs credentials for WNS. + */ public final class WindowsCredential extends PnsCredential { private String packageSid; private String secretKey; + /** + * Creates a new instance of the WindowsCredential class. + */ public WindowsCredential() { - this(null, null); + super(); } + /** + * Creates a new instance of the WindowsCredential class. + * @param packageSid The WNS Package SID. + * @param secretKey The WNS secret key. + */ public WindowsCredential(String packageSid, String secretKey) { super(); this.setPackageSid(packageSid); this.setSecretKey(secretKey); } - public String getPackageSid() { - return packageSid; - } + /** + * Gets the WNS Package SID. + * @return The WNS Package SID. + */ + public String getPackageSid() { return packageSid; } - public void setPackageSid(String packageSid) { - this.packageSid = packageSid; - } + /** + * Sets the WNS Package SID. + * @param value The WNS Package SID to set. + */ + public void setPackageSid(String value) { packageSid = value; } - public String getSecretKey() { - return secretKey; - } + /** + * Gets the WNS secret key. + * @return The WNS secret key. + */ + public String getSecretKey() { return secretKey; } - public void setSecretKey(String secretKey) { - this.secretKey = secretKey; - } + /** + * Sets the WNS secret key. + * @param value The WNS secret key to set. + */ + public void setSecretKey(String value) { secretKey = value; } public void setWindowsLiveEndpoint(String propertyValue) { // fix for reflection that's calling 'setWindowsLiveEndpoint' of null. diff --git a/NotificationHubs/src/com/windowsazure/messaging/WindowsNotification.java b/NotificationHubs/src/com/windowsazure/messaging/WindowsNotification.java new file mode 100644 index 0000000..23bdf3e --- /dev/null +++ b/NotificationHubs/src/com/windowsazure/messaging/WindowsNotification.java @@ -0,0 +1,28 @@ +package com.windowsazure.messaging; + +import org.apache.http.entity.ContentType; + +/** + * This class represents a notification for WNS. + */ +public class WindowsNotification extends Notification { + + /** + * Creates a new instance of the WindowsNotification class. + * @param body The XML or raw body for WNS. + */ + public WindowsNotification(String body) { + this.headers.put("ServiceBusNotification-Format", "windows"); + + if (body.matches("^[\\s\\S]+$")) + this.headers.put("X-WNS-Type", "wns/toast"); + if (body.matches("^[\\s\\S]+$")) + this.headers.put("X-WNS-Type", "wns/tile"); + if (body.matches("^[\\s\\S]+$")) + this.headers.put("X-WNS-Type", "wns/badge"); + + if (body.startsWith("<")) { + this.contentType = ContentType.APPLICATION_XML; + } + } +} diff --git a/NotificationHubs/src/com/windowsazure/messaging/WindowsRawNotification.java b/NotificationHubs/src/com/windowsazure/messaging/WindowsRawNotification.java new file mode 100644 index 0000000..63ab9e8 --- /dev/null +++ b/NotificationHubs/src/com/windowsazure/messaging/WindowsRawNotification.java @@ -0,0 +1,20 @@ +package com.windowsazure.messaging; + +import org.apache.http.entity.ContentType; + +/** + * This class represents a raw notification for WNS. + */ +public class WindowsRawNotification extends Notification { + + /** + * Creates a new instance of the WindowsRawNotification class. + * @param body The raw body to send to WNS. + */ + public WindowsRawNotification(String body) { + this.body = body; + this.headers.put("ServiceBusNotification-Format", "windows"); + this.headers.put("X-WNS-Type", "wns/raw"); + this.contentType = ContentType.APPLICATION_OCTET_STREAM; + } +} diff --git a/NotificationHubs/src/com/windowsazure/messaging/WindowsRegistration.java b/NotificationHubs/src/com/windowsazure/messaging/WindowsRegistration.java index 92ade15..f8b0e43 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/WindowsRegistration.java +++ b/NotificationHubs/src/com/windowsazure/messaging/WindowsRegistration.java @@ -6,6 +6,7 @@ import java.net.URI; import java.net.URISyntaxException; +import java.util.Objects; /** * Class representing a native registration for a device using WNS. @@ -17,23 +18,42 @@ public class WindowsRegistration extends Registration { protected URI channelUri; + /** + * Creates a new instance of the WindowsRegistration class. + */ public WindowsRegistration() { + super(); } + /** + * Creates a new instance of the WindowsRegistration class. + * @param channelUri The channel URI for the WNS registration. + */ public WindowsRegistration(URI channelUri) { super(); this.channelUri = channelUri; } + /** + * Creates a new instance of the WindowsRegistration class. + * @param registrationId The Azure Notification Hubs registration ID. + * @param channelUri The channel URI for the WNS registration. + */ public WindowsRegistration(String registrationId, URI channelUri) { super(registrationId); this.channelUri = channelUri; } - public URI getChannelUri() { - return channelUri; - } + /** + * Gets the WNS channel URI. + * @return The WNS channel URI. + */ + public URI getChannelUri() { return channelUri; } + /** + * Sets the WNS channel URI from a string. + * @param channelUri The WNS channel URI string to set. + */ public void setChannelUri(String channelUri) { try { this.channelUri = new URI(channelUri); @@ -42,31 +62,18 @@ public void setChannelUri(String channelUri) { } } - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result - + ((channelUri == null) ? 0 : channelUri.hashCode()); - return result; + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + WindowsRegistration that = (WindowsRegistration) o; + return Objects.equals(getChannelUri(), that.getChannelUri()); } @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (!super.equals(obj)) - return false; - if (getClass() != obj.getClass()) - return false; - WindowsRegistration other = (WindowsRegistration) obj; - if (channelUri == null) { - if (other.channelUri != null) - return false; - } else if (!channelUri.equals(other.channelUri)) - return false; - return true; + public int hashCode() { + return Objects.hash(super.hashCode(), getChannelUri()); } @Override diff --git a/NotificationHubs/src/com/windowsazure/messaging/WindowsTemplateRegistration.java b/NotificationHubs/src/com/windowsazure/messaging/WindowsTemplateRegistration.java index 5f87ff5..5189090 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/WindowsTemplateRegistration.java +++ b/NotificationHubs/src/com/windowsazure/messaging/WindowsTemplateRegistration.java @@ -7,11 +7,12 @@ import java.net.URI; import java.util.HashMap; import java.util.Map; +import java.util.Objects; /** * Class representing a registration for template notifications for devices using WNS. */ -public class WindowsTemplateRegistration extends WindowsRegistration { +public class WindowsTemplateRegistration extends WindowsRegistration implements TemplateRegistration { private static final String WNS_TEMPLATE_REGISTRATION1 = ""; private static final String WNS_TEMPLATE_REGISTRATION2 = ""; private static final String WNS_TEMPLATE_REGISTRATION3 = " headers = new HashMap(); + /** + * Creates a new instance of the WindowsTemplateRegistration class. + */ public WindowsTemplateRegistration() { + super(); } - public WindowsTemplateRegistration(URI channelUri, String bodyTemplate, - Map headers) { + /** + * Creates a new instance of the WindowsTemplateRegistration class. + * @param channelUri The WNS channel URI + * @param bodyTemplate The Windows registration template body. + */ + public WindowsTemplateRegistration( + URI channelUri, + String bodyTemplate + ) { super(channelUri); this.bodyTemplate = bodyTemplate; - this.headers = headers; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result - + ((bodyTemplate == null) ? 0 : bodyTemplate.hashCode()); - result = prime * result + ((headers == null) ? 0 : headers.hashCode()); - return result; } - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (!super.equals(obj)) - return false; - if (getClass() != obj.getClass()) - return false; - WindowsTemplateRegistration other = (WindowsTemplateRegistration) obj; - if (bodyTemplate == null) { - if (other.bodyTemplate != null) - return false; - } else if (!bodyTemplate.equals(other.bodyTemplate)) - return false; - if (headers == null) { - if (other.headers != null) - return false; - } else if (!headers.equals(other.headers)) - return false; - return true; + /** + * Creates a new instance of the WindowsTemplateRegistration class. + * @param registrationId The Azure Notification Hubs registration ID. + * @param channelUri The WNS channel URI. + * @param bodyTemplate The Windows registration template body. + */ + public WindowsTemplateRegistration( + String registrationId, + URI channelUri, + String bodyTemplate + ) { + super(registrationId, channelUri); + this.bodyTemplate = bodyTemplate; } - - public WindowsTemplateRegistration(URI channelUri, - String bodyTemplate) { + /** + * Creates a new instance of the WindowsTemplateRegistration class. + * @param channelUri The WNS channel URI. + * @param bodyTemplate The Windows registration template body. + * @param headers The WNS headers for the template registration. + */ + public WindowsTemplateRegistration( + URI channelUri, + String bodyTemplate, + Map headers + ) { super(channelUri); this.bodyTemplate = bodyTemplate; + this.headers = headers; } - public String getBodyTemplate() { - return bodyTemplate; - } - - public void setBodyTemplate(String bodyTemplate) { + /** + * Creates a new instance of the WindowsTemplateRegistration class. + * @param registrationId The Azure Notification Hubs registration ID. + * @param channelUri The WNS channel URI. + * @param bodyTemplate The Windows registration template body. + * @param headers The WNS headers for the template registration. + */ + public WindowsTemplateRegistration( + String registrationId, + URI channelUri, + String bodyTemplate, + Map headers + ) { + super(registrationId, channelUri); this.bodyTemplate = bodyTemplate; + this.headers = headers; } - public Map getHeaders() { - return headers; - } + /** + * Gets the registration template body. + * @return The registration template body. + */ + @Override + public String getBodyTemplate() { return bodyTemplate; } + /** + * Sets the registration template body. + * @param value The registration template body to set. + */ + @Override + public void setBodyTemplate(String value) { this.bodyTemplate = value; } + + /** + * Gets the WNS headers for the template registration. + * @return The WNS headers for the template registration. + */ + public Map getHeaders() { return headers; } + + /** + * Adds a header to the WNS headers. + * @param name The name of the WNS header to add. + * @param value The value for the WNS header to add. + */ public void addHeader(String name, String value) { headers.put(name, value); } + /** + * Removes a header from the WNS headers. + * @param name The name of the WNS header to remove. + */ + public void removeHeader(String name) { headers.remove(name); } + + /** + * Clears the WNS headers. + */ + public void clearHeaders() { headers.clear(); } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + WindowsTemplateRegistration that = (WindowsTemplateRegistration) o; + return Objects.equals(getBodyTemplate(), that.getBodyTemplate()) && Objects.equals(getHeaders(), that.getHeaders()); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), getBodyTemplate(), getHeaders()); + } + @Override public String getXml() { return WNS_TEMPLATE_REGISTRATION1 + diff --git a/NotificationHubs/src/com/windowsazure/messaging/WnsSecondaryTile.java b/NotificationHubs/src/com/windowsazure/messaging/WnsSecondaryTile.java index 20ef579..c55a480 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/WnsSecondaryTile.java +++ b/NotificationHubs/src/com/windowsazure/messaging/WnsSecondaryTile.java @@ -6,6 +6,7 @@ import java.io.IOException; import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -16,20 +17,35 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; +/** + * This class represents a WNS secondary tile. + */ public class WnsSecondaryTile { private String pushChannel; private boolean pushChannelExpired; private List tags; private Map templates; + /** + * Creates a new instance of the WnsSecondaryTile class. + */ public WnsSecondaryTile() { - this(null); + } + /** + * Creates a new instance of the WnsSecondaryTile class. + * @param pushChannel The push channel URI for the WNS secondary tile. + */ public WnsSecondaryTile(String pushChannel) { this(pushChannel, (String[]) null); } + /** + * Creates a new instance of the WnsSecondaryTile class. + * @param pushChannel The push channel URI for the WNS secondary tile. + * @param tags The tags for the WNS secondary tile. + */ public WnsSecondaryTile(String pushChannel, String... tags) { this.pushChannel = pushChannel; @@ -40,40 +56,107 @@ public WnsSecondaryTile(String pushChannel, String... tags) { } } - public String getPushChannel() { - return pushChannel; - } + /** + * Gets the push channel for the WNS secondary tile. + * @return The push channel for the WNS secondary tile. + */ + public String getPushChannel() { return pushChannel; } + + /** + * Sets the push channel for the WNS secondary tile. + * @param value The push channel for the WNS secondary tile to set. + */ + public void setPushChannel(String value) { pushChannel = value; } + + /** + * Gets whether the push channel is expired. + * @return true if the push channel has expired, otherwise false. + */ + public boolean isPushChannelExpired() { return pushChannelExpired; } + + /** + * Gets the tags for the WNS secondary tile. + * @return The tags for the WNS secondary tile. + */ + public List getTags() { return tags; } + + /** + * Adds a tag to the WNS secondary tile. + * @param tag The tag to add to the WNS secondary tile. + */ + public void addTag(String tag) { + if (tags == null) { + tags = new ArrayList<>(); + } - public void setPushChannel(String pushChannel) { - this.pushChannel = pushChannel; + tags.add(tag); } - public boolean isPushChannelExpired() { - return pushChannelExpired; - } + /** + * Removes a tag from the WNS secondary tile. + * @param tag The tag to remove from the WNS secondary tile. + */ + public void removeTag(String tag) { + if (tags == null) { + return; + } - public List getTags() { - return tags; + tags.remove(tag); } - public void addTag(String tag) { - if (this.tags == null) { - this.tags = new ArrayList<>(); + /** + * Clears the tags from the WNS secondary tile. + */ + public void clearTags() { + if (tags == null) { + return; } - this.tags.add(tag); + tags.clear(); } + /** + * Gets the WNS secondary tile templates. + * @return The WNS secondary tile templates. + */ public Map getTemplates() { return templates; } + /** + * Adds a template to the WNS secondary tile. + * @param templateName The name of the template. + * @param template The installation template to add with the given name. + */ public void addTemplate(String templateName, InstallationTemplate template) { - if (this.templates == null) { - this.templates = new HashMap<>(); + if (templates == null) { + templates = new HashMap<>(); + } + + templates.put(templateName, template); + } + + /** + * Removes a template from the WNS secondary tile. + * @param templateName The name of the template to remove from the WNS secondary tile. + */ + public void removeTemplate(String templateName) { + if (templates == null) { + return; + } + + templates.remove(templateName); + } + + /** + * Clears the templates from the WNS secondary tile. + */ + public void clearTemplates() { + if (templates == null) { + return; } - this.templates.put(templateName, template); + templates.clear(); } public static WnsSecondaryTile fromJson(String json) { @@ -81,7 +164,7 @@ public static WnsSecondaryTile fromJson(String json) { } public static WnsSecondaryTile fromJson(InputStream json) throws IOException { - return WnsSecondaryTile.fromJson(IOUtils.toString(json)); + return WnsSecondaryTile.fromJson(IOUtils.toString(json, StandardCharsets.UTF_8)); } public String toJson() { diff --git a/NotificationHubs/test/com/windowsazure/messaging/InstallationBrowserMinimal b/NotificationHubs/test/com/windowsazure/messaging/InstallationBrowserMinimal new file mode 100644 index 0000000..dce8c02 --- /dev/null +++ b/NotificationHubs/test/com/windowsazure/messaging/InstallationBrowserMinimal @@ -0,0 +1,9 @@ +{ + "pushChannel":{ + "endpoint":"https://some.url", + "p256dh":"p256-value", + "auth":"auth-value" + }, + "installationId":"123", + "platform":"browser" +} diff --git a/NotificationHubs/test/com/windowsazure/messaging/InstallationMinimal b/NotificationHubs/test/com/windowsazure/messaging/InstallationMinimal index 6fa950d..cf8383d 100644 --- a/NotificationHubs/test/com/windowsazure/messaging/InstallationMinimal +++ b/NotificationHubs/test/com/windowsazure/messaging/InstallationMinimal @@ -1,5 +1,5 @@ { + "pushChannel":"qwe", "installationId":"123", - "platform":"gcm", - "pushChannel":"qwe" -} \ No newline at end of file + "platform":"gcm" +} diff --git a/NotificationHubs/test/com/windowsazure/messaging/InstallationMinimalNoSpaces b/NotificationHubs/test/com/windowsazure/messaging/InstallationMinimalNoSpaces deleted file mode 100644 index e6648de..0000000 --- a/NotificationHubs/test/com/windowsazure/messaging/InstallationMinimalNoSpaces +++ /dev/null @@ -1 +0,0 @@ -{"installationId":"123","platform":"gcm","pushChannel":"qwe","pushChannelExpired":false} \ No newline at end of file diff --git a/NotificationHubs/test/com/windowsazure/messaging/InstallationParseTest.java b/NotificationHubs/test/com/windowsazure/messaging/InstallationParseTest.java index 857a9ab..c9d7d7a 100644 --- a/NotificationHubs/test/com/windowsazure/messaging/InstallationParseTest.java +++ b/NotificationHubs/test/com/windowsazure/messaging/InstallationParseTest.java @@ -20,6 +20,21 @@ public class InstallationParseTest { + @Test + public void InstallationBrowser() throws IOException { + BrowserPushChannel pushChannel = new BrowserPushChannel( + "https://some.url", + "p256-value", + "auth-value"); + + InputStream inputJson = this.getClass().getResourceAsStream("InstallationBrowserMinimal"); + BrowserInstallation installation = BrowserInstallation.fromJson(inputJson); + assertNotNull(installation); + assertEquals("123", installation.getInstallationId()); + assertEquals(NotificationPlatform.Browser, installation.getPlatform()); + assertEquals(pushChannel, installation.getPushChannel()); + } + @Test public void InstallationMinimal() throws IOException { InputStream inputJson = this.getClass().getResourceAsStream("InstallationMinimal"); @@ -28,10 +43,6 @@ public void InstallationMinimal() throws IOException { assertEquals("123", installation.getInstallationId()); assertEquals(NotificationPlatform.Gcm, installation.getPlatform()); assertEquals("qwe", installation.getPushChannel()); - - String expectedResultJson = IOUtils.toString(this.getClass().getResourceAsStream("InstallationMinimalNoSpaces"), StandardCharsets.UTF_8); - String actualResultJson = installation.toJson(); - assertEquals(expectedResultJson, actualResultJson); } @Test @@ -47,11 +58,6 @@ public void InstallationWnsFull() throws IOException, ParseException { assertEquals("", installation.getTemplates().get("template1").getBody()); Date expiration = installation.getExpirationTime(); assertEquals(expiration.toString(), sdf.parse("Wed Nov 26 15:34:01 PST 2014").toString()); - - - String expectedResultJson = IOUtils.toString(this.getClass().getResourceAsStream("InstallationWnsFullNoSpaces"), StandardCharsets.UTF_8); - String actualResultJson = installation.toJson(); - assertEquals(expectedResultJson, actualResultJson); } @Test diff --git a/NotificationHubs/test/com/windowsazure/messaging/e2e/InstallationCrudsE2E.java b/NotificationHubs/test/com/windowsazure/messaging/e2e/InstallationCrudsE2E.java index 34326ce..e4a9995 100644 --- a/NotificationHubs/test/com/windowsazure/messaging/e2e/InstallationCrudsE2E.java +++ b/NotificationHubs/test/com/windowsazure/messaging/e2e/InstallationCrudsE2E.java @@ -21,7 +21,7 @@ public void setUp() throws Exception { String connectionString = p.getProperty("connectionstring"); assertTrue(connectionString != null && !connectionString.isEmpty()); - hubPath = "JavaSDK_" + UUID.randomUUID().toString(); + hubPath = "JavaSDK_" + UUID.randomUUID(); namespaceManager = new NamespaceManager(connectionString); NotificationHubDescription hubDescription = new NotificationHubDescription(hubPath); namespaceManager.createNotificationHub(hubDescription); From 1a41ce5124dfa1af207b2e99e0d6fe4e8586eadf Mon Sep 17 00:00:00 2001 From: Matthew Podwysocki Date: Thu, 12 Aug 2021 15:56:18 -0400 Subject: [PATCH 3/7] Fixing parsing bug --- .../src/com/windowsazure/messaging/WindowsNotification.java | 1 + 1 file changed, 1 insertion(+) diff --git a/NotificationHubs/src/com/windowsazure/messaging/WindowsNotification.java b/NotificationHubs/src/com/windowsazure/messaging/WindowsNotification.java index 1cc36e6..2703e97 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/WindowsNotification.java +++ b/NotificationHubs/src/com/windowsazure/messaging/WindowsNotification.java @@ -25,5 +25,6 @@ public WindowsNotification(String body) { if (body.startsWith("<")) { this.contentType = ContentType.APPLICATION_XML; + } } } From e659eec15c0eef1b3c5d948df3f1b98aad0f928d Mon Sep 17 00:00:00 2001 From: Matthew Podwysocki Date: Sat, 14 Aug 2021 21:10:31 -0400 Subject: [PATCH 4/7] Updating type safety --- .../messaging/AdmInstallation.java | 45 +++ .../messaging/AppleInstallation.java | 45 +++ .../messaging/BaiduInstallation.java | 45 +++ .../messaging/BaseInstallation.java | 63 ++-- .../BaseInstallationDeserializer.java | 27 +- .../messaging/BaseInstallationFactory.java | 7 +- .../messaging/BrowserInstallation.java | 40 +-- .../messaging/FcmInstallation.java | 45 +++ .../messaging/MpnsInstallation.java | 45 +++ .../messaging/NotificationHub.java | 70 +---- .../messaging/NotificationHubClient.java | 22 +- .../messaging/RuntimeTypeAdapterFactory.java | 276 ------------------ .../messaging/WindowsInstallation.java | 96 ++++++ .../messaging/InstallationParseTest.java | 19 +- .../messaging/e2e/InstallationCrudsE2E.java | 11 +- 15 files changed, 396 insertions(+), 460 deletions(-) create mode 100644 NotificationHubs/src/com/windowsazure/messaging/AdmInstallation.java create mode 100644 NotificationHubs/src/com/windowsazure/messaging/AppleInstallation.java create mode 100644 NotificationHubs/src/com/windowsazure/messaging/BaiduInstallation.java create mode 100644 NotificationHubs/src/com/windowsazure/messaging/FcmInstallation.java create mode 100644 NotificationHubs/src/com/windowsazure/messaging/MpnsInstallation.java delete mode 100644 NotificationHubs/src/com/windowsazure/messaging/RuntimeTypeAdapterFactory.java create mode 100644 NotificationHubs/src/com/windowsazure/messaging/WindowsInstallation.java diff --git a/NotificationHubs/src/com/windowsazure/messaging/AdmInstallation.java b/NotificationHubs/src/com/windowsazure/messaging/AdmInstallation.java new file mode 100644 index 0000000..9494eb0 --- /dev/null +++ b/NotificationHubs/src/com/windowsazure/messaging/AdmInstallation.java @@ -0,0 +1,45 @@ +package com.windowsazure.messaging; + +/** + * This class represents an Amazon Device + */ +public class AdmInstallation extends Installation { + + /** + * Creates a new instance of the AdmInstallation class. + * + * @param installationId The ID for the installation. + */ + public AdmInstallation(String installationId) { + super(installationId, NotificationPlatform.Adm, null, null); + } + + /** + * Creates a new instance of the AdmInstallation class. + * + * @param installationId The ID for the installation. + * @param tags The tags for the installation. + */ + public AdmInstallation(String installationId, String... tags) { + super(installationId, NotificationPlatform.Adm, null, tags); + } + + /** + * Creates a new instance of the AdmInstallation class. + * + * @param installationId The ID for the installation. + */ + public AdmInstallation(String installationId, String pushChannel) { + super(installationId, NotificationPlatform.Adm, pushChannel, (String[]) null); + } + + /** + * Creates a new instance of the AdmInstallation class. + * @param installationId The ID for the installation. + * @param pushChannel The device specific push channel for the installation. + * @param tags The tags for the installation. + */ + public AdmInstallation(String installationId, String pushChannel, String... tags) { + super(installationId, NotificationPlatform.Adm, pushChannel, tags); + } +} diff --git a/NotificationHubs/src/com/windowsazure/messaging/AppleInstallation.java b/NotificationHubs/src/com/windowsazure/messaging/AppleInstallation.java new file mode 100644 index 0000000..f387eef --- /dev/null +++ b/NotificationHubs/src/com/windowsazure/messaging/AppleInstallation.java @@ -0,0 +1,45 @@ +package com.windowsazure.messaging; + +/** + * This class represents an Apple installation. + */ +public class AppleInstallation extends Installation { + + /** + * Creates a new instance of the AppleInstallation class. + * + * @param installationId The ID for the installation. + */ + public AppleInstallation(String installationId) { + super(installationId, NotificationPlatform.Apns, null, null); + } + + /** + * Creates a new instance of the AppleInstallation class. + * + * @param installationId The ID for the installation. + * @param tags The tags for the installation. + */ + public AppleInstallation(String installationId, String... tags) { + super(installationId, NotificationPlatform.Apns, null, tags); + } + + /** + * Creates a new instance of the AppleInstallation class. + * + * @param installationId The ID for the installation. + */ + public AppleInstallation(String installationId, String pushChannel) { + super(installationId, NotificationPlatform.Apns, pushChannel, (String[]) null); + } + + /** + * Creates a new instance of the AppleInstallation class. + * @param installationId The ID for the installation. + * @param pushChannel The device specific push channel for the installation. + * @param tags The tags for the installation. + */ + public AppleInstallation(String installationId, String pushChannel, String... tags) { + super(installationId, NotificationPlatform.Apns, pushChannel, tags); + } +} diff --git a/NotificationHubs/src/com/windowsazure/messaging/BaiduInstallation.java b/NotificationHubs/src/com/windowsazure/messaging/BaiduInstallation.java new file mode 100644 index 0000000..f5172d0 --- /dev/null +++ b/NotificationHubs/src/com/windowsazure/messaging/BaiduInstallation.java @@ -0,0 +1,45 @@ +package com.windowsazure.messaging; + +/** + * This class represents a Baidu Installation. + */ +public class BaiduInstallation extends Installation { + + /** + * Creates a new instance of the BaiduInstallation class. + * + * @param installationId The ID for the installation. + */ + public BaiduInstallation(String installationId) { + super(installationId, NotificationPlatform.Baidu, null, null); + } + + /** + * Creates a new instance of the BaiduInstallation class. + * + * @param installationId The ID for the installation. + * @param tags The tags for the installation. + */ + public BaiduInstallation(String installationId, String... tags) { + super(installationId, NotificationPlatform.Baidu, null, tags); + } + + /** + * Creates a new instance of the BaiduInstallation class. + * + * @param installationId The ID for the installation. + */ + public BaiduInstallation(String installationId, String pushChannel) { + super(installationId, NotificationPlatform.Baidu, pushChannel, (String[]) null); + } + + /** + * Creates a new instance of the BaiduInstallation class. + * @param installationId The ID for the installation. + * @param pushChannel The device specific push channel for the installation. + * @param tags The tags for the installation. + */ + public BaiduInstallation(String installationId, String pushChannel, String... tags) { + super(installationId, NotificationPlatform.Baidu, pushChannel, tags); + } +} diff --git a/NotificationHubs/src/com/windowsazure/messaging/BaseInstallation.java b/NotificationHubs/src/com/windowsazure/messaging/BaseInstallation.java index 4101b94..4a55456 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/BaseInstallation.java +++ b/NotificationHubs/src/com/windowsazure/messaging/BaseInstallation.java @@ -5,7 +5,7 @@ import java.text.SimpleDateFormat; import java.util.*; -public abstract class BaseInstallation { +public abstract class BaseInstallation implements Cloneable { private String installationId; private String userId; private NotificationPlatform platform; @@ -13,7 +13,6 @@ public abstract class BaseInstallation { private String expirationTime; private List tags; private Map templates; - private Map secondaryTiles; /** * Creates a new installation. @@ -49,6 +48,12 @@ public BaseInstallation(String installationId, NotificationPlatform platform) { this(installationId, platform, (String[]) null); } + /** + * Creates a new instance of the BaseInstallation class. + * @param installationId The ID for the installation. + * @param platform The platform for the installation. + * @param tags The tags for the installation. + */ public BaseInstallation(String installationId, NotificationPlatform platform, String... tags) { // Validate that this is not FCM validateNotificationPlatform(platform); @@ -62,6 +67,18 @@ public BaseInstallation(String installationId, NotificationPlatform platform, St } } + /** + * Clones the current registration. + * @return A clone of the current registration. + */ + public BaseInstallation clone() { + try { + return (BaseInstallation) super.clone(); + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + /** * Validates that the platform is not FCM. Currently, Notification Hubs supports * FCM Legacy as NotificationPlatform.Gcm Full support for FCM is not currently @@ -257,48 +274,6 @@ public void clearTemplates() { templates.clear(); } - /** - * Gets the secondary tiles for WNS - * - * @return The secondary tiles for WNS. - */ - public Map getSecondaryTiles() { - return secondaryTiles; - } - - /** - * Adds a secondary tile to the installation template. - * - * @param tileName The name for the tile. - * @param tile THe WNS secondary tile. - */ - public void addSecondaryTile(String tileName, WnsSecondaryTile tile) { - if (templates == null) { - secondaryTiles = new HashMap<>(); - } - - secondaryTiles.put(tileName, tile); - } - - public void removeSecondaryTile(String tileName) { - if (templates == null) { - return; - } - - secondaryTiles.remove(tileName); - } - - /** - * Clears the WNS secondary tiles. - */ - public void clearSecondaryTiles() { - if (templates == null) { - return; - } - - secondaryTiles.clear(); - } - /** * Converts the installation to a JSON string. * diff --git a/NotificationHubs/src/com/windowsazure/messaging/BaseInstallationDeserializer.java b/NotificationHubs/src/com/windowsazure/messaging/BaseInstallationDeserializer.java index d7236d8..9ed7f6b 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/BaseInstallationDeserializer.java +++ b/NotificationHubs/src/com/windowsazure/messaging/BaseInstallationDeserializer.java @@ -16,14 +16,27 @@ public BaseInstallation deserialize(JsonElement jsonElement, Type type, JsonDese JsonElement jsonType = jsonObject.get("platform"); String platformString = jsonType.getAsString(); - BaseInstallation installation; + return jsonDeserializationContext.deserialize(jsonElement, getClass(platformString)); + } - if (platformString.equalsIgnoreCase("browser")) { - installation = jsonDeserializationContext.deserialize(jsonElement, BrowserInstallation.class); - } else { - installation = jsonDeserializationContext.deserialize(jsonElement, Installation.class); + private static Class getClass(String platformString) { + switch (platformString) { + case "adm": + return AdmInstallation.class; + case "apple": + return AppleInstallation.class; + case "baidu": + return BaiduInstallation.class; + case "browser": + return BrowserInstallation.class; + case "fcm": + return FcmInstallation.class; + case "mpns": + return MpnsInstallation.class; + case "wns": + return WindowsInstallation.class; + default: + return Installation.class; } - - return installation; } } diff --git a/NotificationHubs/src/com/windowsazure/messaging/BaseInstallationFactory.java b/NotificationHubs/src/com/windowsazure/messaging/BaseInstallationFactory.java index f7663f5..d0e593a 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/BaseInstallationFactory.java +++ b/NotificationHubs/src/com/windowsazure/messaging/BaseInstallationFactory.java @@ -16,13 +16,14 @@ public class BaseInstallationFactory { * @param jsonString The JSON string that represents the installation. * @return An installation created from the JSON string. */ - public static BaseInstallation createInstallation(String jsonString) { + @SuppressWarnings("unchecked") + public static T createInstallation(String jsonString) { Gson gson = new GsonBuilder() .registerTypeAdapter(BaseInstallation.class, new BaseInstallationDeserializer()) .create(); - return gson.fromJson(jsonString, BaseInstallation.class); + return (T)gson.fromJson(jsonString, BaseInstallation.class); } /** @@ -32,7 +33,7 @@ public static BaseInstallation createInstallation(String jsonString) { * @return An installation created from the JSON stream. * @throws IOException An exception reading from the stream occurred. */ - public static BaseInstallation createInstallation(InputStream json) throws IOException { + public static T createInstallation(InputStream json) throws IOException { return createInstallation(IOUtils.toString(json, StandardCharsets.UTF_8)); } } diff --git a/NotificationHubs/src/com/windowsazure/messaging/BrowserInstallation.java b/NotificationHubs/src/com/windowsazure/messaging/BrowserInstallation.java index c207c5b..64a5bbd 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/BrowserInstallation.java +++ b/NotificationHubs/src/com/windowsazure/messaging/BrowserInstallation.java @@ -1,12 +1,5 @@ package com.windowsazure.messaging; -import com.google.gson.Gson; -import org.apache.commons.io.IOUtils; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; - /** * This class represents an installation for browser push. */ @@ -29,28 +22,26 @@ public BrowserInstallation(String installationId) { * @param tags The tags for the installation. */ public BrowserInstallation(String installationId, String... tags) { - this(installationId, null, null, tags); + this(installationId, null, tags); } /** * Creates a new instance of the Installation class. * * @param installationId The ID for the installation. - * @param platform The platform for the installation. */ - public BrowserInstallation(String installationId, NotificationPlatform platform, BrowserPushChannel pushChannel) { - this(installationId, platform, pushChannel, (String[]) null); + public BrowserInstallation(String installationId, BrowserPushChannel pushChannel) { + this(installationId, pushChannel, (String[]) null); } /** * Creates a new instance of the Installation class. * @param installationId The ID for the installation. - * @param platform The platform for the installation * @param pushChannel The device specific push channel for the installation. * @param tags The tags for the installation. */ - public BrowserInstallation(String installationId, NotificationPlatform platform, BrowserPushChannel pushChannel, String... tags) { - super(installationId, platform, tags); + public BrowserInstallation(String installationId, BrowserPushChannel pushChannel, String... tags) { + super(installationId, NotificationPlatform.Browser, tags); this.pushChannel = pushChannel; } @@ -67,25 +58,4 @@ public BrowserInstallation(String installationId, NotificationPlatform platform, * @param value The PNS specific push channel for the installation */ public void setPushChannel(BrowserPushChannel value) { pushChannel = value; } - - /** - * Creates an installation from the JSON string. - * - * @param json The JSON string that represents the installation. - * @return An installation created from the JSON string. - */ - public static BrowserInstallation fromJson(String json) { - return new Gson().fromJson(json, BrowserInstallation.class); - } - - /** - * Creates an installation from the JSON stream. - * - * @param json The JSON string that represents the installation. - * @return An installation created from the JSON stream. - * @throws IOException An exception reading from the stream occurred. - */ - public static BrowserInstallation fromJson(InputStream json) throws IOException { - return BrowserInstallation.fromJson(IOUtils.toString(json, StandardCharsets.UTF_8)); - } } diff --git a/NotificationHubs/src/com/windowsazure/messaging/FcmInstallation.java b/NotificationHubs/src/com/windowsazure/messaging/FcmInstallation.java new file mode 100644 index 0000000..ce29224 --- /dev/null +++ b/NotificationHubs/src/com/windowsazure/messaging/FcmInstallation.java @@ -0,0 +1,45 @@ +package com.windowsazure.messaging; + +/** + * This class represents a Firebase Cloud Messaging installation. + */ +public class FcmInstallation extends Installation { + + /** + * Creates a new instance of the FcmInstallation class. + * + * @param installationId The ID for the installation. + */ + public FcmInstallation(String installationId) { + super(installationId, NotificationPlatform.Gcm, null, (String[]) null); + } + + /** + * Creates a new instance of the FcmInstallation class. + * + * @param installationId The ID for the installation. + * @param tags The tags for the installation. + */ + public FcmInstallation(String installationId, String... tags) { + super(installationId, NotificationPlatform.Gcm, null, tags); + } + + /** + * Creates a new instance of the BaiduInstallation class. + * + * @param installationId The ID for the installation. + */ + public FcmInstallation(String installationId, String pushChannel) { + super(installationId, NotificationPlatform.Gcm, pushChannel, (String[]) null); + } + + /** + * Creates a new instance of the BaiduInstallation class. + * @param installationId The ID for the installation. + * @param pushChannel The device specific push channel for the installation. + * @param tags The tags for the installation. + */ + public FcmInstallation(String installationId, String pushChannel, String... tags) { + super(installationId, NotificationPlatform.Gcm, pushChannel, tags); + } +} diff --git a/NotificationHubs/src/com/windowsazure/messaging/MpnsInstallation.java b/NotificationHubs/src/com/windowsazure/messaging/MpnsInstallation.java new file mode 100644 index 0000000..923a746 --- /dev/null +++ b/NotificationHubs/src/com/windowsazure/messaging/MpnsInstallation.java @@ -0,0 +1,45 @@ +package com.windowsazure.messaging; + +/** + * This class represents a Windows Phone PNS installation + */ +public class MpnsInstallation extends Installation { + + /** + * Creates a new instance of the MpnsInstallation class. + * + * @param installationId The ID for the installation. + */ + public MpnsInstallation(String installationId) { + super(installationId, NotificationPlatform.Mpns, null, (String[]) null); + } + + /** + * Creates a new instance of the MpnsInstallation class. + * + * @param installationId The ID for the installation. + * @param tags The tags for the installation. + */ + public MpnsInstallation(String installationId, String... tags) { + super(installationId, NotificationPlatform.Mpns, null, tags); + } + + /** + * Creates a new instance of the MpnsInstallation class. + * + * @param installationId The ID for the installation. + */ + public MpnsInstallation(String installationId, String pushChannel) { + super(installationId, NotificationPlatform.Mpns, pushChannel, (String[]) null); + } + + /** + * Creates a new instance of the MpnsInstallation class. + * @param installationId The ID for the installation. + * @param pushChannel The device specific push channel for the installation. + * @param tags The tags for the installation. + */ + public MpnsInstallation(String installationId, String pushChannel, String... tags) { + super(installationId, NotificationPlatform.Mpns, pushChannel, tags); + } +} diff --git a/NotificationHubs/src/com/windowsazure/messaging/NotificationHub.java b/NotificationHubs/src/com/windowsazure/messaging/NotificationHub.java index 9dbcca7..1941cda 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/NotificationHub.java +++ b/NotificationHubs/src/com/windowsazure/messaging/NotificationHub.java @@ -1636,7 +1636,7 @@ public void deleteInstallation(String installationId) throws NotificationHubsExc * installation by the installation ID. */ @Override - public void getInstallationAsync(String installationId, final FutureCallback callback) { + public void getInstallationAsync(String installationId, final FutureCallback callback) { try { URI uri = new URI(endpoint + hubPath + "/installations/" + installationId + API_VERSION); final HttpGet get = new HttpGet(uri); @@ -1653,7 +1653,7 @@ public void completed(final HttpResponse response) { return; } - callback.completed(Installation.fromJson(response.getEntity().getContent())); + callback.completed(BaseInstallationFactory.createInstallation(response.getEntity().getContent())); } catch (Exception e) { callback.failed(e); } finally { @@ -1684,74 +1684,12 @@ public void cancelled() { * @throws NotificationHubsException Thrown if there is a client error. */ @Override - public Installation getInstallation(String installationId) throws NotificationHubsException { - SyncCallback callback = new SyncCallback<>(); + public T getInstallation(String installationId) throws NotificationHubsException { + SyncCallback callback = new SyncCallback<>(); getInstallationAsync(installationId, callback); return callback.getResult(); } - /** - * Gets a browser installation by the given installation ID. - * - * @param installationId The installation ID for the installation to get. - * @param callback A callback, when invoked, returns the matching - * installation by the installation ID. - */ - @Override - public void getBrowserInstallationAsync(String installationId, final FutureCallback callback) { - try { - URI uri = new URI(endpoint + hubPath + "/installations/" + installationId + API_VERSION); - final HttpGet get = new HttpGet(uri); - get.setHeader("Authorization", tokenProvider.generateSasToken(uri)); - get.setHeader("User-Agent", getUserAgent()); - - HttpClientManager.getHttpAsyncClient().execute(get, new FutureCallback() { - public void completed(final HttpResponse response) { - try { - int httpStatusCode = response.getStatusLine().getStatusCode(); - if (httpStatusCode != 200) { - callback.failed(NotificationHubsExceptionFactory.createNotificationHubException(response, - httpStatusCode)); - return; - } - - callback.completed(BrowserInstallation.fromJson(response.getEntity().getContent())); - } catch (Exception e) { - callback.failed(e); - } finally { - get.releaseConnection(); - } - } - - public void failed(final Exception ex) { - get.releaseConnection(); - callback.failed(ex); - } - - public void cancelled() { - get.releaseConnection(); - callback.cancelled(); - } - }); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - /** - * Gets an installation by the given installation ID. - * - * @param installationId The installation ID for the installation to get. - * @return The matching installation by the installation ID. - * @throws NotificationHubsException Thrown if there is a client error. - */ - @Override - public BrowserInstallation getBrowserInstallation(String installationId) throws NotificationHubsException { - SyncCallback callback = new SyncCallback<>(); - getBrowserInstallationAsync(installationId, callback); - return callback.getResult(); - } - /** * Submits a notification hub job such as import or export. * diff --git a/NotificationHubs/src/com/windowsazure/messaging/NotificationHubClient.java b/NotificationHubs/src/com/windowsazure/messaging/NotificationHubClient.java index 4707067..aff993e 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/NotificationHubClient.java +++ b/NotificationHubs/src/com/windowsazure/messaging/NotificationHubClient.java @@ -99,34 +99,16 @@ void patchInstallationAsync( * @return The matching installation by the installation ID. * @throws NotificationHubsException Thrown if there is a client error. */ - Installation getInstallation(String installationId) throws NotificationHubsException; + T getInstallation(String installationId) throws NotificationHubsException; /** * Gets an installation by the given installation ID. * * @param installationId The installation ID for the installation to get. - * @return The matching installation by the installation ID. - * @throws NotificationHubsException Thrown if there is a client error. - */ - BrowserInstallation getBrowserInstallation(String installationId) throws NotificationHubsException; - - /** - * Gets an installation by the given installation ID. - * - * @param installationId The installation ID for the installation to get. - * @param callback A callback, when invoked, returns the matching - * installation by the installation ID. - */ - void getInstallationAsync(String installationId, FutureCallback callback); - - /** - * Gets a browser installation by the given installation ID. - * - * @param installationId The installation ID for the installation to get. * @param callback A callback, when invoked, returns the matching * installation by the installation ID. */ - void getBrowserInstallationAsync(String installationId, FutureCallback callback); + void getInstallationAsync(String installationId, FutureCallback callback); /** * Submits a notification hub job such as import or export. diff --git a/NotificationHubs/src/com/windowsazure/messaging/RuntimeTypeAdapterFactory.java b/NotificationHubs/src/com/windowsazure/messaging/RuntimeTypeAdapterFactory.java deleted file mode 100644 index 3b271fa..0000000 --- a/NotificationHubs/src/com/windowsazure/messaging/RuntimeTypeAdapterFactory.java +++ /dev/null @@ -1,276 +0,0 @@ -/* - * Copyright (C) 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.windowsazure.messaging; - -import java.io.IOException; -import java.util.LinkedHashMap; -import java.util.Map; - -import com.google.gson.Gson; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import com.google.gson.JsonPrimitive; -import com.google.gson.TypeAdapter; -import com.google.gson.TypeAdapterFactory; -import com.google.gson.internal.Streams; -import com.google.gson.reflect.TypeToken; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; - -/** - * Adapts values whose runtime type may differ from their declaration type. This - * is necessary when a field's type is not the same type that GSON should create - * when deserializing that field. For example, consider these types: - *
   {@code
- *   abstract class Shape {
- *     int x;
- *     int y;
- *   }
- *   class Circle extends Shape {
- *     int radius;
- *   }
- *   class Rectangle extends Shape {
- *     int width;
- *     int height;
- *   }
- *   class Diamond extends Shape {
- *     int width;
- *     int height;
- *   }
- *   class Drawing {
- *     Shape bottomShape;
- *     Shape topShape;
- *   }
- * }
- *

Without additional type information, the serialized JSON is ambiguous. Is - * the bottom shape in this drawing a rectangle or a diamond?

   {@code
- *   {
- *     "bottomShape": {
- *       "width": 10,
- *       "height": 5,
- *       "x": 0,
- *       "y": 0
- *     },
- *     "topShape": {
- *       "radius": 2,
- *       "x": 4,
- *       "y": 1
- *     }
- *   }}
- * This class addresses this problem by adding type information to the - * serialized JSON and honoring that type information when the JSON is - * deserialized:
   {@code
- *   {
- *     "bottomShape": {
- *       "type": "Diamond",
- *       "width": 10,
- *       "height": 5,
- *       "x": 0,
- *       "y": 0
- *     },
- *     "topShape": {
- *       "type": "Circle",
- *       "radius": 2,
- *       "x": 4,
- *       "y": 1
- *     }
- *   }}
- * Both the type field name ({@code "type"}) and the type labels ({@code - * "Rectangle"}) are configurable. - * - *

Registering Types

- * Create a {@code RuntimeTypeAdapterFactory} by passing the base type and type field - * name to the {@link #of} factory method. If you don't supply an explicit type - * field name, {@code "type"} will be used.
   {@code
- *   RuntimeTypeAdapterFactory shapeAdapterFactory
- *       = RuntimeTypeAdapterFactory.of(Shape.class, "type");
- * }
- * Next register all of your subtypes. Every subtype must be explicitly - * registered. This protects your application from injection attacks. If you - * don't supply an explicit type label, the type's simple name will be used. - *
   {@code
- *   shapeAdapterFactory.registerSubtype(Rectangle.class, "Rectangle");
- *   shapeAdapterFactory.registerSubtype(Circle.class, "Circle");
- *   shapeAdapterFactory.registerSubtype(Diamond.class, "Diamond");
- * }
- * Finally, register the type adapter factory in your application's GSON builder: - *
   {@code
- *   Gson gson = new GsonBuilder()
- *       .registerTypeAdapterFactory(shapeAdapterFactory)
- *       .create();
- * }
- * Like {@code GsonBuilder}, this API supports chaining:
   {@code
- *   RuntimeTypeAdapterFactory shapeAdapterFactory = RuntimeTypeAdapterFactory.of(Shape.class)
- *       .registerSubtype(Rectangle.class)
- *       .registerSubtype(Circle.class)
- *       .registerSubtype(Diamond.class);
- * }
- * - *

Serialization and deserialization

- * In order to serialize and deserialize a polymorphic object, - * you must specify the base type explicitly. - *
   {@code
- *   Diamond diamond = new Diamond();
- *   String json = gson.toJson(diamond, Shape.class);
- * }
- * And then: - *
   {@code
- *   Shape shape = gson.fromJson(json, Shape.class);
- * }
- */ -public final class RuntimeTypeAdapterFactory implements TypeAdapterFactory { - private final Class baseType; - private final String typeFieldName; - private final Map> labelToSubtype = new LinkedHashMap<>(); - private final Map, String> subtypeToLabel = new LinkedHashMap<>(); - private final boolean maintainType; - - private RuntimeTypeAdapterFactory(Class baseType, String typeFieldName, boolean maintainType) { - if (typeFieldName == null || baseType == null) { - throw new NullPointerException(); - } - this.baseType = baseType; - this.typeFieldName = typeFieldName; - this.maintainType = maintainType; - } - - /** - * Creates a new runtime type adapter using for {@code baseType} using {@code - * typeFieldName} as the type field name. Type field names are case-sensitive. - * {@code maintainType} flag decide if the type will be stored in pojo or not. - */ - public static RuntimeTypeAdapterFactory of(Class baseType, String typeFieldName, boolean maintainType) { - return new RuntimeTypeAdapterFactory<>(baseType, typeFieldName, maintainType); - } - - /** - * Creates a new runtime type adapter using for {@code baseType} using {@code - * typeFieldName} as the type field name. Type field names are case-sensitive. - */ - public static RuntimeTypeAdapterFactory of(Class baseType, String typeFieldName) { - return new RuntimeTypeAdapterFactory<>(baseType, typeFieldName, false); - } - - /** - * Creates a new runtime type adapter for {@code baseType} using {@code "type"} as - * the type field name. - */ - public static RuntimeTypeAdapterFactory of(Class baseType) { - return new RuntimeTypeAdapterFactory<>(baseType, "type", false); - } - - /** - * Registers {@code type} identified by {@code label}. Labels are case-sensitive. - * - * @throws IllegalArgumentException if either {@code type} or {@code label} - * have already been registered on this type adapter. - */ - public RuntimeTypeAdapterFactory registerSubtype(Class type, String label) { - if (type == null || label == null) { - throw new NullPointerException(); - } - if (subtypeToLabel.containsKey(type) || labelToSubtype.containsKey(label)) { - throw new IllegalArgumentException("types and labels must be unique"); - } - labelToSubtype.put(label, type); - subtypeToLabel.put(type, label); - return this; - } - - /** - * Registers {@code type} identified by its {@link Class#getSimpleName simple - * name}. Labels are case-sensitive. - * - * @throws IllegalArgumentException if either {@code type} or its simple name - * have already been registered on this type adapter. - */ - public RuntimeTypeAdapterFactory registerSubtype(Class type) { - return registerSubtype(type, type.getSimpleName()); - } - - public TypeAdapter create(Gson gson, TypeToken type) { - if (type.getRawType() != baseType) { - return null; - } - - final Map> labelToDelegate - = new LinkedHashMap<>(); - final Map, TypeAdapter> subtypeToDelegate - = new LinkedHashMap<>(); - for (Map.Entry> entry : labelToSubtype.entrySet()) { - TypeAdapter delegate = gson.getDelegateAdapter(this, TypeToken.get(entry.getValue())); - labelToDelegate.put(entry.getKey(), delegate); - subtypeToDelegate.put(entry.getValue(), delegate); - } - - return new TypeAdapter() { - @Override public R read(JsonReader in) { - JsonElement jsonElement = Streams.parse(in); - JsonElement labelJsonElement; - if (maintainType) { - labelJsonElement = jsonElement.getAsJsonObject().get(typeFieldName); - } else { - labelJsonElement = jsonElement.getAsJsonObject().remove(typeFieldName); - } - - if (labelJsonElement == null) { - throw new JsonParseException("cannot deserialize " + baseType - + " because it does not define a field named " + typeFieldName); - } - String label = labelJsonElement.getAsString(); - @SuppressWarnings("unchecked") // registration requires that subtype extends T - TypeAdapter delegate = (TypeAdapter) labelToDelegate.get(label); - if (delegate == null) { - throw new JsonParseException("cannot deserialize " + baseType + " subtype named " - + label + "; did you forget to register a subtype?"); - } - return delegate.fromJsonTree(jsonElement); - } - - @Override public void write(JsonWriter out, R value) throws IOException { - Class srcType = value.getClass(); - String label = subtypeToLabel.get(srcType); - @SuppressWarnings("unchecked") // registration requires that subtype extends T - TypeAdapter delegate = (TypeAdapter) subtypeToDelegate.get(srcType); - if (delegate == null) { - throw new JsonParseException("cannot serialize " + srcType.getName() - + "; did you forget to register a subtype?"); - } - JsonObject jsonObject = delegate.toJsonTree(value).getAsJsonObject(); - - if (maintainType) { - Streams.write(jsonObject, out); - return; - } - - JsonObject clone = new JsonObject(); - - if (jsonObject.has(typeFieldName)) { - throw new JsonParseException("cannot serialize " + srcType.getName() - + " because it already defines a field named " + typeFieldName); - } - clone.add(typeFieldName, new JsonPrimitive(label)); - - for (Map.Entry e : jsonObject.entrySet()) { - clone.add(e.getKey(), e.getValue()); - } - Streams.write(clone, out); - } - }.nullSafe(); - } -} diff --git a/NotificationHubs/src/com/windowsazure/messaging/WindowsInstallation.java b/NotificationHubs/src/com/windowsazure/messaging/WindowsInstallation.java new file mode 100644 index 0000000..5fe17c7 --- /dev/null +++ b/NotificationHubs/src/com/windowsazure/messaging/WindowsInstallation.java @@ -0,0 +1,96 @@ +package com.windowsazure.messaging; + +import java.util.HashMap; +import java.util.Map; + +/** + * This class represents a WNS Installation. + */ +public class WindowsInstallation extends Installation { + + private Map secondaryTiles; + + /** + * Creates a new instance of the WindowsInstallation class. + * + * @param installationId The ID for the installation. + */ + public WindowsInstallation(String installationId) { + super(installationId, NotificationPlatform.Wns, null, (String[]) null); + } + + /** + * Creates a new instance of the WindowsInstallation class. + * + * @param installationId The ID for the installation. + * @param tags The tags for the installation. + */ + public WindowsInstallation(String installationId, String... tags) { + super(installationId, NotificationPlatform.Wns, null, tags); + } + + /** + * Creates a new instance of the WindowsInstallation class. + * + * @param installationId The ID for the installation. + */ + public WindowsInstallation(String installationId, String pushChannel) { + super(installationId, NotificationPlatform.Wns, pushChannel, (String[]) null); + } + + /** + * Creates a new instance of the Installation class. + * @param installationId The ID for the installation. + * @param pushChannel The device specific push channel for the installation. + * @param tags The tags for the installation. + */ + public WindowsInstallation(String installationId, String pushChannel, String... tags) { + super(installationId, NotificationPlatform.Wns, pushChannel, tags); + } + + /** + * Gets the secondary tiles for WNS + * + * @return The secondary tiles for WNS. + */ + public Map getSecondaryTiles() { + return secondaryTiles; + } + + /** + * Adds a secondary tile to the installation template. + * + * @param tileName The name for the tile. + * @param tile THe WNS secondary tile. + */ + public void addSecondaryTile(String tileName, WnsSecondaryTile tile) { + if (secondaryTiles == null) { + secondaryTiles = new HashMap<>(); + } + + secondaryTiles.put(tileName, tile); + } + + /** + * Removes the secondary WNS secondary tile by name. + * @param tileName The name of the WNS secondary tile. + */ + public void removeSecondaryTile(String tileName) { + if (secondaryTiles == null) { + return; + } + + secondaryTiles.remove(tileName); + } + + /** + * Clears the WNS secondary tiles. + */ + public void clearSecondaryTiles() { + if (secondaryTiles == null) { + return; + } + + secondaryTiles.clear(); + } +} diff --git a/NotificationHubs/test/com/windowsazure/messaging/InstallationParseTest.java b/NotificationHubs/test/com/windowsazure/messaging/InstallationParseTest.java index c9d7d7a..940639d 100644 --- a/NotificationHubs/test/com/windowsazure/messaging/InstallationParseTest.java +++ b/NotificationHubs/test/com/windowsazure/messaging/InstallationParseTest.java @@ -28,7 +28,7 @@ public void InstallationBrowser() throws IOException { "auth-value"); InputStream inputJson = this.getClass().getResourceAsStream("InstallationBrowserMinimal"); - BrowserInstallation installation = BrowserInstallation.fromJson(inputJson); + BrowserInstallation installation = BaseInstallationFactory.createInstallation(inputJson); assertNotNull(installation); assertEquals("123", installation.getInstallationId()); assertEquals(NotificationPlatform.Browser, installation.getPlatform()); @@ -45,11 +45,26 @@ public void InstallationMinimal() throws IOException { assertEquals("qwe", installation.getPushChannel()); } + @Test + public void InstallationWnsFactory() throws IOException, ParseException { + SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH); + InputStream inputJson = this.getClass().getResourceAsStream("InstallationWnsFull"); + WindowsInstallation installation = BaseInstallationFactory.createInstallation(inputJson); + assertNotNull(installation); + assertEquals("123", installation.getInstallationId()); + assertEquals(NotificationPlatform.Wns, installation.getPlatform()); + assertEquals("wns-push-channel1", installation.getPushChannel()); + assertNotNull(installation.getTemplates()); + assertEquals("", installation.getTemplates().get("template1").getBody()); + Date expiration = installation.getExpirationTime(); + assertEquals(expiration.toString(), sdf.parse("Wed Nov 26 15:34:01 PST 2014").toString()); + } + @Test public void InstallationWnsFull() throws IOException, ParseException { SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH); InputStream inputJson = this.getClass().getResourceAsStream("InstallationWnsFull"); - Installation installation = Installation.fromJson(inputJson); + WindowsInstallation installation = BaseInstallationFactory.createInstallation(inputJson); assertNotNull(installation); assertEquals("123", installation.getInstallationId()); assertEquals(NotificationPlatform.Wns, installation.getPlatform()); diff --git a/NotificationHubs/test/com/windowsazure/messaging/e2e/InstallationCrudsE2E.java b/NotificationHubs/test/com/windowsazure/messaging/e2e/InstallationCrudsE2E.java index e4a9995..bcb1965 100644 --- a/NotificationHubs/test/com/windowsazure/messaging/e2e/InstallationCrudsE2E.java +++ b/NotificationHubs/test/com/windowsazure/messaging/e2e/InstallationCrudsE2E.java @@ -38,25 +38,24 @@ public void cleanUp() throws Exception { @Test public void BasicCrudScenarioTest() throws Exception { - Installation installation = new Installation("installation-id", NotificationPlatform.Adm, "adm-push-channel"); + AdmInstallation installation = new AdmInstallation("installation-id", "adm-push-channel"); hub.createOrUpdateInstallation(installation); Thread.sleep(3000); - installation = hub.getInstallation(installation.getInstallationId()); + installation = (AdmInstallation)hub.getInstallation(installation.getInstallationId()); assertNotNull(installation); assertEquals("installation-id", installation.getInstallationId()); assertEquals(NotificationPlatform.Adm, installation.getPlatform()); assertEquals("adm-push-channel", installation.getPushChannel()); assertNull(installation.getTags()); assertNull(installation.getTemplates()); - assertNull(installation.getSecondaryTiles()); installation.addTag("foo"); installation.addTemplate("template1", new InstallationTemplate("{\"data\":{\"key1\":\"value1\"}}")); hub.createOrUpdateInstallation(installation); Thread.sleep(3000); - installation = hub.getInstallation(installation.getInstallationId()); + installation = (AdmInstallation)hub.getInstallation(installation.getInstallationId()); assertEquals("installation-id", installation.getInstallationId()); assertEquals(NotificationPlatform.Adm, installation.getPlatform()); assertEquals("adm-push-channel", installation.getPushChannel()); @@ -67,7 +66,6 @@ public void BasicCrudScenarioTest() throws Exception { assertEquals(1, installation.getTemplates().size()); assertTrue(installation.getTemplates().get("template1").getBody().equalsIgnoreCase("{\"data\":{\"key1\":\"value1\"}}")); assertNull(installation.getTemplates().get("template1").getTags()); - assertNull(installation.getSecondaryTiles()); PartialUpdateOperation addChannel = new PartialUpdateOperation(UpdateOperationType.Add, "/pushChannel", "adm-push-channel2"); PartialUpdateOperation addTag = new PartialUpdateOperation(UpdateOperationType.Add, "/tags", "bar"); @@ -75,7 +73,7 @@ public void BasicCrudScenarioTest() throws Exception { hub.patchInstallation(installation.getInstallationId(), addChannel, addTag, replaceTemplate); Thread.sleep(3000); - installation = hub.getInstallation(installation.getInstallationId()); + installation = (AdmInstallation)hub.getInstallation(installation.getInstallationId()); assertNotNull(installation); assertEquals("installation-id", installation.getInstallationId()); assertEquals(NotificationPlatform.Adm, installation.getPlatform()); @@ -88,7 +86,6 @@ public void BasicCrudScenarioTest() throws Exception { assertEquals(1, installation.getTemplates().size()); assertTrue(installation.getTemplates().get("template1").getBody().equalsIgnoreCase("{\"data\":{\"key2\":\"value2\"}}")); assertNull(installation.getTemplates().get("template1").getTags()); - assertNull(installation.getSecondaryTiles()); hub.deleteInstallation(installation.getInstallationId()); Thread.sleep(3000); From 708fd81bbd67b67612349d66cd6214fa56881e69 Mon Sep 17 00:00:00 2001 From: Matthew Podwysocki Date: Sat, 14 Aug 2021 21:21:48 -0400 Subject: [PATCH 5/7] Cleaning up based upon comments --- .../messaging/AppleNotification.java | 6 +- .../messaging/BaseInstallation.java | 56 +++++++++++-------- .../messaging/BaseInstallationFactory.java | 39 ------------- .../messaging/NotificationHub.java | 2 +- .../messaging/InstallationParseTest.java | 6 +- 5 files changed, 39 insertions(+), 70 deletions(-) delete mode 100644 NotificationHubs/src/com/windowsazure/messaging/BaseInstallationFactory.java diff --git a/NotificationHubs/src/com/windowsazure/messaging/AppleNotification.java b/NotificationHubs/src/com/windowsazure/messaging/AppleNotification.java index 2d31413..5930551 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/AppleNotification.java +++ b/NotificationHubs/src/com/windowsazure/messaging/AppleNotification.java @@ -17,7 +17,7 @@ public class AppleNotification extends Notification { * @param body The JSON body for the notification. */ public AppleNotification(String body) { - this(body, getTomorrow(), null); + this(body, getDefaultExpiration(), null); } /** @@ -26,7 +26,7 @@ public AppleNotification(String body) { * @param headers The headers for the notification. */ public AppleNotification(String body, Map headers) { - this(body, getTomorrow(), headers); + this(body, getDefaultExpiration(), headers); } /** @@ -63,7 +63,7 @@ public AppleNotification(String body, Date expiry, Map headers) } } - private static Date getTomorrow() { + private static Date getDefaultExpiration() { Date now = new Date(); return new Date(now.getTime() + 24 * 60 * 60 * 1000); } diff --git a/NotificationHubs/src/com/windowsazure/messaging/BaseInstallation.java b/NotificationHubs/src/com/windowsazure/messaging/BaseInstallation.java index 4a55456..892c1ca 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/BaseInstallation.java +++ b/NotificationHubs/src/com/windowsazure/messaging/BaseInstallation.java @@ -1,7 +1,12 @@ package com.windowsazure.messaging; +import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import org.apache.commons.io.IOUtils; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; import java.util.*; @@ -14,30 +19,6 @@ public abstract class BaseInstallation implements Cloneable { private List tags; private Map templates; - /** - * Creates a new installation. - */ - public BaseInstallation() {} - - /** - * Creates a new installation with the given installation ID. - * - * @param installationId The ID for the installation. - */ - public BaseInstallation(String installationId) { - this(installationId, (String[]) null); - } - - /** - * Creates an installation from the Installation ID and tags. - * - * @param installationId The ID for the installation. - * @param tags The tags for the installation. - */ - public BaseInstallation(String installationId, String... tags) { - this(installationId, null, tags); - } - /** * Creates an installation with an installation ID, platform and push channel. * @@ -282,4 +263,31 @@ public void clearTemplates() { public String toJson() { return new GsonBuilder().disableHtmlEscaping().create().toJson(this); } + + /** + * Creates an installation from the JSON string. + * + * @param jsonString The JSON string that represents the installation. + * @return An installation created from the JSON string. + */ + @SuppressWarnings("unchecked") + public static T fromJson(String jsonString) { + + Gson gson = new GsonBuilder() + .registerTypeAdapter(BaseInstallation.class, new BaseInstallationDeserializer()) + .create(); + + return (T)gson.fromJson(jsonString, BaseInstallation.class); + } + + /** + * Creates an installation from the JSON stream. + * + * @param json The JSON string that represents the installation. + * @return An installation created from the JSON stream. + * @throws IOException An exception reading from the stream occurred. + */ + public static T fromJson(InputStream json) throws IOException { + return fromJson(IOUtils.toString(json, StandardCharsets.UTF_8)); + } } diff --git a/NotificationHubs/src/com/windowsazure/messaging/BaseInstallationFactory.java b/NotificationHubs/src/com/windowsazure/messaging/BaseInstallationFactory.java deleted file mode 100644 index d0e593a..0000000 --- a/NotificationHubs/src/com/windowsazure/messaging/BaseInstallationFactory.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.windowsazure.messaging; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import org.apache.commons.io.IOUtils; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; - -public class BaseInstallationFactory { - - /** - * Creates an installation from the JSON string. - * - * @param jsonString The JSON string that represents the installation. - * @return An installation created from the JSON string. - */ - @SuppressWarnings("unchecked") - public static T createInstallation(String jsonString) { - - Gson gson = new GsonBuilder() - .registerTypeAdapter(BaseInstallation.class, new BaseInstallationDeserializer()) - .create(); - - return (T)gson.fromJson(jsonString, BaseInstallation.class); - } - - /** - * Creates an installation from the JSON stream. - * - * @param json The JSON string that represents the installation. - * @return An installation created from the JSON stream. - * @throws IOException An exception reading from the stream occurred. - */ - public static T createInstallation(InputStream json) throws IOException { - return createInstallation(IOUtils.toString(json, StandardCharsets.UTF_8)); - } -} diff --git a/NotificationHubs/src/com/windowsazure/messaging/NotificationHub.java b/NotificationHubs/src/com/windowsazure/messaging/NotificationHub.java index 1941cda..61e7f67 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/NotificationHub.java +++ b/NotificationHubs/src/com/windowsazure/messaging/NotificationHub.java @@ -1653,7 +1653,7 @@ public void completed(final HttpResponse response) { return; } - callback.completed(BaseInstallationFactory.createInstallation(response.getEntity().getContent())); + callback.completed(BaseInstallation.fromJson(response.getEntity().getContent())); } catch (Exception e) { callback.failed(e); } finally { diff --git a/NotificationHubs/test/com/windowsazure/messaging/InstallationParseTest.java b/NotificationHubs/test/com/windowsazure/messaging/InstallationParseTest.java index 940639d..19fce1b 100644 --- a/NotificationHubs/test/com/windowsazure/messaging/InstallationParseTest.java +++ b/NotificationHubs/test/com/windowsazure/messaging/InstallationParseTest.java @@ -28,7 +28,7 @@ public void InstallationBrowser() throws IOException { "auth-value"); InputStream inputJson = this.getClass().getResourceAsStream("InstallationBrowserMinimal"); - BrowserInstallation installation = BaseInstallationFactory.createInstallation(inputJson); + BrowserInstallation installation = BaseInstallation.fromJson(inputJson); assertNotNull(installation); assertEquals("123", installation.getInstallationId()); assertEquals(NotificationPlatform.Browser, installation.getPlatform()); @@ -49,7 +49,7 @@ public void InstallationMinimal() throws IOException { public void InstallationWnsFactory() throws IOException, ParseException { SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH); InputStream inputJson = this.getClass().getResourceAsStream("InstallationWnsFull"); - WindowsInstallation installation = BaseInstallationFactory.createInstallation(inputJson); + WindowsInstallation installation = BaseInstallation.fromJson(inputJson); assertNotNull(installation); assertEquals("123", installation.getInstallationId()); assertEquals(NotificationPlatform.Wns, installation.getPlatform()); @@ -64,7 +64,7 @@ public void InstallationWnsFactory() throws IOException, ParseException { public void InstallationWnsFull() throws IOException, ParseException { SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH); InputStream inputJson = this.getClass().getResourceAsStream("InstallationWnsFull"); - WindowsInstallation installation = BaseInstallationFactory.createInstallation(inputJson); + WindowsInstallation installation = BaseInstallation.fromJson(inputJson); assertNotNull(installation); assertEquals("123", installation.getInstallationId()); assertEquals(NotificationPlatform.Wns, installation.getPlatform()); From 4beb4418d31db62a6e08c80583db5c3dd319c7f9 Mon Sep 17 00:00:00 2001 From: Matthew Podwysocki Date: Sun, 15 Aug 2021 16:31:54 -0400 Subject: [PATCH 6/7] Updating typings --- .../messaging/AdmRegistration.java | 7 ++ .../messaging/AppleRegistration.java | 7 ++ .../messaging/BaiduRegistration.java | 7 ++ .../messaging/BrowserRegistration.java | 7 ++ .../messaging/FcmRegistration.java | 7 ++ .../messaging/GcmRegistration.java | 7 ++ .../messaging/MpnsRegistration.java | 7 ++ .../messaging/NotificationHub.java | 66 ++++++++++++------- .../messaging/NotificationHubClient.java | 40 ++++++----- .../windowsazure/messaging/Registration.java | 8 ++- .../messaging/WindowsRegistration.java | 7 ++ 11 files changed, 132 insertions(+), 38 deletions(-) diff --git a/NotificationHubs/src/com/windowsazure/messaging/AdmRegistration.java b/NotificationHubs/src/com/windowsazure/messaging/AdmRegistration.java index 592d599..4bb6806 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/AdmRegistration.java +++ b/NotificationHubs/src/com/windowsazure/messaging/AdmRegistration.java @@ -58,6 +58,13 @@ public void setAdmRegistrationId(String value) { admRegistrationId = value; } + /** + * Gets the PNS handle for getting devices by channel. + * @return The PNS handle for getting devices by channel. + */ + @Override + public String getPnsHandle() { return admRegistrationId; } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/NotificationHubs/src/com/windowsazure/messaging/AppleRegistration.java b/NotificationHubs/src/com/windowsazure/messaging/AppleRegistration.java index 0e4d03a..4ba4b5b 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/AppleRegistration.java +++ b/NotificationHubs/src/com/windowsazure/messaging/AppleRegistration.java @@ -56,6 +56,13 @@ public String getDeviceToken() { */ public void setDeviceToken(String value) { deviceToken = value; } + /** + * Gets the PNS handle for getting devices by channel. + * @return The PNS handle for getting devices by channel. + */ + @Override + public String getPnsHandle() { return deviceToken; } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/NotificationHubs/src/com/windowsazure/messaging/BaiduRegistration.java b/NotificationHubs/src/com/windowsazure/messaging/BaiduRegistration.java index 9f3d0a6..72d7da1 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/BaiduRegistration.java +++ b/NotificationHubs/src/com/windowsazure/messaging/BaiduRegistration.java @@ -72,6 +72,13 @@ public BaiduRegistration(String registrationId, String baiduUserId, String baidu */ public void setBaiduChannelId(String value) { baiduChannelId = value; } + /** + * Gets the PNS handle for getting devices by channel. + * @return The PNS handle for getting devices by channel. + */ + @Override + public String getPnsHandle() { return baiduUserId + "-" + baiduChannelId; } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/NotificationHubs/src/com/windowsazure/messaging/BrowserRegistration.java b/NotificationHubs/src/com/windowsazure/messaging/BrowserRegistration.java index d799af2..3b04f70 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/BrowserRegistration.java +++ b/NotificationHubs/src/com/windowsazure/messaging/BrowserRegistration.java @@ -90,6 +90,13 @@ public BrowserRegistration(String registrationId, String endpoint, String p256dh */ public void setAuth(String value) { auth = value; } + /** + * Gets the PNS handle for getting devices by channel. + * @return The PNS handle for getting devices by channel. + */ + @Override + public String getPnsHandle() { return endpoint; } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/NotificationHubs/src/com/windowsazure/messaging/FcmRegistration.java b/NotificationHubs/src/com/windowsazure/messaging/FcmRegistration.java index 61a092c..bccce5a 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/FcmRegistration.java +++ b/NotificationHubs/src/com/windowsazure/messaging/FcmRegistration.java @@ -63,6 +63,13 @@ public boolean equals(Object o) { return Objects.equals(getFcmRegistrationId(), that.getFcmRegistrationId()); } + /** + * Gets the PNS handle for getting devices by channel. + * @return The PNS handle for getting devices by channel. + */ + @Override + public String getPnsHandle() { return fcmRegistrationId; } + @Override public int hashCode() { return Objects.hash(super.hashCode(), getFcmRegistrationId()); diff --git a/NotificationHubs/src/com/windowsazure/messaging/GcmRegistration.java b/NotificationHubs/src/com/windowsazure/messaging/GcmRegistration.java index 1336807..48dda3d 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/GcmRegistration.java +++ b/NotificationHubs/src/com/windowsazure/messaging/GcmRegistration.java @@ -58,6 +58,13 @@ public GcmRegistration(String gcmRegistrationId) { */ public void setGcmRegistrationId(String value) { gcmRegistrationId = value; } + /** + * Gets the PNS handle for getting devices by channel. + * @return The PNS handle for getting devices by channel. + */ + @Override + public String getPnsHandle() { return gcmRegistrationId; } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/NotificationHubs/src/com/windowsazure/messaging/MpnsRegistration.java b/NotificationHubs/src/com/windowsazure/messaging/MpnsRegistration.java index 0fff9bc..f933080 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/MpnsRegistration.java +++ b/NotificationHubs/src/com/windowsazure/messaging/MpnsRegistration.java @@ -61,6 +61,13 @@ public void setChannelUri(String channelUri) { } } + /** + * Gets the PNS handle for getting devices by channel. + * @return The PNS handle for getting devices by channel. + */ + @Override + public String getPnsHandle() { return channelUri.toString(); } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/NotificationHubs/src/com/windowsazure/messaging/NotificationHub.java b/NotificationHubs/src/com/windowsazure/messaging/NotificationHub.java index 61e7f67..f4d7016 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/NotificationHub.java +++ b/NotificationHubs/src/com/windowsazure/messaging/NotificationHub.java @@ -83,7 +83,7 @@ public NotificationHub(String connectionString, String hubPath) { * ETag, and expiration time) */ @Override - public void createRegistrationAsync(Registration registration, final FutureCallback callback) { + public void createRegistrationAsync(T registration, final FutureCallback callback) { try { URI uri = new URI(endpoint + hubPath + "/registrations" + API_VERSION); final HttpPost post = new HttpPost(uri); @@ -138,8 +138,8 @@ public void cancelled() { * @throws NotificationHubsException Thrown if there is a client error. */ @Override - public Registration createRegistration(Registration registration) throws NotificationHubsException { - SyncCallback callback = new SyncCallback<>(); + public T createRegistration(T registration) throws NotificationHubsException { + SyncCallback callback = new SyncCallback<>(); createRegistrationAsync(registration, callback); return callback.getResult(); } @@ -225,9 +225,10 @@ public String createRegistrationId() throws NotificationHubsException { * @param callback A callback when invoked, returns the updated registration * containing the read-only parameters (registration ID, * ETag, and expiration time). + * @param The type of Registration class. */ @Override - public void updateRegistrationAsync(Registration registration, final FutureCallback callback) { + public void updateRegistrationAsync(T registration, final FutureCallback callback) { try { URI uri = new URI(endpoint + hubPath + "/registrations/" + registration.getRegistrationId() + API_VERSION); final HttpPut put = new HttpPut(uri); @@ -277,11 +278,12 @@ public void cancelled() { * populated. * @return The updated registration containing the read-only parameters * (registration ID, ETag, and expiration time). + * @param The type of Registration class. * @throws NotificationHubsException Thrown if there is a client error. */ @Override - public Registration updateRegistration(Registration registration) throws NotificationHubsException { - SyncCallback callback = new SyncCallback<>(); + public T updateRegistration(T registration) throws NotificationHubsException { + SyncCallback callback = new SyncCallback<>(); updateRegistrationAsync(registration, callback); return callback.getResult(); } @@ -296,9 +298,10 @@ public Registration updateRegistration(Registration registration) throws Notific * @param callback A callback, when invoked, returns the updated * registration containing the read-only parameters * (registration ID, ETag, and expiration time). + * @param The type of Registration class. */ @Override - public void upsertRegistrationAsync(Registration registration, final FutureCallback callback) { + public void upsertRegistrationAsync(T registration, final FutureCallback callback) { try { URI uri = new URI(endpoint + hubPath + "/registrations/" + registration.getRegistrationId() + API_VERSION); final HttpPut put = new HttpPut(uri); @@ -349,10 +352,11 @@ public void cancelled() { * @return The updated registration containing the read-only parameters * (registration ID, ETag, and expiration time). * @throws NotificationHubsException Thrown if there is a client error. + * @param The type of Registration class. */ @Override - public Registration upsertRegistration(Registration registration) throws NotificationHubsException { - SyncCallback callback = new SyncCallback<>(); + public T upsertRegistration(T registration) throws NotificationHubsException { + SyncCallback callback = new SyncCallback<>(); upsertRegistrationAsync(registration, callback); return callback.getResult(); } @@ -452,9 +456,10 @@ public void deleteRegistration(String registrationId) throws NotificationHubsExc * @param registrationId The ID for the registration to retrieve. * @param callback A callback, when invoked, returns the registration with * the ID matching the given registration ID. + * @param The type of Registration class. */ @Override - public void getRegistrationAsync(String registrationId, final FutureCallback callback) { + public void getRegistrationAsync(String registrationId, final FutureCallback callback) { try { URI uri = new URI(endpoint + hubPath + "/registrations/" + registrationId + API_VERSION); final HttpGet get = new HttpGet(uri); @@ -500,10 +505,11 @@ public void cancelled() { * @param registrationId The ID for the registration to retrieve. * @return The registration with the ID matching the given registration ID. * @throws NotificationHubsException Thrown if there is a client error. + * @param The type of Registration class. */ @Override - public Registration getRegistration(String registrationId) throws NotificationHubsException { - SyncCallback callback = new SyncCallback<>(); + public T getRegistration(String registrationId) throws NotificationHubsException { + SyncCallback callback = new SyncCallback<>(); getRegistrationAsync(registrationId, callback); return callback.getResult(); } @@ -851,7 +857,7 @@ public NotificationOutcome sendNotification(Notification notification, String ta } /** - * Schedules a notification at the given scheduled time. + * Schedules a notification at the given scheduled time. Note that this is not available on the free SKU. * * @param notification The notification to send at the scheduled time. * @param scheduledTime The scheduled time for the notification. @@ -864,7 +870,7 @@ public void scheduleNotificationAsync(Notification notification, Date scheduledT } /** - * Schedules a notification at the given scheduled time. + * Schedules a notification at the given scheduled time. Note that this is not available on the free SKU. * * @param notification The notification to send at the scheduled time. * @param scheduledTime The scheduled time for the notification. @@ -879,7 +885,7 @@ public NotificationOutcome scheduleNotification(Notification notification, Date } /** - * Schedules a notification at the given time with a set of tags. + * Schedules a notification at the given time with a set of tags. Note that this is not available on the free SKU. * * @param notification The notification to send at the given time. * @param tags The tags associated with the notification targeting. @@ -904,7 +910,7 @@ public void scheduleNotificationAsync(Notification notification, Set tag } /** - * Schedules a notification at the given time with a set of tags. + * Schedules a notification at the given time with a set of tags. Note that this is not available on the free SKU. * * @param notification The notification to send at the given time. * @param tags The tags associated with the notification targeting. @@ -920,7 +926,7 @@ public NotificationOutcome scheduleNotification(Notification notification, Set callback) { try { @@ -1634,6 +1654,7 @@ public void deleteInstallation(String installationId) throws NotificationHubsExc * @param installationId The installation ID for the installation to get. * @param callback A callback, when invoked, returns the matching * installation by the installation ID. + * @param The type of Installation class. */ @Override public void getInstallationAsync(String installationId, final FutureCallback callback) { @@ -1682,6 +1703,7 @@ public void cancelled() { * @param installationId The installation ID for the installation to get. * @return The matching installation by the installation ID. * @throws NotificationHubsException Thrown if there is a client error. + * @param The type of Installation class. */ @Override public T getInstallation(String installationId) throws NotificationHubsException { @@ -1691,7 +1713,7 @@ public T getInstallation(String installationId) thr } /** - * Submits a notification hub job such as import or export. + * Submits a notification hub job such as import or export. Note this is not available on the free or basic SKU. * * @param job The notification hubs job to submit. * @param callback A callback, when invoked, returns the notification job with @@ -1743,7 +1765,7 @@ public void cancelled() { } /** - * Submits a notification hub job such as import or export. + * Submits a notification hub job such as import or export. Note this is not available on the free or basic SKU. * * @param job The notification hubs job to submit. * @return The notification job with status. diff --git a/NotificationHubs/src/com/windowsazure/messaging/NotificationHubClient.java b/NotificationHubs/src/com/windowsazure/messaging/NotificationHubClient.java index aff993e..87d47da 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/NotificationHubClient.java +++ b/NotificationHubs/src/com/windowsazure/messaging/NotificationHubClient.java @@ -178,7 +178,7 @@ void patchInstallationAsync( * @param callback A callback, when invoked, returns the notification * telemetry for the given notification. */ - void getNotificationTelemetryAsync(String notificationId, FutureCallback callback); + void getNotificationTelemetryAsync(String notificationId, final FutureCallback callback); /** * Create a registrationId, without creating an actual registration. To create @@ -197,7 +197,7 @@ void patchInstallationAsync( * * @param callback A callback with the newly created registration ID. */ - void createRegistrationIdAsync(FutureCallback callback); + void createRegistrationIdAsync(final FutureCallback callback); /** * This method creates a new registration @@ -209,7 +209,7 @@ void patchInstallationAsync( * (registration ID, ETag, and expiration time). * @throws NotificationHubsException Thrown if there is a client error. */ - Registration createRegistration(Registration registration) throws NotificationHubsException; + T createRegistration(T registration) throws NotificationHubsException; /** * This method creates a new registration @@ -221,7 +221,7 @@ void patchInstallationAsync( * containing the read-only parameters (registration ID, * ETag, and expiration time) */ - void createRegistrationAsync(Registration registration, FutureCallback callback); + void createRegistrationAsync(T registration, final FutureCallback callback); /** * This method updates an existing registration @@ -233,7 +233,7 @@ void patchInstallationAsync( * (registration ID, ETag, and expiration time). * @throws NotificationHubsException Thrown if there is a client error. */ - Registration updateRegistration(Registration registration) throws NotificationHubsException; + T updateRegistration(T registration) throws NotificationHubsException; /** * This method updates an existing registration @@ -245,7 +245,7 @@ void patchInstallationAsync( * containing the read-only parameters (registration ID, * ETag, and expiration time). */ - void updateRegistrationAsync(Registration registration, FutureCallback callback); + void updateRegistrationAsync(T registration, final FutureCallback callback); /** * This method updates or creates a new registration with the registration ID @@ -258,7 +258,7 @@ void patchInstallationAsync( * (registration ID, ETag, and expiration time). * @throws NotificationHubsException Thrown if there is a client error. */ - Registration upsertRegistration(Registration registration) throws NotificationHubsException; + T upsertRegistration(T registration) throws NotificationHubsException; /** * This method updates or creates a new registration with the registration id @@ -271,7 +271,7 @@ void patchInstallationAsync( * registration containing the read-only parameters * (registration ID, ETag, and expiration time). */ - void upsertRegistrationAsync(Registration registration, FutureCallback callback); + void upsertRegistrationAsync(T registration, final FutureCallback callback); /** * Deletes a registration with the given registration containing a populated @@ -315,8 +315,9 @@ void patchInstallationAsync( * @param registrationId The ID for the registration to retrieve. * @return The registration with the ID matching the given registration ID. * @throws NotificationHubsException Thrown if there is a client error. + * @param The type of Registration class. */ - Registration getRegistration(String registrationId) throws NotificationHubsException; + T getRegistration(String registrationId) throws NotificationHubsException; /** * Retrieves the description of a registration based on the ID. @@ -324,8 +325,9 @@ void patchInstallationAsync( * @param registrationId The ID for the registration to retrieve. * @param callback A callback, when invoked, returns the registration with * the ID matching the given registration ID. + * @param The type of Registration class. */ - void getRegistrationAsync(String registrationId, FutureCallback callback); + void getRegistrationAsync(String registrationId, FutureCallback callback); /** * Return all registrations in the current notification hub. @@ -495,6 +497,7 @@ void getRegistrationsByChannelAsync(String channel, int top, String continuation * @return A notification outcome with the tracking ID and notification ID. * @throws NotificationHubsException Thrown if there is a client error. */ + @SuppressWarnings("UnusedReturnValue") NotificationOutcome sendNotification(Notification notification, Set tags) throws NotificationHubsException; /** @@ -520,6 +523,7 @@ void sendNotificationAsync(Notification notification, Set tags, * @return A notification outcome with the tracking ID and notification ID. * @throws NotificationHubsException Thrown if there is a client error. */ + @SuppressWarnings("UnusedReturnValue") NotificationOutcome sendNotification(Notification notification, String tagExpression) throws NotificationHubsException; @@ -569,11 +573,12 @@ void scheduleNotificationAsync( * @return A notification outcome with the tracking ID and notification ID. * @throws NotificationHubsException Thrown if there is a client error. */ + @SuppressWarnings("UnusedReturnValue") NotificationOutcome scheduleNotification(Notification notification, Set tags, Date scheduledTime) throws NotificationHubsException; /** - * Schedules a notification at the given time with a set of tags. + * Schedules a notification at the given time with a set of tags. Note that this is not available on the free SKU. * * @param notification The notification to send at the given time. * @param tags The tags associated with the notification targeting. @@ -581,11 +586,15 @@ NotificationOutcome scheduleNotification(Notification notification, Set * @param callback A callback, when invoked, returns a notification outcome * with the tracking ID and notification ID. */ - void scheduleNotificationAsync(Notification notification, Set tags, Date scheduledTime, - FutureCallback callback); + void scheduleNotificationAsync( + Notification notification, + Set tags, + Date scheduledTime, + final FutureCallback callback + ); /** - * Schedules a notification at the given time with a tag expression. + * Schedules a notification at the given time with a tag expression. Note that this is not available on the free SKU. * * @param notification The notification to send at the given time. * @param tagExpression The tag expression associated with the notification @@ -594,11 +603,12 @@ void scheduleNotificationAsync(Notification notification, Set tags, Date * @return A notification outcome with the tracking ID and notification ID. * @throws NotificationHubsException Thrown if there is a client error. */ + @SuppressWarnings("UnusedReturnValue") NotificationOutcome scheduleNotification(Notification notification, String tagExpression, Date scheduledTime) throws NotificationHubsException; /** - * Schedules a notification at the given time with a tag expression. + * Schedules a notification at the given time with a tag expression. Note that this is not available on the free SKU. * * @param notification The notification to send at the given time. * @param tagExpression The tag expression associated with the notification diff --git a/NotificationHubs/src/com/windowsazure/messaging/Registration.java b/NotificationHubs/src/com/windowsazure/messaging/Registration.java index f922979..d7a2d38 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/Registration.java +++ b/NotificationHubs/src/com/windowsazure/messaging/Registration.java @@ -144,6 +144,12 @@ public void setExpirationTimeFromString(String expirationTimeString) { this.expirationTime = javax.xml.bind.DatatypeConverter.parseDateTime(expirationTimeString).getTime(); } + /** + * Gets the PNS handle for getting devices by channel. + * @return The PNS handle for getting devices by channel. + */ + public abstract String getPnsHandle(); + /** * Gets an XML representation of the current object. * @return The XML representation of the current object. @@ -177,7 +183,7 @@ public int hashCode() { return Objects.hash(getRegistrationId(), getTags(), getEtag(), getExpirationTime()); } - public static Registration parse(InputStream content) throws IOException, + public static T parse(InputStream content) throws IOException, SAXException { return singleRegParser.get().parse(content); } diff --git a/NotificationHubs/src/com/windowsazure/messaging/WindowsRegistration.java b/NotificationHubs/src/com/windowsazure/messaging/WindowsRegistration.java index f8b0e43..4ca4113 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/WindowsRegistration.java +++ b/NotificationHubs/src/com/windowsazure/messaging/WindowsRegistration.java @@ -62,6 +62,13 @@ public void setChannelUri(String channelUri) { } } + /** + * Gets the PNS handle for getting devices by channel. + * @return The PNS handle for getting devices by channel. + */ + @Override + public String getPnsHandle() { return channelUri.toString(); } + @Override public boolean equals(Object o) { if (this == o) return true; From f11a8610b76be9ed3a80d003c8e60a4b19bd3403 Mon Sep 17 00:00:00 2001 From: Matthew Podwysocki Date: Mon, 16 Aug 2021 12:08:16 -0400 Subject: [PATCH 7/7] Fixing telemetry --- .../messaging/NotificationTelemetry.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/NotificationHubs/src/com/windowsazure/messaging/NotificationTelemetry.java b/NotificationHubs/src/com/windowsazure/messaging/NotificationTelemetry.java index b52a647..189665f 100644 --- a/NotificationHubs/src/com/windowsazure/messaging/NotificationTelemetry.java +++ b/NotificationHubs/src/com/windowsazure/messaging/NotificationTelemetry.java @@ -13,6 +13,9 @@ import org.apache.commons.digester3.Digester; import org.xml.sax.SAXException; +/** + * This class represents notification telemetry counts. + */ public class NotificationTelemetry { private String notificationId; @@ -47,6 +50,10 @@ public static NotificationTelemetry parseOne(InputStream content) throws IOExcep return parser.get().parse(content); } + /** + * Gets the notification ID. + * @return The notification ID. + */ public String getNotificationId() { return notificationId; } @@ -183,6 +190,14 @@ public void setAdmOutcomeCounts(Map admOutcomeCounts) { this.admOutcomeCounts = admOutcomeCounts; } + public Map getBrowserOutcomeCounts() { + return browserOutcomeCounts; + } + + public void setBrowserOutcomeCounts(Map browserOutcomeCounts) { + this.browserOutcomeCounts = browserOutcomeCounts; + } + public String getPnsErrorDetailsUri() { return pnsErrorDetailsUri; }