Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
pragnagopa committed Oct 8, 2018
2 parents 03a663a + 3155e81 commit 68bf858
Show file tree
Hide file tree
Showing 35 changed files with 1,055 additions and 118 deletions.
10 changes: 10 additions & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# CODEOWNERS is a GitHub standard to specify who is automatically assigned pull requests to review.
# This helps to prevent pull requests from languishing without review.
# GitHub can also be configured to require review from code owners before a pull request can be merged.

# Further reading is available from the following two URLs:
# https://blog.github.com/2017-07-06-introducing-code-owners/
# https://help.github.com/articles/about-codeowners/

# Default owner for repo
* @pragnagopa
88 changes: 53 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@
<version>1.0.0-beta-4</version>
# Building Microsoft Azure Functions in Java
# Microsoft Azure Functions API for Java
This project contains the Java API for building functions for the Azure Functions service. Visit the [complete documentation of Azure Functions - Java Developer Guide](https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-java) for more details.

## azure-functions-maven plugin
[How to use azure-functions-maven plugin to create, update, deploy and test azure java functions](https://docs.microsoft.com/en-us/java/api/overview/azure/maven/azure-functions-maven-plugin/readme?view=azure-java-stable)

## Prerequisites

* JDK 8
* Maven
* JAVA_HOME environment variable
* Node
* NPM Azure Functions CLI
* Java 8

## Programming Model
## Summary

Your Azure function should be a stateless method to process input and produce output. Although you are allowed to write instance methods, your function must not depend on any instance fields of the class. You need to make sure all the function methods are `public` accessible.
Azure Functions is capable of running Function Apps that may contain one or more functions grouped. A function should be a stateless method to process input and produce output. Although you are allowed to write instance methods, your function must not depend on any instance fields of the class. You need to make sure all the function methods are `public` accessible.

You can put multiple functions in one single project (or specifically speaking, one single jar). We strongly recommend you **not to** put your functions in separate jars (or `pom.xml`).
A deployable unit is an uber JAR containing one or more functions (see below), and a JSON file with the list of functions and triggers definitions, deployed to Azure Functions. The JAR can be created in many ways, although we recommend the use of the [Azure Functions Maven Plugin](https://docs.microsoft.com/en-us/java/api/overview/azure/maven/azure-functions-maven-plugin/readme), which also generates the JSON file for you automatically.

Typically an Azure function is invoked because of one trigger. Your function needs to process that trigger (sometimes with additional inputs) and gives one or more output values.
Typically a function is invoked because of a trigger. Your function needs to process that trigger (sometimes with additional inputs) and provide an optional output.

All the input and output bindings can be defined in `function.json` (not recommended), or in the Java method by using annotations (recommended). All the types and annotations used in this document are included in the `azure-functions-java-library` package.

Here is an example for a simple Azure function written in Java:
### Sample

```Java
Here is an example of a HttpTrigger Azure function in Java:


```java
package com.example;

import com.microsoft.azure.functions.annotation.*;
Expand All @@ -34,22 +36,24 @@ public class MyClass {
}
```

### Including 3rd Party Libraries
### Adding 3rd Party Libraries

Azure Functions supports the use of 3rd party libraries. By default, all dependencies specified in your project pom.xml file will be automatically bundled during the `mvn package` step. For libraries that are not specified as dependencies in the pom.xml file, you may place them in a `lib` directory in the function's root directory. These will then be deployed as part of your functions application. All dependencies that are placed in the `lib` directory will be added to the system class loader at runtime.
Azure Functions supports the use of 3rd party libraries. If using the Maven plugin for Azure Functions, all of your dependencies specified in your `pom.xml` file will be automatically bundled during the `mvn package` step.

## General Data Types
## Data Types

You are free to use all the data types in Java for the input and output data, including native types; customized POJO types and specialized Azure types defined in `azure-functions-java-library` package. And Azure Functions runtime will try its best to convert the actual input value to the type you need (for example, a `String` input will be treated as a JSON string and be parsed to a POJO type defined in your code).
You are free to use all the data types in Java for the input and output data, including native types; customized POJO types and specialized Azure types defined in this API. Azure Functions runtime will try its best to convert the actual input value to the type you need (for example, a `String` input will be treated as a JSON string and be parsed to a POJO type defined in your code).

The POJO types you defined have the same accessible requirements as the function methods, it needs to be `public` accessible. While the POJO class fields are not; for example a JSON string `{ "x": 3 }` is able to be converted to the following POJO type:
### JSON Support
The POJO types (Java classes) you may define have to be publicly accessible (`public` modifier). POJO properties/fields may be `private`. For example a JSON string `{ "x": 3 }` is able to be converted to the following POJO type:

```Java
```java
public class MyData {
private int x;
}
```

### Other supported types
Binary data is represented as `byte[]` or `Byte[]` in your Azure functions code. And make sure you specify `dataType = "binary"` in the corresponding triggers/bindings.

Empty input values could be `null` as your functions argument, but a recommended way to deal with potential empty values is to use `Optional<T>` type.
Expand All @@ -61,29 +65,44 @@ Inputs are divided into two categories in Azure Functions: one is the trigger in

Let's take the following code snippet as an example:

```Java
```java
package com.example;

import com.microsoft.azure.functions.annotation.*;

public class MyClass {
@FunctionName("echo")
public static String echo(
public String echo(
@HttpTrigger(name = "req", methods = { "put" }, authLevel = AuthorizationLevel.ANONYMOUS, route = "items/{id}") String in,
@TableInput(name = "item", tableName = "items", partitionKey = "Example", rowKey = "{id}", connection = "AzureWebJobsStorage") MyObject obj
@TableInput(name = "item", tableName = "items", partitionKey = "example", rowKey = "{id}", connection = "AzureWebJobsStorage") MyObject obj
) {
return "Hello, " + in + " and " + obj.getKey() + ".";
return "Hello, " + in + " and " + obj.getRowKey() + ".";
}

public static class MyObject {
public String getKey() { return this.RowKey; }
private String RowKey;
}
}

public class MyObject {
public String getRowKey() { return this.rowKey; }
private String rowKey;
}

```

When this function is invoked, the HTTP request payload will be passed as the `String` for argument `in`; and one entry will be retrieved from the Azure Table Storage and be passed to argument `obj` as `MyObject` type.

To receive events in a batch when using EventHubTrigger, set cardinality to many and change input type to List<>

```Java
@FunctionName("ProcessIotMessages")
public void processIotMessages(
@EventHubTrigger(name = "message", eventHubName = "%AzureWebJobsEventHubPath%", connection = "AzureWebJobsEventHubSender", cardinality = Cardinality.MANY) List<String> messages,
final ExecutionContext context)
{
context.getLogger().info("Java Event Hub trigger received messages. Batch size: " + messages.size());
}

```

## Outputs

Outputs can be expressed in return value or output parameters. If there is only one output, you are recommended to use the return value. For multiple outputs, you have to use **output parameters**.
Expand All @@ -92,7 +111,7 @@ Return value is the simplest form of output, you just return the value of any ty

For example, a blob content copying function could be defined as the following code. `@StorageAccount` annotation is used here to prevent the duplicating of the `connection` property for both `@BlobTrigger` and `@BlobOutput`.

```Java
```java
package com.example;

import com.microsoft.azure.functions.annotation.*;
Expand All @@ -101,23 +120,23 @@ public class MyClass {
@FunctionName("copy")
@StorageAccount("AzureWebJobsStorage")
@BlobOutput(name = "$return", path = "samples-output-java/{name}")
public static String copy(@BlobTrigger(name = "blob", path = "samples-input-java/{name}") String content) {
public String copy(@BlobTrigger(name = "blob", path = "samples-input-java/{name}") String content) {
return content;
}
}
```

To produce multiple output values, use `OutputBinding<T>` type defined in the `azure-functions-java-library` package. If you need to make an HTTP response and push a message to a queue, you can write something like:

```Java
```java
package com.example;

import com.microsoft.azure.functions.*;
import com.microsoft.azure.functions.annotation.*;

public class MyClass {
@FunctionName("push")
public static String push(
public String push(
@HttpTrigger(name = "req", methods = { "post" }, authLevel = AuthorizationLevel.ANONYMOUS) String body,
@QueueOutput(name = "message", queueName = "myqueue", connection = "AzureWebJobsStorage") OutputBinding<String> queue
) {
Expand All @@ -127,16 +146,15 @@ public class MyClass {
}
```

Of course you could use `OutputBinding<byte[]>` type to make a binary output value (for parameters); for return values, just use `byte[]`.

Use `OutputBinding<byte[]>` type to make a binary output value (for parameters); for return values, just use `byte[]`.

## Execution Context

You interact with Azure Functions execution environment via the `ExecutionContext` object defined in the `azure-functions-java-library` package. You are able to get the invocation ID, the function name and a built-in logger (which is integrated prefectly with Azure Function Portal experience as well as AppInsights) from the context object.

What you need to do is just add one more `ExecutionContext` typed parameter to your function method. Let's take a timer triggered function as an example:

```Java
```java
package com.example;

import com.microsoft.azure.functions.*;
Expand Down Expand Up @@ -192,4 +210,4 @@ public class MyClass {

This project is under the benevolent umbrella of the [.NET Foundation](http://www.dotnetfoundation.org/) and is licensed under [the MIT License](LICENSE.txt)

This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.microsoft.azure.functions</groupId>
<artifactId>azure-functions-java-library</artifactId>
<version>1.0.0-beta-5</version>
<version>1.0.0-beta-6</version>
<packaging>jar</packaging>

<name>Microsoft Azure Functions Java Core Types</name>
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/com/microsoft/azure/functions/OutputBinding.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
package com.microsoft.azure.functions;

/**
* <p>This type should be used with the parameter of output bindings.</p>
*
* @since 1.0.0
*/
public interface OutputBinding<T> {
/**
* Get the value to be passed to the output binding.
* @return The actual value to be passed to the output binding.
*/
T getValue();

/**
* Set the value to be passed to the output binding.
* @param value The actual value to be passed to the output binding.
*/
void setValue(T value);
}
32 changes: 0 additions & 32 deletions src/main/java/com/microsoft/azure/functions/WebHookType.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,18 @@
package com.microsoft.azure.functions.annotation;

/**
* Azure Service Bus permission.
*
* @since 1.0.0
*/
public enum AccessRights {
/**
* Confers the right to manage the topology of the namespace, including creating and deleting entities.
*/
MANAGE,

/**
* Confers the right to listen (relay) or receive (queue, subscriptions) and all related message handling.
*/
LISTEN
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,24 @@
package com.microsoft.azure.functions.annotation;

/**
* <p>Azure HTTP authorization level, Determines what keys, if any, need to be present on the request in order to
* invoke the function.</p>
*
* @since 1.0.0
*/
public enum AuthorizationLevel {
/**
* No API key is required.
*/
ANONYMOUS,

/**
* A function-specific API key is required. This is the default value if none is provided.
*/
FUNCTION,

/**
* The master key is required.
*/
ADMIN
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,18 @@
import java.lang.annotation.Target;

/**
* <p>Place this on a parameter whose value would come from Azure Functions runtime.
* Use this annotation when you want to get the value of trigger metadata, or when you defined your own bindings in
* function.json manually.</p>
*
* @since 1.0.0
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface BindingName {
/**
* Defines the trigger metadata name or binding name defined in function.json.
* @return The trigger metadata name or binding name.
*/
String value();
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,62 @@
import java.lang.annotation.Target;

/**
* <p>Place this on a parameter whose value would come from a blob. The parameter type can be one of the following:</p>
*
* <ul>
* <li>Any native Java types such as int, String, byte[]</li>
* <li>Nullable values using Optional&lt;T&gt;</li>
* <li>Any POJO type</li>
* </ul>
*
* <p>The following example is a Java function that uses a queue trigger and an input blob binding. The queue message
* contains the name of the blob, and the function logs the size of the blob.</p>
*
* <pre>{@literal @}FunctionName("getBlobSize")
*{@literal @}StorageAccount("AzureWebJobsStorage")
* public void blobSize(
* {@literal @}QueueTrigger(name = "filename",
* queueName = "myqueue-items") String filename,
* {@literal @}BlobInput(name = "file",
* dataType = "binary",
* path = "samples-workitems/{queueTrigger}") byte[] content,
* final ExecutionContext context
* ) {
* context.getLogger().info("The size of \"" + filename + "\" is: " + content.length + " bytes");
* }</pre>
*
*
* @since 1.0.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface BlobInput {
/**
* The variable name used in function.json.
* @return The variable name used in function.json.
*/
String name();

/**
* <p>Defines how Functions runtime should treat the parameter value. Possible values are:</p>
* <ul>
* <li>"": get the value as a string, and try to deserialize to actual parameter type like POJO</li>
* <li>string: always get the value as a string</li>
* <li>binary: get the value as a binary data, and try to deserialize to actual parameter type byte[]</li>
* </ul>
* @return The dataType which will be used by the Functions runtime.
*/
String dataType() default "";

/**
* Defines the path of the blob to which to bind.
* @return The blob path string.
*/
String path();

/**
* Defines the app setting name that contains the Azure Storage connection string.
* @return The app setting name of the connection string.
*/
String connection() default "";
}
Loading

0 comments on commit 68bf858

Please sign in to comment.