Skip to content

Commit 783f697

Browse files
authored
Merge pull request #337 from overture-stack/develop
Update master to latest develop.
2 parents dd78b99 + bd2334b commit 783f697

File tree

300 files changed

+20724
-7523
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

300 files changed

+20724
-7523
lines changed

Diff for: .circleci/config.yml

+42-6
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,16 @@ jobs:
1717
# Download and cache dependencies
1818
- restore_cache:
1919
keys:
20-
- v1-dependencies-{{ checksum "pom.xml" }}
20+
- v2-dependencies-{{ checksum "pom.xml" }}
2121
# fallback to using the latest cache if no exact match is found
22-
- v1-dependencies-
22+
- v2-dependencies-
2323
- run:
2424
name: Fetch Maven Dependencies
2525
command: mvn dependency:go-offline
2626
- save_cache:
2727
paths:
2828
- ~/.m2
29-
key: v1-dependencies-{{ checksum "pom.xml" }}
29+
key: v2-dependencies-{{ checksum "pom.xml" }}
3030

3131
# Run Tests
3232
- run:
@@ -35,6 +35,36 @@ jobs:
3535
mvn test \
3636
-D spring.profiles.active=test
3737
38+
build-docker-image:
39+
machine: true
40+
41+
steps:
42+
- checkout
43+
44+
- run: docker login -u $DOCKER_USER -p $DOCKER_PASS
45+
46+
- run: docker build -f Dockerfile.prod . -t overture/ego:$(git describe --always)-alpine
47+
48+
- run: docker push overture/ego:$(git describe --always)-alpine
49+
50+
deploy-staging:
51+
machine: true
52+
53+
steps:
54+
- checkout
55+
56+
- run: mkdir ~/.kube && echo $KUBE_CONFIG | base64 --decode > ~/.kube/config
57+
58+
- run: wget https://storage.googleapis.com/kubernetes-helm/helm-v2.12.1-linux-amd64.tar.gz
59+
60+
- run: tar -xvf helm-v2.12.1-linux-amd64.tar.gz
61+
62+
- run: linux-amd64/helm init --client-only
63+
64+
- run: linux-amd64/helm repo add overture https://overture-stack.github.io/charts/
65+
66+
- run: linux-amd64/helm upgrade ego-staging overture/ego --reuse-values --set image.tag=$(git describe --always)-alpine
67+
3868
deploy:
3969
docker:
4070
- image: circleci/openjdk:8-jdk
@@ -78,10 +108,9 @@ jobs:
78108
name: Deploy Script
79109
command: ./.circleci/deploy.sh
80110

81-
82111
workflows:
83112
version: 2
84-
test-deploy:
113+
test-build-deploy:
85114
jobs:
86115
- test
87116
- deploy:
@@ -91,4 +120,11 @@ workflows:
91120
branches:
92121
only:
93122
- develop
94-
123+
- build-docker-image:
124+
filters:
125+
branches:
126+
only:
127+
- develop
128+
- deploy-staging:
129+
requires:
130+
- build-docker-image

Diff for: .gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,7 @@ _build/
3838
_source/
3939
_templates/
4040
.DS_Store
41+
42+
classes/
43+
44+
local.log

