├── .editorconfig ├── .gitignore ├── CODE_OF_CONDUCT.md ├── LICENSE.txt ├── README.md ├── SECURITY.md ├── dependency-injection ├── README.md ├── dagger-function │ ├── README.md │ ├── host.json │ ├── img.png │ ├── img_1.png │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── azfs │ │ │ ├── Function.java │ │ │ ├── component │ │ │ └── FunctionComponent.java │ │ │ ├── dihook │ │ │ └── MyFunctionInstanceInjector.java │ │ │ ├── model │ │ │ └── Communicator.java │ │ │ └── module │ │ │ └── FunctionModule.java │ │ └── resources │ │ └── META-INF │ │ └── services │ │ └── com.microsoft.azure.functions.spi.inject.FunctionInstanceInjector └── guice-function │ ├── .gitignore │ ├── README.md │ ├── host.json │ ├── img.png │ ├── img_2.png │ ├── pom.xml │ └── src │ └── main │ ├── java │ └── com │ │ └── azfs │ │ ├── BasicModule.java │ │ ├── Communicator.java │ │ ├── DefaultCommunicatorImpl.java │ │ ├── Function.java │ │ └── dihook │ │ └── FunctionGuiceFactory.java │ └── resources │ └── META-INF │ └── services │ └── com.microsoft.azure.functions.spi.inject.FunctionInstanceInjector ├── distributed-tracing ├── README.md ├── host.json ├── local.settings.json ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── azfs │ └── example │ └── DistributedTracingFunction.java ├── durable-function ├── README.md ├── host.json ├── local.settings.json ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── azfs │ └── example │ └── DurableFunction.java ├── spring-cloud ├── .gitignore ├── Dockerfile ├── README.md ├── pom.xml └── src │ ├── main │ ├── java │ │ └── example │ │ │ ├── Application.java │ │ │ ├── hello │ │ │ ├── Hello.java │ │ │ ├── HelloHandler.java │ │ │ └── model │ │ │ │ ├── Greeting.java │ │ │ │ └── User.java │ │ │ └── uppercase │ │ │ ├── Config.java │ │ │ ├── EchoHandler.java │ │ │ └── UppercaseHandler.java │ └── resources │ │ └── host.json │ └── test │ └── java │ └── example │ └── hello │ └── HelloTest.java └── triggers-bindings ├── .mvn └── wrapper │ └── maven-wrapper.properties ├── README.md ├── build.gradle ├── gradle └── wrapper │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── host.json ├── local.settings.json ├── mvnw ├── mvnw.cmd ├── pom.xml ├── settings.gradle └── src ├── main └── java │ └── com │ └── functions │ ├── BlobTriggerFunction.java │ ├── CosmosDBTriggerFunction.java │ ├── EventGridTriggerFunction.java │ ├── EventHubTriggerFunction.java │ ├── Function.java │ ├── KafkaTriggerFunction.java │ ├── QueueTriggerFunction.java │ ├── ServiceBusQueueTriggerFunction.java │ ├── ServiceBusTopicTriggerFunction.java │ ├── TableFunction.java │ └── TimerTriggerFunction.java └── test └── java └── com └── functions ├── EventHubTriggerFunctionTest.java ├── FunctionTest.java └── HttpResponseMessageMock.java /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_size = 4 6 | indent_style = space 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | # Build output 26 | target/ 27 | 28 | *.factorypath 29 | 30 | # IDE 31 | .idea/ 32 | *.iml 33 | .classpath 34 | .project 35 | .settings/ 36 | .checkstyle 37 | .vscode/ 38 | 39 | # macOS 40 | .DS_Store 41 | 42 | # gradle-wrapper 43 | !gradle/wrapper/gradle-wrapper.jar 44 | !gradle/wrapper/gradle-wrapper.properties 45 | 46 | # integration test 47 | */src/it/*/bin 48 | 49 | jacoco.exec 50 | bin/ 51 | 52 | # mvnw 53 | !.mvn/wrapper/maven-wrapper.jar 54 | 55 | build/ 56 | 57 | .gradle/ 58 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 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 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_type: sample 3 | languages: 4 | - java 5 | products: 6 | - azure-functions 7 | - azure 8 | description: "This repository contains sample for Azure Functions in Java" 9 | urlFragment: "azure-functions-java" 10 | --- 11 | 12 | # Azure functions samples in Java 13 | 14 | This repository contains samples which show the usage of [Azure Functions](https://docs.microsoft.com/en-us/azure/azure-functions/) in Java for the below scenarios. 15 | 16 | | Scenario | Description | 17 | |-------------------|--------------------------------------------| 18 | | [HttpTrigger](./triggers-bindings/src/main/java/com/functions/Function.java) | Basic HttpTrigger and FixedDelayRetry with HttpTrigger. | 19 | | [BlobTrigger](./triggers-bindings/src/main/java/com/functions/BlobTriggerFunction.java) | BlobTrigger, read blob using BlobInput binding and output to blob using BlobOutput binding. | 20 | | [CosmosDBTrigger](./triggers-bindings/src/main/java/com/functions/CosmosDBTriggerFunction.java) | CosmosDBTrigger, read cosmos DB entries with CosmosDBInput binding and output to cosmos DB CosmosDBOutput binding. | 21 | | [TimerTrigger](./triggers-bindings/src/main/java/com/functions/TimerTriggerFunction.java) | Basic periodic TimerTrigger. | 22 | | [EventGridTrigger](./triggers-bindings/src/main/java/com/functions/EventGridTriggerFunction.java) | EventGridTrigger and send event to Event Grid using EventGridOutput binding. | 23 | | [EventHubTrigger](./triggers-bindings/src/main/java/com/functions/EventHubTriggerFunction.java) | EventHubTrigger for message received in event grid and output to event grid using EventHubOutput binding. | 24 | | [KafkaTrigger](./triggers-bindings/src/main/java/com/functions/KafkaTriggerFunction.java) | KafkaTrigger with KafkaOutput and QueueOutput example. | 25 | | [QueueTrigger](./triggers-bindings/src/main/java/com/functions/QueueTriggerFunction.java) | QueueTrigger to read content from queue and output to queue using QueueOutput binding. | 26 | | [ServiceBusQueueTrigger](./triggers-bindings/src/main/java/com/functions/ServiceBusQueueTriggerFunction.java) | ServiceBusQueueTrigger to read message from a queue in service bus and output to service bus queue using ServiceBusQueueOutput binding. | 27 | | [ServiceBusTopicTrigger](./triggers-bindings/src/main/java/com/functions/ServiceBusTopicTriggerFunction.java) | ServiceBusTopicTrigger to read message from a topic in service bus and output to service bus topic using ServiceBusTopicOutput binding. | 28 | | [Table function](./triggers-bindings/src/main/java/com/functions/TableFunction.java) | Basic example to read and write to table in Azure Storage using TableInput and TableOutput binding. | 29 | | [Durable function](./durable-function/src/main/java/com/azfs/example/DurableFunction.java) | Durable function example to start an orchestration and follow activity chaining. | 30 | | [Distributed tracing](./distributed-tracing/src/main/java/com/azfs/example/DistributedTracingFunction.java) | Distributed tracing example that adds entries to a MYSQL database via JDBC, adds custom metrics to the Application Insights and outputs to cosmos DB CosmosDBOutput binding. | 31 | | [Dependency injection - Dagger](./dependency-injection/dagger-function/src/main/java/com/azfs/Function.java) | Dagger example that shows the usage of dependency injection with azure functions. | 32 | | [Dependency injection - Guice](./dependency-injection/guice-function/src/main/java/com/azfs/Function.java) | Google guice example that shows the usage of dependency injection with azure functions. | 33 | | [Spring cloud](./spring-cloud/src/main/java/example/uppercase/UppercaseHandler.java) | Usage of Spring cloud to develop a function. | 34 | 35 | 36 | ## Contents 37 | 38 | Outlines the contents of this repository. It helps users navigate the codebase, build configuration and any related assets. 39 | 40 | | File/folder | Description | 41 | |-------------------|--------------------------------------------| 42 | | `triggers-bindings` | Triggers and bindings available in Azure functions. | 43 | | `dependency-injection` | Integration of Google Guice and Dagger with Azure Functions. | 44 | | `spring-cloud` | Usage of Spring cloud to develop a Java function. | 45 | | `distributed-tracing` | Sample that shows the usage of distributed tracing coupled with azure functions. | 46 | | `durable-function` | Durable function example to run orchestrations and activities. | 47 | | `.gitignore` | Define what to ignore at commit time. | 48 | | `CHANGELOG.md` | List of changes to the sample. | 49 | | `CONTRIBUTING.md` | Guidelines for contributing to the sample. | 50 | | `README.md` | This README file. | 51 | | `LICENSE.txt` | The license for the sample. | 52 | 53 | ## Prerequisites 54 | 55 | - Gradle 4.10+ 56 | - Latest [Function Core Tools](https://aka.ms/azfunc-install) 57 | - Azure CLI. This plugin use Azure CLI for authentication, please make sure you have Azure CLI installed and logged in. 58 | 59 | ## Setup 60 | 61 | - Please refer individual directories for sample specific setup. Some common setup instructions are provided below. 62 | 63 | - ```cmd 64 | az login 65 | az account set -s 66 | ``` 67 | - Update the Application settings in Azure portal with the required parameters as below 68 | - AzureWebJobsStorage: Connection string to your storage account 69 | - CosmosDBDatabaseName: Cosmos database name. Example: ItemCollectionIn 70 | - CosmosDBCollectionName:Cosmos database collection name. Example: ItemDb 71 | - AzureWebJobsCosmosDBConnectionString: Connection string to your Cosmos database 72 | - AzureWebJobsEventGridOutputBindingTopicUriString: Event Grid URI 73 | - AzureWebJobsEventGridOutputBindingTopicKeyString: Event Grid string 74 | - AzureWebJobsEventHubSender, AzureWebJobsEventHubSender_2 : Event hub connection string 75 | - AzureWebJobsServiceBus: Service bus connection string 76 | - SBQueueName: Service bus queue name. Example: test-input-java 77 | - SBTopicName: Service bus topic name. Example: javaworkercitopic2 78 | - SBTopicSubName: Service bus topic name. Example: javaworkercisub 79 | - Documentation on how to [manage connection strings](https://docs.microsoft.com/en-gb/azure/storage/common/storage-account-keys-manage?tabs=azure-portal) and [access keys](https://docs.microsoft.com/en-gb/azure/storage/common/storage-configure-connection-string#create-a-connection-string-for-an-azure-storage-account) 80 | - Update `host.json` with the right extension bundle version. `V3 - [1.*, 2.0.0) and V4 - [2.*, 3.0.0)` 81 | 82 | 83 | ## Running the sample 84 | 85 | ```cmd 86 | ./mvnw clean package azure-functions:run 87 | ``` 88 | 89 | ```cmd 90 | ./gradlew clean azureFunctionsRun 91 | ``` 92 | 93 | ## Deploy the sample on Azure 94 | 95 | 96 | ```cmd 97 | ./mvnw clean package azure-functions:deploy 98 | ``` 99 | 100 | ```cmd 101 | ./gradlew clean azureFunctionsDeploy 102 | ``` 103 | 104 | > NOTE: please replace '/' with '\\' when you are running on windows. 105 | 106 | 107 | ## Contributing 108 | 109 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 110 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 111 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. 112 | 113 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide 114 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions 115 | provided by the bot. You will only need to do this once across all repos using our CLA. 116 | 117 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 118 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 119 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 120 | 121 | ## Telemetry 122 | This project collects usage data and sends it to Microsoft to help improve our products and services. 123 | Read Microsoft's [privacy statement](https://privacy.microsoft.com/en-us/privacystatement) to learn more. 124 | If you would like to opt out of sending telemetry data to Microsoft, you can set `allowTelemetry` to false in the plugin configuration. 125 | Please read our [document](https://github.com/microsoft/azure-gradle-plugins/wiki/Configuration) to find more details about *allowTelemetry*. 126 | -------------------------------------------------------------------------------- /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 [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)) of a security vulnerability, 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://msrc.microsoft.com/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 the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). 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://www.microsoft.com/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://microsoft.com/msrc/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://www.microsoft.com/en-us/msrc/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /dependency-injection/README.md: -------------------------------------------------------------------------------- 1 | ## Dependency Injection Examples for Azure Java Functions 2 | 3 | This rep contains examples that integrate Google Dagger2 and Google Juice with Azure Java Functions. 4 | -------------------------------------------------------------------------------- /dependency-injection/dagger-function/README.md: -------------------------------------------------------------------------------- 1 | # azure-function-guice 2 | Integration Google Dagger2 with Azure Functions 3 | 4 | Utilize [com.microsoft.azure.functions.spi.inject.FunctionInstanceInjector](https://github.com/Azure/azure-functions-java-additions/blob/dev/azure-functions-java-spi/src/main/java/com/microsoft/azure/functions/spi/inject/FunctionInstanceInjector.java) provided by azure functions java worker to integrate Google Dagger2 framework into Azure Java Function. 5 | 6 | ## Local Setup 7 | 1. Clone the repo 8 | 2. Enter corresponding directory and run `mvn clean package` to build the project 9 | 3. Run `mvn azure-functions:run` to run the project on local. 10 | Local example: 11 | 12 | ![img.png](img.png) 13 | 14 | ![img_1.png](img_1.png) 15 | 4. Run `mvn azure-functions:deploy` to deploy the function app, for more info about deploy azure function java app please refer to [deploy java function app](https://learn.microsoft.com/en-us/azure/azure-functions/create-first-function-cli-java?tabs=bash%2Cazure-cli%2Cbrowser#deploy-the-function-project-to-azure) -------------------------------------------------------------------------------- /dependency-injection/dagger-function/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "extensionBundle": { 4 | "id": "Microsoft.Azure.Functions.ExtensionBundle", 5 | "version": "[3.*, 4.0.0)" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /dependency-injection/dagger-function/img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure-Samples/azure-functions-samples-java/2bd0ceb65134d794539e53c3d0e0fe0787c54470/dependency-injection/dagger-function/img.png -------------------------------------------------------------------------------- /dependency-injection/dagger-function/img_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure-Samples/azure-functions-samples-java/2bd0ceb65134d794539e53c3d0e0fe0787c54470/dependency-injection/dagger-function/img_1.png -------------------------------------------------------------------------------- /dependency-injection/dagger-function/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | com.azfs.example 6 | dagger-function 7 | 1.0-SNAPSHOT 8 | jar 9 | 10 | Azure Java Functions 11 | 12 | 13 | UTF-8 14 | 1.8 15 | 1.21.0 16 | 2.0.1 17 | dagger-function-20221101192648097 18 | 19 | 20 | 21 | 22 | com.microsoft.azure.functions 23 | azure-functions-java-library 24 | ${azure.functions.java.library.version} 25 | 26 | 27 | 28 | com.google.dagger 29 | dagger 30 | 2.44 31 | 32 | 33 | 34 | com.microsoft.azure.functions 35 | azure-functions-java-spi 36 | 1.0.0 37 | provided 38 | 39 | 40 | 41 | 42 | org.junit.jupiter 43 | junit-jupiter 44 | 5.4.2 45 | test 46 | 47 | 48 | 49 | org.mockito 50 | mockito-core 51 | 2.23.4 52 | test 53 | 54 | 55 | 56 | 57 | 58 | 59 | org.apache.maven.plugins 60 | maven-compiler-plugin 61 | 3.8.1 62 | 63 | ${java.version} 64 | ${java.version} 65 | ${project.build.sourceEncoding} 66 | 67 | 68 | com.google.dagger 69 | dagger-compiler 70 | 2.16 71 | 72 | 73 | 74 | 75 | 76 | com.microsoft.azure 77 | azure-functions-maven-plugin 78 | ${azure.functions.maven.plugin.version} 79 | 80 | 81 | ${functionAppName} 82 | 83 | java-functions-group 84 | 85 | java-functions-app-service-plan 86 | 87 | 88 | westus 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | windows 98 | 8 99 | 100 | 101 | 102 | FUNCTIONS_EXTENSION_VERSION 103 | ~4 104 | 105 | 106 | 107 | 108 | 109 | package-functions 110 | 111 | package 112 | 113 | 114 | 115 | 116 | 117 | 118 | maven-clean-plugin 119 | 3.1.0 120 | 121 | 122 | 123 | obj 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | -------------------------------------------------------------------------------- /dependency-injection/dagger-function/src/main/java/com/azfs/Function.java: -------------------------------------------------------------------------------- 1 | package com.azfs; 2 | 3 | import com.azfs.model.Communicator; 4 | import com.microsoft.azure.functions.ExecutionContext; 5 | import com.microsoft.azure.functions.HttpMethod; 6 | import com.microsoft.azure.functions.HttpRequestMessage; 7 | import com.microsoft.azure.functions.HttpResponseMessage; 8 | import com.microsoft.azure.functions.HttpStatus; 9 | import com.microsoft.azure.functions.annotation.AuthorizationLevel; 10 | import com.microsoft.azure.functions.annotation.FunctionName; 11 | import com.microsoft.azure.functions.annotation.HttpTrigger; 12 | 13 | import javax.inject.Inject; 14 | import java.util.Optional; 15 | 16 | /** 17 | * Azure Functions with HTTP Trigger. 18 | */ 19 | public class Function { 20 | /** 21 | * This function listens at endpoint "/api/HttpExample". Two ways to invoke it using "curl" command in bash: 22 | * 1. curl -d "HTTP Body" {your host}/api/HttpExample 23 | * 2. curl "{your host}/api/HttpExample?name=HTTP%20Query" 24 | */ 25 | 26 | private final Communicator communicator; 27 | 28 | @Inject 29 | public Function(Communicator communicator) { 30 | this.communicator = communicator; 31 | } 32 | 33 | @FunctionName("HttpExample") 34 | public HttpResponseMessage run( 35 | @HttpTrigger( 36 | name = "req", 37 | methods = {HttpMethod.GET, HttpMethod.POST}, 38 | authLevel = AuthorizationLevel.ANONYMOUS) 39 | HttpRequestMessage> request, 40 | final ExecutionContext context) { 41 | context.getLogger().info("Java HTTP trigger processed a request."); 42 | 43 | // Parse query parameter 44 | final String query = request.getQueryParameters().get("name"); 45 | final String name = request.getBody().orElse(query); 46 | 47 | communicator.communicate(context); 48 | 49 | if (name == null) { 50 | return request.createResponseBuilder(HttpStatus.BAD_REQUEST).body("Please pass a name on the query string or in the request body").build(); 51 | } else { 52 | return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build(); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /dependency-injection/dagger-function/src/main/java/com/azfs/component/FunctionComponent.java: -------------------------------------------------------------------------------- 1 | package com.azfs.component; 2 | 3 | import com.azfs.Function; 4 | import com.azfs.module.FunctionModule; 5 | import dagger.Component; 6 | 7 | @Component(modules = FunctionModule.class) 8 | public interface FunctionComponent { 9 | Function buildFunction(); 10 | } 11 | -------------------------------------------------------------------------------- /dependency-injection/dagger-function/src/main/java/com/azfs/dihook/MyFunctionInstanceInjector.java: -------------------------------------------------------------------------------- 1 | package com.azfs.dihook; 2 | 3 | import com.azfs.component.DaggerFunctionComponent; 4 | import com.microsoft.azure.functions.spi.inject.FunctionInstanceInjector; 5 | 6 | public class MyFunctionInstanceInjector implements FunctionInstanceInjector { 7 | @Override 8 | public T getInstance(Class aClass) throws Exception { 9 | return (T) DaggerFunctionComponent.create().buildFunction(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /dependency-injection/dagger-function/src/main/java/com/azfs/model/Communicator.java: -------------------------------------------------------------------------------- 1 | package com.azfs.model; 2 | 3 | import com.microsoft.azure.functions.ExecutionContext; 4 | 5 | public class Communicator { 6 | private final String id; 7 | 8 | public Communicator(String id) { 9 | this.id = id; 10 | } 11 | 12 | public void communicate(ExecutionContext context){ 13 | context.getLogger().info("Message sent out from injected communicator :) "); 14 | //add your own logics ... 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /dependency-injection/dagger-function/src/main/java/com/azfs/module/FunctionModule.java: -------------------------------------------------------------------------------- 1 | package com.azfs.module; 2 | 3 | import com.azfs.model.Communicator; 4 | import dagger.Module; 5 | import dagger.Provides; 6 | 7 | @Module 8 | public class FunctionModule { 9 | @Provides 10 | public Communicator provideCommunicator() { 11 | return new Communicator("123"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /dependency-injection/dagger-function/src/main/resources/META-INF/services/com.microsoft.azure.functions.spi.inject.FunctionInstanceInjector: -------------------------------------------------------------------------------- 1 | com.azfs.dihook.MyFunctionInstanceInjector -------------------------------------------------------------------------------- /dependency-injection/guice-function/.gitignore: -------------------------------------------------------------------------------- 1 | # Build output 2 | target/ 3 | *.class 4 | 5 | # Log file 6 | *.log 7 | 8 | # BlueJ files 9 | *.ctxt 10 | 11 | # Mobile Tools for Java (J2ME) 12 | .mtj.tmp/ 13 | 14 | # Package Files # 15 | *.jar 16 | *.war 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | # IDE 26 | .idea/ 27 | *.iml 28 | .settings/ 29 | .project 30 | .classpath 31 | .vscode/ 32 | 33 | # macOS 34 | .DS_Store 35 | 36 | # Azure Functions 37 | local.settings.json 38 | bin/ 39 | obj/ 40 | -------------------------------------------------------------------------------- /dependency-injection/guice-function/README.md: -------------------------------------------------------------------------------- 1 | # azure-function-guice 2 | Integration Google Guice with Azure Functions 3 | 4 | Utilize [com.microsoft.azure.functions.spi.inject.FunctionInstanceInjector](https://github.com/Azure/azure-functions-java-additions/blob/dev/azure-functions-java-spi/src/main/java/com/microsoft/azure/functions/spi/inject/FunctionInstanceInjector.java) provided by azure functions java worker to integrate Google Guice framework into Azure Java Function. 5 | 6 | ## Local Setup 7 | 1. Clone the repo 8 | 2. Enter corresponding directory and run `mvn clean package` to build the project 9 | 3. Run `mvn azure-functions:run` to run the project on local. 10 | Local example: 11 | 12 | ![img.png](img.png) 13 | 14 | ![img_2.png](img_2.png) 15 | 4. Run `mvn azure-functions:deploy` to deploy the function app, for more info about deploy azure function java app please refer to [deploy java function app](https://learn.microsoft.com/en-us/azure/azure-functions/create-first-function-cli-java?tabs=bash%2Cazure-cli%2Cbrowser#deploy-the-function-project-to-azure) -------------------------------------------------------------------------------- /dependency-injection/guice-function/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "extensionBundle": { 4 | "id": "Microsoft.Azure.Functions.ExtensionBundle", 5 | "version": "[3.*, 4.0.0)" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /dependency-injection/guice-function/img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure-Samples/azure-functions-samples-java/2bd0ceb65134d794539e53c3d0e0fe0787c54470/dependency-injection/guice-function/img.png -------------------------------------------------------------------------------- /dependency-injection/guice-function/img_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure-Samples/azure-functions-samples-java/2bd0ceb65134d794539e53c3d0e0fe0787c54470/dependency-injection/guice-function/img_2.png -------------------------------------------------------------------------------- /dependency-injection/guice-function/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | com.azfs.example 6 | juice-test 7 | 1.0-SNAPSHOT 8 | jar 9 | 10 | Azure Java Functions 11 | 12 | 13 | UTF-8 14 | 1.8 15 | 1.19.0 16 | 2.1.0 17 | juice-test-20220912191553642 18 | 19 | 20 | 21 | 22 | com.microsoft.azure.functions 23 | azure-functions-java-library 24 | ${azure.functions.java.library.version} 25 | 26 | 27 | com.microsoft.azure.functions 28 | azure-functions-java-spi 29 | 1.0.0 30 | 31 | 32 | 33 | 34 | com.google.inject 35 | guice 36 | 5.1.0 37 | 38 | 39 | 40 | 41 | 42 | org.junit.jupiter 43 | junit-jupiter 44 | 5.4.2 45 | test 46 | 47 | 48 | 49 | org.mockito 50 | mockito-core 51 | 2.23.4 52 | test 53 | 54 | 55 | 56 | 57 | 58 | 59 | org.apache.maven.plugins 60 | maven-compiler-plugin 61 | 3.8.1 62 | 63 | ${java.version} 64 | ${java.version} 65 | ${project.build.sourceEncoding} 66 | 67 | 68 | 69 | com.microsoft.azure 70 | azure-functions-maven-plugin 71 | ${azure.functions.maven.plugin.version} 72 | 73 | 74 | ${functionAppName} 75 | 76 | java-functions-group 77 | 78 | java-functions-app-service-plan 79 | 80 | 81 | westus 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | windows 91 | 8 92 | 93 | 94 | 95 | FUNCTIONS_EXTENSION_VERSION 96 | ~4 97 | 98 | 99 | 100 | 101 | 102 | package-functions 103 | 104 | package 105 | 106 | 107 | 108 | 109 | 110 | 111 | maven-clean-plugin 112 | 3.1.0 113 | 114 | 115 | 116 | obj 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /dependency-injection/guice-function/src/main/java/com/azfs/BasicModule.java: -------------------------------------------------------------------------------- 1 | package com.azfs; 2 | 3 | import com.google.inject.AbstractModule; 4 | 5 | public class BasicModule extends AbstractModule { 6 | 7 | @Override 8 | protected void configure() { 9 | bind(Communicator.class).to(DefaultCommunicatorImpl.class); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /dependency-injection/guice-function/src/main/java/com/azfs/Communicator.java: -------------------------------------------------------------------------------- 1 | package com.azfs; 2 | 3 | import com.microsoft.azure.functions.ExecutionContext; 4 | 5 | public interface Communicator { 6 | boolean sendMessage(ExecutionContext context); 7 | } 8 | -------------------------------------------------------------------------------- /dependency-injection/guice-function/src/main/java/com/azfs/DefaultCommunicatorImpl.java: -------------------------------------------------------------------------------- 1 | package com.azfs; 2 | 3 | import com.microsoft.azure.functions.ExecutionContext; 4 | 5 | public class DefaultCommunicatorImpl implements Communicator{ 6 | @Override 7 | public boolean sendMessage(ExecutionContext context) { 8 | context.getLogger().info("Message sent out from injected communicator :) "); 9 | //add your own logic... 10 | return true; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /dependency-injection/guice-function/src/main/java/com/azfs/Function.java: -------------------------------------------------------------------------------- 1 | package com.azfs; 2 | 3 | import com.google.inject.Inject; 4 | import com.microsoft.azure.functions.ExecutionContext; 5 | import com.microsoft.azure.functions.HttpMethod; 6 | import com.microsoft.azure.functions.HttpRequestMessage; 7 | import com.microsoft.azure.functions.HttpResponseMessage; 8 | import com.microsoft.azure.functions.HttpStatus; 9 | import com.microsoft.azure.functions.annotation.AuthorizationLevel; 10 | import com.microsoft.azure.functions.annotation.FunctionName; 11 | import com.microsoft.azure.functions.annotation.HttpTrigger; 12 | 13 | import java.util.Optional; 14 | 15 | /** 16 | * Azure Functions with HTTP Trigger. 17 | */ 18 | public class Function { 19 | /** 20 | * This function listens at endpoint "/api/HttpExample". Two ways to invoke it using "curl" command in bash: 21 | * 1. curl -d "HTTP Body" {your host}/api/HttpExample 22 | * 2. curl "{your host}/api/HttpExample?name=HTTP%20Query" 23 | */ 24 | 25 | @Inject 26 | public Communicator communicator; 27 | 28 | @FunctionName("HttpExample") 29 | public HttpResponseMessage run( 30 | @HttpTrigger( 31 | name = "req", 32 | methods = {HttpMethod.GET, HttpMethod.POST}, 33 | authLevel = AuthorizationLevel.ANONYMOUS) 34 | HttpRequestMessage> request, 35 | final ExecutionContext context) { 36 | context.getLogger().info("Java HTTP trigger processed a request."); 37 | 38 | // Parse query parameter 39 | final String query = request.getQueryParameters().get("name"); 40 | final String name = request.getBody().orElse(query); 41 | 42 | //use the injected communicator to send out message 43 | communicator.sendMessage(context); 44 | 45 | if (name == null) { 46 | return request.createResponseBuilder(HttpStatus.BAD_REQUEST).body("Please pass a name on the query string or in the request body").build(); 47 | } else { 48 | return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build(); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /dependency-injection/guice-function/src/main/java/com/azfs/dihook/FunctionGuiceFactory.java: -------------------------------------------------------------------------------- 1 | package com.azfs.dihook; 2 | 3 | import com.google.inject.Guice; 4 | import com.azfs.BasicModule; 5 | import com.microsoft.azure.functions.spi.inject.FunctionInstanceInjector; 6 | 7 | public class FunctionGuiceFactory implements FunctionInstanceInjector { 8 | @Override 9 | public T getInstance(Class functionClass) throws Exception { 10 | return Guice.createInjector(new BasicModule()).getInstance(functionClass); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /dependency-injection/guice-function/src/main/resources/META-INF/services/com.microsoft.azure.functions.spi.inject.FunctionInstanceInjector: -------------------------------------------------------------------------------- 1 | com.azfs.dihook.FunctionGuiceFactory -------------------------------------------------------------------------------- /distributed-tracing/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Azure functions samples in Java - Distributed tracing 3 | 4 | This repository contains samples which show the usage of [Azure Functions](https://docs.microsoft.com/en-us/azure/azure-functions/) in Java using durable functions. 5 | 6 | | Scenario | Description | 7 | |-------------------|--------------------------------------------| 8 | | [Durable function](./durable-function/src/main/java/com/azfs/example/DurableFunction.java) | Durable function example to start an orchestration and follow activity chaining. | 9 | 10 | 11 | ## Prerequisites 12 | 13 | - Gradle 4.10+ 14 | - Latest [Function Core Tools](https://aka.ms/azfunc-install) 15 | - Azure CLI. This plugin use Azure CLI for authentication, please make sure you have Azure CLI installed and logged in. 16 | 17 | ## Setup 18 | 19 | - ```cmd 20 | az login 21 | az account set -s 22 | ``` 23 | - Update the Application settings in Azure portal with the required parameters as below 24 | - AzureWebJobsStorage: Connection string to your storage account 25 | - Application insights specific [settings](https://learn.microsoft.com/en-us/azure/azure-monitor/app/monitor-functions) 26 | - Documentation on how to [manage connection strings](https://docs.microsoft.com/en-gb/azure/storage/common/storage-account-keys-manage?tabs=azure-portal) and [access keys](https://docs.microsoft.com/en-gb/azure/storage/common/storage-configure-connection-string#create-a-connection-string-for-an-azure-storage-account) 27 | - Update `host.json` with the right extension bundle version. `V3 - [1.*, 2.0.0) and V4 - [2.*, 3.0.0)` 28 | 29 | 30 | ## Running the sample 31 | 32 | ```cmd 33 | ./mvnw clean package azure-functions:run 34 | ``` 35 | 36 | ```cmd 37 | ./gradlew clean azureFunctionsRun 38 | ``` 39 | 40 | ## Deploy the sample on Azure 41 | 42 | 43 | ```cmd 44 | ./mvnw clean package azure-functions:deploy 45 | ``` 46 | 47 | ```cmd 48 | ./gradlew clean azureFunctionsDeploy 49 | ``` 50 | 51 | > NOTE: please replace '/' with '\\' when you are running on windows. 52 | 53 | 54 | ## Contributing 55 | 56 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 57 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 58 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. 59 | 60 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide 61 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions 62 | provided by the bot. You will only need to do this once across all repos using our CLA. 63 | 64 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 65 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 66 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 67 | 68 | ## Telemetry 69 | This project collects usage data and sends it to Microsoft to help improve our products and services. 70 | Read Microsoft's [privacy statement](https://privacy.microsoft.com/en-us/privacystatement) to learn more. 71 | If you would like to opt out of sending telemetry data to Microsoft, you can set `allowTelemetry` to false in the plugin configuration. 72 | Please read our [document](https://github.com/microsoft/azure-gradle-plugins/wiki/Configuration) to find more details about *allowTelemetry*. 73 | -------------------------------------------------------------------------------- /distributed-tracing/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "extensionBundle": { 4 | "id": "Microsoft.Azure.Functions.ExtensionBundle", 5 | "version": "[4.*, 5.0.0)" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /distributed-tracing/local.settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "IsEncrypted": false, 3 | "Values": { 4 | "AzureWebJobsStorage": "", 5 | "FUNCTIONS_WORKER_RUNTIME": "java" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /distributed-tracing/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | com.azfs.example 6 | distributed-tracing 7 | 1.0-SNAPSHOT 8 | jar 9 | 10 | Azure Java Functions 11 | 12 | 13 | UTF-8 14 | 1.8 15 | 1.24.0 16 | 3.0.0 17 | distributed-tracing-20231019143908286 18 | 19 | 20 | 21 | 22 | com.microsoft.azure.functions 23 | azure-functions-java-library 24 | ${azure.functions.java.library.version} 25 | 26 | 27 | 28 | org.junit.jupiter 29 | junit-jupiter 30 | 5.4.2 31 | test 32 | 33 | 34 | 35 | org.mockito 36 | mockito-core 37 | 2.23.4 38 | test 39 | 40 | 41 | com.mysql 42 | mysql-connector-j 43 | 8.1.0 44 | 45 | 46 | 47 | com.microsoft.sqlserver 48 | mssql-jdbc 49 | 12.4.1.jre11 50 | 51 | 52 | 53 | io.opentelemetry 54 | opentelemetry-api 55 | 1.31.0 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | org.apache.maven.plugins 64 | maven-compiler-plugin 65 | 3.8.1 66 | 67 | ${java.version} 68 | ${java.version} 69 | ${project.build.sourceEncoding} 70 | 71 | 72 | 73 | com.microsoft.azure 74 | azure-functions-maven-plugin 75 | ${azure.functions.maven.plugin.version} 76 | 77 | 78 | ${functionAppName} 79 | 80 | java-functions-group 81 | 82 | java-functions-app-service-plan 83 | 84 | 85 | westus 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | windows 95 | 8 96 | 97 | 98 | 99 | FUNCTIONS_EXTENSION_VERSION 100 | ~4 101 | 102 | 103 | 104 | 105 | 106 | package-functions 107 | 108 | package 109 | 110 | 111 | 112 | 113 | 114 | 115 | maven-clean-plugin 116 | 3.1.0 117 | 118 | 119 | 120 | obj 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /distributed-tracing/src/main/java/com/azfs/example/DistributedTracingFunction.java: -------------------------------------------------------------------------------- 1 | package com.function; 2 | 3 | import com.microsoft.azure.functions.ExecutionContext; 4 | import com.microsoft.azure.functions.HttpMethod; 5 | import com.microsoft.azure.functions.HttpRequestMessage; 6 | import com.microsoft.azure.functions.annotation.AuthorizationLevel; 7 | import com.microsoft.azure.functions.annotation.CosmosDBOutput; 8 | import com.microsoft.azure.functions.annotation.FunctionName; 9 | import com.microsoft.azure.functions.annotation.HttpTrigger; 10 | import io.opentelemetry.api.GlobalOpenTelemetry; 11 | import io.opentelemetry.api.metrics.LongCounter; 12 | import io.opentelemetry.api.metrics.Meter; 13 | 14 | import java.sql.Connection; 15 | import java.sql.DriverManager; 16 | import java.sql.PreparedStatement; 17 | import java.sql.SQLException; 18 | import java.util.Optional; 19 | import java.util.Random; 20 | 21 | /** 22 | * Azure Functions with custom metrics and MySQL connection that is visible in Application Insights 23 | * when distributed tracing is enabled. 24 | * https://learn.microsoft.com/en-us/azure/azure-monitor/app/opentelemetry-add-modify?tabs=java 25 | * 26 | */ 27 | public class DistributedTracingFunction { 28 | /** 29 | * This function will be invoked with a GET or POST request to /api/JDBCAndCosmosOutput. 30 | * Once invoked, the function parses the name parameter from the request, adds a custom metric to Application Insights, 31 | * adds a new entry to the MySQL database and adds a new entry to the Azure Cosmos database. 32 | */ 33 | @FunctionName("JDBCAndCosmosOutput") 34 | @CosmosDBOutput( 35 | name = "itemOut", 36 | databaseName = "%CosmosDBDatabaseName%", 37 | containerName = "ItemCollectionOut", 38 | connection = "AzureWebJobsCosmosDBConnectionString" 39 | ) 40 | public String jdbcAndCosmosOutput( 41 | @HttpTrigger( 42 | name = "req", 43 | methods = {HttpMethod.GET, HttpMethod.POST}, 44 | authLevel = AuthorizationLevel.ANONYMOUS) 45 | HttpRequestMessage> request, 46 | final ExecutionContext context) { 47 | 48 | context.getLogger().info("Java HTTP trigger processed a request."); 49 | 50 | // Parse query parameter 51 | final String query = request.getQueryParameters().get("name"); 52 | final String name = request.getBody().orElse(query); 53 | final String entry = name == null ? "No new name" : name; 54 | 55 | // Custom metric 56 | Meter meter = GlobalOpenTelemetry.getMeter("DistributedTracing.Demo"); 57 | LongCounter entryCounter = meter.counterBuilder("EntryCounter").build(); 58 | entryCounter.add(1); 59 | 60 | // Register the JDBC driver 61 | try { 62 | Class.forName("com.mysql.cj.jdbc.Driver"); 63 | } catch (ClassNotFoundException e) { 64 | e.printStackTrace(); 65 | } 66 | 67 | // Add entry to MYSQL database 68 | String sqlInsertName = "INSERT INTO input(name) VALUES(?)"; 69 | String user = System.getenv("JDBCUser"); 70 | String password = System.getenv("JDBCPassword"); 71 | String publicIp = System.getenv("JDBCIP"); 72 | String connectionUrl = "jdbc:mysql://" + publicIp + ":3306/jdbcdemo"; 73 | try (Connection con = DriverManager.getConnection(connectionUrl, user, password); 74 | PreparedStatement ps = con.prepareStatement(sqlInsertName)) { 75 | ps.setString(1, entry); 76 | ps.executeUpdate(); 77 | } catch (SQLException e) { 78 | e.printStackTrace(); 79 | } 80 | 81 | // Add entry to cosmos DB 82 | final int id = Math.abs(new Random().nextInt()); 83 | final String jsonDocument = "{\"id\":\"" + id + "\", " + 84 | "\"description\": \"" + entry + "\"}"; 85 | context.getLogger().info("Document to be saved: " + jsonDocument); 86 | return jsonDocument; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /durable-function/README.md: -------------------------------------------------------------------------------- 1 | # Azure functions samples in Java - Durable functions 2 | 3 | Durable functions Java [documentation] (https://learn.microsoft.com/en-us/azure/azure-functions/durable/quickstart-java?tabs=bash&pivots=create-option-manual-setup) 4 | 5 | This repository contains samples which show the usage of [Azure Functions](https://docs.microsoft.com/en-us/azure/azure-functions/) in Java for the below scenarios. 6 | 7 | | Scenario | Description | 8 | |-------------------|--------------------------------------------| 9 | | [Durable function](./triggers-bindings/src/main/java/com/functions/DurableFunction.java) | Durable function example to start an orchestration and follow activity chaining. | 10 | 11 | 12 | ## Prerequisites 13 | 14 | - Gradle 4.10+ 15 | - Latest [Function Core Tools](https://aka.ms/azfunc-install) 16 | - Azure CLI. This plugin use Azure CLI for authentication, please make sure you have Azure CLI installed and logged in. 17 | 18 | ## Setup 19 | 20 | - ```cmd 21 | az login 22 | az account set -s 23 | ``` 24 | - Update the Application settings in Azure portal with the required parameters as below 25 | - AzureWebJobsStorage: Connection string to your storage account 26 | - Documentation on how to [manage connection strings](https://docs.microsoft.com/en-gb/azure/storage/common/storage-account-keys-manage?tabs=azure-portal) and [access keys](https://docs.microsoft.com/en-gb/azure/storage/common/storage-configure-connection-string#create-a-connection-string-for-an-azure-storage-account) 27 | - Update `host.json` with the right extension bundle version. `V3 - [1.*, 2.0.0) and V4 - [2.*, 3.0.0)` 28 | 29 | 30 | ## Running the sample 31 | 32 | ```cmd 33 | ./mvnw clean package azure-functions:run 34 | ``` 35 | 36 | ```cmd 37 | ./gradlew clean azureFunctionsRun 38 | ``` 39 | 40 | ## Deploy the sample on Azure 41 | 42 | 43 | ```cmd 44 | ./mvnw clean package azure-functions:deploy 45 | ``` 46 | 47 | ```cmd 48 | ./gradlew clean azureFunctionsDeploy 49 | ``` 50 | 51 | > NOTE: please replace '/' with '\\' when you are running on windows. 52 | 53 | 54 | ## Contributing 55 | 56 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 57 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 58 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. 59 | 60 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide 61 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions 62 | provided by the bot. You will only need to do this once across all repos using our CLA. 63 | 64 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 65 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 66 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 67 | 68 | ## Telemetry 69 | This project collects usage data and sends it to Microsoft to help improve our products and services. 70 | Read Microsoft's [privacy statement](https://privacy.microsoft.com/en-us/privacystatement) to learn more. 71 | If you would like to opt out of sending telemetry data to Microsoft, you can set `allowTelemetry` to false in the plugin configuration. 72 | Please read our [document](https://github.com/microsoft/azure-gradle-plugins/wiki/Configuration) to find more details about *allowTelemetry*. 73 | -------------------------------------------------------------------------------- /durable-function/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "extensionBundle": { 4 | "id": "Microsoft.Azure.Functions.ExtensionBundle", 5 | "version": "[4.*, 5.0.0)" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /durable-function/local.settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "IsEncrypted": false, 3 | "Values": { 4 | "AzureWebJobsStorage": "", 5 | "FUNCTIONS_WORKER_RUNTIME": "java" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /durable-function/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | com.azfs.example 6 | durable-function 7 | 1.0-SNAPSHOT 8 | jar 9 | 10 | Azure Java Functions 11 | 12 | 13 | UTF-8 14 | 1.8 15 | 1.24.0 16 | 2.2.0 17 | durable-function-20231019143829145 18 | 19 | 20 | 21 | 22 | com.microsoft.azure.functions 23 | azure-functions-java-library 24 | ${azure.functions.java.library.version} 25 | 26 | 27 | 28 | com.microsoft 29 | durabletask-azure-functions 30 | 1.4.0 31 | 32 | 33 | 34 | 35 | org.junit.jupiter 36 | junit-jupiter 37 | 5.4.2 38 | test 39 | 40 | 41 | 42 | org.mockito 43 | mockito-core 44 | 2.23.4 45 | test 46 | 47 | 48 | 49 | 50 | 51 | 52 | org.apache.maven.plugins 53 | maven-compiler-plugin 54 | 3.8.1 55 | 56 | ${java.version} 57 | ${java.version} 58 | ${project.build.sourceEncoding} 59 | 60 | 61 | 62 | com.microsoft.azure 63 | azure-functions-maven-plugin 64 | ${azure.functions.maven.plugin.version} 65 | 66 | 67 | ${functionAppName} 68 | 69 | java-functions-group 70 | 71 | java-functions-app-service-plan 72 | 73 | 74 | westus 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | windows 84 | 8 85 | 86 | 87 | 88 | FUNCTIONS_EXTENSION_VERSION 89 | ~4 90 | 91 | 92 | 93 | 94 | 95 | package-functions 96 | 97 | package 98 | 99 | 100 | 101 | 102 | 103 | 104 | maven-clean-plugin 105 | 3.1.0 106 | 107 | 108 | 109 | obj 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /durable-function/src/main/java/com/azfs/example/DurableFunction.java: -------------------------------------------------------------------------------- 1 | package com.functions; 2 | 3 | import com.microsoft.azure.functions.ExecutionContext; 4 | import com.microsoft.azure.functions.HttpMethod; 5 | import com.microsoft.azure.functions.HttpRequestMessage; 6 | import com.microsoft.azure.functions.HttpResponseMessage; 7 | import com.microsoft.azure.functions.annotation.AuthorizationLevel; 8 | import com.microsoft.azure.functions.annotation.FunctionName; 9 | import com.microsoft.azure.functions.annotation.HttpTrigger; 10 | import com.microsoft.durabletask.DurableTaskClient; 11 | import com.microsoft.durabletask.OrchestrationRunner; 12 | import com.microsoft.durabletask.TaskOrchestrationContext; 13 | import com.microsoft.durabletask.azurefunctions.DurableActivityTrigger; 14 | import com.microsoft.durabletask.azurefunctions.DurableClientContext; 15 | import com.microsoft.durabletask.azurefunctions.DurableClientInput; 16 | import com.microsoft.durabletask.azurefunctions.DurableOrchestrationTrigger; 17 | 18 | import java.util.Optional; 19 | 20 | /** 21 | * Azure Durable Functions with HTTP trigger. 22 | */ 23 | public class DurableFunction { 24 | /** 25 | * This HTTP-triggered function starts the orchestration. 26 | */ 27 | @FunctionName("StartOrchestration") 28 | public HttpResponseMessage startOrchestration( 29 | @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage> request, 30 | @DurableClientInput(name = "durableContext") DurableClientContext durableContext, 31 | final ExecutionContext context) { 32 | context.getLogger().info("Java HTTP trigger processed a request."); 33 | 34 | DurableTaskClient client = durableContext.getClient(); 35 | String instanceId = client.scheduleNewOrchestrationInstance("Cities"); 36 | context.getLogger().info("Created new Java orchestration with instance ID = " + instanceId); 37 | return durableContext.createCheckStatusResponse(request, instanceId); 38 | } 39 | 40 | /** 41 | * This is the orchestrator function, which can schedule activity functions, create durable timers, 42 | * or wait for external events in a way that's completely fault-tolerant. 43 | */ 44 | @FunctionName("Cities") 45 | public String citiesOrchestrator( 46 | @DurableOrchestrationTrigger(name = "ctx") TaskOrchestrationContext ctx) { 47 | String result = ""; 48 | result += ctx.callActivity("Capitalize", "Tokyo", String.class).await() + ", "; 49 | result += ctx.callActivity("Capitalize", "London", String.class).await() + ", "; 50 | result += ctx.callActivity("Capitalize", "Seattle", String.class).await() + ", "; 51 | result += ctx.callActivity("Capitalize", "Austin", String.class).await(); 52 | return result; 53 | } 54 | 55 | /** 56 | * This is the activity function that gets invoked by the orchestration. 57 | */ 58 | @FunctionName("Capitalize") 59 | public String capitalize( 60 | @DurableActivityTrigger(name = "name") String name, 61 | final ExecutionContext context) { 62 | context.getLogger().info("Capitalizing: " + name); 63 | return name.toUpperCase(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /spring-cloud/.gitignore: -------------------------------------------------------------------------------- 1 | # Build output 2 | target/ 3 | *.class 4 | 5 | # Log file 6 | *.log 7 | 8 | # BlueJ files 9 | *.ctxt 10 | 11 | # Mobile Tools for Java (J2ME) 12 | .mtj.tmp/ 13 | 14 | # Package Files # 15 | *.jar 16 | *.war 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | # IDE 26 | .idea/ 27 | *.iml 28 | .settings/ 29 | .project 30 | .classpath 31 | .vscode/ 32 | 33 | # macOS 34 | .DS_Store 35 | 36 | # Azure Functions 37 | local.settings.json 38 | bin/ 39 | obj/ 40 | -------------------------------------------------------------------------------- /spring-cloud/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM springcloudstream/azure-functions-java17:1.0.0 2 | 3 | COPY ./target/azure-functions /src/java-function-app 4 | 5 | RUN mkdir -p /home/site/wwwroot && \ 6 | cd /src/java-function-app && \ 7 | cd $(ls -d */|head -n 1) && \ 8 | cp -a . /home/site/wwwroot 9 | 10 | ENV AzureWebJobsScriptRoot=/home/site/wwwroot \ 11 | AzureFunctionsJobHost__Logging__Console__IsEnabled=true 12 | -------------------------------------------------------------------------------- /spring-cloud/README.md: -------------------------------------------------------------------------------- 1 | # Spring Cloud Function in Azure 2 | 3 | This article guides you through using [Spring Cloud Functions](https://spring.io/projects/spring-cloud-function) to develop a Java function and publish it to Azure Functions. When you're done, your function code runs on the [Consumption Plan](/azure/azure-functions/functions-scale#consumption-plan) in Azure and can be triggered using an HTTP request. 4 | 5 | [!INCLUDE [quickstarts-free-trial-note](../../includes/quickstarts-free-trial-note.md)] 6 | 7 | ## Prerequisites 8 | 9 | To develop functions using Java, you must have the following installed: 10 | 11 | - [Java Developer Kit](../fundamentals/java-support-on-azure.md), version 11 12 | - [Apache Maven](https://maven.apache.org), version 3.0 or higher 13 | - [Azure CLI](/cli/azure) 14 | - [Azure Functions Core Tools](/azure/azure-functions/functions-run-local#v4) version 4 15 | 16 | > [!IMPORTANT] 17 | > 1. You must set the JAVA_HOME environment variable to the install location of the JDK to complete this quickstart. 18 | > 2. Make sure your core tools version is at least 4.0.5030 19 | 20 | ## What we're going to build 21 | 22 | We're going to build a classical "Hello, World" function, that runs on Azure Functions, and which is configured with Spring Cloud Function. 23 | 24 | It will receive a simple `User` JSON object, which contains a user name, and send back a `Greeting` object, which contains the welcome message to that user. 25 | 26 | The project we'll build is available in the samples of [azure-function-java-worker](https://github.com/Azure/azure-functions-java-worker/tree/dev/samples/spring-cloud-example) repository on GitHub. You can use that sample repository directly if you want to see the final work described in this quickstart. 27 | 28 | ## Create a new Maven project 29 | 30 | We're going to create an empty Maven project, and configure it with Spring Cloud Function and Azure Functions. 31 | 32 | In an empty folder, create a new *pom.xml* file and copy/paste the content from the sample project's [pom.xml](https://github.com/Azure-Samples/hello-spring-function-azure/blob/master/pom.xml) file. 33 | 34 | > [!NOTE] 35 | > This file uses Maven dependencies from both Spring Boot and Spring Cloud Function, and it configures 36 | the Spring Boot and Azure Functions Maven plugins. 37 | 38 | You need to customize a few properties for your application: 39 | 40 | - `` is the name of your Azure Function 41 | - `` is the name of the Azure region where your Function is deployed 42 | - `` is the name of the Azure resource group you're using 43 | 44 | Change those properties directly near the top of the *pom.xml* file, as shown in the following example: 45 | 46 | ```xml 47 | 48 | UTF-8 49 | 11 50 | 11 51 | 52 | 1.22.0 53 | 3.0.0 54 | 55 | 56 | my-spring-function-resource-group 57 | my-spring-function-service-plan 58 | my-spring-function 59 | 60 | westeurope 61 | example.Application 62 | 63 | 64 | ``` 65 | 66 | ## Create Azure configuration files 67 | 68 | Create a *src/main/azure* folder and add the following Azure Functions configuration files to it. 69 | 70 | *host.json*: 71 | 72 | ```json 73 | { 74 | "version": "2.0", 75 | "extensionBundle": { 76 | "id": "Microsoft.Azure.Functions.ExtensionBundle", 77 | "version": "[4.*, 5.0.0)" 78 | }, 79 | "functionTimeout": "00:10:00" 80 | } 81 | ``` 82 | 83 | *local.settings.json*: 84 | 85 | ```json 86 | { 87 | "IsEncrypted": false, 88 | "Values": { 89 | "AzureWebJobsStorage": "", 90 | "FUNCTIONS_WORKER_RUNTIME": "java", 91 | "FUNCTIONS_EXTENSION_VERSION": "~4", 92 | "AzureWebJobsDashboard": "" 93 | } 94 | } 95 | ``` 96 | 97 | ## Create domain objects 98 | 99 | Azure Functions can receive and send objects in JSON format. 100 | We're now going to create our `User` and `Greeting` objects, which represent our domain model. 101 | You can create more complex objects, with more properties, if you want to customize this quickstart and make it more interesting for you. 102 | 103 | Create a *src/main/java/com/example/model* folder and add the following two files: 104 | 105 | *User.java*: 106 | 107 | ```java 108 | package com.example.model; 109 | 110 | public class User { 111 | 112 | private String name; 113 | 114 | public User() { 115 | } 116 | 117 | public User(String name) { 118 | this.name = name; 119 | } 120 | 121 | public String getName() { 122 | return name; 123 | } 124 | 125 | public void setName(String name) { 126 | this.name = name; 127 | } 128 | } 129 | ``` 130 | 131 | *Greeting.java*: 132 | 133 | ```java 134 | package com.example.model; 135 | 136 | public class Greeting { 137 | 138 | private String message; 139 | 140 | public Greeting() { 141 | } 142 | 143 | public Greeting(String message) { 144 | this.message = message; 145 | } 146 | 147 | public String getMessage() { 148 | return message; 149 | } 150 | 151 | public void setMessage(String message) { 152 | this.message = message; 153 | } 154 | } 155 | ``` 156 | 157 | ## Create the Spring Boot application 158 | 159 | This application will manage all business logic, and will have access to the full Spring Boot ecosystem. 160 | This capability gives you two main benefits over a standard Azure Function: 161 | 162 | - It doesn't rely on the Azure Functions APIs, so you can easily port it to other systems. For example, you can reuse it in a normal Spring Boot application. 163 | - You can use all the `@Enable` annotations from Spring Boot to add new features. 164 | 165 | In the *src/main/java/example* folder, create the following file, which is a normal Spring Boot application: 166 | 167 | *DemoApplication.java*: 168 | 169 | ```java 170 | package example; 171 | 172 | import example.uppercase.Config; 173 | import org.springframework.boot.SpringApplication; 174 | import org.springframework.boot.autoconfigure.SpringBootApplication; 175 | 176 | @SpringBootApplication 177 | public class Application { 178 | public static void main(String[] args) throws Exception { 179 | SpringApplication.run(Config.class, args); 180 | } 181 | } 182 | ``` 183 | 184 | Now create the following file *src/main/java/example/hello* folder, which contains a Spring Boot component that represents the Function we want to run: 185 | 186 | *Hello.java*: 187 | 188 | ```java 189 | package example.hello; 190 | 191 | import example.hello.model.*; 192 | import org.springframework.stereotype.Component; 193 | import java.util.function.Function; 194 | 195 | @Component 196 | public class Hello implements Function { 197 | 198 | @Override 199 | public Greeting apply(User user) { 200 | return new Greeting("Hello, " + user.getName() + "!\n"); 201 | } 202 | } 203 | ``` 204 | 205 | > [!NOTE] 206 | > The `Hello` function is quite specific: 207 | > 208 | > - It is a `java.util.function.Function`. It contains the business logic, and it uses a standard Java API to transform one object into another. 209 | > - Because it has the `@Component` annotation, it's a Spring Bean, and by default its name is the same as the class, but starting with a lowercase character: `hello`. Following this naming convention is important if you want to create other functions in your application. The name must match the Azure Functions name we'll create in the next section. 210 | 211 | ## Create the Azure Function 212 | 213 | To benefit from the full Azure Functions API, we're now going to code an Azure Function that will delegate its execution to the Spring Cloud Function we've created in the previous step. 214 | 215 | In the *src/main/java/com/example/hello* folder, create the following Azure Function class file: 216 | 217 | *HelloHandler.java*: 218 | 219 | ```java 220 | package example.hello; 221 | 222 | import com.microsoft.azure.functions.*; 223 | import com.microsoft.azure.functions.annotation.AuthorizationLevel; 224 | import com.microsoft.azure.functions.annotation.FunctionName; 225 | import com.microsoft.azure.functions.annotation.HttpTrigger; 226 | import example.hello.model.*; 227 | import org.springframework.beans.factory.annotation.Autowired; 228 | import org.springframework.stereotype.Component; 229 | 230 | import java.util.Optional; 231 | 232 | @Component 233 | public class HelloHandler { 234 | 235 | @Autowired 236 | private Hello hello; 237 | 238 | @FunctionName("hello") 239 | public HttpResponseMessage execute( 240 | @HttpTrigger(name = "request", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage> request, 241 | ExecutionContext context) { 242 | User user = request.getBody() 243 | .filter(u -> u.getName() != null) 244 | .orElseGet(() -> new User(request.getQueryParameters().getOrDefault("name", "world"))); 245 | context.getLogger().info("Greeting user name: " + user.getName()); 246 | return request 247 | .createResponseBuilder(HttpStatus.OK) 248 | .body(hello.apply(user)) 249 | .header("Content-Type", "application/json") 250 | .build(); 251 | } 252 | } 253 | ``` 254 | 255 | This Java class is an Azure Function, with the following interesting features: 256 | 257 | - It has `@Component` annotation, it's a Spring Bean. 258 | - The name of the function, as defined by the `@FunctionName("hello")` annotation, is `hello`. 259 | - It's a real Azure Function, so you can use the full Azure Functions API here. 260 | 261 | ## Add unit tests 262 | 263 | This step is optional but recommended to validate that the application works correctly. 264 | 265 | Create a *src/test/java/com/example* folder and add the following JUnit tests: 266 | 267 | *HelloTest.java*: 268 | 269 | ```java 270 | package example.hello; 271 | 272 | import example.hello.model.Greeting; 273 | import example.hello.model.User; 274 | import org.junit.jupiter.api.Test; 275 | 276 | import static org.assertj.core.api.Assertions.assertThat; 277 | 278 | public class HelloTest { 279 | 280 | @Test 281 | public void test() { 282 | Greeting result = new Hello().apply(new User("foo")); 283 | assertThat(result.getMessage()).isEqualTo("Hello, foo!\n"); 284 | } 285 | } 286 | 287 | ``` 288 | 289 | You can now test your Azure Function using Maven: 290 | 291 | ```bash 292 | mvn clean test 293 | ``` 294 | 295 | ## Run the Function locally 296 | 297 | Before you deploy your application to Azure Function, let's first test it locally. 298 | 299 | First you need to package your application into a Jar file: 300 | 301 | ```bash 302 | mvn package 303 | ``` 304 | 305 | Now that the application is packaged, you can run it using the `azure-functions` Maven plugin: 306 | 307 | ```bash 308 | mvn azure-functions:run 309 | ``` 310 | 311 | The Azure Function should now be available on your localhost, using port 7071. You can test the function by sending it a POST request, with a `User` object in JSON format. For example, using cURL: 312 | 313 | ```bash 314 | curl -X POST http://localhost:7071/api/hello -d "{\"name\":\"Azure\"}" 315 | ``` 316 | 317 | The Function should answer you with a `Greeting` object, still in JSON format: 318 | 319 | ```output 320 | { 321 | "message": "Hello, Azure!\n" 322 | } 323 | ``` 324 | 325 | Here's a screenshot of the cURL request on the top of the screen, and the local Azure Function at the bottom: 326 | 327 | ![Azure Function running locally][RFL01] 328 | 329 | ## Debug the Function locally 330 | 331 | The following sections describe how to debug the function. 332 | 333 | ### Debug using Intellij IDEA 334 | 335 | Open the project in Intellij IDEA, then create a **Remote JVM Debug** run configuration to attach. For more information, see [Tutorial: Remote debug](https://www.jetbrains.com/help/idea/tutorial-remote-debug.html). 336 | 337 | ![Create a Remote JVM Debug run configuration][create-remote-jvm-debug-run-configuration] 338 | 339 | Run the application with the following command: 340 | 341 | ```bash 342 | mvn azure-functions:run -DenableDebug 343 | ``` 344 | 345 | When the application starts, you'll see the following output: 346 | 347 | ```output 348 | Worker process started and initialized. 349 | Listening for transport dt_socket at address: 5005 350 | ``` 351 | 352 | Start project debugging in Intellij IDEA. You'll see the following output: 353 | 354 | ```output 355 | Connected to the target VM, address: 'localhost:5005', transport: 'socket' 356 | ``` 357 | 358 | Mark the breakpoints you want to debug. After sending a request, the Intellij IDEA will enter debugging mode. 359 | 360 | ### Debug using Visual Studio Code 361 | 362 | Open the project in Visual Studio Code, then configure the following *launch.json* file content: 363 | 364 | ```json 365 | { 366 | "version": "0.2.0", 367 | "configurations": [ 368 | { 369 | "type": "java", 370 | "name": "Attach to Remote Program", 371 | "request": "attach", 372 | "hostName": "127.0.0.1", 373 | "port": 5005 374 | } 375 | ] 376 | } 377 | ``` 378 | 379 | Run the application with the following command: 380 | 381 | ```bash 382 | mvn azure-functions:run -DenableDebug 383 | ``` 384 | 385 | When the application starts, you'll see the following output: 386 | 387 | ```output 388 | Worker process started and initialized. 389 | Listening for transport dt_socket at address: 5005 390 | ``` 391 | 392 | Start project debugging in Visual Studio Code, then mark the breakpoints you want to debug. After sending a request, Visual Studio Code will enter debugging mode. For more information, see [Running and debugging Java](https://code.visualstudio.com/docs/java/java-debugging). 393 | 394 | ## Deploy the Function to Azure Functions 395 | 396 | Now you're going to publish the Azure Function to production. Remember that the ``, ``, and `` properties you've defined in your *pom.xml* file will be used to configure your function. 397 | 398 | > [!NOTE] 399 | > The Maven plugin needs to authenticate with Azure. If you have Azure CLI installed, use `az login` before continuing. 400 | > For more authentication options, see [Authentication](https://github.com/microsoft/azure-maven-plugins/wiki/Authentication) in the [azure-maven-plugins](https://github.com/microsoft/azure-maven-plugins) repository. 401 | 402 | Run Maven to deploy your function automatically: 403 | 404 | ```bash 405 | mvn azure-functions:deploy 406 | ``` 407 | 408 | Now go to the [Azure portal](https://portal.azure.com) to find the `Function App` that has been created. 409 | 410 | Select the function: 411 | 412 | - In the function overview, note the function's URL. 413 | - Select the **Platform features** tab to find the **Log streaming** service, then select this service to check your running function. 414 | 415 | Now, as you did in the previous section, use cURL to access the running function, as shown in the following example. Be sure to replace `your-function-name` by your real function name. 416 | 417 | ```bash 418 | curl https://your-function-name.azurewebsites.net/api/hello -d "{\"name\":\"Azure\"}" 419 | ``` 420 | 421 | Like in the previous section, the Function should answer you with a `Greeting` object, still in JSON format: 422 | 423 | ```output 424 | { 425 | "message": "Hello, Azure!\n" 426 | } 427 | ``` 428 | 429 | Congratulations, you have a Spring Cloud Function running on Azure Functions! For more docs and samples of spring cloud functions please checkout below links 430 | - [Spring cloud function blog](https://spring.io/blog/2023/02/24/spring-cloud-function-for-azure-function) 431 | - [Spring cloud function reference documents](https://docs.spring.io/spring-cloud-function/docs/4.0.2-SNAPSHOT/reference/html/azure.html#_microsoft_azure) 432 | - [Spring cloud function samples](https://github.com/spring-cloud/spring-cloud-function/tree/main/spring-cloud-function-samples/function-azure-di-samples) 433 | 434 | 435 | ## Next steps 436 | 437 | To learn more about Spring and Azure, continue to the Spring on Azure documentation center. 438 | 439 | > [!div class="nextstepaction"] 440 | > [Spring on Azure](./index.yml) 441 | 442 | 443 | 444 | [RFL01]: media/getting-started-with-spring-cloud-function-in-azure/RFL01.png 445 | [create-remote-jvm-debug-run-configuration]: media/getting-started-with-spring-cloud-function-in-azure/create-remote-jvm-debug-run-configuration.png 446 | -------------------------------------------------------------------------------- /spring-cloud/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.0.1-SNAPSHOT 9 | 10 | 11 | 12 | com.example.azure.di 13 | azure-httptrigger-demo 14 | 0.0.1-SNAPSHOT 15 | azure-httptrigger-demo 16 | 17 | Demo Spring Boot, Azure Function - HttpTrigger (DI adapter) 18 | 19 | 20 | 17 21 | 1.0.28.RELEASE 22 | 23 | 24 | example.Application 25 | 26 | 27 | 1.22.0 28 | spring-cloud-function-samples 29 | westus 30 | sample-resource-group 31 | sample-service-plan 32 | EP1 33 | 34 | 35 | 36 | 37 | org.springframework.cloud 38 | spring-cloud-function-adapter-azure 39 | 4.0.0 40 | 41 | 42 | 43 | org.springframework.boot 44 | spring-boot-starter-test 45 | test 46 | 47 | 48 | 49 | org.junit.jupiter 50 | junit-jupiter-api 51 | 5.9.2 52 | test 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | org.apache.maven.plugins 61 | maven-deploy-plugin 62 | 63 | true 64 | 65 | 66 | 67 | com.microsoft.azure 68 | azure-functions-maven-plugin 69 | ${azure.functions.maven.plugin.version} 70 | 71 | 72 | ${functionAppName} 73 | ${functionResourceGroup} 74 | ${functionAppRegion} 75 | ${functionAppServicePlanName} 76 | ${functionPricingTier} 77 | 78 | ${project.basedir}/src/main/resources/host.json 79 | ${project.basedir}/src/main/resources/local.settings.json 80 | 81 | 82 | linux 83 | 17 84 | 85 | 86 | 87 | 88 | FUNCTIONS_EXTENSION_VERSION 89 | ~4 90 | 91 | 92 | 93 | 94 | 95 | package-functions 96 | 97 | package 98 | 99 | 100 | 101 | 102 | 103 | 104 | org.springframework.boot 105 | spring-boot-maven-plugin 106 | 107 | 108 | org.springframework.boot.experimental 109 | spring-boot-thin-layout 110 | ${spring-boot-thin-layout.version} 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /spring-cloud/src/main/java/example/Application.java: -------------------------------------------------------------------------------- 1 | package example; 2 | 3 | import example.uppercase.Config; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | @SpringBootApplication 8 | public class Application { 9 | public static void main(String[] args) throws Exception { 10 | SpringApplication.run(Config.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /spring-cloud/src/main/java/example/hello/Hello.java: -------------------------------------------------------------------------------- 1 | package example.hello; 2 | 3 | import example.hello.model.*; 4 | import org.springframework.stereotype.Component; 5 | import java.util.function.Function; 6 | 7 | @Component 8 | public class Hello implements Function { 9 | 10 | @Override 11 | public Greeting apply(User user) { 12 | return new Greeting("Hello, " + user.getName() + "!\n"); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /spring-cloud/src/main/java/example/hello/HelloHandler.java: -------------------------------------------------------------------------------- 1 | package example.hello; 2 | 3 | import com.microsoft.azure.functions.*; 4 | import com.microsoft.azure.functions.annotation.AuthorizationLevel; 5 | import com.microsoft.azure.functions.annotation.FunctionName; 6 | import com.microsoft.azure.functions.annotation.HttpTrigger; 7 | import example.hello.model.*; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Component; 10 | 11 | import java.util.Optional; 12 | 13 | @Component 14 | public class HelloHandler { 15 | 16 | @Autowired 17 | private Hello hello; 18 | 19 | @FunctionName("hello") 20 | public HttpResponseMessage execute( 21 | @HttpTrigger(name = "request", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage> request, 22 | ExecutionContext context) { 23 | User user = request.getBody() 24 | .filter(u -> u.getName() != null) 25 | .orElseGet(() -> new User(request.getQueryParameters().getOrDefault("name", "world"))); 26 | context.getLogger().info("Greeting user name: " + user.getName()); 27 | return request 28 | .createResponseBuilder(HttpStatus.OK) 29 | .body(hello.apply(user)) 30 | .header("Content-Type", "application/json") 31 | .build(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /spring-cloud/src/main/java/example/hello/model/Greeting.java: -------------------------------------------------------------------------------- 1 | package example.hello.model; 2 | 3 | public class Greeting { 4 | 5 | private String message; 6 | 7 | public Greeting() { 8 | } 9 | 10 | public Greeting(String message) { 11 | this.message = message; 12 | } 13 | 14 | public String getMessage() { 15 | return message; 16 | } 17 | 18 | public void setMessage(String message) { 19 | this.message = message; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /spring-cloud/src/main/java/example/hello/model/User.java: -------------------------------------------------------------------------------- 1 | package example.hello.model; 2 | 3 | public class User { 4 | 5 | private String name; 6 | 7 | public User() { 8 | } 9 | 10 | public User(String name) { 11 | this.name = name; 12 | } 13 | 14 | public String getName() { 15 | return name; 16 | } 17 | 18 | public void setName(String name) { 19 | this.name = name; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /spring-cloud/src/main/java/example/uppercase/Config.java: -------------------------------------------------------------------------------- 1 | package example.uppercase; 2 | 3 | import java.util.Map; 4 | import java.util.function.Function; 5 | 6 | import com.microsoft.azure.functions.ExecutionContext; 7 | import org.springframework.context.annotation.Configuration; 8 | import reactor.core.publisher.Flux; 9 | import reactor.core.publisher.Mono; 10 | 11 | import org.springframework.boot.SpringApplication; 12 | import org.springframework.boot.autoconfigure.SpringBootApplication; 13 | import org.springframework.cloud.function.json.JsonMapper; 14 | import org.springframework.context.annotation.Bean; 15 | import org.springframework.messaging.Message; 16 | 17 | @Configuration 18 | public class Config { 19 | 20 | @Bean 21 | public Function echo() { 22 | return payload -> payload; 23 | } 24 | 25 | @Bean 26 | public Function uppercase() { 27 | return payload -> payload.toUpperCase(); 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /spring-cloud/src/main/java/example/uppercase/EchoHandler.java: -------------------------------------------------------------------------------- 1 | package example.uppercase; 2 | 3 | import com.microsoft.azure.functions.ExecutionContext; 4 | import com.microsoft.azure.functions.HttpMethod; 5 | import com.microsoft.azure.functions.HttpRequestMessage; 6 | import com.microsoft.azure.functions.annotation.AuthorizationLevel; 7 | import com.microsoft.azure.functions.annotation.FunctionName; 8 | import com.microsoft.azure.functions.annotation.HttpTrigger; 9 | 10 | import java.util.Optional; 11 | import java.util.function.Function; 12 | 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.cloud.function.adapter.azure.FunctionInvoker; 15 | import org.springframework.messaging.Message; 16 | import org.springframework.messaging.support.MessageBuilder; 17 | import org.springframework.stereotype.Component; 18 | 19 | @Component 20 | public class EchoHandler { 21 | 22 | @Autowired 23 | private Function echo; 24 | 25 | @FunctionName("echo") 26 | public String execute(@HttpTrigger(name = "req", methods = {HttpMethod.GET, 27 | HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage> request, 28 | ExecutionContext context) { 29 | return echo.apply(request.getBody().get()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /spring-cloud/src/main/java/example/uppercase/UppercaseHandler.java: -------------------------------------------------------------------------------- 1 | package example.uppercase; 2 | 3 | import com.microsoft.azure.functions.ExecutionContext; 4 | import com.microsoft.azure.functions.HttpMethod; 5 | import com.microsoft.azure.functions.HttpRequestMessage; 6 | import com.microsoft.azure.functions.annotation.AuthorizationLevel; 7 | import com.microsoft.azure.functions.annotation.FunctionName; 8 | import com.microsoft.azure.functions.annotation.HttpTrigger; 9 | 10 | import java.util.Optional; 11 | import java.util.function.Function; 12 | 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.cloud.function.adapter.azure.FunctionInvoker; 15 | import org.springframework.messaging.Message; 16 | import org.springframework.messaging.support.MessageBuilder; 17 | import org.springframework.stereotype.Component; 18 | 19 | @Component 20 | public class UppercaseHandler { 21 | 22 | @Autowired 23 | private Function uppercase; 24 | 25 | @FunctionName("uppercase") 26 | public String execute( 27 | @HttpTrigger( 28 | name = "req", 29 | methods = {HttpMethod.GET, HttpMethod.POST}, 30 | authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage> request, 31 | ExecutionContext context 32 | ) { 33 | context.getLogger().warning("Using Java (" + System.getProperty("java.version") + ")"); 34 | return uppercase.apply(request.getBody().get()); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /spring-cloud/src/main/resources/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "extensionBundle": { 4 | "id": "Microsoft.Azure.Functions.ExtensionBundle", 5 | "version": "[4.*, 5.0.0)" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /spring-cloud/src/test/java/example/hello/HelloTest.java: -------------------------------------------------------------------------------- 1 | package example.hello; 2 | 3 | 4 | import example.hello.model.Greeting; 5 | import example.hello.model.User; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import static org.assertj.core.api.Assertions.assertThat; 9 | 10 | 11 | public class HelloTest { 12 | 13 | @Test 14 | public void test() { 15 | Greeting result = new Hello().apply(new User("foo")); 16 | assertThat(result.getMessage()).isEqualTo("Hello, foo!\n"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /triggers-bindings/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.0/apache-maven-3.5.0-bin.zip -------------------------------------------------------------------------------- /triggers-bindings/README.md: -------------------------------------------------------------------------------- 1 | # Azure Functions samples in Java for triggers and bindings 2 | 3 | This repository contains samples which show the basic usage of [Azure Functions](https://docs.microsoft.com/en-us/azure/azure-functions/) in Java for the below scenarios. 4 | 5 | | Scenario | Description | 6 | |-------------------|--------------------------------------------| 7 | | [HttpTrigger](./src/main/java/com/functions/Function.java) | Basic HttpTrigger and FixedDelayRetry with HttpTrigger. | 8 | | [BlobTrigger](./src/main/java/com/functions/BlobTriggerFunction.java) | BlobTrigger, read blob using BlobInput binding and output to blob using BlobOutput binding. | 9 | | [CosmosDBTrigger](./src/main/java/com/functions/CosmosDBTriggerFunction.java) | CosmosDBTrigger, read cosmos DB entries with CosmosDBInput binding and output to cosmos DB CosmosDBOutput binding. | 10 | | [TimerTrigger](./src/main/java/com/functions/TimerTriggerFunction.java) | Basic periodic TimerTrigger. | 11 | | [EventGridTrigger](./src/main/java/com/functions/EventGridTriggerFunction.java) | EventGridTrigger and send event to Event Grid using EventGridOutput binding. | 12 | | [EventHubTrigger](./src/main/java/com/functions/EventHubTriggerFunction.java) | EventHubTrigger for message received in event grid and output to event grid using EventHubOutput binding. | 13 | | [KafkaTrigger](./src/main/java/com/functions/KafkaTriggerFunction.java) | KafkaTrigger with KafkaOutput and QueueOutput example. | 14 | | [QueueTrigger](./src/main/java/com/functions/QueueTriggerFunction.java) | QueueTrigger to read content from queue and output to queue using QueueOutput binding. | 15 | | [ServiceBusQueueTrigger](./src/main/java/com/functions/ServiceBusQueueTriggerFunction.java) | ServiceBusQueueTrigger to read message from a queue in service bus and output to service bus queue using ServiceBusQueueOutput binding. | 16 | | [ServiceBusTopicTrigger](./src/main/java/com/functions/ServiceBusTopicTriggerFunction.java) | ServiceBusTopicTrigger to read message from a topic in service bus and output to service bus topic using ServiceBusTopicOutput binding. | 17 | | [Table function](./src/main/java/com/functions/TableFunction.java) | Basic example to read and write to table in Azure Storage using TableInput and TableOutput binding. | 18 | | [Durable Function](./src/main/java/com/functions/DurableFunction.java) | Durable function example to start an orchestration and follow activity chaining. | 19 | | [Distributed Tracing](./src/main/java/com/functions/DistributedTracingFunction.java) | Distributed tracing example that adds entries to a MYSQL database via JDBC, adds custom metrics to the Application Insights and outputs to cosmos DB CosmosDBOutput binding. | 20 | 21 | 22 | ## Contents 23 | 24 | Outline the file contents of the repository. It helps users navigate the codebase, build configuration and any related assets. 25 | 26 | | File/folder | Description | 27 | |-------------------|--------------------------------------------| 28 | | `src` | Sample source code. | 29 | | `build.gradle` | The gradle configuration to this sample. | 30 | | `pom.xml` | The maven configuration to this sample. | 31 | | `README.md` | This README file. | 32 | 33 | ## Prerequisites 34 | 35 | - Gradle 4.10+ 36 | - Latest [Function Core Tools](https://aka.ms/azfunc-install) 37 | - Azure CLI. This plugin use Azure CLI for authentication, please make sure you have Azure CLI installed and logged in. 38 | 39 | ## Setup 40 | 41 | - ```cmd 42 | az login 43 | az account set -s 44 | ``` 45 | - Update the Application settings in Azure portal with the required parameters as below 46 | - AzureWebJobsStorage: Connection string to your storage account 47 | - CosmosDBDatabaseName: Cosmos database name. Example: ItemCollectionIn 48 | - CosmosDBCollectionName:Cosmos database collection name. Example: ItemDb 49 | - AzureWebJobsCosmosDBConnectionString: Connection string to your Cosmos database 50 | - AzureWebJobsEventGridOutputBindingTopicUriString: Event Grid URI 51 | - AzureWebJobsEventGridOutputBindingTopicKeyString: Event Grid string 52 | - AzureWebJobsEventHubSender, AzureWebJobsEventHubSender_2 : Event hub connection string 53 | - AzureWebJobsServiceBus: Service bus connection string 54 | - SBQueueName: Service bus queue name. Example: test-input-java 55 | - SBTopicName: Service bus topic name. Example: javaworkercitopic2 56 | - SBTopicSubName: Service bus topic name. Example: javaworkercisub 57 | - Documentation on how to [manage connection strings](https://docs.microsoft.com/en-gb/azure/storage/common/storage-account-keys-manage?tabs=azure-portal) and [access keys](https://docs.microsoft.com/en-gb/azure/storage/common/storage-configure-connection-string#create-a-connection-string-for-an-azure-storage-account) 58 | - Update `host.json` with the right extension bundle version. `V3 - [1.*, 2.0.0) and V4 - [2.*, 3.0.0)` 59 | 60 | 61 | ## Running the sample 62 | 63 | ```cmd 64 | ./mvnw clean package azure-functions:run 65 | ``` 66 | 67 | ```cmd 68 | ./gradlew clean azureFunctionsRun 69 | ``` 70 | 71 | ## Deploy the sample on Azure 72 | 73 | 74 | ```cmd 75 | ./mvnw clean package azure-functions:deploy 76 | ``` 77 | 78 | ```cmd 79 | ./gradlew clean azureFunctionsDeploy 80 | ``` 81 | 82 | > NOTE: please replace '/' with '\\' when you are running on windows. -------------------------------------------------------------------------------- /triggers-bindings/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "com.microsoft.azure.azurefunctions" version "1.9.0" 3 | } 4 | apply plugin: 'java' 5 | apply plugin: "com.microsoft.azure.azurefunctions" 6 | 7 | group 'com.functions' 8 | version '1.0-SNAPSHOT' 9 | 10 | dependencies { 11 | implementation 'com.microsoft.azure.functions:azure-functions-java-library:3.0.0' 12 | implementation 'com.microsoft:durabletask-azure-functions:1.0.0' 13 | testImplementation 'org.junit.jupiter:junit-jupiter:5.6.2' 14 | testImplementation 'org.mockito:mockito-core:3.3.3' 15 | } 16 | 17 | sourceCompatibility = '1.8' 18 | targetCompatibility = '1.8' 19 | 20 | compileJava.options.encoding = 'UTF-8' 21 | 22 | repositories { 23 | mavenCentral() 24 | } 25 | 26 | azurefunctions { 27 | resourceGroup = 'java-functions-group' 28 | appName = 'azure-functions-sample' 29 | pricingTier = 'Consumption' 30 | region = 'westus' 31 | runtime { 32 | os = 'Windows' 33 | javaVersion = 'Java 8' 34 | } 35 | auth { 36 | type = 'azure_cli' 37 | } 38 | localDebug = "transport=dt_socket,server=y,suspend=n,address=5005" 39 | } 40 | -------------------------------------------------------------------------------- /triggers-bindings/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /triggers-bindings/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | # Determine the Java command to use to start the JVM. 86 | if [ -n "$JAVA_HOME" ] ; then 87 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 88 | # IBM's JDK on AIX uses strange locations for the executables 89 | JAVACMD="$JAVA_HOME/jre/sh/java" 90 | else 91 | JAVACMD="$JAVA_HOME/bin/java" 92 | fi 93 | if [ ! -x "$JAVACMD" ] ; then 94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 95 | 96 | Please set the JAVA_HOME variable in your environment to match the 97 | location of your Java installation." 98 | fi 99 | else 100 | JAVACMD="java" 101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 102 | 103 | Please set the JAVA_HOME variable in your environment to match the 104 | location of your Java installation." 105 | fi 106 | 107 | # Increase the maximum file descriptors if we can. 108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 109 | MAX_FD_LIMIT=`ulimit -H -n` 110 | if [ $? -eq 0 ] ; then 111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 112 | MAX_FD="$MAX_FD_LIMIT" 113 | fi 114 | ulimit -n $MAX_FD 115 | if [ $? -ne 0 ] ; then 116 | warn "Could not set maximum file descriptor limit: $MAX_FD" 117 | fi 118 | else 119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 120 | fi 121 | fi 122 | 123 | # For Darwin, add options to specify how the application appears in the dock 124 | if $darwin; then 125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 126 | fi 127 | 128 | # For Cygwin or MSYS, switch paths to Windows format before running java 129 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 130 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 131 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 132 | JAVACMD=`cygpath --unix "$JAVACMD"` 133 | 134 | # We build the pattern for arguments to be converted via cygpath 135 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 136 | SEP="" 137 | for dir in $ROOTDIRSRAW ; do 138 | ROOTDIRS="$ROOTDIRS$SEP$dir" 139 | SEP="|" 140 | done 141 | OURCYGPATTERN="(^($ROOTDIRS))" 142 | # Add a user-defined pattern to the cygpath arguments 143 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 144 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 145 | fi 146 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 147 | i=0 148 | for arg in "$@" ; do 149 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 150 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 151 | 152 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 153 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 154 | else 155 | eval `echo args$i`="\"$arg\"" 156 | fi 157 | i=`expr $i + 1` 158 | done 159 | case $i in 160 | 0) set -- ;; 161 | 1) set -- "$args0" ;; 162 | 2) set -- "$args0" "$args1" ;; 163 | 3) set -- "$args0" "$args1" "$args2" ;; 164 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 165 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 166 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 167 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 168 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 169 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 170 | esac 171 | fi 172 | 173 | # Escape application args 174 | save () { 175 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 176 | echo " " 177 | } 178 | APP_ARGS=`save "$@"` 179 | 180 | # Collect all arguments for the java command, following the shell quoting and substitution rules 181 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 182 | 183 | exec "$JAVACMD" "$@" 184 | -------------------------------------------------------------------------------- /triggers-bindings/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 34 | 35 | @rem Find java.exe 36 | if defined JAVA_HOME goto findJavaFromJavaHome 37 | 38 | set JAVA_EXE=java.exe 39 | %JAVA_EXE% -version >NUL 2>&1 40 | if "%ERRORLEVEL%" == "0" goto init 41 | 42 | echo. 43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 44 | echo. 45 | echo Please set the JAVA_HOME variable in your environment to match the 46 | echo location of your Java installation. 47 | 48 | goto fail 49 | 50 | :findJavaFromJavaHome 51 | set JAVA_HOME=%JAVA_HOME:"=% 52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 53 | 54 | if exist "%JAVA_EXE%" goto init 55 | 56 | echo. 57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 58 | echo. 59 | echo Please set the JAVA_HOME variable in your environment to match the 60 | echo location of your Java installation. 61 | 62 | goto fail 63 | 64 | :init 65 | @rem Get command-line arguments, handling Windows variants 66 | 67 | if not "%OS%" == "Windows_NT" goto win9xME_args 68 | 69 | :win9xME_args 70 | @rem Slurp the command line arguments. 71 | set CMD_LINE_ARGS= 72 | set _SKIP=2 73 | 74 | :win9xME_args_slurp 75 | if "x%~1" == "x" goto execute 76 | 77 | set CMD_LINE_ARGS=%* 78 | 79 | :execute 80 | @rem Setup the command line 81 | 82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 83 | 84 | @rem Execute Gradle 85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 86 | 87 | :end 88 | @rem End local scope for the variables with windows NT shell 89 | if "%ERRORLEVEL%"=="0" goto mainEnd 90 | 91 | :fail 92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 93 | rem the _cmd.exe /c_ return code! 94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 95 | exit /b 1 96 | 97 | :mainEnd 98 | if "%OS%"=="Windows_NT" endlocal 99 | 100 | :omega 101 | -------------------------------------------------------------------------------- /triggers-bindings/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "extensionBundle": { 4 | "id": "Microsoft.Azure.Functions.ExtensionBundle", 5 | "version": "[4.*, 5.0.0)" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /triggers-bindings/local.settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "IsEncrypted": false, 3 | "Values": { 4 | "AzureWebJobsStorage": "", 5 | "FUNCTIONS_WORKER_RUNTIME": "java", 6 | "CosmosDBDatabaseName": "", 7 | "CosmosDBCollectionName": "", 8 | "AzureWebJobsCosmosDBConnectionString": "", 9 | "AzureWebJobsEventGridOutputBindingTopicUriString": "", 10 | "AzureWebJobsEventGridOutputBindingTopicKeyString": "", 11 | "AzureWebJobsEventHubSender": "", 12 | "AzureWebJobsEventHubSender_2": "", 13 | "BrokerList": "", 14 | "ConfluentCloudUsername": "", 15 | "ConfluentCloudPassword": "", 16 | "AzureWebJobsServiceBus": "", 17 | "SBTopicName": "", 18 | "SBTopicSubName": "", 19 | "SBQueueName": "" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /triggers-bindings/mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Migwn, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | # TODO classpath? 118 | fi 119 | 120 | if [ -z "$JAVA_HOME" ]; then 121 | javaExecutable="`which javac`" 122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 123 | # readlink(1) is not available as standard on Solaris 10. 124 | readLink=`which readlink` 125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 126 | if $darwin ; then 127 | javaHome="`dirname \"$javaExecutable\"`" 128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 129 | else 130 | javaExecutable="`readlink -f \"$javaExecutable\"`" 131 | fi 132 | javaHome="`dirname \"$javaExecutable\"`" 133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 134 | JAVA_HOME="$javaHome" 135 | export JAVA_HOME 136 | fi 137 | fi 138 | fi 139 | 140 | if [ -z "$JAVACMD" ] ; then 141 | if [ -n "$JAVA_HOME" ] ; then 142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 143 | # IBM's JDK on AIX uses strange locations for the executables 144 | JAVACMD="$JAVA_HOME/jre/sh/java" 145 | else 146 | JAVACMD="$JAVA_HOME/bin/java" 147 | fi 148 | else 149 | JAVACMD="`which java`" 150 | fi 151 | fi 152 | 153 | if [ ! -x "$JAVACMD" ] ; then 154 | echo "Error: JAVA_HOME is not defined correctly." >&2 155 | echo " We cannot execute $JAVACMD" >&2 156 | exit 1 157 | fi 158 | 159 | if [ -z "$JAVA_HOME" ] ; then 160 | echo "Warning: JAVA_HOME environment variable is not set." 161 | fi 162 | 163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 164 | 165 | # traverses directory structure from process work directory to filesystem root 166 | # first directory with .mvn subdirectory is considered project base directory 167 | find_maven_basedir() { 168 | 169 | if [ -z "$1" ] 170 | then 171 | echo "Path not specified to find_maven_basedir" 172 | return 1 173 | fi 174 | 175 | basedir="$1" 176 | wdir="$1" 177 | while [ "$wdir" != '/' ] ; do 178 | if [ -d "$wdir"/.mvn ] ; then 179 | basedir=$wdir 180 | break 181 | fi 182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 183 | if [ -d "${wdir}" ]; then 184 | wdir=`cd "$wdir/.."; pwd` 185 | fi 186 | # end of workaround 187 | done 188 | echo "${basedir}" 189 | } 190 | 191 | # concatenates all lines of a file 192 | concat_lines() { 193 | if [ -f "$1" ]; then 194 | echo "$(tr -s '\n' ' ' < "$1")" 195 | fi 196 | } 197 | 198 | BASE_DIR=`find_maven_basedir "$(pwd)"` 199 | if [ -z "$BASE_DIR" ]; then 200 | exit 1; 201 | fi 202 | 203 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 204 | echo $MAVEN_PROJECTBASEDIR 205 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 206 | 207 | # For Cygwin, switch paths to Windows format before running java 208 | if $cygwin; then 209 | [ -n "$M2_HOME" ] && 210 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 211 | [ -n "$JAVA_HOME" ] && 212 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 213 | [ -n "$CLASSPATH" ] && 214 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 215 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 216 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 217 | fi 218 | 219 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 220 | 221 | exec "$JAVACMD" \ 222 | $MAVEN_OPTS \ 223 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 224 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 225 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 226 | -------------------------------------------------------------------------------- /triggers-bindings/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 84 | @REM Fallback to current working directory if not found. 85 | 86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 88 | 89 | set EXEC_DIR=%CD% 90 | set WDIR=%EXEC_DIR% 91 | :findBaseDir 92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 93 | cd .. 94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 95 | set WDIR=%CD% 96 | goto findBaseDir 97 | 98 | :baseDirFound 99 | set MAVEN_PROJECTBASEDIR=%WDIR% 100 | cd "%EXEC_DIR%" 101 | goto endDetectBaseDir 102 | 103 | :baseDirNotFound 104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 105 | cd "%EXEC_DIR%" 106 | 107 | :endDetectBaseDir 108 | 109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 110 | 111 | @setlocal EnableExtensions EnableDelayedExpansion 112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 114 | 115 | :endReadAdditionalConfig 116 | 117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 118 | 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 123 | if ERRORLEVEL 1 goto error 124 | goto end 125 | 126 | :error 127 | set ERROR_CODE=1 128 | 129 | :end 130 | @endlocal & set ERROR_CODE=%ERROR_CODE% 131 | 132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 136 | :skipRcPost 137 | 138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 140 | 141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 142 | 143 | exit /B %ERROR_CODE% 144 | -------------------------------------------------------------------------------- /triggers-bindings/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.functions 7 | azure-functions-sample 8 | 1.0-SNAPSHOT 9 | jar 10 | 11 | Azure Java Functions 12 | 13 | 14 | 1.8 15 | UTF-8 16 | 1.22.0 17 | 3.0.0 18 | azure-functions-sample 19 | westus 20 | java-functions-resource-group 21 | java-functions-service-plan 22 | Y1 23 | 24 | 25 | 26 | 27 | com.microsoft.azure.functions 28 | azure-functions-java-library 29 | ${azure.functions.java.library.version} 30 | 31 | 32 | 33 | com.microsoft 34 | durabletask-azure-functions 35 | 1.0.0 36 | 37 | 38 | 39 | com.mysql 40 | mysql-connector-j 41 | 8.2.0 42 | 43 | 44 | 45 | com.microsoft.sqlserver 46 | mssql-jdbc 47 | 12.4.1.jre11 48 | 49 | 50 | 51 | io.opentelemetry 52 | opentelemetry-api 53 | 1.31.0 54 | 55 | 56 | 57 | 58 | org.junit.jupiter 59 | junit-jupiter 60 | 5.6.2 61 | test 62 | 63 | 64 | org.mockito 65 | mockito-core 66 | 3.3.3 67 | test 68 | 69 | 70 | 71 | 72 | 73 | 74 | org.apache.maven.plugins 75 | maven-compiler-plugin 76 | 3.8.1 77 | 78 | ${java.version} 79 | ${java.version} 80 | ${project.build.sourceEncoding} 81 | 82 | 83 | 84 | com.microsoft.azure 85 | azure-functions-maven-plugin 86 | ${azure.functions.maven.plugin.version} 87 | 88 | 89 | ${functionAppName} 90 | 91 | ${functionResourceGroup} 92 | 93 | ${functionServicePlan} 94 | 95 | 96 | ${functionAppRegion} 97 | 98 | 99 | ${functionPricingTier} 100 | 101 | 102 | 103 | 104 | 105 | 106 | windows 107 | 8 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | FUNCTIONS_EXTENSION_VERSION 116 | ~4 117 | 118 | 119 | 120 | 121 | 122 | package-functions 123 | 124 | package 125 | 126 | 127 | 128 | 129 | 130 | 131 | maven-clean-plugin 132 | 3.1.0 133 | 134 | 135 | 136 | obj 137 | 138 | 139 | 140 | 141 | 142 | maven-surefire-plugin 143 | 2.22.2 144 | 145 | 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /triggers-bindings/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = "azure-functions-samples-java" 2 | -------------------------------------------------------------------------------- /triggers-bindings/src/main/java/com/functions/BlobTriggerFunction.java: -------------------------------------------------------------------------------- 1 | package com.functions; 2 | 3 | import com.microsoft.azure.functions.ExecutionContext; 4 | import com.microsoft.azure.functions.OutputBinding; 5 | import com.microsoft.azure.functions.annotation.*; 6 | 7 | /** 8 | * Azure Functions with Azure Storage Blob. 9 | * https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-storage-blob-trigger?tabs=java 10 | */ 11 | public class BlobTriggerFunction { 12 | /** 13 | * This function will be invoked when a new or updated blob is detected at the specified path. The blob contents are provided as input to this function. 14 | * The location of the blob is provided in the path parameter. Example - test-triggerinput-java/{name} below 15 | */ 16 | @FunctionName("BlobTrigger") 17 | @StorageAccount("AzureWebJobsStorage") 18 | public void BlobTriggerToBlobTest( 19 | @BlobTrigger(name = "triggerBlob", path = "test-triggerinput-java/{name}", dataType = "binary") byte[] triggerBlob, 20 | @BindingName("name") String fileName, 21 | @BlobInput(name = "inputBlob", path = "test-input-java/{name}", dataType = "binary") byte[] inputBlob, 22 | @BlobOutput(name = "outputBlob", path = "test-output-java/{name}", dataType = "binary") OutputBinding outputBlob, 23 | final ExecutionContext context 24 | ) { 25 | context.getLogger().info("Java Blob trigger function BlobTriggerToBlobTest processed a blob.\n Name: " + fileName + "\n Size: " + triggerBlob.length + " Bytes"); 26 | outputBlob.setValue(inputBlob); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /triggers-bindings/src/main/java/com/functions/CosmosDBTriggerFunction.java: -------------------------------------------------------------------------------- 1 | package com.functions; 2 | 3 | import com.microsoft.azure.functions.annotation.*; 4 | import com.microsoft.azure.functions.*; 5 | 6 | import java.io.IOException; 7 | import java.lang.reflect.Array; 8 | import java.util.*; 9 | 10 | /** 11 | * Azure Functions with Azure Cosmos DB. 12 | */ 13 | public class CosmosDBTriggerFunction { 14 | 15 | /** 16 | * This function will be invoked when a message is posted to 17 | * /api/CosmosDBInputId?docId={docId} contents are provided as the input to this 18 | * function. 19 | */ 20 | @FunctionName("CosmosDBInputId") 21 | public HttpResponseMessage CosmosDBInputId(@HttpTrigger(name = "req", methods = { HttpMethod.GET, 22 | HttpMethod.POST }, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage> request, 23 | @CosmosDBInput(name = "item", databaseName = "%CosmosDBDatabaseName%", containerName = "ItemsCollectionIn", connection = "AzureWebJobsCosmosDBConnectionString", id = "{docId}") String item, 24 | final ExecutionContext context) { 25 | 26 | context.getLogger().info("Java HTTP trigger processed a request."); 27 | 28 | if (item != null) { 29 | return request.createResponseBuilder(HttpStatus.OK).body("Received Document" + item).build(); 30 | } else { 31 | return request.createResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR) 32 | .body("Did not find expected item in ItemsCollectionIn").build(); 33 | } 34 | } 35 | 36 | @FunctionName("CosmosDBInputIdPOJO") 37 | public HttpResponseMessage CosmosDBInputIdPOJO(@HttpTrigger(name = "req", methods = { HttpMethod.GET, 38 | HttpMethod.POST }, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage> request, 39 | @CosmosDBInput(name = "item", databaseName = "%CosmosDBDatabaseName%", containerName = "ItemsCollectionIn", connection = "AzureWebJobsCosmosDBConnectionString", id = "{docId}") Document item, 40 | final ExecutionContext context) { 41 | 42 | context.getLogger().info("Java HTTP trigger processed a request."); 43 | 44 | if (item != null) { 45 | return request.createResponseBuilder(HttpStatus.OK).body("Received Document with Id " + item.id).build(); 46 | } else { 47 | return request.createResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR) 48 | .body("Did not find expected item in ItemsCollectionIn").build(); 49 | } 50 | } 51 | 52 | 53 | /** 54 | * This function will be invoked when a message is posted to 55 | * /api/CosmosDBInputQuery?name=joe Receives input with list of items matching 56 | * the sqlQuery 57 | */ 58 | @FunctionName("CosmosDBInputQueryPOJOArray") 59 | public HttpResponseMessage CosmosDBInputQueryPOJOArray(@HttpTrigger(name = "req", methods = { HttpMethod.GET, 60 | HttpMethod.POST }, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage> request, 61 | @CosmosDBInput(name = "items", databaseName = "%CosmosDBDatabaseName%", containerName = "ItemsCollectionIn", connection = "AzureWebJobsCosmosDBConnectionString", sqlQuery = "SELECT f.id, f.name FROM f WHERE f.name = {name}") Document[] items, 62 | @CosmosDBOutput(name = "itemsOut", databaseName = "%CosmosDBDatabaseName%", containerName = "ItemsCollectionOut", connection = "AzureWebJobsCosmosDBConnectionString") OutputBinding itemsOut, 63 | final ExecutionContext context) { 64 | context.getLogger().info("Java HTTP trigger processed a request."); 65 | 66 | if (items.length >= 2) { 67 | itemsOut.setValue(items); 68 | return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + items[0].name).build(); 69 | } else { 70 | return request.createResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR) 71 | .body("Did not find expected items in CosmosDB input list").build(); 72 | } 73 | } 74 | 75 | @FunctionName("CosmosDBInputQueryPOJOList") 76 | public HttpResponseMessage CosmosDBInputQueryPOJOList(@HttpTrigger(name = "req", methods = { HttpMethod.GET, 77 | HttpMethod.POST }, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage> request, 78 | @CosmosDBInput(name = "item", databaseName = "%CosmosDBDatabaseName%", containerName = "ItemsCollectionIn", connection = "AzureWebJobsCosmosDBConnectionString", sqlQuery = "SELECT f.id, f.name FROM f WHERE f.name = {name}") List items, 79 | @CosmosDBOutput(name = "itemsOut", databaseName = "%CosmosDBDatabaseName%", containerName = "ItemsCollectionOut", connection = "AzureWebJobsCosmosDBConnectionString") OutputBinding> itemsOut, 80 | final ExecutionContext context) { 81 | context.getLogger().info("Java HTTP trigger processed a request."); 82 | 83 | if (items.size() >= 2) { 84 | itemsOut.setValue(items); 85 | return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + items.get(0).name).build(); 86 | } else { 87 | return request.createResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR) 88 | .body("Did not find expected items in CosmosDB input list").build(); 89 | } 90 | } 91 | 92 | @FunctionName("CosmosDBInputQuery") 93 | public HttpResponseMessage CosmosDBInputQuery(@HttpTrigger(name = "req", methods = { HttpMethod.GET, 94 | HttpMethod.POST }, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage> request, 95 | @CosmosDBInput(name = "item", databaseName = "%CosmosDBDatabaseName%", containerName = "ItemsCollectionIn", connection = "AzureWebJobsCosmosDBConnectionString", sqlQuery = "SELECT f.id, f.name FROM f WHERE f.name = {name}") List items, 96 | final ExecutionContext context) { 97 | context.getLogger().info("Java HTTP trigger processed a request."); 98 | 99 | // Parse query parameters 100 | String query = request.getQueryParameters().get("name"); 101 | String name = request.getBody().orElse(query); 102 | 103 | if (items.size() >= 2) { 104 | return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build(); 105 | } else { 106 | return request.createResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR) 107 | .body("Did not find expected items in CosmosDB input list").build(); 108 | } 109 | } 110 | 111 | /** 112 | * This function will be invoked when a post request with file to 113 | * http://localhost:7071/api/CosmosDBOutput. A new document will add to the 114 | * container. 115 | */ 116 | @FunctionName("CosmosTriggerAndOutput") 117 | public void CosmosTriggerAndOutput( 118 | @CosmosDBTrigger(name = "itemIn", databaseName = "%CosmosDBDatabaseName%", containerName = "ItemCollectionIn", leaseContainerName = "leases", connection = "AzureWebJobsCosmosDBConnectionString", createLeaseContainerIfNotExists = true) Object inputItem, 119 | @CosmosDBOutput(name = "itemOut", databaseName = "%CosmosDBDatabaseName%", containerName = "ItemCollectionOut", connection = "AzureWebJobsCosmosDBConnectionString") OutputBinding outPutItem, 120 | final ExecutionContext context) { 121 | 122 | context.getLogger().info("Java Cosmos DB trigger function executed. Received document: " + inputItem); 123 | 124 | ArrayList inputItems = (ArrayList) inputItem; 125 | String objString = inputItems.get(0).toString(); 126 | String[] arrOfStr = objString.split("=", 2); 127 | String[] arrOfStrWithId = arrOfStr[1].split(",", 2); 128 | String docId = arrOfStrWithId[0]; 129 | 130 | context.getLogger().info("Writing to CosmosDB output binding Document id: " + docId); 131 | Document testDoc = new Document(); 132 | testDoc.id = docId; 133 | testDoc.Description = "testdescription"; 134 | outPutItem.setValue(testDoc); 135 | } 136 | 137 | public class Document { 138 | public String id; 139 | public String name; 140 | public String Description; 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /triggers-bindings/src/main/java/com/functions/EventGridTriggerFunction.java: -------------------------------------------------------------------------------- 1 | package com.functions; 2 | 3 | import com.microsoft.azure.functions.annotation.*; 4 | import com.microsoft.azure.functions.*; 5 | 6 | import java.util.*; 7 | 8 | /** 9 | * Azure Functions with Event Grid trigger. 10 | * https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-event-grid-trigger?tabs=java%2Cbash 11 | */ 12 | public class EventGridTriggerFunction { 13 | /** 14 | * This function will be invoked when an event is received from Event Grid. 15 | */ 16 | @FunctionName("EventGridTriggerJava") 17 | public void eventGridHandler( 18 | @EventGridTrigger(name = "eventgrid") String eventContent, 19 | final ExecutionContext context 20 | ) { 21 | context.getLogger().info("Java Event Grid trigger function executed."); 22 | context.getLogger().info(eventContent); 23 | } 24 | 25 | /** 26 | * This function will be invoked when a http trigger is received, and sends a custom event to Event Grid. 27 | */ 28 | @FunctionName("EventGridOutputBindingJava") 29 | public HttpResponseMessage eventGridOutputBinding( 30 | @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, 31 | authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage> request, 32 | @EventGridOutput(name = "outputEvent", 33 | topicEndpointUri = "AzureWebJobsEventGridOutputBindingTopicUriString", 34 | topicKeySetting = "AzureWebJobsEventGridOutputBindingTopicKeyString") OutputBinding outputEvent, 35 | final ExecutionContext context 36 | ) { 37 | context.getLogger().info("Java HTTP trigger processed a request."); 38 | 39 | // Parse query parameter 40 | String query = request.getQueryParameters().get("testuuid"); 41 | String message = request.getBody().orElse(query); 42 | context.getLogger().info("testuuid:" + message); 43 | 44 | final EventGridEvent eventGridOutputDocument = new EventGridEvent(); 45 | eventGridOutputDocument.setId("test-id"); 46 | eventGridOutputDocument.setEventType("test-event-1"); 47 | eventGridOutputDocument.setEventTime("2020-01-31T10:10:10+00:00"); 48 | eventGridOutputDocument.setDataVersion("1.0"); 49 | eventGridOutputDocument.setSubject("test-subject"); 50 | eventGridOutputDocument.setData("test-uuid: " + message); 51 | 52 | outputEvent.setValue(eventGridOutputDocument); 53 | 54 | return request.createResponseBuilder(HttpStatus.OK).build(); 55 | } 56 | } 57 | 58 | 59 | class EventGridEvent { 60 | private String id; 61 | private String eventType; 62 | private String subject; 63 | private String eventTime; 64 | private String dataVersion; 65 | private String data; 66 | 67 | public String getId() { 68 | return id; 69 | } 70 | 71 | public String getData() { 72 | return data; 73 | } 74 | 75 | public void setData(String data) { 76 | this.data = data; 77 | } 78 | 79 | public String getDataVersion() { 80 | return dataVersion; 81 | } 82 | 83 | public void setDataVersion(String dataVersion) { 84 | this.dataVersion = dataVersion; 85 | } 86 | 87 | public String getEventTime() { 88 | return eventTime; 89 | } 90 | 91 | public void setEventTime(String eventTime) { 92 | this.eventTime = eventTime; 93 | } 94 | 95 | public String getSubject() { 96 | return subject; 97 | } 98 | 99 | public void setSubject(String subject) { 100 | this.subject = subject; 101 | } 102 | 103 | public String getEventType() { 104 | return eventType; 105 | } 106 | 107 | public void setEventType(String eventType) { 108 | this.eventType = eventType; 109 | } 110 | 111 | public void setId(String id) { 112 | this.id = id; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /triggers-bindings/src/main/java/com/functions/EventHubTriggerFunction.java: -------------------------------------------------------------------------------- 1 | package com.functions; 2 | 3 | import com.microsoft.azure.functions.annotation.*; 4 | import com.microsoft.azure.functions.*; 5 | 6 | import java.util.*; 7 | 8 | /** 9 | * Azure Functions with Azure Event Hub. 10 | * https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-event-hubs-trigger?tabs=java 11 | */ 12 | public class EventHubTriggerFunction { 13 | /** 14 | * This function will be invoked when a new message is received at the specified EventHub. The message contents are provided as input to this function. 15 | */ 16 | @FunctionName("EventHubTriggerAndOutputJSON") 17 | public void EventHubTriggerAndOutputJSON( 18 | @EventHubTrigger(name = "messages", eventHubName = "test-inputjson-java", connection = "AzureWebJobsEventHubSender", cardinality = Cardinality.MANY) List messages, 19 | @EventHubOutput(name = "output", eventHubName = "test-outputjson-java", connection = "AzureWebJobsEventHubSender") OutputBinding output, 20 | final ExecutionContext context 21 | ) { 22 | context.getLogger().info("Java Event Hub trigger received " + messages.size() + " messages"); 23 | output.setValue(messages.get(0)); 24 | } 25 | 26 | @FunctionName("EventHubTriggerCardinalityOneEventMetadata") 27 | public void EventHubTriggerCardinalityOneEventMetadata( 28 | @EventHubTrigger( 29 | name = "message", 30 | eventHubName = "test-input-java", 31 | consumerGroup = "$default", 32 | connection = "AzureWebJobsEventHubSender", 33 | cardinality = Cardinality.ONE 34 | ) String message, 35 | final ExecutionContext context, 36 | @BindingName("Properties") Map properties, 37 | @BindingName("SystemProperties") Map systemProperties, 38 | @BindingName("PartitionContext") Map partitionContext, 39 | @BindingName("EnqueuedTimeUtc") Object enqueuedTimeUtc, 40 | @BindingName("Offset") Object offset, 41 | @BindingName("PartitionKey") Object partitionKey, 42 | @BindingName("SequenceNumber") Object sequenceNumber) { 43 | // Parse query parameter 44 | context.getLogger().info("Java Event Hub trigger received message" + message); 45 | context.getLogger().info("Properties: " + properties); 46 | context.getLogger().info("System Properties: " + systemProperties); 47 | context.getLogger().info("PartitionContext: " + partitionContext); 48 | context.getLogger().info("EnqueuedTimeUtc: " + enqueuedTimeUtc); 49 | context.getLogger().info("Offset: " + offset); 50 | context.getLogger().info("PartitionKey: " + partitionKey); 51 | context.getLogger().info("SequenceNumber: " + sequenceNumber); 52 | } 53 | 54 | @FunctionName("EventHubTriggerCardinalityManyEventMetadata") 55 | public void EventHubTriggerCardinalityManyEventMetadata( 56 | @EventHubTrigger( 57 | name = "messages", 58 | eventHubName = "test-input-java", 59 | connection = "AzureWebJobsEventHubSender", 60 | dataType = "string", 61 | cardinality = Cardinality.MANY 62 | ) String[] messages, 63 | @BindingName("PropertiesArray") Map[] propertiesArray, 64 | @BindingName("SystemPropertiesArray") Map[] systemPropertiesArray, 65 | @BindingName("EnqueuedTimeUtcArray") List enqueuedTimeUtcArray, 66 | @BindingName("OffsetArray") List offsetArray, 67 | @BindingName("PartitionKeyArray") List partitionKeyArray, 68 | @BindingName("SequenceNumberArray") List sequenceNumberArray, 69 | final ExecutionContext context 70 | ) { 71 | context.getLogger().info("Java Event Hub trigger received " + messages.length + " messages"); 72 | context.getLogger().info("message[0]=" + messages[0]); 73 | context.getLogger().info("Properties for message[0]=" + propertiesArray[0]); 74 | context.getLogger().info("SystemProperties for message[0]="+ systemPropertiesArray[0]); 75 | context.getLogger().info("EnqueuedTimeUtc for message[0]=" + enqueuedTimeUtcArray.get(0)); 76 | context.getLogger().info("Offset for message[0]=" + offsetArray.get(0)); 77 | context.getLogger().info("PartitionKey for message[0]=" + partitionKeyArray.get(0)); 78 | context.getLogger().info("SequenceNumber for message[0]=" + sequenceNumberArray.get(0)); 79 | } 80 | 81 | @FunctionName("EventHubTriggerAndOutputString") 82 | public void EventHubTriggerAndOutputString( 83 | @EventHubTrigger(name = "messages", eventHubName = "test-input-java", connection = "AzureWebJobsEventHubSender", dataType = "string", cardinality = Cardinality.MANY) String[] messages, 84 | @BindingName("SystemPropertiesArray") SystemProperty[] systemPropertiesArray, 85 | @EventHubOutput(name = "output", eventHubName = "test-output-java", connection = "AzureWebJobsEventHubSender") OutputBinding output, 86 | final ExecutionContext context 87 | ) { 88 | context.getLogger().info("Java Event Hub trigger received " + messages.length + " messages"); 89 | context.getLogger().info("SystemProperties for message[0]: EnqueuedTimeUtc=" + systemPropertiesArray[0].EnqueuedTimeUtc + " Offset=" + systemPropertiesArray[0].Offset); 90 | output.setValue(messages[0]); 91 | 92 | } 93 | 94 | @FunctionName("EventHubTriggerCardinalityOne") 95 | public void EventHubTriggerCardinalityOne( 96 | @EventHubTrigger(name = "message", eventHubName = "test-inputOne-java", connection = "AzureWebJobsEventHubSender", dataType = "string", cardinality = Cardinality.ONE) String message, 97 | @EventHubOutput(name = "output", eventHubName = "test-outputone-java", connection = "AzureWebJobsEventHubSender") OutputBinding output, 98 | final ExecutionContext context 99 | ) { 100 | context.getLogger().info("Java Event Hub trigger received message" + message); 101 | output.setValue(message); 102 | } 103 | 104 | /** 105 | * This function verifies the above functions 106 | */ 107 | @FunctionName("EventHubOutputJson") 108 | public void TestEventHubOutputJson( 109 | @EventHubTrigger(name = "message", eventHubName = "test-outputjson-java", connection = "AzureWebJobsEventHubSender") String message, 110 | @QueueOutput(name = "output", queueName = "test-eventhuboutputjson-java", connection = "AzureWebJobsStorage") OutputBinding output, 111 | final ExecutionContext context 112 | ) { 113 | context.getLogger().info("Java Event Hub Output function processed a message: " + message); 114 | output.setValue(message); 115 | } 116 | 117 | @FunctionName("EventHubOutput") 118 | public void TestEventHubOutput( 119 | @EventHubTrigger(name = "message", eventHubName = "test-output-java", connection = "AzureWebJobsEventHubSender", cardinality = Cardinality.ONE) String message, 120 | @QueueOutput(name = "output", queueName = "test-eventhuboutput-java", connection = "AzureWebJobsStorage") OutputBinding output, 121 | final ExecutionContext context 122 | ) { 123 | context.getLogger().info("Java Event Hub Output function processed a message: " + message); 124 | output.setValue(message); 125 | } 126 | 127 | @FunctionName("EventHubOutputInputOne") 128 | public void TestEventHubOutputInputOne( 129 | @EventHubTrigger(name = "message", eventHubName = "test-outputone-java", connection = "AzureWebJobsEventHubSender", cardinality = Cardinality.ONE) String message, 130 | @QueueOutput(name = "output", queueName = "test-eventhuboutputone-java", connection = "AzureWebJobsStorage") OutputBinding output, 131 | final ExecutionContext context 132 | ) { 133 | context.getLogger().info("Java Event Hub Output function processed a message: " + message); 134 | output.setValue(message); 135 | } 136 | 137 | @FunctionName("EventHubTriggerAndOutputBinaryCardinalityManyListBinary") 138 | public void EventHubTriggerAndOutputBinaryCardinalityManyListBinary( 139 | @EventHubTrigger(name = "messages", eventHubName = "test-binary-input-cardinality-many-list-java", connection = "AzureWebJobsEventHubSender_2", dataType = "binary", cardinality = Cardinality.MANY) List messages, 140 | @QueueOutput(name = "output", queueName = "test-binary-output-cardinality-many-list-java", connection = "AzureWebJobsStorage") OutputBinding output, 141 | final ExecutionContext context 142 | ) { 143 | context.getLogger().info("Java Event Hub trigger received " + messages.size() + " messages"); 144 | output.setValue(messages.get(0)); 145 | } 146 | 147 | @FunctionName("EventHubTriggerAndOutputBinaryCardinalityOne") 148 | public void EventHubTriggerAndOutputBinaryCardinalityOne( 149 | @EventHubTrigger(name = "message", eventHubName = "test-binary-input-cardinality-one-java", connection = "AzureWebJobsEventHubSender_2", dataType = "binary", cardinality = Cardinality.ONE) byte[] message, 150 | @QueueOutput(name = "output", queueName = "test-binary-output-cardinality-one-java", connection = "AzureWebJobsStorage") OutputBinding output, 151 | final ExecutionContext context 152 | ) { 153 | context.getLogger().info("Java Event Hub trigger received message" + message); 154 | output.setValue(message); 155 | } 156 | 157 | @FunctionName("EventHubTriggerAndOutputBinaryCardinalityManyArrayBinary") 158 | public void EventHubTriggerAndOutputBinaryCardinalityManyArrayBinary( 159 | @EventHubTrigger(name = "messages", eventHubName = "test-binary-input-cardinality-many-array-java", connection = "AzureWebJobsEventHubSender_2", dataType = "binary", cardinality = Cardinality.MANY) byte[][] messages, 160 | @QueueOutput(name = "output", queueName = "test-binary-output-cardinality-many-array-java", connection = "AzureWebJobsStorage") OutputBinding output, 161 | final ExecutionContext context 162 | ) { 163 | context.getLogger().info("Java Event Hub trigger received " + messages.length + " messages"); 164 | output.setValue(messages[0]); 165 | } 166 | 167 | public static class SystemProperty { 168 | public String SequenceNumber; 169 | public String Offset; 170 | public String PartitionKey; 171 | public String EnqueuedTimeUtc; 172 | 173 | public SystemProperty(String sequenceNumber, String offset, String partitionKey, String enqueuedTimeUtc) { 174 | this.SequenceNumber = sequenceNumber; 175 | this.Offset = offset; 176 | this.PartitionKey = partitionKey; 177 | this.EnqueuedTimeUtc = enqueuedTimeUtc; 178 | } 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /triggers-bindings/src/main/java/com/functions/Function.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for 4 | * license information. 5 | */ 6 | 7 | package com.functions; 8 | 9 | import com.microsoft.azure.functions.ExecutionContext; 10 | import com.microsoft.azure.functions.HttpMethod; 11 | import com.microsoft.azure.functions.HttpRequestMessage; 12 | import com.microsoft.azure.functions.HttpResponseMessage; 13 | import com.microsoft.azure.functions.HttpStatus; 14 | import com.microsoft.azure.functions.annotation.AuthorizationLevel; 15 | import com.microsoft.azure.functions.annotation.FixedDelayRetry; 16 | import com.microsoft.azure.functions.annotation.FunctionName; 17 | import com.microsoft.azure.functions.annotation.HttpTrigger; 18 | 19 | import java.io.File; 20 | import java.nio.file.Files; 21 | import java.util.Optional; 22 | 23 | /** 24 | * Azure Functions with HTTP Trigger. 25 | */ 26 | public class Function { 27 | /** 28 | * This function listens at endpoint "/api/HttpExample". Two ways to invoke it using "curl" command in bash: 29 | * 1. curl -d "HTTP Body" {your host}/api/HttpExample 30 | * 2. curl "{your host}/api/HttpExample?name=HTTP%20Query" 31 | */ 32 | @FunctionName("HttpExample") 33 | public HttpResponseMessage run( 34 | @HttpTrigger( 35 | name = "req", 36 | methods = {HttpMethod.GET, HttpMethod.POST}, 37 | authLevel = AuthorizationLevel.ANONYMOUS) 38 | HttpRequestMessage> request, 39 | final ExecutionContext context) { 40 | context.getLogger().info("Java HTTP trigger processed a request."); 41 | 42 | // Parse query parameter 43 | final String query = request.getQueryParameters().get("name"); 44 | final String name = request.getBody().orElse(query); 45 | 46 | if (name == null) { 47 | return request.createResponseBuilder(HttpStatus.BAD_REQUEST).body("Please pass a name on the query string or in the request body").build(); 48 | } else { 49 | return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build(); 50 | } 51 | } 52 | 53 | public static int count = 1; 54 | 55 | /** 56 | * This function listens at endpoint "/api/HttpExampleRetry". The function is re-executed in case of errors until the maximum number of retries occur. 57 | * Retry policies: https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-error-pages?tabs=java 58 | */ 59 | @FunctionName("HttpExampleRetry") 60 | @FixedDelayRetry(maxRetryCount = 3, delayInterval = "00:00:05") 61 | public HttpResponseMessage HttpExampleRetry( 62 | @HttpTrigger( 63 | name = "req", 64 | methods = {HttpMethod.GET, HttpMethod.POST}, 65 | authLevel = AuthorizationLevel.ANONYMOUS) 66 | HttpRequestMessage> request, 67 | final ExecutionContext context) throws Exception { 68 | context.getLogger().info("Java HTTP trigger processed a request."); 69 | 70 | if(count<3) { 71 | count ++; 72 | throw new Exception("error"); 73 | } 74 | 75 | // Parse query parameter 76 | final String query = request.getQueryParameters().get("name"); 77 | final String name = request.getBody().orElse(query); 78 | 79 | if (name == null) { 80 | return request.createResponseBuilder(HttpStatus.BAD_REQUEST).body("Please pass a name on the query string or in the request body").build(); 81 | } else { 82 | return request.createResponseBuilder(HttpStatus.OK).body(name).build(); 83 | } 84 | } 85 | 86 | /** 87 | * This function listens at endpoint "/api/HttpTriggerJavaVersion". 88 | * It can be used to verify the Java home and java version currently in use in your Azure function 89 | */ 90 | @FunctionName("HttpTriggerJavaVersion") 91 | public static HttpResponseMessage HttpTriggerJavaVersion( 92 | @HttpTrigger( 93 | name = "req", 94 | methods = {HttpMethod.GET, HttpMethod.POST}, 95 | authLevel = AuthorizationLevel.ANONYMOUS) 96 | HttpRequestMessage> request, 97 | final ExecutionContext context 98 | ) { 99 | context.getLogger().info("Java HTTP trigger processed a request."); 100 | final String javaVersion = getJavaVersion(); 101 | context.getLogger().info("Function - HttpTriggerJavaVersion" + javaVersion); 102 | return request.createResponseBuilder(HttpStatus.OK).body("HttpTriggerJavaVersion").build(); 103 | } 104 | 105 | public static String getJavaVersion() { 106 | return String.join(" - ", System.getProperty("java.home"), System.getProperty("java.version")); 107 | } 108 | 109 | /** 110 | * This function listens at endpoint "/api/StaticWebPage". 111 | * It can be used to read and serve a static web page. 112 | * Note: Read the file from the right location for local machine and azure portal usage. 113 | */ 114 | @FunctionName("StaticWebPage") 115 | public HttpResponseMessage getStaticWebPage( 116 | @HttpTrigger( 117 | name = "req", 118 | methods = {HttpMethod.GET, HttpMethod.POST}, 119 | authLevel = AuthorizationLevel.ANONYMOUS) 120 | HttpRequestMessage> request, 121 | final ExecutionContext context) { 122 | context.getLogger().info("Java HTTP trigger processed a request."); 123 | 124 | File htmlFile = new File("index.html"); 125 | try{ 126 | byte[] fileContent = Files.readAllBytes(htmlFile.toPath()); 127 | return request.createResponseBuilder(HttpStatus.OK).body(fileContent).build(); 128 | }catch (Exception e){ 129 | context.getLogger().info("Error reading file."); 130 | return request.createResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR).build(); 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /triggers-bindings/src/main/java/com/functions/KafkaTriggerFunction.java: -------------------------------------------------------------------------------- 1 | package com.functions; 2 | 3 | import java.util.*; 4 | 5 | import com.microsoft.azure.functions.annotation.*; 6 | import com.microsoft.azure.functions.*; 7 | 8 | 9 | import java.util.Optional; 10 | 11 | public class KafkaTriggerFunction { 12 | 13 | @FunctionName("HttpTriggerAndKafkaOutput") 14 | public HttpResponseMessage HttpTriggerAndKafkaOutput( 15 | @HttpTrigger(name = "req", methods = {HttpMethod.GET}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage> request, 16 | @KafkaOutput( 17 | name = "httpTriggerAndKafkaOutput", 18 | topic = "ci", 19 | brokerList = "%BrokerList%", 20 | username = "%ConfluentCloudUsername%", 21 | password = "%ConfluentCloudPassword%", 22 | authenticationMode = BrokerAuthenticationMode.PLAIN, 23 | sslCaLocation = "confluent_cloud_cacert.pem", 24 | protocol = BrokerProtocol.SASLSSL 25 | ) OutputBinding output, 26 | final ExecutionContext context) { 27 | String message = request.getQueryParameters().get("message"); 28 | message = request.getBody().orElse(message); 29 | context.getLogger().info("Java Http trigger received Message:" + message + " messages for Kafka Output"); 30 | output.setValue(message); 31 | return request.createResponseBuilder(HttpStatus.OK).body(message).build(); 32 | } 33 | 34 | @FunctionName("KafkaTriggerAndKafkaOutput") 35 | public void KafkaTriggerAndKafkaOutput( 36 | @KafkaTrigger( 37 | name = "kafkaTriggerAndKafkaOutput", 38 | topic = "ci", 39 | brokerList = "%BrokerList%", 40 | consumerGroup = "$Default", 41 | username = "%ConfluentCloudUsername%", 42 | password = "%ConfluentCloudPassword%", 43 | authenticationMode = BrokerAuthenticationMode.PLAIN, 44 | protocol = BrokerProtocol.SASLSSL, 45 | sslCaLocation = "confluent_cloud_cacert.pem", 46 | dataType = "string" 47 | ) String message, 48 | @QueueOutput(name = "output", queueName = "test-kafka-output-cardinality-one-java", connection = "AzureWebJobsStorage") OutputBinding output, 49 | final ExecutionContext context) { 50 | context.getLogger().info("Java Kafka Output function processed a message: " + message); 51 | output.setValue(message); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /triggers-bindings/src/main/java/com/functions/QueueTriggerFunction.java: -------------------------------------------------------------------------------- 1 | package com.functions; 2 | 3 | import com.microsoft.azure.functions.annotation.*; 4 | import com.microsoft.azure.functions.*; 5 | 6 | import java.util.*; 7 | 8 | /** 9 | * Azure Functions with Azure Storage Queue. 10 | * https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-storage-queue-trigger?tabs=java 11 | */ 12 | public class QueueTriggerFunction { 13 | /** 14 | * This function will be invoked when a http request is received. The message contents are provided as output to this function. 15 | */ 16 | @FunctionName("QueueTriggerAndOutput") 17 | public void queuetriggerandoutput( 18 | @QueueTrigger(name = "message", queueName = "test-input-java", connection = "AzureWebJobsStorage") String message, 19 | @QueueOutput(name = "output", queueName = "test-output-java", connection = "AzureWebJobsStorage") OutputBinding output, 20 | final ExecutionContext context 21 | ) { 22 | context.getLogger().info("Java Queue trigger function processed a message: " + message); 23 | output.setValue(message); 24 | } 25 | 26 | @FunctionName("QueueOutputPOJOList") 27 | public HttpResponseMessage QueueOutputPOJOList(@HttpTrigger(name = "req", methods = {HttpMethod.GET, 28 | HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage> request, 29 | @QueueOutput(name = "output", queueName = "test-output-java-pojo", connection = "AzureWebJobsStorage") OutputBinding> itemsOut, 30 | final ExecutionContext context) { 31 | context.getLogger().info("Java HTTP trigger processed a request."); 32 | 33 | String query = request.getQueryParameters().get("queueMessageId"); 34 | String queueMessageId = request.getBody().orElse(query); 35 | itemsOut.setValue(new ArrayList()); 36 | if (queueMessageId != null) { 37 | TestData testData1 = new TestData(); 38 | testData1.id = "msg1" + queueMessageId; 39 | TestData testData2 = new TestData(); 40 | testData2.id = "msg2" + queueMessageId; 41 | 42 | itemsOut.getValue().add(testData1); 43 | itemsOut.getValue().add(testData2); 44 | 45 | return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + queueMessageId).build(); 46 | } else { 47 | return request.createResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR) 48 | .body("Did not find expected items in CosmosDB input list").build(); 49 | } 50 | } 51 | 52 | @FunctionName("QueueTriggerAndOutputPOJO") 53 | public void queuetriggerandoutputPOJO( 54 | @QueueTrigger(name = "message", queueName = "test-input-java-pojo", connection = "AzureWebJobsStorage") TestData message, 55 | @QueueOutput(name = "output", queueName = "test-output-java-pojo", connection = "AzureWebJobsStorage") OutputBinding output, 56 | final ExecutionContext context 57 | ) { 58 | context.getLogger().info("Java Queue trigger POJO function processed a message: " + message.id); 59 | output.setValue(message); 60 | } 61 | 62 | @FunctionName("QueueTriggerMetadata") 63 | public void QueueTriggerMetadata( 64 | @QueueTrigger(name = "message", queueName = "test-input-java-metadata", connection = "AzureWebJobsStorage") String message, @BindingName("Id") String metadataId, 65 | @QueueOutput(name = "output", queueName = "test-output-java-metadata", connection = "AzureWebJobsStorage") OutputBinding output, 66 | final ExecutionContext context 67 | ) { 68 | context.getLogger().info("Java Queue trigger function processed a message: " + message + " whith metadaId:" + metadataId); 69 | TestData testData = new TestData(); 70 | testData.id = metadataId; 71 | output.setValue(testData); 72 | } 73 | 74 | public static class TestData { 75 | public String id; 76 | } 77 | } 78 | 79 | 80 | -------------------------------------------------------------------------------- /triggers-bindings/src/main/java/com/functions/ServiceBusQueueTriggerFunction.java: -------------------------------------------------------------------------------- 1 | package com.functions; 2 | 3 | import com.microsoft.azure.functions.annotation.*; 4 | import com.microsoft.azure.functions.*; 5 | 6 | import java.util.*; 7 | 8 | /** 9 | * Azure Functions with Azure Service Bus Queue. 10 | * https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-service-bus-trigger?tabs=java 11 | */ 12 | public class ServiceBusQueueTriggerFunction { 13 | 14 | @FunctionName("ServiceBusQueueTrigger") 15 | public void serviceBusQueueTrigger( 16 | @ServiceBusQueueTrigger(name = "message", queueName = "SBQueueNameSingle", connection = "AzureWebJobsServiceBus") String message, 17 | @QueueOutput(name = "output", queueName = "test-servicebusqueuesingle-java", connection = "AzureWebJobsStorage") OutputBinding output, 18 | final ExecutionContext context 19 | ) { 20 | context.getLogger().info("Java Service Bus Queue trigger function processed a message: " + message); 21 | output.setValue(message); 22 | } 23 | 24 | @FunctionName("ServiceBusQueueBatchTrigger") 25 | public void serviceBusQueueBatchTrigger( 26 | @ServiceBusQueueTrigger(name = "message", queueName = "SBQueueNameBatch", connection = "AzureWebJobsServiceBus", cardinality = Cardinality.MANY, dataType = "String") String[] messages, 27 | @QueueOutput(name = "output", queueName = "test-servicebusqueuebatch-java", connection = "AzureWebJobsStorage") OutputBinding output, 28 | final ExecutionContext context 29 | ) { 30 | context.getLogger().info("Java Service Bus Queue trigger function processed a message: " + messages[0]); 31 | output.setValue(messages[0]); 32 | } 33 | 34 | /** 35 | * This function will be invoked when a http request is received. The message contents are provided as output to this function. 36 | */ 37 | @FunctionName("ServiceBusQueueOutput") 38 | public void serviceBusQueueOutput( 39 | @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage> request, 40 | @ServiceBusQueueOutput(name = "output", queueName = "%SBQueueName%", connection = "AzureWebJobsServiceBus") OutputBinding output, 41 | final ExecutionContext context 42 | ) { 43 | String message = request.getBody().orElse("default message"); 44 | output.setValue(message); 45 | context.getLogger().info("Java Service Bugs Queue output function got a message: " + message); 46 | } 47 | 48 | 49 | } 50 | -------------------------------------------------------------------------------- /triggers-bindings/src/main/java/com/functions/ServiceBusTopicTriggerFunction.java: -------------------------------------------------------------------------------- 1 | package com.functions; 2 | 3 | 4 | import com.microsoft.azure.functions.annotation.*; 5 | import com.microsoft.azure.functions.*; 6 | 7 | import java.util.*; 8 | 9 | /** 10 | * Azure Functions with Azure Service Bus Topic. 11 | * https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-service-bus-trigger?tabs=java 12 | */ 13 | public class ServiceBusTopicTriggerFunction { 14 | 15 | @FunctionName("ServiceBusTopicTrigger") 16 | public void serviceBusTopicTrigger( 17 | @ServiceBusTopicTrigger(name = "message", topicName = "SBTopicNameSingle", subscriptionName = "SBTopicNameSingleSubName", connection = "AzureWebJobsServiceBus") String message, 18 | @QueueOutput(name = "output", queueName = "test-servicebustopicbatch-java", connection = "AzureWebJobsStorage") OutputBinding output, 19 | final ExecutionContext context 20 | ) { 21 | context.getLogger().info("Java Service Bus Topic trigger function processed a message: " + message); 22 | output.setValue(message); 23 | } 24 | 25 | @FunctionName("ServiceBusTopicTriggerMetadata") 26 | public void serviceBusTopicTriggerMetadata( 27 | @ServiceBusTopicTrigger(name = "message", topicName = "SBTopicNameMetadata", subscriptionName = "SBTopicNameMetadataSubName", connection = "AzureWebJobsServiceBus") String message, 28 | @BindingName("UserProperties") Map properties, 29 | @BindingName("CorrelationId") String correlationId, 30 | final ExecutionContext context 31 | ) { 32 | context.getLogger().info("Java Service Bus Topic trigger function processed a message: " + message); 33 | context.getLogger().info("Custom message properties = " + properties); 34 | context.getLogger().info("CorrelationId = " + correlationId); 35 | } 36 | 37 | @FunctionName("ServiceBusTopicBatchTrigger") 38 | public void serviceBusTopicBatchTrigger( 39 | @ServiceBusTopicTrigger(name = "message", topicName = "SBTopicNameBatch", subscriptionName = "SBTopicNameBatchSubName", connection = "AzureWebJobsServiceBus", cardinality = Cardinality.MANY, dataType = "String") List messages, 40 | @QueueOutput(name = "output", queueName = "test-servicebustopicbatch-java", connection = "AzureWebJobsStorage") OutputBinding output, 41 | final ExecutionContext context 42 | ) { 43 | context.getLogger().info("Java Service Bus Topic trigger function processed a message: " + messages.get(0)); 44 | output.setValue(messages.get(0)); 45 | } 46 | 47 | /** 48 | * This function will be invoked when a http request is received. The message contents are provided as output to this function. 49 | */ 50 | @FunctionName("ServiceBusTopicOutput") 51 | public void serviceBusTopicOutput( 52 | @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage> request, 53 | @ServiceBusTopicOutput(name = "message", topicName = "%SBTopicName%", subscriptionName = "%SBTopicSubName%", connection = "AzureWebJobsServiceBus") OutputBinding output, 54 | final ExecutionContext context 55 | ) { 56 | String message = request.getBody().orElse("default message"); 57 | output.setValue(message); 58 | context.getLogger().info("Java Service Bus Topic output function got a message: " + message); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /triggers-bindings/src/main/java/com/functions/TableFunction.java: -------------------------------------------------------------------------------- 1 | package com.functions; 2 | 3 | import com.microsoft.azure.functions.annotation.*; 4 | import com.microsoft.azure.functions.*; 5 | 6 | import java.util.*; 7 | 8 | /** 9 | * Azure Functions with Azure Storage table. 10 | * https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-storage-table-output?tabs=java 11 | */ 12 | public class TableFunction { 13 | /** 14 | * This function will be invoked when a new queue message is received. 15 | */ 16 | @FunctionName("TableInput") 17 | public void tableInputJava( 18 | @QueueTrigger(name = "message", queueName = "mytablequeue", connection = "AzureWebJobsStorage") String message, 19 | @TableInput(name = "personEntity", tableName = "Person", rowKey = "{queueTrigger}", partitionKey = "firstPartition", connection = "AzureWebJobsStorage") String personEntity, 20 | final ExecutionContext context 21 | ) { 22 | context.getLogger().info("Java Queue trigger function processed a new message: " + message); 23 | context.getLogger().info("Java Table Input function processed a Person entity:" + personEntity); 24 | } 25 | 26 | /** 27 | * This function will be invoked when a new http request is received at the specified path. 28 | */ 29 | @FunctionName("TableOutput") 30 | public void tableOutputJava( 31 | @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage> request, 32 | @TableOutput(name = "myOutputTable", tableName = "Person", connection = "AzureWebJobsStorage") OutputBinding myOutputTable, 33 | final ExecutionContext context 34 | ) { 35 | String httpbody = request.getBody().orElse("default"); 36 | myOutputTable.setValue(new Person(httpbody + "Partition", httpbody + "Row", httpbody + "Name")); 37 | context.getLogger().info("Java Table Output function write a new entity into table Person with name: " + httpbody + "Name"); 38 | } 39 | 40 | public static class Person { 41 | public String PartitionKey; 42 | public String RowKey; 43 | public String Name; 44 | 45 | public Person(String p, String r, String n) { 46 | this.PartitionKey = p; 47 | this.RowKey = r; 48 | this.Name = n; 49 | } 50 | } 51 | } 52 | 53 | -------------------------------------------------------------------------------- /triggers-bindings/src/main/java/com/functions/TimerTriggerFunction.java: -------------------------------------------------------------------------------- 1 | package com.functions; 2 | 3 | import com.microsoft.azure.functions.annotation.*; 4 | import com.microsoft.azure.functions.*; 5 | import java.time.*; 6 | 7 | /** 8 | * Azure Functions with Timer trigger. 9 | * https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-timer?tabs=java 10 | */ 11 | public class TimerTriggerFunction { 12 | /** 13 | * This function will be invoked periodically according to the specified schedule. 14 | * The below function is executed each time the minutes have a value divisible by five 15 | */ 16 | @FunctionName("TimerTrigger") 17 | public void timerHandler( 18 | @TimerTrigger(name = "timerInfo", schedule = "0 */5 * * * *") String timerInfo, 19 | final ExecutionContext context 20 | ) { 21 | context.getLogger().info("Java Timer trigger function executed at: " + LocalDateTime.now()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /triggers-bindings/src/test/java/com/functions/EventHubTriggerFunctionTest.java: -------------------------------------------------------------------------------- 1 | package com.functions; 2 | 3 | import com.microsoft.azure.functions.ExecutionContext; 4 | import com.microsoft.azure.functions.OutputBinding; 5 | import org.junit.jupiter.api.BeforeEach; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import java.nio.charset.StandardCharsets; 9 | import java.time.Instant; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | import java.util.logging.Logger; 13 | 14 | import static org.junit.jupiter.api.Assertions.assertEquals; 15 | import static org.mockito.Mockito.doReturn; 16 | import static org.mockito.Mockito.mock; 17 | 18 | public class EventHubTriggerFunctionTest { 19 | /** 20 | * Unit test for EventHubTriggerFunction class. 21 | */ 22 | // Define the shared variables globally. 23 | ExecutionContext context; 24 | EventHubTriggerFunction eventHubTriggerFunction; 25 | OutputBinding output; 26 | OutputBinding outputAsByteArray; 27 | 28 | // Before the tests are run, execute the below configurations. 29 | @BeforeEach 30 | void setup() { 31 | // Mock the Execution Context and its logger since we will be using this in the Azure Functions. 32 | this.context = mock(ExecutionContext.class); 33 | doReturn(Logger.getGlobal()).when(context).getLogger(); 34 | 35 | // Define the properties of the OutputBinding object. 36 | this.output = new OutputBinding() { 37 | String value; 38 | 39 | @Override 40 | public String getValue() { 41 | return value; 42 | } 43 | 44 | @Override 45 | public void setValue(String value) { 46 | this.value = value; 47 | } 48 | }; 49 | 50 | this.outputAsByteArray = new OutputBinding() { 51 | byte[] value; 52 | 53 | @Override 54 | public byte[] getValue() { 55 | return value; 56 | } 57 | 58 | @Override 59 | public void setValue(byte[] value) { 60 | this.value = value; 61 | } 62 | }; 63 | 64 | // Instantiate the EventHubTriggerFunction class so that we can call its methods. 65 | this.eventHubTriggerFunction = new EventHubTriggerFunction(); 66 | } 67 | 68 | @Test 69 | public void testEventHubTriggerAndOutputJSONJava() throws Exception { 70 | List messages = new ArrayList<>(); 71 | for(int i = 0; i < 3; ++i) { 72 | messages.add("Message" + i); 73 | } 74 | 75 | eventHubTriggerFunction.EventHubTriggerAndOutputJSON(messages, output, context); 76 | 77 | assertEquals(messages.get(0), output.getValue()); 78 | } 79 | 80 | @Test 81 | public void testEventHubTriggerAndOutputStringJava() throws Exception { 82 | EventHubTriggerFunction.SystemProperty[] systemPropertiesArray; 83 | String[] messages = new String[4]; 84 | List systemPropertyList = new ArrayList<>(); 85 | 86 | for(int i = 0; i < 3; ++i) { 87 | messages[i] = "Message" + i; 88 | EventHubTriggerFunction.SystemProperty systemProperty = new EventHubTriggerFunction.SystemProperty("Sequence Number: " + i, 89 | "Offset: " + (i * 2), 90 | "Partition Key: " + (i * 3), 91 | "EnqueuedTimeUtc: " + Instant.now()); 92 | 93 | systemPropertyList.add(systemProperty); 94 | } 95 | 96 | systemPropertiesArray = systemPropertyList.toArray(new EventHubTriggerFunction.SystemProperty[0]); 97 | 98 | eventHubTriggerFunction.EventHubTriggerAndOutputString(messages, systemPropertiesArray, output, context); 99 | 100 | assertEquals(messages[0], output.getValue()); 101 | } 102 | 103 | @Test 104 | public void testEventHubTriggerCardinalityOneJava() throws Exception { 105 | String message = "Hello World!"; 106 | 107 | eventHubTriggerFunction.EventHubTriggerCardinalityOne(message, output, context); 108 | 109 | assertEquals(message, output.getValue()); 110 | } 111 | 112 | @Test 113 | public void testEventHubTriggerAndOutputBinaryCardinalityManyListBinaryJava() throws Exception { 114 | String message = "Hello World!"; 115 | byte[] messageAsByteArray = message.getBytes(StandardCharsets.UTF_8); 116 | 117 | List messageByteArrayList = new ArrayList<>(); 118 | messageByteArrayList.add(messageAsByteArray); 119 | 120 | eventHubTriggerFunction.EventHubTriggerAndOutputBinaryCardinalityManyListBinary(messageByteArrayList, outputAsByteArray, context); 121 | 122 | assertEquals(messageByteArrayList.get(0), outputAsByteArray.getValue()); 123 | } 124 | 125 | @Test 126 | public void testEventHubTriggerAndOutputBinaryCardinalityOneJava() throws Exception { 127 | String message = "Hello World!"; 128 | byte[] messageAsByteArray = message.getBytes(StandardCharsets.UTF_8); 129 | 130 | eventHubTriggerFunction.EventHubTriggerAndOutputBinaryCardinalityOne(messageAsByteArray, outputAsByteArray, context); 131 | 132 | assertEquals(messageAsByteArray, outputAsByteArray.getValue()); 133 | } 134 | 135 | @Test 136 | public void testEventHubTriggerAndOutputBinaryCardinalityManyArrayBinaryJava() throws Exception { 137 | byte[][] twoDimensionalByteArray = new byte[2][2]; 138 | 139 | eventHubTriggerFunction.EventHubTriggerAndOutputBinaryCardinalityManyArrayBinary(twoDimensionalByteArray, outputAsByteArray, context); 140 | 141 | assertEquals(twoDimensionalByteArray[0], outputAsByteArray.getValue()); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /triggers-bindings/src/test/java/com/functions/FunctionTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for 4 | * license information. 5 | */ 6 | package com.functions; 7 | 8 | import com.microsoft.azure.functions.*; 9 | import org.mockito.invocation.InvocationOnMock; 10 | import org.mockito.stubbing.Answer; 11 | 12 | import java.util.*; 13 | import java.util.logging.Logger; 14 | 15 | import org.junit.jupiter.api.Test; 16 | import static org.junit.jupiter.api.Assertions.*; 17 | import static org.mockito.ArgumentMatchers.*; 18 | import static org.mockito.Mockito.*; 19 | 20 | 21 | /** 22 | * Unit test for Function class. 23 | */ 24 | public class FunctionTest { 25 | /** 26 | * Unit test for HttpTriggerJava method. 27 | */ 28 | @Test 29 | public void testHttpTriggerJava() throws Exception { 30 | // Setup 31 | @SuppressWarnings("unchecked") 32 | final HttpRequestMessage> req = mock(HttpRequestMessage.class); 33 | 34 | final Map queryParams = new HashMap<>(); 35 | queryParams.put("name", "Azure"); 36 | doReturn(queryParams).when(req).getQueryParameters(); 37 | 38 | final Optional queryBody = Optional.empty(); 39 | doReturn(queryBody).when(req).getBody(); 40 | 41 | doAnswer(new Answer() { 42 | @Override 43 | public HttpResponseMessage.Builder answer(InvocationOnMock invocation) { 44 | HttpStatus status = (HttpStatus) invocation.getArguments()[0]; 45 | return new HttpResponseMessageMock.HttpResponseMessageBuilderMock().status(status); 46 | } 47 | }).when(req).createResponseBuilder(any(HttpStatus.class)); 48 | 49 | final ExecutionContext context = mock(ExecutionContext.class); 50 | doReturn(Logger.getGlobal()).when(context).getLogger(); 51 | 52 | // Invoke 53 | final HttpResponseMessage ret = new Function().run(req, context); 54 | 55 | // Verify 56 | assertEquals(ret.getStatus(), HttpStatus.OK); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /triggers-bindings/src/test/java/com/functions/HttpResponseMessageMock.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for 4 | * license information. 5 | */ 6 | package com.functions; 7 | 8 | import com.microsoft.azure.functions.*; 9 | 10 | import java.util.Map; 11 | import java.util.HashMap; 12 | 13 | /** 14 | * The mock for HttpResponseMessage, can be used in unit tests to verify if the 15 | * returned response by HTTP trigger function is correct or not. 16 | */ 17 | public class HttpResponseMessageMock implements HttpResponseMessage { 18 | private int httpStatusCode; 19 | private HttpStatusType httpStatus; 20 | private Object body; 21 | private Map headers; 22 | 23 | public HttpResponseMessageMock(HttpStatusType status, Map headers, Object body) { 24 | this.httpStatus = status; 25 | this.httpStatusCode = status.value(); 26 | this.headers = headers; 27 | this.body = body; 28 | } 29 | 30 | @Override 31 | public HttpStatusType getStatus() { 32 | return this.httpStatus; 33 | } 34 | 35 | @Override 36 | public int getStatusCode() { 37 | return httpStatusCode; 38 | } 39 | 40 | @Override 41 | public String getHeader(String key) { 42 | return this.headers.get(key); 43 | } 44 | 45 | @Override 46 | public Object getBody() { 47 | return this.body; 48 | } 49 | 50 | public static class HttpResponseMessageBuilderMock implements HttpResponseMessage.Builder { 51 | private Object body; 52 | private int httpStatusCode; 53 | private Map headers = new HashMap<>(); 54 | private HttpStatusType httpStatus; 55 | 56 | public Builder status(HttpStatus status) { 57 | this.httpStatusCode = status.value(); 58 | this.httpStatus = status; 59 | return this; 60 | } 61 | 62 | @Override 63 | public Builder status(HttpStatusType httpStatusType) { 64 | this.httpStatusCode = httpStatusType.value(); 65 | this.httpStatus = httpStatusType; 66 | return this; 67 | } 68 | 69 | @Override 70 | public HttpResponseMessage.Builder header(String key, String value) { 71 | this.headers.put(key, value); 72 | return this; 73 | } 74 | 75 | @Override 76 | public HttpResponseMessage.Builder body(Object body) { 77 | this.body = body; 78 | return this; 79 | } 80 | 81 | @Override 82 | public HttpResponseMessage build() { 83 | return new HttpResponseMessageMock(this.httpStatus, this.headers, this.body); 84 | } 85 | } 86 | } 87 | --------------------------------------------------------------------------------