Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Java Tender Loving Care #3

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions java11/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@
/model/repos
/entrypoint/repos

build
52 changes: 52 additions & 0 deletions java11/README.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
= OpenFaas Java

This project builds Java libraries and modules used by OpenFaas.

This project uses https://gradle.org/[Gradle] build tool.

This project publishes java libraries to https://search.maven.org/[Maven Central].

The libraries are used by the https://github.com/openfaas/templates[OpenFaas Java templates].

You will use these libraries as dependencies when building your functions.

== Contributions to this project

The project uses https://github.com/diffplug/spotless/tree/main/plugin-gradle#java[gradle-spotless-plugin] to take care of checking and formatting the source code.
This ensures that contributions are always formatted in the same way.
It also ensures files contain the proper license header.

This is a https://docs.gradle.org/current/userguide/multi_project_builds.html[Multi-Project Gradle build] .
It means we have multiple libraries published from this project.

We use https://docs.gradle.org/current/userguide/publishing_maven.html[maven-publish] plugin to publish the libraries.

== Making a release

Releases are published to Maven Central.
See https://issues.sonatype.org/browse/OSSRH-48617 and https://central.sonatype.org/pages/ossrh-guide.html .

All of the release and publish steps are done by gradle.
You will have to have write access to the staging repository and aprove the release.

You will have to pass the release property: `./gradlew clean build -Prelease` .
That will enable the tasks in the build responsible for publishing.

You will also have to provide valid credentials via `ossrhUsername` and `ossrhPassword` .

Publishing requires signing the artifacts and you will need to configure a https://docs.gradle.org/current/userguide/signing_plugin.html#sec:signatory_credentials[signatory]
You can avoid the signing process by excluding the task `./gradlew build -x sign` .

To configure a signatory you will need to add some properties to your `~/.gradle/gradle.properties` file .

You will need to provide values for the properties defined in the `build.gradle` file:

[source,groovy]
----
signing {
def signingKeyId = findProperty("openfaas.signingKeyId")
def signingKey = findProperty("openfaas.signingKey")
def signingPassword = findProperty("openfaas.signingPassword")
// ...
}
----
33 changes: 33 additions & 0 deletions java11/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
plugins {
id "com.diffplug.spotless" version "5.1.0"
}

allprojects {
group = 'com.openfaas'
}

spotless {
format 'misc', {
// define the files to apply `misc` to
target '*.gradle', '*/*.gradle', '*.md', '.gitignore'

// define the steps to apply to those files
trimTrailingWhitespace()
indentWithSpaces(2) // or spaces. Takes an integer argument if you don't like 4
endWithNewline()
}
java {
// don't need to set target, it is inferred from java
target '**/src/*/java/**/*.java'

importOrder()
removeUnusedImports()

// apply a specific flavor of google-java-format
googleJavaFormat('1.8').aosp()
// make sure every file has the following copyright header.
// optionally, Spotless can set copyright years by digging
// through git history (see "license" section below)
licenseHeader "// Copyright (c) OpenFaaS Author(s) 2018. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n"
}
}
135 changes: 67 additions & 68 deletions java11/entrypoint/build.gradle
Original file line number Diff line number Diff line change
@@ -1,99 +1,98 @@
buildscript {
group = 'com.openfaas'
version = '0.1.0'
}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexellis : We don't need to setup these inside a buildscript.
One way of configuring common options is to use allprojects and subprojects .

https://docs.gradle.org/current/dsl/org.gradle.api.Project.html#org.gradle.api.Project:allprojects(groovy.lang.Closure)


plugins {
id 'java'
id 'application'
id 'maven'
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexellis : maven plugin is deprecated an being removed. maven-publish is the right way to go.
https://docs.gradle.org/current/userguide/maven_plugin.html#header

id 'signing'
id 'java-library'
id 'maven-publish'
id 'signing'
}

signing {
sign configurations.archives
}
description = 'OpenFaaS Function entry point'
version = '0.1.0'

