├── .gitattributes ├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md └── SUPPORT.md ├── .gitignore ├── LICENSE ├── README.md ├── SECURITY.md ├── THIRD PARTY NOTICES ├── azure-servicebus ├── azure-servicebus.pom ├── pom.xml ├── resources │ └── client.properties └── src │ ├── main │ └── java │ │ └── com │ │ └── microsoft │ │ └── azure │ │ └── servicebus │ │ ├── BrowsableMessageSession.java │ │ ├── ClientFactory.java │ │ ├── ClientSettings.java │ │ ├── ExceptionPhase.java │ │ ├── ICloseable.java │ │ ├── IMessage.java │ │ ├── IMessageAndSessionPump.java │ │ ├── IMessageBrowser.java │ │ ├── IMessageEntityClient.java │ │ ├── IMessageHandler.java │ │ ├── IMessageReceiver.java │ │ ├── IMessageSender.java │ │ ├── IMessageSession.java │ │ ├── IMessageSessionEntity.java │ │ ├── IQueueClient.java │ │ ├── ISessionHandler.java │ │ ├── ISubscriptionClient.java │ │ ├── ITopicClient.java │ │ ├── InitializableEntity.java │ │ ├── Message.java │ │ ├── MessageAndSessionPump.java │ │ ├── MessageBody.java │ │ ├── MessageBodyType.java │ │ ├── MessageBrowser.java │ │ ├── MessageConverter.java │ │ ├── MessageHandlerOptions.java │ │ ├── MessageReceiver.java │ │ ├── MessageSender.java │ │ ├── MessageSession.java │ │ ├── QueueClient.java │ │ ├── ReceiveMode.java │ │ ├── SessionBrowser.java │ │ ├── SessionHandlerOptions.java │ │ ├── SubscriptionClient.java │ │ ├── TopicClient.java │ │ ├── Utils.java │ │ ├── amqp │ │ ├── AmqpConstants.java │ │ ├── AmqpErrorCode.java │ │ ├── AmqpException.java │ │ ├── BaseLinkHandler.java │ │ ├── ConnectionHandler.java │ │ ├── CustomIOHandler.java │ │ ├── DispatchHandler.java │ │ ├── IAmqpConnection.java │ │ ├── IAmqpLink.java │ │ ├── IAmqpReceiver.java │ │ ├── IAmqpSender.java │ │ ├── LoggingHandler.java │ │ ├── ProtonUtil.java │ │ ├── ReactorDispatcher.java │ │ ├── ReactorHandler.java │ │ ├── ReceiveLinkHandler.java │ │ ├── SendLinkHandler.java │ │ ├── SessionHandler.java │ │ ├── StrictTLSContext.java │ │ └── StrictTLSContextSpi.java │ │ ├── primitives │ │ ├── AsyncUtil.java │ │ ├── AuthorizationFailedException.java │ │ ├── ClientConstants.java │ │ ├── ClientEntity.java │ │ ├── CommonRequestResponseOperations.java │ │ ├── CommunicationException.java │ │ ├── ConnectionStringBuilder.java │ │ ├── CoreMessageReceiver.java │ │ ├── CoreMessageSender.java │ │ ├── ErrorContext.java │ │ ├── ExceptionUtil.java │ │ ├── IErrorContextProvider.java │ │ ├── IllegalConnectionStringFormatException.java │ │ ├── IteratorUtil.java │ │ ├── MessageLockLostException.java │ │ ├── MessageNotFoundException.java │ │ ├── MessageWithDeliveryTag.java │ │ ├── MessageWithLockToken.java │ │ ├── MessagingEntityAlreadyExistsException.java │ │ ├── MessagingEntityDisabledException.java │ │ ├── MessagingEntityNotFoundException.java │ │ ├── MessagingEntityType.java │ │ ├── MessagingFactory.java │ │ ├── MiscRequestResponseOperationHandler.java │ │ ├── OperationCancelledException.java │ │ ├── Pair.java │ │ ├── PayloadSizeExceededException.java │ │ ├── QuotaExceededException.java │ │ ├── ReceiveWorkItem.java │ │ ├── ReceiverDisconnectedException.java │ │ ├── ReceiverErrorContext.java │ │ ├── RequestResponseLink.java │ │ ├── RequestResponseLinkCache.java │ │ ├── RequestResponseUtils.java │ │ ├── RequestResponseWorkItem.java │ │ ├── RetryExponential.java │ │ ├── RetryPolicy.java │ │ ├── SASUtil.java │ │ ├── SendWorkItem.java │ │ ├── SenderErrorContext.java │ │ ├── ServerBusyException.java │ │ ├── ServiceBusException.java │ │ ├── SessionCannotBeLockedException.java │ │ ├── SessionLockLostException.java │ │ ├── SettleModePair.java │ │ ├── StringUtil.java │ │ ├── TimeoutException.java │ │ ├── TimeoutTracker.java │ │ ├── Timer.java │ │ ├── TimerType.java │ │ ├── TrackingUtil.java │ │ ├── UpdateStateWorkItem.java │ │ ├── Util.java │ │ └── WorkItem.java │ │ ├── rules │ │ ├── CorrelationFilter.java │ │ ├── FalseFilter.java │ │ ├── Filter.java │ │ ├── RuleAction.java │ │ ├── RuleDescription.java │ │ ├── SqlFilter.java │ │ ├── SqlRuleAction.java │ │ └── TrueFilter.java │ │ └── security │ │ ├── AzureActiveDirectoryTokenProvider.java │ │ ├── ManagedServiceIdentityTokenProvider.java │ │ ├── SecurityConstants.java │ │ ├── SecurityToken.java │ │ ├── SecurityTokenType.java │ │ ├── SharedAccessSignatureTokenProvider.java │ │ └── TokenProvider.java │ └── test │ ├── HowToRunTests.txt │ └── java │ └── com │ └── microsoft │ └── azure │ └── servicebus │ ├── ClientSessionTests.java │ ├── ClientTests.java │ ├── ClientValidationTests.java │ ├── MaxConcurrencyCounter.java │ ├── MessageAndSessionPumpTests.java │ ├── MessageBodyTests.java │ ├── PartitionedQueueClientSessionTests.java │ ├── PartitionedQueueClientTests.java │ ├── PartitionedQueueSendReceiveTests.java │ ├── PartitionedQueueSessionTests.java │ ├── PartitionedSubscriptionClientSessionTests.java │ ├── PartitionedSubscriptionClientTests.java │ ├── PartitionedTopicSendReceiveTests.java │ ├── PartitionedTopicSessionTests.java │ ├── QueueClientSessionTests.java │ ├── QueueClientTests.java │ ├── QueueSendReceiveTests.java │ ├── QueueSessionTests.java │ ├── SendReceiveTests.java │ ├── SessionTests.java │ ├── SubscriptionClientSessionTests.java │ ├── SubscriptionClientTests.java │ ├── TestCommons.java │ ├── TestMessageHandler.java │ ├── TestSessionHandler.java │ ├── TestUtils.java │ ├── Tests.java │ ├── TopicSendReceiveTests.java │ ├── TopicSessionTests.java │ ├── management │ ├── EntityManager.java │ ├── ManagementException.java │ ├── QueueDescription.java │ ├── ResourceDescripton.java │ ├── SerializerUtil.java │ ├── SubscriptionDescription.java │ └── TopicDescription.java │ └── primitives │ ├── ConnectionStringBuilderTests.java │ └── UtilsTests.java ├── build └── azuredeploy.json ├── contribute.md ├── pom.xml └── service-bus.png /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.java diff=java 14 | 15 | ############################################################################### 16 | # behavior for image files 17 | # 18 | # image files are treated as binary by default. 19 | ############################################################################### 20 | #*.jpg binary 21 | #*.png binary 22 | #*.gif binary 23 | 24 | ############################################################################### 25 | # diff behavior for common document formats 26 | # 27 | # Convert binary document formats to text before diffing them. This feature 28 | # is only available from the command line. Turn it on by uncommenting the 29 | # entries below. 30 | ############################################################################### 31 | #*.doc diff=astextplain 32 | #*.DOC diff=astextplain 33 | #*.docx diff=astextplain 34 | #*.DOCX diff=astextplain 35 | #*.dot diff=astextplain 36 | #*.DOT diff=astextplain 37 | #*.pdf diff=astextplain 38 | #*.PDF diff=astextplain 39 | #*.rtf diff=astextplain 40 | #*.RTF diff=astextplain 41 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribute or Provide Feedback for Azure Service Bus 2 | 3 | ## Table of Contents 4 | 5 | - [Code of Conduct](#code-of-conduct) 6 | - [Filing Issues](#filing-issues) 7 | - [Pull Requests](#pull-requests) 8 | - [General guidelines](#general-guidelines) 9 | - [Testing guidelines](#testing-guidelines) 10 | 11 | ## Code of Conduct 12 | 13 | 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. 14 | 15 | ## Filing Issues 16 | 17 | You can find all of the issues that have been filed in the [Issues](https://github.com/Azure/azure-service-bus-java/issues) section of the repository. 18 | 19 | If you encounter any bugs, please file an issue [here](https://github.com/Azure/azure-service-bus-java/issues/new) and make sure to fill out the provided template with the requested information. 20 | 21 | To suggest a new feature or changes that could be made, file an issue the same way you would for a bug, but remove the provided template and replace it with information about your suggestion. 22 | 23 | ### Pull Requests 24 | 25 | If you are thinking about making a large change to this library, **break up the change into small, logical, testable chunks, and organize your pull requests accordingly**. 26 | 27 | You can find all of the pull requests that have been opened in the [Pull Request](https://github.com/Azure/azure-service-bus-java/pulls) section of the repository. 28 | 29 | To open your own pull request, click [here](https://github.com/Azure/azure-service-bus-java/compare). When creating a pull request, keep the following in mind: 30 | - Make sure you are pointing to the fork and branch that your changes were made in 31 | - The pull request template that is provided **should be filled out**; this is not something that should just be deleted or ignored when the pull request is created 32 | - Deleting or ignoring this template will elongate the time it takes for your pull request to be reviewed 33 | 34 | #### General guidelines 35 | 36 | The following guidelines must be followed in **EVERY** pull request that is opened. 37 | 38 | - Title of the pull request is clear and informative 39 | - There are a small number of commits that each have an informative message 40 | - A description of the changes the pull request makes is included, and a reference to the bug/issue the pull request fixes is included, if applicable 41 | - All files have the Microsoft copyright header 42 | 43 | #### Testing guidelines 44 | 45 | The following guidelines must be followed in **EVERY** pull request that is opened. 46 | 47 | - Pull request includes test coverage for the included changes 48 | - Tests must use xunit 49 | - Test code should not contain hard coded values for resource names or similar values 50 | - Test should not use App.config files for settings 51 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Actual Behavior 2 | 1. 3 | 2. 4 | 5 | ## Expected Behavior 6 | 1. 7 | 2. 8 | 9 | ## Versions 10 | - OS platform and version: 11 | - Maven package version or commit ID: -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 7 | 8 | This checklist is used to make sure that common guidelines for a pull request are followed. 9 | 10 | - [ ] **I have read the [contribution guidelines](./CONTRIBUTING.md).** 11 | - [ ] Title of the pull request is clear and informative. 12 | - [ ] There are a small number of commits, each of which have an informative message. This means that previously merged commits do not appear in the history of the PR. 13 | - [ ] The pull request does not introduce breaking changes (unless a major version change occurs in the assembly and module). 14 | - [ ] If applicable, the public code is properly documented. 15 | - [ ] Pull request includes test coverage for the included changes. 16 | - [ ] The code builds without any errors. -------------------------------------------------------------------------------- /.github/SUPPORT.md: -------------------------------------------------------------------------------- 1 | ## Support resources to check prior to raising issues 2 | 3 | 1. Azure Service Bus [samples](https://github.com/Azure/azure-service-bus/tree/master/samples) 4 | 1. Already [resolved issues](https://github.com/Azure/azure-service-bus-java/issues?q=is%3Aissue+is%3Aclosed) 5 | 1. [StackOverflow](https://stackoverflow.com/questions/tagged/azureservicebus) -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | #External libs 4 | extlib/ 5 | 6 | # Auth files 7 | *.auth 8 | *.azureauth 9 | 10 | # Local checkstyle 11 | *.checkstyle 12 | 13 | # Mobile Tools for Java (J2ME) 14 | .mtj.tmp/ 15 | 16 | # Package Files # 17 | *.jar 18 | *.war 19 | *.ear 20 | 21 | # Azure Tooling # 22 | node_modules 23 | packages 24 | 25 | # Eclipse # 26 | *.pydevproject 27 | .project 28 | .metadata 29 | bin/** 30 | tmp/** 31 | tmp/**/* 32 | *.tmp 33 | *.bak 34 | *.swp 35 | *~.nib 36 | local.properties 37 | .classpath 38 | .settings/ 39 | .loadpath 40 | 41 | # Other Tooling # 42 | .classpath 43 | .project 44 | target 45 | .idea 46 | *.iml 47 | 48 | # Mac OS # 49 | .DS_Store 50 | .DS_Store? 51 | 52 | # Windows # 53 | Thumbs.db -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright © Microsoft Corporation 2016 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Microsoft Azure Service Bus 3 |

4 | 5 | |Build/Package|Status| 6 | |------|-------------| 7 | |master|[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.microsoft.azure/azure-servicebus/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.microsoft.azure/azure-servicebus)| 8 | 9 | # Moved 10 | All new work on SDK is happening in the repository https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/servicebus. This repository is only to address any issues found in versions 1.2.x. And master1.0 is the branch corresponding to versions 1.2.x. Both dev and master branches moved to the new repository. 11 | 12 | # Microsoft Azure Service Bus Client for Java 13 | 14 | This is the next generation Service Bus Java client library that focuses on Queues & Topics. If you are looking for Event Hubs, follow this [link](https://github.com/azure/azure-event-hubs-java). 15 | 16 | Azure Service Bus is an asynchronous messaging cloud platform that enables you to send messages between decoupled systems. Microsoft offers this feature as a service, which means that you do not need to host any of your own hardware in order to use it. 17 | 18 | Refer to [azure.com](https://azure.microsoft.com/services/service-bus/) to learn more about Service Bus. And package can be downloaded from [Maven](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.microsoft.azure%22%20AND%20a%3A%22azure-servicebus%22) 19 | 20 | ## How to provide feedback 21 | 22 | See our [Contribution Guidelines](./.github/CONTRIBUTING.md). 23 | 24 | ## Known issues 25 | 26 | ## FAQ 27 | ### Where is the API document? 28 | Click [here](https://docs.microsoft.com/en-us/java/api/overview/azure/servicebus/clientlibrary). 29 | 30 | ### Where can I find examples that use this library? 31 | 32 | The samples are located in this repo. [Java Samples](https://github.com/Azure/azure-service-bus/tree/master/samples/Java). 33 | 34 | ### Can I manage Service Bus entities with this library? 35 | 36 | Only rules management of subscription will be supported in this client library. This library focuses on Azure Service Bus Data Plane functionalities (e.g. send, receive). 37 | 38 | The standard way to manage Azure resources is by using [Azure Resource Manager](https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-overview). In order to use functionality that previously existed in the azure-servicebus Java library, this is [Azure Service Bus Management Library](https://mvnrepository.com/artifact/com.microsoft.azure/azure-mgmt-servicebus) which is available on Maven. And this is the [API document](https://docs.microsoft.com/en-us/java/api/com.microsoft.azure.management.servicebus). This management library will enable use cases that dynamically create/read/update/delete resources. 39 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | 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. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /azure-servicebus/azure-servicebus.pom: -------------------------------------------------------------------------------- 1 | 2 | azure-servicebus 3 | Java library for Azure Service Bus 4 | 4.0.0 5 | com.microsoft.azure 6 | azure-servicebus 7 | 1.2.18 8 | 9 | 10 | The MIT License (MIT) 11 | http://opensource.org/licenses/MIT 12 | repo 13 | 14 | 15 | https://github.com/Azure/azure-service-bus-java 16 | 17 | scm:git:https://github.com/Azure/azure-service-bus-java 18 | scm:git:git@github.com:Azure/azure-service-bus-java.git 19 | HEAD 20 | 21 | 22 | 23 | microsoft 24 | Microsoft 25 | 26 | 27 | 28 | 29 | 30 | 31 | org.apache.maven.plugins 32 | maven-compiler-plugin 33 | 3.5 34 | 35 | 1.8 36 | 1.8 37 | true 38 | true 39 | true 40 | 41 | 42 | 43 | org.apache.maven.plugins 44 | maven-surefire-plugin 45 | 2.20 46 | 47 | 48 | 49 | 50 | 51 | 52 | org.apache.qpid 53 | proton-j 54 | 0.31.0 55 | 56 | 57 | junit 58 | junit 59 | 4.12 60 | test 61 | 62 | 63 | org.slf4j 64 | slf4j-api 65 | 1.7.0 66 | 67 | 68 | com.microsoft.azure 69 | adal4j 70 | 1.3.0 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /azure-servicebus/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | azure-servicebus 3 | Java library for Azure Service Bus 4 | 4.0.0 5 | azure-servicebus 6 | ${client-current-version} 7 | https://github.com/Azure/azure-service-bus-java 8 | 9 | 10 | com.microsoft.azure 11 | azure-servicebus-parent 12 | 1.0.0 13 | 14 | 15 | 16 | UTF-8 17 | UTF-8 18 | 19 | 20 | 21 | 22 | 23 | resources 24 | true 25 | 26 | 27 | 28 | 29 | org.apache.maven.plugins 30 | maven-compiler-plugin 31 | 3.5 32 | 33 | 1.8 34 | 1.8 35 | true 36 | true 37 | true 38 | 39 | 40 | 41 | org.apache.maven.plugins 42 | maven-surefire-plugin 43 | 2.20 44 | 45 | 0 46 | true 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | org.apache.qpid 55 | proton-j 56 | ${proton-j-version} 57 | 58 | 59 | com.microsoft.azure 60 | adal4j 61 | 1.3.0 62 | 63 | 64 | junit 65 | junit 66 | ${junit-version} 67 | test 68 | 69 | 70 | org.slf4j 71 | slf4j-api 72 | ${slf4j-version} 73 | 74 | 79 | 80 | org.slf4j 81 | slf4j-log4j12 82 | ${slf4j-version} 83 | 84 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /azure-servicebus/resources/client.properties: -------------------------------------------------------------------------------- 1 | client.version = ${project.version} -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/ClientSettings.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus; 2 | 3 | import java.time.Duration; 4 | 5 | import com.microsoft.azure.servicebus.primitives.ClientConstants; 6 | import com.microsoft.azure.servicebus.primitives.RetryPolicy; 7 | import com.microsoft.azure.servicebus.security.TokenProvider; 8 | 9 | /** 10 | * Class encapsulating common client level settings like TokenProvider, RetryPolicy, OperationTimeout. 11 | * @since 1.2.0 12 | * 13 | */ 14 | public class ClientSettings { 15 | 16 | private TokenProvider tokenProvider; 17 | private RetryPolicy retryPolicy; 18 | private Duration operationTimeout; 19 | 20 | /** 21 | * Creates a new instance with the given token provider, default retry policy and default operation timeout. 22 | * @param tokenProvider {@link TokenProvider} instance 23 | * 24 | * @see RetryPolicy#getDefault() 25 | */ 26 | public ClientSettings(TokenProvider tokenProvider) 27 | { 28 | this(tokenProvider, RetryPolicy.getDefault(), Duration.ofSeconds(ClientConstants.DEFAULT_OPERATION_TIMEOUT_IN_SECONDS)); 29 | } 30 | 31 | /** 32 | * Creates a new instance with the given token provider, retry policy and operation timeout. 33 | * @param tokenProvider {@link TokenProvider} instance 34 | * @param retryPolicy {@link RetryPolicy} instance 35 | * @param operationTimeout default operation timeout to be used for all client operations. Client can override this value by explicitly specifying a timeout in the operation. 36 | */ 37 | public ClientSettings(TokenProvider tokenProvider, RetryPolicy retryPolicy, Duration operationTimeout) 38 | { 39 | this.tokenProvider = tokenProvider; 40 | this.retryPolicy = retryPolicy; 41 | this.operationTimeout = operationTimeout; 42 | } 43 | 44 | /** 45 | * Gets the token provider contained in this instance. 46 | * @return TokenProvider contained in this instance 47 | */ 48 | public TokenProvider getTokenProvider() 49 | { 50 | return tokenProvider; 51 | } 52 | 53 | /** 54 | * Gets the retry policy contained in this instance. 55 | * @return RetryPolicy contained in this instance 56 | */ 57 | public RetryPolicy getRetryPolicy() 58 | { 59 | return retryPolicy; 60 | } 61 | 62 | /** 63 | * Gets the operation timeout contained in this instance. 64 | * @return operation timeout contained in this instance 65 | */ 66 | public Duration getOperationTimeout() 67 | { 68 | return operationTimeout; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/ExceptionPhase.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | package com.microsoft.azure.servicebus; 5 | 6 | /** 7 | * Enumeration to represent the phase in a message pump or session pump at which an exception occurred. 8 | * 9 | * @since 1.0 10 | */ 11 | public enum ExceptionPhase { 12 | /** 13 | * Receiving messages from Azure Service Bus threw an exception. 14 | */ 15 | RECEIVE, 16 | /** 17 | * Renewing the lock of a message threw an exception. 18 | */ 19 | RENEWMESSAGELOCK, 20 | /** 21 | * Completing a message threw an exception 22 | */ 23 | COMPLETE, 24 | /** 25 | * Abandoning a message threw an exception 26 | */ 27 | ABANDON, 28 | /** 29 | * Application code in message handler or session handler threw an exception. Applications should ideally not throw exceptions from message handler or session handler. 30 | */ 31 | USERCALLBACK, 32 | /** 33 | * Closing a session threw an exception. 34 | */ 35 | SESSIONCLOSE, 36 | /** 37 | * Accepting a session threw an exception. 38 | */ 39 | ACCEPTSESSION, 40 | /** 41 | * Renewing the lock of a session threw an exception. 42 | */ 43 | RENEWSESSIONLOCK 44 | } 45 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/ICloseable.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | package com.microsoft.azure.servicebus; 5 | 6 | import java.util.concurrent.CompletableFuture; 7 | 8 | import com.microsoft.azure.servicebus.primitives.ServiceBusException; 9 | 10 | /** 11 | * Defines a standard way of properly closing and disposing objects. 12 | * @since 1.0 13 | * 14 | */ 15 | public interface ICloseable { 16 | /** 17 | * Closes and disposes any resources associated with this object. An object cannot be used after it is closed. This is an asynchronous method that returns a CompletableFuture immediately. 18 | * This object is completely closed when the returned CompletableFuture is completed. 19 | * @return a CompletableFuture representing the closing of this object. 20 | */ 21 | CompletableFuture closeAsync(); 22 | 23 | /** 24 | * Synchronously closes and disposes any resources associated with this object. Calling this method is equivalent of calling closeAsync().get(). This method blocks until this object is closed. 25 | * @throws ServiceBusException If this object cannot be properly closed. 26 | */ 27 | void close() throws ServiceBusException; 28 | } 29 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/IMessageBrowser.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | package com.microsoft.azure.servicebus; 5 | 6 | import java.util.Collection; 7 | import java.util.concurrent.CompletableFuture; 8 | 9 | import com.microsoft.azure.servicebus.primitives.ServiceBusException; 10 | 11 | /** 12 | * Represents a message browser that can browse messages from Azure Service Bus. 13 | */ 14 | public interface IMessageBrowser { 15 | 16 | /** 17 | * reads next the active message without changing the state of the receiver or the message source. 18 | * The first call to {@link IMessageBrowser#peek()} fetches the first active message for this receiver. 19 | * Each subsequent call fetches the subsequent message in the entity. 20 | * 21 | * @return {@link Message} peeked 22 | * @throws InterruptedException if the current thread was interrupted while waiting 23 | * @throws ServiceBusException if peek failed 24 | */ 25 | IMessage peek() throws InterruptedException, ServiceBusException; 26 | 27 | /** 28 | * Reads next the active message without changing the state of the receiver or the message source. 29 | * 30 | * @param fromSequenceNumber The sequence number from where to read the message. 31 | * @return {@link Message} peeked 32 | * @throws InterruptedException if the current thread was interrupted while waiting 33 | * @throws ServiceBusException if peek failed 34 | */ 35 | IMessage peek(long fromSequenceNumber) throws InterruptedException, ServiceBusException; 36 | 37 | /** 38 | * Reads next batch of the active messages without changing the state of the receiver or the message source. 39 | * 40 | * @param messageCount The number of messages. 41 | * @return Batch of {@link Message} peeked 42 | * @throws InterruptedException if the current thread was interrupted while waiting 43 | * @throws ServiceBusException if peek failed 44 | */ 45 | Collection peekBatch(int messageCount) throws InterruptedException, ServiceBusException; 46 | 47 | /** 48 | * Reads next batch of the active messages without changing the state of the receiver or the message source. 49 | * 50 | * @param fromSequenceNumber The sequence number from where to read the message. 51 | * @param messageCount The number of messages. 52 | * @return Batch of {@link Message} peeked 53 | * @throws InterruptedException if the current thread was interrupted while waiting 54 | * @throws ServiceBusException if peek failed 55 | */ 56 | Collection peekBatch(long fromSequenceNumber, int messageCount) throws InterruptedException, ServiceBusException; 57 | 58 | /** 59 | * Asynchronously reads the active messages without changing the state of the receiver or the message source. 60 | * 61 | * @return {@link Message} peeked 62 | */ 63 | CompletableFuture peekAsync(); 64 | 65 | /** 66 | * Asynchronously reads next the active message without changing the state of the receiver or the message source. 67 | * 68 | * @param fromSequenceNumber The sequence number from where to read the message. 69 | * @return CompletableFuture that returns {@link Message} peeked. 70 | */ 71 | CompletableFuture peekAsync(long fromSequenceNumber); 72 | 73 | /** 74 | * Asynchronously reads the next batch of active messages without changing the state of the receiver or the message source. 75 | * 76 | * @param messageCount The number of messages. 77 | * @return CompletableFuture that returns batch of {@link Message} peeked. 78 | */ 79 | CompletableFuture> peekBatchAsync(int messageCount); 80 | 81 | /** 82 | * Asynchronously reads the next batch of active messages without changing the state of the receiver or the message source. 83 | * 84 | * @param fromSequenceNumber The sequence number from where to read the message. 85 | * @param messageCount The number of messages. 86 | * @return CompletableFuture that returns batch of {@link Message} peeked. 87 | */ 88 | CompletableFuture> peekBatchAsync(long fromSequenceNumber, int messageCount); 89 | } 90 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/IMessageEntityClient.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | package com.microsoft.azure.servicebus; 5 | 6 | /** 7 | * Represents a messaging client to an Azure Service Bus entity. 8 | * 9 | * @since 1.0 10 | */ 11 | public interface IMessageEntityClient extends ICloseable { 12 | /** 13 | * Gets the path of the entity this client is sending messages to or receiving messages from. 14 | * 15 | * @return path of the entity this client is connecting to 16 | */ 17 | public String getEntityPath(); 18 | } 19 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/IMessageHandler.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | package com.microsoft.azure.servicebus; 5 | 6 | import java.util.concurrent.CompletableFuture; 7 | 8 | /** 9 | * Defines the contract for registering the callback {@link QueueClient#registerMessageHandler(IMessageHandler)} and {@link SubscriptionClient#registerMessageHandler(IMessageHandler)} for {@link QueueClient} and {@link SubscriptionClient}. 10 | */ 11 | public interface IMessageHandler { 12 | 13 | /** 14 | * The callback for message pump to pass received {@link Message}s. 15 | * 16 | * @param message The received {@link Message}. 17 | * @return CompletableFuture for the message handler. 18 | */ 19 | public CompletableFuture onMessageAsync(IMessage message); 20 | 21 | /** 22 | * Receiving the exceptions that passed by pump during message processing. 23 | * 24 | * @param exception Exception received in pump. 25 | * @param phase Exception phase. 26 | */ 27 | public void notifyException(Throwable exception, ExceptionPhase phase); 28 | } 29 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/IMessageSession.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | package com.microsoft.azure.servicebus; 5 | 6 | import java.time.Instant; 7 | import java.util.concurrent.CompletableFuture; 8 | 9 | import com.microsoft.azure.servicebus.primitives.ServiceBusException; 10 | 11 | /** 12 | * Describes a Session object. IMessageSession can be used to perform operations on sessions. 13 | *

