Compare commits
60 Commits
dependabot
...
test
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43b9c83917 | ||
|
|
b558643405 | ||
|
|
acdf98e71b | ||
|
|
c30b27b240 | ||
|
|
dbdd4d20cb | ||
|
|
379f0d6799 | ||
|
|
8e299cf819 | ||
|
|
14536868c5 | ||
|
|
bbca460ed2 | ||
|
|
cd2e56a959 | ||
|
|
143a5b53d0 | ||
|
|
fec088b7db | ||
|
|
d68609b407 | ||
|
|
8b1ae3f3ed | ||
|
|
0ccd671636 | ||
|
|
1dac3ad175 | ||
|
|
91e38a8361 | ||
|
|
071651aa67 | ||
|
|
a6c5ab4cd7 | ||
|
|
c28b2d4a73 | ||
|
|
8bca7692e2 | ||
|
|
d1b5b19dd6 | ||
|
|
d5ff8dae58 | ||
|
|
4bb5bb8af9 | ||
|
|
e03595d5bd | ||
|
|
b5cfe4ad2a | ||
|
|
4a64888977 | ||
|
|
44d082c163 | ||
|
|
8b3fc4cf5c | ||
|
|
5bd780f9c8 | ||
|
|
eba824b908 | ||
|
|
8de5f6d41c | ||
|
|
381be70991 | ||
|
|
87a6cac6b3 | ||
|
|
fef6c48fe1 | ||
|
|
3f59bd2ea4 | ||
|
|
e2d6cc3acb | ||
|
|
fef53fa72a | ||
|
|
6b2ad23059 | ||
|
|
368a059cfe | ||
|
|
67b4cbe08f | ||
|
|
0514f9f517 | ||
|
|
76bcc6c016 | ||
|
|
fd14c4c13e | ||
|
|
39dbdc129f | ||
|
|
dbaa38a5fe | ||
|
|
8f6e222ef2 | ||
|
|
88c5ff3dc7 | ||
|
|
4cf2cbc10c | ||
|
|
e4e3d8a55b | ||
|
|
d41fa4a006 | ||
|
|
48cdce6e65 | ||
|
|
2d8c099993 | ||
|
|
1c92604f3b | ||
|
|
6a63059b8c | ||
|
|
1de287bcdb | ||
|
|
f044fcc228 | ||
|
|
ee1712c245 | ||
|
|
8f03b89816 | ||
|
|
f751203867 |
117
aws/cdk/.mvn/wrapper/MavenWrapperDownloader.java
vendored
Normal file
117
aws/cdk/.mvn/wrapper/MavenWrapperDownloader.java
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2007-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.Properties;
|
||||
|
||||
public class MavenWrapperDownloader {
|
||||
|
||||
private static final String WRAPPER_VERSION = "0.5.6";
|
||||
/**
|
||||
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
|
||||
*/
|
||||
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
|
||||
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
|
||||
|
||||
/**
|
||||
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
|
||||
* use instead of the default one.
|
||||
*/
|
||||
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
|
||||
".mvn/wrapper/maven-wrapper.properties";
|
||||
|
||||
/**
|
||||
* Path where the maven-wrapper.jar will be saved to.
|
||||
*/
|
||||
private static final String MAVEN_WRAPPER_JAR_PATH =
|
||||
".mvn/wrapper/maven-wrapper.jar";
|
||||
|
||||
/**
|
||||
* Name of the property which should be used to override the default download url for the wrapper.
|
||||
*/
|
||||
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.out.println("- Downloader started");
|
||||
File baseDirectory = new File(args[0]);
|
||||
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
|
||||
|
||||
// If the maven-wrapper.properties exists, read it and check if it contains a custom
|
||||
// wrapperUrl parameter.
|
||||
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
|
||||
String url = DEFAULT_DOWNLOAD_URL;
|
||||
if(mavenWrapperPropertyFile.exists()) {
|
||||
FileInputStream mavenWrapperPropertyFileInputStream = null;
|
||||
try {
|
||||
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
|
||||
Properties mavenWrapperProperties = new Properties();
|
||||
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
|
||||
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
|
||||
} catch (IOException e) {
|
||||
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
|
||||
} finally {
|
||||
try {
|
||||
if(mavenWrapperPropertyFileInputStream != null) {
|
||||
mavenWrapperPropertyFileInputStream.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Ignore ...
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("- Downloading from: " + url);
|
||||
|
||||
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
|
||||
if(!outputFile.getParentFile().exists()) {
|
||||
if(!outputFile.getParentFile().mkdirs()) {
|
||||
System.out.println(
|
||||
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
|
||||
}
|
||||
}
|
||||
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
|
||||
try {
|
||||
downloadFileFromURL(url, outputFile);
|
||||
System.out.println("Done");
|
||||
System.exit(0);
|
||||
} catch (Throwable e) {
|
||||
System.out.println("- Error downloading");
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
|
||||
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
|
||||
String username = System.getenv("MVNW_USERNAME");
|
||||
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
|
||||
Authenticator.setDefault(new Authenticator() {
|
||||
@Override
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
return new PasswordAuthentication(username, password);
|
||||
}
|
||||
});
|
||||
}
|
||||
URL website = new URL(urlString);
|
||||
ReadableByteChannel rbc;
|
||||
rbc = Channels.newChannel(website.openStream());
|
||||
FileOutputStream fos = new FileOutputStream(destination);
|
||||
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
|
||||
fos.close();
|
||||
rbc.close();
|
||||
}
|
||||
|
||||
}
|
||||
BIN
aws/cdk/.mvn/wrapper/maven-wrapper.jar
vendored
Normal file
BIN
aws/cdk/.mvn/wrapper/maven-wrapper.jar
vendored
Normal file
Binary file not shown.
2
aws/cdk/.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
2
aws/cdk/.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
|
||||
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
|
||||
0
aws/cdk/mvnw
vendored
Normal file
0
aws/cdk/mvnw
vendored
Normal file
182
aws/cdk/mvnw.cmd
vendored
Normal file
182
aws/cdk/mvnw.cmd
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||
@REM or more contributor license agreements. See the NOTICE file
|
||||
@REM distributed with this work for additional information
|
||||
@REM regarding copyright ownership. The ASF licenses this file
|
||||
@REM to you under the Apache License, Version 2.0 (the
|
||||
@REM "License"); you may not use this file except in compliance
|
||||
@REM with the License. You may obtain a copy of the License at
|
||||
@REM
|
||||
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||
@REM
|
||||
@REM Unless required by applicable law or agreed to in writing,
|
||||
@REM software distributed under the License is distributed on an
|
||||
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
@REM KIND, either express or implied. See the License for the
|
||||
@REM specific language governing permissions and limitations
|
||||
@REM under the License.
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Maven Start Up Batch script
|
||||
@REM
|
||||
@REM Required ENV vars:
|
||||
@REM JAVA_HOME - location of a JDK home dir
|
||||
@REM
|
||||
@REM Optional ENV vars
|
||||
@REM M2_HOME - location of maven2's installed home dir
|
||||
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
|
||||
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
|
||||
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
@REM e.g. to debug Maven itself, use
|
||||
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
|
||||
@echo off
|
||||
@REM set title of command window
|
||||
title %0
|
||||
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
|
||||
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
|
||||
|
||||
@REM set %HOME% to equivalent of $HOME
|
||||
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
|
||||
|
||||
@REM Execute a user defined script before this one
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
|
||||
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
|
||||
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
|
||||
:skipRcPre
|
||||
|
||||
@setlocal
|
||||
|
||||
set ERROR_CODE=0
|
||||
|
||||
@REM To isolate internal variables from possible post scripts, we use another setlocal
|
||||
@setlocal
|
||||
|
||||
@REM ==== START VALIDATION ====
|
||||
if not "%JAVA_HOME%" == "" goto OkJHome
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME not found in your environment. >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
:OkJHome
|
||||
if exist "%JAVA_HOME%\bin\java.exe" goto init
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME is set to an invalid directory. >&2
|
||||
echo JAVA_HOME = "%JAVA_HOME%" >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
@REM ==== END VALIDATION ====
|
||||
|
||||
:init
|
||||
|
||||
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
|
||||
@REM Fallback to current working directory if not found.
|
||||
|
||||
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
|
||||
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
|
||||
|
||||
set EXEC_DIR=%CD%
|
||||
set WDIR=%EXEC_DIR%
|
||||
:findBaseDir
|
||||
IF EXIST "%WDIR%"\.mvn goto baseDirFound
|
||||
cd ..
|
||||
IF "%WDIR%"=="%CD%" goto baseDirNotFound
|
||||
set WDIR=%CD%
|
||||
goto findBaseDir
|
||||
|
||||
:baseDirFound
|
||||
set MAVEN_PROJECTBASEDIR=%WDIR%
|
||||
cd "%EXEC_DIR%"
|
||||
goto endDetectBaseDir
|
||||
|
||||
:baseDirNotFound
|
||||
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
|
||||
cd "%EXEC_DIR%"
|
||||
|
||||
:endDetectBaseDir
|
||||
|
||||
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
|
||||
|
||||
@setlocal EnableExtensions EnableDelayedExpansion
|
||||
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
|
||||
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
|
||||
|
||||
:endReadAdditionalConfig
|
||||
|
||||
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
|
||||
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
|
||||
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
|
||||
|
||||
FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
|
||||
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
|
||||
)
|
||||
|
||||
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
if exist %WRAPPER_JAR% (
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Found %WRAPPER_JAR%
|
||||
)
|
||||
) else (
|
||||
if not "%MVNW_REPOURL%" == "" (
|
||||
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
|
||||
)
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Couldn't find %WRAPPER_JAR%, downloading it ...
|
||||
echo Downloading from: %DOWNLOAD_URL%
|
||||
)
|
||||
|
||||
powershell -Command "&{"^
|
||||
"$webclient = new-object System.Net.WebClient;"^
|
||||
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
|
||||
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
|
||||
"}"^
|
||||
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
|
||||
"}"
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Finished downloading %WRAPPER_JAR%
|
||||
)
|
||||
)
|
||||
@REM End of extension
|
||||
|
||||
@REM Provide a "standardized" way to retrieve the CLI args that will
|
||||
@REM work with both Windows and non-Windows executions.
|
||||
set MAVEN_CMD_LINE_ARGS=%*
|
||||
|
||||
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
|
||||
if ERRORLEVEL 1 goto error
|
||||
goto end
|
||||
|
||||
:error
|
||||
set ERROR_CODE=1
|
||||
|
||||
:end
|
||||
@endlocal & set ERROR_CODE=%ERROR_CODE%
|
||||
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
|
||||
@REM check for post script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
|
||||
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
|
||||
:skipRcPost
|
||||
|
||||
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
|
||||
if "%MAVEN_BATCH_PAUSE%" == "on" pause
|
||||
|
||||
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
|
||||
|
||||
exit /B %ERROR_CODE%
|
||||
23
aws/cdk/src/main/java/com/myorg/SecondStack.java
Normal file
23
aws/cdk/src/main/java/com/myorg/SecondStack.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package com.myorg;
|
||||
|
||||
import software.amazon.awscdk.core.Construct;
|
||||
import software.amazon.awscdk.core.Stack;
|
||||
import software.amazon.awscdk.core.StackProps;
|
||||
import software.amazon.awscdk.services.s3.Bucket;
|
||||
|
||||
public class SecondStack extends Stack {
|
||||
public SecondStack(final Construct scope, final String id) {
|
||||
this(scope, id, null);
|
||||
}
|
||||
|
||||
public SecondStack(final Construct scope, final String id, final StackProps props) {
|
||||
super(scope, id, props);
|
||||
|
||||
String bucketName = (String) this.getNode().tryGetContext("bucketName2");
|
||||
|
||||
Bucket bucket = Bucket.Builder.create(this, "bucket")
|
||||
.bucketName(bucketName)
|
||||
.build();
|
||||
|
||||
}
|
||||
}
|
||||
141
aws/s3/.gitignore
vendored
Normal file
141
aws/s3/.gitignore
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/java,intellij+all,gradle
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=java,intellij+all,gradle
|
||||
|
||||
### Intellij+all ###
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/artifacts
|
||||
# .idea/compiler.xml
|
||||
# .idea/jarRepositories.xml
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
# *.iml
|
||||
# *.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
# out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
### Intellij+all Patch ###
|
||||
# Ignores the whole .idea folder and all .iml files
|
||||
# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360
|
||||
|
||||
.idea/
|
||||
|
||||
# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
|
||||
|
||||
*.iml
|
||||
modules.xml
|
||||
.idea/misc.xml
|
||||
*.ipr
|
||||
|
||||
# Sonarlint plugin
|
||||
.idea/sonarlint
|
||||
|
||||
### Java ###
|
||||
# Compiled class file
|
||||
*.class
|
||||
|
||||
# Log file
|
||||
*.log
|
||||
|
||||
# BlueJ files
|
||||
*.ctxt
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.nar
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
|
||||
### Gradle ###
|
||||
.gradle
|
||||
build/
|
||||
|
||||
# Ignore Gradle GUI config
|
||||
gradle-app.setting
|
||||
|
||||
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||
!gradle-wrapper.jar
|
||||
|
||||
# Cache of project
|
||||
.gradletasknamecache
|
||||
|
||||
# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
|
||||
# gradle/wrapper/gradle-wrapper.properties
|
||||
|
||||
### Gradle Patch ###
|
||||
**/build/
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/java,intellij+all,gradle
|
||||
|
||||
# Dumps of the meta-db
|
||||
data/*.db
|
||||
167
aws/s3/Readme.md
Normal file
167
aws/s3/Readme.md
Normal file
@@ -0,0 +1,167 @@
|
||||
<!-- PROJECT LOGO -->
|
||||
<br />
|
||||
<p align="center">
|
||||
<img src="images/logo.png" alt="Logo" width="200" height="200">
|
||||
<h3 align="center">Private File Upload</h3>
|
||||
|
||||
<p align="center">
|
||||
Build on Spring Cloud & AWS S3
|
||||
</p>
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
<!-- TABLE OF CONTENTS -->
|
||||
## Table of Contents
|
||||
|
||||
* [About the Project](#about-the-project)
|
||||
* [Built With](#built-with)
|
||||
* [Getting Started](#getting-started)
|
||||
* [Prerequisites](#prerequisites)
|
||||
* [Installation](#installation)
|
||||
* [Usage](#usage)
|
||||
* [Contact](#contact)
|
||||
* [Acknowledgements](#acknowledgements)
|
||||
|
||||
|
||||
|
||||
<!-- ABOUT THE PROJECT -->
|
||||
## About The Project
|
||||
|
||||
<p align="center">
|
||||
<img src="images/usage.gif">
|
||||
</p>
|
||||
|
||||
|
||||
### Built With
|
||||
- Spring Boot
|
||||
- Spring Cloud
|
||||
- AWS S3
|
||||
- ☕️ & ❤️
|
||||
|
||||
<!-- GETTING STARTED -->
|
||||
## Getting Started
|
||||
|
||||
### Prerequisites
|
||||
|
||||
In order to run this application you should have an Amazon Web Services (AWS) account.
|
||||
|
||||
### Installation
|
||||
|
||||
1. Update the `application.yaml` settings value for `cloud.aws.credentials.profile-name` to the name of your local AWS-profile
|
||||
2. run `./gradlew bootRun`
|
||||
3. Open your browser at `localhost:8080`
|
||||
|
||||
<!-- USAGE EXAMPLES -->
|
||||
## Usage
|
||||
|
||||
The application wraps a lot of S3-related API calls in easy to use UI elements to
|
||||
|
||||
- create/delete buckets (mapped as "spaces" so we can give them non-unique names)
|
||||
- upload/delete files
|
||||
- make files public/private
|
||||
- create pre-signed URLs for files
|
||||
- create bucket policy rules to set the lifecycle duration for elements
|
||||
|
||||
More detailed instructions can be found here:
|
||||
|
||||
<details>
|
||||
<summary>🪣 Create a bucket</summary>
|
||||
|
||||
1. Navigate to the _Spaces_ section
|
||||
2. Click on _New Space_
|
||||
3. Enter the name and click _Submit_
|
||||
4. A message should pop up to indicate success
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>🗂 Upload a File</summary>
|
||||
|
||||
1. Navigate to the _Spaces_ section
|
||||
2. Select _Details_ on the target Space/Bucket
|
||||
3. Click on _Upload File_
|
||||
4. Pick our file, provide a name and click _Submit_
|
||||
5. A message should pop up to indicate success
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>🔎 List all Objects in a Bucket</summary>
|
||||
|
||||
1. Navigate to the _Spaces_ section
|
||||
2. Select _Details_ on the target Space/Bucket
|
||||
3. You see a list of all objects stored in the bucket
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>🌐 Get an Object's URL</summary>
|
||||
|
||||
1. Navigate to the _Spaces_ section
|
||||
2. Select _Details_ on the target Space/Bucket
|
||||
3. Select _Download_ on the target object
|
||||
4. The object's URL shall be opened in a new tab
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>📢 Make an object public</summary>
|
||||
|
||||
1. Navigate to the _Spaces_ section
|
||||
2. Select _Details_ on the target Space/Bucket
|
||||
3. Select _Make Public_ on the target object
|
||||
4. A message should pop up to indicate success
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>🤫 Make an Object private</summary>
|
||||
|
||||
1. Navigate to the _Spaces_ section
|
||||
2. Select _Details_ on the target Space/Bucket
|
||||
3. Select _Make Private_ on the target object
|
||||
4. A message should pop up to indicate success
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>🔥 Delete an Object</summary>
|
||||
|
||||
1. Navigate to the _Spaces_ section
|
||||
2. Select _Details_ on the target Space/Bucket
|
||||
3. Select _Delete_ on the target object
|
||||
4. The list of objects should reload without the deleted one
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>☄️ Delete a Bucket</summary>
|
||||
|
||||
1. Navigate to the _Spaces_ section
|
||||
2. Select _Delete_ on the target Space/Bucket
|
||||
3. The list of buckets should reload without the deleted one
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>👾 Generate a pre-signed URL</summary>
|
||||
|
||||
1. Navigate to the _Spaces_ section
|
||||
2. Select _Details_ on the target Space/Bucket
|
||||
3. Select _Magic Link_ on the target object
|
||||
4. A message should pop up, containing a pre-signed URL for that object (which is valid for 15 minutes)
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>⏳ Set Expiration on Bucket</summary>
|
||||
|
||||
1. Navigate to the _Spaces_ section
|
||||
2. Select _Make Temporary_ on the target Space/Bucket
|
||||
3. Select _Delete_ on the target object
|
||||
4. A message should pop up to indicate success
|
||||
</details>
|
||||
|
||||
<!-- CONTACT -->
|
||||
## Contact
|
||||
|
||||
Joshua Görner - [jgoerner](https://www.linkedin.com/in/jgoerner/) - joshua.goerner[at]gmail.com
|
||||
|
||||
|
||||
<!-- ACKNOWLEDGEMENTS -->
|
||||
## Acknowledgements
|
||||
* [O. Drew](https://github.com/othneildrew/Best-README-Template) - nice GH Readme template
|
||||
* [Hatchful](https://hatchful.shopify.com/) - Easy Logo Generation
|
||||
41
aws/s3/build.gradle
Normal file
41
aws/s3/build.gradle
Normal file
@@ -0,0 +1,41 @@
|
||||
plugins {
|
||||
id 'org.springframework.boot' version '2.4.2'
|
||||
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
|
||||
id 'java'
|
||||
}
|
||||
|
||||
group = 'io.jgoerner'
|
||||
version = '0.0.1-SNAPSHOT'
|
||||
sourceCompatibility = '11'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
ext {
|
||||
// set('springCloudVersion', "Hoxton.SR9")
|
||||
set('springCloudVersion', "Finchley.SR1")
|
||||
}
|
||||
|
||||
|
||||
dependencies {
|
||||
annotationProcessor 'org.projectlombok:lombok'
|
||||
developmentOnly 'org.springframework.boot:spring-boot-devtools'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-web'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
|
||||
implementation 'org.springframework.cloud:spring-cloud-starter-aws'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||
implementation 'org.projectlombok:lombok:1.18.16'
|
||||
runtimeOnly 'com.h2database:h2'
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||
}
|
||||
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
|
||||
}
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
0
aws/s3/data/.gitkeep
Normal file
0
aws/s3/data/.gitkeep
Normal file
BIN
aws/s3/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
aws/s3/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
aws/s3/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
aws/s3/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#Mon Jan 04 22:38:53 CET 2021
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
185
aws/s3/gradlew
vendored
Executable file
185
aws/s3/gradlew
vendored
Executable file
@@ -0,0 +1,185 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=`save "$@"`
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
89
aws/s3/gradlew.bat
vendored
Normal file
89
aws/s3/gradlew.bat
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
BIN
aws/s3/images/logo.png
Normal file
BIN
aws/s3/images/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 60 KiB |
BIN
aws/s3/images/usage.gif
Normal file
BIN
aws/s3/images/usage.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.0 MiB |
1
aws/s3/settings.gradle
Normal file
1
aws/s3/settings.gradle
Normal file
@@ -0,0 +1 @@
|
||||
rootProject.name = 's3'
|
||||
38
aws/s3/src/main/java/io/jgoerner/s3/S3Application.java
Normal file
38
aws/s3/src/main/java/io/jgoerner/s3/S3Application.java
Normal file
@@ -0,0 +1,38 @@
|
||||
package io.jgoerner.s3;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.thymeleaf.ThymeleafProperties;
|
||||
import org.springframework.cloud.aws.autoconfigure.context.ContextInstanceDataAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.thymeleaf.templateresolver.FileTemplateResolver;
|
||||
import org.thymeleaf.templateresolver.ITemplateResolver;
|
||||
|
||||
@SpringBootApplication(exclude = ContextInstanceDataAutoConfiguration.class)
|
||||
public class S3Application {
|
||||
|
||||
private final ThymeleafProperties properties;
|
||||
|
||||
@Value("${spring.thymeleaf.templates_root:}")
|
||||
private String templatesRoot;
|
||||
|
||||
public S3Application(ThymeleafProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(S3Application.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ITemplateResolver defaultTemplateResolver() {
|
||||
FileTemplateResolver resolver = new FileTemplateResolver();
|
||||
resolver.setSuffix(properties.getSuffix());
|
||||
resolver.setPrefix(templatesRoot);
|
||||
resolver.setTemplateMode(properties.getMode());
|
||||
resolver.setCacheable(properties.isCache());
|
||||
return resolver;
|
||||
}
|
||||
|
||||
}
|
||||
128
aws/s3/src/main/java/io/jgoerner/s3/adapter/in/RestApi.java
Normal file
128
aws/s3/src/main/java/io/jgoerner/s3/adapter/in/RestApi.java
Normal file
@@ -0,0 +1,128 @@
|
||||
package io.jgoerner.s3.adapter.in;
|
||||
|
||||
import io.jgoerner.s3.application.port.in.object.*;
|
||||
import io.jgoerner.s3.application.port.in.space.*;
|
||||
import io.jgoerner.s3.domain.Object;
|
||||
import io.jgoerner.s3.domain.ObjectPartial;
|
||||
import io.jgoerner.s3.domain.Space;
|
||||
import io.jgoerner.s3.domain.SpacePartial;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("api")
|
||||
@Log4j2
|
||||
public class RestApi {
|
||||
|
||||
private final CreateSpace spaceCreator;
|
||||
private final GetAllSpaces allSpaceGetter;
|
||||
private final RemoveSpace spaceRemover;
|
||||
private final GetAllObjects allObjectsInSpaceGetter;
|
||||
private final UploadObject objectUploader;
|
||||
private final UpdateObject objectUpdater;
|
||||
private final RemoveObject objectDeleter;
|
||||
private final ForceRemoveSpace forceSpaceRemover;
|
||||
private final CreateLink linkCreator;
|
||||
private final SetTTL ttlUpdater;
|
||||
private final RemoveTTL ttlRemover;
|
||||
|
||||
public RestApi(
|
||||
CreateSpace spaceCreator,
|
||||
GetAllSpaces allSpaceGetter,
|
||||
RemoveSpace spaceRemover,
|
||||
GetAllObjects allObjectsInSpaceGetter,
|
||||
UploadObject objectUploader,
|
||||
UpdateObject objectUpdater,
|
||||
RemoveObject objectDeleter,
|
||||
ForceRemoveSpace forceSpaceRemover,
|
||||
CreateLink linkCreator,
|
||||
SetTTL ttlUpdater,
|
||||
RemoveTTL ttlRemover) {
|
||||
this.spaceCreator = spaceCreator;
|
||||
this.allSpaceGetter = allSpaceGetter;
|
||||
this.spaceRemover = spaceRemover;
|
||||
this.allObjectsInSpaceGetter = allObjectsInSpaceGetter;
|
||||
this.objectUploader = objectUploader;
|
||||
this.objectUpdater = objectUpdater;
|
||||
this.objectDeleter = objectDeleter;
|
||||
this.forceSpaceRemover = forceSpaceRemover;
|
||||
this.linkCreator = linkCreator;
|
||||
this.ttlUpdater = ttlUpdater;
|
||||
this.ttlRemover = ttlRemover;
|
||||
}
|
||||
|
||||
@GetMapping("/space")
|
||||
List<Space> getSpaces() {
|
||||
return allSpaceGetter.getAll();
|
||||
}
|
||||
|
||||
@PostMapping("/space/{space}")
|
||||
Space postSpace(@PathVariable String space) {
|
||||
return spaceCreator.create(space);
|
||||
}
|
||||
|
||||
@DeleteMapping("/space/{space}")
|
||||
void deleteSpace(@PathVariable String space, @RequestParam Optional<Boolean> force) {
|
||||
log.info("Got the value " + force);
|
||||
force.ifPresentOrElse(
|
||||
value -> {
|
||||
if (value) {
|
||||
forceSpaceRemover.forceRemove(space);
|
||||
} else {
|
||||
spaceRemover.remove(space);
|
||||
}
|
||||
},
|
||||
() -> spaceRemover.remove(space));
|
||||
}
|
||||
|
||||
@GetMapping("/space/{space}/object")
|
||||
List<Object> getObjectsInSpace(@PathVariable String space) {
|
||||
return allObjectsInSpaceGetter.getAllObjects(space);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@PostMapping("/space/{space}/object")
|
||||
Object postObject(
|
||||
@PathVariable String space,
|
||||
@RequestParam("file") MultipartFile file,
|
||||
@RequestParam(required = false, name = "name") String name) {
|
||||
var key = name != null ? name : file.getOriginalFilename();
|
||||
return objectUploader.upload(space, key, file.getInputStream());
|
||||
}
|
||||
|
||||
@PatchMapping("/space/{space}/object/{key}")
|
||||
Object patchObject(
|
||||
@PathVariable String space, @PathVariable String key, @RequestBody ObjectPartial body) {
|
||||
log.info("Got the partial " + body);
|
||||
return objectUpdater.update(space, key, body);
|
||||
}
|
||||
|
||||
@DeleteMapping("/space/{space}/object/{key}")
|
||||
void deleteObject(@PathVariable String space, @PathVariable String key) {
|
||||
objectDeleter.delete(space, key);
|
||||
}
|
||||
|
||||
@PostMapping("/space/{space}/object/{key}/url")
|
||||
URL createLink(
|
||||
@PathVariable String space,
|
||||
@PathVariable String key,
|
||||
@RequestParam(required = false, name = "duration", defaultValue = "300") Long duration) {
|
||||
return linkCreator.createLink(space, key, duration);
|
||||
}
|
||||
|
||||
@PatchMapping("/space/{space}")
|
||||
void patchSpace(@PathVariable String space, @RequestBody(required = false) SpacePartial body) {
|
||||
log.info("got " + body);
|
||||
if (body.getTtlInDays() > 1) {
|
||||
ttlUpdater.setTTL(space, body.getTtlInDays());
|
||||
} else {
|
||||
ttlRemover.removeTTL(space);
|
||||
}
|
||||
}
|
||||
}
|
||||
126
aws/s3/src/main/java/io/jgoerner/s3/adapter/in/View.java
Normal file
126
aws/s3/src/main/java/io/jgoerner/s3/adapter/in/View.java
Normal file
@@ -0,0 +1,126 @@
|
||||
package io.jgoerner.s3.adapter.in;
|
||||
|
||||
import io.jgoerner.s3.domain.ObjectPartial;
|
||||
import io.jgoerner.s3.domain.SpacePartial;
|
||||
import lombok.Data;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@Log4j2
|
||||
@Controller()
|
||||
public class View {
|
||||
|
||||
private final RestApi api;
|
||||
|
||||
public View(RestApi api) {
|
||||
this.api = api;
|
||||
}
|
||||
|
||||
@GetMapping("space")
|
||||
String space(Model model) {
|
||||
var spaces = api.getSpaces();
|
||||
model.addAttribute("spaces", spaces);
|
||||
return "space-overview";
|
||||
}
|
||||
|
||||
@GetMapping("space/{name}")
|
||||
String spaceDetail(@PathVariable String name, Model model) {
|
||||
model.addAllAttributes(Map.of("space", name, "objects", api.getObjectsInSpace(name)));
|
||||
return "space-detail";
|
||||
}
|
||||
|
||||
@GetMapping("space/{space}/make-public/{key}")
|
||||
String makePublic(
|
||||
@PathVariable String space, @PathVariable String key, RedirectAttributes redirectAttributes) {
|
||||
api.patchObject(space, key, new ObjectPartial(true));
|
||||
redirectAttributes.addFlashAttribute("success", "Made object public");
|
||||
return "redirect:/space/" + space;
|
||||
}
|
||||
|
||||
@GetMapping("space/{space}/make-private/{key}")
|
||||
String makePrivate(
|
||||
@PathVariable String space, @PathVariable String key, RedirectAttributes redirectAttributes) {
|
||||
api.patchObject(space, key, new ObjectPartial(false));
|
||||
redirectAttributes.addFlashAttribute("success", "Made object private");
|
||||
return "redirect:/space/" + space;
|
||||
}
|
||||
|
||||
@GetMapping("space/{space}/delete/{key}")
|
||||
String deleteObject(@PathVariable String space, @PathVariable String key) {
|
||||
api.deleteObject(space, key);
|
||||
return "redirect:/space/" + space;
|
||||
}
|
||||
|
||||
@GetMapping("/space/{space}/object-form")
|
||||
String objectNew(@PathVariable String space, Model model) {
|
||||
model.addAllAttributes(Map.of("space", space, "object", new ObjectForm()));
|
||||
return "object-form";
|
||||
}
|
||||
|
||||
@PostMapping("/space/{space}/object-form")
|
||||
String postObject(
|
||||
@PathVariable String space,
|
||||
@RequestParam("file") MultipartFile file,
|
||||
@ModelAttribute ObjectForm form,
|
||||
RedirectAttributes redirectAttributes) {
|
||||
api.postObject(space, file, form.getName());
|
||||
redirectAttributes.addFlashAttribute("success", "Successfully uploaded " + form.getName());
|
||||
return "redirect:/space/" + space;
|
||||
}
|
||||
|
||||
@GetMapping("/space/{space}/magic/{key}")
|
||||
String magicLink(
|
||||
@PathVariable String space, @PathVariable String key, RedirectAttributes redirectAttributes) {
|
||||
var link = api.createLink(space, key, 15L);
|
||||
redirectAttributes.addFlashAttribute("warn", link);
|
||||
return "redirect:/space/" + space;
|
||||
}
|
||||
|
||||
@GetMapping("space-form")
|
||||
String spaceNew(Model model) {
|
||||
model.addAttribute("space", new SpaceForm());
|
||||
return "space-form";
|
||||
}
|
||||
|
||||
@PostMapping("space-form")
|
||||
String newSpace(@ModelAttribute SpaceForm form, RedirectAttributes redirectAttributes) {
|
||||
api.postSpace(form.getName());
|
||||
redirectAttributes.addFlashAttribute("success", "Successfully created " + form.getName());
|
||||
return "redirect:space";
|
||||
}
|
||||
|
||||
@GetMapping("space/temporary/{name}")
|
||||
String makeTemporary(@PathVariable String name) {
|
||||
api.patchSpace(name, new SpacePartial(2));
|
||||
return "redirect:/space";
|
||||
}
|
||||
|
||||
@GetMapping("space/permanent/{name}")
|
||||
String makePermanent(@PathVariable String name) {
|
||||
api.patchSpace(name, new SpacePartial(-1));
|
||||
return "redirect:/space";
|
||||
}
|
||||
|
||||
@GetMapping("space/delete/{name}")
|
||||
String delete(@PathVariable String name) {
|
||||
api.deleteSpace(name, Optional.of(true));
|
||||
return "redirect:/space";
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
class SpaceForm {
|
||||
String name;
|
||||
}
|
||||
|
||||
@Data
|
||||
class ObjectForm {
|
||||
String name;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package io.jgoerner.s3.adapter.out.h2;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
@Entity
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class SpaceEntity {
|
||||
@Id private String name;
|
||||
private String bucket;
|
||||
private Integer ttl;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package io.jgoerner.s3.adapter.out.h2;
|
||||
|
||||
import io.jgoerner.s3.application.port.out.space.*;
|
||||
import io.jgoerner.s3.domain.Space;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
@Log4j2
|
||||
public class SpacePersistenceHandler
|
||||
implements CheckSpaceExistence,
|
||||
SaveSpace,
|
||||
RetrieveAllSpaces,
|
||||
ResolveSpaceName,
|
||||
DeleteSpace,
|
||||
RetrieveSpaceByName {
|
||||
|
||||
private final SpaceRepository spaceRepository;
|
||||
|
||||
public SpacePersistenceHandler(SpaceRepository spaceRepository) {
|
||||
this.spaceRepository = spaceRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doesExist(String name) {
|
||||
return this.spaceRepository.findById(name).isPresent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Space save(Space name) {
|
||||
this.spaceRepository.save(SpacePersistenceHandler.mapPojoToJpa(name));
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Space> findAll() {
|
||||
return spaceRepository.findAll().stream()
|
||||
.map(SpacePersistenceHandler::mapJpaToPojo)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static SpaceEntity mapPojoToJpa(Space space) {
|
||||
return new SpaceEntity(space.getName(), space.getBucket(), space.getTtl());
|
||||
}
|
||||
|
||||
private static Space mapJpaToPojo(SpaceEntity entity) {
|
||||
return new Space(entity.getName(), entity.getBucket(), entity.getTtl());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolve(String name) {
|
||||
var bucket = spaceRepository.findById(name).get().getBucket();
|
||||
log.info("Space " + name + " was resolved to " + bucket);
|
||||
return bucket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String name) {
|
||||
spaceRepository.deleteById(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Space retrieveByName(String name) {
|
||||
return mapJpaToPojo(spaceRepository.findById(name).orElseThrow());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package io.jgoerner.s3.adapter.out.h2;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface SpaceRepository extends JpaRepository<SpaceEntity, String> {}
|
||||
@@ -0,0 +1,143 @@
|
||||
package io.jgoerner.s3.adapter.out.s3;
|
||||
|
||||
import com.amazonaws.services.s3.AmazonS3Client;
|
||||
import com.amazonaws.services.s3.model.*;
|
||||
import com.amazonaws.services.s3.model.lifecycle.LifecycleFilter;
|
||||
import com.amazonaws.waiters.WaiterParameters;
|
||||
import io.jgoerner.s3.application.port.out.bucket.*;
|
||||
import io.jgoerner.s3.application.port.out.object.*;
|
||||
import io.jgoerner.s3.domain.Object;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Repository
|
||||
@Log4j2
|
||||
public class S3Repository
|
||||
implements CreateBucket,
|
||||
DeleteBucket,
|
||||
ListObjects,
|
||||
SaveObject,
|
||||
MakeObjectPublic,
|
||||
MakeObjectPrivate,
|
||||
DeleteObject,
|
||||
CreatePresignedUrl,
|
||||
SetVisibilityInObjectLifecycle,
|
||||
RemoveVisibilityInObjectLifecycle {
|
||||
|
||||
private final AmazonS3Client s3Client;
|
||||
|
||||
public S3Repository(AmazonS3Client s3Client) {
|
||||
this.s3Client = s3Client;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void create(String bucket) {
|
||||
// send bucket creation request
|
||||
s3Client.createBucket(bucket);
|
||||
log.info("Request to create " + bucket + " sent");
|
||||
|
||||
// assure that bucket is available
|
||||
s3Client.waiters().bucketExists().run(new WaiterParameters<>(new HeadBucketRequest(bucket)));
|
||||
log.info("Bucket " + bucket + " is ready");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String bucket) {
|
||||
// send deletion request
|
||||
s3Client.deleteBucket(bucket);
|
||||
log.info("Request to delete " + bucket + " sent");
|
||||
|
||||
// assure bucket is deleted
|
||||
s3Client.waiters().bucketNotExists().run(new WaiterParameters(new HeadBucketRequest(bucket)));
|
||||
log.info("Bucket " + bucket + " is deleted");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Object> listObjectsInBucket(String bucket) {
|
||||
var items =
|
||||
s3Client.listObjectsV2(bucket).getObjectSummaries().stream()
|
||||
.parallel()
|
||||
.map(S3ObjectSummary::getKey)
|
||||
.map(key -> mapS3ToObject(bucket, key))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
log.info("Found " + items.size() + " objects in the bucket " + bucket);
|
||||
return items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object safe(String bucket, String key, String name, InputStream payload) {
|
||||
var metadata = new ObjectMetadata();
|
||||
metadata.addUserMetadata("name", name);
|
||||
s3Client.putObject(bucket, key, payload, metadata);
|
||||
log.info("Sent the request");
|
||||
return Object.builder().name(name).key(key).url(s3Client.getUrl(bucket, key)).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void makePublic(String bucket, String key) {
|
||||
s3Client.setObjectAcl(bucket, key, CannedAccessControlList.PublicRead);
|
||||
log.info("Sent request to make object in bucket " + bucket + " with key " + key + " public");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void makePrivate(String bucket, String key) {
|
||||
s3Client.setObjectAcl(bucket, key, CannedAccessControlList.BucketOwnerFullControl);
|
||||
log.info("Sent request to make object in bucket " + bucket + " with key " + key + " private");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String bucket, String key) {
|
||||
s3Client.deleteObject(bucket, key);
|
||||
log.info("Sent request to delete file with key " + key + " in bucket " + bucket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL createURL(String bucket, String key, Long duration) {
|
||||
var date = new Date(new Date().getTime() + duration * 1000); // 1 s * 1000 ms/s
|
||||
var url = s3Client.generatePresignedUrl(bucket, key, date);
|
||||
log.info("Generated the signature " + url);
|
||||
return url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisibility(String bucket, Integer ttlInDays) {
|
||||
s3Client.setBucketLifecycleConfiguration(
|
||||
bucket,
|
||||
new BucketLifecycleConfiguration()
|
||||
.withRules(
|
||||
new BucketLifecycleConfiguration.Rule()
|
||||
.withId("custom-expiration-id")
|
||||
.withFilter(new LifecycleFilter())
|
||||
.withStatus(BucketLifecycleConfiguration.ENABLED)
|
||||
.withExpirationInDays(ttlInDays)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeVisibility(String bucket) {
|
||||
s3Client.deleteBucketLifecycleConfiguration(bucket);
|
||||
}
|
||||
|
||||
private Object mapS3ToObject(String bucket, String key) {
|
||||
|
||||
return Object.builder()
|
||||
.name(s3Client.getObjectMetadata(bucket, key).getUserMetaDataOf("name"))
|
||||
.key(key)
|
||||
.url(s3Client.getUrl(bucket, key))
|
||||
.isPublic(
|
||||
s3Client.getObjectAcl(bucket, key).getGrantsAsList().stream()
|
||||
.anyMatch(grant -> grant.equals(S3Repository.publicObjectReadGrant())))
|
||||
.build();
|
||||
}
|
||||
|
||||
private static Grant publicObjectReadGrant() {
|
||||
return new Grant(
|
||||
GroupGrantee.parseGroupGrantee(GroupGrantee.AllUsers.getIdentifier()), Permission.Read);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package io.jgoerner.s3.application.port.in.object;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
public interface CreateLink {
|
||||
URL createLink(String space, String key, Long duration);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package io.jgoerner.s3.application.port.in.object;
|
||||
|
||||
import io.jgoerner.s3.domain.Object;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface GetAllObjects {
|
||||
List<Object> getAllObjects(String space);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package io.jgoerner.s3.application.port.in.object;
|
||||
|
||||
public interface RemoveObject {
|
||||
void delete(String space, String key);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package io.jgoerner.s3.application.port.in.object;
|
||||
|
||||
import io.jgoerner.s3.domain.ObjectPartial;
|
||||
import io.jgoerner.s3.domain.Object;
|
||||
|
||||
public interface UpdateObject {
|
||||
Object update(String space, String key, ObjectPartial updates);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package io.jgoerner.s3.application.port.in.object;
|
||||
|
||||
import io.jgoerner.s3.domain.Object;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
public interface UploadObject {
|
||||
Object upload(String space, String name, InputStream payload);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package io.jgoerner.s3.application.port.in.space;
|
||||
|
||||
import io.jgoerner.s3.domain.Space;
|
||||
|
||||
public interface CreateSpace {
|
||||
Space create(String name);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package io.jgoerner.s3.application.port.in.space;
|
||||
|
||||
public interface ForceRemoveSpace {
|
||||
void forceRemove(String space);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package io.jgoerner.s3.application.port.in.space;
|
||||
|
||||
import io.jgoerner.s3.domain.Space;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface GetAllSpaces {
|
||||
List<Space> getAll();
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package io.jgoerner.s3.application.port.in.space;
|
||||
|
||||
public interface RemoveSpace {
|
||||
void remove(String space);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package io.jgoerner.s3.application.port.in.space;
|
||||
|
||||
public interface RemoveTTL {
|
||||
void removeTTL(String space);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package io.jgoerner.s3.application.port.in.space;
|
||||
|
||||
public interface SetTTL {
|
||||
void setTTL(String space, Integer ttlInDays);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package io.jgoerner.s3.application.port.out.bucket;
|
||||
|
||||
public interface CreateBucket {
|
||||
void create(String bucket);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package io.jgoerner.s3.application.port.out.bucket;
|
||||
|
||||
public interface DeleteBucket {
|
||||
void delete(String bucket);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package io.jgoerner.s3.application.port.out.bucket;
|
||||
|
||||
import io.jgoerner.s3.domain.Object;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ListObjects {
|
||||
List<Object> listObjectsInBucket(String bucket);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package io.jgoerner.s3.application.port.out.bucket;
|
||||
|
||||
public interface RemoveVisibilityInObjectLifecycle {
|
||||
void removeVisibility(String bucket);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package io.jgoerner.s3.application.port.out.bucket;
|
||||
|
||||
public interface SetVisibilityInObjectLifecycle {
|
||||
void setVisibility(String bucket, Integer ttlInDays);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package io.jgoerner.s3.application.port.out.object;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
public interface CreatePresignedUrl {
|
||||
URL createURL(String bucket, String key, Long duration);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package io.jgoerner.s3.application.port.out.object;
|
||||
|
||||
public interface DeleteObject {
|
||||
void delete(String bucket, String key);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package io.jgoerner.s3.application.port.out.object;
|
||||
|
||||
public interface MakeObjectPrivate {
|
||||
void makePrivate(String bucket, String key);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package io.jgoerner.s3.application.port.out.object;
|
||||
|
||||
public interface MakeObjectPublic {
|
||||
void makePublic(String bucket, String key);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package io.jgoerner.s3.application.port.out.object;
|
||||
|
||||
import io.jgoerner.s3.domain.Object;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
public interface SaveObject {
|
||||
Object safe(String bucket, String key, String name, InputStream payload);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package io.jgoerner.s3.application.port.out.space;
|
||||
|
||||
public interface CheckSpaceExistence {
|
||||
boolean doesExist(String name);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package io.jgoerner.s3.application.port.out.space;
|
||||
|
||||
public interface DeleteSpace {
|
||||
void delete(String name);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package io.jgoerner.s3.application.port.out.space;
|
||||
|
||||
public interface ResolveSpaceName {
|
||||
String resolve(String name);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package io.jgoerner.s3.application.port.out.space;
|
||||
|
||||
import io.jgoerner.s3.domain.Space;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface RetrieveAllSpaces {
|
||||
List<Space> findAll();
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package io.jgoerner.s3.application.port.out.space;
|
||||
|
||||
import io.jgoerner.s3.domain.Space;
|
||||
|
||||
public interface RetrieveSpaceByName {
|
||||
Space retrieveByName(String name);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package io.jgoerner.s3.application.port.out.space;
|
||||
|
||||
import io.jgoerner.s3.domain.Space;
|
||||
|
||||
public interface SaveSpace {
|
||||
Space save(Space name);
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package io.jgoerner.s3.application.service;
|
||||
|
||||
import io.jgoerner.s3.application.port.in.object.CreateLink;
|
||||
import io.jgoerner.s3.application.port.in.object.RemoveObject;
|
||||
import io.jgoerner.s3.application.port.in.object.UpdateObject;
|
||||
import io.jgoerner.s3.application.port.in.object.UploadObject;
|
||||
import io.jgoerner.s3.application.port.out.object.*;
|
||||
import io.jgoerner.s3.application.port.out.space.ResolveSpaceName;
|
||||
import io.jgoerner.s3.domain.Object;
|
||||
import io.jgoerner.s3.domain.ObjectPartial;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
@Log4j2
|
||||
public class ObjectService implements UploadObject, UpdateObject, RemoveObject, CreateLink {
|
||||
|
||||
private final ResolveSpaceName bucketNameResolver;
|
||||
private final SaveObject objectSaver;
|
||||
private final MakeObjectPublic objectPublicMaker;
|
||||
private final MakeObjectPrivate objectPrivateMaker;
|
||||
private final DeleteObject objectDeleter;
|
||||
private final CreatePresignedUrl presignedUrlCreator;
|
||||
|
||||
public ObjectService(
|
||||
ResolveSpaceName bucketNameResolver,
|
||||
SaveObject objectSaver,
|
||||
MakeObjectPublic objectPublicMaker,
|
||||
MakeObjectPrivate objectPrivateMaker,
|
||||
DeleteObject objectDeleter,
|
||||
CreatePresignedUrl presignedUrlCreator) {
|
||||
this.bucketNameResolver = bucketNameResolver;
|
||||
this.objectSaver = objectSaver;
|
||||
this.objectPublicMaker = objectPublicMaker;
|
||||
this.objectPrivateMaker = objectPrivateMaker;
|
||||
this.objectDeleter = objectDeleter;
|
||||
this.presignedUrlCreator = presignedUrlCreator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object upload(String space, String name, InputStream payload) {
|
||||
// check if bucket exists
|
||||
var bucket = bucketNameResolver.resolve(space);
|
||||
|
||||
// generate a id & store in lookup table
|
||||
var key = UUID.randomUUID().toString();
|
||||
|
||||
// save
|
||||
log.info(
|
||||
"Going to upload the file into to "
|
||||
+ bucket
|
||||
+ "/"
|
||||
+ key
|
||||
+ " with metadata name of "
|
||||
+ name);
|
||||
|
||||
return objectSaver.safe(bucket, key, name, payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object update(String space, String key, ObjectPartial updates) {
|
||||
var bucket = bucketNameResolver.resolve(space);
|
||||
|
||||
if (updates.getIsPublic() != null) {
|
||||
if (updates.getIsPublic()) {
|
||||
log.info("going to open up to public");
|
||||
objectPublicMaker.makePublic(bucket, key);
|
||||
} else {
|
||||
log.info("going to remove public access");
|
||||
objectPrivateMaker.makePrivate(bucket, key);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String space, String key) {
|
||||
var bucket = bucketNameResolver.resolve(space);
|
||||
|
||||
log.info("Going to delete the file with the key " + key + " in the bucket " + bucket);
|
||||
|
||||
objectDeleter.delete(bucket, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL createLink(String space, String key, Long duration) {
|
||||
var bucket = bucketNameResolver.resolve(space);
|
||||
|
||||
log.info(
|
||||
"Going to generate a link for the file "
|
||||
+ key
|
||||
+ " in bucket "
|
||||
+ bucket
|
||||
+ " with visibility duration of "
|
||||
+ duration
|
||||
+ " seconds");
|
||||
|
||||
return presignedUrlCreator.createURL(bucket, key, duration);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
package io.jgoerner.s3.application.service;
|
||||
|
||||
import io.jgoerner.s3.application.port.in.object.GetAllObjects;
|
||||
import io.jgoerner.s3.application.port.in.object.RemoveObject;
|
||||
import io.jgoerner.s3.application.port.in.space.*;
|
||||
import io.jgoerner.s3.application.port.out.bucket.*;
|
||||
import io.jgoerner.s3.application.port.out.object.DeleteObject;
|
||||
import io.jgoerner.s3.application.port.out.space.*;
|
||||
import io.jgoerner.s3.domain.Object;
|
||||
import io.jgoerner.s3.domain.Space;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
@Log4j2
|
||||
public class SpaceService
|
||||
implements CreateSpace,
|
||||
GetAllSpaces,
|
||||
GetAllObjects,
|
||||
RemoveSpace,
|
||||
ForceRemoveSpace,
|
||||
SetTTL,
|
||||
RemoveTTL {
|
||||
|
||||
private final CheckSpaceExistence spaceExistenceChecker;
|
||||
private final SaveSpace spaceSaver;
|
||||
private final RetrieveAllSpaces allSpaceRetriever;
|
||||
private final CreateBucket bucketCreator;
|
||||
private final ResolveSpaceName bucketNameResolver;
|
||||
private final DeleteBucket bucketDeleter;
|
||||
private final DeleteSpace spaceDeleter;
|
||||
private final ListObjects objectLister;
|
||||
private final DeleteObject objectDeleter;
|
||||
private final SetVisibilityInObjectLifecycle objectLifecycleVisibilitySetter;
|
||||
private final RemoveVisibilityInObjectLifecycle objectLifecycleVisibilityRemover;
|
||||
private final RetrieveSpaceByName spaceByNameRetriever;
|
||||
|
||||
public SpaceService(
|
||||
CheckSpaceExistence spaceExistenceChecker,
|
||||
SaveSpace spaceSaver,
|
||||
RetrieveAllSpaces allSpaceRetriever,
|
||||
CreateBucket bucketCreator,
|
||||
ResolveSpaceName bucketNameResolver,
|
||||
DeleteBucket bucketDeleter,
|
||||
DeleteSpace spaceDeleter,
|
||||
ListObjects objectLister,
|
||||
RemoveObject objectRemover,
|
||||
DeleteObject objectDeleter,
|
||||
SetVisibilityInObjectLifecycle objectLifecycleVisibilitySetter,
|
||||
RemoveVisibilityInObjectLifecycle objectLifecycleVisibilityRemover,
|
||||
RetrieveSpaceByName spaceByNameRetriever) {
|
||||
this.spaceExistenceChecker = spaceExistenceChecker;
|
||||
this.spaceSaver = spaceSaver;
|
||||
this.allSpaceRetriever = allSpaceRetriever;
|
||||
this.bucketNameResolver = bucketNameResolver;
|
||||
this.bucketCreator = bucketCreator;
|
||||
this.bucketDeleter = bucketDeleter;
|
||||
this.spaceDeleter = spaceDeleter;
|
||||
this.objectLister = objectLister;
|
||||
this.objectDeleter = objectDeleter;
|
||||
this.objectLifecycleVisibilitySetter = objectLifecycleVisibilitySetter;
|
||||
this.objectLifecycleVisibilityRemover = objectLifecycleVisibilityRemover;
|
||||
this.spaceByNameRetriever = spaceByNameRetriever;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Space create(String name) {
|
||||
// check if bucket exists
|
||||
if (spaceExistenceChecker.doesExist(name)) {
|
||||
log.info("Space " + name + " does already exist");
|
||||
return null;
|
||||
}
|
||||
|
||||
// create
|
||||
Space space = new Space(name, "spring-boot-s3-tutorial-" + UUID.randomUUID().toString(), null);
|
||||
log.info("Mapped space to bucket " + space);
|
||||
bucketCreator.create(space.getBucket());
|
||||
|
||||
// create bucket meta
|
||||
return this.spaceSaver.save(space);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Space> getAll() {
|
||||
var buckets = allSpaceRetriever.findAll();
|
||||
log.info("Found " + buckets.size() + " buckets");
|
||||
return buckets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Object> getAllObjects(String space) {
|
||||
// get bucket from H2
|
||||
var bucket = bucketNameResolver.resolve(space);
|
||||
|
||||
// return all files in bucket
|
||||
return objectLister.listObjectsInBucket(bucket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(String space) {
|
||||
// get bucket from H2
|
||||
var bucket = bucketNameResolver.resolve(space);
|
||||
|
||||
// delete from S3
|
||||
bucketDeleter.delete(bucket);
|
||||
|
||||
// delete from H2
|
||||
spaceDeleter.delete(space);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forceRemove(String space) {
|
||||
// get bucket from H2
|
||||
var bucket = bucketNameResolver.resolve(space);
|
||||
|
||||
// empty bucket
|
||||
getAllObjects(space).stream()
|
||||
.peek(log::info)
|
||||
.forEach(object -> objectDeleter.delete(bucket, object.getKey()));
|
||||
|
||||
// get rid of bucket
|
||||
remove(space);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTTL(String space, Integer ttlInDays) {
|
||||
var bucket = bucketNameResolver.resolve(space);
|
||||
log.info("Going to adjust the TTL for the bucket " + bucket + " to " + ttlInDays + " day(s)");
|
||||
|
||||
// S3
|
||||
objectLifecycleVisibilitySetter.setVisibility(bucket, ttlInDays);
|
||||
|
||||
// H2
|
||||
var spaceEntity = spaceByNameRetriever.retrieveByName(space);
|
||||
spaceEntity.setTtl(ttlInDays);
|
||||
spaceSaver.save(spaceEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTTL(String space) {
|
||||
var bucket = bucketNameResolver.resolve(space);
|
||||
log.info("Going to remove TTL policy for bucket " + bucket);
|
||||
|
||||
// S3
|
||||
objectLifecycleVisibilityRemover.removeVisibility(bucket);
|
||||
|
||||
// H2
|
||||
var spaceEntity = spaceByNameRetriever.retrieveByName(space);
|
||||
spaceEntity.setTtl(null);
|
||||
spaceSaver.save(spaceEntity);
|
||||
}
|
||||
}
|
||||
15
aws/s3/src/main/java/io/jgoerner/s3/domain/Object.java
Normal file
15
aws/s3/src/main/java/io/jgoerner/s3/domain/Object.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package io.jgoerner.s3.domain;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Value;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
@Value
|
||||
@Builder
|
||||
public class Object {
|
||||
String name;
|
||||
String key;
|
||||
URL url;
|
||||
@Builder.Default boolean isPublic = false;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package io.jgoerner.s3.domain;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
public class ObjectPartial {
|
||||
Boolean isPublic;
|
||||
}
|
||||
12
aws/s3/src/main/java/io/jgoerner/s3/domain/Space.java
Normal file
12
aws/s3/src/main/java/io/jgoerner/s3/domain/Space.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package io.jgoerner.s3.domain;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
public class Space {
|
||||
String name;
|
||||
String bucket;
|
||||
Integer ttl;
|
||||
}
|
||||
12
aws/s3/src/main/java/io/jgoerner/s3/domain/SpacePartial.java
Normal file
12
aws/s3/src/main/java/io/jgoerner/s3/domain/SpacePartial.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package io.jgoerner.s3.domain;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
public class SpacePartial {
|
||||
Integer ttlInDays;
|
||||
}
|
||||
36
aws/s3/src/main/resources/application.yaml
Normal file
36
aws/s3/src/main/resources/application.yaml
Normal file
@@ -0,0 +1,36 @@
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:h2:./data/metadb
|
||||
username: admin
|
||||
h2:
|
||||
console:
|
||||
enabled: true
|
||||
path: /h2
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: update
|
||||
# https://stackoverflow.com/questions/40057057/spring-boot-and-thymeleaf-hot-swap-templates-and-resources-once-again
|
||||
thymeleaf:
|
||||
cache: false
|
||||
templates_root: src/main/resources/templates/
|
||||
servlet:
|
||||
multipart:
|
||||
max-file-size: 15MB
|
||||
max-request-size: 15MB
|
||||
|
||||
cloud:
|
||||
aws:
|
||||
region:
|
||||
static: eu-central-1
|
||||
stack:
|
||||
auto: false
|
||||
credentials:
|
||||
profile-name: dev
|
||||
|
||||
# https://docs.spring.io/spring-cloud-aws/docs/2.2.3.RELEASE/reference/html/#amazon-sdk-configuration
|
||||
logging:
|
||||
level:
|
||||
com:
|
||||
amazonaws:
|
||||
util:
|
||||
EC2MetadataUtils: error
|
||||
1
aws/s3/src/main/resources/static/css/bulma.min.css
vendored
Normal file
1
aws/s3/src/main/resources/static/css/bulma.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
7
aws/s3/src/main/resources/templates/fragments/head.html
Normal file
7
aws/s3/src/main/resources/templates/fragments/head.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<head th:fragment="head" xmlns:th="http://www.w3.org/1999/xhtml">
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>File Share</title>
|
||||
<link rel="stylesheet" th:href="@{/css/bulma.min.css}">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/css/all.min.css">
|
||||
</head>
|
||||
43
aws/s3/src/main/resources/templates/fragments/navbar.html
Normal file
43
aws/s3/src/main/resources/templates/fragments/navbar.html
Normal file
@@ -0,0 +1,43 @@
|
||||
<nav class="navbar" th:fragment="navbar" xmlns:th="http://www.w3.org/1999/xhtml">
|
||||
<div class=" container">
|
||||
|
||||
<div class="navbar-brand">
|
||||
<a class="navbar-item" href="/">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="fas fa-home"></i>
|
||||
</span>
|
||||
<span>Home</span>
|
||||
</span>
|
||||
</a>
|
||||
<a class="navbar-item" th:href="@{~/space}">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="fas fa-folder-open"></i>
|
||||
</span>
|
||||
<span>Spaces</span>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="navbar-menu">
|
||||
<div class="navbar-end">
|
||||
<a class="navbar-item" href="h2" target="_blank">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="fas fa-database"></i>
|
||||
</span>
|
||||
<span>DB</span>
|
||||
</span>
|
||||
</a>
|
||||
<span class="navbar-item">
|
||||
<a class="button is-primary" href="https://github.com/jgoerner" target="_blank">
|
||||
<span class="icon">
|
||||
<i class="fab fa-github"></i>
|
||||
</span>
|
||||
<span>GitHub</span>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -0,0 +1,23 @@
|
||||
<script th:inline="javascript" th:fragment="script" xmlns:th="http://www.w3.org/1999/xhtml">
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
(document.querySelectorAll('.notification .delete') || []).forEach(($delete) => {
|
||||
var $notification = $delete.parentNode;
|
||||
|
||||
$delete.addEventListener('click', () => {
|
||||
$notification.parentNode.removeChild($notification);
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<div th:fragment="notification" xmlns:th="http://www.w3.org/1999/xhtml">
|
||||
|
||||
<div class="notification" th:if="${success}">
|
||||
<button class="delete"></button>
|
||||
<p class="has-text-grey-light" th:text="${success}"/>
|
||||
</div>
|
||||
<div class="notification is-warning is-light" th:if="${warn}">
|
||||
<button class="delete"></button>
|
||||
<p th:text="${warn}"/>
|
||||
</div>
|
||||
</div>
|
||||
24
aws/s3/src/main/resources/templates/index.html
Normal file
24
aws/s3/src/main/resources/templates/index.html
Normal file
@@ -0,0 +1,24 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:th="http://www.thymeleaf.org">
|
||||
<head th:replace="fragments/head :: head"/>
|
||||
<body>
|
||||
|
||||
<div th:replace="fragments/navbar :: navbar"/>
|
||||
|
||||
<section class="hero is-primary is-fullheight-with-navbar is-bold">
|
||||
<div class="hero-body">
|
||||
<div class="container has-text-centered">
|
||||
<h1 class="title">
|
||||
Private File Share
|
||||
</h1>
|
||||
<h2 class="subtitle">
|
||||
powered by Spring Boot & Simple Storage Service (S3)
|
||||
</h2>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
49
aws/s3/src/main/resources/templates/object-form.html
Normal file
49
aws/s3/src/main/resources/templates/object-form.html
Normal file
@@ -0,0 +1,49 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:th="http://www.thymeleaf.org">
|
||||
<head th:replace="fragments/head :: head"/>
|
||||
<body>
|
||||
|
||||
<div th:replace="fragments/navbar :: navbar"/>
|
||||
|
||||
<section class="hero is-fullheight-with-navbar is-primary is-bold">
|
||||
|
||||
<section class="hero-body columns is-centered m-0">
|
||||
<div class="column is-half ">
|
||||
<form action="#" th:action="@{/space/__${space}__/object-form}" th:object="${object}" method="post"
|
||||
enctype="multipart/form-data">
|
||||
<div class="field">
|
||||
<div class="control has-icons-left">
|
||||
<input class="input is-medium" type="text" th:field="*{name}" placeholder="Name of your File">
|
||||
<span class="icon is-small is-left">
|
||||
<i class="fas fa-heading"></i>
|
||||
</span>
|
||||
</div>
|
||||
<p class="help">Human readable name of the file</p>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input type="file" name="file"/>
|
||||
</div>
|
||||
<p class="help">Human readable name of the file</p>
|
||||
</div>
|
||||
|
||||
<div class="field is-grouped is-grouped-centered">
|
||||
<p class="control">
|
||||
<button class="button is-primary is-outlined is-inverted" type="submit">
|
||||
Submit
|
||||
</button>
|
||||
</p>
|
||||
<p class="control">
|
||||
<a class="button is-primary is-outlined is-inverted" href="#">
|
||||
Cancel
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
81
aws/s3/src/main/resources/templates/space-detail.html
Normal file
81
aws/s3/src/main/resources/templates/space-detail.html
Normal file
@@ -0,0 +1,81 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:th="http://www.thymeleaf.org">
|
||||
<head th:replace="fragments/head :: head"/>
|
||||
<body>
|
||||
|
||||
<div th:replace="fragments/navbar :: navbar"/>
|
||||
|
||||
<section class="hero is-fullheight-with-navbar is-primary is-bold">
|
||||
|
||||
<section class="hero-body columns is-centered m-0">
|
||||
<div class="column is-half has-text-centered">
|
||||
<div th:replace="fragments/notification :: notification"/>
|
||||
<div th:each="object: ${objects}" class="card m-4">
|
||||
<div class="card-content">
|
||||
<div class="media">
|
||||
<div class="media-content">
|
||||
<p class="title is-4 has-text-dark" th:text="${object.name}"/>
|
||||
<p class="subtitle is-6 has-text-grey-light mb-1" th:text="${object.key}"/>
|
||||
<p th:if="${object.isPublic}" class="subtitle is-6 has-text-grey-light">
|
||||
Publicly accessible
|
||||
</p>
|
||||
<p th:unless="${object.isPublic}" class="subtitle is-6 has-text-grey-light">Private</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<a th:href="${object.url}" target="_blank"
|
||||
class="card-footer-item has-text-info">
|
||||
<span class="icon is-small pr-3">
|
||||
<i class="fas fa-download"></i>
|
||||
</span>
|
||||
<span>Download</span>
|
||||
</a>
|
||||
<a th:if="${object.isPublic}" th:href="@{~/space/__${space}__/make-private/__${object.key}__}"
|
||||
class="card-footer-item has-text-info">
|
||||
<span class="icon is-small pr-3">
|
||||
<i class="fas fa-eye-slash"></i>
|
||||
</span>
|
||||
<span>Make Private</span>
|
||||
</a>
|
||||
<a th:unless="${object.isPublic}" th:href="@{~/space/__${space}__/make-public/__${object.key}__}"
|
||||
class="card-footer-item has-text-info">
|
||||
<span class="icon is-small pr-3">
|
||||
<i class="fas fa-eye"></i>
|
||||
</span>
|
||||
<span>Make Public</span>
|
||||
</a>
|
||||
<a th:href="@{~/space/__${space}__/magic/__${object.key}__}"
|
||||
class="card-footer-item has-text-info">
|
||||
<span class="icon is-small pr-3">
|
||||
<i class="fas fa-magic"></i>
|
||||
</span>
|
||||
<span>Magic Link</span>
|
||||
</a>
|
||||
<a th:href="@{~/space/__${space}__/delete/__${object.key}__}"
|
||||
class="card-footer-item has-text-danger">
|
||||
<span class="icon is-small pr-3">
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
</span>
|
||||
<span>Delete</span>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<button class="button is-medium is-primary is-inverted is-outlined ">
|
||||
<a th:href="@{~/space/__${space}__/object-form}">
|
||||
<span class="icon is-small">
|
||||
<i class="fas fa-upload"></i>
|
||||
</span>
|
||||
<span>Upload File</span>
|
||||
</a>
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<script th:replace="fragments/notification :: script"/>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
41
aws/s3/src/main/resources/templates/space-form.html
Normal file
41
aws/s3/src/main/resources/templates/space-form.html
Normal file
@@ -0,0 +1,41 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:th="http://www.thymeleaf.org">
|
||||
<head th:replace="fragments/head :: head"/>
|
||||
<body>
|
||||
|
||||
<div th:replace="fragments/navbar :: navbar"/>
|
||||
|
||||
<section class="hero is-fullheight-with-navbar is-primary is-bold">
|
||||
|
||||
<section class="hero-body columns is-centered m-0">
|
||||
<div class="column is-half ">
|
||||
<form action="#" th:action="@{/space-form}" th:object="${space}" method="post">
|
||||
<div class="field">
|
||||
<div class="control has-icons-left">
|
||||
<input class="input is-medium" type="text" th:field="*{name}" placeholder="Name of your space">
|
||||
<span class="icon is-small is-left">
|
||||
<i class="fas fa-heading"></i>
|
||||
</span>
|
||||
</div>
|
||||
<p class="help">Human readable name of the bucket</p>
|
||||
|
||||
</div>
|
||||
<div class="field is-grouped is-grouped-centered">
|
||||
<p class="control">
|
||||
<button class="button is-primary is-outlined is-inverted" type="submit">
|
||||
Submit
|
||||
</button>
|
||||
</p>
|
||||
<p class="control">
|
||||
<a class="button is-primary is-outlined is-inverted" href="space">
|
||||
Cancel
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
73
aws/s3/src/main/resources/templates/space-overview.html
Normal file
73
aws/s3/src/main/resources/templates/space-overview.html
Normal file
@@ -0,0 +1,73 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:th="http://www.thymeleaf.org">
|
||||
<head th:replace="fragments/head :: head"/>
|
||||
|
||||
<body>
|
||||
<div th:replace="fragments/navbar :: navbar"/>
|
||||
|
||||
<section class="hero is-fullheight-with-navbar is-primary is-bold">
|
||||
|
||||
<section class="hero-body columns is-centered m-0">
|
||||
<div class="column is-half has-text-centered">
|
||||
<div th:replace="fragments/notification :: notification"/>
|
||||
<div th:each="space: ${spaces}" class="card m-4">
|
||||
<div class="card-content">
|
||||
<div class="media">
|
||||
<div class="media-content">
|
||||
<p class="title is-4 has-text-dark" th:text="${space.name}"/>
|
||||
<p class="subtitle is-6 has-text-grey-light mb-1" th:text="${space.bucket}"/>
|
||||
<p th:if=${space.ttl} class="subtitle is-6 has-text-grey-light"
|
||||
th:text="${'Only storing files for ' + space.ttl + ' days'}"/>
|
||||
<p th:unless=${space.ttl} class="subtitle is-6 has-text-grey-light"
|
||||
>Permanent Storage</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<a th:href="@{space/__${space.name}__}"
|
||||
class="card-footer-item has-text-info">
|
||||
<span class="icon is-small pr-3">
|
||||
<i class="fas fa-info"></i>
|
||||
</span>
|
||||
<span>Details</span>
|
||||
</a>
|
||||
<a th:unless="${space.ttl}" th:href="@{space/temporary/__${space.name}__}"
|
||||
class="card-footer-item has-text-info">
|
||||
<span class="icon is-small pr-3">
|
||||
<i class="fas fa-hourglass-half"></i>
|
||||
</span>
|
||||
<span>Make Temporary</span>
|
||||
</a>
|
||||
<a th:if="${space.ttl}" th:href="@{space/permanent/__${space.name}__}"
|
||||
class="card-footer-item has-text-info">
|
||||
<span class="icon is-small pr-3">
|
||||
<i class="fas fa-infinity"></i>
|
||||
</span>
|
||||
<span>Make Permanent</span>
|
||||
</a>
|
||||
<a th:href="@{space/delete/__${space.name}__}"
|
||||
class="card-footer-item has-text-danger">
|
||||
<span class="icon is-small pr-3">
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
</span>
|
||||
<span>Delete</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<button class="button is-medium is-primary is-inverted is-outlined ">
|
||||
<a href="space-form">
|
||||
<span class="icon is-small">
|
||||
<i class="fas fa-plus-square"></i>
|
||||
</span>
|
||||
<span>New Space</span>
|
||||
</a>
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<script th:replace="fragments/notification :: script"/>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
13
aws/s3/src/test/java/io/jgoerner/s3/S3ApplicationTests.java
Normal file
13
aws/s3/src/test/java/io/jgoerner/s3/S3ApplicationTests.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package io.jgoerner.s3;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest
|
||||
class S3ApplicationTests {
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
}
|
||||
|
||||
}
|
||||
16
build-all.sh
16
build-all.sh
@@ -86,6 +86,16 @@ if [[ "$MODULE" == "module5" ]]
|
||||
then
|
||||
# ADD NEW MODULES HERE
|
||||
# (add new modules above the rest so you get quicker feedback if it fails)
|
||||
build_maven_module "core-java/service-provider-interface"
|
||||
build_gradle_module "spring-boot/hazelcast/hazelcast-embedded-cache"
|
||||
build_gradle_module "spring-boot/hazelcast/hazelcast-client-server"
|
||||
build_maven_module "core-java/heapdump"
|
||||
build_gradle_module "aws/s3"
|
||||
build_maven_module "graphql"
|
||||
build_gradle_module "spring-boot/exception-handling"
|
||||
build_maven_module "spring-boot/spring-boot-elasticsearch"
|
||||
build_gradle_module "spring-boot/spring-boot-mocking-modules"
|
||||
build_gradle_module "spring-boot/specification"
|
||||
build_gradle_module "spring-boot/hibernate-search"
|
||||
build_maven_module "core-java/streams/fileswithstreams"
|
||||
build_maven_module "spring-boot/spring-boot-health-check"
|
||||
@@ -97,8 +107,6 @@ then
|
||||
build_gradle_module "spring-boot/bean-lifecycle"
|
||||
build_gradle_module "spring-boot/request-response/client"
|
||||
build_gradle_module "spring-boot/request-response/server"
|
||||
build_gradle_module "spring-boot/hazelcast/hazelcast-embedded-cache"
|
||||
build_gradle_module "spring-boot/hazelcast/hazelcast-client-server"
|
||||
|
||||
echo ""
|
||||
echo "+++"
|
||||
@@ -109,6 +117,7 @@ fi
|
||||
|
||||
if [[ "$MODULE" == "module1" ]]
|
||||
then
|
||||
build_maven_module "spring-boot/spring-boot-cookie-demo"
|
||||
build_maven_module "spring-boot/spring-boot-kafka"
|
||||
build_gradle_module "spring-boot/spring-boot-springdoc"
|
||||
build_maven_module "spring-boot/dependency-injection"
|
||||
@@ -135,6 +144,7 @@ then
|
||||
build_maven_module "resilience4j/ratelimiter"
|
||||
build_maven_module "resilience4j/timelimiter"
|
||||
build_maven_module "resilience4j/bulkhead"
|
||||
build_maven_module "resilience4j/circuitbreaker"
|
||||
build_gradle_module "spring-data/spring-data-jdbc-converter"
|
||||
build_gradle_module "reactive"
|
||||
build_gradle_module "junit/assumptions"
|
||||
@@ -187,4 +197,4 @@ then
|
||||
echo "+++"
|
||||
echo "+++ MODULE 4 SUCCESSFUL"
|
||||
echo "+++"
|
||||
fi
|
||||
fi
|
||||
|
||||
BIN
core-java/heapdump/.DS_Store
vendored
Normal file
BIN
core-java/heapdump/.DS_Store
vendored
Normal file
Binary file not shown.
117
core-java/heapdump/.mvn/wrapper/MavenWrapperDownloader.java
vendored
Normal file
117
core-java/heapdump/.mvn/wrapper/MavenWrapperDownloader.java
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2007-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.Properties;
|
||||
|
||||
public class MavenWrapperDownloader {
|
||||
|
||||
private static final String WRAPPER_VERSION = "0.5.6";
|
||||
/**
|
||||
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
|
||||
*/
|
||||
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
|
||||
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
|
||||
|
||||
/**
|
||||
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
|
||||
* use instead of the default one.
|
||||
*/
|
||||
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
|
||||
".mvn/wrapper/maven-wrapper.properties";
|
||||
|
||||
/**
|
||||
* Path where the maven-wrapper.jar will be saved to.
|
||||
*/
|
||||
private static final String MAVEN_WRAPPER_JAR_PATH =
|
||||
".mvn/wrapper/maven-wrapper.jar";
|
||||
|
||||
/**
|
||||
* Name of the property which should be used to override the default download url for the wrapper.
|
||||
*/
|
||||
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.out.println("- Downloader started");
|
||||
File baseDirectory = new File(args[0]);
|
||||
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
|
||||
|
||||
// If the maven-wrapper.properties exists, read it and check if it contains a custom
|
||||
// wrapperUrl parameter.
|
||||
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
|
||||
String url = DEFAULT_DOWNLOAD_URL;
|
||||
if(mavenWrapperPropertyFile.exists()) {
|
||||
FileInputStream mavenWrapperPropertyFileInputStream = null;
|
||||
try {
|
||||
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
|
||||
Properties mavenWrapperProperties = new Properties();
|
||||
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
|
||||
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
|
||||
} catch (IOException e) {
|
||||
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
|
||||
} finally {
|
||||
try {
|
||||
if(mavenWrapperPropertyFileInputStream != null) {
|
||||
mavenWrapperPropertyFileInputStream.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Ignore ...
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("- Downloading from: " + url);
|
||||
|
||||
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
|
||||
if(!outputFile.getParentFile().exists()) {
|
||||
if(!outputFile.getParentFile().mkdirs()) {
|
||||
System.out.println(
|
||||
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
|
||||
}
|
||||
}
|
||||
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
|
||||
try {
|
||||
downloadFileFromURL(url, outputFile);
|
||||
System.out.println("Done");
|
||||
System.exit(0);
|
||||
} catch (Throwable e) {
|
||||
System.out.println("- Error downloading");
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
|
||||
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
|
||||
String username = System.getenv("MVNW_USERNAME");
|
||||
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
|
||||
Authenticator.setDefault(new Authenticator() {
|
||||
@Override
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
return new PasswordAuthentication(username, password);
|
||||
}
|
||||
});
|
||||
}
|
||||
URL website = new URL(urlString);
|
||||
ReadableByteChannel rbc;
|
||||
rbc = Channels.newChannel(website.openStream());
|
||||
FileOutputStream fos = new FileOutputStream(destination);
|
||||
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
|
||||
fos.close();
|
||||
rbc.close();
|
||||
}
|
||||
|
||||
}
|
||||
BIN
core-java/heapdump/.mvn/wrapper/maven-wrapper.jar
vendored
Normal file
BIN
core-java/heapdump/.mvn/wrapper/maven-wrapper.jar
vendored
Normal file
Binary file not shown.
2
core-java/heapdump/.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
2
core-java/heapdump/.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
|
||||
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
|
||||
3
core-java/heapdump/README.md
Normal file
3
core-java/heapdump/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Related Blog Posts
|
||||
|
||||
* [How to do heap dump analysis](https://reflectoring.io/create-analyze-heapdump/)
|
||||
310
core-java/heapdump/mvnw
vendored
Executable file
310
core-java/heapdump/mvnw
vendored
Executable file
@@ -0,0 +1,310 @@
|
||||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------------
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Maven Start Up Batch script
|
||||
#
|
||||
# Required ENV vars:
|
||||
# ------------------
|
||||
# JAVA_HOME - location of a JDK home dir
|
||||
#
|
||||
# Optional ENV vars
|
||||
# -----------------
|
||||
# M2_HOME - location of maven2's installed home dir
|
||||
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
# e.g. to debug Maven itself, use
|
||||
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
if [ -z "$MAVEN_SKIP_RC" ] ; then
|
||||
|
||||
if [ -f /etc/mavenrc ] ; then
|
||||
. /etc/mavenrc
|
||||
fi
|
||||
|
||||
if [ -f "$HOME/.mavenrc" ] ; then
|
||||
. "$HOME/.mavenrc"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# OS specific support. $var _must_ be set to either true or false.
|
||||
cygwin=false;
|
||||
darwin=false;
|
||||
mingw=false
|
||||
case "`uname`" in
|
||||
CYGWIN*) cygwin=true ;;
|
||||
MINGW*) mingw=true;;
|
||||
Darwin*) darwin=true
|
||||
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
|
||||
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
if [ -x "/usr/libexec/java_home" ]; then
|
||||
export JAVA_HOME="`/usr/libexec/java_home`"
|
||||
else
|
||||
export JAVA_HOME="/Library/Java/Home"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
if [ -r /etc/gentoo-release ] ; then
|
||||
JAVA_HOME=`java-config --jre-home`
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$M2_HOME" ] ; then
|
||||
## resolve links - $0 may be a link to maven's home
|
||||
PRG="$0"
|
||||
|
||||
# need this for relative symlinks
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG="`dirname "$PRG"`/$link"
|
||||
fi
|
||||
done
|
||||
|
||||
saveddir=`pwd`
|
||||
|
||||
M2_HOME=`dirname "$PRG"`/..
|
||||
|
||||
# make it fully qualified
|
||||
M2_HOME=`cd "$M2_HOME" && pwd`
|
||||
|
||||
cd "$saveddir"
|
||||
# echo Using m2 at $M2_HOME
|
||||
fi
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched
|
||||
if $cygwin ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --unix "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
|
||||
fi
|
||||
|
||||
# For Mingw, ensure paths are in UNIX format before anything is touched
|
||||
if $mingw ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME="`(cd "$M2_HOME"; pwd)`"
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
javaExecutable="`which javac`"
|
||||
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
|
||||
# readlink(1) is not available as standard on Solaris 10.
|
||||
readLink=`which readlink`
|
||||
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
|
||||
if $darwin ; then
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
|
||||
else
|
||||
javaExecutable="`readlink -f \"$javaExecutable\"`"
|
||||
fi
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
|
||||
JAVA_HOME="$javaHome"
|
||||
export JAVA_HOME
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$JAVACMD" ] ; then
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
else
|
||||
JAVACMD="`which java`"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
echo "Error: JAVA_HOME is not defined correctly." >&2
|
||||
echo " We cannot execute $JAVACMD" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
echo "Warning: JAVA_HOME environment variable is not set."
|
||||
fi
|
||||
|
||||
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
|
||||
|
||||
# traverses directory structure from process work directory to filesystem root
|
||||
# first directory with .mvn subdirectory is considered project base directory
|
||||
find_maven_basedir() {
|
||||
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
echo "Path not specified to find_maven_basedir"
|
||||
return 1
|
||||
fi
|
||||
|
||||
basedir="$1"
|
||||
wdir="$1"
|
||||
while [ "$wdir" != '/' ] ; do
|
||||
if [ -d "$wdir"/.mvn ] ; then
|
||||
basedir=$wdir
|
||||
break
|
||||
fi
|
||||
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
|
||||
if [ -d "${wdir}" ]; then
|
||||
wdir=`cd "$wdir/.."; pwd`
|
||||
fi
|
||||
# end of workaround
|
||||
done
|
||||
echo "${basedir}"
|
||||
}
|
||||
|
||||
# concatenates all lines of a file
|
||||
concat_lines() {
|
||||
if [ -f "$1" ]; then
|
||||
echo "$(tr -s '\n' ' ' < "$1")"
|
||||
fi
|
||||
}
|
||||
|
||||
BASE_DIR=`find_maven_basedir "$(pwd)"`
|
||||
if [ -z "$BASE_DIR" ]; then
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
##########################################################################################
|
||||
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
# This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
##########################################################################################
|
||||
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found .mvn/wrapper/maven-wrapper.jar"
|
||||
fi
|
||||
else
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
|
||||
fi
|
||||
if [ -n "$MVNW_REPOURL" ]; then
|
||||
jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
|
||||
else
|
||||
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
|
||||
fi
|
||||
while IFS="=" read key value; do
|
||||
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
|
||||
esac
|
||||
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Downloading from: $jarUrl"
|
||||
fi
|
||||
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
|
||||
if $cygwin; then
|
||||
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
|
||||
fi
|
||||
|
||||
if command -v wget > /dev/null; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found wget ... using wget"
|
||||
fi
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
wget "$jarUrl" -O "$wrapperJarPath"
|
||||
else
|
||||
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
|
||||
fi
|
||||
elif command -v curl > /dev/null; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found curl ... using curl"
|
||||
fi
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
curl -o "$wrapperJarPath" "$jarUrl" -f
|
||||
else
|
||||
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
|
||||
fi
|
||||
|
||||
else
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Falling back to using Java to download"
|
||||
fi
|
||||
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
|
||||
# For Cygwin, switch paths to Windows format before running javac
|
||||
if $cygwin; then
|
||||
javaClass=`cygpath --path --windows "$javaClass"`
|
||||
fi
|
||||
if [ -e "$javaClass" ]; then
|
||||
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo " - Compiling MavenWrapperDownloader.java ..."
|
||||
fi
|
||||
# Compiling the Java class
|
||||
("$JAVA_HOME/bin/javac" "$javaClass")
|
||||
fi
|
||||
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||
# Running the downloader
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo " - Running MavenWrapperDownloader.java ..."
|
||||
fi
|
||||
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
##########################################################################################
|
||||
# End of extension
|
||||
##########################################################################################
|
||||
|
||||
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo $MAVEN_PROJECTBASEDIR
|
||||
fi
|
||||
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --path --windows "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
|
||||
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
|
||||
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
|
||||
fi
|
||||
|
||||
# Provide a "standardized" way to retrieve the CLI args that will
|
||||
# work with both Windows and non-Windows executions.
|
||||
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
|
||||
export MAVEN_CMD_LINE_ARGS
|
||||
|
||||
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
exec "$JAVACMD" \
|
||||
$MAVEN_OPTS \
|
||||
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
|
||||
182
core-java/heapdump/mvnw.cmd
vendored
Normal file
182
core-java/heapdump/mvnw.cmd
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||
@REM or more contributor license agreements. See the NOTICE file
|
||||
@REM distributed with this work for additional information
|
||||
@REM regarding copyright ownership. The ASF licenses this file
|
||||
@REM to you under the Apache License, Version 2.0 (the
|
||||
@REM "License"); you may not use this file except in compliance
|
||||
@REM with the License. You may obtain a copy of the License at
|
||||
@REM
|
||||
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||
@REM
|
||||
@REM Unless required by applicable law or agreed to in writing,
|
||||
@REM software distributed under the License is distributed on an
|
||||
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
@REM KIND, either express or implied. See the License for the
|
||||
@REM specific language governing permissions and limitations
|
||||
@REM under the License.
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Maven Start Up Batch script
|
||||
@REM
|
||||
@REM Required ENV vars:
|
||||
@REM JAVA_HOME - location of a JDK home dir
|
||||
@REM
|
||||
@REM Optional ENV vars
|
||||
@REM M2_HOME - location of maven2's installed home dir
|
||||
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
|
||||
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
|
||||
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
@REM e.g. to debug Maven itself, use
|
||||
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
|
||||
@echo off
|
||||
@REM set title of command window
|
||||
title %0
|
||||
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
|
||||
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
|
||||
|
||||
@REM set %HOME% to equivalent of $HOME
|
||||
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
|
||||
|
||||
@REM Execute a user defined script before this one
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
|
||||
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
|
||||
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
|
||||
:skipRcPre
|
||||
|
||||
@setlocal
|
||||
|
||||
set ERROR_CODE=0
|
||||
|
||||
@REM To isolate internal variables from possible post scripts, we use another setlocal
|
||||
@setlocal
|
||||
|
||||
@REM ==== START VALIDATION ====
|
||||
if not "%JAVA_HOME%" == "" goto OkJHome
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME not found in your environment. >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
:OkJHome
|
||||
if exist "%JAVA_HOME%\bin\java.exe" goto init
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME is set to an invalid directory. >&2
|
||||
echo JAVA_HOME = "%JAVA_HOME%" >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
@REM ==== END VALIDATION ====
|
||||
|
||||
:init
|
||||
|
||||
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
|
||||
@REM Fallback to current working directory if not found.
|
||||
|
||||
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
|
||||
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
|
||||
|
||||
set EXEC_DIR=%CD%
|
||||
set WDIR=%EXEC_DIR%
|
||||
:findBaseDir
|
||||
IF EXIST "%WDIR%"\.mvn goto baseDirFound
|
||||
cd ..
|
||||
IF "%WDIR%"=="%CD%" goto baseDirNotFound
|
||||
set WDIR=%CD%
|
||||
goto findBaseDir
|
||||
|
||||
:baseDirFound
|
||||
set MAVEN_PROJECTBASEDIR=%WDIR%
|
||||
cd "%EXEC_DIR%"
|
||||
goto endDetectBaseDir
|
||||
|
||||
:baseDirNotFound
|
||||
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
|
||||
cd "%EXEC_DIR%"
|
||||
|
||||
:endDetectBaseDir
|
||||
|
||||
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
|
||||
|
||||
@setlocal EnableExtensions EnableDelayedExpansion
|
||||
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
|
||||
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
|
||||
|
||||
:endReadAdditionalConfig
|
||||
|
||||
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
|
||||
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
|
||||
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
|
||||
|
||||
FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
|
||||
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
|
||||
)
|
||||
|
||||
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
if exist %WRAPPER_JAR% (
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Found %WRAPPER_JAR%
|
||||
)
|
||||
) else (
|
||||
if not "%MVNW_REPOURL%" == "" (
|
||||
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
|
||||
)
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Couldn't find %WRAPPER_JAR%, downloading it ...
|
||||
echo Downloading from: %DOWNLOAD_URL%
|
||||
)
|
||||
|
||||
powershell -Command "&{"^
|
||||
"$webclient = new-object System.Net.WebClient;"^
|
||||
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
|
||||
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
|
||||
"}"^
|
||||
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
|
||||
"}"
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Finished downloading %WRAPPER_JAR%
|
||||
)
|
||||
)
|
||||
@REM End of extension
|
||||
|
||||
@REM Provide a "standardized" way to retrieve the CLI args that will
|
||||
@REM work with both Windows and non-Windows executions.
|
||||
set MAVEN_CMD_LINE_ARGS=%*
|
||||
|
||||
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
|
||||
if ERRORLEVEL 1 goto error
|
||||
goto end
|
||||
|
||||
:error
|
||||
set ERROR_CODE=1
|
||||
|
||||
:end
|
||||
@endlocal & set ERROR_CODE=%ERROR_CODE%
|
||||
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
|
||||
@REM check for post script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
|
||||
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
|
||||
:skipRcPost
|
||||
|
||||
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
|
||||
if "%MAVEN_BATCH_PAUSE%" == "on" pause
|
||||
|
||||
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
|
||||
|
||||
exit /B %ERROR_CODE%
|
||||
32
core-java/heapdump/pom.xml
Normal file
32
core-java/heapdump/pom.xml
Normal file
@@ -0,0 +1,32 @@
|
||||
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>io.pratik</groupId>
|
||||
<artifactId>oomegen</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>oomegen</name>
|
||||
<properties>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<!-- Build an executable JAR -->
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>io.pratik.OOMGenerator</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
BIN
core-java/heapdump/src/.DS_Store
vendored
Normal file
BIN
core-java/heapdump/src/.DS_Store
vendored
Normal file
Binary file not shown.
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package io.pratik;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author Pratik Das
|
||||
*
|
||||
*/
|
||||
public class AbstractProduct {
|
||||
|
||||
private String name;
|
||||
private String id;
|
||||
private byte[] logo;
|
||||
private static final Random random = new Random();
|
||||
|
||||
public AbstractProduct() {
|
||||
super();
|
||||
this.id = UUID.randomUUID().toString();
|
||||
this.logo = new byte[(5 ) * 1024 * 1024];
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public byte[] getLogo() {
|
||||
return logo;
|
||||
}
|
||||
|
||||
public void setLogo(byte[] logo) {
|
||||
this.logo = logo;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return JavaAgent.getObjectSize(this) + JavaAgent.getObjectSize(logo) + JavaAgent.getObjectSize(id);
|
||||
}
|
||||
|
||||
}
|
||||
23
core-java/heapdump/src/main/java/io/pratik/JavaAgent.java
Normal file
23
core-java/heapdump/src/main/java/io/pratik/JavaAgent.java
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package io.pratik;
|
||||
|
||||
import java.lang.instrument.Instrumentation;
|
||||
|
||||
/**
|
||||
* @author Pratik Das
|
||||
*
|
||||
*/
|
||||
public class JavaAgent {
|
||||
private static volatile Instrumentation instrumentation;
|
||||
public static void premain(final String agentArgs, final Instrumentation instrumentation) {
|
||||
JavaAgent.instrumentation = instrumentation;
|
||||
}
|
||||
public static long getObjectSize(final Object object) {
|
||||
if (instrumentation == null) {
|
||||
return -1L;
|
||||
}
|
||||
return instrumentation.getObjectSize(object);
|
||||
}
|
||||
}
|
||||
29
core-java/heapdump/src/main/java/io/pratik/OOMGenerator.java
Normal file
29
core-java/heapdump/src/main/java/io/pratik/OOMGenerator.java
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package io.pratik;
|
||||
|
||||
/**
|
||||
* @author Pratik Das
|
||||
*
|
||||
*/
|
||||
public class OOMGenerator {
|
||||
|
||||
/**
|
||||
* @param args
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
System.out.println("Max JVM memory: " + Runtime.getRuntime().maxMemory()/(1024*1024));
|
||||
try {
|
||||
ProductManager productManager = new ProductManager();
|
||||
productManager.populateProducts();
|
||||
|
||||
} catch (OutOfMemoryError outofMemory) {
|
||||
System.out.println("Catching out of memory error "+ Runtime.getRuntime().freeMemory()/(1024*1024));
|
||||
// Log the information,so that we can generate the statistics (latter on).
|
||||
throw outofMemory;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package io.pratik;
|
||||
|
||||
import io.pratik.models.BrandedProduct;
|
||||
import io.pratik.models.ElectronicGood;
|
||||
import io.pratik.models.GroceryProduct;
|
||||
import io.pratik.models.LuxuryGood;
|
||||
import io.pratik.models.ProductGroup;
|
||||
|
||||
/**
|
||||
* @author Pratik Das
|
||||
*
|
||||
*/
|
||||
public class ProductManager {
|
||||
private ProductGroup regularItems = new ProductGroup();
|
||||
|
||||
private ProductGroup discountedItems = new ProductGroup();
|
||||
|
||||
public void populateProducts() {
|
||||
|
||||
int dummyArraySize = 1;
|
||||
for (int loop = 0; loop < 10; loop++) {
|
||||
if(loop%2 == 0) {
|
||||
createObjects(regularItems, dummyArraySize);
|
||||
}else {
|
||||
createObjects(discountedItems, dummyArraySize);
|
||||
}
|
||||
System.out.println("Memory Consumed till now: " + loop + "::"+ regularItems + " "+discountedItems );
|
||||
dummyArraySize *= dummyArraySize * 2;
|
||||
}
|
||||
}
|
||||
|
||||
private void createObjects(ProductGroup productGroup, int dummyArraySize) {
|
||||
for (int i = 0; i < dummyArraySize; ) {
|
||||
productGroup.add(createProduct());
|
||||
}
|
||||
}
|
||||
|
||||
private AbstractProduct createProduct() {
|
||||
int randomIndex = (int) Math.round(Math.random() * 10);
|
||||
switch (randomIndex) {
|
||||
case 0:
|
||||
return new ElectronicGood();
|
||||
case 1:
|
||||
return new BrandedProduct();
|
||||
case 2:
|
||||
return new GroceryProduct();
|
||||
case 3:
|
||||
return new LuxuryGood();
|
||||
default:
|
||||
return new BrandedProduct();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package io.pratik.models;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.pratik.AbstractProduct;
|
||||
import io.pratik.JavaAgent;
|
||||
|
||||
/**
|
||||
* @author Pratik Das
|
||||
*
|
||||
*/
|
||||
public class BrandedProduct extends AbstractProduct{
|
||||
private String brandName;
|
||||
private Price mrp;
|
||||
|
||||
|
||||
|
||||
public BrandedProduct() {
|
||||
super();
|
||||
mrp = new Price();
|
||||
|
||||
}
|
||||
|
||||
public Price getMrp() {
|
||||
return mrp;
|
||||
}
|
||||
|
||||
public void setMrp(Price mrp) {
|
||||
this.mrp = mrp;
|
||||
}
|
||||
|
||||
public String getBrandName() {
|
||||
return brandName;
|
||||
}
|
||||
|
||||
public void setBrandName(String brandName) {
|
||||
this.brandName = brandName;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return JavaAgent.getObjectSize(this) + JavaAgent.getObjectSize(brandName);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package io.pratik.models;
|
||||
|
||||
import io.pratik.AbstractProduct;
|
||||
|
||||
/**
|
||||
* @author Pratik Das
|
||||
*
|
||||
*/
|
||||
public class ElectronicGood extends AbstractProduct{
|
||||
|
||||
private Manufacturer manufacturer;
|
||||
|
||||
|
||||
|
||||
public ElectronicGood() {
|
||||
super();
|
||||
this.manufacturer = new Manufacturer();
|
||||
}
|
||||
|
||||
public Manufacturer getManufacturer() {
|
||||
return manufacturer;
|
||||
}
|
||||
|
||||
public void setManufacturer(Manufacturer manufacturer) {
|
||||
this.manufacturer = manufacturer;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package io.pratik.models;
|
||||
|
||||
import io.pratik.AbstractProduct;
|
||||
|
||||
/**
|
||||
* @author Pratik Das
|
||||
*
|
||||
*/
|
||||
public class GroceryProduct extends AbstractProduct{
|
||||
private Price mrp;
|
||||
private Price discountedPrice;
|
||||
|
||||
|
||||
public GroceryProduct() {
|
||||
super();
|
||||
mrp = new Price();
|
||||
discountedPrice = new Price();
|
||||
}
|
||||
public Price getMrp() {
|
||||
return mrp;
|
||||
}
|
||||
public void setMrp(Price mrp) {
|
||||
this.mrp = mrp;
|
||||
}
|
||||
public Price getDiscountedPrice() {
|
||||
return discountedPrice;
|
||||
}
|
||||
public void setDiscountedPrice(Price discountedPrice) {
|
||||
this.discountedPrice = discountedPrice;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package io.pratik.models;
|
||||
|
||||
import io.pratik.AbstractProduct;
|
||||
|
||||
/**
|
||||
* @author Pratik Das
|
||||
*
|
||||
*/
|
||||
public class LuxuryGood extends AbstractProduct{
|
||||
private String luxuryCategory;
|
||||
|
||||
public String getLuxuryCategory() {
|
||||
return luxuryCategory;
|
||||
}
|
||||
|
||||
public void setLuxuryCategory(String luxuryCategory) {
|
||||
this.luxuryCategory = luxuryCategory;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package io.pratik.models;
|
||||
|
||||
import io.pratik.JavaAgent;
|
||||
|
||||
/**
|
||||
* @author Pratik Das
|
||||
*
|
||||
*/
|
||||
public class Manufacturer {
|
||||
|
||||
private String name;
|
||||
private String address;
|
||||
|
||||
|
||||
public Manufacturer() {
|
||||
super();
|
||||
this.name = "Dummy";
|
||||
this.address = "dummy state";
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return JavaAgent.getObjectSize(this)
|
||||
+ JavaAgent.getObjectSize(name)
|
||||
+ JavaAgent.getObjectSize(address);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
45
core-java/heapdump/src/main/java/io/pratik/models/Price.java
Normal file
45
core-java/heapdump/src/main/java/io/pratik/models/Price.java
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package io.pratik.models;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import io.pratik.JavaAgent;
|
||||
|
||||
/**
|
||||
* @author Pratik Das
|
||||
*
|
||||
*/
|
||||
public final class Price {
|
||||
|
||||
private Double value;
|
||||
private Date lastUpdated;
|
||||
|
||||
|
||||
public Price() {
|
||||
super();
|
||||
value = 48.0;
|
||||
lastUpdated = new Date();
|
||||
|
||||
}
|
||||
public Double getValue() {
|
||||
return value;
|
||||
}
|
||||
public void setValue(Double value) {
|
||||
this.value = value;
|
||||
}
|
||||
public Date getLastUpdated() {
|
||||
return lastUpdated;
|
||||
}
|
||||
public void setLastUpdated(Date lastUpdated) {
|
||||
this.lastUpdated = lastUpdated;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return JavaAgent.getObjectSize(this)
|
||||
+ JavaAgent.getObjectSize(value)
|
||||
+ JavaAgent.getObjectSize(lastUpdated.toString());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package io.pratik.models;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.pratik.AbstractProduct;
|
||||
|
||||
/**
|
||||
* @author Pratik Das
|
||||
*
|
||||
*/
|
||||
public class ProductGroup {
|
||||
|
||||
private List<AbstractProduct> products = new ArrayList<AbstractProduct>();
|
||||
|
||||
public void add(AbstractProduct product) {
|
||||
products.add(product);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
Manifest-Version: 1.0
|
||||
Premain-Class: io.pratik.JavaAgent
|
||||
2
core-java/service-provider-interface/.gitignore
vendored
Normal file
2
core-java/service-provider-interface/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/.idea
|
||||
**/target
|
||||
117
core-java/service-provider-interface/.mvn/wrapper/MavenWrapperDownloader.java
vendored
Normal file
117
core-java/service-provider-interface/.mvn/wrapper/MavenWrapperDownloader.java
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2007-present the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.Properties;
|
||||
|
||||
public class MavenWrapperDownloader {
|
||||
|
||||
private static final String WRAPPER_VERSION = "0.5.6";
|
||||
/**
|
||||
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
|
||||
*/
|
||||
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
|
||||
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
|
||||
|
||||
/**
|
||||
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
|
||||
* use instead of the default one.
|
||||
*/
|
||||
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
|
||||
".mvn/wrapper/maven-wrapper.properties";
|
||||
|
||||
/**
|
||||
* Path where the maven-wrapper.jar will be saved to.
|
||||
*/
|
||||
private static final String MAVEN_WRAPPER_JAR_PATH =
|
||||
".mvn/wrapper/maven-wrapper.jar";
|
||||
|
||||
/**
|
||||
* Name of the property which should be used to override the default download url for the wrapper.
|
||||
*/
|
||||
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.out.println("- Downloader started");
|
||||
File baseDirectory = new File(args[0]);
|
||||
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
|
||||
|
||||
// If the maven-wrapper.properties exists, read it and check if it contains a custom
|
||||
// wrapperUrl parameter.
|
||||
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
|
||||
String url = DEFAULT_DOWNLOAD_URL;
|
||||
if(mavenWrapperPropertyFile.exists()) {
|
||||
FileInputStream mavenWrapperPropertyFileInputStream = null;
|
||||
try {
|
||||
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
|
||||
Properties mavenWrapperProperties = new Properties();
|
||||
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
|
||||
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
|
||||
} catch (IOException e) {
|
||||
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
|
||||
} finally {
|
||||
try {
|
||||
if(mavenWrapperPropertyFileInputStream != null) {
|
||||
mavenWrapperPropertyFileInputStream.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Ignore ...
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("- Downloading from: " + url);
|
||||
|
||||
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
|
||||
if(!outputFile.getParentFile().exists()) {
|
||||
if(!outputFile.getParentFile().mkdirs()) {
|
||||
System.out.println(
|
||||
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
|
||||
}
|
||||
}
|
||||
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
|
||||
try {
|
||||
downloadFileFromURL(url, outputFile);
|
||||
System.out.println("Done");
|
||||
System.exit(0);
|
||||
} catch (Throwable e) {
|
||||
System.out.println("- Error downloading");
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
|
||||
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
|
||||
String username = System.getenv("MVNW_USERNAME");
|
||||
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
|
||||
Authenticator.setDefault(new Authenticator() {
|
||||
@Override
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
return new PasswordAuthentication(username, password);
|
||||
}
|
||||
});
|
||||
}
|
||||
URL website = new URL(urlString);
|
||||
ReadableByteChannel rbc;
|
||||
rbc = Channels.newChannel(website.openStream());
|
||||
FileOutputStream fos = new FileOutputStream(destination);
|
||||
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
|
||||
fos.close();
|
||||
rbc.close();
|
||||
}
|
||||
|
||||
}
|
||||
BIN
core-java/service-provider-interface/.mvn/wrapper/maven-wrapper.jar
vendored
Normal file
BIN
core-java/service-provider-interface/.mvn/wrapper/maven-wrapper.jar
vendored
Normal file
Binary file not shown.
2
core-java/service-provider-interface/.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
2
core-java/service-provider-interface/.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
|
||||
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
|
||||
3
core-java/service-provider-interface/README.md
Normal file
3
core-java/service-provider-interface/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Related Blog Posts
|
||||
|
||||
* [Service Provider Interface](https://reflectoring.io/service-provider-interface/)
|
||||
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<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/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>service-provider-interface</artifactId>
|
||||
<groupId>org.library</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>classics-library</artifactId>
|
||||
|
||||
<name>classics-library</name>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.library</groupId>
|
||||
<artifactId>library-service-provider</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,40 @@
|
||||
package org.library;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.library.spi.Book;
|
||||
import org.library.spi.Library;
|
||||
|
||||
public class ClassicsLibrary implements Library {
|
||||
|
||||
public static final String CLASSICS_LIBRARY = "CLASSICS";
|
||||
private final Map<String, Book> books;
|
||||
|
||||
public ClassicsLibrary() {
|
||||
books = new TreeMap<>();
|
||||
Book nineteenEightyFour = new Book("Nineteen Eighty-Four", "George Orwell",
|
||||
"It was a bright cold day in April, and the clocks were striking thirteen.");
|
||||
Book theLordOfTheRings = new Book("The Lord of the Rings", "J. R. R. Tolkien",
|
||||
"When Mr. Bilbo Baggins of Bag End announced that he would shortly be celebrating his " +
|
||||
"eleventy-first birthday with a party of special magnificence, there was much talk and excitement in Hobbiton.");
|
||||
Book cleanCode = new Book("Clean Code", "Robert C. Martin",
|
||||
"ClassicsEven bad code can function. But if code isn’t clean, it can bring a development organization to its knees");
|
||||
|
||||
books.put("Nineteen Eighty-Four", nineteenEightyFour);
|
||||
books.put("The Lord of the Rings", theLordOfTheRings);
|
||||
books.put("Clean Code", cleanCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return CLASSICS_LIBRARY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Book getBook(String name) {
|
||||
return books.get(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
org.library.ClassicsLibrary
|
||||
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<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/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.library</groupId>
|
||||
<artifactId>computer-science-library</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<name>computer-science-library</name>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.library</groupId>
|
||||
<artifactId>library-service-provider</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
</build>
|
||||
</project>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user