task javadocJar(type: Jar) {
classifier = 'javadoc'
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This way of adding a javadoc and sources jars are also deprecated .
Using an IDE with intellisense will notify you that the classifier is deprecated.

https://docs.gradle.org/current/userguide/publishing_maven.html#publishing_maven:complete_example

from javadoc
}
dependencies {
api project(':model')

task sourcesJar(type: Jar) {
classifier = 'sources'
from sourceSets.main.allSource
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.6.0'
}

mainClassName = 'App'

dependencies {
compile 'com.google.guava:guava:23.0'
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Guava is not used in any of the code here.
Why is it a dependency of the project?
I removed it.

Also, compile is deprecated in favor of other configurations:
https://docs.gradle.org/current/userguide/java_plugin.html#tab:configurations

compile(Deprecated)
Compile time dependencies. Superseded by implementation.

testCompile 'junit:junit:4.12'
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

junit 5 is better and since we don't have legacy tests why not use it.
https://junit.org/junit5/

compile 'com.openfaas:model:0.1.1'
test {
useJUnitPlatform()
}

java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
jar {
manifest {
attributes 'Implementation-Title': 'OpenFaaS Function',
'Implementation-Version': project.version
}
}

repositories {
jcenter()

flatDir {
dirs 'libs'
}
jcenter()
}

artifacts {
archives javadocJar, sourcesJar
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
withJavadocJar()
withSourcesJar()
}

uploadArchives {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uploadArchives is deprecated and is going to be removed.
It also has some downsides.

uploadArchives — Upload

Uploads artifacts in the archives configuration — including the production JAR file — to the configured repositories. > This task is deprecated, you should use one of the Ivy or Maven publishing plugins instead.

https://docs.gradle.org/current/userguide/java_plugin.html#sec:java_tasks

repositories {
flatDir {
dirs 'repos'
}

mavenDeployer {
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }

repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
authentication(userName: ossrhUsername, password: ossrhPassword)
}

snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") {
authentication(userName: ossrhUsername, password: ossrhPassword)
}
publishing {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the new and recommended way of publishing artifacts with gradle.
I've added all the information you had in uploadArchives.

It should work but I haven't publish anything yet.
It might require some small changes for signing.

publications {
mavenJava(MavenPublication) {
from components.java

pom.project {
name 'OpenFaaS model'
packaging 'jar'
// optionally artifactId can be defined here
description 'OpenFaaS Model for function invocations.'
url 'http://www.openfaas.com/'

scm {
connection 'scm:git:https://github.com/openfaas/templates'
developerConnection 'scm:git:https://github.com/openfaas/templates'
url 'https://github.com/openfaas/templates'
}
pom {
url = 'http://www.openfaas.com/'
description = 'OpenFaaS Function.'

licenses {
license {
name 'MIT'
url 'https://opensource.org/licenses/MIT'
name = 'MIT'
url = 'https://opensource.org/licenses/MIT'
}
}

scm {
connection = 'scm:git:https://github.com/openfaas/templates-sdk.git'
developerConnection = 'scm:git:https://github.com/openfaas/templates-sdk.git'
url = 'https://github.com/openfaas/templates-sdk/'
}
developers {
developer {
id 'openfaas'
name 'OpenFaaS Ltd'
email '[email protected]'
id = 'openfaas'
name = 'OpenFaaS Ltd'
email = '[email protected]'
}
}
}
}
}
repositories {
maven {
def releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
def snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots/"

url = project.hasProperty('release') ? releasesRepoUrl : snapshotsRepoUrl

credentials(PasswordCredentials) {
username = project.hasProperty('ossrhUsername') ? ossrhUsername : null;
password = project.hasProperty('ossrhPassword')? ossrhPassword : null;
}
}
}
}

signing {
def signingKeyId = findProperty("openfaas.signingKeyId")
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated this according to the documentation
https://docs.gradle.org/current/userguide/signing_plugin.html#header

def signingKey = findProperty("openfaas.signingKey")
def signingPassword = findProperty("openfaas.signingPassword")
useInMemoryPgpKeys(signingKeyId, signingKey, signingPassword)

sign publishing.publications.mavenJava
}

javadoc {
if(JavaVersion.current().isJava9Compatible()) {
options.addBooleanOption('html5', true)
}
}
10 changes: 0 additions & 10 deletions java11/entrypoint/settings.gradle

This file was deleted.

34 changes: 18 additions & 16 deletions java11/entrypoint/src/main/java/com/openfaas/entrypoint/App.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
// Copyright (c) OpenFaaS Author(s) 2018. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

package com.openfaas.entrypoint;

import com.openfaas.model.*;
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Star imports are not recommended in Java because they hide dependency on classes.

import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.io.OutputStream;
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code has been formatted wit spotless plugin.
https://github.com/diffplug/spotless/tree/main/plugin-gradle .

The plugin runs as part of the build and checks the formatting is consistent according.

All contributions will have a single style - will make code easier to maintain.
People won't depend on IDE's for formatting.

The style is google AOSP (Android OpenSource Project), adopted by many projects, good tooling support https://google.github.io/styleguide/javaguide.html .

Formatting can be done via tooling and the plugin suggests that ./gradlew :sptlessApply .

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;

import java.util.HashMap;
import java.util.Map;
import com.sun.net.httpserver.Headers;

import com.openfaas.model.*;

public class App {

Expand Down Expand Up @@ -56,15 +53,15 @@ public void handle(HttpExchange t) throws IOException {
}
// StandardCharsets.UTF_8.name() > JDK 7
requestBody = result.toString("UTF-8");
}
}

// System.out.println(requestBody);
Headers reqHeaders = t.getRequestHeaders();
Map<String, String> reqHeadersMap = new HashMap<String, String>();

for (Map.Entry<String, java.util.List<String>> header : reqHeaders.entrySet()) {
java.util.List<String> headerValues = header.getValue();
if(headerValues.size() > 0) {
if (headerValues.size() > 0) {
reqHeadersMap.put(header.getKey(), headerValues.get(0));
}
}
Expand All @@ -73,20 +70,25 @@ public void handle(HttpExchange t) throws IOException {
// System.out.println("Req header " + entry.getKey() + " " + entry.getValue());
// }

IRequest req = new Request(requestBody, reqHeadersMap,t.getRequestURI().getRawQuery(), t.getRequestURI().getPath());
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No code has been changed.
Just formatting and build.


IRequest req =
new Request(
requestBody,
reqHeadersMap,
t.getRequestURI().getRawQuery(),
t.getRequestURI().getPath());

IResponse res = this.handler.Handle(req);

String response = res.getBody();
byte[] bytesOut = response.getBytes("UTF-8");

Headers responseHeaders = t.getResponseHeaders();
String contentType = res.getContentType();
if(contentType.length() > 0) {
if (contentType.length() > 0) {
responseHeaders.set("Content-Type", contentType);
}

for(Map.Entry<String, String> entry : res.getHeaders().entrySet()) {
for (Map.Entry<String, String> entry : res.getHeaders().entrySet()) {
responseHeaders.set(entry.getKey(), entry.getValue());
}

Expand All @@ -96,8 +98,8 @@ public void handle(HttpExchange t) throws IOException {
os.write(bytesOut);
os.close();

System.out.println("Request / " + Integer.toString(bytesOut.length) +" bytes written.");
System.out.println(
"Request / " + Integer.toString(bytesOut.length) + " bytes written.");
}
}

}
Original file line number Diff line number Diff line change
@@ -1,32 +1,31 @@
// Copyright (c) OpenFaaS Author(s) 2018. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

package com.openfaas.entrypoint;

import java.util.ServiceLoader;
import com.openfaas.model.*;
import java.util.ServiceLoader;

public class HandlerProvider {
private static HandlerProvider provider;
private ServiceLoader<AbstractHandler> loader;

private HandlerProvider() {
loader = ServiceLoader.load(AbstractHandler.class);
}

public static HandlerProvider getInstance() {
if(provider == null) {
if (provider == null) {
provider = new HandlerProvider();
}
return provider;
}

public AbstractHandler getHandler() {
AbstractHandler service = loader.iterator().next();
if(service != null) {
if (service != null) {
return service;
} else {
throw new java.util.NoSuchElementException(
"No implementation for HandlerProvider");
throw new java.util.NoSuchElementException("No implementation for HandlerProvider");
}
}
}
}
Loading