14 | * Service Bus Sessions, also called 'Groups' in the AMQP 1.0 protocol, are unbounded sequences of related messages. ServiceBus guarantees ordering of messages in a session. 15 | *

16 | * Any sender can create a session when submitting messages into a Topic or Queue by setting the {@link Message#sessionId} property on Message to some application defined unique identifier. At the AMQP 1.0 protocol level, this value maps to the group-id property. 17 | *

18 | * Sessions come into existence when there is at least one message with the session's SessionId in the Queue or Topic subscription. Once a Session exists, there is no defined moment or gesture for when the session expires or disappears. 19 | */ 20 | public interface IMessageSession extends IMessageReceiver { 21 | 22 | /** 23 | * @return Gets the SessionId. 24 | */ 25 | String getSessionId(); 26 | 27 | /** 28 | * @return Gets the time that the session identified by {@link IMessageSession#getSessionId()} is locked until for this client. 29 | */ 30 | Instant getLockedUntilUtc(); 31 | 32 | /** 33 | * Renews the lock on the session specified by the {@link IMessageSession#getSessionId()}. The lock will be renewed based on the setting specified on the entity. 34 | *

35 | * When you accept a session, the session is locked for this client instance by the service for a duration as specified during the Queue/Subscription creation. 36 | * If processing of the session requires longer than this duration, the session-lock needs to be renewed. For each renewal, the session-lock is renewed by 37 | * the entity's LockDuration. 38 | *

39 | * Renewal of session renews all the messages in the session as well. Each individual message need not be renewed. 40 | * 41 | * @throws InterruptedException if the current thread was interrupted while waiting 42 | * @throws ServiceBusException if the renew failed. 43 | */ 44 | void renewSessionLock() throws InterruptedException, ServiceBusException; 45 | 46 | /** 47 | * Renews the lock on the session specified by the {@link IMessageSession#getSessionId()}. The lock will be renewed based on the setting specified on the entity. 48 | * 49 | * @return a CompletableFuture representing the pending renew. 50 | * @see IMessageSession#renewSessionLock() 51 | */ 52 | CompletableFuture renewSessionLockAsync(); 53 | 54 | /** 55 | * Set a custom state on the session which can be later retrieved using {@link IMessageSession#getState()}. 56 | * 57 | * @param state The session state. 58 | * @throws InterruptedException if the current thread was interrupted while waiting 59 | * @throws ServiceBusException if the set state failed. 60 | */ 61 | void setState(byte[] state) throws InterruptedException, ServiceBusException; 62 | 63 | /** 64 | * Asynchronously set a custom state on the session which can be later retrieved using {@link IMessageSession#getState()}. 65 | * 66 | * @param state The session state. 67 | * @return a CompletableFuture representing the pending session state setting. 68 | * @see IMessageSession#setState 69 | */ 70 | CompletableFuture setStateAsync(byte[] state); 71 | 72 | /** 73 | * Gets the session state. 74 | * 75 | * @return The session state 76 | * @throws InterruptedException if the current thread was interrupted while waiting 77 | * @throws ServiceBusException if get state failed. 78 | */ 79 | byte[] getState() throws InterruptedException, ServiceBusException; 80 | 81 | /** 82 | * Asynchronously gets the session state. 83 | * @return a CompletableFuture representing the pending session state retrieving. 84 | * @see IMessageSession#getState 85 | */ 86 | CompletableFuture getStateAsync(); 87 | } 88 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/IMessageSessionEntity.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | package com.microsoft.azure.servicebus; 5 | 6 | import java.time.Instant; 7 | import java.util.Collection; 8 | import java.util.concurrent.CompletableFuture; 9 | 10 | import com.microsoft.azure.servicebus.primitives.ServiceBusException; 11 | 12 | /** 13 | * Represents a session full client entity. 14 | */ 15 | public interface IMessageSessionEntity { 16 | // int getSessionPrefetchCount(); 17 | // 18 | // void setSessionPrefetchCount(int prefetchCount); 19 | // 20 | // IMessageSession acceptMessageSession() throws InterruptedException, ServiceBusException; 21 | // 22 | // IMessageSession acceptMessageSession(Duration serverWaitTime) throws InterruptedException, ServiceBusException; 23 | // 24 | // IMessageSession acceptMessageSession(String sessionId) throws InterruptedException, ServiceBusException; 25 | // 26 | // IMessageSession acceptMessageSession(String sessionId, Duration serverWaitTime) throws InterruptedException, ServiceBusException; 27 | // 28 | // CompletableFuture acceptMessageSessionAsync(); 29 | // 30 | // CompletableFuture acceptMessageSessionAsync(Duration serverWaitTime); 31 | // 32 | // CompletableFuture acceptMessageSessionAsync(String sessionId); 33 | // 34 | // CompletableFuture acceptMessageSessionAsync(String sessionId, Duration serverWaitTime); 35 | 36 | /** 37 | * Gets the message sessions, enabling you to browse sessions on queues. 38 | * 39 | * @return A collection of sessions. 40 | * @throws InterruptedException if the current thread was interrupted while waiting. 41 | * @throws ServiceBusException if get sessions failed. 42 | */ 43 | Collection getMessageSessions() throws InterruptedException, ServiceBusException; 44 | 45 | /** 46 | * Retrieves all message sessions whose session state was updated since lastUpdatedTime. 47 | * 48 | * @param lastUpdatedTime The time the session was last updated. 49 | * @return A collection of sessions. 50 | * @throws InterruptedException if the current thread was interrupted while waiting. 51 | * @throws ServiceBusException if get sessions failed. 52 | */ 53 | Collection getMessageSessions(Instant lastUpdatedTime) throws InterruptedException, ServiceBusException; 54 | 55 | /** 56 | * Asynchronously gets the message sessions, enabling you to browse sessions on queues. 57 | * 58 | * @return a CompletableFuture representing the pending operation to get sessions. 59 | * @see IMessageSessionEntity#getMessageSessions 60 | */ 61 | CompletableFuture> getMessageSessionsAsync(); 62 | 63 | /** 64 | * Asynchronously retrieves all message sessions whose session state was updated since lastUpdatedTime. 65 | * 66 | * @param lastUpdatedTime The time the session was last updated. 67 | * @return a CompletableFuture representing the pending operation to get sessions. 68 | * @see IMessageSessionEntity#getMessageSessions(Instant) 69 | */ 70 | CompletableFuture> getMessageSessionsAsync(Instant lastUpdatedTime); 71 | } 72 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/IQueueClient.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | package com.microsoft.azure.servicebus; 5 | 6 | /** 7 | * QueueClient can be used for all basic interactions with a Service Bus Queue. 8 | */ 9 | public interface IQueueClient extends IMessageSender, IMessageAndSessionPump, IMessageEntityClient { 10 | 11 | /** 12 | * Gets the {@link ReceiveMode} of the current receiver 13 | * 14 | * @return The receive mode. 15 | */ 16 | public ReceiveMode getReceiveMode(); 17 | 18 | /** 19 | * Gets the name of the queue. 20 | * 21 | * @return The name of the queue. 22 | */ 23 | public String getQueueName(); 24 | } 25 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/ISessionHandler.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | package com.microsoft.azure.servicebus; 5 | 6 | import java.util.concurrent.CompletableFuture; 7 | 8 | /** 9 | * Defines the contract for registering the session message processing callback {@link QueueClient#registerSessionHandler(ISessionHandler)} or {@link SubscriptionClient#registerSessionHandler(ISessionHandler)} for {@link QueueClient} and {@link SubscriptionClient}. 10 | */ 11 | public interface ISessionHandler { 12 | 13 | /** 14 | * The callback for message pump to pass received {@link Message}s. 15 | * 16 | * @param session The {@link MessageSession} of the message. 17 | * @param message The received {@link Message}. 18 | * @return CompletableFuture for the message handler. 19 | */ 20 | public CompletableFuture onMessageAsync(IMessageSession session, IMessage message); 21 | 22 | /** 23 | * Called just before a session is closed by the session pump 24 | * 25 | * @param session session being closed 26 | * @return a future that executes the action 27 | */ 28 | public CompletableFuture OnCloseSessionAsync(IMessageSession session); 29 | 30 | /** 31 | * Receiving the exceptions that passed by pump during message processing. 32 | * 33 | * @param exception Exception received in pump. 34 | * @param phase Exception phase. 35 | */ 36 | public void notifyException(Throwable exception, ExceptionPhase phase); 37 | } 38 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/ISubscriptionClient.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | package com.microsoft.azure.servicebus; 5 | 6 | import java.util.Collection; 7 | import java.util.concurrent.CompletableFuture; 8 | 9 | import com.microsoft.azure.servicebus.primitives.ServiceBusException; 10 | import com.microsoft.azure.servicebus.rules.Filter; 11 | import com.microsoft.azure.servicebus.rules.RuleDescription; 12 | 13 | /** 14 | * SubscriptionClient can be used for all basic interactions with a Service Bus Subscription. 15 | */ 16 | public interface ISubscriptionClient extends IMessageEntityClient, IMessageAndSessionPump { 17 | 18 | /** 19 | * Gets the {@link ReceiveMode} of the current receiver 20 | * 21 | * @return The receive mode. 22 | */ 23 | public ReceiveMode getReceiveMode(); 24 | 25 | /** 26 | * Adds a rule to the current subscription to filter the messages reaching from topic to the subscription. 27 | * 28 | * @param ruleDescription The rule description that provides the rule to add. 29 | * @throws InterruptedException if the current thread was interrupted while waiting 30 | * @throws ServiceBusException if add rule failed 31 | */ 32 | public void addRule(RuleDescription ruleDescription) throws InterruptedException, ServiceBusException; 33 | 34 | /** 35 | * Asynchronously adds a rule to the current subscription to filter the messages reaching from topic to the subscription. 36 | * 37 | * @param ruleDescription The rule description that provides the rule to add. 38 | * @return a CompletableFuture representing the pending rule add operation. 39 | */ 40 | public CompletableFuture addRuleAsync(RuleDescription ruleDescription); 41 | 42 | /** 43 | * Adds a rule with specified name and {@link Filter} to the current subscription to filter the messages reaching from topic to the subscription. 44 | * 45 | * @param ruleName The rule name 46 | * @param filter The {@link Filter} to add. 47 | * @throws InterruptedException if the current thread was interrupted while waiting 48 | * @throws ServiceBusException if add rule failed 49 | */ 50 | public void addRule(String ruleName, Filter filter) throws InterruptedException, ServiceBusException; 51 | 52 | /** 53 | * Asynchronously adds a rule with specified name and {@link Filter} to the current subscription to filter the messages reaching from topic to the subscription. 54 | * 55 | * @param ruleName The rule name 56 | * @param filter The {@link Filter} to add. 57 | * @return a CompletableFuture representing the pending rule add operation. 58 | */ 59 | public CompletableFuture addRuleAsync(String ruleName, Filter filter); 60 | 61 | /** 62 | * Asynchronously removes the rule on the subscription identified by ruleName 63 | * 64 | * @param ruleName he name of rule. 65 | * @return a CompletableFuture representing the pending rule remove operation. 66 | */ 67 | public CompletableFuture removeRuleAsync(String ruleName); 68 | 69 | /** 70 | * Removes the rule on the subscription identified by ruleName 71 | * 72 | * @param ruleName The name of rule. 73 | * @throws InterruptedException if the current thread was interrupted while waiting 74 | * @throws ServiceBusException if remove rule failed 75 | */ 76 | public void removeRule(String ruleName) throws InterruptedException, ServiceBusException; 77 | 78 | /** 79 | * Get all rules associated with the subscription. 80 | * 81 | * @return The collection fo the rules. 82 | * @throws InterruptedException if the current thread was interrupted while waiting 83 | * @throws ServiceBusException if get rules failed 84 | */ 85 | public Collection getRules() throws ServiceBusException, InterruptedException; 86 | 87 | /** 88 | * Get all rules associated with the subscription. 89 | * 90 | * @return a CompletableFuture representing the pending get rules operation. 91 | */ 92 | public CompletableFuture> getRulesAsync(); 93 | 94 | /** 95 | * Gets the name of the topic, for this subscription. 96 | * 97 | * @return the name of the topic 98 | */ 99 | public String getTopicName(); 100 | 101 | /** 102 | * Gets the subscription name. 103 | * @return The subscription name. 104 | */ 105 | public String getSubscriptionName(); 106 | } 107 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/ITopicClient.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | package com.microsoft.azure.servicebus; 5 | 6 | /** 7 | * TopicClient can be used for all basic interactions with a Service Bus topic. 8 | * {@code 9 | * 10 | * } 11 | */ 12 | public interface ITopicClient extends IMessageSender, IMessageBrowser, IMessageEntityClient { 13 | 14 | /** 15 | * Get the name of the topic 16 | * @return the name of the topic 17 | */ 18 | public String getTopicName(); 19 | } 20 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/InitializableEntity.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | package com.microsoft.azure.servicebus; 5 | 6 | import java.util.concurrent.CompletableFuture; 7 | 8 | import com.microsoft.azure.servicebus.primitives.ClientEntity; 9 | 10 | /** 11 | * Represents an entity that needs to be initialized before using. This class defines a standard way of properly initializing client objects. 12 | * 13 | * @since 1.0 14 | */ 15 | abstract class InitializableEntity extends ClientEntity { 16 | 17 | //TODO Init and close semantics are primitive now. Fix them with support for other states like Initializing, Closing, and concurrency. 18 | protected InitializableEntity(String clientId) { 19 | super(clientId); 20 | } 21 | 22 | /** 23 | * Initializes this object. This method is asynchronous and returns a CompletableFuture immediately. Initializing of the object is complete when the returned future completes. 24 | * 25 | * @return CompletableFuture representing the initialization 26 | */ 27 | abstract CompletableFuture initializeAsync(); 28 | 29 | } 30 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/MessageBody.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus; 2 | 3 | import java.io.Serializable; 4 | import java.util.List; 5 | 6 | /** 7 | * This class encapsulates the body of a message. Body types map to AMQP message body types. 8 | * It has getters and setters for multiple body types. 9 | * Client should test for body type before calling corresponding get method. 10 | * Get methods not corresponding to the type of the body return null. 11 | */ 12 | public class MessageBody implements Serializable{ 13 | 14 | private static final long serialVersionUID = 7215009530928988502L; 15 | 16 | private MessageBodyType bodyType; 17 | private Object valueData; 18 | private List> sequenceData; 19 | private List binaryData; 20 | 21 | private MessageBody() {} 22 | 23 | /** 24 | * Creates message body of AMQPValue type. 25 | * @param value AMQPValue content of the message. It must be of a type supported by AMQP. 26 | * @return MessageBody instance wrapping around the value data. 27 | */ 28 | public static MessageBody fromValueData(Object value) 29 | { 30 | if(value == null) 31 | { 32 | throw new IllegalArgumentException("Value data is null."); 33 | } 34 | 35 | MessageBody body = new MessageBody(); 36 | body.bodyType = MessageBodyType.VALUE; 37 | body.valueData = value; 38 | body.sequenceData = null; 39 | body.binaryData = null; 40 | return body; 41 | } 42 | 43 | /** 44 | * Creates a message body from a list of AMQPSequence sections.Each AMQPSequence section is in turn a list of objects. 45 | * Please note that this version of the SDK supports only one AMQPSequence section in a message. It means only a list of exactly one sequence in it is accepted as message body. 46 | * @param sequenceData a list of AMQPSequence sections. Each AMQPSequence section is in turn a list of objects. Every object in each list must of a type supported by AMQP. 47 | * @return MessageBody instance wrapping around the sequence data. 48 | */ 49 | public static MessageBody fromSequenceData(List> sequenceData) 50 | { 51 | if(sequenceData == null || sequenceData.size() == 0 || sequenceData.size() > 1) 52 | { 53 | throw new IllegalArgumentException("Sequence data is null or has more than one collection in it."); 54 | } 55 | 56 | MessageBody body = new MessageBody(); 57 | body.bodyType = MessageBodyType.SEQUENCE; 58 | body.valueData = null; 59 | body.sequenceData = sequenceData; 60 | body.binaryData = null; 61 | return body; 62 | } 63 | 64 | /** 65 | * Creates a message body from a list of Data sections.Each Data section is a byte array. 66 | * Please note that this version of the SDK supports only one Data section in a message. It means only a list of exactly one byte array in it is accepted as message body. 67 | * @param binaryData a list of byte arrays. 68 | * @return MessageBody instance wrapping around the binary data. 69 | */ 70 | public static MessageBody fromBinaryData(List binaryData) 71 | { 72 | if(binaryData == null || binaryData.size() == 0 || binaryData.size() > 1) 73 | { 74 | throw new IllegalArgumentException("Binary data is null or has more than one byte array in it."); 75 | } 76 | 77 | MessageBody body = new MessageBody(); 78 | body.bodyType = MessageBodyType.BINARY; 79 | body.valueData = null; 80 | body.sequenceData = null; 81 | body.binaryData = binaryData; 82 | return body; 83 | } 84 | 85 | /** 86 | * Returns the content of message body. 87 | * @return value of message body only if the MessageBody is of Value type. Returns null otherwise. 88 | */ 89 | public Object getValueData() { 90 | return valueData; 91 | } 92 | 93 | /** 94 | * Returns the content of message body. 95 | * @return a list of AMQPSequence sections only if the MessageBody is of Sequence type. Returns null otherwise. Each AMQPSequence section is in turn a list of objects. 96 | */ 97 | public List> getSequenceData() { 98 | return sequenceData; 99 | } 100 | 101 | /** 102 | * Returns the content of message body. 103 | * @return message body as list of byte arrays only if the MessageBody is of Binary type. Returns null otherwise. 104 | */ 105 | public List getBinaryData() { 106 | return binaryData; 107 | } 108 | 109 | /** 110 | * Return the type of content in this message body. 111 | * @return type of message content 112 | */ 113 | public MessageBodyType getBodyType() { 114 | return bodyType; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/MessageBodyType.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus; 2 | 3 | /** 4 | * Enumeration to represent body type of a message. 5 | * 6 | */ 7 | public enum MessageBodyType { 8 | /** 9 | * Message content is byte array, equivalent to AMQP Data. 10 | */ 11 | BINARY, 12 | /** 13 | * Message content is a list of objects, equivalent to AMQP Sequence. Each object must be of a type supported by AMQP. 14 | */ 15 | SEQUENCE, 16 | /** 17 | * Message content is a single object, equivalent to AMQP Value. The object must be of a type supported by AMQP. 18 | */ 19 | VALUE 20 | } 21 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/MessageHandlerOptions.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | package com.microsoft.azure.servicebus; 4 | 5 | import java.time.Duration; 6 | import java.util.Locale; 7 | 8 | /** 9 | * The OnMessage handler processing options. 10 | */ 11 | public final class MessageHandlerOptions { 12 | private static final boolean DEFAULT_AUTO_COMPLETE = true; 13 | private static final int DEFAULT_MAX_CONCURRENT_CALLS = 1; 14 | private static final int DEFAULT_MAX_RENEW_TIME_MINUTES = 5; 15 | private static final int DEFAULT_MESSAGE_WAIT_TIME_MINUTES = 1; 16 | 17 | private boolean autoComplete; 18 | private Duration maxAutoRenewDuration; 19 | private Duration messageWaitDuration; 20 | private int maxConcurrentCalls; 21 | 22 | /** 23 | * Default constructor for create {@link MessageHandlerOptions} with default settings. 24 | * {@link MessageHandlerOptions#getMaxConcurrentCalls()} default value is 1. 25 | * {@link MessageHandlerOptions#getMaxAutoRenewDuration()} default value is 5 minutes. 26 | * {@link MessageHandlerOptions#isAutoComplete()} default is true. 27 | */ 28 | public MessageHandlerOptions() { 29 | this(DEFAULT_MAX_CONCURRENT_CALLS, DEFAULT_AUTO_COMPLETE, Duration.ofMinutes(DEFAULT_MAX_RENEW_TIME_MINUTES)); 30 | } 31 | 32 | /** 33 | * Create a instance of {@link MessageHandlerOptions}. 34 | * 35 | * @param maxConcurrentCalls maximum number of concurrent calls to the onMessage handler 36 | * @param autoComplete true if the pump should automatically complete message after onMessageHandler action is completed. false otherwise. 37 | * @param maxAutoRenewDuration - Maximum duration within which the client keeps renewing the message lock if the processing of the message is not completed by the handler. 38 | */ 39 | public MessageHandlerOptions(int maxConcurrentCalls, boolean autoComplete, Duration maxAutoRenewDuration) { 40 | this(maxConcurrentCalls, autoComplete, maxAutoRenewDuration, Duration.ofMinutes(DEFAULT_MESSAGE_WAIT_TIME_MINUTES)); 41 | } 42 | 43 | /** 44 | * Create a instance of {@link MessageHandlerOptions}. 45 | * 46 | * @param maxConcurrentCalls maximum number of concurrent calls to the onMessage handler 47 | * @param autoComplete true if the pump should automatically complete message after onMessageHandler action is completed. false otherwise. 48 | * @param maxAutoRenewDuration - Maximum duration within which the client keeps renewing the message lock if the processing of the message is not completed by the handler. 49 | * @param messageWaitDuration duration to wait for receiving the message 50 | */ 51 | public MessageHandlerOptions(int maxConcurrentCalls, boolean autoComplete, Duration maxAutoRenewDuration, Duration messageWaitDuration) { 52 | this.autoComplete = autoComplete; 53 | this.maxAutoRenewDuration = maxAutoRenewDuration; 54 | this.maxConcurrentCalls = maxConcurrentCalls; 55 | this.messageWaitDuration = messageWaitDuration; 56 | } 57 | 58 | /** 59 | * Whether the auto complete is set to true. 60 | * 61 | * @return true to complete the message processing automatically on successful execution of the operation; otherwise, false. 62 | */ 63 | public boolean isAutoComplete() { 64 | return this.autoComplete; 65 | } 66 | 67 | /** 68 | * Gets the maximum number of concurrent calls to the callback the message pump should initiate. 69 | * 70 | * @return The maximum number of concurrent calls to the callback. 71 | */ 72 | public int getMaxConcurrentCalls() { 73 | return this.maxConcurrentCalls; 74 | } 75 | 76 | /** 77 | * Gets the maximum duration within which the lock will be renewed automatically. This value should be greater than the longest message lock duration; for example, the LockDuration Property. 78 | * 79 | * @return The maximum duration during which locks are automatically renewed. 80 | */ 81 | public Duration getMaxAutoRenewDuration() { 82 | return this.maxAutoRenewDuration; 83 | } 84 | 85 | /** 86 | * Gets the time to wait for receiving a message. Defaults to 1 minute. 87 | * @return The wait duration for receive calls. 88 | */ 89 | public Duration getMessageWaitDuration() { return this.messageWaitDuration; } 90 | 91 | @Override 92 | public String toString() { 93 | return String.format(Locale.US, "MessageHandlerOptions - AutoComplete:%s, MaxConcurrentCalls:%s, MaxAutoRenewDuration:%s", this.autoComplete, this.maxConcurrentCalls, this.maxAutoRenewDuration); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/MessageSession.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | package com.microsoft.azure.servicebus; 5 | 6 | import java.net.URI; 7 | import java.time.Instant; 8 | import java.util.concurrent.CompletableFuture; 9 | 10 | import com.microsoft.azure.servicebus.primitives.MessagingEntityType; 11 | import com.microsoft.azure.servicebus.primitives.MessagingFactory; 12 | import com.microsoft.azure.servicebus.primitives.ServiceBusException; 13 | 14 | public class MessageSession extends MessageReceiver implements IMessageSession { 15 | private String requestedSessionId; 16 | 17 | MessageSession(URI namespaceEndpointURI, String entityPath, MessagingEntityType entityType, String requestedSessionId, ClientSettings clientSettings, ReceiveMode receiveMode) { 18 | super(namespaceEndpointURI, entityPath, entityType, clientSettings, receiveMode); 19 | this.requestedSessionId = requestedSessionId; 20 | } 21 | 22 | MessageSession(MessagingFactory messagingFactory, String entityPath, MessagingEntityType entityType, String requestedSessionId, ReceiveMode receiveMode) { 23 | super(messagingFactory, entityPath, entityType, receiveMode); 24 | this.requestedSessionId = requestedSessionId; 25 | } 26 | 27 | @Override 28 | protected final boolean isSessionReceiver() { 29 | return true; 30 | } 31 | 32 | @Override 33 | protected boolean isBrowsableSession() { 34 | return false; 35 | } 36 | 37 | @Override 38 | protected String getRequestedSessionId() { 39 | return this.requestedSessionId; 40 | } 41 | 42 | @Override 43 | public Instant getLockedUntilUtc() { 44 | return this.getInternalReceiver().getSessionLockedUntilUtc(); 45 | } 46 | 47 | @Override 48 | public void renewSessionLock() throws InterruptedException, ServiceBusException { 49 | Utils.completeFuture(this.renewSessionLockAsync()); 50 | } 51 | 52 | @Override 53 | public CompletableFuture renewSessionLockAsync() { 54 | return this.getInternalReceiver().renewSessionLocksAsync(); 55 | } 56 | 57 | @Override 58 | public void setState(byte[] sessionState) throws InterruptedException, ServiceBusException { 59 | Utils.completeFuture(this.setStateAsync(sessionState)); 60 | } 61 | 62 | @Override 63 | public CompletableFuture setStateAsync(byte[] sessionState) { 64 | return this.getInternalReceiver().setSessionStateAsync(sessionState); 65 | } 66 | 67 | @Override 68 | public byte[] getState() throws InterruptedException, ServiceBusException { 69 | return Utils.completeFuture(this.getStateAsync()); 70 | } 71 | 72 | @Override 73 | public CompletableFuture getStateAsync() { 74 | return this.getInternalReceiver().getSessionStateAsync(); 75 | } 76 | 77 | @Override 78 | public String getSessionId() { 79 | return this.getInternalReceiver().getSessionId(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/ReceiveMode.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | package com.microsoft.azure.servicebus; 5 | 6 | /** 7 | * Enumeration to represent the two receive modes Azure Service Bus supports. 8 | * 9 | * @since 1.0 10 | */ 11 | public enum ReceiveMode { 12 | /** 13 | * In this mode, received message is not deleted from the queue or subscription, instead it is temporarily locked to the receiver, making it invisible to other receivers. Then the service waits for one of the three events 14 | *

    15 | *
  • If the receiver processes the message successfully, it calls complete and the message will be deleted.
  • 16 | *
  • If the receiver decides that it can't process the message successfully, it calls abandon and the message will be unlocked and made available to other receivers.
  • 17 | *
  • If the receiver wants to defer the processing of the message to a later point in time, it calls defer and the message will be deferred. A deferred can only be received by its sequence number.
  • 18 | *
  • If the receiver wants to dead-letter the message, it calls deadLetter and the message will be moved to a special sub-queue called deadletter queue.
  • 19 | *
  • If the receiver calls neither of these methods within a configurable period of time (by default, 60 seconds), the service assumes the receiver has failed. In this case, it behaves as if the receiver had called abandon, making the message available to other receivers
  • 20 | *
21 | */ 22 | PEEKLOCK, 23 | /** 24 | * In this mode, received message is removed from the queue or subscription and immediately deleted. This option is simple, but if the receiver crashes 25 | * before it finishes processing the message, the message is lost. Because it's been removed from the queue, no other receiver can access it. 26 | */ 27 | RECEIVEANDDELETE 28 | } 29 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/SessionBrowser.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | package com.microsoft.azure.servicebus; 5 | 6 | import java.util.ArrayList; 7 | import java.util.Collection; 8 | import java.util.Date; 9 | import java.util.concurrent.CompletableFuture; 10 | 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import com.microsoft.azure.servicebus.primitives.MessagingEntityType; 15 | import com.microsoft.azure.servicebus.primitives.MessagingFactory; 16 | import com.microsoft.azure.servicebus.primitives.MiscRequestResponseOperationHandler; 17 | 18 | final class SessionBrowser { 19 | private static final Logger TRACE_LOGGER = LoggerFactory.getLogger(SessionBrowser.class); 20 | private static final int PAGESIZE = 100; 21 | // .net DateTime.MaxValue need to be passed 22 | private static final Date MAXDATE = new Date(253402300800000l); 23 | 24 | private final MessagingFactory messagingFactory; 25 | private final String entityPath; 26 | private final MessagingEntityType entityType; 27 | private MiscRequestResponseOperationHandler miscRequestResponseHandler; 28 | 29 | SessionBrowser(MessagingFactory messagingFactory, String entityPath, MessagingEntityType entityType, MiscRequestResponseOperationHandler miscRequestResponseHandler) { 30 | this.messagingFactory = messagingFactory; 31 | this.entityPath = entityPath; 32 | this.entityType = entityType; 33 | this.miscRequestResponseHandler = miscRequestResponseHandler; 34 | } 35 | 36 | public CompletableFuture> getMessageSessionsAsync() { 37 | return this.getMessageSessionsAsync(MAXDATE); 38 | } 39 | 40 | public CompletableFuture> getMessageSessionsAsync(Date lastUpdatedTime) { 41 | return this.getMessageSessionsAsync(lastUpdatedTime, 0, null); 42 | } 43 | 44 | private CompletableFuture> getMessageSessionsAsync(Date lastUpdatedTime, int lastReceivedSkip, String lastSessionId) { 45 | TRACE_LOGGER.debug("Getting '{}' browsable sessions from entity '{}', lastUpdatedTime '{}', lastReceivedSkip '{}', lastSessionId '{}'", PAGESIZE, this.entityPath, lastUpdatedTime, lastReceivedSkip, lastSessionId); 46 | return this.miscRequestResponseHandler.getMessageSessionsAsync(lastUpdatedTime, lastReceivedSkip, PAGESIZE, lastSessionId).thenComposeAsync((p) -> 47 | { 48 | int newLastReceivedSkip = p.getSecondItem(); 49 | String[] sessionIds = p.getFirstItem(); 50 | ArrayList sessionsList = new ArrayList<>(); 51 | if (sessionIds != null && sessionIds.length > 0) { 52 | TRACE_LOGGER.debug("Got '{}' browsable sessions from entity '{}', receivedSkip '{}'", sessionIds.length, this.entityPath, newLastReceivedSkip); 53 | CompletableFuture[] initFutures = new CompletableFuture[sessionIds.length]; 54 | int initFutureIndex = 0; 55 | String newLastSessionId = sessionIds[sessionIds.length - 1]; 56 | for (String sessionId : sessionIds) { 57 | BrowsableMessageSession browsableSession = new BrowsableMessageSession(sessionId, this.messagingFactory, this.entityPath, this.entityType); 58 | sessionsList.add(browsableSession); 59 | initFutures[initFutureIndex++] = browsableSession.initializeAsync(); 60 | } 61 | CompletableFuture allInitFuture = CompletableFuture.allOf(initFutures); 62 | return allInitFuture.thenComposeAsync((v) -> getMessageSessionsAsync(lastUpdatedTime, newLastReceivedSkip, newLastSessionId), MessagingFactory.INTERNAL_THREAD_POOL).thenApply((c) -> { 63 | sessionsList.addAll(c); 64 | return sessionsList; 65 | }); 66 | } else { 67 | TRACE_LOGGER.debug("Got no browsable sessions from entity '{}'", this.entityPath); 68 | return CompletableFuture.completedFuture(sessionsList); 69 | } 70 | }, MessagingFactory.INTERNAL_THREAD_POOL); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/Utils.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | package com.microsoft.azure.servicebus; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | import java.util.concurrent.CompletableFuture; 9 | import java.util.concurrent.ExecutionException; 10 | 11 | import com.microsoft.azure.servicebus.primitives.ServiceBusException; 12 | 13 | final class Utils { 14 | 15 | static T completeFuture(CompletableFuture future) throws InterruptedException, ServiceBusException { 16 | try { 17 | return future.get(); 18 | } catch (InterruptedException ie) { 19 | // Rare instance 20 | throw ie; 21 | } catch (ExecutionException ee) { 22 | Throwable cause = ee.getCause(); 23 | if(cause instanceof RuntimeException) 24 | { 25 | throw (RuntimeException)cause; 26 | } 27 | else if (cause instanceof Error) 28 | { 29 | throw (Error)cause; 30 | } 31 | else if (cause instanceof ServiceBusException) 32 | { 33 | throw (ServiceBusException) cause; 34 | } 35 | else 36 | { 37 | throw new ServiceBusException(true, cause); 38 | } 39 | } 40 | } 41 | 42 | static void assertNonNull(String argumentName, Object argument) { 43 | if (argument == null) 44 | throw new IllegalArgumentException("Argument '" + argumentName + "' is null."); 45 | } 46 | 47 | static MessageBody fromSequence(List sequence) 48 | { 49 | List> sequenceData = new ArrayList<>(); 50 | sequenceData.add(sequence); 51 | return MessageBody.fromSequenceData(sequenceData); 52 | } 53 | 54 | static MessageBody fromBinay(byte[] binary) 55 | { 56 | List binaryData = new ArrayList<>(); 57 | binaryData.add(binary); 58 | return MessageBody.fromBinaryData(binaryData); 59 | } 60 | 61 | static byte[] getDataFromMessageBody(MessageBody messageBody) 62 | { 63 | List binaryData = messageBody.getBinaryData(); 64 | if(binaryData == null || binaryData.size() == 0) 65 | { 66 | return null; 67 | } 68 | else 69 | { 70 | return binaryData.get(0); 71 | } 72 | } 73 | 74 | static List getSequenceFromMessageBody(MessageBody messageBody) 75 | { 76 | List> sequenceData = messageBody.getSequenceData(); 77 | if(sequenceData == null || sequenceData.size() == 0) 78 | { 79 | return null; 80 | } 81 | else 82 | { 83 | return sequenceData.get(0); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/amqp/AmqpConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.amqp; 6 | 7 | import org.apache.qpid.proton.amqp.*; 8 | 9 | public final class AmqpConstants 10 | { 11 | private AmqpConstants() { } 12 | 13 | public static final String APACHE = "apache.org"; 14 | public static final String VENDOR = "com.microsoft"; 15 | 16 | public static final Symbol STRING_FILTER = Symbol.valueOf(AmqpConstants.APACHE + ":selector-filter:string"); 17 | public static final Symbol EPOCH = Symbol.valueOf(AmqpConstants.VENDOR + ":epoch"); 18 | 19 | public static final int AMQP_BATCH_MESSAGE_FORMAT = 0x80013700; // 2147563264L; 20 | 21 | public static final int MAX_FRAME_SIZE = 65536; 22 | 23 | public static final String MANAGEMENT_NODE_ADDRESS_SEGMENT = "$management"; 24 | public static final String CBS_NODE_ADDRESS_SEGMENT = "$cbs"; 25 | 26 | public static final Symbol PRODUCT = Symbol.valueOf("product"); 27 | public static final Symbol VERSION = Symbol.valueOf("version"); 28 | public static final Symbol PLATFORM = Symbol.valueOf("platform"); 29 | } 30 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/amqp/AmqpErrorCode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.amqp; 6 | 7 | import org.apache.qpid.proton.amqp.Symbol; 8 | 9 | public final class AmqpErrorCode 10 | { 11 | 12 | public static final Symbol NotFound = Symbol.getSymbol("amqp:not-found"); 13 | public static final Symbol UnauthorizedAccess = Symbol.getSymbol("amqp:unauthorized-access"); 14 | public static final Symbol ResourceLimitExceeded = Symbol.getSymbol("amqp:resource-limit-exceeded"); 15 | public static final Symbol NotAllowed = Symbol.getSymbol("amqp:not-allowed"); 16 | public static final Symbol InternalError = Symbol.getSymbol("amqp:internal-error"); 17 | public static final Symbol IllegalState = Symbol.getSymbol("amqp:illegal-state"); 18 | public static final Symbol NotImplemented = Symbol.getSymbol("amqp:not-implemented"); 19 | 20 | // link errors 21 | public static final Symbol Stolen = Symbol.getSymbol("amqp:link:stolen"); 22 | public static final Symbol PayloadSizeExceeded = Symbol.getSymbol("amqp:link:message-size-exceeded"); 23 | public static final Symbol AmqpLinkDetachForced = Symbol.getSymbol("amqp:link:detach-forced"); 24 | 25 | // connection errors 26 | public static final Symbol ConnectionForced = Symbol.getSymbol("amqp:connection:forced"); 27 | public static final Symbol FramingError = Symbol.getSymbol("amqp:connection:framing-error"); 28 | } 29 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/amqp/AmqpException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.amqp; 6 | 7 | import org.apache.qpid.proton.amqp.transport.*; 8 | 9 | /** 10 | * All AmqpExceptions - which EventHub client handles internally. 11 | */ 12 | public class AmqpException extends Exception 13 | { 14 | private static final long serialVersionUID = -750417419234273714L; 15 | private ErrorCondition errorCondition; 16 | 17 | public AmqpException(ErrorCondition errorCondition) 18 | { 19 | super(errorCondition.getDescription()); 20 | this.errorCondition = errorCondition; 21 | } 22 | 23 | public ErrorCondition getError() 24 | { 25 | return this.errorCondition; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/amqp/BaseLinkHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.amqp; 6 | 7 | import org.apache.qpid.proton.amqp.transport.*; 8 | import org.apache.qpid.proton.engine.*; 9 | import org.slf4j.LoggerFactory; 10 | import org.slf4j.Logger; 11 | 12 | public class BaseLinkHandler extends BaseHandler { 13 | private static final Logger TRACE_LOGGER = LoggerFactory.getLogger(BaseLinkHandler.class); 14 | 15 | private final IAmqpLink underlyingEntity; 16 | 17 | public BaseLinkHandler(final IAmqpLink amqpLink) { 18 | this.underlyingEntity = amqpLink; 19 | } 20 | 21 | @Override 22 | public void onLinkLocalClose(Event event) { 23 | Link link = event.getLink(); 24 | if (link != null) { 25 | TRACE_LOGGER.debug("local link close. linkName:{}", link.getName()); 26 | 27 | checkAndFreeLink(link); 28 | closeSession(link); 29 | } 30 | } 31 | 32 | @Override 33 | public void onLinkRemoteClose(Event event) { 34 | final Link link = event.getLink(); 35 | if(link != null) 36 | { 37 | TRACE_LOGGER.debug("link remote close. linkName:{}", link.getName()); 38 | if (link.getLocalState() != EndpointState.CLOSED) { 39 | link.close(); 40 | } 41 | 42 | ErrorCondition condition = link.getRemoteCondition(); 43 | this.processOnClose(link, condition); 44 | checkAndFreeLink(link); 45 | closeSession(link); 46 | } 47 | } 48 | 49 | @Override 50 | public void onLinkRemoteDetach(Event event) { 51 | final Link link = event.getLink(); 52 | if(link != null) 53 | { 54 | TRACE_LOGGER.debug("link remote detach. linkName:{}", link.getName()); 55 | if (link.getLocalState() != EndpointState.CLOSED) { 56 | link.close(); 57 | } 58 | 59 | this.processOnClose(link, link.getRemoteCondition()); 60 | closeSession(link); 61 | } 62 | } 63 | 64 | @Override 65 | public void onLinkFinal(Event event) 66 | { 67 | Link link = event.getLink(); 68 | if(link != null) 69 | { 70 | link.attachments().clear(); 71 | } 72 | } 73 | 74 | public void processOnClose(Link link, ErrorCondition condition) { 75 | if (condition != null) { 76 | TRACE_LOGGER.debug("linkName:{}, ErrorCondition:{}, {}", link.getName(), condition.getCondition(), condition.getDescription()); 77 | } 78 | 79 | this.underlyingEntity.onClose(condition); 80 | } 81 | 82 | public void processOnClose(Link link, Exception exception) { 83 | this.underlyingEntity.onError(exception); 84 | } 85 | 86 | private static void closeSession(Link link) { 87 | if (link.getSession() != null && link.getSession().getLocalState() != EndpointState.CLOSED) 88 | link.getSession().close(); 89 | } 90 | 91 | private static void checkAndFreeLink(Link link) { 92 | if (link.getLocalState() == EndpointState.CLOSED && link.getRemoteState() == EndpointState.CLOSED) 93 | { 94 | link.free(); 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/amqp/CustomIOHandler.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.amqp; 2 | 3 | import org.apache.qpid.proton.Proton; 4 | import org.apache.qpid.proton.engine.Connection; 5 | import org.apache.qpid.proton.engine.EndpointState; 6 | import org.apache.qpid.proton.engine.Event; 7 | import org.apache.qpid.proton.engine.Transport; 8 | import org.apache.qpid.proton.reactor.impl.IOHandler; 9 | 10 | public class CustomIOHandler extends IOHandler 11 | { 12 | @Override 13 | public void onConnectionLocalOpen(Event event) 14 | { 15 | Connection connection = event.getConnection(); 16 | if (connection.getRemoteState() != EndpointState.UNINITIALIZED) 17 | { 18 | return; 19 | } 20 | 21 | Transport transport = Proton.transport(); 22 | transport.setMaxFrameSize(AmqpConstants.MAX_FRAME_SIZE); 23 | // To fix connection drops that the client recognizes only with a delay of 15 or 20 minutes 24 | transport.setIdleTimeout(60000); 25 | transport.sasl(); 26 | transport.setEmitFlowEventOnSend(false); 27 | transport.bind(connection); 28 | } 29 | 30 | @Override 31 | public void onTransportClosed(Event event) 32 | { 33 | if(event.getTransport() != null) 34 | { 35 | event.getTransport().unbind(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/amqp/DispatchHandler.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.amqp; 2 | 3 | import org.apache.qpid.proton.engine.BaseHandler; 4 | import org.apache.qpid.proton.engine.Event; 5 | 6 | public abstract class DispatchHandler extends BaseHandler 7 | { 8 | @Override public void onTimerTask(Event e) 9 | { 10 | this.onEvent(); 11 | } 12 | 13 | public abstract void onEvent(); 14 | } 15 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/amqp/IAmqpConnection.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.amqp; 6 | 7 | import org.apache.qpid.proton.amqp.transport.ErrorCondition; 8 | import org.apache.qpid.proton.engine.Link; 9 | 10 | public interface IAmqpConnection 11 | { 12 | String getHostName(); 13 | 14 | void onConnectionOpen(); 15 | 16 | void onConnectionError(ErrorCondition error); 17 | 18 | void registerForConnectionError(Link link); 19 | 20 | void deregisterForConnectionError(Link link); 21 | } 22 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/amqp/IAmqpLink.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.amqp; 6 | 7 | import org.apache.qpid.proton.amqp.transport.ErrorCondition; 8 | 9 | public interface IAmqpLink 10 | { 11 | /** 12 | * @param completionException completionException=null if open is successful 13 | */ 14 | void onOpenComplete(Exception completionException); 15 | 16 | void onError(Exception exception); 17 | 18 | void onClose(ErrorCondition condition); 19 | } 20 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/amqp/IAmqpReceiver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.amqp; 6 | 7 | import org.apache.qpid.proton.engine.Delivery; 8 | 9 | public interface IAmqpReceiver extends IAmqpLink 10 | { 11 | void onReceiveComplete(Delivery delivery); 12 | } 13 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/amqp/IAmqpSender.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.amqp; 6 | 7 | import org.apache.qpid.proton.engine.Delivery; 8 | 9 | public interface IAmqpSender extends IAmqpLink 10 | { 11 | void onFlow(final int creditIssued); 12 | 13 | void onSendComplete(final Delivery delivery); 14 | } 15 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/amqp/LoggingHandler.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.amqp; 2 | 3 | import org.apache.qpid.proton.engine.BaseHandler; 4 | import org.apache.qpid.proton.engine.Event; 5 | import org.apache.qpid.proton.engine.Event.Type; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | public class LoggingHandler extends BaseHandler { 10 | private static final Logger TRACE_LOGGER = LoggerFactory.getLogger(LoggingHandler.class); 11 | 12 | @Override 13 | public void onUnhandled(Event event) 14 | { 15 | if(TRACE_LOGGER.isTraceEnabled() && event.getType() != Type.REACTOR_QUIESCED ) // Too may REACTOR_QUIESCED events will be raised 16 | { 17 | TRACE_LOGGER.trace("Event raised by protonj: {}", event.toString()); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/amqp/ProtonUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.amqp; 6 | 7 | import java.io.IOException; 8 | import org.apache.qpid.proton.Proton; 9 | import org.apache.qpid.proton.reactor.Reactor; 10 | 11 | public final class ProtonUtil 12 | { 13 | private ProtonUtil() 14 | { 15 | } 16 | 17 | public static Reactor reactor(ReactorHandler reactorHandler) throws IOException 18 | { 19 | Reactor reactor = Proton.reactor(reactorHandler); 20 | reactor.setGlobalHandler(new CustomIOHandler()); 21 | reactor.getGlobalHandler().add(new LoggingHandler()); 22 | return reactor; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/amqp/ReactorDispatcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.amqp; 6 | 7 | import java.io.IOException; 8 | import java.nio.ByteBuffer; 9 | import java.nio.channels.ClosedChannelException; 10 | import java.nio.channels.Pipe; 11 | import java.util.concurrent.ConcurrentLinkedQueue; 12 | 13 | import org.apache.qpid.proton.engine.BaseHandler; 14 | import org.apache.qpid.proton.engine.Event; 15 | import org.apache.qpid.proton.Proton; 16 | import org.apache.qpid.proton.reactor.Reactor; 17 | import org.apache.qpid.proton.reactor.Selectable; 18 | import org.apache.qpid.proton.reactor.Selectable.Callback; 19 | 20 | /** 21 | * {@link Reactor} is not thread-safe - all calls to {@link Proton} API's should be - on the Reactor Thread. 22 | * {@link Reactor} works out-of-box for all event driven API - ex: onReceive - which could raise upon onSocketRead. 23 | * {@link Reactor} didn't support API's like Send() out-of-box - which could potentially run on different thread to that of Reactor. 24 | * So, the following utility class is used to generate an Event to hook into {@link Reactor}'s event delegation pattern. 25 | * It uses a {@link Pipe} as the IO on which Reactor Listens to. 26 | * Cardinality: multiple {@link ReactorDispatcher}'s could be attached to 1 {@link Reactor}. 27 | * Each {@link ReactorDispatcher} should be initialized Synchronously - as it calls API in {@link Reactor} which is not thread-safe. 28 | */ 29 | public final class ReactorDispatcher 30 | { 31 | private final Reactor reactor; 32 | private final Pipe ioSignal; 33 | private final ConcurrentLinkedQueue workQueue; 34 | private final ScheduleHandler workScheduler; 35 | 36 | public ReactorDispatcher(final Reactor reactor) throws IOException 37 | { 38 | this.reactor = reactor; 39 | this.ioSignal = Pipe.open(); 40 | this.workQueue = new ConcurrentLinkedQueue(); 41 | this.workScheduler = new ScheduleHandler(); 42 | 43 | initializeSelectable(); 44 | } 45 | 46 | private void initializeSelectable() 47 | { 48 | Selectable schedulerSelectable = this.reactor.selectable(); 49 | 50 | schedulerSelectable.setChannel(this.ioSignal.source()); 51 | schedulerSelectable.onReadable(this.workScheduler); 52 | schedulerSelectable.onFree(new CloseHandler()); 53 | 54 | schedulerSelectable.setReading(true); 55 | this.reactor.update(schedulerSelectable); 56 | } 57 | 58 | public void invoke(final DispatchHandler timerCallback) throws IOException 59 | { 60 | this.workQueue.offer(timerCallback); 61 | this.signalWorkQueue(); 62 | } 63 | 64 | public void invoke(final int delay, final DispatchHandler timerCallback) throws IOException 65 | { 66 | this.workQueue.offer(new DelayHandler(this.reactor, delay, timerCallback)); 67 | this.signalWorkQueue(); 68 | } 69 | 70 | private void signalWorkQueue() throws IOException 71 | { 72 | try 73 | { 74 | this.ioSignal.sink().write(ByteBuffer.allocate(1)); 75 | } 76 | catch(ClosedChannelException ignorePipeClosedDuringReactorShutdown) 77 | { 78 | } 79 | } 80 | 81 | private final class DelayHandler extends BaseHandler 82 | { 83 | final int delay; 84 | final BaseHandler timerCallback; 85 | final Reactor reactor; 86 | 87 | public DelayHandler(final Reactor reactor, final int delay, final DispatchHandler timerCallback) 88 | { 89 | this.delay = delay; 90 | this.timerCallback = timerCallback; 91 | this.reactor = reactor; 92 | } 93 | 94 | @Override 95 | public void onTimerTask(Event e) 96 | { 97 | this.reactor.schedule(this.delay, this.timerCallback); 98 | } 99 | } 100 | 101 | private final class ScheduleHandler implements Callback 102 | { 103 | @Override 104 | public void run(Selectable selectable) 105 | { 106 | try 107 | { 108 | ioSignal.source().read(ByteBuffer.allocate(1024)); 109 | } 110 | catch(ClosedChannelException ignorePipeClosedDuringReactorShutdown) 111 | { 112 | } 113 | catch(IOException ioException) 114 | { 115 | throw new RuntimeException(ioException); 116 | } 117 | 118 | BaseHandler topWork; 119 | while ((topWork = workQueue.poll()) != null) 120 | { 121 | topWork.onTimerTask(null); 122 | } 123 | } 124 | } 125 | 126 | private final class CloseHandler implements Callback 127 | { 128 | @Override 129 | public void run(Selectable selectable) 130 | { 131 | try 132 | { 133 | selectable.getChannel().close(); 134 | } 135 | catch (IOException ignore) 136 | { 137 | } 138 | 139 | try 140 | { 141 | if (ioSignal.sink().isOpen()) 142 | ioSignal.sink().close(); 143 | } 144 | catch (IOException ignore) 145 | { 146 | } 147 | 148 | workScheduler.run(null); 149 | 150 | try 151 | { 152 | if (ioSignal.source().isOpen()) 153 | ioSignal.source().close(); 154 | } 155 | catch (IOException ignore) 156 | { 157 | } 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/amqp/ReactorHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.amqp; 6 | 7 | import org.apache.qpid.proton.engine.BaseHandler; 8 | import org.apache.qpid.proton.engine.Event; 9 | import org.apache.qpid.proton.reactor.Reactor; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import com.microsoft.azure.servicebus.primitives.ClientConstants; 14 | 15 | public class ReactorHandler extends BaseHandler 16 | { 17 | private static final Logger TRACE_LOGGER = LoggerFactory.getLogger(ReactorHandler.class); 18 | 19 | @Override 20 | public void onReactorInit(Event e) 21 | { 22 | TRACE_LOGGER.debug("reactor.onReactorInit"); 23 | 24 | Reactor reactor = e.getReactor(); 25 | reactor.setTimeout(ClientConstants.REACTOR_IO_POLL_TIMEOUT); 26 | } 27 | 28 | @Override 29 | public void onReactorFinal(Event e) 30 | { 31 | TRACE_LOGGER.debug("reactor.onReactorFinal"); 32 | Reactor reactor = e.getReactor(); 33 | if(reactor != null) 34 | { 35 | reactor.attachments().clear(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/amqp/ReceiveLinkHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.amqp; 6 | 7 | import org.apache.qpid.proton.engine.Delivery; 8 | import org.apache.qpid.proton.engine.Event; 9 | import org.apache.qpid.proton.engine.Link; 10 | import org.apache.qpid.proton.engine.Receiver; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | // ServiceBus <-> ProtonReactor interaction 15 | // handles all recvLink - reactor events 16 | public final class ReceiveLinkHandler extends BaseLinkHandler 17 | { 18 | private static final Logger TRACE_LOGGER = LoggerFactory.getLogger(ReceiveLinkHandler.class); 19 | 20 | private final IAmqpReceiver amqpReceiver; 21 | private final Object firstResponse; 22 | private boolean isFirstResponse; 23 | 24 | public ReceiveLinkHandler(final IAmqpReceiver receiver) 25 | { 26 | super(receiver); 27 | 28 | this.amqpReceiver = receiver; 29 | this.firstResponse = new Object(); 30 | this.isFirstResponse = true; 31 | } 32 | 33 | @Override 34 | public void onLinkLocalOpen(Event evt) 35 | { 36 | Link link = evt.getLink(); 37 | if (link instanceof Receiver) 38 | { 39 | Receiver receiver = (Receiver) link; 40 | TRACE_LOGGER.debug("onLinkLocalOpen: linkName:{}, localSource:{}", receiver.getName(), receiver.getSource()); 41 | } 42 | } 43 | 44 | @Override 45 | public void onLinkRemoteOpen(Event event) 46 | { 47 | Link link = event.getLink(); 48 | if (link != null && link instanceof Receiver) 49 | { 50 | Receiver receiver = (Receiver) link; 51 | if (link.getRemoteSource() != null) 52 | { 53 | TRACE_LOGGER.debug("onLinkRemoteOpen: linkName:{}, remoteSource:{}", receiver.getName(), receiver.getRemoteSource()); 54 | 55 | synchronized (this.firstResponse) 56 | { 57 | this.isFirstResponse = false; 58 | this.amqpReceiver.onOpenComplete(null); 59 | } 60 | } 61 | else 62 | { 63 | TRACE_LOGGER.debug("onLinkRemoteOpen: linkName:{}, remoteSource:{}, remoteTarget:{}, action:{}", receiver.getName(), null, null, "waitingForError"); 64 | } 65 | } 66 | } 67 | 68 | @Override 69 | public void onDelivery(Event event) 70 | { 71 | synchronized (this.firstResponse) 72 | { 73 | if (this.isFirstResponse) 74 | { 75 | this.isFirstResponse = false; 76 | this.amqpReceiver.onOpenComplete(null); 77 | } 78 | } 79 | 80 | Delivery delivery = event.getDelivery(); 81 | Receiver receiveLink = (Receiver) delivery.getLink(); 82 | 83 | TRACE_LOGGER.debug("onDelivery: linkName:{}, updatedLinkCredit:{}, remoteCredit:{}, remoteCondition:{}, delivery.isPartial:{}", 84 | receiveLink.getName(), receiveLink.getCredit(), receiveLink.getRemoteCredit(), receiveLink.getRemoteCondition(), delivery.isPartial()); 85 | 86 | //TODO: What happens when a delivery has no message, but only disposition from the remote link? Like when ServiceBus service sends just a disposition to the receiver?" 87 | 88 | // If a message spans across deliveries (for ex: 200k message will be 4 frames (deliveries) 64k 64k 64k 8k), 89 | // all until "last-1" deliveries will be partial 90 | // reactor will raise onDelivery event for all of these - we only need the last one 91 | if (!delivery.isPartial()) 92 | { 93 | this.amqpReceiver.onReceiveComplete(delivery); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/amqp/SendLinkHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.amqp; 6 | 7 | import org.apache.qpid.proton.engine.Delivery; 8 | import org.apache.qpid.proton.engine.Event; 9 | import org.apache.qpid.proton.engine.Link; 10 | import org.apache.qpid.proton.engine.Sender; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | public class SendLinkHandler extends BaseLinkHandler 15 | { 16 | private static final Logger TRACE_LOGGER = LoggerFactory.getLogger(SendLinkHandler.class); 17 | 18 | private final IAmqpSender msgSender; 19 | private final Object firstFlow; 20 | private boolean isFirstFlow; 21 | 22 | public SendLinkHandler(final IAmqpSender sender) 23 | { 24 | super(sender); 25 | 26 | this.msgSender = sender; 27 | this.firstFlow = new Object(); 28 | this.isFirstFlow = true; 29 | } 30 | 31 | @Override 32 | public void onLinkRemoteOpen(Event event) 33 | { 34 | Link link = event.getLink(); 35 | if (link != null && link instanceof Sender) 36 | { 37 | Sender sender = (Sender) link; 38 | if (link.getRemoteTarget() != null) 39 | { 40 | TRACE_LOGGER.debug("onLinkRemoteOpen: linkName:{}, remoteTarge:{}", sender.getName(), link.getRemoteTarget()); 41 | 42 | synchronized (this.firstFlow) 43 | { 44 | this.isFirstFlow = false; 45 | this.msgSender.onOpenComplete(null); 46 | } 47 | } 48 | else 49 | { 50 | TRACE_LOGGER.debug("onLinkRemoteOpen: linkName:{}, remoteTarget:{}, remoteSource:{}, action:{}", sender.getName(), null, null, "waitingForError"); 51 | } 52 | } 53 | } 54 | 55 | @Override 56 | public void onDelivery(Event event) 57 | { 58 | Delivery delivery = event.getDelivery(); 59 | 60 | while (delivery != null) 61 | { 62 | Sender sender = (Sender) delivery.getLink(); 63 | 64 | TRACE_LOGGER.debug("onDelivery: linkName:{}, unsettled:{}, credit:{}, deliveryState:{}, delivery.isBuffered:{}, delivery.tag:{}", 65 | sender.getName(), sender.getUnsettled(), sender.getRemoteCredit(), delivery.getRemoteState(), delivery.isBuffered(), delivery.getTag()); 66 | 67 | msgSender.onSendComplete(delivery); 68 | delivery.settle(); 69 | 70 | delivery = sender.current(); 71 | } 72 | } 73 | 74 | @Override 75 | public void onLinkFlow(Event event) 76 | { 77 | if (this.isFirstFlow) 78 | { 79 | synchronized (this.firstFlow) 80 | { 81 | if (this.isFirstFlow) 82 | { 83 | this.msgSender.onOpenComplete(null); 84 | this.isFirstFlow = false; 85 | } 86 | } 87 | } 88 | 89 | Sender sender = event.getSender(); 90 | this.msgSender.onFlow(sender.getRemoteCredit()); 91 | 92 | TRACE_LOGGER.debug("onLinkFlow: linkName:{}, unsettled:{}, credit:{}", sender.getName(), sender.getUnsettled(), sender.getCredit()); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/amqp/SessionHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.amqp; 6 | 7 | import org.apache.qpid.proton.engine.BaseHandler; 8 | import org.apache.qpid.proton.engine.EndpointState; 9 | import org.apache.qpid.proton.engine.Event; 10 | import org.apache.qpid.proton.engine.Session; 11 | import org.slf4j.LoggerFactory; 12 | import org.slf4j.Logger; 13 | 14 | public class SessionHandler extends BaseHandler 15 | { 16 | protected static final Logger TRACE_LOGGER = LoggerFactory.getLogger(SessionHandler.class); 17 | 18 | private final String name; 19 | 20 | public SessionHandler(final String name) 21 | { 22 | this.name = name; 23 | } 24 | 25 | @Override 26 | public void onSessionRemoteOpen(Event e) 27 | { 28 | TRACE_LOGGER.debug("onSessionRemoteOpen - entityName: {}, sessionIncCapacity: {}, sessionOutgoingWindow: {}", this.name, e.getSession().getIncomingCapacity(), e.getSession().getOutgoingWindow()); 29 | 30 | Session session = e.getSession(); 31 | if (session != null && session.getLocalState() == EndpointState.UNINITIALIZED) 32 | { 33 | session.open(); 34 | } 35 | } 36 | 37 | 38 | @Override 39 | public void onSessionLocalClose(Event e) 40 | { 41 | TRACE_LOGGER.debug("onSessionLocalClose - entityName: {}, condition: {}", this.name, e.getSession().getCondition() == null ? "none" : e.getSession().getCondition().toString()); 42 | Session session = e.getSession(); 43 | if (session != null) 44 | { 45 | checkAndFreeSession(session); 46 | } 47 | } 48 | 49 | @Override 50 | public void onSessionRemoteClose(Event e) 51 | { 52 | TRACE_LOGGER.debug("onSessionRemoteClose - entityName: {}, condition: {}", this.name, e.getSession().getCondition() == null ? "none" : e.getSession().getCondition().toString()); 53 | 54 | Session session = e.getSession(); 55 | if (session != null) 56 | { 57 | if(session.getLocalState() != EndpointState.CLOSED) 58 | { 59 | session.close(); 60 | } 61 | 62 | checkAndFreeSession(session); 63 | } 64 | } 65 | 66 | @Override 67 | public void onSessionFinal(Event e) 68 | { 69 | TRACE_LOGGER.debug("onSessionFinal - entityName: {}", this.name); 70 | Session session = e.getSession(); 71 | if(session != null) 72 | { 73 | session.attachments().clear(); 74 | } 75 | } 76 | 77 | private static void checkAndFreeSession(Session session) 78 | { 79 | if(session.getLocalState() == EndpointState.CLOSED && session.getRemoteState() == EndpointState.CLOSED) 80 | { 81 | session.free(); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/amqp/StrictTLSContext.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.amqp; 2 | 3 | import java.security.Provider; 4 | 5 | import javax.net.ssl.SSLContext; 6 | import javax.net.ssl.SSLContextSpi; 7 | 8 | // Customer SSLContext that wraps around an SSLContext and removes SSLv2Hello protocol from every SSLEngine created. 9 | public class StrictTLSContext extends SSLContext{ 10 | 11 | protected StrictTLSContext(SSLContextSpi contextSpi, Provider provider, String protocol) { 12 | super(contextSpi, provider, protocol); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/amqp/StrictTLSContextSpi.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.amqp; 2 | 3 | import java.security.KeyManagementException; 4 | import java.security.SecureRandom; 5 | import java.util.ArrayList; 6 | 7 | import javax.net.ssl.KeyManager; 8 | import javax.net.ssl.SSLContext; 9 | import javax.net.ssl.SSLContextSpi; 10 | import javax.net.ssl.SSLEngine; 11 | import javax.net.ssl.SSLServerSocketFactory; 12 | import javax.net.ssl.SSLSessionContext; 13 | import javax.net.ssl.SSLSocketFactory; 14 | import javax.net.ssl.TrustManager; 15 | 16 | // Wraps over a standard SSL context and disables the SSLv2Hello protocol. 17 | public class StrictTLSContextSpi extends SSLContextSpi{ 18 | 19 | private static final String SSLv2Hello = "SSLv2Hello"; 20 | 21 | SSLContext innerContext; 22 | public StrictTLSContextSpi(SSLContext innerContext) { 23 | this.innerContext = innerContext; 24 | } 25 | 26 | @Override 27 | protected SSLEngine engineCreateSSLEngine() { 28 | SSLEngine engine = this.innerContext.createSSLEngine(); 29 | this.removeSSLv2Hello(engine); 30 | return engine; 31 | } 32 | 33 | @Override 34 | protected SSLEngine engineCreateSSLEngine(String arg0, int arg1) { 35 | SSLEngine engine = this.innerContext.createSSLEngine(arg0, arg1); 36 | this.removeSSLv2Hello(engine); 37 | return engine; 38 | } 39 | 40 | @Override 41 | protected SSLSessionContext engineGetClientSessionContext() { 42 | return innerContext.getClientSessionContext(); 43 | } 44 | 45 | @Override 46 | protected SSLSessionContext engineGetServerSessionContext() { 47 | return this.innerContext.getServerSessionContext(); 48 | } 49 | 50 | @Override 51 | protected SSLServerSocketFactory engineGetServerSocketFactory() { 52 | return this.innerContext.getServerSocketFactory(); 53 | } 54 | 55 | @Override 56 | protected SSLSocketFactory engineGetSocketFactory() { 57 | return this.innerContext.getSocketFactory(); 58 | } 59 | 60 | @Override 61 | protected void engineInit(KeyManager[] km, TrustManager[] tm, SecureRandom sr) throws KeyManagementException { 62 | this.innerContext.init(km, tm, sr); 63 | } 64 | 65 | private void removeSSLv2Hello(SSLEngine engine) 66 | { 67 | String[] enabledProtocols = engine.getEnabledProtocols(); 68 | boolean sslv2HelloFound = false; 69 | for(String protocol : enabledProtocols) 70 | { 71 | if(protocol.equalsIgnoreCase(SSLv2Hello)) 72 | { 73 | sslv2HelloFound = true; 74 | break; 75 | } 76 | } 77 | 78 | if(sslv2HelloFound) 79 | { 80 | ArrayList modifiedProtocols = new ArrayList(); 81 | for(String protocol : enabledProtocols) 82 | { 83 | if(!protocol.equalsIgnoreCase(SSLv2Hello)) 84 | { 85 | modifiedProtocols.add(protocol); 86 | } 87 | } 88 | 89 | engine.setEnabledProtocols(modifiedProtocols.toArray(new String[modifiedProtocols.size()])); 90 | } 91 | 92 | 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/AsyncUtil.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.primitives; 2 | 3 | import java.util.concurrent.Callable; 4 | import java.util.concurrent.CompletableFuture; 5 | import java.util.concurrent.ExecutionException; 6 | 7 | // To complete futures using a different thread. Otherwise every future is completed on the single reactor thread 8 | // which badly affects perf and a client can potentially kill the thread or lock the thread. 9 | class AsyncUtil { 10 | 11 | public static boolean completeFutureAndGetStatus(CompletableFuture future, T result) 12 | { 13 | try { 14 | return MessagingFactory.INTERNAL_THREAD_POOL.submit(new CompleteCallable(future, result)).get(); 15 | } catch (InterruptedException | ExecutionException e) { 16 | e.printStackTrace(); 17 | return false; 18 | } 19 | } 20 | 21 | public static void completeFuture(CompletableFuture future, T result) 22 | { 23 | MessagingFactory.INTERNAL_THREAD_POOL.submit(new CompleteCallable(future, result)); 24 | } 25 | 26 | public static boolean completeFutureExceptionallyAndGetStatus(CompletableFuture future, Throwable exception) 27 | { 28 | try { 29 | return MessagingFactory.INTERNAL_THREAD_POOL.submit(new CompleteExceptionallyCallable(future, exception)).get(); 30 | } catch (InterruptedException | ExecutionException e) { 31 | e.printStackTrace(); 32 | return false; 33 | } 34 | } 35 | 36 | public static void completeFutureExceptionally(CompletableFuture future, Throwable exception) 37 | { 38 | MessagingFactory.INTERNAL_THREAD_POOL.submit(new CompleteExceptionallyCallable(future, exception)); 39 | } 40 | 41 | public static void run(Runnable runnable) 42 | { 43 | MessagingFactory.INTERNAL_THREAD_POOL.submit(runnable); 44 | } 45 | 46 | private static class CompleteCallable implements Callable 47 | { 48 | private CompletableFuture future; 49 | private T result; 50 | 51 | CompleteCallable(CompletableFuture future, T result) 52 | { 53 | this.future = future; 54 | this.result = result; 55 | } 56 | 57 | @Override 58 | public Boolean call() throws Exception { 59 | return this.future.complete(this.result); 60 | } 61 | } 62 | 63 | private static class CompleteExceptionallyCallable implements Callable 64 | { 65 | private CompletableFuture future; 66 | private Throwable exception; 67 | 68 | CompleteExceptionallyCallable(CompletableFuture future, Throwable exception) 69 | { 70 | this.future = future; 71 | this.exception = exception; 72 | } 73 | 74 | @Override 75 | public Boolean call() throws Exception { 76 | return this.future.completeExceptionally(this.exception); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/AuthorizationFailedException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.primitives; 6 | 7 | /** 8 | * Authorization failed exception is thrown when error is encountered during authorizing user's permission to run the intended operations. 9 | * When encountered this exception user should check whether the token/key provided in the connection string is valid, and has correct 10 | * execution right for the intended operations (e.g. Receive call will need Listen claim associated with the key/token). 11 | * @see http://go.microsoft.com/fwlink/?LinkId=761101 12 | * @since 1.0 13 | */ 14 | public class AuthorizationFailedException extends ServiceBusException 15 | { 16 | private static final long serialVersionUID = 5384872132102860710L; 17 | 18 | AuthorizationFailedException() 19 | { 20 | super(false); 21 | } 22 | 23 | /** 24 | * Constructor for the exception class 25 | * @param message the actual error message detailing the reason for the failure 26 | */ 27 | public AuthorizationFailedException(final String message) 28 | { 29 | super(false, message); 30 | } 31 | 32 | AuthorizationFailedException(final Throwable cause) 33 | { 34 | super(false, cause); 35 | } 36 | 37 | AuthorizationFailedException(final String message, final Throwable cause) 38 | { 39 | super(false, message, cause); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/ClientEntity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.primitives; 6 | 7 | import java.util.Locale; 8 | import java.util.concurrent.CompletableFuture; 9 | import java.util.concurrent.ExecutionException; 10 | 11 | /** 12 | * Contract for all client entities with Open-Close/Abort state m/c

13 | * main-purpose: closeAll related entities

14 | * Internal-class 15 | * @since 1.0 16 | */ 17 | public abstract class ClientEntity 18 | { 19 | private final String clientId; 20 | private final Object syncClose; 21 | 22 | private boolean isClosing; 23 | private boolean isClosed; 24 | 25 | protected ClientEntity(final String clientId) 26 | { 27 | this.clientId = clientId; 28 | this.syncClose = new Object(); 29 | } 30 | 31 | protected abstract CompletableFuture onClose(); 32 | 33 | public String getClientId() 34 | { 35 | return this.clientId; 36 | } 37 | 38 | protected boolean getIsClosed() 39 | { 40 | synchronized (this.syncClose) 41 | { 42 | return this.isClosed; 43 | } 44 | } 45 | 46 | protected boolean getIsClosingOrClosed() 47 | { 48 | 49 | synchronized (this.syncClose) 50 | { 51 | return this.isClosing || this.isClosed; 52 | } 53 | } 54 | 55 | // used to force close when entity is faulted 56 | protected final void setClosed() 57 | { 58 | synchronized (this.syncClose) 59 | { 60 | this.isClosing = false; 61 | this.isClosed = true; 62 | } 63 | } 64 | 65 | protected final void setClosing() 66 | { 67 | synchronized (this.syncClose) 68 | { 69 | if (!this.isClosed) { 70 | this.isClosing = true; 71 | } 72 | } 73 | } 74 | 75 | public final CompletableFuture closeAsync() 76 | { 77 | if(this.getIsClosingOrClosed()) 78 | { 79 | return CompletableFuture.completedFuture(null); 80 | } 81 | 82 | synchronized (this.syncClose) 83 | { 84 | this.isClosing = true; 85 | } 86 | 87 | return this.onClose().thenRunAsync(new Runnable() 88 | { 89 | @Override 90 | public void run() 91 | { 92 | synchronized (ClientEntity.this.syncClose) 93 | { 94 | ClientEntity.this.isClosing = false; 95 | ClientEntity.this.isClosed = true; 96 | } 97 | }}, MessagingFactory.INTERNAL_THREAD_POOL); 98 | } 99 | 100 | public final void close() throws ServiceBusException 101 | { 102 | try 103 | { 104 | this.closeAsync().get(); 105 | } 106 | catch (InterruptedException|ExecutionException exception) 107 | { 108 | if (exception instanceof InterruptedException) 109 | { 110 | // Re-assert the thread's interrupted status 111 | Thread.currentThread().interrupt(); 112 | } 113 | 114 | Throwable throwable = exception.getCause(); 115 | if (throwable != null) 116 | { 117 | if (throwable instanceof RuntimeException) 118 | { 119 | throw (RuntimeException)throwable; 120 | } 121 | 122 | if (throwable instanceof ServiceBusException) 123 | { 124 | throw (ServiceBusException)throwable; 125 | } 126 | 127 | throw new ServiceBusException(true, throwable); 128 | } 129 | } 130 | } 131 | 132 | protected final void throwIfClosed(Throwable cause) 133 | { 134 | if (this.getIsClosingOrClosed()) 135 | { 136 | throw new IllegalStateException(String.format(Locale.US, "Operation not allowed after the %s instance is closed.", this.getClass().getName()), cause); 137 | } 138 | } 139 | 140 | @Override 141 | protected void finalize() throws Throwable { 142 | if (!this.getIsClosingOrClosed()) { 143 | this.closeAsync(); 144 | } 145 | super.finalize(); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/CommunicationException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.primitives; 6 | 7 | /** 8 | * This exception is thrown when there is a client side connectivity issue. When receiving this exception user should 9 | * check client connectivity settings to the service: 10 | *

    11 | *
  • Check for correct hostname and port number used in endpoint. 12 | *
  • Check for any possible proxy settings that can block amqp ports 13 | *
  • Check for any firewall settings that can block amqp ports 14 | *
  • Check for any general network connectivity issues, as well as network latency. 15 | *
16 | * @see http://go.microsoft.com/fwlink/?LinkId=761101 17 | * @since 1.0 18 | */ 19 | public class CommunicationException extends ServiceBusException 20 | { 21 | private static final long serialVersionUID = 7968596830506494332L; 22 | 23 | CommunicationException() 24 | { 25 | super(true); 26 | } 27 | 28 | CommunicationException(final String message) 29 | { 30 | super(true, message); 31 | } 32 | 33 | CommunicationException(final Throwable cause) 34 | { 35 | super(true, cause); 36 | } 37 | 38 | CommunicationException(final String message, final Throwable cause) 39 | { 40 | super(true, message, cause); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/ErrorContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.primitives; 6 | 7 | import java.util.Locale; 8 | 9 | abstract class ErrorContext 10 | { 11 | private final String namespaceName; 12 | 13 | ErrorContext(final String namespaceName) 14 | { 15 | this.namespaceName = namespaceName; 16 | } 17 | 18 | protected String getNamespaceName() 19 | { 20 | return this.namespaceName; 21 | } 22 | 23 | @Override 24 | public String toString() 25 | { 26 | return StringUtil.isNullOrEmpty(this.namespaceName) ? null : String.format(Locale.US, "NS: %s", this.namespaceName); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/IErrorContextProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.primitives; 6 | 7 | interface IErrorContextProvider 8 | { 9 | ErrorContext getContext(); 10 | } 11 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/IllegalConnectionStringFormatException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.primitives; 6 | 7 | /** 8 | * This exception is thrown when the connection string provided does not meet the requirement for connection. 9 | * @since 1.0 10 | */ 11 | public class IllegalConnectionStringFormatException extends IllegalArgumentException 12 | { 13 | private static final long serialVersionUID = 2514898858133972030L; 14 | 15 | IllegalConnectionStringFormatException() 16 | { 17 | } 18 | 19 | IllegalConnectionStringFormatException(String detail) 20 | { 21 | super(detail); 22 | } 23 | 24 | IllegalConnectionStringFormatException(Throwable cause) 25 | { 26 | super(cause); 27 | } 28 | 29 | IllegalConnectionStringFormatException(String detail, Throwable cause) 30 | { 31 | super(detail, cause); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/IteratorUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.primitives; 6 | 7 | import java.util.Iterator; 8 | 9 | final class IteratorUtil 10 | { 11 | private IteratorUtil() 12 | { 13 | } 14 | 15 | public static boolean sizeEquals(Iterable iterable, int expectedSize) 16 | { 17 | Iterator iterator = iterable.iterator(); 18 | 19 | int currentSize = 0; 20 | while(iterator.hasNext()) 21 | { 22 | if (expectedSize > currentSize) 23 | { 24 | currentSize++; 25 | iterator.next(); 26 | continue; 27 | } 28 | else 29 | { 30 | return false; 31 | } 32 | } 33 | 34 | return true; 35 | } 36 | 37 | public static T getLast(Iterator iterator) 38 | { 39 | T last = null; 40 | while(iterator.hasNext()) 41 | { 42 | last = iterator.next(); 43 | } 44 | 45 | return last; 46 | } 47 | 48 | public static T getFirst(final Iterable iterable) 49 | { 50 | if (iterable == null) 51 | { 52 | return null; 53 | } 54 | 55 | final Iterator iterator = iterable.iterator(); 56 | if (iterator == null) 57 | { 58 | return null; 59 | } 60 | 61 | return iterator.hasNext() ? iterator.next() : null; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/MessageLockLostException.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.primitives; 2 | 3 | /** 4 | * This exception is thrown when a receiver attempts complete or abandon or renew-lock or deadLetter or defer operation 5 | * on a peek-locked message whose lock had already expired. 6 | * @since 1.0 7 | * 8 | */ 9 | public class MessageLockLostException extends ServiceBusException { 10 | 11 | private static final long serialVersionUID = -203350475131556600L; 12 | 13 | public MessageLockLostException() 14 | { 15 | super(false); 16 | } 17 | 18 | public MessageLockLostException(String message) 19 | { 20 | super(false, message); 21 | } 22 | 23 | public MessageLockLostException(Throwable cause) 24 | { 25 | super(false, cause); 26 | } 27 | 28 | public MessageLockLostException(String message, Throwable cause) 29 | { 30 | super(false, message, cause); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/MessageNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.primitives; 2 | 3 | /** 4 | * This exception is thrown when a receiver attempts to receive a message with sequence number and the message with that sequence number is not available in the queue or subscription. 5 | * @since 1.0 6 | * 7 | */ 8 | public class MessageNotFoundException extends ServiceBusException { 9 | 10 | private static final long serialVersionUID = -7138414297734634975L; 11 | 12 | public MessageNotFoundException() 13 | { 14 | super(false); 15 | } 16 | 17 | public MessageNotFoundException(String message) 18 | { 19 | super(false, message); 20 | } 21 | 22 | public MessageNotFoundException(Throwable cause) 23 | { 24 | super(false, cause); 25 | } 26 | 27 | public MessageNotFoundException(String message, Throwable cause) 28 | { 29 | super(false, message, cause); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/MessageWithDeliveryTag.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.primitives; 2 | 3 | import org.apache.qpid.proton.message.Message; 4 | 5 | public class MessageWithDeliveryTag { 6 | private final Message message; 7 | private final byte[] deliveryTag; 8 | 9 | public MessageWithDeliveryTag(Message message, byte[] deliveryTag) 10 | { 11 | this.message = message; 12 | this.deliveryTag = deliveryTag; 13 | } 14 | 15 | public Message getMessage() { 16 | return message; 17 | } 18 | 19 | public byte[] getDeliveryTag() { 20 | return deliveryTag; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/MessageWithLockToken.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.primitives; 2 | 3 | import java.util.UUID; 4 | 5 | import org.apache.qpid.proton.message.Message; 6 | 7 | public class MessageWithLockToken { 8 | private final Message message; 9 | private final UUID lockToken; 10 | 11 | public MessageWithLockToken(Message message, UUID lockToken) 12 | { 13 | this.message = message; 14 | this.lockToken = lockToken; 15 | } 16 | 17 | public Message getMessage() { 18 | return message; 19 | } 20 | 21 | public UUID getLockToken() { 22 | return lockToken; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/MessagingEntityAlreadyExistsException.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.primitives; 2 | 3 | /** 4 | * This exception is thrown when a subscription client tries to create a rule with the name of an already existing rule. 5 | * @since 1.0 6 | * 7 | */ 8 | public class MessagingEntityAlreadyExistsException extends ServiceBusException { 9 | 10 | private static final long serialVersionUID = -3652949479773950838L; 11 | 12 | public MessagingEntityAlreadyExistsException(String message) 13 | { 14 | super(false, message); 15 | } 16 | 17 | public MessagingEntityAlreadyExistsException(String message, Throwable cause) 18 | { 19 | super(false, message, cause); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/MessagingEntityDisabledException.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.primitives; 2 | 3 | /** 4 | * This exception is thrown when a client attempts to send messages to or receive messages from a disabled entity. An entity can be disabled for SEND operations or RECEIVE operations or both. 5 | * @since 1.0 6 | * 7 | */ 8 | public class MessagingEntityDisabledException extends ServiceBusException{ 9 | 10 | private static final long serialVersionUID = 9086472912026637605L; 11 | 12 | public MessagingEntityDisabledException() 13 | { 14 | super(false); 15 | } 16 | 17 | public MessagingEntityDisabledException(String message) 18 | { 19 | super(false, message); 20 | } 21 | 22 | public MessagingEntityDisabledException(Throwable cause) 23 | { 24 | super(false, cause); 25 | } 26 | 27 | public MessagingEntityDisabledException(String message, Throwable cause) 28 | { 29 | super(false, message, cause); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/MessagingEntityNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.primitives; 2 | 3 | /** 4 | * This exception is thrown when a client attempts to create a sender or receiver or client to a non existent entity. 5 | * @since 1.0 6 | * 7 | */ 8 | public class MessagingEntityNotFoundException extends ServiceBusException { 9 | 10 | private static final long serialVersionUID = -4624769494653591824L; 11 | 12 | public MessagingEntityNotFoundException() 13 | { 14 | super(false); 15 | } 16 | 17 | public MessagingEntityNotFoundException(String message) 18 | { 19 | super(false, message); 20 | } 21 | 22 | public MessagingEntityNotFoundException(Throwable cause) 23 | { 24 | super(false, cause); 25 | } 26 | 27 | public MessagingEntityNotFoundException(String message, Throwable cause) 28 | { 29 | super(false, message, cause); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/MessagingEntityType.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.primitives; 2 | 3 | // For internal use only. 4 | // Integers are to achieve parity with .net enums which are integer by default 5 | public enum MessagingEntityType { 6 | QUEUE(0), 7 | TOPIC(1), 8 | SUBSCRIPTION(2), 9 | FILTER(3); 10 | 11 | private int enumValue; 12 | MessagingEntityType(int enumValue) 13 | { 14 | this.enumValue = enumValue; 15 | } 16 | 17 | public int getIntValue() 18 | { 19 | return this.enumValue; 20 | } 21 | } -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/OperationCancelledException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.primitives; 6 | 7 | /** 8 | * This exception is thrown when the underlying Amqp layer encounter an abnormal link abort or disconnect of connection in an unexpected fashion. 9 | * @since 1.0 10 | */ 11 | public class OperationCancelledException extends ServiceBusException 12 | { 13 | private static final long serialVersionUID = 1L; 14 | 15 | OperationCancelledException() 16 | { 17 | super(false); 18 | } 19 | 20 | public OperationCancelledException(final String message) 21 | { 22 | super(false, message); 23 | } 24 | 25 | OperationCancelledException(final Throwable cause) 26 | { 27 | super(false, cause); 28 | } 29 | 30 | OperationCancelledException(final String message, final Throwable cause) 31 | { 32 | super(false, message, cause); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/Pair.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.primitives; 2 | 3 | // Utility class to encapsulate any pair 4 | public class Pair 5 | { 6 | private T t; 7 | private V v; 8 | 9 | Pair(T t, V v) 10 | { 11 | this.t= t; 12 | this.v = v; 13 | } 14 | 15 | public T getFirstItem() { 16 | return t; 17 | } 18 | 19 | public V getSecondItem() { 20 | return v; 21 | } 22 | 23 | @Override 24 | public int hashCode() { 25 | final int prime = 31; 26 | int result = 1; 27 | result = prime * result + ((t == null) ? 0 : t.hashCode()); 28 | result = prime * result + ((v == null) ? 0 : v.hashCode()); 29 | return result; 30 | } 31 | 32 | @Override 33 | public boolean equals(Object obj) { 34 | if (this == obj) 35 | return true; 36 | if (obj == null) 37 | return false; 38 | if (getClass() != obj.getClass()) 39 | return false; 40 | Pair other = (Pair) obj; 41 | if (t == null) { 42 | if (other.t != null) 43 | return false; 44 | } else if (!t.equals(other.t)) 45 | return false; 46 | if (v == null) { 47 | if (other.v != null) 48 | return false; 49 | } else if (!v.equals(other.v)) 50 | return false; 51 | return true; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/PayloadSizeExceededException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.primitives; 6 | 7 | /** 8 | * this exception is thrown when user attempts to send a event data or brokered message that has exceeded the 9 | * allowed payload size as defined by the service. Note that in a batch send scenario the limit can include possible 10 | * batch overhead. 11 | * @see http://go.microsoft.com/fwlink/?LinkId=761101 12 | * @since 1.0 13 | */ 14 | public class PayloadSizeExceededException extends ServiceBusException 15 | { 16 | private static final long serialVersionUID = 3627182744252750014L; 17 | 18 | PayloadSizeExceededException() 19 | { 20 | super(false); 21 | } 22 | 23 | PayloadSizeExceededException(final String message) 24 | { 25 | super(false, message); 26 | } 27 | 28 | PayloadSizeExceededException(final Throwable cause) 29 | { 30 | super(false, cause); 31 | } 32 | 33 | PayloadSizeExceededException(final String message, final Throwable cause) 34 | { 35 | super(false, message, cause); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/QuotaExceededException.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.primitives; 2 | 3 | /** 4 | * This exception is thrown to signal that a service bus entity or namespace exceeded its quota. A quota can be a limit on entity size, message size, maximum concurrent connections or 5 | * maximum concurrent operations. 6 | * @since 1.0 7 | * 8 | */ 9 | public class QuotaExceededException extends ServiceBusException { 10 | 11 | private static final long serialVersionUID = -6963913971977282430L; 12 | 13 | public QuotaExceededException() 14 | { 15 | super(false); 16 | } 17 | 18 | public QuotaExceededException(String message) 19 | { 20 | super(false, message); 21 | } 22 | 23 | public QuotaExceededException(Throwable cause) 24 | { 25 | super(false, cause); 26 | } 27 | 28 | public QuotaExceededException(String message, Throwable cause) 29 | { 30 | super(false, message, cause); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/ReceiveWorkItem.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.primitives; 2 | 3 | import java.time.Duration; 4 | import java.util.Collection; 5 | import java.util.concurrent.CompletableFuture; 6 | 7 | class ReceiveWorkItem extends WorkItem> 8 | { 9 | private final int maxMessageCount; 10 | 11 | public ReceiveWorkItem(CompletableFuture> completableFuture, Duration timeout, final int maxMessageCount) 12 | { 13 | super(completableFuture, timeout); 14 | this.maxMessageCount = maxMessageCount; 15 | } 16 | 17 | public int getMaxMessageCount() 18 | { 19 | return this.maxMessageCount; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/ReceiverDisconnectedException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.primitives; 6 | 7 | /** 8 | * This exception is thrown when a EventHubReceiver is being disconnected because of one of the 9 | * following reason: 10 | *
    11 | *
  • user attempts to connect a non-epoch receiver to a event hub partition, when there is an epoch receiver connected to the partition. 12 | *
  • you are using an epoch receiver for a given partition but another epoch receiver with a higher epoch value connects to the same partition. 13 | *
14 | * User should make sure either all code are using non-epoch receivers, or ensure that there is only one epoch receiver processing a given partition 15 | * at any given point in time. 16 | * @see http://go.microsoft.com/fwlink/?LinkId=761101 17 | * @since 1.0 18 | */ 19 | public class ReceiverDisconnectedException extends ServiceBusException 20 | { 21 | private static final long serialVersionUID = 3385140843418138213L; 22 | 23 | ReceiverDisconnectedException() 24 | { 25 | super(false); 26 | } 27 | 28 | ReceiverDisconnectedException(final String message) 29 | { 30 | super(false, message); 31 | } 32 | 33 | ReceiverDisconnectedException(final Throwable cause) 34 | { 35 | super(false, cause); 36 | } 37 | 38 | ReceiverDisconnectedException(final String message, final Throwable cause) 39 | { 40 | super(false, message, cause); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/ReceiverErrorContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.primitives; 6 | 7 | import java.util.Locale; 8 | 9 | public class ReceiverErrorContext extends ErrorContext 10 | { 11 | final static boolean EPOCH_RECEIVER_TYPE = true; 12 | final static boolean NON_EPOCH_RECEIVER_TYPE = !ReceiverErrorContext.EPOCH_RECEIVER_TYPE; 13 | 14 | final String receivePath; 15 | final String referenceId; 16 | final Integer prefetchCount; 17 | final Integer currentLinkCredit; 18 | final Integer prefetchQueueLength; 19 | 20 | ReceiverErrorContext( 21 | final String namespaceName, 22 | final String receivePath, 23 | final String referenceId, 24 | final Integer prefetchCount, 25 | final Integer currentLinkCredit, 26 | final Integer prefetchQueueLength) 27 | { 28 | super(namespaceName); 29 | this.receivePath = receivePath; 30 | this.referenceId = referenceId; 31 | this.prefetchCount = prefetchCount; 32 | this.currentLinkCredit = currentLinkCredit; 33 | this.prefetchQueueLength = prefetchQueueLength; 34 | } 35 | 36 | @Override 37 | public String toString() 38 | { 39 | final String superString = super.toString(); 40 | StringBuilder toString = new StringBuilder(); 41 | 42 | if (!StringUtil.isNullOrEmpty(superString)) 43 | { 44 | toString.append(superString); 45 | toString.append(", "); 46 | } 47 | 48 | if (this.receivePath != null) 49 | { 50 | toString.append(String.format(Locale.US, "PATH: %s", this.receivePath)); 51 | toString.append(", "); 52 | } 53 | 54 | if (this.referenceId != null) 55 | { 56 | toString.append(String.format(Locale.US, "REFERENCE_ID: %s", this.referenceId)); 57 | toString.append(", "); 58 | } 59 | 60 | if (this.prefetchCount != null) 61 | { 62 | toString.append(String.format(Locale.US, "PREFETCH_COUNT: %s", this.prefetchCount)); 63 | toString.append(", "); 64 | } 65 | 66 | if (this.currentLinkCredit != null) 67 | { 68 | toString.append(String.format(Locale.US, "LINK_CREDIT: %s", this.currentLinkCredit)); 69 | toString.append(", "); 70 | } 71 | 72 | if (this.prefetchQueueLength != null) 73 | { 74 | toString.append(String.format(Locale.US, "PREFETCH_Q_LEN: %s", this.prefetchQueueLength)); 75 | toString.append(", "); 76 | } 77 | 78 | if (toString.length() > 2) 79 | { 80 | toString.setLength(toString.length() - 2); 81 | } 82 | 83 | return toString.toString(); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/RequestResponseWorkItem.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.primitives; 2 | 3 | import java.time.Duration; 4 | import java.util.concurrent.CompletableFuture; 5 | 6 | import org.apache.qpid.proton.message.Message; 7 | 8 | public class RequestResponseWorkItem extends WorkItem 9 | { 10 | Message request; 11 | 12 | public RequestResponseWorkItem(Message request, CompletableFuture completableFuture, TimeoutTracker tracker) { 13 | super(completableFuture, tracker); 14 | this.request = request; 15 | } 16 | 17 | public RequestResponseWorkItem(Message request, CompletableFuture completableFuture, Duration timeout) { 18 | super(completableFuture, timeout); 19 | this.request = request; 20 | } 21 | 22 | public Message getRequest() 23 | { 24 | return this.request; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/RetryExponential.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.primitives; 6 | 7 | import java.time.Duration; 8 | 9 | /** 10 | * RetryPolicy implementation where the delay between retries will grow in an exponential manner. 11 | * RetryPolicy can be set on the client operations using {@link ConnectionStringBuilder}. 12 | * RetryIntervals will be computed using a retryFactor which is a function of deltaBackOff (MaximumBackoff - MinimumBackoff) and MaximumRetryCount 13 | * @since 1.0 14 | */ 15 | public final class RetryExponential extends RetryPolicy 16 | { 17 | private final Duration minimumBackoff; 18 | private final Duration maximumBackoff; 19 | private final int maximumRetryCount; 20 | private final double retryFactor; 21 | 22 | public RetryExponential(final Duration minimumBackoff, final Duration maximumBackoff, final int maximumRetryCount, final String name) 23 | { 24 | super(name); 25 | 26 | this.minimumBackoff = minimumBackoff; 27 | this.maximumBackoff = maximumBackoff; 28 | this.maximumRetryCount = maximumRetryCount; 29 | this.retryFactor = this.computeRetryFactor(); 30 | } 31 | 32 | @Override 33 | protected Duration onGetNextRetryInterval(final String clientId, final Exception lastException, final Duration remainingTime, final int baseWaitTimeSecs) 34 | { 35 | int currentRetryCount = this.getRetryCount(clientId); 36 | 37 | if (currentRetryCount >= this.maximumRetryCount) 38 | { 39 | return null; 40 | } 41 | 42 | double nextRetryInterval = Math.pow(this.retryFactor, (double)currentRetryCount); 43 | long nextRetryIntervalSeconds = (long) nextRetryInterval ; 44 | long nextRetryIntervalNano = (long)((nextRetryInterval - (double)nextRetryIntervalSeconds) * 1000000000); 45 | if (remainingTime.getSeconds() < Math.max(nextRetryInterval, ClientConstants.TIMER_TOLERANCE.getSeconds())) 46 | { 47 | return null; 48 | } 49 | 50 | Duration retryAfter = this.minimumBackoff.plus(Duration.ofSeconds(nextRetryIntervalSeconds, nextRetryIntervalNano)); 51 | retryAfter = retryAfter.plus(Duration.ofSeconds(baseWaitTimeSecs)); 52 | 53 | return retryAfter; 54 | } 55 | 56 | private double computeRetryFactor() 57 | { 58 | long deltaBackoff = this.maximumBackoff.minus(this.minimumBackoff).getSeconds(); 59 | if (deltaBackoff <= 0 || this.maximumRetryCount <= 0) 60 | { 61 | return 0; 62 | } 63 | 64 | return (Math.log(deltaBackoff) / Math.log(this.maximumRetryCount)); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/SASUtil.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.primitives; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.net.URLEncoder; 5 | import java.nio.charset.StandardCharsets; 6 | import java.security.InvalidKeyException; 7 | import java.security.NoSuchAlgorithmException; 8 | import java.time.Instant; 9 | import java.util.Base64; 10 | import java.util.Locale; 11 | 12 | import javax.crypto.Mac; 13 | import javax.crypto.spec.SecretKeySpec; 14 | 15 | import org.slf4j.Logger; 16 | import org.slf4j.LoggerFactory; 17 | import org.slf4j.Marker; 18 | import org.slf4j.MarkerFactory; 19 | 20 | /** 21 | * 22 | * @deprecated Use {@link com.microsoft.azure.servicebus.security.SharedAccessSignatureTokenProvider} 23 | * 24 | */ 25 | @Deprecated 26 | public class SASUtil { 27 | private static final Logger TRACE_LOGGER = LoggerFactory.getLogger(SASUtil.class); 28 | private static final String SAS_FORMAT = "SharedAccessSignature sr=%s&sig=%s&se=%s&skn=%s"; 29 | private static final String HMACAlgorithm = "HMACSHA256"; 30 | private static final Base64.Encoder base64Encoder = Base64.getEncoder(); 31 | 32 | public static String generateSharedAccessSignatureToken(String sasKeyName, String sasKey, String resourceURI, int validityInSeconds) throws InvalidKeyException 33 | { 34 | if(StringUtil.isNullOrWhiteSpace(sasKey)) 35 | { 36 | throw new IllegalArgumentException("Invalid SAS key"); 37 | } 38 | 39 | if(StringUtil.isNullOrWhiteSpace(resourceURI)) 40 | { 41 | throw new IllegalArgumentException("Invalid resourceURI"); 42 | } 43 | 44 | if(validityInSeconds <= 0) 45 | { 46 | throw new IllegalArgumentException("validityInSeconds should be positive"); 47 | } 48 | 49 | String validUntil = String.valueOf(Instant.now().getEpochSecond() + validityInSeconds); 50 | try 51 | { 52 | String utf8EncodingName = StandardCharsets.UTF_8.name(); 53 | String encodedResourceURI = URLEncoder.encode(resourceURI, utf8EncodingName); 54 | String secretToSign = encodedResourceURI + "\n" + validUntil; 55 | Mac hmac = Mac.getInstance(HMACAlgorithm); 56 | SecretKeySpec secretKey = new SecretKeySpec(StringUtil.convertStringToBytes(sasKey), HMACAlgorithm); 57 | hmac.init(secretKey); 58 | byte[] signatureBytes = hmac.doFinal(StringUtil.convertStringToBytes(secretToSign)); 59 | String signature = base64Encoder.encodeToString(signatureBytes); 60 | TRACE_LOGGER.debug("Generated SAS token for resource: {} with sas key name : {}", resourceURI, sasKeyName); 61 | return String.format(Locale.US, SAS_FORMAT, 62 | encodedResourceURI, 63 | URLEncoder.encode(signature, utf8EncodingName), 64 | validUntil, 65 | URLEncoder.encode(sasKeyName, utf8EncodingName)); 66 | } catch (UnsupportedEncodingException | NoSuchAlgorithmException e) { 67 | // These exceptions shouldn't occur. 68 | String errorMessage = "UTF-8 encoding or HMACSHA256 algorithm is missing in the java runtime."; 69 | Marker fatalMarker = MarkerFactory.getMarker(ClientConstants.FATAL_MARKER); 70 | TRACE_LOGGER.error(fatalMarker, errorMessage, e); 71 | throw new RuntimeException(errorMessage); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/SendWorkItem.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.primitives; 6 | 7 | import java.time.Duration; 8 | import java.util.concurrent.CompletableFuture; 9 | 10 | class SendWorkItem extends WorkItem 11 | { 12 | private byte[] amqpMessage; 13 | private int messageFormat; 14 | private int encodedMessageSize; 15 | private boolean waitingForAck; 16 | private String deliveryTag; 17 | 18 | public SendWorkItem(byte[] amqpMessage, int encodedMessageSize, int messageFormat, String deliveryTag, CompletableFuture completableFuture, Duration timeout) 19 | { 20 | super(completableFuture, timeout); 21 | this.initialize(amqpMessage, encodedMessageSize, messageFormat, deliveryTag); 22 | } 23 | 24 | public SendWorkItem(byte[] amqpMessage, int encodedMessageSize, int messageFormat, String deliveryTag, CompletableFuture completableFuture, TimeoutTracker timeout) 25 | { 26 | super(completableFuture, timeout); 27 | this.initialize(amqpMessage, encodedMessageSize, messageFormat, deliveryTag); 28 | } 29 | 30 | private void initialize(byte[] amqpMessage, int encodedMessageSize, int messageFormat, String deliveryTag) 31 | { 32 | this.amqpMessage = amqpMessage; 33 | this.messageFormat = messageFormat; 34 | this.encodedMessageSize = encodedMessageSize; 35 | this.deliveryTag = deliveryTag; 36 | } 37 | 38 | public byte[] getMessage() 39 | { 40 | return this.amqpMessage; 41 | } 42 | 43 | public int getEncodedMessageSize() 44 | { 45 | return this.encodedMessageSize; 46 | } 47 | 48 | public int getMessageFormat() 49 | { 50 | return this.messageFormat; 51 | } 52 | 53 | public void setWaitingForAck() 54 | { 55 | this.waitingForAck = true; 56 | } 57 | 58 | public boolean isWaitingForAck() 59 | { 60 | return this.waitingForAck; 61 | } 62 | 63 | public String getDeliveryTag() 64 | { 65 | return this.deliveryTag; 66 | } 67 | 68 | public void setDeliveryTag(String deliveryTag) 69 | { 70 | this.deliveryTag = deliveryTag; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/SenderErrorContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.primitives; 6 | 7 | import java.util.Locale; 8 | 9 | public class SenderErrorContext extends ErrorContext 10 | { 11 | final String sendPath; 12 | final String referenceId; 13 | final Integer currentLinkCredit; 14 | 15 | SenderErrorContext( 16 | final String namespaceName, 17 | final String sendPath, 18 | final String referenceId, 19 | final Integer currentLinkCredit) 20 | { 21 | super(namespaceName); 22 | 23 | this.sendPath = sendPath; 24 | this.referenceId = referenceId; 25 | this.currentLinkCredit = currentLinkCredit; 26 | } 27 | 28 | @Override 29 | public String toString() 30 | { 31 | final String superString = super.toString(); 32 | StringBuilder toString = new StringBuilder(); 33 | 34 | if (!StringUtil.isNullOrEmpty(superString)) 35 | { 36 | toString.append(superString); 37 | toString.append(", "); 38 | } 39 | 40 | if (this.sendPath != null) 41 | { 42 | toString.append(String.format(Locale.US, "PATH: %s", this.sendPath)); 43 | toString.append(", "); 44 | } 45 | 46 | if (this.referenceId != null) 47 | { 48 | toString.append(String.format(Locale.US, "REFERENCE_ID: %s", this.referenceId)); 49 | toString.append(", "); 50 | } 51 | 52 | if (this.currentLinkCredit != null) 53 | { 54 | toString.append(String.format(Locale.US, "LINK_CREDIT: %s", this.currentLinkCredit)); 55 | toString.append(", "); 56 | } 57 | 58 | if (toString.length() > 2) 59 | { 60 | toString.setLength(toString.length() - 2); 61 | } 62 | 63 | return toString.toString(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/ServerBusyException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.primitives; 6 | 7 | /** 8 | * Server busy exception is thrown when the current entity's activity has put excessive load onto the service. 9 | * When encountered this exception user should wait at least 4 seconds before any retry/runtime operations for the said entity again. 10 | * @see http://go.microsoft.com/fwlink/?LinkId=761101 11 | * @since 1.0 12 | */ 13 | public class ServerBusyException extends ServiceBusException 14 | { 15 | private static final long serialVersionUID = 1L; 16 | 17 | /** 18 | * Default constructor for the exception 19 | */ 20 | public ServerBusyException() 21 | { 22 | super(true); 23 | } 24 | 25 | ServerBusyException(final String message) 26 | { 27 | super(true, message); 28 | } 29 | 30 | ServerBusyException(final Throwable cause) 31 | { 32 | super(true, cause); 33 | } 34 | 35 | ServerBusyException(final String message, final Throwable cause) 36 | { 37 | super(true, message, cause); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/ServiceBusException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.primitives; 6 | 7 | import java.util.Locale; 8 | 9 | /** 10 | * This is the base exception that service bus will generate for all error cases. 11 | * @since 1.0 12 | */ 13 | public class ServiceBusException extends Exception 14 | { 15 | private static final long serialVersionUID = -3654294093967132325L; 16 | 17 | private boolean isTransient; 18 | private ErrorContext errorContext; 19 | 20 | public ServiceBusException(final boolean isTransient) 21 | { 22 | super(); 23 | this.isTransient = isTransient; 24 | } 25 | 26 | public ServiceBusException(final boolean isTransient, final String message) 27 | { 28 | super(message); 29 | this.isTransient = isTransient; 30 | } 31 | 32 | public ServiceBusException(final boolean isTransient, final Throwable cause) 33 | { 34 | super(cause); 35 | this.isTransient = isTransient; 36 | } 37 | 38 | public ServiceBusException(final boolean isTransient, final String message, final Throwable cause) 39 | { 40 | super(message, cause); 41 | this.isTransient = isTransient; 42 | } 43 | 44 | @Override 45 | public String getMessage() 46 | { 47 | final String baseMessage = super.getMessage(); 48 | return this.errorContext == null || StringUtil.isNullOrEmpty(this.errorContext.toString()) 49 | ? baseMessage 50 | : (!StringUtil.isNullOrEmpty(baseMessage) 51 | ? String.format(Locale.US, "%s, %s[%s]", baseMessage, "errorContext", this.errorContext.toString()) 52 | : String.format(Locale.US, "%s[%s]", "errorContext", this.errorContext.toString())); 53 | } 54 | 55 | /** 56 | * A boolean indicating if the exception is a transient error or not. 57 | * @return returns true when user can retry the operation that generated the exception without additional intervention. 58 | */ 59 | public boolean getIsTransient() 60 | { 61 | return this.isTransient; 62 | } 63 | 64 | public ErrorContext getContext() 65 | { 66 | return this.errorContext; 67 | } 68 | 69 | void setContext(ErrorContext errorContext) 70 | { 71 | this.errorContext = errorContext; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/SessionCannotBeLockedException.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.primitives; 2 | 3 | /** 4 | * This exception is thrown when a client attempts to accept a session that is already locked by another client. 5 | * @since 1.0 6 | * 7 | */ 8 | public class SessionCannotBeLockedException extends ServiceBusException { 9 | 10 | private static final long serialVersionUID = -421016051252808254L; 11 | 12 | public SessionCannotBeLockedException() 13 | { 14 | super(false); 15 | } 16 | 17 | public SessionCannotBeLockedException(String message) 18 | { 19 | super(false, message); 20 | } 21 | 22 | public SessionCannotBeLockedException(Throwable cause) 23 | { 24 | super(false, cause); 25 | } 26 | 27 | public SessionCannotBeLockedException(String message, Throwable cause) 28 | { 29 | super(false, message, cause); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/SessionLockLostException.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.primitives; 2 | 3 | /** 4 | * This exception is thrown when a session receiver performs an operation on a session after its lock is expired. When a client accepts a session, the session is locked to the receiver 5 | * for a duration specified in the entity definition. When the accepted session remains idle for the duration of lock, that is no operations performed on the session, the lock expires and the session is made available 6 | * to other clients. 7 | * @since 1.0 8 | * 9 | */ 10 | public class SessionLockLostException extends ServiceBusException { 11 | 12 | private static final long serialVersionUID = -5861754850637792928L; 13 | 14 | public SessionLockLostException() 15 | { 16 | super(false); 17 | } 18 | 19 | public SessionLockLostException(String message) 20 | { 21 | super(false, message); 22 | } 23 | 24 | public SessionLockLostException(Throwable cause) 25 | { 26 | super(false, cause); 27 | } 28 | 29 | public SessionLockLostException(String message, Throwable cause) 30 | { 31 | super(false, message, cause); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/SettleModePair.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.primitives; 2 | 3 | import org.apache.qpid.proton.amqp.transport.ReceiverSettleMode; 4 | import org.apache.qpid.proton.amqp.transport.SenderSettleMode; 5 | 6 | public class SettleModePair { 7 | private final SenderSettleMode senderSettleMode; 8 | private final ReceiverSettleMode receiverSettleMode; 9 | 10 | public SettleModePair(SenderSettleMode senderSettleMode, ReceiverSettleMode receiverSettleMode) 11 | { 12 | this.senderSettleMode = senderSettleMode; 13 | this.receiverSettleMode = receiverSettleMode; 14 | } 15 | 16 | public SenderSettleMode getSenderSettleMode() { 17 | return senderSettleMode; 18 | } 19 | 20 | public ReceiverSettleMode getReceiverSettleMode() { 21 | return receiverSettleMode; 22 | } 23 | 24 | @Override 25 | public String toString() 26 | { 27 | return String.format("sender settle mode: %s, receiver settle mode: %s", this.senderSettleMode, this.receiverSettleMode); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/StringUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.primitives; 6 | 7 | import java.nio.charset.Charset; 8 | import java.nio.charset.StandardCharsets; 9 | import java.util.UUID; 10 | 11 | public final class StringUtil 12 | { 13 | public final static String EMPTY = ""; 14 | private final static Charset UTF8CharSet = StandardCharsets.UTF_8; 15 | 16 | public static boolean isNullOrEmpty(String string) 17 | { 18 | return (string == null || string.isEmpty()); 19 | } 20 | 21 | public static boolean isNullOrWhiteSpace(String string) 22 | { 23 | if (string == null) 24 | return true; 25 | 26 | for (int index=0; index < string.length(); index++) 27 | { 28 | if (!Character.isWhitespace(string.charAt(index))) 29 | { 30 | return false; 31 | } 32 | } 33 | 34 | return true; 35 | } 36 | 37 | public static String getShortRandomString() 38 | { 39 | return getRandomString().substring(0, 6); 40 | } 41 | 42 | public static String getRandomString() 43 | { 44 | return UUID.randomUUID().toString(); 45 | } 46 | 47 | static String convertBytesToString(byte[] bytes) 48 | { 49 | return new String(bytes, UTF8CharSet); 50 | } 51 | 52 | static byte[] convertStringToBytes(String string) 53 | { 54 | return string.getBytes(UTF8CharSet); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/TimeoutException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.primitives; 6 | 7 | /** 8 | * This exception is thrown when the operation has exceeded the predetermined time limit. 9 | * User should check connectivity is healthy between client process and service. 10 | * @see http://go.microsoft.com/fwlink/?LinkId=761101 11 | * @since 1.0 12 | */ 13 | public class TimeoutException extends ServiceBusException 14 | { 15 | private static final long serialVersionUID = -3505469991851121512L; 16 | 17 | /** 18 | * Default constructor for exception type. 19 | */ 20 | public TimeoutException() 21 | { 22 | super(true); 23 | } 24 | 25 | public TimeoutException(final String message) 26 | { 27 | super(true, message); 28 | } 29 | 30 | public TimeoutException(final Throwable cause) 31 | { 32 | super(true, cause); 33 | } 34 | 35 | public TimeoutException(final String message, final Throwable cause) 36 | { 37 | super(true, message, cause); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/TimeoutTracker.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.primitives; 6 | 7 | import java.time.*; 8 | 9 | public class TimeoutTracker 10 | { 11 | private final Duration originalTimeout; 12 | private boolean isTimerStarted; 13 | private Instant startTime; 14 | 15 | /** 16 | * @param timeout original operationTimeout 17 | * @param startTrackingTimeout whether/not to start the timeout tracking - right now. if not started now, timer tracking will start upon the first call to {@link TimeoutTracker#elapsed()}/{@link TimeoutTracker#remaining()} 18 | */ 19 | public TimeoutTracker(Duration timeout, boolean startTrackingTimeout) 20 | { 21 | if (timeout.compareTo(Duration.ZERO) < 0) 22 | { 23 | throw new IllegalArgumentException("timeout should be non-negative"); 24 | } 25 | 26 | this.originalTimeout = timeout; 27 | 28 | if (startTrackingTimeout) 29 | { 30 | this.startTime = Instant.now(); 31 | } 32 | 33 | this.isTimerStarted = startTrackingTimeout; 34 | } 35 | 36 | public static TimeoutTracker create(Duration timeout) 37 | { 38 | return new TimeoutTracker(timeout, true); 39 | } 40 | 41 | public Duration remaining() 42 | { 43 | return this.originalTimeout.minus(this.elapsed()); 44 | } 45 | 46 | public Duration elapsed() 47 | { 48 | if (!this.isTimerStarted) 49 | { 50 | this.startTime = Instant.now(); 51 | this.isTimerStarted = true; 52 | } 53 | 54 | return Duration.between(this.startTime, Instant.now()); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/Timer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.primitives; 6 | 7 | import java.time.Duration; 8 | import java.util.HashSet; 9 | import java.util.concurrent.Executors; 10 | import java.util.concurrent.ScheduledExecutorService; 11 | import java.util.concurrent.ScheduledFuture; 12 | import java.util.concurrent.TimeUnit; 13 | 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | 17 | 18 | /** 19 | * An abstraction for a Scheduler functionality - which can later be replaced by a light-weight Thread 20 | */ 21 | final public class Timer 22 | { 23 | private static ScheduledExecutorService executor = null; 24 | 25 | private static final Logger TRACE_LOGGER = LoggerFactory.getLogger(Timer.class); 26 | private static final HashSet references = new HashSet(); 27 | private static final Object syncReferences = new Object(); 28 | 29 | private Timer() 30 | { 31 | } 32 | 33 | 34 | // runFrequency implemented only for TimeUnit granularity - Seconds 35 | public static ScheduledFuture schedule(Runnable runnable, Duration runFrequency, TimerType timerType) 36 | { 37 | switch (timerType) 38 | { 39 | case OneTimeRun: 40 | return executor.schedule(runnable, runFrequency.toMillis(), TimeUnit.MILLISECONDS); 41 | 42 | case RepeatRun: 43 | return executor.scheduleWithFixedDelay(runnable, runFrequency.toMillis(), runFrequency.toMillis(), TimeUnit.MILLISECONDS); 44 | 45 | default: 46 | throw new UnsupportedOperationException("Unsupported timer pattern."); 47 | } 48 | } 49 | 50 | static void register(final String clientId) 51 | { 52 | synchronized (syncReferences) 53 | { 54 | if (references.size() == 0 && (executor == null || executor.isShutdown())) 55 | { 56 | final int corePoolSize = Math.max(Runtime.getRuntime().availableProcessors(), 4); 57 | TRACE_LOGGER.debug("Starting ScheduledThreadPoolExecutor with coreThreadPoolSize:{}", corePoolSize); 58 | 59 | executor = Executors.newScheduledThreadPool(corePoolSize); 60 | } 61 | 62 | references.add(clientId); 63 | } 64 | } 65 | 66 | static void unregister(final String clientId) 67 | { 68 | synchronized (syncReferences) 69 | { 70 | if (references.remove(clientId) && references.size() == 0 && executor != null) 71 | { 72 | TRACE_LOGGER.debug("Shuting down ScheduledThreadPoolExecutor"); 73 | executor.shutdownNow(); 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/TimerType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.primitives; 6 | 7 | public enum TimerType 8 | { 9 | OneTimeRun, 10 | RepeatRun 11 | } 12 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/TrackingUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.primitives; 6 | 7 | public final class TrackingUtil 8 | { 9 | public static final String TRACKING_ID_TOKEN_SEPARATOR = "_"; 10 | 11 | private TrackingUtil() 12 | { 13 | } 14 | 15 | /** 16 | * parses ServiceBus role identifiers from trackingId 17 | * @return null if no roleIdentifier found 18 | */ 19 | static String parseRoleIdentifier(final String trackingId) 20 | { 21 | if (StringUtil.isNullOrWhiteSpace(trackingId) || !trackingId.contains(TRACKING_ID_TOKEN_SEPARATOR)) 22 | { 23 | return null; 24 | } 25 | 26 | return trackingId.substring(trackingId.indexOf(TRACKING_ID_TOKEN_SEPARATOR)); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/UpdateStateWorkItem.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | package com.microsoft.azure.servicebus.primitives; 5 | 6 | import java.time.Duration; 7 | import java.util.concurrent.CompletableFuture; 8 | 9 | import org.apache.qpid.proton.amqp.messaging.Outcome; 10 | 11 | class UpdateStateWorkItem extends WorkItem { 12 | final Outcome outcome; 13 | 14 | public UpdateStateWorkItem(final CompletableFuture completableFuture, Outcome expectedOutcome, Duration timeout) { 15 | super(completableFuture, new TimeoutTracker(timeout, true)); 16 | this.outcome = expectedOutcome; 17 | } 18 | 19 | public UpdateStateWorkItem(final CompletableFuture completableFuture, Outcome expectedOutcome, final TimeoutTracker tracker) { 20 | super(completableFuture, tracker); 21 | this.outcome = expectedOutcome; 22 | } 23 | 24 | public Outcome getOutcome() { 25 | return this.outcome; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/primitives/WorkItem.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft. All rights reserved. 3 | * Licensed under the MIT license. See LICENSE file in the project root for full license information. 4 | */ 5 | package com.microsoft.azure.servicebus.primitives; 6 | 7 | import java.time.*; 8 | import java.util.concurrent.*; 9 | 10 | class WorkItem 11 | { 12 | private final TimeoutTracker tracker; 13 | private final CompletableFuture work; 14 | private ScheduledFuture timeoutTask; 15 | private Exception lastKnownException; 16 | 17 | public WorkItem(final CompletableFuture completableFuture, final Duration timeout) 18 | { 19 | this(completableFuture, TimeoutTracker.create(timeout)); 20 | } 21 | 22 | public WorkItem(final CompletableFuture completableFuture, final TimeoutTracker tracker) 23 | { 24 | this.work = completableFuture; 25 | this.tracker = tracker; 26 | } 27 | 28 | public TimeoutTracker getTimeoutTracker() 29 | { 30 | return this.tracker; 31 | } 32 | 33 | // TODO; remove this method. Synchronize calls to complete on the future so two different threads don't attempt to complete at the same time. 34 | // Also group complete and canceling timeout task in one method so calling code doesn't have to call both of them one after the other. 35 | public CompletableFuture getWork() 36 | { 37 | return this.work; 38 | } 39 | 40 | public ScheduledFuture getTimeoutTask() 41 | { 42 | return this.timeoutTask; 43 | } 44 | 45 | public void setTimeoutTask(final ScheduledFuture timeoutTask) 46 | { 47 | this.timeoutTask = timeoutTask; 48 | } 49 | 50 | public boolean cancelTimeoutTask(boolean mayInterruptIfRunning) 51 | { 52 | if(this.timeoutTask != null) 53 | { 54 | return this.timeoutTask.cancel(mayInterruptIfRunning); 55 | } 56 | 57 | return false; 58 | } 59 | 60 | public Exception getLastKnownException() 61 | { 62 | return this.lastKnownException; 63 | } 64 | 65 | public void setLastKnownException(Exception exception) 66 | { 67 | this.lastKnownException = exception; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/rules/FalseFilter.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | package com.microsoft.azure.servicebus.rules; 5 | 6 | /** 7 | * Represents a special kind of filter that doesn't match any message. 8 | * 9 | * @since 1.0 10 | */ 11 | public class FalseFilter extends SqlFilter { 12 | private static final String FALSE_FILTER_EXPRESSION = "1=0"; 13 | 14 | /** 15 | * A false filter object that is pre-created. Clients can use this object instead of recreating a new instance every time. 16 | */ 17 | public static final FalseFilter DEFAULT = new FalseFilter(); 18 | 19 | /** 20 | * Creates a false filter. 21 | */ 22 | public FalseFilter() { 23 | super(FALSE_FILTER_EXPRESSION); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/rules/Filter.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | package com.microsoft.azure.servicebus.rules; 5 | 6 | /** 7 | * Represents a filter expression that is evaluated against a message on a topic. This client library provides support for creating only limited types of filters. 8 | * This is an empty interface to serve as root interface for all supported filter types. 9 | * 10 | * @since 1.0 11 | */ 12 | public abstract class Filter { 13 | // No methods. Just a skeleton root class for filters 14 | // Filter execution happens in the cloud on .net runtime. There is no point implementing custom filters in Java. 15 | } 16 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/rules/RuleAction.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | package com.microsoft.azure.servicebus.rules; 5 | 6 | /** 7 | * Represents an action that transforms a message matched by a filter. This client library provides support for creating only limited types of rule actions. 8 | * This is an empty interface to serve as root interface for all supported rule actions. 9 | * 10 | * @since 1.0 11 | */ 12 | public class RuleAction { 13 | // No methods. Just a skeleton root class for actions 14 | } 15 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/rules/RuleDescription.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | package com.microsoft.azure.servicebus.rules; 5 | 6 | /** 7 | * Representation of a rule defined on service bus topics. 8 | * 9 | * @since 1.0 10 | */ 11 | public class RuleDescription { 12 | private Filter filter; 13 | private RuleAction action; 14 | private String name; 15 | 16 | /** 17 | * Creates a rule description with no name, {@link TrueFilter} as filter and no action. 18 | */ 19 | public RuleDescription() { 20 | this.filter = TrueFilter.DEFAULT; 21 | } 22 | 23 | /** 24 | * Creates a rule description with the given name, {@link TrueFilter} as filter and no action. 25 | * 26 | * @param name name of the rule 27 | */ 28 | public RuleDescription(String name) { 29 | this.filter = TrueFilter.DEFAULT; 30 | this.name = name; 31 | } 32 | 33 | /** 34 | * Creates a rule description with no name, given filter as filter and no action. 35 | * 36 | * @param filter filter the rule uses to filter messages. Can be {@link CorrelationFilter} or {@link SqlFilter}. 37 | */ 38 | public RuleDescription(Filter filter) { 39 | this.filter = filter; 40 | } 41 | 42 | /** 43 | * Creates a rule description with the given name, given filter as filter and no action. 44 | * 45 | * @param name name of the rule 46 | * @param filter filter this rule uses to filter messages. Can be Can be {@link CorrelationFilter} or {@link SqlFilter}. 47 | */ 48 | public RuleDescription(String name, Filter filter) { 49 | this.name = name; 50 | this.filter = filter; 51 | } 52 | 53 | /** 54 | * Gets the filter of this rule. 55 | * 56 | * @return the filter this rule uses to filter messages 57 | */ 58 | public Filter getFilter() { 59 | return filter; 60 | } 61 | 62 | /** 63 | * Sets the filter of this rule. 64 | * 65 | * @param filter filter this rule uses to filter messages. Can be Can be {@link CorrelationFilter} or {@link SqlFilter}. 66 | */ 67 | public void setFilter(Filter filter) { 68 | this.filter = filter; 69 | } 70 | 71 | /** 72 | * Gets the action this rule performs on messages matched by this rule's filter. 73 | * 74 | * @return action action this rule performs on matched messages 75 | */ 76 | public RuleAction getAction() { 77 | return action; 78 | } 79 | 80 | /** 81 | * Sets the action this rule performs on messages matched by this rule's filter. 82 | * 83 | * @param action action this rule performs on matched messages 84 | */ 85 | public void setAction(RuleAction action) { 86 | this.action = action; 87 | } 88 | 89 | /** 90 | * Gets the name of this rule. 91 | * 92 | * @return name of this rule 93 | */ 94 | public String getName() { 95 | return name; 96 | } 97 | 98 | /** 99 | * Sets the name of this rule. 100 | * 101 | * @param name name of this rule 102 | */ 103 | public void setName(String name) { 104 | this.name = name; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/rules/SqlFilter.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | package com.microsoft.azure.servicebus.rules; 5 | 6 | /** 7 | * Represents a SQL language-based filter expression that is evaluated against a message. 8 | * 9 | * @since 1.0 10 | */ 11 | public class SqlFilter extends Filter { 12 | 13 | private String sqlExpression; 14 | 15 | /** 16 | * Creates an instance of SqlFilter with the given match expression. 17 | * 18 | * @param sqlExpression SQL language-based filter expression 19 | */ 20 | public SqlFilter(String sqlExpression) { 21 | this.sqlExpression = sqlExpression; 22 | } 23 | 24 | /** 25 | * Gets the match expression of this filter. 26 | * 27 | * @return SQL language-based expression of this filter 28 | */ 29 | public String getSqlExpression() { 30 | return this.sqlExpression; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/rules/SqlRuleAction.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | package com.microsoft.azure.servicebus.rules; 5 | 6 | /** 7 | * Represents a SQL language-based transformation expression that is performed against a message. 8 | * 9 | * @since 1.0 10 | */ 11 | public class SqlRuleAction extends RuleAction { 12 | private String sqlExpression; 13 | 14 | /** 15 | * Creates an instance of SqlRuleAction with the given transformation expression. 16 | * 17 | * @param sqlExpression SQL language-based transformation expression 18 | */ 19 | public SqlRuleAction(String sqlExpression) { 20 | this.sqlExpression = sqlExpression; 21 | } 22 | 23 | /** 24 | * Gets the transformation expression of this rule action. 25 | * 26 | * @return SQL language-based transformation expression 27 | */ 28 | public String getSqlExpression() { 29 | return this.sqlExpression; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/rules/TrueFilter.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | package com.microsoft.azure.servicebus.rules; 5 | 6 | /** 7 | * Represents a special kind of filter that matches every message. 8 | * 9 | * @since 1.0 10 | */ 11 | public class TrueFilter extends SqlFilter { 12 | private static final String TRUE_FILTER_EXPRESSION = "1=1"; 13 | 14 | /** 15 | * A true filter object that is pre-created. Clients can use this object instead of recreating a new instance every time. 16 | */ 17 | public static final TrueFilter DEFAULT = new TrueFilter(); 18 | 19 | /** 20 | * Creates a true filter. 21 | */ 22 | public TrueFilter() { 23 | super(TRUE_FILTER_EXPRESSION); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/security/SecurityConstants.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.security; 2 | 3 | /** 4 | * This class contains all security related constants. 5 | * @since 1.2.0 6 | * 7 | */ 8 | public class SecurityConstants { 9 | /** 10 | * Resource URI to be used, for all service bus entities, when requesting authentication token from Azure Active Directory. 11 | */ 12 | public static final String SERVICEBUS_AAD_AUDIENCE_RESOURCE_URL = "https://servicebus.azure.net/"; 13 | /** 14 | * JSON web token type. 15 | */ 16 | public static final String JWT_TOKEN_TYPE = "jwt"; 17 | /** 18 | * Shared Access Signature token type. 19 | */ 20 | public static final String SAS_TOKEN_TYPE = "servicebus.windows.net:sastoken"; 21 | /** 22 | * Default validity of a security token in seconds. 23 | */ 24 | public static final int DEFAULT_SAS_TOKEN_VALIDITY_IN_SECONDS = 20*60; // 20 minutes 25 | 26 | } 27 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/security/SecurityToken.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.security; 2 | 3 | import java.time.Instant; 4 | 5 | /** 6 | * This class encapsulates the details of a security token. 7 | * 8 | * @since 1.2.0 9 | * 10 | */ 11 | public class SecurityToken { 12 | private SecurityTokenType tokenType; 13 | private String tokenAudience; 14 | private String tokenValue; 15 | private Instant validFrom; 16 | private Instant validUntil; 17 | 18 | /** 19 | * Creates an instance of security token. 20 | * @param tokenType {@link SecurityTokenType} 21 | * @param tokenAudience path of the entity for which this security token is to be presented 22 | * @param tokenValue string representation of the token value 23 | * @param validFrom Instant from when this token is valid 24 | * @param validUntil Instant when this token expires 25 | */ 26 | public SecurityToken(SecurityTokenType tokenType, String tokenAudience, String tokenValue, Instant validFrom, Instant validUntil) 27 | { 28 | this.tokenType = tokenType; 29 | this.tokenAudience = tokenAudience; 30 | this.tokenValue = tokenValue; 31 | this.validFrom = validFrom; 32 | this.validUntil = validUntil; 33 | } 34 | 35 | /** 36 | * Gets the type of this security token. 37 | * @return security token type 38 | */ 39 | public SecurityTokenType getTokenType() { 40 | return tokenType; 41 | } 42 | 43 | /** 44 | * Gets the path of the entity for which this token is to be presented. 45 | * @return path of the entity for which this token is created 46 | */ 47 | public String getTokenAudience() { 48 | return this.tokenAudience; 49 | } 50 | 51 | /** 52 | * Gets the value of this token. 53 | * @return string representation of the token value 54 | */ 55 | public String getTokenValue() { 56 | return this.tokenValue; 57 | } 58 | 59 | /** 60 | * Gets the start time of this token validity 61 | * @return Instant from when this token is valid 62 | */ 63 | public Instant getValidFrom() { 64 | return this.validFrom; 65 | } 66 | 67 | /** 68 | * Gets the end time of this token validity. 69 | * @return Instant when this token expires 70 | */ 71 | public Instant getValidUntil() { 72 | return this.validUntil; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/security/SecurityTokenType.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.security; 2 | 3 | /** 4 | * Enumeration representing security token types supported by Azure Service Bus. 5 | * @since 1.2.0 6 | * 7 | */ 8 | public enum SecurityTokenType { 9 | /** 10 | * Shared Access Signature token type 11 | */ 12 | SAS(SecurityConstants.SAS_TOKEN_TYPE), 13 | /** 14 | * JSON web token type 15 | */ 16 | JWT(SecurityConstants.JWT_TOKEN_TYPE); 17 | 18 | private final String tokenTypeString; 19 | SecurityTokenType(String tokenTypeString) 20 | { 21 | this.tokenTypeString = tokenTypeString; 22 | } 23 | 24 | @Override 25 | public String toString() 26 | { 27 | return this.tokenTypeString; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /azure-servicebus/src/main/java/com/microsoft/azure/servicebus/security/SharedAccessSignatureTokenProvider.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.security; 2 | 3 | import java.security.InvalidKeyException; 4 | import java.time.Duration; 5 | import java.time.Instant; 6 | import java.util.concurrent.CompletableFuture; 7 | 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import com.microsoft.azure.servicebus.primitives.MessagingFactory; 12 | import com.microsoft.azure.servicebus.primitives.SASUtil; 13 | 14 | /** 15 | * This is a token provider that generates Shared Access Signature(SAS) tokens or reuses an already generated SAS token. 16 | * @since 1.2.0 17 | * 18 | */ 19 | public class SharedAccessSignatureTokenProvider extends TokenProvider 20 | { 21 | private static final Logger TRACE_LOGGER = LoggerFactory.getLogger(SharedAccessSignatureTokenProvider.class); 22 | 23 | private String sasKeyName; 24 | private String sasKey; 25 | private int tokenValidityInSeconds; 26 | private String sasToken; 27 | private Instant sasTokenValidUntil; 28 | 29 | /** 30 | * Creates an instance that generates SAS tokens from the given SAS key name and value. 31 | * @param sasKeyName name of the SAS key 32 | * @param sasKey SAS key 33 | * @param tokenValidityInSeconds validity of the token to be generated 34 | */ 35 | public SharedAccessSignatureTokenProvider(String sasKeyName, String sasKey, int tokenValidityInSeconds) 36 | { 37 | this.sasKeyName = sasKeyName; 38 | this.sasKey = sasKey; 39 | this.tokenValidityInSeconds = tokenValidityInSeconds; 40 | this.sasToken = null; 41 | } 42 | 43 | /** 44 | * Creates an instance that doesn't generate tokens but reuses an already generated SAS token. 45 | * @param sasToken SAS token already generated 46 | * @param sasTokenValidUntil Instant when the SAS token expires. 47 | */ 48 | public SharedAccessSignatureTokenProvider(String sasToken, Instant sasTokenValidUntil) 49 | { 50 | this.sasToken = sasToken; 51 | this.sasTokenValidUntil= sasTokenValidUntil; 52 | } 53 | 54 | @Override 55 | public CompletableFuture getSecurityTokenAsync(String audience) { 56 | if(this.sasToken != null) 57 | { 58 | SecurityToken securityToken = new SecurityToken(SecurityTokenType.SAS, audience, this.sasToken, Instant.now(), this.sasTokenValidUntil); 59 | return CompletableFuture.completedFuture(securityToken); 60 | } 61 | else 62 | { 63 | CompletableFuture tokenGeneratingFuture = new CompletableFuture<>(); 64 | MessagingFactory.INTERNAL_THREAD_POOL.execute(() -> { 65 | try { 66 | String genereatedSASToken = SASUtil.generateSharedAccessSignatureToken(this.sasKeyName, this.sasKey, audience, this.tokenValidityInSeconds); 67 | tokenGeneratingFuture.complete(new SecurityToken(SecurityTokenType.SAS, audience, genereatedSASToken, Instant.now(), Instant.now().plus(Duration.ofSeconds(this.tokenValidityInSeconds)))); 68 | } catch (InvalidKeyException e) { 69 | TRACE_LOGGER.error("SharedAccessSignature token generation failed.", e); 70 | tokenGeneratingFuture.completeExceptionally(e); 71 | } 72 | }); 73 | 74 | return tokenGeneratingFuture; 75 | } 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /azure-servicebus/src/test/HowToRunTests.txt: -------------------------------------------------------------------------------- 1 | How to run unit tests? 2 | ----------------------- 3 | Tests are simple JUnit tests. They can be run from the command line or any IDE that supports running JUnit tests. 4 | Only prerequisite to running tests is setting an environment variable named 'AZURE_SERVICEBUS_JAVA_CLIENT_TEST_CONNECTION_STRING' to the connection string 5 | of the namespace in which the tests will create entities. The tests create entities in the namespace and run tests and delete the created entities. 6 | And test classes also have methods to specify whether to create entities per test or once for all tests in a suite. Creating entities per test is better 7 | as it keeps test independent of each other. -------------------------------------------------------------------------------- /azure-servicebus/src/test/java/com/microsoft/azure/servicebus/MaxConcurrencyCounter.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus; 2 | 3 | public class MaxConcurrencyCounter 4 | { 5 | private int concurrencyCount = 0; 6 | private int maxConcurrencyCount = 0; 7 | 8 | public synchronized void incrementCount() 9 | { 10 | this.concurrencyCount++; 11 | if(this.concurrencyCount > this.maxConcurrencyCount) 12 | { 13 | this.maxConcurrencyCount = this.concurrencyCount; 14 | } 15 | } 16 | 17 | public synchronized void decrementCount() 18 | { 19 | this.concurrencyCount--; 20 | } 21 | 22 | public synchronized int getMaxConcurrencyCount() 23 | { 24 | //System.out.println("Max concurrency count :" + this.maxConcurrencyCount); 25 | return this.maxConcurrencyCount; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /azure-servicebus/src/test/java/com/microsoft/azure/servicebus/PartitionedQueueClientSessionTests.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus; 2 | 3 | public class PartitionedQueueClientSessionTests extends QueueClientSessionTests{ 4 | @Override 5 | public String getEntityNamePrefix() { 6 | return "PartitionedQueueClientSessionTests"; 7 | } 8 | 9 | @Override 10 | public boolean shouldCreateEntityForEveryTest() { 11 | return TestUtils.shouldCreateEntityForEveryTest(); 12 | } 13 | 14 | @Override 15 | public boolean isEntityPartitioned() { 16 | return true; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /azure-servicebus/src/test/java/com/microsoft/azure/servicebus/PartitionedQueueClientTests.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus; 2 | 3 | public class PartitionedQueueClientTests extends QueueClientTests{ 4 | @Override 5 | public String getEntityNamePrefix() { 6 | return "PartitionedQueueClientTests"; 7 | } 8 | 9 | @Override 10 | public boolean shouldCreateEntityForEveryTest() { 11 | return TestUtils.shouldCreateEntityForEveryTest(); 12 | } 13 | 14 | @Override 15 | public boolean isEntityPartitioned() { 16 | return true; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /azure-servicebus/src/test/java/com/microsoft/azure/servicebus/PartitionedQueueSendReceiveTests.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus; 2 | 3 | public class PartitionedQueueSendReceiveTests extends QueueSendReceiveTests{ 4 | @Override 5 | public String getEntityNamePrefix() { 6 | return "PartitionedQueueSendReceiveTests"; 7 | } 8 | 9 | @Override 10 | public boolean shouldCreateEntityForEveryTest() { 11 | return TestUtils.shouldCreateEntityForEveryTest(); 12 | } 13 | 14 | @Override 15 | public boolean isEntityPartitioned() { 16 | return true; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /azure-servicebus/src/test/java/com/microsoft/azure/servicebus/PartitionedQueueSessionTests.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus; 2 | 3 | public class PartitionedQueueSessionTests extends QueueSessionTests 4 | { 5 | @Override 6 | public String getEntityNamePrefix() { 7 | return "PartitionedQueueSessionTests"; 8 | } 9 | 10 | @Override 11 | public boolean shouldCreateEntityForEveryTest() { 12 | return TestUtils.shouldCreateEntityForEveryTest(); 13 | } 14 | 15 | @Override 16 | public boolean isEntityPartitioned() { 17 | return true; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /azure-servicebus/src/test/java/com/microsoft/azure/servicebus/PartitionedSubscriptionClientSessionTests.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus; 2 | 3 | public class PartitionedSubscriptionClientSessionTests extends SubscriptionClientSessionTests{ 4 | @Override 5 | public String getEntityNamePrefix() { 6 | return "PartitionedSubscriptionClientSessionTests"; 7 | } 8 | 9 | @Override 10 | public boolean shouldCreateEntityForEveryTest() { 11 | return TestUtils.shouldCreateEntityForEveryTest(); 12 | } 13 | 14 | @Override 15 | public boolean isEntityPartitioned() { 16 | return true; 17 | } 18 | } -------------------------------------------------------------------------------- /azure-servicebus/src/test/java/com/microsoft/azure/servicebus/PartitionedSubscriptionClientTests.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus; 2 | 3 | public class PartitionedSubscriptionClientTests extends SubscriptionClientTests{ 4 | @Override 5 | public String getEntityNamePrefix() { 6 | return "PartitionedSubscriptionClientTests"; 7 | } 8 | 9 | @Override 10 | public boolean isEntityPartitioned() { 11 | return true; 12 | } 13 | 14 | @Override 15 | public boolean shouldCreateEntityForEveryTest() { 16 | return TestUtils.shouldCreateEntityForEveryTest(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /azure-servicebus/src/test/java/com/microsoft/azure/servicebus/PartitionedTopicSendReceiveTests.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus; 2 | 3 | public class PartitionedTopicSendReceiveTests extends TopicSendReceiveTests { 4 | 5 | @Override 6 | public String getEntityNamePrefix() { 7 | return "PartitionedTopicSendReceiveTests"; 8 | } 9 | 10 | @Override 11 | public boolean isEntityPartitioned() { 12 | return true; 13 | } 14 | 15 | @Override 16 | public boolean shouldCreateEntityForEveryTest() { 17 | return TestUtils.shouldCreateEntityForEveryTest(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /azure-servicebus/src/test/java/com/microsoft/azure/servicebus/PartitionedTopicSessionTests.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus; 2 | 3 | public class PartitionedTopicSessionTests extends TopicSessionTests { 4 | 5 | @Override 6 | public String getEntityNamePrefix() { 7 | return "PartitionedTopicSessionTests"; 8 | } 9 | 10 | @Override 11 | public boolean isEntityPartitioned() { 12 | return true; 13 | } 14 | 15 | @Override 16 | public boolean shouldCreateEntityForEveryTest() { 17 | return TestUtils.shouldCreateEntityForEveryTest(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /azure-servicebus/src/test/java/com/microsoft/azure/servicebus/QueueClientSessionTests.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus; 2 | 3 | public class QueueClientSessionTests extends ClientSessionTests{ 4 | @Override 5 | public String getEntityNamePrefix() { 6 | return "QueueClientSessionTests"; 7 | } 8 | 9 | @Override 10 | public boolean isEntityQueue() { 11 | return true; 12 | } 13 | 14 | @Override 15 | public boolean shouldCreateEntityForEveryTest() { 16 | return TestUtils.shouldCreateEntityForEveryTest(); 17 | } 18 | 19 | @Override 20 | public boolean isEntityPartitioned() { 21 | return false; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /azure-servicebus/src/test/java/com/microsoft/azure/servicebus/QueueClientTests.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus; 2 | 3 | public class QueueClientTests extends ClientTests{ 4 | @Override 5 | public String getEntityNamePrefix() { 6 | return "QueueClientTests"; 7 | } 8 | 9 | @Override 10 | public boolean isEntityQueue() { 11 | return true; 12 | } 13 | 14 | @Override 15 | public boolean shouldCreateEntityForEveryTest() { 16 | return TestUtils.shouldCreateEntityForEveryTest(); 17 | } 18 | 19 | @Override 20 | public boolean isEntityPartitioned() { 21 | return false; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /azure-servicebus/src/test/java/com/microsoft/azure/servicebus/QueueSendReceiveTests.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus; 2 | 3 | public class QueueSendReceiveTests extends SendReceiveTests 4 | { 5 | @Override 6 | public String getEntityNamePrefix() { 7 | return "QueueSendReceiveTests"; 8 | } 9 | 10 | @Override 11 | public boolean isEntityQueue() { 12 | return true; 13 | } 14 | 15 | @Override 16 | public boolean shouldCreateEntityForEveryTest() { 17 | return TestUtils.shouldCreateEntityForEveryTest(); 18 | } 19 | 20 | @Override 21 | public boolean isEntityPartitioned() { 22 | return false; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /azure-servicebus/src/test/java/com/microsoft/azure/servicebus/QueueSessionTests.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus; 2 | 3 | public class QueueSessionTests extends SessionTests 4 | { 5 | @Override 6 | public String getEntityNamePrefix() { 7 | return "QueueSessionTests"; 8 | } 9 | 10 | @Override 11 | public boolean isEntityQueue() { 12 | return true; 13 | } 14 | 15 | @Override 16 | public boolean shouldCreateEntityForEveryTest() { 17 | return TestUtils.shouldCreateEntityForEveryTest(); 18 | } 19 | 20 | @Override 21 | public boolean isEntityPartitioned() { 22 | return false; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /azure-servicebus/src/test/java/com/microsoft/azure/servicebus/SubscriptionClientSessionTests.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus; 2 | 3 | public class SubscriptionClientSessionTests extends ClientSessionTests{ 4 | @Override 5 | public String getEntityNamePrefix() { 6 | return "SubscriptionClientSessionTests"; 7 | } 8 | 9 | @Override 10 | public boolean isEntityQueue() { 11 | return false; 12 | } 13 | 14 | @Override 15 | public boolean shouldCreateEntityForEveryTest() { 16 | return TestUtils.shouldCreateEntityForEveryTest(); 17 | } 18 | 19 | @Override 20 | public boolean isEntityPartitioned() { 21 | return false; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /azure-servicebus/src/test/java/com/microsoft/azure/servicebus/TestMessageHandler.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus; 2 | 3 | public abstract class TestMessageHandler implements IMessageHandler { 4 | 5 | @Override 6 | public void notifyException(Throwable exception, ExceptionPhase phase) { 7 | //exception.printStackTrace(); 8 | System.out.println(phase + "-" + exception.getMessage()); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /azure-servicebus/src/test/java/com/microsoft/azure/servicebus/TestSessionHandler.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus; 2 | 3 | import java.time.Instant; 4 | 5 | public abstract class TestSessionHandler implements ISessionHandler 6 | { 7 | @Override 8 | public void notifyException(Throwable exception, ExceptionPhase phase) { 9 | System.out.println(phase + "-" + exception.getMessage() + ":" + Instant.now()); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /azure-servicebus/src/test/java/com/microsoft/azure/servicebus/TestUtils.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus; 2 | 3 | import java.net.URI; 4 | import java.util.UUID; 5 | 6 | import com.microsoft.azure.servicebus.primitives.ConnectionStringBuilder; 7 | import com.microsoft.azure.servicebus.primitives.Util; 8 | 9 | public class TestUtils { 10 | 11 | private static final String NAMESPACE_CONNECTION_STRING_ENVIRONMENT_VARIABLE_NAME = "AZURE_SERVICEBUS_JAVA_CLIENT_TEST_CONNECTION_STRING"; 12 | public static final String FIRST_SUBSCRIPTION_NAME = "subscription1"; 13 | private static String namespaceConnectionString; 14 | private static ConnectionStringBuilder namespaceConnectionStringBuilder; 15 | 16 | static 17 | { 18 | // Read connection string 19 | namespaceConnectionString = System.getenv(NAMESPACE_CONNECTION_STRING_ENVIRONMENT_VARIABLE_NAME); 20 | if(namespaceConnectionString == null || namespaceConnectionString.isEmpty()) 21 | { 22 | System.err.println(NAMESPACE_CONNECTION_STRING_ENVIRONMENT_VARIABLE_NAME + " environment variable not set. Tests will not be able to connecto to any service bus entity."); 23 | } 24 | namespaceConnectionStringBuilder = new ConnectionStringBuilder(namespaceConnectionString); 25 | } 26 | 27 | public static URI getNamespaceEndpointURI() 28 | { 29 | return namespaceConnectionStringBuilder.getEndpoint(); 30 | } 31 | 32 | public static ClientSettings getClientSettings() 33 | { 34 | return Util.getClientSettingsFromConnectionStringBuilder(namespaceConnectionStringBuilder); 35 | } 36 | 37 | // AADTokens cannot yet be used for management operations, sent directly to gateway 38 | public static ClientSettings getManagementClientSettings() 39 | { 40 | return Util.getClientSettingsFromConnectionStringBuilder(namespaceConnectionStringBuilder); 41 | } 42 | 43 | public static String randomizeEntityName(String entityName) 44 | { 45 | return entityName + getRandomString(); 46 | } 47 | 48 | public static String getRandomString() 49 | { 50 | return UUID.randomUUID().toString(); 51 | } 52 | 53 | /** 54 | * Tells this class whether to create an entity for every test and delete it after the test. Creating an entity for every test makes the tests independent of 55 | * each other and advisable if the SB namespace allows it. If the namespace doesn't allow creation and deletion of many entities in a short span of time, the suite 56 | * will create one entity at the start, uses it for all test and deletes the entity at the end. 57 | * @return true if each test should create and delete its own entity. Else return false. 58 | */ 59 | public static boolean shouldCreateEntityForEveryTest() 60 | { 61 | return true; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /azure-servicebus/src/test/java/com/microsoft/azure/servicebus/Tests.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus; 2 | 3 | public abstract class Tests { 4 | public abstract String getEntityNamePrefix(); 5 | 6 | public abstract boolean isEntityQueue(); 7 | 8 | public abstract boolean isEntityPartitioned(); 9 | 10 | /** 11 | * Tells this class whether to create an entity for every test and delete it after the test. Creating an entity for every test makes the tests independent of 12 | * each other and advisable if the SB namespace allows it. If the namespace doesn't allow creation and deletion of many entities in a short span of time, the suite 13 | * will create one entity at the start, uses it for all test and deletes the entity at the end. 14 | * @return true if each test should create and delete its own entity. Else return false. 15 | */ 16 | public abstract boolean shouldCreateEntityForEveryTest(); 17 | } 18 | -------------------------------------------------------------------------------- /azure-servicebus/src/test/java/com/microsoft/azure/servicebus/TopicSendReceiveTests.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus; 2 | 3 | public class TopicSendReceiveTests extends SendReceiveTests { 4 | 5 | @Override 6 | public String getEntityNamePrefix() { 7 | return "TopicSendReceiveTests"; 8 | } 9 | 10 | @Override 11 | public boolean isEntityQueue() { 12 | return false; 13 | } 14 | 15 | @Override 16 | public boolean isEntityPartitioned() { 17 | return false; 18 | } 19 | 20 | @Override 21 | public boolean shouldCreateEntityForEveryTest() { 22 | return TestUtils.shouldCreateEntityForEveryTest(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /azure-servicebus/src/test/java/com/microsoft/azure/servicebus/TopicSessionTests.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus; 2 | 3 | public class TopicSessionTests extends SessionTests { 4 | 5 | @Override 6 | public String getEntityNamePrefix() { 7 | return "TopicSessionTests"; 8 | } 9 | 10 | @Override 11 | public boolean isEntityQueue() { 12 | return false; 13 | } 14 | 15 | @Override 16 | public boolean isEntityPartitioned() { 17 | return false; 18 | } 19 | 20 | @Override 21 | public boolean shouldCreateEntityForEveryTest() { 22 | return TestUtils.shouldCreateEntityForEveryTest(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /azure-servicebus/src/test/java/com/microsoft/azure/servicebus/management/ManagementException.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.management; 2 | 3 | public class ManagementException extends Exception{ 4 | 5 | private static final long serialVersionUID = -2884923885075130724L; 6 | 7 | public ManagementException() { 8 | super(); 9 | // TODO Auto-generated constructor stub 10 | } 11 | 12 | public ManagementException(String message, Throwable cause) { 13 | super(message, cause); 14 | // TODO Auto-generated constructor stub 15 | } 16 | 17 | public ManagementException(String message) { 18 | super(message); 19 | // TODO Auto-generated constructor stub 20 | } 21 | 22 | public ManagementException(Throwable cause) { 23 | super(cause); 24 | // TODO Auto-generated constructor stub 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /azure-servicebus/src/test/java/com/microsoft/azure/servicebus/management/QueueDescription.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.management; 2 | 3 | import java.time.Duration; 4 | 5 | public class QueueDescription extends ResourceDescripton{ 6 | // Supports only a limited set of properties, just for unit tests.. There are some quirks too. Order of xml elements also matters 7 | private static final String ATOM_XML_FORMAT = "" 8 | + "" 9 | + "" 10 | + "%s" 11 | + "%d" 12 | + "%b" 13 | + "%s" 14 | + "%s" 15 | + "%b" 16 | + "" 17 | + "" 18 | + ""; 19 | private String path; 20 | private String forwardTo; 21 | private String forwardDeadLetteredMessagesTo; 22 | private int maxSizeInMegaBytes; 23 | private int maxDeliveryCount; 24 | private boolean requiresDuplicateDetection; 25 | private boolean requiresSession; 26 | private boolean enableDeadLetteringOnMessageExpiration; 27 | private boolean enablePartitioning; 28 | private boolean enableExpress; 29 | private boolean supportsOrdering; 30 | private Duration lockDuration; 31 | private Duration defaultMessageTimeToLive; 32 | private Duration autoDeleteOnIdle; 33 | private Duration duplicateDetectionHistoryTimeWindow; 34 | 35 | public QueueDescription(String path) 36 | { 37 | this.path = path; 38 | this.defaultMessageTimeToLive = Duration.ofDays(7); 39 | this.maxSizeInMegaBytes = 1024; 40 | this.lockDuration = Duration.ofMinutes(1); 41 | this.maxDeliveryCount = 10; 42 | } 43 | 44 | @Override 45 | public String getPath() { 46 | return path; 47 | } 48 | 49 | public void setPath(String path) { 50 | this.path = path; 51 | } 52 | 53 | public int getMaxSizeInMegaBytes() { 54 | return maxSizeInMegaBytes; 55 | } 56 | 57 | public void setMaxSizeInMegaBytes(int maxSizeInMegaBytes) { 58 | this.maxSizeInMegaBytes = maxSizeInMegaBytes; 59 | } 60 | 61 | public boolean isRequiresSession() { 62 | return requiresSession; 63 | } 64 | 65 | public void setRequiresSession(boolean requiresSession) { 66 | this.requiresSession = requiresSession; 67 | } 68 | 69 | public boolean isEnablePartitioning() { 70 | return enablePartitioning; 71 | } 72 | 73 | public void setEnablePartitioning(boolean enablePartitioning) { 74 | this.enablePartitioning = enablePartitioning; 75 | } 76 | 77 | public Duration getLockDuration() { 78 | return lockDuration; 79 | } 80 | 81 | public void setLockDuration(Duration lockDuration) { 82 | this.lockDuration = lockDuration; 83 | } 84 | 85 | public Duration getDefaultMessageTimeToLive() { 86 | return defaultMessageTimeToLive; 87 | } 88 | 89 | public void setDefaultMessageTimeToLive(Duration defaultMessageTimeToLive) { 90 | this.defaultMessageTimeToLive = defaultMessageTimeToLive; 91 | } 92 | 93 | public int getMaxDeliveryCount() { 94 | return maxDeliveryCount; 95 | } 96 | 97 | public void setMaxDeliveryCount(int maxDeliveryCount) { 98 | this.maxDeliveryCount = maxDeliveryCount; 99 | } 100 | 101 | @Override 102 | String getAtomXml() 103 | { 104 | //return String.format(ATOM_XML_FORMAT, SerializerUtil.serializeDuration(this.lockDuration), this.maxSizeInMegaBytes, this.requiresSession, SerializerUtil.serializeDuration(this.defaultMessageTimeToLive), SerializerUtil.serializeEnablePartitioning(this.enablePartitioning)); 105 | return String.format(ATOM_XML_FORMAT, SerializerUtil.serializeDuration(this.lockDuration), this.maxSizeInMegaBytes, this.requiresSession, SerializerUtil.serializeDuration(this.defaultMessageTimeToLive), this.maxDeliveryCount, this.enablePartitioning); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /azure-servicebus/src/test/java/com/microsoft/azure/servicebus/management/ResourceDescripton.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.management; 2 | 3 | public abstract class ResourceDescripton { 4 | abstract String getAtomXml(); 5 | public abstract String getPath(); 6 | } 7 | -------------------------------------------------------------------------------- /azure-servicebus/src/test/java/com/microsoft/azure/servicebus/management/SerializerUtil.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.management; 2 | 3 | import java.time.Duration; 4 | 5 | // Fields that require special serializations 6 | public class SerializerUtil { 7 | 8 | public static String serializeDuration(Duration duration) 9 | { 10 | if(duration == null || duration.isNegative() || duration.isZero()) 11 | { 12 | return ""; 13 | } 14 | Duration remainingTime = duration; 15 | StringBuffer sb = new StringBuffer("P"); 16 | long days = remainingTime.toDays(); 17 | if(days > 0) 18 | { 19 | sb.append(days).append("D"); 20 | remainingTime = duration.minusDays(days); 21 | } 22 | if(!remainingTime.isZero()) 23 | { 24 | sb.append("T"); 25 | long hours = remainingTime.toHours(); 26 | if(hours > 0) 27 | { 28 | sb.append(hours).append("H"); 29 | remainingTime = duration.minusHours(hours); 30 | } 31 | 32 | long minutes = remainingTime.toMinutes(); 33 | if(minutes > 0) 34 | { 35 | sb.append(minutes).append("M"); 36 | remainingTime = duration.minusMinutes(minutes); 37 | } 38 | 39 | long seconds = remainingTime.getSeconds(); 40 | if(seconds > 0) 41 | { 42 | sb.append(seconds).append("S"); 43 | } 44 | } 45 | 46 | return sb.toString(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /azure-servicebus/src/test/java/com/microsoft/azure/servicebus/management/SubscriptionDescription.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.management; 2 | 3 | import java.time.Duration; 4 | 5 | public class SubscriptionDescription extends ResourceDescripton { 6 | private static final String ATOM_XML_FORMAT = "" 7 | + "" 8 | + "" 9 | + "%s" 10 | + "%b" 11 | + "%s" 12 | + "%s" 13 | + "" 14 | + "" 15 | + ""; 16 | 17 | private String topicPath; 18 | private String name; 19 | private String forwardTo; 20 | private String forwardDeadLetteredMessagesTo; 21 | private int maxDeliveryCount; 22 | private boolean requiresSession; 23 | private boolean enableDeadLetteringOnMessageExpiration; 24 | private boolean enableDeadLetteringOnFilterEvaluationExceptions; 25 | private Duration lockDuration; 26 | private Duration defaultMessageTimeToLive; 27 | private Duration autoDeleteOnIdle; 28 | 29 | public SubscriptionDescription(String topicPath, String subscriptionName) 30 | { 31 | this.topicPath = topicPath; 32 | this.name = subscriptionName; 33 | this.defaultMessageTimeToLive = Duration.ofDays(7); 34 | this.lockDuration = Duration.ofMinutes(1); 35 | this.maxDeliveryCount = 10; 36 | } 37 | 38 | public String getTopicPath() { 39 | return topicPath; 40 | } 41 | 42 | public void setTopicPath(String topicPath) { 43 | this.topicPath = topicPath; 44 | } 45 | 46 | public String getName() { 47 | return name; 48 | } 49 | 50 | public void setName(String name) { 51 | this.name = name; 52 | } 53 | 54 | public boolean isRequiresSession() { 55 | return requiresSession; 56 | } 57 | 58 | public Duration getLockDuration() { 59 | return lockDuration; 60 | } 61 | 62 | public void setLockDuration(Duration lockDuration) { 63 | this.lockDuration = lockDuration; 64 | } 65 | 66 | public void setRequiresSession(boolean requiresSession) { 67 | this.requiresSession = requiresSession; 68 | } 69 | 70 | @Override 71 | public String getPath() 72 | { 73 | return this.topicPath + "/subscriptions/" + this.name; 74 | } 75 | 76 | public int getMaxDeliveryCount() { 77 | return maxDeliveryCount; 78 | } 79 | 80 | public void setMaxDeliveryCount(int maxDeliveryCount) { 81 | this.maxDeliveryCount = maxDeliveryCount; 82 | } 83 | 84 | @Override 85 | String getAtomXml() 86 | { 87 | return String.format(ATOM_XML_FORMAT, SerializerUtil.serializeDuration(this.lockDuration), this.requiresSession, SerializerUtil.serializeDuration(this.defaultMessageTimeToLive), this.maxDeliveryCount); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /azure-servicebus/src/test/java/com/microsoft/azure/servicebus/management/TopicDescription.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.management; 2 | 3 | import java.time.Duration; 4 | 5 | public class TopicDescription extends ResourceDescripton{ 6 | private static final String ATOM_XML_FORMAT = "" 7 | + "" 8 | + "" 9 | + "%d" 10 | + "%b" 11 | + "" 12 | + "" 13 | + ""; 14 | 15 | private String path; 16 | private int maxSizeInMegaBytes; 17 | private boolean enablePartitioning; 18 | private boolean enableSubscriptionPartitioning; 19 | private boolean requiresDuplicateDetection; 20 | private boolean enableExpress; 21 | private boolean supportsOrdering; 22 | private boolean enableFilteringMessagesBeforePublishing; 23 | private Duration autoDeleteOnIdle; 24 | private Duration duplicateDetectionHistoryTimeWindow; 25 | 26 | public TopicDescription(String path) 27 | { 28 | this.path = path; 29 | this.maxSizeInMegaBytes = 1024; 30 | } 31 | 32 | @Override 33 | public String getPath() { 34 | return path; 35 | } 36 | 37 | public void setPath(String path) { 38 | this.path = path; 39 | } 40 | 41 | public int getMaxSizeInMegaBytes() { 42 | return maxSizeInMegaBytes; 43 | } 44 | 45 | public void setMaxSizeInMegaBytes(int maxSizeInMegaBytes) { 46 | this.maxSizeInMegaBytes = maxSizeInMegaBytes; 47 | } 48 | 49 | public boolean isEnablePartitioning() { 50 | return enablePartitioning; 51 | } 52 | 53 | public void setEnablePartitioning(boolean enablePartitioning) { 54 | this.enablePartitioning = enablePartitioning; 55 | } 56 | 57 | @Override 58 | String getAtomXml() { 59 | return String.format(ATOM_XML_FORMAT, this.maxSizeInMegaBytes, this.enablePartitioning); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /azure-servicebus/src/test/java/com/microsoft/azure/servicebus/primitives/ConnectionStringBuilderTests.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.primitives; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | 7 | public class ConnectionStringBuilderTests { 8 | 9 | @Test 10 | public void ConnectionStringBuilderTest() { 11 | String connectionString = "Endpoint=sb://test.servicebus.windows.net/;SharedAccessSignatureToken=SharedAccessSignature sr=amqp%3A%2F%2test.servicebus.windows.net%2topic"; 12 | ConnectionStringBuilder builder = new ConnectionStringBuilder(connectionString); 13 | 14 | assertEquals("SharedAccessSignature sr=amqp%3A%2F%2test.servicebus.windows.net%2topic", builder.getSharedAccessSignatureToken()); 15 | assertEquals(connectionString, builder.toString()); 16 | } 17 | 18 | } -------------------------------------------------------------------------------- /azure-servicebus/src/test/java/com/microsoft/azure/servicebus/primitives/UtilsTests.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.servicebus.primitives; 2 | 3 | import java.time.Instant; 4 | import java.util.UUID; 5 | 6 | import org.junit.Test; 7 | 8 | import com.microsoft.azure.servicebus.primitives.Util; 9 | 10 | import org.junit.Assert; 11 | 12 | public class UtilsTests { 13 | @Test 14 | public void testGuidConversionFromDotNetToJava() 15 | { 16 | String guidString = "b5dc4a70-ac5d-43b3-b132-ec8fcdac3a9d"; 17 | // Java bytes are signed where as dotNet bytes are unsigned. No problem type casting larger than 127 unsigned bytes to java signed bytes 18 | // as we are interested only in the individual bits for UUID conversion. 19 | byte[] dotNetGuidBytes = {112, 74, (byte)220, (byte)181, 93, (byte)172, (byte)179, 67, (byte)177, 50, (byte)236, (byte)143, (byte)205, (byte)172, 58, (byte)157}; 20 | UUID convertedGuid = Util.convertDotNetBytesToUUID(dotNetGuidBytes); 21 | Assert.assertEquals("UUID conversion from DotNet to Java failed", guidString, convertedGuid.toString()); 22 | } 23 | 24 | @Test 25 | public void testGuidConversionFromJavaToDotNet() 26 | { 27 | String guidString = "b5dc4a70-ac5d-43b3-b132-ec8fcdac3a9d"; 28 | UUID javaGuid = UUID.fromString(guidString); 29 | byte[] dotNetGuidBytes = {112, 74, (byte)220, (byte)181, 93, (byte)172, (byte)179, 67, (byte)177, 50, (byte)236, (byte)143, (byte)205, (byte)172, 58, (byte)157}; 30 | byte[] convertedBytes = Util.convertUUIDToDotNetBytes(javaGuid); 31 | Assert.assertArrayEquals("UUID conversion from Java to DotNet failed", dotNetGuidBytes, convertedBytes); 32 | } 33 | 34 | @Test 35 | public void testDateTimeConversionFromDotNetToJava() 36 | { 37 | String dotNetDateTimeString = "2016-11-30T20:57:01.4638052Z"; 38 | long dotNetTicks = 636161362214638052l; 39 | Instant convertedInstant = Util.convertDotNetTicksToInstant(dotNetTicks); 40 | Instant expectedInstant = Instant.parse(dotNetDateTimeString); 41 | Assert.assertEquals("DateTime conversion from DotNet to Java failed", expectedInstant, convertedInstant); 42 | } 43 | 44 | @Test 45 | public void testDateTimeConversionFromJavaToDotNet() 46 | { 47 | String dotNetDateTimeString = "2016-11-30T20:57:01.4638052Z"; 48 | long dotNetTicks = 636161362214638052l; 49 | Instant javaInstant = Instant.parse(dotNetDateTimeString); 50 | Assert.assertEquals("DateTime conversion from Java to DotNet failed", dotNetTicks, Util.convertInstantToDotNetTicks(javaInstant)); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /build/azuredeploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "serviceBusNamespaceName": { 6 | "type": "string", 7 | "metadata": { 8 | "description": "Name of the Service Bus namespace" 9 | } 10 | } 11 | }, 12 | "variables": { 13 | "location": "[resourceGroup().location]", 14 | "sbVersion": "2015-08-01", 15 | "defaultSASKeyName": "RootManageSharedAccessKey", 16 | "authRuleResourceId": "[resourceId('Microsoft.ServiceBus/namespaces/authorizationRules', parameters('serviceBusNamespaceName'), variables('defaultSASKeyName'))]" 17 | }, 18 | "resources": [ 19 | { 20 | "apiVersion": "[variables('sbVersion')]", 21 | "name": "[parameters('serviceBusNamespaceName')]", 22 | "type": "Microsoft.ServiceBus/Namespaces", 23 | "location": "[variables('location')]", 24 | "sku": { 25 | "name": "Standard", 26 | "tier": "Standard" 27 | }, 28 | "resources": [ 29 | ] 30 | } 31 | ], 32 | "outputs": { 33 | "NamespaceConnectionString": { 34 | "type": "string", 35 | "value": "[listkeys(variables('authRuleResourceId'), variables('sbVersion')).primaryConnectionString]" 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /contribute.md: -------------------------------------------------------------------------------- 1 | ## What to contribute 2 | There are many ways that you can contribute to the Azure Event Hubs client project: 3 | 4 | * Submit a bug 5 | * Submit a code fix for a bug 6 | * Submit code to add a new platform/language support to the project, or modify existing code 7 | * Submit additions or modifications to the documentation 8 | * Submit a feature request 9 | 10 | ## Contributing Code 11 | To contribute code you need to issue a Pull Request against the develop branch. All code submissions will be reviewed and tested by the team, and those that meet a high bar for both quality and design/roadmap appropriateness will be merged into the source. Be sure to follow the existing file/folder structure when adding new boards or sensors. 12 | 13 | You must sign a [Contribution License Agreement](https://cla.microsoft.com/) ([CLA](https://cla.microsoft.com/)) before submitting a Pull Request. To complete the CLA, you will need to submit the request via the form and then electronically sign the CLA when you receive the email containing the link to the document. 14 | 15 | ## Big contributions 16 | If your contribution is significantly big it is better to first check with the project developers in order to make sure the change aligns with the long term plans. This can be done simply by submitting a question via the GitHub Issues section. 17 | 18 | ## Things to keep in mind when contributing 19 | Some guidance for when you make a contribution: 20 | 21 | * Add/update unit tests and code as required by your change 22 | * Make sure you run all the unit tests on the affected platform(s)/languages. If the change is in common code, generally running on one platform would be acceptable. 23 | * Run end-to-end tests or simple sample code to make sure the lib works in an end-to-end scenario. 24 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | azure-servicebus-parent 3 | Java library for Azure Service Bus 4 | 4.0.0 5 | com.microsoft.azure 6 | azure-servicebus-parent 7 | 1.0.0 8 | pom 9 | 10 | https://github.com/Azure/azure-service-bus-java 11 | 12 | 13 | 0.31.0 14 | 4.12 15 | 1.7.0 16 | 1.2.19-SNAPSHOT 17 | 18 | 19 | 20 | azure-servicebus 21 | 22 | -------------------------------------------------------------------------------- /service-bus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/azure-service-bus-java/48bedb86356911b68736c36086d30934be4e2c65/service-bus.png --------------------------------------------------------------------------------