Diff for: .mvn/wrapper/MavenWrapperDownloader.java

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
Licensed to the Apache Software Foundation (ASF) under one
3+
or more contributor license agreements. See the NOTICE file
4+
distributed with this work for additional information
5+
regarding copyright ownership. The ASF licenses this file
6+
to you under the Apache License, Version 2.0 (the
7+
"License"); you may not use this file except in compliance
8+
with the License. You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing,
13+
software distributed under the License is distributed on an
14+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
KIND, either express or implied. See the License for the
16+
specific language governing permissions and limitations
17+
under the License.
18+
*/
19+
20+
import java.net.*;
21+
import java.io.*;
22+
import java.nio.channels.*;
23+
import java.util.Properties;
24+
25+
public class MavenWrapperDownloader {
26+
27+
/**
28+
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
29+
*/
30+
private static final String DEFAULT_DOWNLOAD_URL =
31+
"https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar";
32+
33+
/**
34+
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
35+
* use instead of the default one.
36+
*/
37+
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
38+
".mvn/wrapper/maven-wrapper.properties";
39+
40+
/**
41+
* Path where the maven-wrapper.jar will be saved to.
42+
*/
43+
private static final String MAVEN_WRAPPER_JAR_PATH =
44+
".mvn/wrapper/maven-wrapper.jar";
45+
46+
/**
47+
* Name of the property which should be used to override the default download url for the wrapper.
48+
*/
49+
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
50+
51+
public static void main(String args[]) {
52+
System.out.println("- Downloader started");
53+
File baseDirectory = new File(args[0]);
54+
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
55+
56+
// If the maven-wrapper.properties exists, read it and check if it contains a custom
57+
// wrapperUrl parameter.
58+
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
59+
String url = DEFAULT_DOWNLOAD_URL;
60+
if(mavenWrapperPropertyFile.exists()) {
61+
FileInputStream mavenWrapperPropertyFileInputStream = null;
62+
try {
63+
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
64+
Properties mavenWrapperProperties = new Properties();
65+
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
66+
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
67+
} catch (IOException e) {
68+
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
69+
} finally {
70+
try {
71+
if(mavenWrapperPropertyFileInputStream != null) {
72+
mavenWrapperPropertyFileInputStream.close();
73+
}
74+
} catch (IOException e) {
75+
// Ignore ...
76+
}
77+
}
78+
}
79+
System.out.println("- Downloading from: : " + url);
80+
81+
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
82+
if(!outputFile.getParentFile().exists()) {
83+
if(!outputFile.getParentFile().mkdirs()) {
84+
System.out.println(
85+
"- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'");
86+
}
87+
}
88+
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
89+
try {
90+
downloadFileFromURL(url, outputFile);
91+
System.out.println("Done");
92+
System.exit(0);
93+
} catch (Throwable e) {
94+
System.out.println("- Error downloading");
95+
e.printStackTrace();
96+
System.exit(1);
97+
}
98+
}
99+
100+
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
101+
URL website = new URL(urlString);
102+
ReadableByteChannel rbc;
103+
rbc = Channels.newChannel(website.openStream());
104+
FileOutputStream fos = new FileOutputStream(destination);
105+
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
106+
fos.close();
107+
rbc.close();
108+
}
109+
110+
}

Diff for: .mvn/wrapper/maven-wrapper.jar

100644100755
727 Bytes
Binary file not shown.

Diff for: .mvn/wrapper/maven-wrapper.properties

100644100755
+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.0/apache-maven-3.5.0-bin.zip
1+
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.5.4/apache-maven-3.5.4-bin.zip

