Skip to content

Commit

Permalink
Add a more sophisicated binding resolving architecture and algorithm (A…
Browse files Browse the repository at this point in the history
…zure#13)

* Re-format some of the the source code.

* Adopt the new architecture of binding data resolution.

* Update the annotation names and name resolution algorithm.
  • Loading branch information
Junyi Yi authored Sep 16, 2017
1 parent 406df1d commit 1750ea5
Show file tree
Hide file tree
Showing 40 changed files with 1,001 additions and 650 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,19 @@ Our version strategy just follows the maven package version convention: `<major>
6. New features are added to `1.1-SNAPSHOT`.

Every time you release a non-development version (like `1.0.0-ALPHA` or `1.0.1`), you also need to update the tag in your git repository.

# Advanced Java Concepts

## Reflection for Type

Primitives have two different type definitions, for example: `int.class` (which is identical to `Integer.TYPE`) is not `Integer.class`.

All Java types are represented by `Type` interface, which may be one of the following implementations:
* `Class<?>`: normal class type like `String`
* `ParameterizedType`: generic class type like `List<Integer>`
* `WildcardType`: generic argument contains question mark like `? extends Number`
* `TypeVariable<?>`: generic argument like `T`
* `GenericArrayType`: generic array like `T[]`

For the generic type behaviors (including compile-time validation and runtime type erasure) in Java, please refer to *[Generics in the Java Programming Language
](https://www.cs.rice.edu/~cork/312/Readings/GenericsTutorial.pdf)*.
4 changes: 2 additions & 2 deletions azure-functions-java-core/pom.xml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.microsoft.azure.serverless</groupId>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-functions-java-core</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<version>1.1-SNAPSHOT</version>
<url>http://maven.apache.org</url>

<properties>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ public interface HttpRequestMessage {
Map<String, String> getHeaders();
Map<String, String> getQueryParameters();
Object getBody();

HttpResponseMessage createResponse();
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,8 @@
package com.microsoft.azure.serverless.functions;

public final class HttpResponseMessage {
public HttpResponseMessage(int status) {
this(status, null);
}

public HttpResponseMessage(Object body) {
this(200, body);
}

public HttpResponseMessage(int status, Object body) {
this.status = status;
this.body = (body != null ? body : "");
}

public Integer getStatus() { return this.status; }
public Object getBody() { return this.body; }

private int status;
private Object body;
public interface HttpResponseMessage {
int getStatus();
void setStatus(int status);
Object getBody();
void setBody(Object body);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.microsoft.azure.serverless.functions;

public interface OutputBinding<T> {
T getValue();
void setValue(T value);
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for
* license information.
*/

package com.microsoft.azure.serverless.functions.annotation;

public enum AccessRights {
MANAGE,
LISTEN
}
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for
* license information.
*/

package com.microsoft.azure.serverless.functions.annotation;

public enum AccessRights {
MANAGE,
LISTEN
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for
* license information.
*/

package com.microsoft.azure.serverless.functions.annotation;

public enum AuthorizationLevel {
ANONYMOUS,
FUNCTION,
ADMIN
}
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for
* license information.
*/

package com.microsoft.azure.serverless.functions.annotation;

public enum AuthorizationLevel {
ANONYMOUS,
FUNCTION,
ADMIN
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface Bind {
public @interface BindingName {
String value();
}
4 changes: 2 additions & 2 deletions azure-functions-java-sample/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>com.microsoft.azure.serverless</groupId>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-functions-java-core</artifactId>
<version>1.0-SNAPSHOT</version>
<version>1.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
Expand Down
18 changes: 18 additions & 0 deletions azure-functions-java-sample/src/main/functions/echo/function.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"scriptFile": "../../../../target/azure-functions-java-sample-1.0-SNAPSHOT.jar",
"entryPoint": "com.microsoft.serverless.Miscellany.echo",
"bindings": [
{
"type": "httpTrigger",
"name": "req",
"direction": "in",
"authLevel": "anonymous",
"methods": [ "get", "post" ]
},
{
"type": "http",
"name": "$return",
"direction": "out"
}
]
}
Original file line number Diff line number Diff line change
@@ -1,43 +1,40 @@
package com.microsoft.serverless;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.microsoft.azure.serverless.functions.ExecutionContext;
import com.microsoft.azure.serverless.functions.HttpRequestMessage;
import com.microsoft.azure.serverless.functions.HttpResponseMessage;
import com.microsoft.azure.serverless.functions.OutputParameter;
import com.microsoft.azure.serverless.functions.annotation.Bind;
import com.microsoft.azure.serverless.functions.OutputBinding;
import com.microsoft.azure.serverless.functions.annotation.BindingName;

public class Miscellany {
public static String echo(String body, @Bind("message") OutputParameter<String> message) {
String result = String.format("Hello, %s!", (body != null && !body.isEmpty() ? body : "[Unnamed]"));
message.setValue(String.format("%s [generated at %2$tD %2$tT, by echo]", result, new Date()));
return result;
public static HttpResponseMessage echo(HttpRequestMessage request) {
HttpResponseMessage response = request.createResponse();
response.setStatus(202);
response.setBody(echo(request.getBody().toString()));
return response;
}

public static String echo(@Bind("name") String param, String body, @Bind("message") OutputParameter<String> message) {
List<String> targets = new ArrayList<>();
if (param != null && !param.isEmpty()) { targets.add(param); }
if (body != null && !body.isEmpty()) { targets.add(body); }
return echo(String.join(" and ", targets), message);
public static String echo(@BindingName("name") String content) {
return "Hello " + content + "!";
}

public static String heartbeat(ExecutionContext context) {
context.getLogger().info("Java Timer Trigger Function Executed.");
return String.format("I'm still alive :) [generated at %1$tD %1$tT, by heartbeat]", new Date());
}

public static HttpResponseMessage upload(byte[] data) {
return new HttpResponseMessage(202, data.length + " bytes");
public static String upload(byte[] data) {
return data.length + " bytes";
}

public static String listMessages(@Bind("storage") String storage, @Bind("result") OutputParameter<String[]> result) {
public static String listMessages(@BindingName("storage") String storage, @BindingName("result") OutputBinding<String[]> result) {
result.setValue(storage.split("\n"));
return String.format("[Last consumed at %1$tD %1$tT]", new Date());
}

public static String handleMessage(@Bind("message") String message, @Bind("storage") String storage) {
public static String handleMessage(@BindingName("message") String message, @BindingName("storage") String storage) {
message = String.format("%s [handled at %2$tD %2$tT]", message, new Date());
return storage + "\n" + message;
}
Expand Down
8 changes: 4 additions & 4 deletions azure-functions-java-worker/pom.xml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.microsoft.azure.serverless</groupId>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-functions-java-worker</artifactId>
<version>1.0-SNAPSHOT</version>
<version>1.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>Microsoft Azure Functions Java Runtime</name>
Expand All @@ -19,9 +19,9 @@

<dependencies>
<dependency>
<groupId>com.microsoft.azure.serverless</groupId>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-functions-java-core</artifactId>
<version>1.0-SNAPSHOT</version>
<version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ private Application(String[] args) {
}

public String getHost() { return this.host; }
public int getPort() { return this.port; }
public String getWorkerId() { return this.workerId; }
public String getRequestId() { return this.requestId; }
public boolean logToConsole() { return this.logToConsole; }
int getPort() { return this.port; }
private String getWorkerId() { return this.workerId; }
private String getRequestId() { return this.requestId; }
boolean logToConsole() { return this.logToConsole; }

private void printUsage() {
HelpFormatter formatter = new HelpFormatter();
Expand Down Expand Up @@ -71,43 +71,34 @@ private int parsePort(String input) throws ParseException {
private boolean logToConsole;

private final Options OPTIONS = new Options()
.addOption(Option.builder("h")
.longOpt("host")
.hasArg()
.argName("HostName")
.desc("The address of the machine that the webjobs host is running on")
.addOption(Option.builder("h").longOpt("host")
.hasArg().argName("HostName")
.desc("The address of the machine that the Azure Functions host is running on")
.required()
.build())
.addOption(Option.builder("p")
.longOpt("port")
.hasArg()
.argName("PortNumber")
.desc("The port number which the webjobs host is listening to")
.addOption(Option.builder("p").longOpt("port")
.hasArg().argName("PortNumber")
.desc("The port number which the Azure Functions host is listening to")
.required()
.build())
.addOption(Option.builder("w")
.longOpt("workerId")
.hasArg()
.argName("WorkerId")
.desc("The ID of this running worker of throughout communication session")
.addOption(Option.builder("w").longOpt("workerId")
.hasArg().argName("WorkerId")
.desc("The ID of this running worker throughout communication session")
.required()
.build())
.addOption(Option.builder("q")
.longOpt("requestId")
.hasArg()
.argName("RequestId")
.desc("The request ID of this communication session")
.addOption(Option.builder("q").longOpt("requestId")
.hasArg().argName("RequestId")
.desc("The startup request ID of this communication session")
.required()
.build())
.addOption(Option.builder("l")
.longOpt("consoleLog")
.desc("Duplicate all host logs to console")
.addOption(Option.builder("l").longOpt("consoleLog")
.desc("Whether to duplicate all host logs to console as well")
.build());


public static void main(String[] args) throws IOException {
System.out.println("Microsoft Azure Functions Java Runtime [build " + version() + "]");
Application app = new Application(args);

if (!app.isCommandlineValid()) {
app.printUsage();
System.exit(1);
Expand All @@ -123,6 +114,6 @@ public static void main(String[] args) throws IOException {

public static String version() {
String jarVersion = Application.class.getPackage().getImplementationVersion();
return jarVersion != null ? jarVersion : "Unknown";
return jarVersion != null && !jarVersion.isEmpty() ? jarVersion : "Unknown";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,13 @@ public static <TSource, TResult> List<TResult> mapOptional(Iterable<TSource> sou
return result;
}

public static <TSource, TResult> Optional<TResult> single(Iterable<TSource> source, Function<TSource, Optional<TResult>> convert) {
int count = 0;
Optional<TResult> result = Optional.empty();
public static <TSource, TResult> List<TResult> take(Iterable<TSource> source, int max, Function<TSource, Optional<TResult>> convert) {
List<TResult> result = new ArrayList<>();
for (TSource item : source) {
Optional<TResult> convertedItem = convert.apply(item);
if (convertedItem.isPresent()) {
result = convertedItem;
if (++count >= 2) { return Optional.empty(); }
result.add(convertedItem.get());
if (result.size() >= max) { break; }
}
}
return result;
Expand Down
Loading

0 comments on commit 1750ea5

Please sign in to comment.