Diff for: CONTRIBUTING.md

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Contributing
2+
3+
When contributing to this repository, please first discuss the change you wish to make via issue,
4+
email, or any other method with the owners of this repository before making a change.
5+
6+
Please note we have a code of conduct, please follow it in all your interactions with the project.
7+
8+
## Code Standards
9+
10+
#### General
11+
1. Do not use field injection (ie. `@Value`, `@Autowired`)
12+
- Instead use an `@Autowired` or `@Value` annotated constructor
13+
- Provide a static builder (ie. Lombok `@Builder` annotation)
14+
- This helps to improves testability
15+
- Helps to decouple from Spring
16+
- If your constructor is feeling messy or too big - you are probably overloading the class you are working on
17+
2. Do not use any implementation specific JPA code (ie. Hibernate-only annotations)
18+
- Exception for when no alternative functionality exists (ie. Postgres JSON field search)
19+
3. All of our code is auto-formatted to Google Java Format using the [fmt-maven-plugin](https://mvnrepository.com/artifact/com.coveo/fmt-maven-plugin) on build:
20+
```xml
21+
<plugin>
22+
<groupId>com.coveo</groupId>
23+
<artifactId>fmt-maven-plugin</artifactId>
24+
<version>${FMT_MVN_PLG.VERSION}</version>
25+
<executions>
26+
<execution>
27+
<goals>
28+
<goal>format</goal>
29+
</goals>
30+
</execution>
31+
</executions>
32+
</plugin>
33+
```
34+
5. Constants
35+
- must be declared in a `@NoArgsConstructor(access=PRIVATE)` annotated class with a name representative of the type of constants. For example, the class `Tables` under the package `constants` would contain sql table names.
36+
- Constant variable names should be consistent throughout code base. For example, the text `egoUserPermissions` should be defined by the variable `EGO_USER_PERMISSION`.
37+
6. If a method is not stateful and not an interface/abstract method, then it should be static
38+
7. Never allow a method to return `null`. Instead, it should return `Optiona<T>` or an empty container type (something that has `.isEmpty()`)
39+
40+
#### Service Layer
41+
1. Get * should always return Optional<T>
42+
2. Find * should always return a Collection<T>
43+
44+
#### JPA
45+
1. Entity member declarations should take the following presidence:
46+
1. @Id (identifier)
47+
2. Non-relationship @Column
48+
3. @OneToOne
49+
4. @OneToMany
50+
5. @ManyToOne
51+
6. @ManyToMany
52+
2. As explained in this [article](https://vladmihalcea.com/the-best-way-to-map-a-onetomany-association-with-jpa-and-hibernate/), you should prefer bidirectional associations since they are more efficient than unidirectional ones in terms of SQL performance [source](https://vladmihalcea.com/merge-entity-collections-jpa-hibernate/)
53+
3. Always lazy load for @OneToMany and @ManyToMany
54+
4. Never use CascadeType.ALL or CascadeType.REMOVE becuase they are too destructive. Use CascadeType.MERGE and CascadeType.PERSIST instead
55+
5. Name methods with `remove` indicating an entity was deleted
56+
6. Name methods with `dissociate` indicating a child relationship with its parent will be destoryed
57+
7. For performance reasons, @ManyToMany collections should be a Set as described [here](https://thoughts-on-java.org/association-mappings-bag-list-set/)
58+
8. For performance reasons, @OneToMany collections should be a list as described [here](https://vladmihalcea.com/hibernate-facts-favoring-sets-vs-bags/)
59+
9. In ManyToMany relationships, the JoinTable should only be defined on the **owning** side , and on the inverse side the `mappedBy` ManyToMany annotation parameter should be defined, as described [here](https://www.baeldung.com/hibernate-many-to-many)
60+
61+
### Testing
62+
1. Test FEATURES not methods
63+
2. Test method names should follow this convention: `[the name of the tested feature]_[expected input / tested state]_[expected behavior]`.
64+
65+
#### General
66+
1. DB via Test Containers - no in-memory DB or OS specific services
67+
2. No dependencies on any external services (ie. production micro-service)
68+
3. Tests **DO NOT** clear their data between runs, meaning that no test should rely on or expect a clean DB when running
69+
70+
##### Unit Testing
71+
72+
##### Integration Testing

Diff for: Dockerfile

+2-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ RUN mkdir -p /srv/ego/install \
2727

2828
# setup required environment variables
2929
ENV EGO_INSTALL_PATH /srv/ego
30+
ENV CONFIG_FILE /usr/src/app/src/main/resources/flyway/conf/flyway.conf
3031

3132
# start ego server
3233
WORKDIR $EGO_INSTALL_PATH
33-
CMD $EGO_INSTALL_PATH/exec/run.sh
34+
CMD cd /usr/src/app;mvn "flyway:migrate" -Dflyway.configFiles=$CONFIG_FILE -Dflyway.password=password -Dflyway.url=jdbc:postgresql://postgres:5432/ego?stringtype=unspecified;$EGO_INSTALL_PATH/exec/run.sh

Diff for: Dockerfile.prod

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
FROM maven:3.6-jdk-8
2+
3+
WORKDIR /usr/src/app
4+
5+
ADD . .
6+
7+
RUN mvn package -Dmaven.test.skip=true
8+
9+
FROM java:8-alpine
10+
11+
COPY --from=0 /usr/src/app/target/ego-*-SNAPSHOT-exec.jar /usr/bin/ego.jar
12+
COPY --from=0 /usr/src/app/src/main/resources/flyway/sql /usr/src/flyway-migration-sql
13+
14+
ENTRYPOINT ["java", "-jar", "/usr/bin/ego.jar"]
15+
16+
EXPOSE 8081/tcp

Diff for: EgoDatabaseDiagram.pdf

14.4 KB
Binary file not shown.

Diff for: NOTES.md

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
Notes
2+
------
3+
4+
## 1. Reason for using the `@Type` hibernate annotation
5+
6+
#### Problem
7+
In the entity `Policy`, the field `accessLevel` of type `AccessLevel` (which is an enum), the `@Type` annotation is used, which is a hibernate specific and not JPA annotation. The goal is to minimize or eliminate use of hibernate specific syntax, and just use JPA related code.
8+
9+
#### Solutions
10+
The goal is to map the enum to the database. In the end, solution 3 was chosen.
11+
12+
##### 1. Middleware Level Enum Handling without Hibernate Annotations
13+
Set the type of the field in the database to a `VARCHAR` and only use the `@Enumerated` JPA annotation
14+
Pros:
15+
- Hibernate will handle the logic of converting an AccessLevel to a string. This means Enum conversion is handelled by the middleware naturally.
16+
- Simple and clean solution using only JPA annotations
17+
Cons:
18+
- Enum type is represented as an Enum at the application level but as a VARCHAR at the database level. If someone was to backdoor the database and update the `accessLevel` of a policy, they could potentially break the application. There is no safeguard outside of hibernate/JPA
19+
20+
##### 2. Application Level Enum Handling
21+
Set the type of the field in the postgres database to a `AccessLevelType` and in the Java DAO, represent the field as a `String`. The application level (i.e the service layers) will manage the conversion of the Policies `String` accessLevel field to the `AccessLevel` Java enum type. Hibernate will pass the string to the postgres database, and since the url ends with `?stringtype=unspecified`, postgres will cast the string to the Database enum type
22+
Pros:
23+
- No need for Hibernate annotations
24+
- Since conversions are done manually at application layer, functionality is more obvious and cleaner
25+
Cons:
26+
- Its manual, meaning, if the developer forgets to check that the conversion from `AccessLevel->String` and `String->AccessLevel` is correct, a potentially wrong string value will be passed from hibernate to postrgres, resulting in a postgres error
27+
28+
29+
##### 3. Middleware Level Enum Handling WITH Hibernate Annotations
30+
Follow the instructions from this [blog post](https://vladmihalcea.com/the-best-way-to-map-an-enum-type-with-jpa-and-hiberate/) under the heading `Mapping a Java Enum to a database-specific Enumarated column type`. This results in the use of the `@Type` hibernate specific annotation for the `Policy` entity. This annotation modifies the way hibernate process the `accessLevel` field.
31+
Pros:
32+
- All processing is done at the middleware (hibernate) and the developer does not need to add any extra code at the application layer.
33+
- Hibernate properly process the Java enum type to a Postgres enum type. This means **BOTH** the java code (the `Policy` entity) and the Policy table in postgres are types and protected from values outside the enumeration.
34+
- Almost no developer effort and minimizes developer mistakes
35+
Cons:
36+
- The `Policy` entity is using a hibernate annotation with a custom `PostgresSQLEnumType` processor to assist hibernate in supporting Postgres enum types.
37+
38+

Diff for: README.md

+13-3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<a href="http://www.overture.bio/products/ego" target="_blank"><img alt="General Availability" title="General Availability" src="http://www.overture.bio/img/progress-horizontal-GA.svg" width="320" /></a>
99
</p>
1010

11+
[![BrowserStack Status](https://www.browserstack.com/automate/badge.svg?badge_key=U3dLZnRFNWI2MWNFY2NGcXVtVTB3WDcyU2dPVjlVeEFYUEdxUnpYZlhrUT0tLTFzY0taYTA0MVFEa3ErNkRZdTBRWVE9PQ==--690f89a41a0eedf7b4975bd7df2eac162e04e775% )](https://www.browserstack.com/automate/public-build/U3dLZnRFNWI2MWNFY2NGcXVtVTB3WDcyU2dPVjlVeEFYUEdxUnpYZlhrUT0tLTFzY0taYTA0MVFEa3ErNkRZdTBRWVE9PQ==--690f89a41a0eedf7b4975bd7df2eac162e04e775%)
1112
[![Build Status](https://travis-ci.org/overture-stack/ego.svg?branch=master)](https://travis-ci.org/overture-stack/ego)
1213
[![CircleCI](https://circleci.com/gh/overture-stack/ego/tree/develop.svg?style=svg)](https://circleci.com/gh/overture-stack/ego/tree/develop)
1314
[![Slack](http://slack.overture.bio/badge.svg)](http://slack.overture.bio)
@@ -23,6 +24,8 @@
2324
- [Step 2 - Run](#step-2---run)
2425
- [Tech Specifications](#tech-specification)
2526
- [Usage](#usage)
27+
- [Shoutouts](#shoutouts)
28+
- [Browserstack](#browserstack)
2629

2730
## Introduction
2831

@@ -91,13 +94,13 @@ Database migrations and versioning is managed by [flyway](https://flywaydb.org/)
9194
Get current version information:
9295

9396
```bash
94-
./flyway -configFiles=<path_to_ego>/ego/src/main/resources/flyway/conf/flyway.conf -locations=filesystem:<path_to_ego>/ego/src/main/resources/flyway/sql info
97+
./fly
9598
```
9699

97100
Run outstanding migrations:
98101

99102
```bash
100-
./flyway -configFiles=<path_to_ego>/ego/src/main/resources/flyway/conf/flyway.conf -locations=filesystem:<path_to_ego>/ego/src/main/resources/flyway/sql migrate
103+
./fly migrate
101104
```
102105

103106
To see the migration naming convention, [click here.](https://flywaydb.org/documentation/migrations#naming)
@@ -163,7 +166,6 @@ An example ego JWT is mentioned below:
163166
```
164167

165168
#### Notes
166-
167169
- "aud" field can contain one or more client IDs. This field indicates the client services that are authorized to use this JWT.
168170
- "groups" will differ based on the domain of client services - each domain of service should get list of groups from that domain's ego service.
169171
- "permissions" will differ based on domain of client service - each domain of service should get list of permissions from that domain's ego service.
@@ -204,3 +206,11 @@ curl example:
204206
-H 'Content-Type: application/x-www-form-urlencoded' \
205207
-d 'grant_type=client_credentials&client_id=my-app-id&client_secret=secretpassword'
206208
```
209+
210+
## Shoutouts
211+
212+
### Browserstack
213+
Many thanks to [Browserstack](https://www.browserstack.com/) for giving our test capabilities a powerup!
214+
![Browserstack](https://p14.zdusercontent.com/attachment/1015988/qyPFNKIZXCbr4qKjd5oxrayZc?token=eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0..-yKqMwgZKdCDJZmW2kcVYw.IKGbK6GBbU3uZ3B7Vapw8uZeQ-uhXDV9kANtz5OOOBl0Ceg6Oi1gS5wqBnStOsCKgb3CibgGIrYjk-odWPwaL9Ei0u3OIDuBldkxF6aJ6eGtC9G4LfbDLGtOnYkUiANvx5HNPb7HZa3QyivKxCcX_MjO5U01F0WbmJajfYBsFVHHLtO0dBqFz-eWZMmLB0yfjZEaVPAUfLk9H1TO4c6Vw91Or29FrzaoGDQmvmcP7Pg00LMoxuaLxGJuuOiUlEe6OunidzxRd_elUZxMJ_caonvHEjSCkq_yHilG67tGewY.IV6Qg9p5vE0TGk59pqZtRg)
215+
216+

0 commit comments

Comments
 (0)