mirror of
https://github.com/spring-cloud/spring-cloud-netflix.git
synced 2026-09-17 23:59:04 +00:00
Compare commits
80
Commits
docs-build
..
1.2.x
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d6058cca2d | ||
|
|
abfdeeeab0 | ||
|
|
87bc38d899 | ||
|
|
b8758f0606 | ||
|
|
3f1b372895 | ||
|
|
21ec7f0280 | ||
|
|
a18fee5391 | ||
|
|
9e531e9ddd | ||
|
|
a487d35f49 | ||
|
|
15d4a71960 | ||
|
|
9c906f9b49 | ||
|
|
164ba01365 | ||
|
|
7eb6647730 | ||
|
|
4381eb1381 | ||
|
|
ec4c02aba9 | ||
|
|
2cfc32710f | ||
|
|
ae5b313bdd | ||
|
|
b15c106bf1 | ||
|
|
dc3aa2ba22 | ||
|
|
5d9363b32f | ||
|
|
08bb746c70 | ||
|
|
661faa8d88 | ||
|
|
7596c1d152 | ||
|
|
3016992fb0 | ||
|
|
bd3391ae55 | ||
|
|
f7cf155eef | ||
|
|
a2ad006899 | ||
|
|
f0fc9df67d | ||
|
|
1270ba0edb | ||
|
|
ac0539cdc4 | ||
|
|
880a6ce4b5 | ||
|
|
b5a0274b58 | ||
|
|
7e6c7ee221 | ||
|
|
f1fb32cfdb | ||
|
|
9bc8bc6bbe | ||
|
|
5073cd89ad | ||
|
|
08ba0cc72b | ||
|
|
ee953bef07 | ||
|
|
4ca231aff9 | ||
|
|
4ee2055d5c | ||
|
|
1fffc923e1 | ||
|
|
b41027191e | ||
|
|
0df5957f6b | ||
|
|
234c4c65ae | ||
|
|
c5117a8573 | ||
|
|
f304ab7101 | ||
|
|
f591136d80 | ||
|
|
9170365b85 | ||
|
|
f5c6920843 | ||
|
|
470d6abf63 | ||
|
|
f3275c160b | ||
|
|
5cd39df5e7 | ||
|
|
a91815aa43 | ||
|
|
0f7f88f89b | ||
|
|
2487ef2fad | ||
|
|
b5195b7b86 | ||
|
|
845590e46c | ||
|
|
7fdd86e69c | ||
|
|
d1f8c03110 | ||
|
|
728ef05bf3 | ||
|
|
27a2c31241 | ||
|
|
3034c55b13 | ||
|
|
cdaa97c006 | ||
|
|
f563fcb4cd | ||
|
|
14dd2d2359 | ||
|
|
8b4469db31 | ||
|
|
658f29ed27 | ||
|
|
19556dc25d | ||
|
|
b31f6c5c4f | ||
|
|
dfcc319ba7 | ||
|
|
fad2c5d400 | ||
|
|
3201234ee1 | ||
|
|
9b64d0da8f | ||
|
|
be8eece91e | ||
|
|
7c48814234 | ||
|
|
72ccf2e649 | ||
|
|
3df42159fb | ||
|
|
45e7a088bb | ||
|
|
0f0c6b6204 | ||
|
|
88a36b38e9 |
@@ -1,134 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-build</artifactId>
|
||||
<version>4.1.0-SNAPSHOT</version>
|
||||
<relativePath></relativePath>
|
||||
</parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>4.1.0-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Spring Cloud Netflix</name>
|
||||
<description>Spring Cloud Netflix</description>
|
||||
<url>https://spring.io/spring-cloud/spring-cloud-netflix</url>
|
||||
<organization>
|
||||
<name>Pivotal Software, Inc.</name>
|
||||
<url>https://www.spring.io</url>
|
||||
</organization>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>Apache License, Version 2.0</name>
|
||||
<url>https://www.apache.org/licenses/LICENSE-2.0</url>
|
||||
<comments>Copyright 2014-2021 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.</comments>
|
||||
</license>
|
||||
</licenses>
|
||||
<developers>
|
||||
<developer>
|
||||
<id>dsyer</id>
|
||||
<name>Dave Syer</name>
|
||||
<email>dsyer at pivotal.io</email>
|
||||
<organization>Pivotal Software, Inc.</organization>
|
||||
<organizationUrl>https://www.spring.io</organizationUrl>
|
||||
<roles>
|
||||
<role>lead</role>
|
||||
</roles>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>sgibb</id>
|
||||
<name>Spencer Gibb</name>
|
||||
<email>sgibb at pivotal.io</email>
|
||||
<organization>Pivotal Software, Inc.</organization>
|
||||
<organizationUrl>https://www.spring.io</organizationUrl>
|
||||
<roles>
|
||||
<role>lead</role>
|
||||
</roles>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>mgrzejszczak</id>
|
||||
<name>Marcin Grzejszczak</name>
|
||||
<email>mgrzejszczak at pivotal.io</email>
|
||||
<organization>Pivotal Software, Inc.</organization>
|
||||
<organizationUrl>https://www.spring.io</organizationUrl>
|
||||
<roles>
|
||||
<role>developer</role>
|
||||
</roles>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>rbaxter</id>
|
||||
<name>Ryan Baxter</name>
|
||||
<email>rbaxter at pivotal.io</email>
|
||||
<organization>Pivotal Software, Inc.</organization>
|
||||
<organizationUrl>https://www.spring.io</organizationUrl>
|
||||
<roles>
|
||||
<role>developer</role>
|
||||
</roles>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>omaciaszeksharma</id>
|
||||
<name>Olga Maciaszek-Sharma</name>
|
||||
<email>omaciaszeksharma at pivotal.io</email>
|
||||
<organization>Pivotal Software, Inc.</organization>
|
||||
<organizationUrl>https://www.spring.io</organizationUrl>
|
||||
<roles>
|
||||
<role>developer</role>
|
||||
</roles>
|
||||
</developer>
|
||||
</developers>
|
||||
<scm>
|
||||
<connection>scm:git:git://github.com/spring-cloud/spring-cloud-netflix.git</connection>
|
||||
<developerConnection>scm:git:ssh://git@github.com/spring-cloud/spring-cloud-netflix.git</developerConnection>
|
||||
<url>https://github.com/spring-cloud/spring-cloud-netflix</url>
|
||||
</scm>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>spring</id>
|
||||
<repositories>
|
||||
<repository>
|
||||
<releases>
|
||||
<enabled>false</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/libs-snapshot-local</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/libs-milestone-local</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
<id>spring-releases</id>
|
||||
<name>Spring Releases</name>
|
||||
<url>https://repo.spring.io/release</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
@@ -1,31 +0,0 @@
|
||||
# Generated by the rollout-deploy-docs workflow in
|
||||
# spring-cloud/spring-cloud-github-actions.
|
||||
#
|
||||
# Do not edit this file directly - update examples/deploy-docs.yml there
|
||||
# and re-run the rollout, otherwise your change will be overwritten.
|
||||
|
||||
name: Deploy Docs
|
||||
run-name: ${{ format('{0} ({1})', github.workflow, github.event.inputs.build-refname || 'all') }}
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
build-refname:
|
||||
description: Enter git refname to build (e.g., 4.3.x).
|
||||
required: false
|
||||
push:
|
||||
branches: docs-build
|
||||
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
deploy-docs:
|
||||
uses: spring-cloud/spring-cloud-github-actions/.github/workflows/deploy-docs.yml@b6a6b1963b8762420526591c3d363bd7d09e7d4b # v1.1.1
|
||||
with:
|
||||
build_refname: ${{ github.event.inputs.build-refname }}
|
||||
# Optional overrides - the defaults are correct for every current project:
|
||||
# java_version: '17'
|
||||
# build_command: './mvnw --no-transfer-progress -B antora -Pdocs'
|
||||
# runs_on: 'ubuntu-latest'
|
||||
# context_root: 'spring-cloud-<project>'
|
||||
secrets: inherit
|
||||
+15
-18
@@ -1,23 +1,20 @@
|
||||
target/
|
||||
.settings/
|
||||
.project
|
||||
*~
|
||||
#*
|
||||
*#
|
||||
.#*
|
||||
.classpath
|
||||
*.orig
|
||||
.project
|
||||
.settings/
|
||||
.springBeans
|
||||
.factorypath
|
||||
.sts4-cache
|
||||
.ant-targets-build.xml
|
||||
src/ant/.ant-targets-upload-dist.xml
|
||||
*.sonar4clipse*
|
||||
.DS_Store
|
||||
target/
|
||||
bin/
|
||||
_site/
|
||||
.idea
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
/.idea/
|
||||
*.graphml
|
||||
node
|
||||
node_modules
|
||||
build
|
||||
docs/package.json
|
||||
package-lock.json
|
||||
.flattened-pom.xml
|
||||
.factorypath
|
||||
*.log
|
||||
.shelf
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
-DaltSnapshotDeploymentRepository=repo.spring.io::default::https://repo.spring.io/libs-snapshot-local -P spring
|
||||
-117
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
|
||||
}
|
||||
Vendored
BIN
Binary file not shown.
+1
-2
@@ -1,2 +1 @@
|
||||
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
|
||||
distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip
|
||||
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<settings>
|
||||
<servers>
|
||||
<server>
|
||||
<id>repo.spring.io</id>
|
||||
<username>${env.CI_DEPLOY_USERNAME}</username>
|
||||
<password>${env.CI_DEPLOY_PASSWORD}</password>
|
||||
</server>
|
||||
</servers>
|
||||
<profiles>
|
||||
<profile>
|
||||
<!--
|
||||
N.B. this profile is only here to support users and IDEs that do not use Maven 3.3.
|
||||
It isn't needed on the command line if you use the wrapper script (mvnw) or if you use
|
||||
a native Maven with the right version. Eclipse users should points their Maven tooling to
|
||||
this settings file, or copy the profile into their ~/.m2/settings.xml.
|
||||
-->
|
||||
<id>spring</id>
|
||||
<activation><activeByDefault>true</activeByDefault></activation>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/libs-snapshot-local</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/libs-milestone-local</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-releases</id>
|
||||
<name>Spring Releases</name>
|
||||
<url>https://repo.spring.io/release</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/libs-snapshot-local</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/libs-milestone-local</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
</profile>
|
||||
</profiles>
|
||||
</settings>
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
sudo: false
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.m2
|
||||
language: java
|
||||
jdk:
|
||||
- oraclejdk8
|
||||
services:
|
||||
- rabbitmq
|
||||
before_install:
|
||||
- git config user.name "$GIT_NAME"
|
||||
- git config user.email "$GIT_EMAIL"
|
||||
- git config credential.helper "store --file=.git/credentials"
|
||||
- echo "https://$GH_TOKEN:@github.com" > .git/credentials
|
||||
- gem install asciidoctor
|
||||
install:
|
||||
- ./mvnw install -P docs -q -U -DskipTests=true $MVN_LOCAL_OPTS
|
||||
- '[ "${MVN_GOAL}" == "deploy" ] && ./docs/src/main/asciidoc/ghpages.sh || echo "Not updating docs"'
|
||||
script:
|
||||
- './mvnw -s .settings.xml $MVN_GOAL $MVN_PROFILE -nsu $MVN_LOCAL_OPTS'
|
||||
env:
|
||||
global:
|
||||
- MVN_LOCAL_OPTS="-Dmaven.source.skip=true -Dmaven.javadoc.skip=true -Dmaven.test.redirectTestOutputToFile=true"
|
||||
- GIT_NAME="Dave Syer"
|
||||
- GIT_EMAIL=dsyer@pivotal.io
|
||||
- CI_DEPLOY_USERNAME=buildmaster
|
||||
- FEATURE_BRANCH=$(echo ${TRAVIS_BRANCH} | grep -q "^.*/.*$" && echo true || echo false)
|
||||
- SPRING_CLOUD_BUILD=$(echo ${TRAVIS_REPO_SLUG} | grep -q "^spring-cloud/.*$" && echo true || echo false)
|
||||
- MVN_GOAL=install
|
||||
- VERSION=$(mvn validate | grep Building | head -1 | sed -e 's/.* //')
|
||||
- MILESTONE=$(echo ${VERSION} | egrep 'M|RC' && echo true || echo false)
|
||||
- MVN_PROFILE=$([ "${MILESTONE}" == "true" ] && echo -P milestone)
|
||||
- JAVA_OPTS="-Xmx1024m -XX:CICompilerCount=1 -XX:TieredStopAtLevel=1 -Djava.security.egd=file:/dev/./urandom"
|
||||
- secure: aeLXRC5oFSddwnZt1/7G2/OHr7jDbxz0ET7sej3I+eSbe3N5vbzQ6FC08es4l89l54ciXd90I1g2BMw7DTYKOO373FP78XPdAEbifJTU4DGd6fCELmoTtUPhjunBIk7E49hisPbv82892IYYA7qi/hzG548cPyZ1IgiJjq0NCsc=
|
||||
@@ -0,0 +1,11 @@
|
||||
require 'asciidoctor'
|
||||
require 'erb'
|
||||
|
||||
options = {:mkdirs => true, :safe => :unsafe, :attributes => ['linkcss', 'allow-uri-read']}
|
||||
|
||||
guard 'shell' do
|
||||
watch(/^docs\/[A-Z-a-z][^#]*\.adoc$/) {|m|
|
||||
Asciidoctor.load_file('docs/src/main/asciidoc/README.adoc', :to_file => './README.adoc', safe: :safe, parse: false, attributes: 'allow-uri-read')
|
||||
Asciidoctor.render_file('docs/src/main/asciidoc/spring-cloud-netflix.adoc', options.merge(:to_dir => 'target/generated-docs'))
|
||||
}
|
||||
end
|
||||
+202
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
https://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
+187
-12
@@ -1,23 +1,198 @@
|
||||
= Spring Cloud Netflix Docs Build
|
||||
// Do not edit this file (e.g. go instead to src/main/asciidoc)
|
||||
|
||||
You're currently viewing the Antora playbook branch.
|
||||
The playbook branch hosts the docs build that is used to build and publish the production docs site.
|
||||
image::https://circleci.com/gh/spring-cloud/spring-cloud-netflix/tree/master.svg?style=svg["CircleCI", link="https://circleci.com/gh/spring-cloud/spring-cloud-netflix/tree/master"]
|
||||
image::https://codecov.io/gh/spring-cloud/spring-cloud-netflix/branch/master/graph/badge.svg["Codecov", link="https://codecov.io/gh/spring-cloud/spring-cloud-netflix/branch/master"]
|
||||
image::https://api.codacy.com/project/badge/Grade/a6885a06921e4f72a0df0b7aabd6d118["Codacy code quality", link="https://www.codacy.com/app/Spring-Cloud/spring-cloud-netflix?utm_source=github.com&utm_medium=referral&utm_content=spring-cloud/spring-cloud-netflix&utm_campaign=Badge_Grade"]
|
||||
|
||||
The Spring Cloud Netflix reference docs are built using https://antora.org[Antora].
|
||||
This README covers how to build the docs in a software branch as well as how to build the production docs site locally.
|
||||
|
||||
== Building the Site
|
||||
This project provides Netflix OSS integrations for Spring Boot apps through autoconfiguration
|
||||
and binding to the Spring Environment and other Spring programming model idioms. With a few
|
||||
simple annotations you can quickly enable and configure the common patterns inside your
|
||||
application and build large distributed systems with battle-tested Netflix components. The
|
||||
patterns provided include Service Discovery (Eureka), Circuit Breaker (Hystrix),
|
||||
Intelligent Routing (Zuul) and Client Side Load Balancing (Ribbon).
|
||||
|
||||
You can build the entire site by invoking the following on the docs-build branch and then viewing the site at `target/site/index.html`
|
||||
|
||||
[source,bash]
|
||||
== Features
|
||||
|
||||
* Service Discovery: Eureka instances can be registered and clients can discover the instances using Spring-managed beans
|
||||
* Service Discovery: an embedded Eureka server can be created with declarative Java configuration
|
||||
* Circuit Breaker: Hystrix clients can be built with a simple annotation-driven method decorator
|
||||
* Circuit Breaker: embedded Hystrix dashboard with declarative Java configuration
|
||||
* Declarative REST Client: Feign creates a dynamic implementation of an interface decorated with JAX-RS or Spring MVC annotations
|
||||
* Client Side Load Balancer: Ribbon
|
||||
* External Configuration: a bridge from the Spring Environment to Archaius (enables native configuration of Netflix components using Spring Boot conventions)
|
||||
* Router and Filter: automatic registration of Zuul filters, and a simple convention over configuration approach to reverse proxy creation
|
||||
|
||||
== Building
|
||||
|
||||
:jdkversion: 1.8
|
||||
|
||||
=== Basic Compile and Test
|
||||
|
||||
To build the source you will need to install JDK {jdkversion}.
|
||||
|
||||
Spring Cloud uses Maven for most build-related activities, and you
|
||||
should be able to get off the ground quite quickly by cloning the
|
||||
project you are interested in and typing
|
||||
|
||||
----
|
||||
./mvnw antora
|
||||
$ ./mvnw install
|
||||
----
|
||||
|
||||
== Building a Specific Branch
|
||||
NOTE: You can also install Maven (>=3.3.3) yourself and run the `mvn` command
|
||||
in place of `./mvnw` in the examples below. If you do that you also
|
||||
might need to add `-P spring` if your local Maven settings do not
|
||||
contain repository declarations for spring pre-release artifacts.
|
||||
|
||||
[source,bash]
|
||||
NOTE: Be aware that you might need to increase the amount of memory
|
||||
available to Maven by setting a `MAVEN_OPTS` environment variable with
|
||||
a value like `-Xmx512m -XX:MaxPermSize=128m`. We try to cover this in
|
||||
the `.mvn` configuration, so if you find you have to do it to make a
|
||||
build succeed, please raise a ticket to get the settings added to
|
||||
source control.
|
||||
|
||||
For hints on how to build the project look in `.travis.yml` if there
|
||||
is one. There should be a "script" and maybe "install" command. Also
|
||||
look at the "services" section to see if any services need to be
|
||||
running locally (e.g. mongo or rabbit). Ignore the git-related bits
|
||||
that you might find in "before_install" since they're related to setting git
|
||||
credentials and you already have those.
|
||||
|
||||
The projects that require middleware generally include a
|
||||
`docker-compose.yml`, so consider using
|
||||
https://compose.docker.io/[Docker Compose] to run the middeware servers
|
||||
in Docker containers. See the README in the
|
||||
https://github.com/spring-cloud-samples/scripts[scripts demo
|
||||
repository] for specific instructions about the common cases of mongo,
|
||||
rabbit and redis.
|
||||
|
||||
NOTE: If all else fails, build with the command from `.travis.yml` (usually
|
||||
`./mvnw install`).
|
||||
|
||||
=== Documentation
|
||||
|
||||
The spring-cloud-build module has a "docs" profile, and if you switch
|
||||
that on it will try to build asciidoc sources from
|
||||
`src/main/asciidoc`. As part of that process it will look for a
|
||||
`README.adoc` and process it by loading all the includes, but not
|
||||
parsing or rendering it, just copying it to `${main.basedir}`
|
||||
(defaults to `${basedir}`, i.e. the root of the project). If there are
|
||||
any changes in the README it will then show up after a Maven build as
|
||||
a modified file in the correct place. Just commit it and push the change.
|
||||
|
||||
=== Working with the code
|
||||
If you don't have an IDE preference we would recommend that you use
|
||||
https://www.springsource.com/developer/sts[Spring Tools Suite] or
|
||||
https://eclipse.org[Eclipse] when working with the code. We use the
|
||||
https://eclipse.org/m2e/[m2eclipse] eclipse plugin for maven support. Other IDEs and tools
|
||||
should also work without issue as long as they use Maven 3.3.3 or better.
|
||||
|
||||
==== Importing into eclipse with m2eclipse
|
||||
We recommend the https://eclipse.org/m2e/[m2eclipse] eclipse plugin when working with
|
||||
eclipse. If you don't already have m2eclipse installed it is available from the "eclipse
|
||||
marketplace".
|
||||
|
||||
NOTE: Older versions of m2e do not support Maven 3.3, so once the
|
||||
projects are imported into Eclipse you will also need to tell
|
||||
m2eclipse to use the right profile for the projects. If you
|
||||
see many different errors related to the POMs in the projects, check
|
||||
that you have an up to date installation. If you can't upgrade m2e,
|
||||
add the "spring" profile to your `settings.xml`. Alternatively you can
|
||||
copy the repository settings from the "spring" profile of the parent
|
||||
pom into your `settings.xml`.
|
||||
|
||||
==== Importing into eclipse without m2eclipse
|
||||
If you prefer not to use m2eclipse you can generate eclipse project metadata using the
|
||||
following command:
|
||||
|
||||
[indent=0]
|
||||
----
|
||||
./mvnw antora
|
||||
$ ./mvnw eclipse:eclipse
|
||||
----
|
||||
|
||||
The generated eclipse projects can be imported by selecting `import existing projects`
|
||||
from the `file` menu.
|
||||
|
||||
|
||||
|
||||
==== Adding Project Lombok Agent
|
||||
|
||||
Spring Cloud uses https://projectlombok.org/features/index.html[Project Lombok]
|
||||
to generate getters and setters etc. Compiling from the command line this
|
||||
shouldn't cause any problems, but in an IDE you need to add an agent
|
||||
to the JVM. Full instructions can be found in the Lombok website. The
|
||||
sign that you need to do this is a lot of compiler errors to do with
|
||||
missing methods and fields, e.g.
|
||||
|
||||
[indent=0]
|
||||
----
|
||||
The method getInitialStatus() is undefined for the type EurekaInstanceConfigBean EurekaDiscoveryClientConfiguration.java /spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka line 120 Java Problem
|
||||
The method getInitialStatus() is undefined for the type EurekaInstanceConfigBean EurekaDiscoveryClientConfiguration.java /spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka line 121 Java Problem
|
||||
The method setNonSecurePort(int) is undefined for the type EurekaInstanceConfigBean EurekaDiscoveryClientConfiguration.java /spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka line 112 Java Problem
|
||||
The type EurekaInstanceConfigBean.IdentifyingDataCenterInfo must implement the inherited abstract method DataCenterInfo.getName() EurekaInstanceConfigBean.java /spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka line 131 Java Problem
|
||||
The method getId() is undefined for the type ProxyRouteLocator.ProxyRouteSpec PreDecorationFilter.java /spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre line 60 Java Problem
|
||||
The method getLocation() is undefined for the type ProxyRouteLocator.ProxyRouteSpec PreDecorationFilter.java /spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre line 55 Java Problem
|
||||
----
|
||||
|
||||
==== Importing into Intellij
|
||||
Spring Cloud projects use annotation processing, particularly Lombok, which requires configuration
|
||||
or you will encounter compile problems. It also needs a specific version of maven and a profile
|
||||
enabled. Intellij 14.1+ requires some configuration to ensure these are setup properly.
|
||||
|
||||
1. Click Preferences, Plugins. *Ensure Lombok is installed*
|
||||
2. Click New, Project from Existing Sources, choose your spring-cloud project directory
|
||||
3. Choose Maven, and select Environment Settings. *Ensure you are using Maven 3.3.3*
|
||||
4. In the next screen, *Select the profile `spring`* click Next until Finish.
|
||||
5. Click Preferences, "Build, Execution, Deployment", Compiler, Annotation Processors. *Click Enable Annotation Processing*
|
||||
6. Click Build, Rebuild Project, and you are ready to go!
|
||||
|
||||
==== Importing into other IDEs
|
||||
Maven is well supported by most Java IDEs. Refer to you vendor documentation.
|
||||
|
||||
== Contributing
|
||||
|
||||
Spring Cloud is released under the non-restrictive Apache 2.0 license,
|
||||
and follows a very standard Github development process, using Github
|
||||
tracker for issues and merging pull requests into master. If you want
|
||||
to contribute even something trivial please do not hesitate, but
|
||||
follow the guidelines below.
|
||||
|
||||
=== Sign the Contributor License Agreement
|
||||
Before we accept a non-trivial patch or pull request we will need you to sign the
|
||||
https://cla.pivotal.io/sign/spring[Contributor License Agreement].
|
||||
Signing the contributor's agreement does not grant anyone commit rights to the main
|
||||
repository, but it does mean that we can accept your contributions, and you will get an
|
||||
author credit if we do. Active contributors might be asked to join the core team, and
|
||||
given the ability to merge pull requests.
|
||||
|
||||
=== Code of Conduct
|
||||
This project adheres to the Contributor Covenant https://github.com/spring-cloud/spring-cloud-build/blob/master/docs/src/main/asciidoc/code-of-conduct.adoc[code of
|
||||
conduct]. By participating, you are expected to uphold this code. Please report
|
||||
unacceptable behavior to spring-code-of-conduct@pivotal.io.
|
||||
|
||||
=== Code Conventions and Housekeeping
|
||||
None of these is essential for a pull request, but they will all help. They can also be
|
||||
added after the original pull request but before a merge.
|
||||
|
||||
* Use the Spring Framework code format conventions. If you use Eclipse
|
||||
you can import formatter settings using the
|
||||
`eclipse-code-formatter.xml` file from the
|
||||
https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-dependencies-parent/eclipse-code-formatter.xml[Spring
|
||||
Cloud Build] project. If using IntelliJ, you can use the
|
||||
https://plugins.jetbrains.com/plugin/6546[Eclipse Code Formatter
|
||||
Plugin] to import the same file.
|
||||
* Make sure all new `.java` files to have a simple Javadoc class comment with at least an
|
||||
`@author` tag identifying you, and preferably at least a paragraph on what the class is
|
||||
for.
|
||||
* Add the ASF license header comment to all new `.java` files (copy from existing files
|
||||
in the project)
|
||||
* Add yourself as an `@author` to the .java files that you modify substantially (more
|
||||
than cosmetic changes).
|
||||
* Add some Javadocs and, if you change the namespace, some XSD doc elements.
|
||||
* A few unit tests would help a lot as well -- someone has to do it.
|
||||
* If no-one else is using your branch, please rebase it against the current master (or
|
||||
other target branch in the main project).
|
||||
* When writing a commit message please follow https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html[these conventions],
|
||||
if you are fixing an existing issue please add `Fixes gh-XXXX` at the end of the commit
|
||||
message (where XXXX is the issue number).
|
||||
@@ -1,39 +0,0 @@
|
||||
antora:
|
||||
extensions:
|
||||
- require: '@springio/antora-extensions'
|
||||
root_component_name: 'cloud-netflix'
|
||||
site:
|
||||
title: Spring Cloud Netflix
|
||||
url: https://docs.spring.io/spring-cloud-netflix/reference
|
||||
robots: allow
|
||||
git:
|
||||
ensure_git_suffix: false
|
||||
content:
|
||||
sources:
|
||||
- url: https://github.com/spring-cloud/spring-cloud-netflix
|
||||
# Refname matching:
|
||||
# https://docs.antora.org/antora/latest/playbook/content-refname-matching/
|
||||
branches: [ main, 5.0.x ]
|
||||
tags: [ 'v{4..9}.+({0..9}).+({0..9})?(-{RC,M}*)', '!v4.1.0-M1', '!v4.0.*' ]
|
||||
start_path: docs
|
||||
asciidoc:
|
||||
attributes:
|
||||
page-stackoverflow-url: https://stackoverflow.com/tags/spring-cloud
|
||||
page-pagination: ''
|
||||
hide-uri-scheme: '@'
|
||||
tabs-sync-option: '@'
|
||||
extensions:
|
||||
- '@asciidoctor/tabs'
|
||||
- '@springio/asciidoctor-extensions'
|
||||
urls:
|
||||
latest_version_segment_strategy: redirect:to
|
||||
latest_version_segment: ''
|
||||
redirect_facility: httpd
|
||||
ui:
|
||||
bundle:
|
||||
url: https://github.com/spring-io/antora-ui-spring/releases/download/v0.4.18/ui-bundle.zip
|
||||
snapshot: true
|
||||
runtime:
|
||||
log:
|
||||
failure_level: warn
|
||||
format: pretty
|
||||
+399
@@ -0,0 +1,399 @@
|
||||
/* Asciidoctor default stylesheet | MIT License | https://asciidoctor.org */
|
||||
/* Remove the comments around the @import statement below when using this as a custom stylesheet */
|
||||
/*@import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic|Noto+Serif:400,400italic,700,700italic|Droid+Sans+Mono:400";*/
|
||||
article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}
|
||||
audio,canvas,video{display:inline-block}
|
||||
audio:not([controls]){display:none;height:0}
|
||||
[hidden],template{display:none}
|
||||
script{display:none!important}
|
||||
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}
|
||||
body{margin:0}
|
||||
a{background:transparent}
|
||||
a:focus{outline:thin dotted}
|
||||
a:active,a:hover{outline:0}
|
||||
h1{font-size:2em;margin:.67em 0}
|
||||
abbr[title]{border-bottom:1px dotted}
|
||||
b,strong{font-weight:bold}
|
||||
dfn{font-style:italic}
|
||||
hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}
|
||||
mark{background:#ff0;color:#000}
|
||||
code,kbd,pre,samp{font-family:monospace;font-size:1em}
|
||||
pre{white-space:pre-wrap}
|
||||
q{quotes:"\201C" "\201D" "\2018" "\2019"}
|
||||
small{font-size:80%}
|
||||
sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
|
||||
sup{top:-.5em}
|
||||
sub{bottom:-.25em}
|
||||
img{border:0}
|
||||
svg:not(:root){overflow:hidden}
|
||||
figure{margin:0}
|
||||
fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}
|
||||
legend{border:0;padding:0}
|
||||
button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}
|
||||
button,input{line-height:normal}
|
||||
button,select{text-transform:none}
|
||||
button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}
|
||||
button[disabled],html input[disabled]{cursor:default}
|
||||
input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}
|
||||
input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}
|
||||
input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}
|
||||
button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}
|
||||
textarea{overflow:auto;vertical-align:top}
|
||||
table{border-collapse:collapse;border-spacing:0}
|
||||
*,*:before,*:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
|
||||
html,body{font-size:100%}
|
||||
body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto}
|
||||
a:hover{cursor:pointer}
|
||||
img,object,embed{max-width:100%;height:auto}
|
||||
object,embed{height:100%}
|
||||
img{-ms-interpolation-mode:bicubic}
|
||||
#map_canvas img,#map_canvas embed,#map_canvas object,.map_canvas img,.map_canvas embed,.map_canvas object{max-width:none!important}
|
||||
.left{float:left!important}
|
||||
.right{float:right!important}
|
||||
.text-left{text-align:left!important}
|
||||
.text-right{text-align:right!important}
|
||||
.text-center{text-align:center!important}
|
||||
.text-justify{text-align:justify!important}
|
||||
.hide{display:none}
|
||||
.antialiased,body{-webkit-font-smoothing:antialiased}
|
||||
img{display:inline-block;vertical-align:middle}
|
||||
textarea{height:auto;min-height:50px}
|
||||
select{width:100%}
|
||||
p.lead,.paragraph.lead>p,#preamble>.sectionbody>.paragraph:first-of-type p{font-size:1.21875em;line-height:1.6}
|
||||
.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em}
|
||||
div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0;direction:ltr}
|
||||
a{color:#2156a5;text-decoration:underline;line-height:inherit}
|
||||
a:hover,a:focus{color:#1d4b8f}
|
||||
a img{border:none}
|
||||
p{font-family:inherit;font-weight:400;font-size:1em;line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility}
|
||||
p aside{font-size:.875em;line-height:1.35;font-style:italic}
|
||||
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em}
|
||||
h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0}
|
||||
h1{font-size:2.125em}
|
||||
h2{font-size:1.6875em}
|
||||
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em}
|
||||
h4,h5{font-size:1.125em}
|
||||
h6{font-size:1em}
|
||||
hr{border:solid #ddddd8;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em;height:0}
|
||||
em,i{font-style:italic;line-height:inherit}
|
||||
strong,b{font-weight:bold;line-height:inherit}
|
||||
small{font-size:60%;line-height:inherit}
|
||||
code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)}
|
||||
ul,ol,dl{font-size:1em;line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit}
|
||||
ul,ol,ul.no-bullet,ol.no-bullet{margin-left:1.5em}
|
||||
ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0;font-size:1em}
|
||||
ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit}
|
||||
ul.square{list-style-type:square}
|
||||
ul.circle{list-style-type:circle}
|
||||
ul.disc{list-style-type:disc}
|
||||
ul.no-bullet{list-style:none}
|
||||
ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}
|
||||
dl dt{margin-bottom:.3125em;font-weight:bold}
|
||||
dl dd{margin-bottom:1.25em}
|
||||
abbr,acronym{text-transform:uppercase;font-size:90%;color:rgba(0,0,0,.8);border-bottom:1px dotted #ddd;cursor:help}
|
||||
abbr{text-transform:none}
|
||||
blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd}
|
||||
blockquote cite{display:block;font-size:.9375em;color:rgba(0,0,0,.6)}
|
||||
blockquote cite:before{content:"\2014 \0020"}
|
||||
blockquote cite a,blockquote cite a:visited{color:rgba(0,0,0,.6)}
|
||||
blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)}
|
||||
@media only screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}
|
||||
h1{font-size:2.75em}
|
||||
h2{font-size:2.3125em}
|
||||
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em}
|
||||
h4{font-size:1.4375em}}table{background:#fff;margin-bottom:1.25em;border:solid 1px #dedede}
|
||||
table thead,table tfoot{background:#f7f8f7;font-weight:bold}
|
||||
table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left}
|
||||
table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)}
|
||||
table tr.even,table tr.alt,table tr:nth-of-type(even){background:#f8f8f7}
|
||||
table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{display:table-cell;line-height:1.6}
|
||||
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em}
|
||||
h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400}
|
||||
.clearfix:before,.clearfix:after,.float-group:before,.float-group:after{content:" ";display:table}
|
||||
.clearfix:after,.float-group:after{clear:both}
|
||||
*:not(pre)>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background-color:#f7f7f8;-webkit-border-radius:4px;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed}
|
||||
pre,pre>code{line-height:1.45;color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;text-rendering:optimizeSpeed}
|
||||
.keyseq{color:rgba(51,51,51,.8)}
|
||||
kbd{display:inline-block;color:rgba(0,0,0,.8);font-size:.75em;line-height:1.4;background-color:#f7f7f7;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em white inset;box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em #fff inset;margin:-.15em .15em 0 .15em;padding:.2em .6em .2em .5em;vertical-align:middle;white-space:nowrap}
|
||||
.keyseq kbd:first-child{margin-left:0}
|
||||
.keyseq kbd:last-child{margin-right:0}
|
||||
.menuseq,.menu{color:rgba(0,0,0,.8)}
|
||||
b.button:before,b.button:after{position:relative;top:-1px;font-weight:400}
|
||||
b.button:before{content:"[";padding:0 3px 0 2px}
|
||||
b.button:after{content:"]";padding:0 2px 0 3px}
|
||||
p a>code:hover{color:rgba(0,0,0,.9)}
|
||||
#header,#content,#footnotes,#footer{width:100%;margin-left:auto;margin-right:auto;margin-top:0;margin-bottom:0;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em}
|
||||
#header:before,#header:after,#content:before,#content:after,#footnotes:before,#footnotes:after,#footer:before,#footer:after{content:" ";display:table}
|
||||
#header:after,#content:after,#footnotes:after,#footer:after{clear:both}
|
||||
#content{margin-top:1.25em}
|
||||
#content:before{content:none}
|
||||
#header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0}
|
||||
#header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #ddddd8}
|
||||
#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #ddddd8;padding-bottom:8px}
|
||||
#header .details{border-bottom:1px solid #ddddd8;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap}
|
||||
#header .details span:first-child{margin-left:-.125em}
|
||||
#header .details span.email a{color:rgba(0,0,0,.85)}
|
||||
#header .details br{display:none}
|
||||
#header .details br+span:before{content:"\00a0\2013\00a0"}
|
||||
#header .details br+span.author:before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)}
|
||||
#header .details br+span#revremark:before{content:"\00a0|\00a0"}
|
||||
#header #revnumber{text-transform:capitalize}
|
||||
#header #revnumber:after{content:"\00a0"}
|
||||
#content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #ddddd8;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem}
|
||||
#toc{border-bottom:1px solid #efefed;padding-bottom:.5em}
|
||||
#toc>ul{margin-left:.125em}
|
||||
#toc ul.sectlevel0>li>a{font-style:italic}
|
||||
#toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0}
|
||||
#toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none}
|
||||
#toc a{text-decoration:none}
|
||||
#toc a:active{text-decoration:underline}
|
||||
#toctitle{color:#7a2518;font-size:1.2em}
|
||||
@media only screen and (min-width:768px){#toctitle{font-size:1.375em}
|
||||
body.toc2{padding-left:15em;padding-right:0}
|
||||
#toc.toc2{margin-top:0!important;background-color:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #efefed;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto}
|
||||
#toc.toc2 #toctitle{margin-top:0;font-size:1.2em}
|
||||
#toc.toc2>ul{font-size:.9em;margin-bottom:0}
|
||||
#toc.toc2 ul ul{margin-left:0;padding-left:1em}
|
||||
#toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em}
|
||||
body.toc2.toc-right{padding-left:0;padding-right:15em}
|
||||
body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #efefed;left:auto;right:0}}@media only screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0}
|
||||
#toc.toc2{width:20em}
|
||||
#toc.toc2 #toctitle{font-size:1.375em}
|
||||
#toc.toc2>ul{font-size:.95em}
|
||||
#toc.toc2 ul ul{padding-left:1.25em}
|
||||
body.toc2.toc-right{padding-left:0;padding-right:20em}}#content #toc{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
|
||||
#content #toc>:first-child{margin-top:0}
|
||||
#content #toc>:last-child{margin-bottom:0}
|
||||
#footer{max-width:100%;background-color:rgba(0,0,0,.8);padding:1.25em}
|
||||
#footer-text{color:rgba(255,255,255,.8);line-height:1.44}
|
||||
.sect1{padding-bottom:.625em}
|
||||
@media only screen and (min-width:768px){.sect1{padding-bottom:1.25em}}.sect1+.sect1{border-top:1px solid #efefed}
|
||||
#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400}
|
||||
#content h1>a.anchor:before,h2>a.anchor:before,h3>a.anchor:before,#toctitle>a.anchor:before,.sidebarblock>.content>.title>a.anchor:before,h4>a.anchor:before,h5>a.anchor:before,h6>a.anchor:before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em}
|
||||
#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}
|
||||
#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none}
|
||||
#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221}
|
||||
.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em}
|
||||
.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic}
|
||||
table.tableblock>caption.title{white-space:nowrap;overflow:visible;max-width:0}
|
||||
.paragraph.lead>p,#preamble>.sectionbody>.paragraph:first-of-type p{color:rgba(0,0,0,.85)}
|
||||
table.tableblock #preamble>.sectionbody>.paragraph:first-of-type p{font-size:inherit}
|
||||
.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%}
|
||||
.admonitionblock>table td.icon{text-align:center;width:80px}
|
||||
.admonitionblock>table td.icon img{max-width:none}
|
||||
.admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase}
|
||||
.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #ddddd8;color:rgba(0,0,0,.6)}
|
||||
.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}
|
||||
.exampleblock>.content{border-style:solid;border-width:1px;border-color:#e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;-webkit-border-radius:4px;border-radius:4px}
|
||||
.exampleblock>.content>:first-child{margin-top:0}
|
||||
.exampleblock>.content>:last-child{margin-bottom:0}
|
||||
.sidebarblock{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
|
||||
.sidebarblock>:first-child{margin-top:0}
|
||||
.sidebarblock>:last-child{margin-bottom:0}
|
||||
.sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center}
|
||||
.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}
|
||||
.literalblock pre,.listingblock pre:not(.highlight),.listingblock pre[class="highlight"],.listingblock pre[class^="highlight "],.listingblock pre.CodeRay,.listingblock pre.prettyprint{background:#f7f7f8}
|
||||
.sidebarblock .literalblock pre,.sidebarblock .listingblock pre:not(.highlight),.sidebarblock .listingblock pre[class="highlight"],.sidebarblock .listingblock pre[class^="highlight "],.sidebarblock .listingblock pre.CodeRay,.sidebarblock .listingblock pre.prettyprint{background:#f2f1f1}
|
||||
.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{-webkit-border-radius:4px;border-radius:4px;word-wrap:break-word;padding:1em;font-size:.8125em}
|
||||
.literalblock pre.nowrap,.literalblock pre[class].nowrap,.listingblock pre.nowrap,.listingblock pre[class].nowrap{overflow-x:auto;white-space:pre;word-wrap:normal}
|
||||
@media only screen and (min-width:768px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:.90625em}}@media only screen and (min-width:1280px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:1em}}.literalblock.output pre{color:#f7f7f8;background-color:rgba(0,0,0,.9)}
|
||||
.listingblock pre.highlightjs{padding:0}
|
||||
.listingblock pre.highlightjs>code{padding:1em;-webkit-border-radius:4px;border-radius:4px}
|
||||
.listingblock pre.prettyprint{border-width:0}
|
||||
.listingblock>.content{position:relative}
|
||||
.listingblock code[data-lang]:before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:#999}
|
||||
.listingblock:hover code[data-lang]:before{display:block}
|
||||
.listingblock.terminal pre .command:before{content:attr(data-prompt);padding-right:.5em;color:#999}
|
||||
.listingblock.terminal pre .command:not([data-prompt]):before{content:"$"}
|
||||
table.pyhltable{border-collapse:separate;border:0;margin-bottom:0;background:none}
|
||||
table.pyhltable td{vertical-align:top;padding-top:0;padding-bottom:0}
|
||||
table.pyhltable td.code{padding-left:.75em;padding-right:0}
|
||||
pre.pygments .lineno,table.pyhltable td:not(.code){color:#999;padding-left:0;padding-right:.5em;border-right:1px solid #ddddd8}
|
||||
pre.pygments .lineno{display:inline-block;margin-right:.25em}
|
||||
table.pyhltable .linenodiv{background:none!important;padding-right:0!important}
|
||||
.quoteblock{margin:0 1em 1.25em 1.5em;display:table}
|
||||
.quoteblock>.title{margin-left:-1.5em;margin-bottom:.75em}
|
||||
.quoteblock blockquote,.quoteblock blockquote p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify}
|
||||
.quoteblock blockquote{margin:0;padding:0;border:0}
|
||||
.quoteblock blockquote:before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)}
|
||||
.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}
|
||||
.quoteblock .attribution{margin-top:.5em;margin-right:.5ex;text-align:right}
|
||||
.quoteblock .quoteblock{margin-left:0;margin-right:0;padding:.5em 0;border-left:3px solid rgba(0,0,0,.6)}
|
||||
.quoteblock .quoteblock blockquote{padding:0 0 0 .75em}
|
||||
.quoteblock .quoteblock blockquote:before{display:none}
|
||||
.verseblock{margin:0 1em 1.25em 1em}
|
||||
.verseblock pre{font-family:"Open Sans","DejaVu Sans",sans;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility}
|
||||
.verseblock pre strong{font-weight:400}
|
||||
.verseblock .attribution{margin-top:1.25rem;margin-left:.5ex}
|
||||
.quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic}
|
||||
.quoteblock .attribution br,.verseblock .attribution br{display:none}
|
||||
.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.05em;color:rgba(0,0,0,.6)}
|
||||
.quoteblock.abstract{margin:0 0 1.25em 0;display:block}
|
||||
.quoteblock.abstract blockquote,.quoteblock.abstract blockquote p{text-align:left;word-spacing:0}
|
||||
.quoteblock.abstract blockquote:before,.quoteblock.abstract blockquote p:first-of-type:before{display:none}
|
||||
table.tableblock{max-width:100%;border-collapse:separate}
|
||||
table.tableblock td>.paragraph:last-child p>p:last-child,table.tableblock th>p:last-child,table.tableblock td>p:last-child{margin-bottom:0}
|
||||
table.spread{width:100%}
|
||||
table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede}
|
||||
table.grid-all th.tableblock,table.grid-all td.tableblock{border-width:0 1px 1px 0}
|
||||
table.grid-all tfoot>tr>th.tableblock,table.grid-all tfoot>tr>td.tableblock{border-width:1px 1px 0 0}
|
||||
table.grid-cols th.tableblock,table.grid-cols td.tableblock{border-width:0 1px 0 0}
|
||||
table.grid-all *>tr>.tableblock:last-child,table.grid-cols *>tr>.tableblock:last-child{border-right-width:0}
|
||||
table.grid-rows th.tableblock,table.grid-rows td.tableblock{border-width:0 0 1px 0}
|
||||
table.grid-all tbody>tr:last-child>th.tableblock,table.grid-all tbody>tr:last-child>td.tableblock,table.grid-all thead:last-child>tr>th.tableblock,table.grid-rows tbody>tr:last-child>th.tableblock,table.grid-rows tbody>tr:last-child>td.tableblock,table.grid-rows thead:last-child>tr>th.tableblock{border-bottom-width:0}
|
||||
table.grid-rows tfoot>tr>th.tableblock,table.grid-rows tfoot>tr>td.tableblock{border-width:1px 0 0 0}
|
||||
table.frame-all{border-width:1px}
|
||||
table.frame-sides{border-width:0 1px}
|
||||
table.frame-topbot{border-width:1px 0}
|
||||
th.halign-left,td.halign-left{text-align:left}
|
||||
th.halign-right,td.halign-right{text-align:right}
|
||||
th.halign-center,td.halign-center{text-align:center}
|
||||
th.valign-top,td.valign-top{vertical-align:top}
|
||||
th.valign-bottom,td.valign-bottom{vertical-align:bottom}
|
||||
th.valign-middle,td.valign-middle{vertical-align:middle}
|
||||
table thead th,table tfoot th{font-weight:bold}
|
||||
tbody tr th{display:table-cell;line-height:1.6;background:#f7f8f7}
|
||||
tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold}
|
||||
p.tableblock>code:only-child{background:none;padding:0}
|
||||
p.tableblock{font-size:1em}
|
||||
td>div.verse{white-space:pre}
|
||||
ol{margin-left:1.75em}
|
||||
ul li ol{margin-left:1.5em}
|
||||
dl dd{margin-left:1.125em}
|
||||
dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}
|
||||
ol>li p,ul>li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em}
|
||||
ul.unstyled,ol.unnumbered,ul.checklist,ul.none{list-style-type:none}
|
||||
ul.unstyled,ol.unnumbered,ul.checklist{margin-left:.625em}
|
||||
ul.checklist li>p:first-child>.fa-check-square-o:first-child,ul.checklist li>p:first-child>input[type="checkbox"]:first-child{margin-right:.25em}
|
||||
ul.checklist li>p:first-child>input[type="checkbox"]:first-child{position:relative;top:1px}
|
||||
ul.inline{margin:0 auto .625em auto;margin-left:-1.375em;margin-right:0;padding:0;list-style:none;overflow:hidden}
|
||||
ul.inline>li{list-style:none;float:left;margin-left:1.375em;display:block}
|
||||
ul.inline>li>*{display:block}
|
||||
.unstyled dl dt{font-weight:400;font-style:normal}
|
||||
ol.arabic{list-style-type:decimal}
|
||||
ol.decimal{list-style-type:decimal-leading-zero}
|
||||
ol.loweralpha{list-style-type:lower-alpha}
|
||||
ol.upperalpha{list-style-type:upper-alpha}
|
||||
ol.lowerroman{list-style-type:lower-roman}
|
||||
ol.upperroman{list-style-type:upper-roman}
|
||||
ol.lowergreek{list-style-type:lower-greek}
|
||||
.hdlist>table,.colist>table{border:0;background:none}
|
||||
.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none}
|
||||
td.hdlist1{padding-right:.75em;font-weight:bold}
|
||||
td.hdlist1,td.hdlist2{vertical-align:top}
|
||||
.literalblock+.colist,.listingblock+.colist{margin-top:-.5em}
|
||||
.colist>table tr>td:first-of-type{padding:0 .75em;line-height:1}
|
||||
.colist>table tr>td:last-of-type{padding:.25em 0}
|
||||
.thumb,.th{line-height:0;display:inline-block;border:solid 4px #fff;-webkit-box-shadow:0 0 0 1px #ddd;box-shadow:0 0 0 1px #ddd}
|
||||
.imageblock.left,.imageblock[style*="float: left"]{margin:.25em .625em 1.25em 0}
|
||||
.imageblock.right,.imageblock[style*="float: right"]{margin:.25em 0 1.25em .625em}
|
||||
.imageblock>.title{margin-bottom:0}
|
||||
.imageblock.thumb,.imageblock.th{border-width:6px}
|
||||
.imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em}
|
||||
.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0}
|
||||
.image.left{margin-right:.625em}
|
||||
.image.right{margin-left:.625em}
|
||||
a.image{text-decoration:none}
|
||||
span.footnote,span.footnoteref{vertical-align:super;font-size:.875em}
|
||||
span.footnote a,span.footnoteref a{text-decoration:none}
|
||||
span.footnote a:active,span.footnoteref a:active{text-decoration:underline}
|
||||
#footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em}
|
||||
#footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em 0;border-width:1px 0 0 0}
|
||||
#footnotes .footnote{padding:0 .375em;line-height:1.3;font-size:.875em;margin-left:1.2em;text-indent:-1.2em;margin-bottom:.2em}
|
||||
#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none}
|
||||
#footnotes .footnote:last-of-type{margin-bottom:0}
|
||||
#content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0}
|
||||
.gist .file-data>table{border:0;background:#fff;width:100%;margin-bottom:0}
|
||||
.gist .file-data>table td.line-data{width:99%}
|
||||
div.unbreakable{page-break-inside:avoid}
|
||||
.big{font-size:larger}
|
||||
.small{font-size:smaller}
|
||||
.underline{text-decoration:underline}
|
||||
.overline{text-decoration:overline}
|
||||
.line-through{text-decoration:line-through}
|
||||
.aqua{color:#00bfbf}
|
||||
.aqua-background{background-color:#00fafa}
|
||||
.black{color:#000}
|
||||
.black-background{background-color:#000}
|
||||
.blue{color:#0000bf}
|
||||
.blue-background{background-color:#0000fa}
|
||||
.fuchsia{color:#bf00bf}
|
||||
.fuchsia-background{background-color:#fa00fa}
|
||||
.gray{color:#606060}
|
||||
.gray-background{background-color:#7d7d7d}
|
||||
.green{color:#006000}
|
||||
.green-background{background-color:#007d00}
|
||||
.lime{color:#00bf00}
|
||||
.lime-background{background-color:#00fa00}
|
||||
.maroon{color:#600000}
|
||||
.maroon-background{background-color:#7d0000}
|
||||
.navy{color:#000060}
|
||||
.navy-background{background-color:#00007d}
|
||||
.olive{color:#606000}
|
||||
.olive-background{background-color:#7d7d00}
|
||||
.purple{color:#600060}
|
||||
.purple-background{background-color:#7d007d}
|
||||
.red{color:#bf0000}
|
||||
.red-background{background-color:#fa0000}
|
||||
.silver{color:#909090}
|
||||
.silver-background{background-color:#bcbcbc}
|
||||
.teal{color:#006060}
|
||||
.teal-background{background-color:#007d7d}
|
||||
.white{color:#bfbfbf}
|
||||
.white-background{background-color:#fafafa}
|
||||
.yellow{color:#bfbf00}
|
||||
.yellow-background{background-color:#fafa00}
|
||||
span.icon>.fa{cursor:default}
|
||||
.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default}
|
||||
.admonitionblock td.icon .icon-note:before{content:"\f05a";color:#19407c}
|
||||
.admonitionblock td.icon .icon-tip:before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111}
|
||||
.admonitionblock td.icon .icon-warning:before{content:"\f071";color:#bf6900}
|
||||
.admonitionblock td.icon .icon-caution:before{content:"\f06d";color:#bf3400}
|
||||
.admonitionblock td.icon .icon-important:before{content:"\f06a";color:#bf0000}
|
||||
.conum[data-value]{display:inline-block;color:#fff!important;background-color:rgba(0,0,0,.8);-webkit-border-radius:100px;border-radius:100px;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
|
||||
.conum[data-value] *{color:#fff!important}
|
||||
.conum[data-value]+b{display:none}
|
||||
.conum[data-value]:after{content:attr(data-value)}
|
||||
pre .conum[data-value]{position:relative;top:-.125em}
|
||||
b.conum *{color:inherit!important}
|
||||
.conum:not([data-value]):empty{display:none}
|
||||
h1,h2{letter-spacing:-.01em}
|
||||
dt,th.tableblock,td.content{text-rendering:optimizeLegibility}
|
||||
p,td.content{letter-spacing:-.01em}
|
||||
p strong,td.content strong{letter-spacing:-.005em}
|
||||
p,blockquote,dt,td.content{font-size:1.0625rem}
|
||||
p{margin-bottom:1.25rem}
|
||||
.sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em}
|
||||
.exampleblock>.content{background-color:#fffef7;border-color:#e0e0dc;-webkit-box-shadow:0 1px 4px #e0e0dc;box-shadow:0 1px 4px #e0e0dc}
|
||||
.print-only{display:none!important}
|
||||
@media print{@page{margin:1.25cm .75cm}
|
||||
*{-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important}
|
||||
a{color:inherit!important;text-decoration:underline!important}
|
||||
a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important}
|
||||
a[href^="http:"]:not(.bare):after,a[href^="https:"]:not(.bare):after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em}
|
||||
abbr[title]:after{content:" (" attr(title) ")"}
|
||||
pre,blockquote,tr,img{page-break-inside:avoid}
|
||||
thead{display:table-header-group}
|
||||
img{max-width:100%!important}
|
||||
p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3}
|
||||
h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid}
|
||||
#toc,.sidebarblock,.exampleblock>.content{background:none!important}
|
||||
#toc{border-bottom:1px solid #ddddd8!important;padding-bottom:0!important}
|
||||
.sect1{padding-bottom:0!important}
|
||||
.sect1+.sect1{border:0!important}
|
||||
#header>h1:first-child{margin-top:1.25rem}
|
||||
body.book #header{text-align:center}
|
||||
body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em 0}
|
||||
body.book #header .details{border:0!important;display:block;padding:0!important}
|
||||
body.book #header .details span:first-child{margin-left:0!important}
|
||||
body.book #header .details br{display:block}
|
||||
body.book #header .details br+span:before{content:none!important}
|
||||
body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important}
|
||||
body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always}
|
||||
.listingblock code[data-lang]:before{display:block}
|
||||
#footer{background:none!important;padding:0 .9375em}
|
||||
#footer-text{color:rgba(0,0,0,.6)!important;font-size:.9em}
|
||||
.hide-on-print{display:none!important}
|
||||
.print-only{display:block!important}
|
||||
.hide-for-print{display:none!important}
|
||||
.show-for-print{display:inherit!important}}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
general:
|
||||
branches:
|
||||
ignore:
|
||||
- gh-pages # list of branches to ignore
|
||||
machine:
|
||||
java:
|
||||
version: oraclejdk8
|
||||
environment:
|
||||
_JAVA_OPTIONS: "-Xms1024m -Xmx2048m"
|
||||
dependencies:
|
||||
override:
|
||||
- ./mvnw -s .settings.xml -U --fail-never dependency:go-offline || true
|
||||
test:
|
||||
override:
|
||||
- ./mvnw -s .settings.xml clean install org.jacoco:jacoco-maven-plugin:prepare-agent install -U -P sonar -nsu --batch-mode -Dmaven.test.redirectTestOutputToFile=true -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn
|
||||
post:
|
||||
- find . -type f -regex ".*/spring-cloud-*.*/target/*.*" | cpio -pdm $CIRCLE_ARTIFACTS
|
||||
- mkdir -p $CIRCLE_TEST_REPORTS/junit/
|
||||
- find . -type f -regex ".*/target/.*-reports/.*" -exec cp {} $CIRCLE_TEST_REPORTS/junit/ \;
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
|
||||
notify:
|
||||
webhooks:
|
||||
# A list of hook hashes, containing the url field
|
||||
# gitter hook
|
||||
- url: https://webhooks.gitter.im/e/22e6bb4eb945dd61ba54
|
||||
@@ -1,112 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>4.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix-docs</artifactId>
|
||||
<version>4.1.0-SNAPSHOT</version>
|
||||
<name>Spring Cloud Netflix Docs</name>
|
||||
<description>Spring Cloud Docs</description>
|
||||
<url>https://spring.io/spring-cloud/spring-cloud-netflix/spring-cloud-netflix-docs</url>
|
||||
<organization>
|
||||
<name>Pivotal Software, Inc.</name>
|
||||
<url>https://www.spring.io</url>
|
||||
</organization>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>Apache License, Version 2.0</name>
|
||||
<url>https://www.apache.org/licenses/LICENSE-2.0</url>
|
||||
<comments>Copyright 2014-2021 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.</comments>
|
||||
</license>
|
||||
</licenses>
|
||||
<developers>
|
||||
<developer>
|
||||
<id>dsyer</id>
|
||||
<name>Dave Syer</name>
|
||||
<email>dsyer at pivotal.io</email>
|
||||
<organization>Pivotal Software, Inc.</organization>
|
||||
<organizationUrl>https://www.spring.io</organizationUrl>
|
||||
<roles>
|
||||
<role>lead</role>
|
||||
</roles>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>sgibb</id>
|
||||
<name>Spencer Gibb</name>
|
||||
<email>sgibb at pivotal.io</email>
|
||||
<organization>Pivotal Software, Inc.</organization>
|
||||
<organizationUrl>https://www.spring.io</organizationUrl>
|
||||
<roles>
|
||||
<role>lead</role>
|
||||
</roles>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>mgrzejszczak</id>
|
||||
<name>Marcin Grzejszczak</name>
|
||||
<email>mgrzejszczak at pivotal.io</email>
|
||||
<organization>Pivotal Software, Inc.</organization>
|
||||
<organizationUrl>https://www.spring.io</organizationUrl>
|
||||
<roles>
|
||||
<role>developer</role>
|
||||
</roles>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>rbaxter</id>
|
||||
<name>Ryan Baxter</name>
|
||||
<email>rbaxter at pivotal.io</email>
|
||||
<organization>Pivotal Software, Inc.</organization>
|
||||
<organizationUrl>https://www.spring.io</organizationUrl>
|
||||
<roles>
|
||||
<role>developer</role>
|
||||
</roles>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>omaciaszeksharma</id>
|
||||
<name>Olga Maciaszek-Sharma</name>
|
||||
<email>omaciaszeksharma at pivotal.io</email>
|
||||
<organization>Pivotal Software, Inc.</organization>
|
||||
<organizationUrl>https://www.spring.io</organizationUrl>
|
||||
<roles>
|
||||
<role>developer</role>
|
||||
</roles>
|
||||
</developer>
|
||||
</developers>
|
||||
<scm>
|
||||
<connection>scm:git:git://github.com/spring-cloud/spring-cloud-netflix.git/spring-cloud-netflix-docs</connection>
|
||||
<developerConnection>scm:git:ssh://git@github.com/spring-cloud/spring-cloud-netflix.git/spring-cloud-netflix-docs</developerConnection>
|
||||
<url>https://github.com/spring-cloud/spring-cloud-netflix/spring-cloud-netflix-docs</url>
|
||||
</scm>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
|
||||
<version>4.1.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
|
||||
<version>4.1.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,53 @@
|
||||
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>1.2.8.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-docs</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>Spring Cloud Netflix Docs</name>
|
||||
<description>Spring Cloud Docs</description>
|
||||
<properties>
|
||||
<docs.main>spring-cloud-netflix</docs.main>
|
||||
<main.basedir>${basedir}/..</main.basedir>
|
||||
<docs.whitelisted.branches>1.0.x,1.1.x</docs.whitelisted.branches>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>docs</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.asciidoctor</groupId>
|
||||
<artifactId>asciidoctor-maven-plugin</artifactId>
|
||||
<inherited>false</inherited>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<inherited>false</inherited>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<inherited>false</inherited>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
@@ -0,0 +1,27 @@
|
||||
image::https://circleci.com/gh/spring-cloud/spring-cloud-netflix/tree/master.svg?style=svg["CircleCI", link="https://circleci.com/gh/spring-cloud/spring-cloud-netflix/tree/master"]
|
||||
image::https://codecov.io/gh/spring-cloud/spring-cloud-netflix/branch/master/graph/badge.svg["Codecov", link="https://codecov.io/gh/spring-cloud/spring-cloud-netflix/branch/master"]
|
||||
image::https://api.codacy.com/project/badge/Grade/a6885a06921e4f72a0df0b7aabd6d118["Codacy code quality", link="https://www.codacy.com/app/Spring-Cloud/spring-cloud-netflix?utm_source=github.com&utm_medium=referral&utm_content=spring-cloud/spring-cloud-netflix&utm_campaign=Badge_Grade"]
|
||||
|
||||
|
||||
include::intro.adoc[]
|
||||
|
||||
== Features
|
||||
|
||||
* Service Discovery: Eureka instances can be registered and clients can discover the instances using Spring-managed beans
|
||||
* Service Discovery: an embedded Eureka server can be created with declarative Java configuration
|
||||
* Circuit Breaker: Hystrix clients can be built with a simple annotation-driven method decorator
|
||||
* Circuit Breaker: embedded Hystrix dashboard with declarative Java configuration
|
||||
* Declarative REST Client: Feign creates a dynamic implementation of an interface decorated with JAX-RS or Spring MVC annotations
|
||||
* Client Side Load Balancer: Ribbon
|
||||
* External Configuration: a bridge from the Spring Environment to Archaius (enables native configuration of Netflix components using Spring Boot conventions)
|
||||
* Router and Filter: automatic registration of Zuul filters, and a simple convention over configuration approach to reverse proxy creation
|
||||
|
||||
== Building
|
||||
|
||||
include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/docs/src/main/asciidoc/building-jdk8.adoc[]
|
||||
|
||||
include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/docs/src/main/asciidoc/building-lombok.adoc[]
|
||||
|
||||
== Contributing
|
||||
|
||||
include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/docs/src/main/asciidoc/contributing.adoc[]
|
||||
Executable
+330
@@ -0,0 +1,330 @@
|
||||
#!/bin/bash -x
|
||||
|
||||
set -e
|
||||
|
||||
# Set default props like MAVEN_PATH, ROOT_FOLDER etc.
|
||||
function set_default_props() {
|
||||
# The script should be executed from the root folder
|
||||
ROOT_FOLDER=`pwd`
|
||||
echo "Current folder is ${ROOT_FOLDER}"
|
||||
|
||||
if [[ ! -e "${ROOT_FOLDER}/.git" ]]; then
|
||||
echo "You're not in the root folder of the project!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Prop that will let commit the changes
|
||||
COMMIT_CHANGES="no"
|
||||
MAVEN_PATH=${MAVEN_PATH:-}
|
||||
echo "Path to Maven is [${MAVEN_PATH}]"
|
||||
REPO_NAME=${PWD##*/}
|
||||
echo "Repo name is [${REPO_NAME}]"
|
||||
SPRING_CLOUD_STATIC_REPO=${SPRING_CLOUD_STATIC_REPO:-git@github.com:spring-cloud/spring-cloud-static.git}
|
||||
echo "Spring Cloud Static repo is [${SPRING_CLOUD_STATIC_REPO}"
|
||||
}
|
||||
|
||||
# Check if gh-pages exists and docs have been built
|
||||
function check_if_anything_to_sync() {
|
||||
git remote set-url --push origin `git config remote.origin.url | sed -e 's/^git:/https:/'`
|
||||
|
||||
if ! (git remote set-branches --add origin gh-pages && git fetch -q); then
|
||||
echo "No gh-pages, so not syncing"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! [ -d docs/target/generated-docs ] && ! [ "${BUILD}" == "yes" ]; then
|
||||
echo "No gh-pages sources in docs/target/generated-docs, so not syncing"
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
function retrieve_current_branch() {
|
||||
# Code getting the name of the current branch. For master we want to publish as we did until now
|
||||
# https://stackoverflow.com/questions/1593051/how-to-programmatically-determine-the-current-checked-out-git-branch
|
||||
# If there is a branch already passed will reuse it - otherwise will try to find it
|
||||
CURRENT_BRANCH=${BRANCH}
|
||||
if [[ -z "${CURRENT_BRANCH}" ]] ; then
|
||||
CURRENT_BRANCH=$(git symbolic-ref -q HEAD)
|
||||
CURRENT_BRANCH=${CURRENT_BRANCH##refs/heads/}
|
||||
CURRENT_BRANCH=${CURRENT_BRANCH:-HEAD}
|
||||
fi
|
||||
echo "Current branch is [${CURRENT_BRANCH}]"
|
||||
git checkout ${CURRENT_BRANCH} || echo "Failed to check the branch... continuing with the script"
|
||||
}
|
||||
|
||||
# Switches to the provided value of the release version. We always prefix it with `v`
|
||||
function switch_to_tag() {
|
||||
git checkout v${VERSION}
|
||||
}
|
||||
|
||||
# Build the docs if switch is on
|
||||
function build_docs_if_applicable() {
|
||||
if [[ "${BUILD}" == "yes" ]] ; then
|
||||
./mvnw clean install -P docs -pl docs -DskipTests
|
||||
fi
|
||||
}
|
||||
|
||||
# Get the name of the `docs.main` property
|
||||
# Get whitelisted branches - assumes that a `docs` module is available under `docs` profile
|
||||
function retrieve_doc_properties() {
|
||||
MAIN_ADOC_VALUE=$("${MAVEN_PATH}"mvn -q \
|
||||
-Dexec.executable="echo" \
|
||||
-Dexec.args='${docs.main}' \
|
||||
--non-recursive \
|
||||
org.codehaus.mojo:exec-maven-plugin:1.3.1:exec)
|
||||
echo "Extracted 'main.adoc' from Maven build [${MAIN_ADOC_VALUE}]"
|
||||
|
||||
|
||||
WHITELIST_PROPERTY=${WHITELIST_PROPERTY:-"docs.whitelisted.branches"}
|
||||
WHITELISTED_BRANCHES_VALUE=$("${MAVEN_PATH}"mvn -q \
|
||||
-Dexec.executable="echo" \
|
||||
-Dexec.args="\${${WHITELIST_PROPERTY}}" \
|
||||
org.codehaus.mojo:exec-maven-plugin:1.3.1:exec \
|
||||
-P docs \
|
||||
-pl docs)
|
||||
echo "Extracted '${WHITELIST_PROPERTY}' from Maven build [${WHITELISTED_BRANCHES_VALUE}]"
|
||||
}
|
||||
|
||||
# Stash any outstanding changes
|
||||
function stash_changes() {
|
||||
git diff-index --quiet HEAD && dirty=$? || (echo "Failed to check if the current repo is dirty. Assuming that it is." && dirty="1")
|
||||
if [ "$dirty" != "0" ]; then git stash; fi
|
||||
}
|
||||
|
||||
# Switch to gh-pages branch to sync it with current branch
|
||||
function add_docs_from_target() {
|
||||
local DESTINATION_REPO_FOLDER
|
||||
if [[ -z "${DESTINATION}" && -z "${CLONE}" ]] ; then
|
||||
DESTINATION_REPO_FOLDER=${ROOT_FOLDER}
|
||||
elif [[ "${CLONE}" == "yes" ]]; then
|
||||
mkdir -p ${ROOT_FOLDER}/target
|
||||
local clonedStatic=${ROOT_FOLDER}/target/spring-cloud-static
|
||||
if [[ ! -e "${clonedStatic}/.git" ]]; then
|
||||
echo "Cloning Spring Cloud Static to target"
|
||||
git clone ${SPRING_CLOUD_STATIC_REPO} ${clonedStatic} && git checkout gh-pages
|
||||
else
|
||||
echo "Spring Cloud Static already cloned - will pull changes"
|
||||
cd ${clonedStatic} && git checkout gh-pages && git pull origin gh-pages
|
||||
fi
|
||||
DESTINATION_REPO_FOLDER=${clonedStatic}/${REPO_NAME}
|
||||
mkdir -p ${DESTINATION_REPO_FOLDER}
|
||||
else
|
||||
if [[ ! -e "${DESTINATION}/.git" ]]; then
|
||||
echo "[${DESTINATION}] is not a git repository"
|
||||
exit 1
|
||||
fi
|
||||
DESTINATION_REPO_FOLDER=${DESTINATION}/${REPO_NAME}
|
||||
mkdir -p ${DESTINATION_REPO_FOLDER}
|
||||
echo "Destination was provided [${DESTINATION}]"
|
||||
fi
|
||||
cd ${DESTINATION_REPO_FOLDER}
|
||||
git checkout gh-pages
|
||||
git pull origin gh-pages
|
||||
|
||||
# Add git branches
|
||||
###################################################################
|
||||
if [[ -z "${VERSION}" ]] ; then
|
||||
copy_docs_for_current_version
|
||||
else
|
||||
copy_docs_for_provided_version
|
||||
fi
|
||||
commit_changes_if_applicable
|
||||
}
|
||||
|
||||
|
||||
# Copies the docs by using the retrieved properties from Maven build
|
||||
function copy_docs_for_current_version() {
|
||||
if [[ "${CURRENT_BRANCH}" == "master" ]] ; then
|
||||
echo -e "Current branch is master - will copy the current docs only to the root folder"
|
||||
for f in docs/target/generated-docs/*; do
|
||||
file=${f#docs/target/generated-docs/*}
|
||||
if ! git ls-files -i -o --exclude-standard --directory | grep -q ^$file$; then
|
||||
# Not ignored...
|
||||
cp -rf $f ${ROOT_FOLDER}/
|
||||
git add -A ${ROOT_FOLDER}/$file
|
||||
fi
|
||||
done
|
||||
COMMIT_CHANGES="yes"
|
||||
else
|
||||
echo -e "Current branch is [${CURRENT_BRANCH}]"
|
||||
# https://stackoverflow.com/questions/29300806/a-bash-script-to-check-if-a-string-is-present-in-a-comma-separated-list-of-strin
|
||||
if [[ ",${WHITELISTED_BRANCHES_VALUE}," = *",${CURRENT_BRANCH},"* ]] ; then
|
||||
mkdir -p ${ROOT_FOLDER}/${CURRENT_BRANCH}
|
||||
echo -e "Branch [${CURRENT_BRANCH}] is whitelisted! Will copy the current docs to the [${CURRENT_BRANCH}] folder"
|
||||
for f in docs/target/generated-docs/*; do
|
||||
file=${f#docs/target/generated-docs/*}
|
||||
if ! git ls-files -i -o --exclude-standard --directory | grep -q ^$file$; then
|
||||
# Not ignored...
|
||||
# We want users to access 1.0.0.RELEASE/ instead of 1.0.0.RELEASE/spring-cloud.sleuth.html
|
||||
if [[ "${file}" == "${MAIN_ADOC_VALUE}.html" ]] ; then
|
||||
# We don't want to copy the spring-cloud-sleuth.html
|
||||
# we want it to be converted to index.html
|
||||
cp -rf $f ${ROOT_FOLDER}/${CURRENT_BRANCH}/index.html
|
||||
git add -A ${ROOT_FOLDER}/${CURRENT_BRANCH}/index.html
|
||||
else
|
||||
cp -rf $f ${ROOT_FOLDER}/${CURRENT_BRANCH}
|
||||
git add -A ${ROOT_FOLDER}/${CURRENT_BRANCH}/$file
|
||||
fi
|
||||
fi
|
||||
done
|
||||
COMMIT_CHANGES="yes"
|
||||
else
|
||||
echo -e "Branch [${CURRENT_BRANCH}] is not on the white list! Check out the Maven [${WHITELIST_PROPERTY}] property in
|
||||
[docs] module available under [docs] profile. Won't commit any changes to gh-pages for this branch."
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Copies the docs by using the explicitly provided version
|
||||
function copy_docs_for_provided_version() {
|
||||
local FOLDER=${DESTINATION_REPO_FOLDER}/${VERSION}
|
||||
mkdir -p ${FOLDER}
|
||||
echo -e "Current tag is [v${VERSION}] Will copy the current docs to the [${FOLDER}] folder"
|
||||
for f in ${ROOT_FOLDER}/docs/target/generated-docs/*; do
|
||||
file=${f#${ROOT_FOLDER}/docs/target/generated-docs/*}
|
||||
copy_docs_for_branch ${file} ${FOLDER}
|
||||
done
|
||||
COMMIT_CHANGES="yes"
|
||||
CURRENT_BRANCH="v${VERSION}"
|
||||
}
|
||||
|
||||
# Copies the docs from target to the provided destination
|
||||
# Params:
|
||||
# $1 - file from target
|
||||
# $2 - destination to which copy the files
|
||||
function copy_docs_for_branch() {
|
||||
local file=$1
|
||||
local destination=$2
|
||||
if ! git ls-files -i -o --exclude-standard --directory | grep -q ^${file}$; then
|
||||
# Not ignored...
|
||||
# We want users to access 1.0.0.RELEASE/ instead of 1.0.0.RELEASE/spring-cloud.sleuth.html
|
||||
if [[ ("${file}" == "${MAIN_ADOC_VALUE}.html") || ("${file}" == "${REPO_NAME}.html") ]] ; then
|
||||
# We don't want to copy the spring-cloud-sleuth.html
|
||||
# we want it to be converted to index.html
|
||||
cp -rf $f ${destination}/index.html
|
||||
git add -A ${destination}/index.html
|
||||
else
|
||||
cp -rf $f ${destination}
|
||||
git add -A ${destination}/$file
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function commit_changes_if_applicable() {
|
||||
if [[ "${COMMIT_CHANGES}" == "yes" ]] ; then
|
||||
COMMIT_SUCCESSFUL="no"
|
||||
git commit -a -m "Sync docs from ${CURRENT_BRANCH} to gh-pages" && COMMIT_SUCCESSFUL="yes" || echo "Failed to commit changes"
|
||||
|
||||
# Uncomment the following push if you want to auto push to
|
||||
# the gh-pages branch whenever you commit to master locally.
|
||||
# This is a little extreme. Use with care!
|
||||
###################################################################
|
||||
if [[ "${COMMIT_SUCCESSFUL}" == "yes" ]] ; then
|
||||
git push origin gh-pages
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Switch back to the previous branch and exit block
|
||||
function checkout_previous_branch() {
|
||||
# If -version was provided we need to come back to root project
|
||||
cd ${ROOT_FOLDER}
|
||||
git checkout ${CURRENT_BRANCH} || echo "Failed to check the branch... continuing with the script"
|
||||
if [ "$dirty" != "0" ]; then git stash pop; fi
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Assert if properties have been properly passed
|
||||
function assert_properties() {
|
||||
echo "VERSION [${VERSION}], DESTINATION [${DESTINATION}], CLONE [${CLONE}]"
|
||||
if [[ "${VERSION}" != "" && (-z "${DESTINATION}" && -z "${CLONE}") ]] ; then echo "Version was set but destination / clone was not!"; exit 1;fi
|
||||
if [[ ("${DESTINATION}" != "" && "${CLONE}" != "") && -z "${VERSION}" ]] ; then echo "Destination / clone was set but version was not!"; exit 1;fi
|
||||
if [[ "${DESTINATION}" != "" && "${CLONE}" == "yes" ]] ; then echo "Destination and clone was set. Pick one!"; exit 1;fi
|
||||
}
|
||||
|
||||
# Prints the usage
|
||||
function print_usage() {
|
||||
cat <<EOF
|
||||
The idea of this script is to update gh-pages branch with the generated docs. Without any options
|
||||
the script will work in the following manner:
|
||||
|
||||
- if there's no gh-pages / target for docs module then the script ends
|
||||
- for master branch the generated docs are copied to the root of gh-pages branch
|
||||
- for any other branch (if that branch is whitelisted) a subfolder with branch name is created
|
||||
and docs are copied there
|
||||
- if the version switch is passed (-v) then a tag with (v) prefix will be retrieved and a folder
|
||||
with that version number will be created in the gh-pages branch. WARNING! No whitelist verification will take place
|
||||
- if the destination switch is passed (-d) then the script will check if the provided dir is a git repo and then will
|
||||
switch to gh-pages of that repo and copy the generated docs to `docs/<project-name>/<version>`
|
||||
- if the destination switch is passed (-d) then the script will check if the provided dir is a git repo and then will
|
||||
switch to gh-pages of that repo and copy the generated docs to `docs/<project-name>/<version>`
|
||||
|
||||
USAGE:
|
||||
|
||||
You can use the following options:
|
||||
|
||||
-v|--version - the script will apply the whole procedure for a particular library version
|
||||
-d|--destination - the root of destination folder where the docs should be copied. You have to use the full path.
|
||||
E.g. point to spring-cloud-static folder. Can't be used with (-c)
|
||||
-b|--build - will run the standard build process after checking out the branch
|
||||
-c|--clone - will automatically clone the spring-cloud-static repo instead of providing the destination.
|
||||
Obviously can't be used with (-d)
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
|
||||
# ==========================================
|
||||
# ____ ____ _____ _____ _____ _______
|
||||
# / ____|/ ____| __ \|_ _| __ \__ __|
|
||||
# | (___ | | | |__) | | | | |__) | | |
|
||||
# \___ \| | | _ / | | | ___/ | |
|
||||
# ____) | |____| | \ \ _| |_| | | |
|
||||
# |_____/ \_____|_| \_\_____|_| |_|
|
||||
#
|
||||
# ==========================================
|
||||
|
||||
while [[ $# > 0 ]]
|
||||
do
|
||||
key="$1"
|
||||
case ${key} in
|
||||
-v|--version)
|
||||
VERSION="$2"
|
||||
shift # past argument
|
||||
;;
|
||||
-d|--destination)
|
||||
DESTINATION="$2"
|
||||
shift # past argument
|
||||
;;
|
||||
-b|--build)
|
||||
BUILD="yes"
|
||||
;;
|
||||
-c|--clone)
|
||||
CLONE="yes"
|
||||
;;
|
||||
-h|--help)
|
||||
print_usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Invalid option: [$1]"
|
||||
print_usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift # past argument or value
|
||||
done
|
||||
|
||||
assert_properties
|
||||
set_default_props
|
||||
check_if_anything_to_sync
|
||||
if [[ -z "${VERSION}" ]] ; then
|
||||
retrieve_current_branch
|
||||
else
|
||||
switch_to_tag
|
||||
fi
|
||||
build_docs_if_applicable
|
||||
retrieve_doc_properties
|
||||
stash_changes
|
||||
add_docs_from_target
|
||||
checkout_previous_branch
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 225 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,7 @@
|
||||
This project provides Netflix OSS integrations for Spring Boot apps through autoconfiguration
|
||||
and binding to the Spring Environment and other Spring programming model idioms. With a few
|
||||
simple annotations you can quickly enable and configure the common patterns inside your
|
||||
application and build large distributed systems with battle-tested Netflix components. The
|
||||
patterns provided include Service Discovery (Eureka), Circuit Breaker (Hystrix),
|
||||
Intelligent Routing (Zuul) and Client Side Load Balancing (Ribbon).
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Executable
+37
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
base_dir = File.join(File.dirname(__FILE__),'../../..')
|
||||
src_dir = File.join(base_dir, "/src/main/asciidoc")
|
||||
require 'asciidoctor'
|
||||
require 'optparse'
|
||||
|
||||
options = {}
|
||||
file = "#{src_dir}/README.adoc"
|
||||
|
||||
OptionParser.new do |o|
|
||||
o.on('-o OUTPUT_FILE', 'Output file (default is stdout)') { |file| options[:to_file] = file unless file=='-' }
|
||||
o.on('-h', '--help') { puts o; exit }
|
||||
o.parse!
|
||||
end
|
||||
|
||||
file = ARGV[0] if ARGV.length>0
|
||||
|
||||
# Copied from https://github.com/asciidoctor/asciidoctor-extensions-lab/blob/master/scripts/asciidoc-coalescer.rb
|
||||
doc = Asciidoctor.load_file file, safe: :unsafe, header_only: true, attributes: options[:attributes]
|
||||
header_attr_names = (doc.instance_variable_get :@attributes_modified).to_a
|
||||
header_attr_names.each {|k| doc.attributes[%(#{k}!)] = '' unless doc.attr? k }
|
||||
attrs = doc.attributes
|
||||
attrs['allow-uri-read'] = true
|
||||
puts attrs
|
||||
|
||||
out = "// Do not edit this file (e.g. go instead to src/main/asciidoc)\n\n"
|
||||
doc = Asciidoctor.load_file file, safe: :unsafe, parse: false, attributes: attrs
|
||||
out << doc.reader.read
|
||||
|
||||
unless options[:to_file]
|
||||
puts out
|
||||
else
|
||||
File.open(options[:to_file],'w+') do |file|
|
||||
file.write(out)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,295 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<profiles version="12">
|
||||
<profile kind="CodeFormatterProfile" name="Spring Cloud Java Conventions" version="12">
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="8"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.problem.enumIdentifier" value="error"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="90"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.problem.assertIdentifier" value="error"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode" value="enabled"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.source" value="1.8"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform" value="1.8"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_binary_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.compiler.compliance" value="1.8"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="tab"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="90"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
|
||||
</profile>
|
||||
</profiles>
|
||||
@@ -0,0 +1,389 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.codeComplete.argumentPrefixes=
|
||||
org.eclipse.jdt.core.codeComplete.argumentSuffixes=
|
||||
org.eclipse.jdt.core.codeComplete.fieldPrefixes=
|
||||
org.eclipse.jdt.core.codeComplete.fieldSuffixes=
|
||||
org.eclipse.jdt.core.codeComplete.localPrefixes=
|
||||
org.eclipse.jdt.core.codeComplete.localSuffixes=
|
||||
org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
|
||||
org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
|
||||
org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
|
||||
org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.doc.comment.support=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
|
||||
org.eclipse.jdt.core.compiler.problem.deadCode=warning
|
||||
org.eclipse.jdt.core.compiler.problem.deprecation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
|
||||
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
|
||||
org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
|
||||
org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.invalidJavadoc=warning
|
||||
org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=default
|
||||
org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
|
||||
org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public
|
||||
org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=return_tag
|
||||
org.eclipse.jdt.core.compiler.problem.missingJavadocTags=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingJavadocTagsMethodTypeParameters=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=private
|
||||
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
|
||||
org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
|
||||
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.nullReference=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
|
||||
org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
|
||||
org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
|
||||
org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
|
||||
org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedImport=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
|
||||
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
|
||||
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.6
|
||||
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_assignment=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
|
||||
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
|
||||
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
|
||||
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_after_package=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_field=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_method=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_package=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
|
||||
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
|
||||
org.eclipse.jdt.core.formatter.comment.format_block_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_header=false
|
||||
org.eclipse.jdt.core.formatter.comment.format_html=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_line_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_source_code=false
|
||||
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
|
||||
org.eclipse.jdt.core.formatter.comment.indent_root_tags=false
|
||||
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=do not insert
|
||||
org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
|
||||
org.eclipse.jdt.core.formatter.comment.line_length=90
|
||||
org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
|
||||
org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
|
||||
org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
|
||||
org.eclipse.jdt.core.formatter.compact_else_if=true
|
||||
org.eclipse.jdt.core.formatter.continuation_indentation=2
|
||||
org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
|
||||
org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
|
||||
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
|
||||
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
|
||||
org.eclipse.jdt.core.formatter.indent_empty_lines=false
|
||||
org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
|
||||
org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
|
||||
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
|
||||
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
|
||||
org.eclipse.jdt.core.formatter.indentation.size=8
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.join_lines_in_comments=true
|
||||
org.eclipse.jdt.core.formatter.join_wrapped_lines=true
|
||||
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.lineSplit=90
|
||||
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
|
||||
org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
|
||||
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
|
||||
org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
|
||||
org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
|
||||
org.eclipse.jdt.core.formatter.tabulation.char=tab
|
||||
org.eclipse.jdt.core.formatter.tabulation.size=4
|
||||
org.eclipse.jdt.core.formatter.use_on_off_tags=false
|
||||
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
|
||||
org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
|
||||
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
|
||||
File diff suppressed because one or more lines are too long
@@ -8,7 +8,7 @@
|
||||
# "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
|
||||
# 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
|
||||
@@ -19,7 +19,7 @@
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Maven Start Up Batch script
|
||||
# Maven2 Start Up Batch script
|
||||
#
|
||||
# Required ENV vars:
|
||||
# ------------------
|
||||
@@ -54,16 +54,38 @@ 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
|
||||
;;
|
||||
#
|
||||
# Look for the Apple JDKs first to preserve the existing behaviour, and then look
|
||||
# for the new JDKs provided by Oracle.
|
||||
#
|
||||
if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then
|
||||
#
|
||||
# Apple JDKs
|
||||
#
|
||||
export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then
|
||||
#
|
||||
# Apple JDKs
|
||||
#
|
||||
export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then
|
||||
#
|
||||
# Oracle JDKs
|
||||
#
|
||||
export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then
|
||||
#
|
||||
# Apple JDKs
|
||||
#
|
||||
export JAVA_HOME=`/usr/libexec/java_home`
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
@@ -108,12 +130,13 @@ if $cygwin ; then
|
||||
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
|
||||
fi
|
||||
|
||||
# For Mingw, ensure paths are in UNIX format before anything is touched
|
||||
# For Migwn, 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)`"
|
||||
# TODO classpath?
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
@@ -161,28 +184,27 @@ fi
|
||||
|
||||
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
|
||||
|
||||
# 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"`
|
||||
fi
|
||||
|
||||
# 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"
|
||||
local basedir=$(pwd)
|
||||
local wdir=$(pwd)
|
||||
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
|
||||
wdir=$(cd "$wdir/.."; pwd)
|
||||
done
|
||||
echo "${basedir}"
|
||||
}
|
||||
@@ -194,108 +216,9 @@ concat_lines() {
|
||||
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
|
||||
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)}
|
||||
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 $@"
|
||||
@@ -303,8 +226,28 @@ export MAVEN_CMD_LINE_ARGS
|
||||
|
||||
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
echo "Running version check"
|
||||
VERSION=$( sed '\!<parent!,\!</parent!d' `dirname $0`/pom.xml | grep '<version' | head -1 | sed -e 's/.*<version>//' -e 's!</version>.*$!!' )
|
||||
echo "The found version is [${VERSION}]"
|
||||
|
||||
if echo $VERSION | egrep -q 'M|RC'; then
|
||||
echo Activating \"milestone\" profile for version=\"$VERSION\"
|
||||
echo $MAVEN_ARGS | grep -q milestone || MAVEN_ARGS="$MAVEN_ARGS -Pmilestone"
|
||||
else
|
||||
echo Deactivating \"milestone\" profile for version=\"$VERSION\"
|
||||
echo $MAVEN_ARGS | grep -q milestone && MAVEN_ARGS=$(echo $MAVEN_ARGS | sed -e 's/-Pmilestone//')
|
||||
fi
|
||||
|
||||
if echo $VERSION | egrep -q 'RELEASE'; then
|
||||
echo Activating \"central\" profile for version=\"$VERSION\"
|
||||
echo $MAVEN_ARGS | grep -q milestone || MAVEN_ARGS="$MAVEN_ARGS -Pcentral"
|
||||
else
|
||||
echo Deactivating \"central\" profile for version=\"$VERSION\"
|
||||
echo $MAVEN_ARGS | grep -q central && MAVEN_ARGS=$(echo $MAVEN_ARGS | sed -e 's/-Pcentral//')
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" \
|
||||
$MAVEN_OPTS \
|
||||
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
|
||||
${WRAPPER_LAUNCHER} ${MAVEN_ARGS} "$@"
|
||||
|
||||
@@ -1,182 +1,145 @@
|
||||
@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 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 https://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 Maven2 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 key stroke 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 enable echoing my 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
|
||||
|
||||
set MAVEN_CMD_LINE_ARGS=%*
|
||||
|
||||
@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"
|
||||
|
||||
@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%
|
||||
set WRAPPER_JAR="".\.mvn\wrapper\maven-wrapper.jar""
|
||||
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS%
|
||||
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%
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"antora": "3.2.0",
|
||||
"@antora/atlas-extension": "1.0.0-alpha.5",
|
||||
"@antora/collector-extension": "1.0.3",
|
||||
"@asciidoctor/tabs": "1.0.0-beta.6",
|
||||
"@springio/antora-extensions": "1.14.13",
|
||||
"@springio/asciidoctor-extensions": "1.0.0-alpha.18"
|
||||
}
|
||||
}
|
||||
@@ -1,63 +1,252 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<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>
|
||||
<artifactId>spring-cloud-netflix-docs-build</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>5.0.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
<name>Spring Cloud Netflix Docs Build</name>
|
||||
<description>Builds Spring Cloud Netflix Docs.</description>
|
||||
<url>https://spring.io/projects/spring-cloud-netflix</url>
|
||||
<scm>
|
||||
<connection>scm:git:https://github.com/spring-cloud/spring-cloud-netflix.git
|
||||
</connection>
|
||||
<developerConnection>
|
||||
scm:git:git@github.com:spring-cloud/spring-cloud-netflix.git
|
||||
</developerConnection>
|
||||
<url>https://github.com/spring-cloud/spring-cloud-netflix</url>
|
||||
</scm>
|
||||
<issueManagement>
|
||||
<url>https://github.com/spring-cloud/spring-cloud-netflix/issues</url>
|
||||
</issueManagement>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.antora</groupId>
|
||||
<artifactId>antora-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<snapshots><enabled>true</enabled></snapshots>
|
||||
<releases><enabled>false</enabled></releases>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
<snapshots><enabled>false</enabled></snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<snapshots><enabled>true</enabled></snapshots>
|
||||
<releases><enabled>false</enabled></releases>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
<snapshots><enabled>false</enabled></snapshots>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>1.2.8.BUILD-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Spring Cloud Netflix</name>
|
||||
<description>Spring Cloud Netflix</description>
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-build</artifactId>
|
||||
<version>1.2.3.BUILD-SNAPSHOT</version>
|
||||
<relativePath />
|
||||
</parent>
|
||||
<scm>
|
||||
<url>https://github.com/spring-cloud/spring-cloud-netflix</url>
|
||||
<connection>scm:git:git://github.com/spring-cloud/spring-cloud-netflix.git</connection>
|
||||
<developerConnection>scm:git:ssh://git@github.com/spring-cloud/spring-cloud-netflix.git</developerConnection>
|
||||
<tag>HEAD</tag>
|
||||
</scm>
|
||||
<properties>
|
||||
<bintray.package>netflix</bintray.package>
|
||||
<main.basedir>${basedir}</main.basedir>
|
||||
<netty.version>4.0.27.Final</netty.version>
|
||||
<jackson.version>2.7.3</jackson.version>
|
||||
<spring-cloud-commons.version>1.1.9.BUILD-SNAPSHOT</spring-cloud-commons.version>
|
||||
<spring-cloud-config.version>1.2.4.BUILD-SNAPSHOT</spring-cloud-config.version>
|
||||
<spring-cloud-stream.version>Brooklyn.BUILD-SNAPSHOT</spring-cloud-stream.version>
|
||||
|
||||
<!-- Sonar -->
|
||||
<surefire.plugin.version>2.19.1</surefire.plugin.version>
|
||||
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
|
||||
<sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
|
||||
<sonar.jacoco.reportPath>${project.basedir}/../target/jacoco.exec</sonar.jacoco.reportPath>
|
||||
<sonar.language>java</sonar.language>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-eclipse-plugin</artifactId>
|
||||
<configuration>
|
||||
<useProjectReferences>false</useProjectReferences>
|
||||
<additionalConfig>
|
||||
<file>
|
||||
<name>.settings/org.eclipse.jdt.ui.prefs</name>
|
||||
<location>${main.basedir}/eclipse/org.eclipse.jdt.ui.prefs</location>
|
||||
</file>
|
||||
<file>
|
||||
<name>.settings/org.eclipse.jdt.core.prefs</name>
|
||||
<location>${main.basedir}/eclipse/org.eclipse.jdt.core.prefs</location>
|
||||
</file>
|
||||
</additionalConfig>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix-dependencies</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-commons-dependencies</artifactId>
|
||||
<version>${spring-cloud-commons.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-commons</artifactId>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
<version>${spring-cloud-commons.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-config-dependencies</artifactId>
|
||||
<version>${spring-cloud-config.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-stream-dependencies</artifactId>
|
||||
<version>${spring-cloud-stream.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-codec-http</artifactId>
|
||||
<version>${netty.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-transport-native-epoll</artifactId>
|
||||
<version>${netty.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||
<artifactId>jackson-dataformat-smile</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<modules>
|
||||
<module>spring-cloud-netflix-dependencies</module>
|
||||
<module>spring-cloud-netflix-core</module>
|
||||
<module>spring-cloud-netflix-hystrix-dashboard</module>
|
||||
<module>spring-cloud-netflix-hystrix-amqp</module>
|
||||
<module>spring-cloud-netflix-hystrix-stream</module>
|
||||
<module>spring-cloud-netflix-eureka-client</module>
|
||||
<module>spring-cloud-netflix-eureka-server</module>
|
||||
<module>spring-cloud-netflix-spectator</module>
|
||||
<module>spring-cloud-netflix-turbine</module>
|
||||
<module>spring-cloud-netflix-turbine-stream</module>
|
||||
<module>spring-cloud-netflix-sidecar</module>
|
||||
<module>spring-cloud-starter-archaius</module>
|
||||
<module>spring-cloud-starter-atlas</module>
|
||||
<module>spring-cloud-starter-eureka</module>
|
||||
<module>spring-cloud-starter-eureka-server</module>
|
||||
<module>spring-cloud-starter-feign</module>
|
||||
<module>spring-cloud-starter-hystrix</module>
|
||||
<module>spring-cloud-starter-hystrix-dashboard</module>
|
||||
<module>spring-cloud-starter-ribbon</module>
|
||||
<module>spring-cloud-starter-spectator</module>
|
||||
<module>spring-cloud-starter-turbine</module>
|
||||
<module>spring-cloud-starter-turbine-amqp</module>
|
||||
<module>spring-cloud-starter-turbine-stream</module>
|
||||
<module>spring-cloud-starter-zuul</module>
|
||||
<module>docs</module>
|
||||
</modules>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>spring</id>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/libs-snapshot-local</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
<releases>
|
||||
<enabled>false</enabled>
|
||||
</releases>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/libs-milestone-local</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-releases</id>
|
||||
<name>Spring Releases</name>
|
||||
<url>https://repo.spring.io/release</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/libs-snapshot-local</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
<releases>
|
||||
<enabled>false</enabled>
|
||||
</releases>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/libs-milestone-local</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<id>spring-releases</id>
|
||||
<name>Spring Releases</name>
|
||||
<url>https://repo.spring.io/libs-release-local</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>sonar</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>pre-unit-test</id>
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<propertyName>surefireArgLine</propertyName>
|
||||
<destFile>${project.build.directory}/jacoco.exec</destFile>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>post-unit-test</id>
|
||||
<phase>test</phase>
|
||||
<goals>
|
||||
<goal>report</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<!-- Sets the path to the file which contains the execution data. -->
|
||||
<dataFile>${project.build.directory}/jacoco.exec</dataFile>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<!-- Sets the VM argument line used when unit tests are run. -->
|
||||
<argLine>${surefireArgLine}</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
|
||||
Executable
+27
@@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -o errexit
|
||||
|
||||
mkdir -p target
|
||||
|
||||
SCRIPT_URL="https://raw.githubusercontent.com/spring-cloud-samples/brewery/master/runAcceptanceTests.sh"
|
||||
AT_WHAT_TO_TEST="EUREKA"
|
||||
|
||||
cd target
|
||||
|
||||
curl "${SCRIPT_URL}" --output runAcceptanceTests.sh
|
||||
|
||||
chmod +x runAcceptanceTests.sh
|
||||
|
||||
echo "Killing all running apps"
|
||||
./runAcceptanceTests.sh -t "${AT_WHAT_TO_TEST}" --killnow
|
||||
|
||||
./runAcceptanceTests.sh -t "${AT_WHAT_TO_TEST}" --killattheend
|
||||
|
||||
SCRIPT_URL="https://raw.githubusercontent.com/spring-cloud-samples/tests/master/scripts/runTests.sh"
|
||||
|
||||
curl "${SCRIPT_URL}" --output runIntegrationTests.sh
|
||||
|
||||
chmod +x runIntegrationTests.sh
|
||||
|
||||
./runIntegrationTests.sh
|
||||
@@ -0,0 +1,234 @@
|
||||
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>1.2.8.BUILD-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Spring Cloud Netflix Core</name>
|
||||
<description>Spring Cloud Netflix Core</description>
|
||||
<properties>
|
||||
<main.basedir>${basedir}/..</main.basedir>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.retry</groupId>
|
||||
<artifactId>spring-retry</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-commons</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-context</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.archaius</groupId>
|
||||
<artifactId>archaius-core</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!-- archaius dependencies that are now runtime -->
|
||||
<dependency>
|
||||
<groupId>commons-configuration</groupId>
|
||||
<artifactId>commons-configuration</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!-- end archaius deps -->
|
||||
<dependency>
|
||||
<groupId>com.netflix.servo</groupId>
|
||||
<artifactId>servo-core</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.netflix-commons</groupId>
|
||||
<artifactId>netflix-commons-util</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.inject</groupId>
|
||||
<artifactId>javax.inject</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.ribbon</groupId>
|
||||
<artifactId>ribbon-loadbalancer</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.openfeign</groupId>
|
||||
<artifactId>feign-core</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.openfeign</groupId>
|
||||
<artifactId>feign-slf4j</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.openfeign</groupId>
|
||||
<artifactId>feign-httpclient</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.openfeign</groupId>
|
||||
<artifactId>feign-hystrix</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.openfeign</groupId>
|
||||
<artifactId>feign-okhttp</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.hystrix</groupId>
|
||||
<artifactId>hystrix-core</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.hystrix</groupId>
|
||||
<artifactId>hystrix-metrics-event-stream</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.hystrix</groupId>
|
||||
<artifactId>hystrix-javanica</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.ribbon</groupId>
|
||||
<artifactId>ribbon</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.ribbon</groupId>
|
||||
<artifactId>ribbon-core</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.ribbon</groupId>
|
||||
<artifactId>ribbon-httpclient</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.zuul</groupId>
|
||||
<artifactId>zuul-core</artifactId>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>groovy-all</artifactId>
|
||||
<groupId>org.codehaus.groovy</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<groupId>org.mockito</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.reactivex</groupId>
|
||||
<artifactId>rxjava</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey.contribs</groupId>
|
||||
<artifactId>jersey-apache-client4</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<!-- Only needed at compile time -->
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-commons</artifactId>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||
<artifactId>jackson-dataformat-smile</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>java8plus</id>
|
||||
<activation>
|
||||
<jdk>[1.8,2.0)</jdk>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<compilerArgs>
|
||||
<arg>-parameters</arg>
|
||||
</compilerArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
+214
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.archaius;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import javax.annotation.PreDestroy;
|
||||
|
||||
import org.apache.commons.configuration.AbstractConfiguration;
|
||||
import org.apache.commons.configuration.ConfigurationBuilder;
|
||||
import org.apache.commons.configuration.EnvironmentConfiguration;
|
||||
import org.apache.commons.configuration.SystemConfiguration;
|
||||
import org.apache.commons.configuration.event.ConfigurationEvent;
|
||||
import org.apache.commons.configuration.event.ConfigurationListener;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.condition.ConditionalOnEnabledEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.Endpoint;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import com.netflix.config.AggregatedConfiguration;
|
||||
import com.netflix.config.ConcurrentCompositeConfiguration;
|
||||
import com.netflix.config.ConfigurationManager;
|
||||
import com.netflix.config.DeploymentContext;
|
||||
import com.netflix.config.DynamicProperty;
|
||||
import com.netflix.config.DynamicPropertyFactory;
|
||||
import com.netflix.config.DynamicURLConfiguration;
|
||||
|
||||
import static com.netflix.config.ConfigurationManager.APPLICATION_PROPERTIES;
|
||||
import static com.netflix.config.ConfigurationManager.DISABLE_DEFAULT_ENV_CONFIG;
|
||||
import static com.netflix.config.ConfigurationManager.DISABLE_DEFAULT_SYS_CONFIG;
|
||||
import static com.netflix.config.ConfigurationManager.ENV_CONFIG_NAME;
|
||||
import static com.netflix.config.ConfigurationManager.SYS_CONFIG_NAME;
|
||||
import static com.netflix.config.ConfigurationManager.URL_CONFIG_NAME;
|
||||
|
||||
import lombok.extern.apachecommons.CommonsLog;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass({ ConcurrentCompositeConfiguration.class,
|
||||
ConfigurationBuilder.class })
|
||||
@CommonsLog
|
||||
public class ArchaiusAutoConfiguration {
|
||||
|
||||
private static final AtomicBoolean initialized = new AtomicBoolean(false);
|
||||
|
||||
@Autowired
|
||||
private ConfigurableEnvironment env;
|
||||
|
||||
@Autowired
|
||||
private List<AbstractConfiguration> externalConfigurations;
|
||||
|
||||
@PreDestroy
|
||||
public void close() {
|
||||
setStatic(ConfigurationManager.class, "instance", null);
|
||||
setStatic(ConfigurationManager.class, "customConfigurationInstalled", false);
|
||||
setStatic(DynamicPropertyFactory.class, "config", null);
|
||||
setStatic(DynamicPropertyFactory.class, "initializedWithDefaultConfig", false);
|
||||
setStatic(DynamicProperty.class, "dynamicPropertySupportImpl", null);
|
||||
initialized.compareAndSet(true, false);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ConfigurableEnvironmentConfiguration configurableEnvironmentConfiguration() {
|
||||
ConfigurableEnvironmentConfiguration envConfig = new ConfigurableEnvironmentConfiguration(
|
||||
this.env);
|
||||
configureArchaius(envConfig);
|
||||
return envConfig;
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(Endpoint.class)
|
||||
@ConditionalOnEnabledEndpoint("archaius")
|
||||
protected static class ArchaiusEndpointConfiguration {
|
||||
@Bean
|
||||
protected ArchaiusEndpoint archaiusEndpoint() {
|
||||
return new ArchaiusEndpoint();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnProperty(value = "archaius.propagate.environmentChangedEvent", matchIfMissing = true)
|
||||
@ConditionalOnClass(EnvironmentChangeEvent.class)
|
||||
protected static class PropagateEventsConfiguration
|
||||
implements ApplicationListener<EnvironmentChangeEvent> {
|
||||
@Autowired
|
||||
private Environment env;
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(EnvironmentChangeEvent event) {
|
||||
AbstractConfiguration manager = ConfigurationManager.getConfigInstance();
|
||||
for (String key : event.getKeys()) {
|
||||
for (ConfigurationListener listener : manager
|
||||
.getConfigurationListeners()) {
|
||||
Object source = event.getSource();
|
||||
// TODO: Handle add vs set vs delete?
|
||||
int type = AbstractConfiguration.EVENT_SET_PROPERTY;
|
||||
String value = this.env.getProperty(key);
|
||||
boolean beforeUpdate = false;
|
||||
listener.configurationChanged(new ConfigurationEvent(source, type,
|
||||
key, value, beforeUpdate));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void configureArchaius(ConfigurableEnvironmentConfiguration envConfig) {
|
||||
if (initialized.compareAndSet(false, true)) {
|
||||
String appName = this.env.getProperty("spring.application.name");
|
||||
if (appName == null) {
|
||||
appName = "application";
|
||||
log.warn("No spring.application.name found, defaulting to 'application'");
|
||||
}
|
||||
System.setProperty(DeploymentContext.ContextKey.appId.getKey(), appName);
|
||||
|
||||
ConcurrentCompositeConfiguration config = new ConcurrentCompositeConfiguration();
|
||||
|
||||
// support to add other Configurations (Jdbc, DynamoDb, Zookeeper, jclouds,
|
||||
// etc...)
|
||||
if (this.externalConfigurations != null) {
|
||||
for (AbstractConfiguration externalConfig : this.externalConfigurations) {
|
||||
config.addConfiguration(externalConfig);
|
||||
}
|
||||
}
|
||||
config.addConfiguration(envConfig,
|
||||
ConfigurableEnvironmentConfiguration.class.getSimpleName());
|
||||
|
||||
// below come from ConfigurationManager.createDefaultConfigInstance()
|
||||
DynamicURLConfiguration defaultURLConfig = new DynamicURLConfiguration();
|
||||
try {
|
||||
config.addConfiguration(defaultURLConfig, URL_CONFIG_NAME);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
log.error("Cannot create config from " + defaultURLConfig, ex);
|
||||
}
|
||||
|
||||
// TODO: sys/env above urls?
|
||||
if (!Boolean.getBoolean(DISABLE_DEFAULT_SYS_CONFIG)) {
|
||||
SystemConfiguration sysConfig = new SystemConfiguration();
|
||||
config.addConfiguration(sysConfig, SYS_CONFIG_NAME);
|
||||
}
|
||||
if (!Boolean.getBoolean(DISABLE_DEFAULT_ENV_CONFIG)) {
|
||||
EnvironmentConfiguration environmentConfiguration = new EnvironmentConfiguration();
|
||||
config.addConfiguration(environmentConfiguration, ENV_CONFIG_NAME);
|
||||
}
|
||||
|
||||
ConcurrentCompositeConfiguration appOverrideConfig = new ConcurrentCompositeConfiguration();
|
||||
config.addConfiguration(appOverrideConfig, APPLICATION_PROPERTIES);
|
||||
config.setContainerConfigurationIndex(
|
||||
config.getIndexOfConfiguration(appOverrideConfig));
|
||||
|
||||
addArchaiusConfiguration(config);
|
||||
}
|
||||
else {
|
||||
// TODO: reinstall ConfigurationManager
|
||||
log.warn(
|
||||
"Netflix ConfigurationManager has already been installed, unable to re-install");
|
||||
}
|
||||
}
|
||||
|
||||
private void addArchaiusConfiguration(ConcurrentCompositeConfiguration config) {
|
||||
if (ConfigurationManager.isConfigurationInstalled()) {
|
||||
AbstractConfiguration installedConfiguration = ConfigurationManager
|
||||
.getConfigInstance();
|
||||
if (installedConfiguration instanceof ConcurrentCompositeConfiguration) {
|
||||
ConcurrentCompositeConfiguration configInstance = (ConcurrentCompositeConfiguration) installedConfiguration;
|
||||
configInstance.addConfiguration(config);
|
||||
}
|
||||
else {
|
||||
installedConfiguration.append(config);
|
||||
if (!(installedConfiguration instanceof AggregatedConfiguration)) {
|
||||
log.warn(
|
||||
"Appending a configuration to an existing non-aggregated installed configuration will have no effect");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
ConfigurationManager.install(config);
|
||||
}
|
||||
}
|
||||
|
||||
private static void setStatic(Class<?> type, String name, Object value) {
|
||||
// Hack a private static field
|
||||
Field field = ReflectionUtils.findField(type, name);
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
ReflectionUtils.setField(field, null, value);
|
||||
}
|
||||
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2013-2014 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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.archaius;
|
||||
|
||||
import org.apache.commons.configuration.AbstractConfiguration;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
import com.netflix.config.ConfigurationManager;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class ArchaiusDelegatingProxyUtils {
|
||||
|
||||
public static String APPLICATION_CONTEXT = ApplicationContext.class.getName();
|
||||
|
||||
public static <T> T getNamedInstance(Class<T> type, String name) {
|
||||
ApplicationContext context = (ApplicationContext) ConfigurationManager
|
||||
.getConfigInstance().getProperty(APPLICATION_CONTEXT);
|
||||
return context != null && context.containsBean(name) ? context
|
||||
.getBean(name, type) : null;
|
||||
}
|
||||
|
||||
public static <T> T getInstanceWithPrefix(Class<T> type, String prefix) {
|
||||
String name = prefix + type.getSimpleName();
|
||||
return getNamedInstance(type, name);
|
||||
}
|
||||
|
||||
public static void addApplicationContext(ConfigurableApplicationContext context) {
|
||||
AbstractConfiguration config = ConfigurationManager.getConfigInstance();
|
||||
config.clearProperty(APPLICATION_CONTEXT);
|
||||
config.setProperty(APPLICATION_CONTEXT, context);
|
||||
}
|
||||
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2013-2014 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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.archaius;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.configuration.AbstractConfiguration;
|
||||
import org.apache.commons.configuration.Configuration;
|
||||
import org.apache.commons.configuration.EnvironmentConfiguration;
|
||||
import org.apache.commons.configuration.SystemConfiguration;
|
||||
import org.springframework.boot.actuate.endpoint.AbstractEndpoint;
|
||||
|
||||
import com.netflix.config.ConcurrentCompositeConfiguration;
|
||||
import com.netflix.config.ConfigurationManager;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class ArchaiusEndpoint extends AbstractEndpoint<Map<String, Object>> {
|
||||
|
||||
public ArchaiusEndpoint() {
|
||||
super("archaius");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> invoke() {
|
||||
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
AbstractConfiguration config = ConfigurationManager.getConfigInstance();
|
||||
if (config instanceof ConcurrentCompositeConfiguration) {
|
||||
ConcurrentCompositeConfiguration composite = (ConcurrentCompositeConfiguration) config;
|
||||
for (Configuration item : composite.getConfigurations()) {
|
||||
append(map, item);
|
||||
}
|
||||
}
|
||||
else {
|
||||
append(map, config);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private void append(Map<String, Object> map, Configuration config) {
|
||||
if (config instanceof ConfigurableEnvironmentConfiguration) {
|
||||
return;
|
||||
}
|
||||
if (config instanceof SystemConfiguration) {
|
||||
return;
|
||||
}
|
||||
if (config instanceof EnvironmentConfiguration) {
|
||||
return;
|
||||
}
|
||||
for (Iterator<String> iter = config.getKeys(); iter.hasNext();) {
|
||||
String key = iter.next();
|
||||
map.put(key, config.getProperty(key));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.archaius;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.configuration.AbstractConfiguration;
|
||||
import org.springframework.core.env.CompositePropertySource;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.EnumerablePropertySource;
|
||||
import org.springframework.core.env.MutablePropertySources;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class ConfigurableEnvironmentConfiguration extends AbstractConfiguration {
|
||||
|
||||
private final ConfigurableEnvironment environment;
|
||||
|
||||
public ConfigurableEnvironmentConfiguration(ConfigurableEnvironment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addPropertyDirect(String key, Object value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return !getKeys().hasNext(); // TODO: find a better way to do this
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(String key) {
|
||||
return this.environment.containsProperty(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getProperty(String key) {
|
||||
return this.environment.getProperty(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<String> getKeys() {
|
||||
List<String> result = new ArrayList<>();
|
||||
for (Map.Entry<String, PropertySource<?>> entry : getPropertySources().entrySet()) {
|
||||
PropertySource<?> source = entry.getValue();
|
||||
if (source instanceof EnumerablePropertySource) {
|
||||
EnumerablePropertySource<?> enumerable = (EnumerablePropertySource<?>) source;
|
||||
for (String name : enumerable.getPropertyNames()) {
|
||||
result.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.iterator();
|
||||
}
|
||||
|
||||
private Map<String, PropertySource<?>> getPropertySources() {
|
||||
Map<String, PropertySource<?>> map = new LinkedHashMap<>();
|
||||
MutablePropertySources sources = (this.environment != null ? this.environment
|
||||
.getPropertySources() : new StandardEnvironment().getPropertySources());
|
||||
for (PropertySource<?> source : sources) {
|
||||
extract("", map, source);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private void extract(String root, Map<String, PropertySource<?>> map,
|
||||
PropertySource<?> source) {
|
||||
if (source instanceof CompositePropertySource) {
|
||||
for (PropertySource<?> nest : ((CompositePropertySource) source)
|
||||
.getPropertySources()) {
|
||||
extract(source.getName() + ":", map, nest);
|
||||
}
|
||||
}
|
||||
else {
|
||||
map.put(root + source.getName(), source);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.endpoint;
|
||||
|
||||
import javax.servlet.Servlet;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.boot.actuate.endpoint.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.context.ServletContextAware;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.mvc.ServletWrappingController;
|
||||
|
||||
public abstract class ServletWrappingEndpoint implements InitializingBean,
|
||||
ApplicationContextAware, ServletContextAware, MvcEndpoint {
|
||||
|
||||
// TODO: move to spring-boot?
|
||||
|
||||
private String path;
|
||||
|
||||
private boolean sensitive;
|
||||
|
||||
private boolean enabled = true;
|
||||
|
||||
private final ServletWrappingController controller = new ServletWrappingController();
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
this.controller.afterPropertiesSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setServletContext(ServletContext servletContext) {
|
||||
this.controller.setServletContext(servletContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext)
|
||||
throws BeansException {
|
||||
this.controller.setApplicationContext(applicationContext);
|
||||
}
|
||||
|
||||
protected ServletWrappingEndpoint(Class<? extends Servlet> servletClass,
|
||||
String servletName, String path, boolean sensitive, boolean enabled) {
|
||||
this.controller.setServletClass(servletClass);
|
||||
this.controller.setServletName(servletName);
|
||||
this.path = path;
|
||||
this.sensitive = sensitive;
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
@RequestMapping("**")
|
||||
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response)
|
||||
throws Exception {
|
||||
return this.controller.handleRequest(request, response);
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
public ServletWrappingController getController() {
|
||||
return this.controller;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return this.path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSensitive() {
|
||||
return this.sensitive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Endpoint<?>> getEndpointType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Collection;
|
||||
|
||||
import feign.MethodMetadata;
|
||||
|
||||
/**
|
||||
* Feign contract method parameter processor.
|
||||
*
|
||||
* @author Jakub Narloch
|
||||
*/
|
||||
public interface AnnotatedParameterProcessor {
|
||||
|
||||
/**
|
||||
* Retrieves the processor supported annotation type.
|
||||
*
|
||||
* @return the annotation type
|
||||
*/
|
||||
Class<? extends Annotation> getAnnotationType();
|
||||
|
||||
/**
|
||||
* Process the annotated parameter.
|
||||
*
|
||||
* @param context the parameter context
|
||||
* @param annotation the annotation instance
|
||||
* @return whether the parameter is http
|
||||
*/
|
||||
boolean processArgument(AnnotatedParameterContext context, Annotation annotation);
|
||||
|
||||
/**
|
||||
* Specifies the parameter context.
|
||||
*
|
||||
* @author Jakub Narloch
|
||||
*/
|
||||
interface AnnotatedParameterContext {
|
||||
|
||||
/**
|
||||
* Retrieves the method metadata.
|
||||
*
|
||||
* @return the method metadata
|
||||
*/
|
||||
MethodMetadata getMethodMetadata();
|
||||
|
||||
/**
|
||||
* Retrieves the index of the parameter.
|
||||
*
|
||||
* @return the parameter index
|
||||
*/
|
||||
int getParameterIndex();
|
||||
|
||||
/**
|
||||
* Sets the parameter name.
|
||||
*
|
||||
* @param name the name of the parameter
|
||||
*/
|
||||
void setParameterName(String name);
|
||||
|
||||
/**
|
||||
* Sets the template parameter.
|
||||
*
|
||||
* @param name the template parameter
|
||||
* @param rest the existing parameter values
|
||||
* @return parameters
|
||||
*/
|
||||
Collection<String> setTemplateParameter(String name, Collection<String> rest);
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2016 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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign;
|
||||
|
||||
import feign.Logger;
|
||||
import feign.slf4j.Slf4jLogger;
|
||||
|
||||
/**
|
||||
* @author Venil Noronha
|
||||
*/
|
||||
public class DefaultFeignLoggerFactory implements FeignLoggerFactory {
|
||||
|
||||
private Logger logger;
|
||||
|
||||
public DefaultFeignLoggerFactory(Logger logger) {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logger create(Class<?> type) {
|
||||
return this.logger != null ? this.logger : new Slf4jLogger(type);
|
||||
}
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign;
|
||||
|
||||
import feign.Feign;
|
||||
import feign.Target;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
class DefaultTargeter implements Targeter {
|
||||
|
||||
@Override
|
||||
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,
|
||||
Target.HardCodedTarget<T> target) {
|
||||
return feign.target(target);
|
||||
}
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* Scans for interfaces that declare they are feign clients (via {@link FeignClient
|
||||
* <code>@FeignClient</code>}). Configures component scanning directives for use with
|
||||
* {@link org.springframework.context.annotation.Configuration
|
||||
* <code>@Configuration</code>} classes.
|
||||
*
|
||||
* @author Spencer Gibb
|
||||
* @author Dave Syer
|
||||
* @since 1.0
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Documented
|
||||
@Import(FeignClientsRegistrar.class)
|
||||
public @interface EnableFeignClients {
|
||||
|
||||
/**
|
||||
* Alias for the {@link #basePackages()} attribute. Allows for more concise annotation
|
||||
* declarations e.g.: {@code @ComponentScan("org.my.pkg")} instead of
|
||||
* {@code @ComponentScan(basePackages="org.my.pkg")}.
|
||||
* @return the array of 'basePackages'.
|
||||
*/
|
||||
String[] value() default {};
|
||||
|
||||
/**
|
||||
* Base packages to scan for annotated components.
|
||||
* <p>
|
||||
* {@link #value()} is an alias for (and mutually exclusive with) this attribute.
|
||||
* <p>
|
||||
* Use {@link #basePackageClasses()} for a type-safe alternative to String-based
|
||||
* package names.
|
||||
*
|
||||
* @return the array of 'basePackages'.
|
||||
*/
|
||||
String[] basePackages() default {};
|
||||
|
||||
/**
|
||||
* Type-safe alternative to {@link #basePackages()} for specifying the packages to
|
||||
* scan for annotated components. The package of each class specified will be scanned.
|
||||
* <p>
|
||||
* Consider creating a special no-op marker class or interface in each package that
|
||||
* serves no purpose other than being referenced by this attribute.
|
||||
*
|
||||
* @return the array of 'basePackageClasses'.
|
||||
*/
|
||||
Class<?>[] basePackageClasses() default {};
|
||||
|
||||
/**
|
||||
* A custom <code>@Configuration</code> for all feign clients. Can contain override
|
||||
* <code>@Bean</code> definition for the pieces that make up the client, for instance
|
||||
* {@link feign.codec.Decoder}, {@link feign.codec.Encoder}, {@link feign.Contract}.
|
||||
*
|
||||
* @see FeignClientsConfiguration for the defaults
|
||||
*/
|
||||
Class<?>[] defaultConfiguration() default {};
|
||||
|
||||
/**
|
||||
* List of classes annotated with @FeignClient. If not empty, disables classpath scanning.
|
||||
* @return
|
||||
*/
|
||||
Class<?>[] clients() default {};
|
||||
}
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.client.actuator.HasFeatures;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import feign.Client;
|
||||
import feign.Feign;
|
||||
import feign.httpclient.ApacheHttpClient;
|
||||
import feign.okhttp.OkHttpClient;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
* @author Julien Roy
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(Feign.class)
|
||||
public class FeignAutoConfiguration {
|
||||
|
||||
@Autowired(required = false)
|
||||
private List<FeignClientSpecification> configurations = new ArrayList<>();
|
||||
|
||||
@Bean
|
||||
public HasFeatures feignFeature() {
|
||||
return HasFeatures.namedFeature("Feign", Feign.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FeignContext feignContext() {
|
||||
FeignContext context = new FeignContext();
|
||||
context.setConfigurations(this.configurations);
|
||||
return context;
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(name = "feign.hystrix.HystrixFeign")
|
||||
protected static class HystrixFeignTargeterConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Targeter feignTargeter() {
|
||||
return new HystrixTargeter();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnMissingClass("feign.hystrix.HystrixFeign")
|
||||
protected static class DefaultFeignTargeterConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Targeter feignTargeter() {
|
||||
return new DefaultTargeter();
|
||||
}
|
||||
}
|
||||
|
||||
// the following configuration is for alternate feign clients if
|
||||
// ribbon is not on the class path.
|
||||
// see corresponding configurations in FeignRibbonClientAutoConfiguration
|
||||
// for load balanced ribbon clients.
|
||||
@Configuration
|
||||
@ConditionalOnClass(ApacheHttpClient.class)
|
||||
@ConditionalOnMissingClass("com.netflix.loadbalancer.ILoadBalancer")
|
||||
@ConditionalOnProperty(value = "feign.httpclient.enabled", matchIfMissing = true)
|
||||
protected static class HttpClientFeignConfiguration {
|
||||
|
||||
@Autowired(required = false)
|
||||
private HttpClient httpClient;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(Client.class)
|
||||
public Client feignClient() {
|
||||
if (this.httpClient != null) {
|
||||
return new ApacheHttpClient(this.httpClient);
|
||||
}
|
||||
return new ApacheHttpClient();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(OkHttpClient.class)
|
||||
@ConditionalOnMissingClass("com.netflix.loadbalancer.ILoadBalancer")
|
||||
@ConditionalOnProperty(value = "feign.okhttp.enabled", matchIfMissing = true)
|
||||
protected static class OkHttpFeignConfiguration {
|
||||
|
||||
@Autowired(required = false)
|
||||
private okhttp3.OkHttpClient okHttpClient;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(Client.class)
|
||||
public Client feignClient() {
|
||||
if (this.okHttpClient != null) {
|
||||
return new OkHttpClient(this.okHttpClient);
|
||||
}
|
||||
return new OkHttpClient();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
|
||||
/**
|
||||
* Annotation for interfaces declaring that a REST client with that interface should be
|
||||
* created (e.g. for autowiring into another component). If ribbon is available it will be
|
||||
* used to load balance the backend requests, and the load balancer can be configured
|
||||
* using a <code>@RibbonClient</code> with the same name (i.e. value) as the feign client.
|
||||
*
|
||||
* @author Spencer Gibb
|
||||
* @author Venil Noronha
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface FeignClient {
|
||||
|
||||
/**
|
||||
* The name of the service with optional protocol prefix. Synonym for {@link #name()
|
||||
* name}. A name must be specified for all clients, whether or not a url is provided.
|
||||
* Can be specified as property key, eg: ${propertyKey}.
|
||||
*/
|
||||
@AliasFor("name")
|
||||
String value() default "";
|
||||
|
||||
/**
|
||||
* The service id with optional protocol prefix. Synonym for {@link #value() value}.
|
||||
*
|
||||
* @deprecated use {@link #name() name} instead
|
||||
*/
|
||||
@Deprecated
|
||||
String serviceId() default "";
|
||||
|
||||
/**
|
||||
* The service id with optional protocol prefix. Synonym for {@link #value() value}.
|
||||
*/
|
||||
@AliasFor("value")
|
||||
String name() default "";
|
||||
|
||||
/**
|
||||
* Sets the <code>@Qualifier</code> value for the feign client.
|
||||
*/
|
||||
String qualifier() default "";
|
||||
|
||||
/**
|
||||
* An absolute URL or resolvable hostname (the protocol is optional).
|
||||
*/
|
||||
String url() default "";
|
||||
|
||||
/**
|
||||
* Whether 404s should be decoded instead of throwing FeignExceptions
|
||||
*/
|
||||
boolean decode404() default false;
|
||||
|
||||
/**
|
||||
* A custom <code>@Configuration</code> for the feign client. Can contain override
|
||||
* <code>@Bean</code> definition for the pieces that make up the client, for instance
|
||||
* {@link feign.codec.Decoder}, {@link feign.codec.Encoder}, {@link feign.Contract}.
|
||||
*
|
||||
* @see FeignClientsConfiguration for the defaults
|
||||
*/
|
||||
Class<?>[] configuration() default {};
|
||||
|
||||
/**
|
||||
* Fallback class for the specified Feign client interface. The fallback class must
|
||||
* implement the interface annotated by this annotation and be a valid spring bean.
|
||||
*/
|
||||
Class<?> fallback() default void.class;
|
||||
|
||||
/**
|
||||
* Define a fallback factory for the specified Feign client interface. The fallback
|
||||
* factory must produce instances of fallback classes that implement the interface
|
||||
* annotated by {@link FeignClient}. The fallback factory must be a valid spring
|
||||
* bean.
|
||||
*
|
||||
* @see feign.hystrix.FallbackFactory for details.
|
||||
*/
|
||||
Class<?> fallbackFactory() default void.class;
|
||||
|
||||
/**
|
||||
* Path prefix to be used by all method-level mappings. Can be used with or without
|
||||
* <code>@RibbonClient</code>.
|
||||
*/
|
||||
String path() default "";
|
||||
|
||||
}
|
||||
+211
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.netflix.feign.ribbon.LoadBalancerFeignClient;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import feign.Client;
|
||||
import feign.Contract;
|
||||
import feign.Feign;
|
||||
import feign.Logger;
|
||||
import feign.Request;
|
||||
import feign.RequestInterceptor;
|
||||
import feign.Retryer;
|
||||
import feign.Target.HardCodedTarget;
|
||||
import feign.codec.Decoder;
|
||||
import feign.codec.Encoder;
|
||||
import feign.codec.ErrorDecoder;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
* @author Venil Noronha
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean,
|
||||
ApplicationContextAware {
|
||||
/***********************************
|
||||
* WARNING! Nothing in this class should be @Autowired. It causes NPEs because of some lifecycle race condition.
|
||||
***********************************/
|
||||
|
||||
private Class<?> type;
|
||||
|
||||
private String name;
|
||||
|
||||
private String url;
|
||||
|
||||
private String path;
|
||||
|
||||
private boolean decode404;
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private Class<?> fallback = void.class;
|
||||
|
||||
private Class<?> fallbackFactory = void.class;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.hasText(this.name, "Name must be set");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext context) throws BeansException {
|
||||
this.applicationContext = context;
|
||||
}
|
||||
|
||||
protected Feign.Builder feign(FeignContext context) {
|
||||
FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
|
||||
Logger logger = loggerFactory.create(this.type);
|
||||
|
||||
// @formatter:off
|
||||
Feign.Builder builder = get(context, Feign.Builder.class)
|
||||
// required values
|
||||
.logger(logger)
|
||||
.encoder(get(context, Encoder.class))
|
||||
.decoder(get(context, Decoder.class))
|
||||
.contract(get(context, Contract.class));
|
||||
// @formatter:on
|
||||
|
||||
// optional values
|
||||
Logger.Level level = getOptional(context, Logger.Level.class);
|
||||
if (level != null) {
|
||||
builder.logLevel(level);
|
||||
}
|
||||
Retryer retryer = getOptional(context, Retryer.class);
|
||||
if (retryer != null) {
|
||||
builder.retryer(retryer);
|
||||
}
|
||||
ErrorDecoder errorDecoder = getOptional(context, ErrorDecoder.class);
|
||||
if (errorDecoder != null) {
|
||||
builder.errorDecoder(errorDecoder);
|
||||
}
|
||||
Request.Options options = getOptional(context, Request.Options.class);
|
||||
if (options != null) {
|
||||
builder.options(options);
|
||||
}
|
||||
Map<String, RequestInterceptor> requestInterceptors = context.getInstances(
|
||||
this.name, RequestInterceptor.class);
|
||||
if (requestInterceptors != null) {
|
||||
builder.requestInterceptors(requestInterceptors.values());
|
||||
}
|
||||
|
||||
if (decode404) {
|
||||
builder.decode404();
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
protected <T> T get(FeignContext context, Class<T> type) {
|
||||
T instance = context.getInstance(this.name, type);
|
||||
if (instance == null) {
|
||||
throw new IllegalStateException("No bean found of type " + type + " for "
|
||||
+ this.name);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
protected <T> T getOptional(FeignContext context, Class<T> type) {
|
||||
return context.getInstance(this.name, type);
|
||||
}
|
||||
|
||||
protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
|
||||
HardCodedTarget<T> target) {
|
||||
Client client = getOptional(context, Client.class);
|
||||
if (client != null) {
|
||||
builder.client(client);
|
||||
Targeter targeter = get(context, Targeter.class);
|
||||
return targeter.target(this, builder, context, target);
|
||||
}
|
||||
|
||||
throw new IllegalStateException(
|
||||
"No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-ribbon?");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObject() throws Exception {
|
||||
FeignContext context = applicationContext.getBean(FeignContext.class);
|
||||
Feign.Builder builder = feign(context);
|
||||
|
||||
if (!StringUtils.hasText(this.url)) {
|
||||
String url;
|
||||
if (!this.name.startsWith("http")) {
|
||||
url = "http://" + this.name;
|
||||
}
|
||||
else {
|
||||
url = this.name;
|
||||
}
|
||||
url += cleanPath();
|
||||
return loadBalance(builder, context, new HardCodedTarget<>(this.type,
|
||||
this.name, url));
|
||||
}
|
||||
if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
|
||||
this.url = "http://" + this.url;
|
||||
}
|
||||
String url = this.url + cleanPath();
|
||||
Client client = getOptional(context, Client.class);
|
||||
if (client != null) {
|
||||
if (client instanceof LoadBalancerFeignClient) {
|
||||
// not lod balancing because we have a url,
|
||||
// but ribbon is on the classpath, so unwrap
|
||||
client = ((LoadBalancerFeignClient)client).getDelegate();
|
||||
}
|
||||
builder.client(client);
|
||||
}
|
||||
Targeter targeter = get(context, Targeter.class);
|
||||
return targeter.target(this, builder, context, new HardCodedTarget<>(
|
||||
this.type, this.name, url));
|
||||
}
|
||||
|
||||
private String cleanPath() {
|
||||
String path = this.path.trim();
|
||||
if (StringUtils.hasLength(path)) {
|
||||
if (!path.startsWith("/")) {
|
||||
path = "/" + path;
|
||||
}
|
||||
if (path.endsWith("/")) {
|
||||
path = path.substring(0, path.length() - 1);
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign;
|
||||
|
||||
import org.springframework.cloud.context.named.NamedContextFactory;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
class FeignClientSpecification implements NamedContextFactory.Specification {
|
||||
|
||||
private String name;
|
||||
|
||||
private Class<?>[] configuration;
|
||||
|
||||
}
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign;
|
||||
|
||||
import feign.Contract;
|
||||
import feign.Feign;
|
||||
import feign.Logger;
|
||||
import feign.Retryer;
|
||||
import feign.codec.Decoder;
|
||||
import feign.codec.Encoder;
|
||||
import feign.hystrix.HystrixFeign;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
|
||||
import org.springframework.cloud.netflix.feign.support.ResponseEntityDecoder;
|
||||
import org.springframework.cloud.netflix.feign.support.SpringDecoder;
|
||||
import org.springframework.cloud.netflix.feign.support.SpringEncoder;
|
||||
import org.springframework.cloud.netflix.feign.support.SpringMvcContract;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.format.support.DefaultFormattingConversionService;
|
||||
import org.springframework.format.support.FormattingConversionService;
|
||||
import com.netflix.hystrix.HystrixCommand;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
* @author Venil Noronha
|
||||
*/
|
||||
@Configuration
|
||||
public class FeignClientsConfiguration {
|
||||
|
||||
@Autowired
|
||||
private ObjectFactory<HttpMessageConverters> messageConverters;
|
||||
|
||||
@Autowired(required = false)
|
||||
private List<AnnotatedParameterProcessor> parameterProcessors = new ArrayList<>();
|
||||
|
||||
@Autowired(required = false)
|
||||
private List<FeignFormatterRegistrar> feignFormatterRegistrars = new ArrayList<>();
|
||||
|
||||
@Autowired(required = false)
|
||||
private Logger logger;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Decoder feignDecoder() {
|
||||
return new ResponseEntityDecoder(new SpringDecoder(this.messageConverters));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Encoder feignEncoder() {
|
||||
return new SpringEncoder(this.messageConverters);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Contract feignContract(ConversionService feignConversionService) {
|
||||
return new SpringMvcContract(this.parameterProcessors, feignConversionService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FormattingConversionService feignConversionService() {
|
||||
FormattingConversionService conversionService = new DefaultFormattingConversionService();
|
||||
for (FeignFormatterRegistrar feignFormatterRegistrar : feignFormatterRegistrars) {
|
||||
feignFormatterRegistrar.registerFormatters(conversionService);
|
||||
}
|
||||
return conversionService;
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass({ HystrixCommand.class, HystrixFeign.class })
|
||||
protected static class HystrixFeignConfiguration {
|
||||
@Bean
|
||||
@Scope("prototype")
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnProperty(name = "feign.hystrix.enabled", matchIfMissing = true)
|
||||
public Feign.Builder feignHystrixBuilder() {
|
||||
return HystrixFeign.builder();
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Retryer feignRetryer() {
|
||||
return Retryer.NEVER_RETRY;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Scope("prototype")
|
||||
@ConditionalOnMissingBean
|
||||
public Feign.Builder feignBuilder(Retryer retryer) {
|
||||
return Feign.builder().retryer(retryer);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(FeignLoggerFactory.class)
|
||||
public FeignLoggerFactory feignLoggerFactory() {
|
||||
return new DefaultFeignLoggerFactory(logger);
|
||||
}
|
||||
|
||||
}
|
||||
+410
@@ -0,0 +1,410 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.core.type.ClassMetadata;
|
||||
import org.springframework.core.type.classreading.MetadataReader;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
import org.springframework.core.type.filter.AbstractClassTestingTypeFilter;
|
||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
import org.springframework.core.type.filter.TypeFilter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
* @author Jakub Narloch
|
||||
* @author Venil Noronha
|
||||
*/
|
||||
class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar,
|
||||
ResourceLoaderAware, BeanClassLoaderAware {
|
||||
|
||||
// patterned after Spring Integration IntegrationComponentScanRegistrar
|
||||
// and RibbonClientsConfigurationRegistgrar
|
||||
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
private ClassLoader classLoader;
|
||||
|
||||
public FeignClientsRegistrar() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerBeanDefinitions(AnnotationMetadata metadata,
|
||||
BeanDefinitionRegistry registry) {
|
||||
registerDefaultConfiguration(metadata, registry);
|
||||
registerFeignClients(metadata, registry);
|
||||
}
|
||||
|
||||
private void registerDefaultConfiguration(AnnotationMetadata metadata,
|
||||
BeanDefinitionRegistry registry) {
|
||||
Map<String, Object> defaultAttrs = metadata
|
||||
.getAnnotationAttributes(EnableFeignClients.class.getName(), true);
|
||||
|
||||
if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) {
|
||||
String name;
|
||||
if (metadata.hasEnclosingClass()) {
|
||||
name = "default." + metadata.getEnclosingClassName();
|
||||
}
|
||||
else {
|
||||
name = "default." + metadata.getClassName();
|
||||
}
|
||||
registerClientConfiguration(registry, name,
|
||||
defaultAttrs.get("defaultConfiguration"));
|
||||
}
|
||||
}
|
||||
|
||||
public void registerFeignClients(AnnotationMetadata metadata,
|
||||
BeanDefinitionRegistry registry) {
|
||||
ClassPathScanningCandidateComponentProvider scanner = getScanner();
|
||||
scanner.setResourceLoader(this.resourceLoader);
|
||||
|
||||
Set<String> basePackages;
|
||||
|
||||
Map<String, Object> attrs = metadata
|
||||
.getAnnotationAttributes(EnableFeignClients.class.getName());
|
||||
AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(
|
||||
FeignClient.class);
|
||||
final Class<?>[] clients = attrs == null ? null
|
||||
: (Class<?>[]) attrs.get("clients");
|
||||
if (clients == null || clients.length == 0) {
|
||||
scanner.addIncludeFilter(annotationTypeFilter);
|
||||
basePackages = getBasePackages(metadata);
|
||||
}
|
||||
else {
|
||||
final Set<String> clientClasses = new HashSet<>();
|
||||
basePackages = new HashSet<>();
|
||||
for (Class<?> clazz : clients) {
|
||||
basePackages.add(ClassUtils.getPackageName(clazz));
|
||||
clientClasses.add(clazz.getCanonicalName());
|
||||
}
|
||||
AbstractClassTestingTypeFilter filter = new AbstractClassTestingTypeFilter() {
|
||||
@Override
|
||||
protected boolean match(ClassMetadata metadata) {
|
||||
String cleaned = metadata.getClassName().replaceAll("\\$", ".");
|
||||
return clientClasses.contains(cleaned);
|
||||
}
|
||||
};
|
||||
scanner.addIncludeFilter(
|
||||
new AllTypeFilter(Arrays.asList(filter, annotationTypeFilter)));
|
||||
}
|
||||
|
||||
for (String basePackage : basePackages) {
|
||||
Set<BeanDefinition> candidateComponents = scanner
|
||||
.findCandidateComponents(basePackage);
|
||||
for (BeanDefinition candidateComponent : candidateComponents) {
|
||||
if (candidateComponent instanceof AnnotatedBeanDefinition) {
|
||||
// verify annotated class is an interface
|
||||
AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
|
||||
AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
|
||||
Assert.isTrue(annotationMetadata.isInterface(),
|
||||
"@FeignClient can only be specified on an interface");
|
||||
|
||||
Map<String, Object> attributes = annotationMetadata
|
||||
.getAnnotationAttributes(
|
||||
FeignClient.class.getCanonicalName());
|
||||
|
||||
String name = getClientName(attributes);
|
||||
registerClientConfiguration(registry, name,
|
||||
attributes.get("configuration"));
|
||||
|
||||
registerFeignClient(registry, annotationMetadata, attributes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void registerFeignClient(BeanDefinitionRegistry registry,
|
||||
AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
|
||||
String className = annotationMetadata.getClassName();
|
||||
BeanDefinitionBuilder definition = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(FeignClientFactoryBean.class);
|
||||
validate(attributes);
|
||||
definition.addPropertyValue("url", getUrl(attributes));
|
||||
definition.addPropertyValue("path", getPath(attributes));
|
||||
String name = getName(attributes);
|
||||
definition.addPropertyValue("name", name);
|
||||
definition.addPropertyValue("type", className);
|
||||
definition.addPropertyValue("decode404", attributes.get("decode404"));
|
||||
definition.addPropertyValue("fallback", attributes.get("fallback"));
|
||||
definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
|
||||
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
|
||||
|
||||
String alias = name + "FeignClient";
|
||||
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
|
||||
beanDefinition.setPrimary(true);
|
||||
|
||||
String qualifier = getQualifier(attributes);
|
||||
if (StringUtils.hasText(qualifier)) {
|
||||
alias = qualifier;
|
||||
}
|
||||
|
||||
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
|
||||
new String[] { alias });
|
||||
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
|
||||
}
|
||||
|
||||
private void validate(Map<String, Object> attributes) {
|
||||
AnnotationAttributes annotation = AnnotationAttributes.fromMap(attributes);
|
||||
// This blows up if an aliased property is overspecified
|
||||
annotation.getAliasedString("name", FeignClient.class, null);
|
||||
}
|
||||
|
||||
/* for testing */ String getName(Map<String, Object> attributes) {
|
||||
String name = (String) attributes.get("serviceId");
|
||||
if (!StringUtils.hasText(name)) {
|
||||
name = (String) attributes.get("name");
|
||||
}
|
||||
if (!StringUtils.hasText(name)) {
|
||||
name = (String) attributes.get("value");
|
||||
}
|
||||
name = resolve(name);
|
||||
if (!StringUtils.hasText(name)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
String host = null;
|
||||
try {
|
||||
String url;
|
||||
if (!name.startsWith("http://") && !name.startsWith("https://")) {
|
||||
url = "http://" + name;
|
||||
} else {
|
||||
url = name;
|
||||
}
|
||||
host = new URI(url).getHost();
|
||||
|
||||
}
|
||||
catch (URISyntaxException e) {
|
||||
}
|
||||
Assert.state(host != null, "Service id not legal hostname (" + name + ")");
|
||||
return name;
|
||||
}
|
||||
|
||||
private String resolve(String value) {
|
||||
if (StringUtils.hasText(value)
|
||||
&& this.resourceLoader instanceof ConfigurableApplicationContext) {
|
||||
return ((ConfigurableApplicationContext) this.resourceLoader).getEnvironment()
|
||||
.resolvePlaceholders(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private String getUrl(Map<String, Object> attributes) {
|
||||
String url = resolve((String) attributes.get("url"));
|
||||
if (StringUtils.hasText(url)) {
|
||||
if (!url.contains("://")) {
|
||||
url = "http://" + url;
|
||||
}
|
||||
try {
|
||||
new URL(url);
|
||||
}
|
||||
catch (MalformedURLException e) {
|
||||
throw new IllegalArgumentException(url + " is malformed", e);
|
||||
}
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
private String getPath(Map<String, Object> attributes) {
|
||||
String path = resolve((String) attributes.get("path"));
|
||||
if (StringUtils.hasText(path)) {
|
||||
path = path.trim();
|
||||
if (!path.startsWith("/")) {
|
||||
path = "/" + path;
|
||||
}
|
||||
if (path.endsWith("/")) {
|
||||
path = path.substring(0, path.length() - 1);
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
protected ClassPathScanningCandidateComponentProvider getScanner() {
|
||||
return new ClassPathScanningCandidateComponentProvider(false) {
|
||||
|
||||
@Override
|
||||
protected boolean isCandidateComponent(
|
||||
AnnotatedBeanDefinition beanDefinition) {
|
||||
if (beanDefinition.getMetadata().isIndependent()) {
|
||||
// TODO until SPR-11711 will be resolved
|
||||
if (beanDefinition.getMetadata().isInterface()
|
||||
&& beanDefinition.getMetadata()
|
||||
.getInterfaceNames().length == 1
|
||||
&& Annotation.class.getName().equals(beanDefinition
|
||||
.getMetadata().getInterfaceNames()[0])) {
|
||||
try {
|
||||
Class<?> target = ClassUtils.forName(
|
||||
beanDefinition.getMetadata().getClassName(),
|
||||
FeignClientsRegistrar.this.classLoader);
|
||||
return !target.isAnnotation();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
this.logger.error(
|
||||
"Could not load target class: "
|
||||
+ beanDefinition.getMetadata().getClassName(),
|
||||
ex);
|
||||
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected Set<String> getBasePackages(AnnotationMetadata importingClassMetadata) {
|
||||
Map<String, Object> attributes = importingClassMetadata
|
||||
.getAnnotationAttributes(EnableFeignClients.class.getCanonicalName());
|
||||
|
||||
Set<String> basePackages = new HashSet<>();
|
||||
for (String pkg : (String[]) attributes.get("value")) {
|
||||
if (StringUtils.hasText(pkg)) {
|
||||
basePackages.add(pkg);
|
||||
}
|
||||
}
|
||||
for (String pkg : (String[]) attributes.get("basePackages")) {
|
||||
if (StringUtils.hasText(pkg)) {
|
||||
basePackages.add(pkg);
|
||||
}
|
||||
}
|
||||
for (Class<?> clazz : (Class[]) attributes.get("basePackageClasses")) {
|
||||
basePackages.add(ClassUtils.getPackageName(clazz));
|
||||
}
|
||||
|
||||
if (basePackages.isEmpty()) {
|
||||
basePackages.add(
|
||||
ClassUtils.getPackageName(importingClassMetadata.getClassName()));
|
||||
}
|
||||
return basePackages;
|
||||
}
|
||||
|
||||
private String getQualifier(Map<String, Object> client) {
|
||||
if (client == null) {
|
||||
return null;
|
||||
}
|
||||
String qualifier = (String) client.get("qualifier");
|
||||
if (StringUtils.hasText(qualifier)) {
|
||||
return qualifier;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getClientName(Map<String, Object> client) {
|
||||
if (client == null) {
|
||||
return null;
|
||||
}
|
||||
String value = (String) client.get("value");
|
||||
if (!StringUtils.hasText(value)) {
|
||||
value = (String) client.get("name");
|
||||
}
|
||||
if (!StringUtils.hasText(value)) {
|
||||
value = (String) client.get("serviceId");
|
||||
}
|
||||
if (StringUtils.hasText(value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Either 'name' or 'value' must be provided in @"
|
||||
+ FeignClient.class.getSimpleName());
|
||||
}
|
||||
|
||||
private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name,
|
||||
Object configuration) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(FeignClientSpecification.class);
|
||||
builder.addConstructorArgValue(name);
|
||||
builder.addConstructorArgValue(configuration);
|
||||
registry.registerBeanDefinition(
|
||||
name + "." + FeignClientSpecification.class.getSimpleName(),
|
||||
builder.getBeanDefinition());
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class to create a {@link TypeFilter} that matches if all the delegates
|
||||
* match.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private static class AllTypeFilter implements TypeFilter {
|
||||
|
||||
private final List<TypeFilter> delegates;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AllTypeFilter} to match if all the given delegates match.
|
||||
*
|
||||
* @param delegates must not be {@literal null}.
|
||||
*/
|
||||
public AllTypeFilter(List<TypeFilter> delegates) {
|
||||
|
||||
Assert.notNull(delegates);
|
||||
this.delegates = delegates;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean match(MetadataReader metadataReader,
|
||||
MetadataReaderFactory metadataReaderFactory) throws IOException {
|
||||
|
||||
for (TypeFilter filter : this.delegates) {
|
||||
if (!filter.match(metadataReader, metadataReaderFactory)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign;
|
||||
|
||||
import org.springframework.cloud.context.named.NamedContextFactory;
|
||||
|
||||
/**
|
||||
* A factory that creates instances of feign classes. It creates a Spring
|
||||
* ApplicationContext per client name, and extracts the beans that it needs from there.
|
||||
*
|
||||
* @author Spencer Gibb
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class FeignContext extends NamedContextFactory<FeignClientSpecification> {
|
||||
|
||||
public FeignContext() {
|
||||
super(FeignClientsConfiguration.class, "feign", "feign.client.name");
|
||||
}
|
||||
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign;
|
||||
|
||||
import org.springframework.format.FormatterRegistrar;
|
||||
import org.springframework.format.support.FormattingConversionService;
|
||||
|
||||
/**
|
||||
* Allows an application to customize the Feign {@link FormattingConversionService}.
|
||||
*
|
||||
* @author Matt Benson
|
||||
*/
|
||||
public interface FeignFormatterRegistrar extends FormatterRegistrar {
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2016 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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign;
|
||||
|
||||
import feign.Logger;
|
||||
|
||||
/**
|
||||
* Allows an application to use a custom Feign {@link Logger}.
|
||||
*
|
||||
* @author Venil Noronha
|
||||
*/
|
||||
public interface FeignLoggerFactory {
|
||||
|
||||
/**
|
||||
* Factory method to provide a {@link Logger} for a given {@link Class}.
|
||||
*
|
||||
* @param type the {@link Class} for which a {@link Logger} instance is to be created
|
||||
* @return a {@link Logger} instance
|
||||
*/
|
||||
public Logger create(Class<?> type);
|
||||
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign;
|
||||
|
||||
import feign.Feign;
|
||||
import feign.Target;
|
||||
import feign.hystrix.FallbackFactory;
|
||||
import feign.hystrix.HystrixFeign;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
class HystrixTargeter implements Targeter {
|
||||
|
||||
@Override
|
||||
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,
|
||||
Target.HardCodedTarget<T> target) {
|
||||
if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {
|
||||
return feign.target(target);
|
||||
}
|
||||
feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign;
|
||||
Class<?> fallback = factory.getFallback();
|
||||
if (fallback != void.class) {
|
||||
return targetWithFallback(factory.getName(), context, target, builder, fallback);
|
||||
}
|
||||
Class<?> fallbackFactory = factory.getFallbackFactory();
|
||||
if (fallbackFactory != void.class) {
|
||||
return targetWithFallbackFactory(factory.getName(), context, target, builder, fallbackFactory);
|
||||
}
|
||||
|
||||
return feign.target(target);
|
||||
}
|
||||
|
||||
private <T> T targetWithFallbackFactory(String feignClientName, FeignContext context,
|
||||
Target.HardCodedTarget<T> target,
|
||||
HystrixFeign.Builder builder,
|
||||
Class<?> fallbackFactoryClass) {
|
||||
FallbackFactory<? extends T> fallbackFactory = (FallbackFactory<? extends T>)
|
||||
getFromContext("fallbackFactory", feignClientName, context, fallbackFactoryClass, FallbackFactory.class);
|
||||
/* We take a sample fallback from the fallback factory to check if it returns a fallback
|
||||
that is compatible with the annotated feign interface. */
|
||||
Object exampleFallback = fallbackFactory.create(new RuntimeException());
|
||||
Assert.notNull(exampleFallback,
|
||||
String.format(
|
||||
"Incompatible fallbackFactory instance for feign client %s. Factory may not produce null!",
|
||||
feignClientName));
|
||||
if (!target.type().isAssignableFrom(exampleFallback.getClass())) {
|
||||
throw new IllegalStateException(
|
||||
String.format(
|
||||
"Incompatible fallbackFactory instance for feign client %s. Factory produces instances of '%s', but should produce instances of '%s'",
|
||||
feignClientName, exampleFallback.getClass(), target.type()));
|
||||
}
|
||||
return builder.target(target, fallbackFactory);
|
||||
}
|
||||
|
||||
|
||||
private <T> T targetWithFallback(String feignClientName, FeignContext context,
|
||||
Target.HardCodedTarget<T> target,
|
||||
HystrixFeign.Builder builder, Class<?> fallback) {
|
||||
T fallbackInstance = getFromContext("fallback", feignClientName, context, fallback, target.type());
|
||||
return builder.target(target, fallbackInstance);
|
||||
}
|
||||
|
||||
private <T> T getFromContext(String fallbackMechanism, String feignClientName, FeignContext context,
|
||||
Class<?> beanType, Class<T> targetType) {
|
||||
Object fallbackInstance = context.getInstance(feignClientName, beanType);
|
||||
if (fallbackInstance == null) {
|
||||
throw new IllegalStateException(String.format(
|
||||
"No " + fallbackMechanism + " instance of type %s found for feign client %s",
|
||||
beanType, feignClientName));
|
||||
}
|
||||
|
||||
if (!targetType.isAssignableFrom(beanType)) {
|
||||
throw new IllegalStateException(
|
||||
String.format(
|
||||
"Incompatible " + fallbackMechanism + " instance. Fallback/fallbackFactory of type %s is not assignable to %s for feign client %s",
|
||||
beanType, targetType, feignClientName));
|
||||
}
|
||||
return (T) fallbackInstance;
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign;
|
||||
|
||||
import feign.Feign;
|
||||
import feign.Target;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
interface Targeter {
|
||||
<T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,
|
||||
Target.HardCodedTarget<T> target);
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign.annotation;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.cloud.netflix.feign.AnnotatedParameterProcessor;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
|
||||
import feign.MethodMetadata;
|
||||
|
||||
import static feign.Util.checkState;
|
||||
import static feign.Util.emptyToNull;
|
||||
|
||||
/**
|
||||
* {@link PathVariable} parameter processor.
|
||||
*
|
||||
* @author Jakub Narloch
|
||||
* @see AnnotatedParameterProcessor
|
||||
*/
|
||||
public class PathVariableParameterProcessor implements AnnotatedParameterProcessor {
|
||||
|
||||
private static final Class<PathVariable> ANNOTATION = PathVariable.class;
|
||||
|
||||
@Override
|
||||
public Class<? extends Annotation> getAnnotationType() {
|
||||
return ANNOTATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processArgument(AnnotatedParameterContext context, Annotation annotation) {
|
||||
String name = ANNOTATION.cast(annotation).value();
|
||||
checkState(emptyToNull(name) != null,
|
||||
"PathVariable annotation was empty on param %s.", context.getParameterIndex());
|
||||
context.setParameterName(name);
|
||||
|
||||
MethodMetadata data = context.getMethodMetadata();
|
||||
String varName = '{' + name + '}';
|
||||
if (!data.template().url().contains(varName)
|
||||
&& !searchMapValues(data.template().queries(), varName)
|
||||
&& !searchMapValues(data.template().headers(), varName)) {
|
||||
data.formParams().add(name);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private <K, V> boolean searchMapValues(Map<K, Collection<V>> map, V search) {
|
||||
Collection<Collection<V>> values = map.values();
|
||||
if (values == null) {
|
||||
return false;
|
||||
}
|
||||
for (Collection<V> entry : values) {
|
||||
if (entry.contains(search)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign.annotation;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.cloud.netflix.feign.AnnotatedParameterProcessor;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
|
||||
import feign.MethodMetadata;
|
||||
|
||||
import static feign.Util.checkState;
|
||||
import static feign.Util.emptyToNull;
|
||||
|
||||
/**
|
||||
* {@link RequestHeader} parameter processor.
|
||||
*
|
||||
* @author Jakub Narloch
|
||||
* @see AnnotatedParameterProcessor
|
||||
*/
|
||||
public class RequestHeaderParameterProcessor implements AnnotatedParameterProcessor {
|
||||
|
||||
private static final Class<RequestHeader> ANNOTATION = RequestHeader.class;
|
||||
|
||||
@Override
|
||||
public Class<? extends Annotation> getAnnotationType() {
|
||||
return ANNOTATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processArgument(AnnotatedParameterContext context, Annotation annotation) {
|
||||
String name = ANNOTATION.cast(annotation).value();
|
||||
checkState(emptyToNull(name) != null,
|
||||
"RequestHeader.value() was empty on parameter %s", context.getParameterIndex());
|
||||
context.setParameterName(name);
|
||||
|
||||
MethodMetadata data = context.getMethodMetadata();
|
||||
Collection<String> header = context.setTemplateParameter(name, data.template().headers().get(name));
|
||||
data.template().header(name, header);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign.annotation;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.cloud.netflix.feign.AnnotatedParameterProcessor;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import static feign.Util.checkState;
|
||||
import static feign.Util.emptyToNull;
|
||||
|
||||
import feign.MethodMetadata;
|
||||
|
||||
/**
|
||||
* {@link RequestParam} parameter processor.
|
||||
*
|
||||
* @author Jakub Narloch
|
||||
* @see AnnotatedParameterProcessor
|
||||
*/
|
||||
public class RequestParamParameterProcessor implements AnnotatedParameterProcessor {
|
||||
|
||||
private static final Class<RequestParam> ANNOTATION = RequestParam.class;
|
||||
|
||||
@Override
|
||||
public Class<? extends Annotation> getAnnotationType() {
|
||||
return ANNOTATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processArgument(AnnotatedParameterContext context,
|
||||
Annotation annotation) {
|
||||
RequestParam requestParam = ANNOTATION.cast(annotation);
|
||||
String name = requestParam.value();
|
||||
if (emptyToNull(name) != null) {
|
||||
context.setParameterName(name);
|
||||
|
||||
MethodMetadata data = context.getMethodMetadata();
|
||||
Collection<String> query = context.setTemplateParameter(name,
|
||||
data.template().queries().get(name));
|
||||
data.template().query(name, query);
|
||||
} else {
|
||||
// supports `Map` types
|
||||
MethodMetadata data = context.getMethodMetadata();
|
||||
data.queryMapIndex(context.getParameterIndex());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign.encoding;
|
||||
|
||||
import feign.RequestInterceptor;
|
||||
import feign.RequestTemplate;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* The base request interceptor.
|
||||
*
|
||||
* @author Jakub Narloch
|
||||
*/
|
||||
public abstract class BaseRequestInterceptor implements RequestInterceptor {
|
||||
|
||||
/**
|
||||
* The encoding properties.
|
||||
*/
|
||||
@Getter(AccessLevel.PROTECTED)
|
||||
private final FeignClientEncodingProperties properties;
|
||||
|
||||
/**
|
||||
* Creates new instance of {@link BaseRequestInterceptor}.
|
||||
*
|
||||
* @param properties the encoding properties
|
||||
*/
|
||||
protected BaseRequestInterceptor(FeignClientEncodingProperties properties) {
|
||||
Assert.notNull(properties, "Properties can not be null");
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the header if it wasn't yet specified.
|
||||
*
|
||||
* @param requestTemplate the request
|
||||
* @param name the header name
|
||||
* @param values the header values
|
||||
*/
|
||||
protected void addHeader(RequestTemplate requestTemplate, String name, String... values) {
|
||||
|
||||
if (!requestTemplate.headers().containsKey(name)) {
|
||||
requestTemplate.header(name, values);
|
||||
}
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign.encoding;
|
||||
|
||||
import feign.Feign;
|
||||
import feign.httpclient.ApacheHttpClient;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.netflix.feign.FeignAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Configures the Feign response compression.
|
||||
*
|
||||
* @author Jakub Narloch
|
||||
* @see FeignAcceptGzipEncodingInterceptor
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(FeignClientEncodingProperties.class)
|
||||
@ConditionalOnClass(Feign.class)
|
||||
@ConditionalOnBean(ApacheHttpClient.class)
|
||||
@ConditionalOnProperty(value = "feign.compression.response.enabled", matchIfMissing = false)
|
||||
@AutoConfigureAfter(FeignAutoConfiguration.class)
|
||||
public class FeignAcceptGzipEncodingAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public FeignAcceptGzipEncodingInterceptor feignAcceptGzipEncodingInterceptor(FeignClientEncodingProperties properties) {
|
||||
return new FeignAcceptGzipEncodingInterceptor(properties);
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign.encoding;
|
||||
|
||||
import feign.RequestTemplate;
|
||||
|
||||
/**
|
||||
* Enables the HTTP response payload compression by specifying the {@code Accept-Encoding} headers.
|
||||
* Although this does not yet mean that the requests will be compressed, it requires the remote server
|
||||
* to understand the header and be configured to compress responses. Still no all responses might be compressed
|
||||
* based on the media type matching and other factors like the response content length.
|
||||
*
|
||||
* @author Jakub Narloch
|
||||
*/
|
||||
public class FeignAcceptGzipEncodingInterceptor extends BaseRequestInterceptor {
|
||||
|
||||
/**
|
||||
* Creates new instance of {@link FeignAcceptGzipEncodingInterceptor}.
|
||||
*
|
||||
* @param properties the encoding properties
|
||||
*/
|
||||
protected FeignAcceptGzipEncodingInterceptor(FeignClientEncodingProperties properties) {
|
||||
super(properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void apply(RequestTemplate template) {
|
||||
|
||||
addHeader(template, HttpEncoding.ACCEPT_ENCODING_HEADER, HttpEncoding.GZIP_ENCODING,
|
||||
HttpEncoding.DEFLATE_ENCODING);
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign.encoding;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* The Feign encoding properties.
|
||||
*
|
||||
* @author Jakub Narloch
|
||||
*/
|
||||
@Data
|
||||
@ConfigurationProperties("feign.compression.request")
|
||||
public class FeignClientEncodingProperties {
|
||||
|
||||
/**
|
||||
* The list of supported mime types.
|
||||
*/
|
||||
private String[] mimeTypes = new String[]{"text/xml", "application/xml", "application/json"};
|
||||
|
||||
/**
|
||||
* The minimum threshold content size.
|
||||
*/
|
||||
private int minRequestSize = 2048;
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign.encoding;
|
||||
|
||||
import feign.Feign;
|
||||
import feign.httpclient.ApacheHttpClient;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.netflix.feign.FeignAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Configures the Feign request compression.
|
||||
*
|
||||
* @author Jakub Narloch
|
||||
* @see FeignContentGzipEncodingInterceptor
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(FeignClientEncodingProperties.class)
|
||||
@ConditionalOnClass(Feign.class)
|
||||
@ConditionalOnBean(ApacheHttpClient.class)
|
||||
@ConditionalOnProperty(value = "feign.compression.request.enabled", matchIfMissing = false)
|
||||
@AutoConfigureAfter(FeignAutoConfiguration.class)
|
||||
public class FeignContentGzipEncodingAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public FeignContentGzipEncodingInterceptor feignContentGzipEncodingInterceptor(FeignClientEncodingProperties properties) {
|
||||
return new FeignContentGzipEncodingInterceptor(properties);
|
||||
}
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign.encoding;
|
||||
|
||||
import feign.RequestTemplate;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Enables the HTTP request payload compression by specifying the {@code Content-Encoding} headers.
|
||||
*
|
||||
* @author Jakub Narloch
|
||||
*/
|
||||
public class FeignContentGzipEncodingInterceptor extends BaseRequestInterceptor {
|
||||
|
||||
/**
|
||||
* Creates new instance of {@link FeignContentGzipEncodingInterceptor}.
|
||||
*
|
||||
* @param properties the encoding properties
|
||||
*/
|
||||
protected FeignContentGzipEncodingInterceptor(FeignClientEncodingProperties properties) {
|
||||
super(properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void apply(RequestTemplate template) {
|
||||
|
||||
if (requiresCompression(template)) {
|
||||
addHeader(template, HttpEncoding.CONTENT_ENCODING_HEADER, HttpEncoding.GZIP_ENCODING,
|
||||
HttpEncoding.DEFLATE_ENCODING);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the request requires GZIP compression.
|
||||
*
|
||||
* @param template the request template
|
||||
* @return true if request requires compression, false otherwise
|
||||
*/
|
||||
private boolean requiresCompression(RequestTemplate template) {
|
||||
|
||||
final Map<String, Collection<String>> headers = template.headers();
|
||||
return matchesMimeType(headers.get(HttpEncoding.CONTENT_TYPE))
|
||||
&& contentLengthExceedThreshold(headers.get(HttpEncoding.CONTENT_LENGTH));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the request content length exceed configured minimum size.
|
||||
*
|
||||
* @param contentLength the content length header value
|
||||
* @return true if length is grater than minimum size, false otherwise
|
||||
*/
|
||||
private boolean contentLengthExceedThreshold(Collection<String> contentLength) {
|
||||
|
||||
try {
|
||||
if (contentLength.size() != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final String strLen = contentLength.iterator().next();
|
||||
final long length = Long.parseLong(strLen);
|
||||
return length > getProperties().getMinRequestSize();
|
||||
} catch (NumberFormatException ex) {
|
||||
// ignores the exception
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the content mime types matches the configures mime types.
|
||||
*
|
||||
* @param contentTypes the content types
|
||||
* @return true if any specified content type matches the request content types
|
||||
*/
|
||||
private boolean matchesMimeType(Collection<String> contentTypes) {
|
||||
if (contentTypes == null || contentTypes.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (getProperties().getMimeTypes() == null || getProperties().getMimeTypes().length == 0) {
|
||||
// no specific mime types has been set - matching everything
|
||||
return true;
|
||||
}
|
||||
|
||||
for (String mimeType : getProperties().getMimeTypes()) {
|
||||
if (contentTypes.contains(mimeType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign.encoding;
|
||||
|
||||
/**
|
||||
* Lists all constants used by Feign encoders.
|
||||
*
|
||||
* @author Jakub Narloch
|
||||
*/
|
||||
public interface HttpEncoding {
|
||||
|
||||
/**
|
||||
* The HTTP Content-Length header.
|
||||
*/
|
||||
String CONTENT_LENGTH = "Content-Length";
|
||||
|
||||
/**
|
||||
* The HTTP Content-Type header.
|
||||
*/
|
||||
String CONTENT_TYPE = "Content-Type";
|
||||
|
||||
/**
|
||||
* The HTTP Accept-Encoding header.
|
||||
*/
|
||||
String ACCEPT_ENCODING_HEADER = "Accept-Encoding";
|
||||
|
||||
/**
|
||||
* The HTTP Content-Encoding header.
|
||||
*/
|
||||
String CONTENT_ENCODING_HEADER = "Content-Encoding";
|
||||
|
||||
/**
|
||||
* The GZIP encoding.
|
||||
*/
|
||||
String GZIP_ENCODING = "gzip";
|
||||
|
||||
/**
|
||||
* The Deflate encoding.
|
||||
*/
|
||||
String DEFLATE_ENCODING = "deflate";
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign.ribbon;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryPolicyFactory;
|
||||
import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancedRetryPolicyFactory;
|
||||
import org.springframework.cloud.netflix.ribbon.ServerIntrospector;
|
||||
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
|
||||
import org.springframework.retry.support.RetryTemplate;
|
||||
import org.springframework.util.ConcurrentReferenceHashMap;
|
||||
|
||||
import com.netflix.client.config.IClientConfig;
|
||||
import com.netflix.loadbalancer.ILoadBalancer;
|
||||
|
||||
/**
|
||||
* Factory for SpringLoadBalancer instances that caches the entries created.
|
||||
*
|
||||
* @author Spencer Gibb
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class CachingSpringLoadBalancerFactory {
|
||||
|
||||
private final SpringClientFactory factory;
|
||||
private final LoadBalancedRetryPolicyFactory loadBalancedRetryPolicyFactory;
|
||||
private boolean enableRetry = false;
|
||||
|
||||
private volatile Map<String, FeignLoadBalancer> cache = new ConcurrentReferenceHashMap<>();
|
||||
|
||||
public CachingSpringLoadBalancerFactory(SpringClientFactory factory) {
|
||||
this.factory = factory;
|
||||
this.loadBalancedRetryPolicyFactory = new RibbonLoadBalancedRetryPolicyFactory(factory);
|
||||
}
|
||||
|
||||
public CachingSpringLoadBalancerFactory(SpringClientFactory factory,
|
||||
LoadBalancedRetryPolicyFactory loadBalancedRetryPolicyFactory) {
|
||||
this.factory = factory;
|
||||
this.loadBalancedRetryPolicyFactory = loadBalancedRetryPolicyFactory;
|
||||
}
|
||||
|
||||
public CachingSpringLoadBalancerFactory(SpringClientFactory factory,
|
||||
LoadBalancedRetryPolicyFactory loadBalancedRetryPolicyFactory, boolean enableRetry) {
|
||||
this.factory = factory;
|
||||
this.loadBalancedRetryPolicyFactory = loadBalancedRetryPolicyFactory;
|
||||
this.enableRetry = enableRetry;
|
||||
}
|
||||
|
||||
public FeignLoadBalancer create(String clientName) {
|
||||
if (this.cache.containsKey(clientName)) {
|
||||
return this.cache.get(clientName);
|
||||
}
|
||||
IClientConfig config = this.factory.getClientConfig(clientName);
|
||||
ILoadBalancer lb = this.factory.getLoadBalancer(clientName);
|
||||
ServerIntrospector serverIntrospector = this.factory.getInstance(clientName, ServerIntrospector.class);
|
||||
FeignLoadBalancer client = enableRetry ? new RetryableFeignLoadBalancer(lb, config, serverIntrospector,
|
||||
loadBalancedRetryPolicyFactory) : new FeignLoadBalancer(lb, config, serverIntrospector);
|
||||
this.cache.put(clientName, client);
|
||||
return client;
|
||||
}
|
||||
|
||||
}
|
||||
+216
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign.ribbon;
|
||||
|
||||
import feign.Client;
|
||||
import feign.Request;
|
||||
import feign.Response;
|
||||
import feign.Util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.springframework.cloud.netflix.ribbon.ServerIntrospector;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import com.netflix.client.AbstractLoadBalancerAwareClient;
|
||||
import com.netflix.client.ClientException;
|
||||
import com.netflix.client.ClientRequest;
|
||||
import com.netflix.client.IResponse;
|
||||
import com.netflix.client.RequestSpecificRetryHandler;
|
||||
import com.netflix.client.RetryHandler;
|
||||
import com.netflix.client.config.CommonClientConfigKey;
|
||||
import com.netflix.client.config.IClientConfig;
|
||||
import com.netflix.loadbalancer.ILoadBalancer;
|
||||
import com.netflix.loadbalancer.Server;
|
||||
|
||||
import static org.springframework.cloud.netflix.ribbon.RibbonUtils.updateToHttpsIfNeeded;
|
||||
|
||||
public class FeignLoadBalancer extends
|
||||
AbstractLoadBalancerAwareClient<FeignLoadBalancer.RibbonRequest, FeignLoadBalancer.RibbonResponse> {
|
||||
|
||||
protected int connectTimeout;
|
||||
protected int readTimeout;
|
||||
protected IClientConfig clientConfig;
|
||||
protected ServerIntrospector serverIntrospector;
|
||||
|
||||
public FeignLoadBalancer(ILoadBalancer lb, IClientConfig clientConfig,
|
||||
ServerIntrospector serverIntrospector) {
|
||||
super(lb, clientConfig);
|
||||
this.setRetryHandler(RetryHandler.DEFAULT);
|
||||
this.clientConfig = clientConfig;
|
||||
this.connectTimeout = clientConfig.get(CommonClientConfigKey.ConnectTimeout);
|
||||
this.readTimeout = clientConfig.get(CommonClientConfigKey.ReadTimeout);
|
||||
this.serverIntrospector = serverIntrospector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RibbonResponse execute(RibbonRequest request, IClientConfig configOverride)
|
||||
throws IOException {
|
||||
Request.Options options;
|
||||
if (configOverride != null) {
|
||||
options = new Request.Options(
|
||||
configOverride.get(CommonClientConfigKey.ConnectTimeout,
|
||||
this.connectTimeout),
|
||||
(configOverride.get(CommonClientConfigKey.ReadTimeout,
|
||||
this.readTimeout)));
|
||||
}
|
||||
else {
|
||||
options = new Request.Options(this.connectTimeout, this.readTimeout);
|
||||
}
|
||||
Response response = request.client().execute(request.toRequest(), options);
|
||||
return new RibbonResponse(request.getUri(), response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestSpecificRetryHandler getRequestSpecificRetryHandler(
|
||||
RibbonRequest request, IClientConfig requestConfig) {
|
||||
if (this.clientConfig.get(CommonClientConfigKey.OkToRetryOnAllOperations,
|
||||
false)) {
|
||||
return new RequestSpecificRetryHandler(true, true, this.getRetryHandler(),
|
||||
requestConfig);
|
||||
}
|
||||
if (!request.toRequest().method().equals("GET")) {
|
||||
return new RequestSpecificRetryHandler(true, false, this.getRetryHandler(),
|
||||
requestConfig);
|
||||
}
|
||||
else {
|
||||
return new RequestSpecificRetryHandler(true, true, this.getRetryHandler(),
|
||||
requestConfig);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI reconstructURIWithServer(Server server, URI original) {
|
||||
URI uri = updateToHttpsIfNeeded(original, this.clientConfig, this.serverIntrospector, server);
|
||||
return super.reconstructURIWithServer(server, uri);
|
||||
}
|
||||
|
||||
static class RibbonRequest extends ClientRequest implements Cloneable {
|
||||
|
||||
private final Request request;
|
||||
private final Client client;
|
||||
|
||||
RibbonRequest(Client client, Request request, URI uri) {
|
||||
this.client = client;
|
||||
setUri(uri);
|
||||
this.request = toRequest(request);
|
||||
}
|
||||
|
||||
private Request toRequest(Request request) {
|
||||
Map<String, Collection<String>> headers = new LinkedHashMap<>(
|
||||
request.headers());
|
||||
return Request.create(request.method(),getUri().toASCIIString(),headers,request.body(),request.charset());
|
||||
}
|
||||
|
||||
Request toRequest() {
|
||||
return toRequest(this.request);
|
||||
}
|
||||
|
||||
Client client() {
|
||||
return this.client;
|
||||
}
|
||||
|
||||
HttpRequest toHttpRequest() {
|
||||
return new HttpRequest() {
|
||||
@Override
|
||||
public HttpMethod getMethod() {
|
||||
return HttpMethod.resolve(RibbonRequest.this.toRequest().method());
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getURI() {
|
||||
return RibbonRequest.this.getUri();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders getHeaders() {
|
||||
Map<String, List<String>> headers = new HashMap<String, List<String>>();
|
||||
Map<String, Collection<String>> feignHeaders = RibbonRequest.this.toRequest().headers();
|
||||
for(String key : feignHeaders.keySet()) {
|
||||
headers.put(key, new ArrayList<String>(feignHeaders.get(key)));
|
||||
}
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
httpHeaders.putAll(headers);
|
||||
return httpHeaders;
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object clone() {
|
||||
return new RibbonRequest(this.client, this.request, getUri());
|
||||
}
|
||||
}
|
||||
|
||||
static class RibbonResponse implements IResponse {
|
||||
|
||||
private final URI uri;
|
||||
private final Response response;
|
||||
|
||||
RibbonResponse(URI uri, Response response) {
|
||||
this.uri = uri;
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPayload() throws ClientException {
|
||||
return this.response.body();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPayload() {
|
||||
return this.response.body() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuccess() {
|
||||
return this.response.status() == 200;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getRequestedURI() {
|
||||
return this.uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Collection<String>> getHeaders() {
|
||||
return this.response.headers();
|
||||
}
|
||||
|
||||
Response toResponse() {
|
||||
return this.response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (this.response != null && this.response.body() != null) {
|
||||
this.response.body().close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2013-2016 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.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign.ribbon;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.loadbalancer.InterceptorRetryPolicy;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryContext;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryPolicy;
|
||||
import org.springframework.cloud.client.loadbalancer.ServiceInstanceChooser;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.retry.RetryContext;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
public class FeignRetryPolicy extends InterceptorRetryPolicy {
|
||||
private HttpRequest request;
|
||||
private String serviceId;
|
||||
public FeignRetryPolicy(HttpRequest request, LoadBalancedRetryPolicy policy, ServiceInstanceChooser serviceInstanceChooser, String serviceName) {
|
||||
super(request, policy, serviceInstanceChooser, serviceName);
|
||||
this.request = request;
|
||||
this.serviceId = serviceName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRetry(RetryContext context) {
|
||||
/*
|
||||
* In InterceptorRetryPolicy.canRetry we ask the LoadBalancer to choose a server if one is not
|
||||
* set in the retry context and then return true. RetryTemplat calls the canRetry method of
|
||||
* the policy even on its first execution. So the fact that we didnt have a service instance set
|
||||
* in the RetryContext signaled that it was the first execution and we should return true.
|
||||
*
|
||||
* In the Feign scenario, Feign as actually already queried the load balancer for a service instance
|
||||
* and we set that service instance in the context when we call the open method of the policy. So in
|
||||
* the Feign case we just return true if the retry count is 0 indicating we haven't yet made a failed
|
||||
* request.
|
||||
*/
|
||||
if(context.getRetryCount() == 0) {
|
||||
return true;
|
||||
}
|
||||
return super.canRetry(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RetryContext open(RetryContext parent) {
|
||||
/*
|
||||
* With Feign (unlike Ribbon) the request already has the URI for the service instance
|
||||
* we are going to make the request to, so extract that information and set the service
|
||||
* instance in the context. In the Ribbon scenario the URI in the request object still has
|
||||
* the service id so we choose and set the service instance later on.
|
||||
*/
|
||||
LoadBalancedRetryContext context = new LoadBalancedRetryContext(parent, this.request);
|
||||
context.setServiceInstance(new FeignRetryPolicyServiceInstance(serviceId, request));
|
||||
return context;
|
||||
}
|
||||
|
||||
class FeignRetryPolicyServiceInstance implements ServiceInstance {
|
||||
|
||||
private String serviceId;
|
||||
private HttpRequest request;
|
||||
private Map<String, String> metadata;
|
||||
|
||||
FeignRetryPolicyServiceInstance(String serviceId, HttpRequest request) {
|
||||
this.serviceId = serviceId;
|
||||
this.request = request;
|
||||
this.metadata = new HashMap<String, String>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServiceId() {
|
||||
return serviceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHost() {
|
||||
return request.getURI().getHost();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPort() {
|
||||
return request.getURI().getPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSecure() {
|
||||
return "https".equals(request.getURI().getScheme());
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getUri() {
|
||||
return request.getURI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
}
|
||||
}
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign.ribbon;
|
||||
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryPolicyFactory;
|
||||
import org.springframework.cloud.netflix.feign.FeignAutoConfiguration;
|
||||
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
|
||||
import com.netflix.loadbalancer.ILoadBalancer;
|
||||
|
||||
import feign.Client;
|
||||
import feign.Feign;
|
||||
import feign.Request;
|
||||
import feign.httpclient.ApacheHttpClient;
|
||||
import feign.okhttp.OkHttpClient;
|
||||
|
||||
/**
|
||||
* Autoconfiguration to be activated if Feign is in use and needs to be use Ribbon as a
|
||||
* load balancer.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@ConditionalOnClass({ ILoadBalancer.class, Feign.class })
|
||||
@Configuration
|
||||
@AutoConfigureBefore(FeignAutoConfiguration.class)
|
||||
public class FeignRibbonClientAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
|
||||
public CachingSpringLoadBalancerFactory cachingLBClientFactory(
|
||||
SpringClientFactory factory) {
|
||||
return new CachingSpringLoadBalancerFactory(factory);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
@ConditionalOnClass(name = "org.springframework.retry.support.RetryTemplate")
|
||||
public CachingSpringLoadBalancerFactory retryabeCachingLBClientFactory(
|
||||
SpringClientFactory factory, LoadBalancedRetryPolicyFactory retryPolicyFactory) {
|
||||
return new CachingSpringLoadBalancerFactory(factory, retryPolicyFactory, true);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
|
||||
SpringClientFactory clientFactory) {
|
||||
return new LoadBalancerFeignClient(new Client.Default(null, null),
|
||||
cachingFactory, clientFactory);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Request.Options feignRequestOptions() {
|
||||
return LoadBalancerFeignClient.DEFAULT_OPTIONS;
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(ApacheHttpClient.class)
|
||||
@ConditionalOnProperty(value = "feign.httpclient.enabled", matchIfMissing = true)
|
||||
protected static class HttpClientFeignLoadBalancedConfiguration {
|
||||
|
||||
@Autowired(required = false)
|
||||
private HttpClient httpClient;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(Client.class)
|
||||
public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
|
||||
SpringClientFactory clientFactory) {
|
||||
ApacheHttpClient delegate;
|
||||
if (this.httpClient != null) {
|
||||
delegate = new ApacheHttpClient(this.httpClient);
|
||||
}
|
||||
else {
|
||||
delegate = new ApacheHttpClient();
|
||||
}
|
||||
return new LoadBalancerFeignClient(delegate, cachingFactory, clientFactory);
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(OkHttpClient.class)
|
||||
@ConditionalOnProperty(value = "feign.okhttp.enabled", matchIfMissing = true)
|
||||
protected static class OkHttpFeignLoadBalancedConfiguration {
|
||||
|
||||
@Autowired(required = false)
|
||||
private okhttp3.OkHttpClient okHttpClient;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(Client.class)
|
||||
public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
|
||||
SpringClientFactory clientFactory) {
|
||||
OkHttpClient delegate;
|
||||
if (this.okHttpClient != null) {
|
||||
delegate = new OkHttpClient(this.okHttpClient);
|
||||
}
|
||||
else {
|
||||
delegate = new OkHttpClient();
|
||||
}
|
||||
return new LoadBalancerFeignClient(delegate, cachingFactory, clientFactory);
|
||||
}
|
||||
}
|
||||
}
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign.ribbon;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
|
||||
|
||||
import com.netflix.client.ClientException;
|
||||
import com.netflix.client.config.CommonClientConfigKey;
|
||||
import com.netflix.client.config.DefaultClientConfigImpl;
|
||||
import com.netflix.client.config.IClientConfig;
|
||||
|
||||
import feign.Client;
|
||||
import feign.Request;
|
||||
import feign.Response;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class LoadBalancerFeignClient implements Client {
|
||||
|
||||
static final Request.Options DEFAULT_OPTIONS = new Request.Options();
|
||||
|
||||
private final Client delegate;
|
||||
private CachingSpringLoadBalancerFactory lbClientFactory;
|
||||
private SpringClientFactory clientFactory;
|
||||
|
||||
public LoadBalancerFeignClient(Client delegate,
|
||||
CachingSpringLoadBalancerFactory lbClientFactory,
|
||||
SpringClientFactory clientFactory) {
|
||||
this.delegate = delegate;
|
||||
this.lbClientFactory = lbClientFactory;
|
||||
this.clientFactory = clientFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response execute(Request request, Request.Options options) throws IOException {
|
||||
try {
|
||||
URI asUri = URI.create(request.url());
|
||||
String clientName = asUri.getHost();
|
||||
URI uriWithoutHost = cleanUrl(request.url(), clientName);
|
||||
FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest(
|
||||
this.delegate, request, uriWithoutHost);
|
||||
|
||||
IClientConfig requestConfig = getClientConfig(options, clientName);
|
||||
return lbClient(clientName).executeWithLoadBalancer(ribbonRequest,
|
||||
requestConfig).toResponse();
|
||||
}
|
||||
catch (ClientException e) {
|
||||
IOException io = findIOException(e);
|
||||
if (io != null) {
|
||||
throw io;
|
||||
}
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
IClientConfig getClientConfig(Request.Options options, String clientName) {
|
||||
IClientConfig requestConfig;
|
||||
if (options == DEFAULT_OPTIONS) {
|
||||
requestConfig = this.clientFactory.getClientConfig(clientName);
|
||||
} else {
|
||||
requestConfig = new FeignOptionsClientConfig(options);
|
||||
}
|
||||
return requestConfig;
|
||||
}
|
||||
|
||||
protected IOException findIOException(Throwable t) {
|
||||
if (t == null) {
|
||||
return null;
|
||||
}
|
||||
if (t instanceof IOException) {
|
||||
return (IOException) t;
|
||||
}
|
||||
return findIOException(t.getCause());
|
||||
}
|
||||
|
||||
public Client getDelegate() {
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
static URI cleanUrl(String originalUrl, String host) {
|
||||
return URI.create(originalUrl.replaceFirst(host, ""));
|
||||
}
|
||||
|
||||
private FeignLoadBalancer lbClient(String clientName) {
|
||||
return this.lbClientFactory.create(clientName);
|
||||
}
|
||||
|
||||
static class FeignOptionsClientConfig extends DefaultClientConfigImpl {
|
||||
|
||||
public FeignOptionsClientConfig(Request.Options options) {
|
||||
setProperty(CommonClientConfigKey.ConnectTimeout,
|
||||
options.connectTimeoutMillis());
|
||||
setProperty(CommonClientConfigKey.ReadTimeout, options.readTimeoutMillis());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadProperties(String clientName) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadDefaultValues() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2013-2016 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.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign.ribbon;
|
||||
|
||||
import feign.Request;
|
||||
import feign.Response;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryContext;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryPolicy;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryPolicyFactory;
|
||||
import org.springframework.cloud.client.loadbalancer.ServiceInstanceChooser;
|
||||
import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient;
|
||||
import org.springframework.cloud.netflix.ribbon.ServerIntrospector;
|
||||
import org.springframework.retry.RetryCallback;
|
||||
import org.springframework.retry.RetryContext;
|
||||
import org.springframework.retry.policy.NeverRetryPolicy;
|
||||
import org.springframework.retry.support.RetryTemplate;
|
||||
import com.netflix.client.DefaultLoadBalancerRetryHandler;
|
||||
import com.netflix.client.RequestSpecificRetryHandler;
|
||||
import com.netflix.client.config.CommonClientConfigKey;
|
||||
import com.netflix.client.config.IClientConfig;
|
||||
import com.netflix.loadbalancer.ILoadBalancer;
|
||||
import com.netflix.loadbalancer.Server;
|
||||
|
||||
/**
|
||||
* A {@link FeignLoadBalancer} that leverages Spring Retry to retry failed requests.
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
public class RetryableFeignLoadBalancer extends FeignLoadBalancer implements ServiceInstanceChooser {
|
||||
|
||||
private final LoadBalancedRetryPolicyFactory loadBalancedRetryPolicyFactory;
|
||||
|
||||
public RetryableFeignLoadBalancer(ILoadBalancer lb, IClientConfig clientConfig,
|
||||
ServerIntrospector serverIntrospector, LoadBalancedRetryPolicyFactory loadBalancedRetryPolicyFactory) {
|
||||
super(lb, clientConfig, serverIntrospector);
|
||||
this.loadBalancedRetryPolicyFactory = loadBalancedRetryPolicyFactory;
|
||||
this.setRetryHandler(new DefaultLoadBalancerRetryHandler(clientConfig));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RibbonResponse execute(final RibbonRequest request, IClientConfig configOverride)
|
||||
throws IOException {
|
||||
final Request.Options options;
|
||||
if (configOverride != null) {
|
||||
options = new Request.Options(
|
||||
configOverride.get(CommonClientConfigKey.ConnectTimeout,
|
||||
this.connectTimeout),
|
||||
(configOverride.get(CommonClientConfigKey.ReadTimeout,
|
||||
this.readTimeout)));
|
||||
}
|
||||
else {
|
||||
options = new Request.Options(this.connectTimeout, this.readTimeout);
|
||||
}
|
||||
LoadBalancedRetryPolicy retryPolicy = loadBalancedRetryPolicyFactory.create(this.getClientName(), this);
|
||||
RetryTemplate retryTemplate = new RetryTemplate();
|
||||
retryTemplate.setRetryPolicy(retryPolicy == null ? new NeverRetryPolicy()
|
||||
: new FeignRetryPolicy(request.toHttpRequest(), retryPolicy, this, this.getClientName()));
|
||||
return retryTemplate.execute(new RetryCallback<RibbonResponse, IOException>() {
|
||||
@Override
|
||||
public RibbonResponse doWithRetry(RetryContext retryContext) throws IOException {
|
||||
Request feignRequest = null;
|
||||
//on retries the policy will choose the server and set it in the context
|
||||
//extract the server and update the request being made
|
||||
if(retryContext instanceof LoadBalancedRetryContext) {
|
||||
ServiceInstance service = ((LoadBalancedRetryContext)retryContext).getServiceInstance();
|
||||
if(service != null) {
|
||||
feignRequest = ((RibbonRequest)request.replaceUri(reconstructURIWithServer(new Server(service.getHost(), service.getPort()), request.getUri()))).toRequest();
|
||||
}
|
||||
}
|
||||
if(feignRequest == null) {
|
||||
feignRequest = request.toRequest();
|
||||
}
|
||||
Response response = request.client().execute(feignRequest, options);
|
||||
return new RibbonResponse(request.getUri(), response);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestSpecificRetryHandler getRequestSpecificRetryHandler(
|
||||
FeignLoadBalancer.RibbonRequest request, IClientConfig requestConfig) {
|
||||
return new RequestSpecificRetryHandler(false, false, this.getRetryHandler(), requestConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServiceInstance choose(String serviceId) {
|
||||
return new RibbonLoadBalancerClient.RibbonServer(serviceId,
|
||||
this.getLoadBalancer().chooseServer(serviceId));
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package org.springframework.cloud.netflix.feign.support;
|
||||
|
||||
import com.netflix.hystrix.HystrixCommand;
|
||||
import com.netflix.hystrix.HystrixCommandGroupKey;
|
||||
import com.netflix.hystrix.HystrixThreadPoolKey;
|
||||
|
||||
/**
|
||||
* Convenience class for implementing feign fallbacks that return {@link HystrixCommand}.
|
||||
* Also useful for return types of {@link rx.Observable} and {@link java.util.concurrent.Future}.
|
||||
* For those return types, just call {@link FallbackCommand#observe()} or {@link FallbackCommand#queue()} respectively.
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class FallbackCommand<T> extends HystrixCommand<T> {
|
||||
|
||||
private T result;
|
||||
|
||||
public FallbackCommand(T result) {
|
||||
this(result, "fallback");
|
||||
}
|
||||
|
||||
protected FallbackCommand(T result, String groupname) {
|
||||
super(HystrixCommandGroupKey.Factory.asKey(groupname));
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public FallbackCommand(T result, HystrixCommandGroupKey group) {
|
||||
super(group);
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public FallbackCommand(T result, HystrixCommandGroupKey group, int executionIsolationThreadTimeoutInMilliseconds) {
|
||||
super(group, executionIsolationThreadTimeoutInMilliseconds);
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public FallbackCommand(T result, HystrixCommandGroupKey group, HystrixThreadPoolKey threadPool) {
|
||||
super(group, threadPool);
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public FallbackCommand(T result, HystrixCommandGroupKey group, HystrixThreadPoolKey threadPool, int executionIsolationThreadTimeoutInMilliseconds) {
|
||||
super(group, threadPool, executionIsolationThreadTimeoutInMilliseconds);
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public FallbackCommand(T result, Setter setter) {
|
||||
super(setter);
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected T run() throws Exception {
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign.support;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class FeignUtils {
|
||||
|
||||
static HttpHeaders getHttpHeaders(Map<String, Collection<String>> headers) {
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
for (Map.Entry<String, Collection<String>> entry : headers.entrySet()) {
|
||||
httpHeaders.put(entry.getKey(), new ArrayList<>(entry.getValue()));
|
||||
}
|
||||
return httpHeaders;
|
||||
}
|
||||
|
||||
static Map<String, Collection<String>> getHeaders(HttpHeaders httpHeaders) {
|
||||
LinkedHashMap<String, Collection<String>> headers = new LinkedHashMap<>();
|
||||
|
||||
for (Map.Entry<String, List<String>> entry : httpHeaders.entrySet()) {
|
||||
headers.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
package org.springframework.cloud.netflix.feign.support;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
import feign.FeignException;
|
||||
import feign.Response;
|
||||
import feign.codec.Decoder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* Decoder adds compatibility for Spring MVC's ResponseEntity to any other decoder via
|
||||
* composition.
|
||||
* @author chadjaros
|
||||
*/
|
||||
@Slf4j
|
||||
public class ResponseEntityDecoder implements Decoder {
|
||||
|
||||
private Decoder decoder;
|
||||
|
||||
public ResponseEntityDecoder(Decoder decoder) {
|
||||
this.decoder = decoder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object decode(final Response response, Type type) throws IOException,
|
||||
FeignException {
|
||||
|
||||
if (isParameterizeHttpEntity(type)) {
|
||||
type = ((ParameterizedType) type).getActualTypeArguments()[0];
|
||||
Object decodedObject = decoder.decode(response, type);
|
||||
|
||||
return createResponse(decodedObject, response);
|
||||
}
|
||||
else if (isHttpEntity(type)) {
|
||||
return createResponse(null, response);
|
||||
}
|
||||
else {
|
||||
return decoder.decode(response, type);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isParameterizeHttpEntity(Type type) {
|
||||
if (type instanceof ParameterizedType) {
|
||||
return isHttpEntity(((ParameterizedType) type).getRawType());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isHttpEntity(Type type) {
|
||||
if (type instanceof Class) {
|
||||
Class c = (Class) type;
|
||||
return HttpEntity.class.isAssignableFrom(c);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> ResponseEntity<T> createResponse(Object instance, Response response) {
|
||||
|
||||
MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
|
||||
for (String key : response.headers().keySet()) {
|
||||
headers.put(key, new LinkedList<>(response.headers().get(key)));
|
||||
}
|
||||
|
||||
return new ResponseEntity<>((T) instance, headers, HttpStatus.valueOf(response
|
||||
.status()));
|
||||
}
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign.support;
|
||||
|
||||
import static org.springframework.cloud.netflix.feign.support.FeignUtils.getHttpHeaders;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.web.client.HttpMessageConverterExtractor;
|
||||
|
||||
import feign.FeignException;
|
||||
import feign.Response;
|
||||
import feign.codec.DecodeException;
|
||||
import feign.codec.Decoder;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class SpringDecoder implements Decoder {
|
||||
|
||||
private ObjectFactory<HttpMessageConverters> messageConverters;
|
||||
|
||||
public SpringDecoder(ObjectFactory<HttpMessageConverters> messageConverters) {
|
||||
this.messageConverters = messageConverters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object decode(final Response response, Type type) throws IOException,
|
||||
FeignException {
|
||||
if (type instanceof Class || type instanceof ParameterizedType) {
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
HttpMessageConverterExtractor<?> extractor = new HttpMessageConverterExtractor(
|
||||
type, this.messageConverters.getObject().getConverters());
|
||||
|
||||
return extractor.extractData(new FeignResponseAdapter(response));
|
||||
}
|
||||
throw new DecodeException(
|
||||
"type is not an instance of Class or ParameterizedType: " + type);
|
||||
}
|
||||
|
||||
private class FeignResponseAdapter implements ClientHttpResponse {
|
||||
|
||||
private final Response response;
|
||||
|
||||
private FeignResponseAdapter(Response response) {
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpStatus getStatusCode() throws IOException {
|
||||
return HttpStatus.valueOf(this.response.status());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRawStatusCode() throws IOException {
|
||||
return this.response.status();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStatusText() throws IOException {
|
||||
return this.response.reason();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
this.response.body().close();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
// Ignore exception on close...
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getBody() throws IOException {
|
||||
return this.response.body().asInputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders getHeaders() {
|
||||
return getHttpHeaders(this.response.headers());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign.support;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpOutputMessage;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
|
||||
import feign.RequestTemplate;
|
||||
import feign.codec.EncodeException;
|
||||
import feign.codec.Encoder;
|
||||
import lombok.extern.apachecommons.CommonsLog;
|
||||
|
||||
import static org.springframework.cloud.netflix.feign.support.FeignUtils.getHeaders;
|
||||
import static org.springframework.cloud.netflix.feign.support.FeignUtils.getHttpHeaders;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@CommonsLog
|
||||
public class SpringEncoder implements Encoder {
|
||||
|
||||
private ObjectFactory<HttpMessageConverters> messageConverters;
|
||||
|
||||
public SpringEncoder(ObjectFactory<HttpMessageConverters> messageConverters) {
|
||||
this.messageConverters = messageConverters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(Object requestBody, Type bodyType, RequestTemplate request)
|
||||
throws EncodeException {
|
||||
// template.body(conversionService.convert(object, String.class));
|
||||
if (requestBody != null) {
|
||||
Class<?> requestType = requestBody.getClass();
|
||||
Collection<String> contentTypes = request.headers().get("Content-Type");
|
||||
|
||||
MediaType requestContentType = null;
|
||||
if (contentTypes != null && !contentTypes.isEmpty()) {
|
||||
String type = contentTypes.iterator().next();
|
||||
requestContentType = MediaType.valueOf(type);
|
||||
}
|
||||
|
||||
for (HttpMessageConverter<?> messageConverter : this.messageConverters
|
||||
.getObject().getConverters()) {
|
||||
if (messageConverter.canWrite(requestType, requestContentType)) {
|
||||
if (log.isDebugEnabled()) {
|
||||
if (requestContentType != null) {
|
||||
log.debug("Writing [" + requestBody + "] as \""
|
||||
+ requestContentType + "\" using ["
|
||||
+ messageConverter + "]");
|
||||
}
|
||||
else {
|
||||
log.debug("Writing [" + requestBody + "] using ["
|
||||
+ messageConverter + "]");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
FeignOutputMessage outputMessage = new FeignOutputMessage(request);
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
HttpMessageConverter<Object> copy = (HttpMessageConverter<Object>) messageConverter;
|
||||
copy.write(requestBody, requestContentType, outputMessage);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new EncodeException("Error converting request body", ex);
|
||||
}
|
||||
// clear headers
|
||||
request.headers(null);
|
||||
// converters can modify headers, so update the request
|
||||
// with the modified headers
|
||||
request.headers(getHeaders(outputMessage.getHeaders()));
|
||||
|
||||
request.body(outputMessage.getOutputStream().toByteArray(),
|
||||
Charset.forName("UTF-8")); // TODO: set charset
|
||||
return;
|
||||
}
|
||||
}
|
||||
String message = "Could not write request: no suitable HttpMessageConverter "
|
||||
+ "found for request type [" + requestType.getName() + "]";
|
||||
if (requestContentType != null) {
|
||||
message += " and content type [" + requestContentType + "]";
|
||||
}
|
||||
throw new EncodeException(message);
|
||||
}
|
||||
}
|
||||
|
||||
private class FeignOutputMessage implements HttpOutputMessage {
|
||||
|
||||
private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
|
||||
private final HttpHeaders httpHeaders;
|
||||
|
||||
private FeignOutputMessage(RequestTemplate request) {
|
||||
httpHeaders = getHttpHeaders(request.headers());
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getBody() throws IOException {
|
||||
return this.outputStream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders getHeaders() {
|
||||
return this.httpHeaders;
|
||||
}
|
||||
|
||||
public ByteArrayOutputStream getOutputStream() {
|
||||
return this.outputStream;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+387
@@ -0,0 +1,387 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.feign.support;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.cloud.netflix.feign.AnnotatedParameterProcessor;
|
||||
import org.springframework.cloud.netflix.feign.annotation.PathVariableParameterProcessor;
|
||||
import org.springframework.cloud.netflix.feign.annotation.RequestHeaderParameterProcessor;
|
||||
import org.springframework.cloud.netflix.feign.annotation.RequestParamParameterProcessor;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.core.DefaultParameterNameDiscoverer;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
import static feign.Util.checkState;
|
||||
import static feign.Util.emptyToNull;
|
||||
import static org.springframework.core.annotation.AnnotatedElementUtils.findMergedAnnotation;
|
||||
|
||||
import feign.Contract;
|
||||
import feign.Feign;
|
||||
import feign.MethodMetadata;
|
||||
import feign.Param;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class SpringMvcContract extends Contract.BaseContract
|
||||
implements ResourceLoaderAware {
|
||||
|
||||
private static final String ACCEPT = "Accept";
|
||||
|
||||
private static final String CONTENT_TYPE = "Content-Type";
|
||||
|
||||
private static final ParameterNameDiscoverer PARAMETER_NAME_DISCOVERER = new DefaultParameterNameDiscoverer();
|
||||
|
||||
private final Map<Class<? extends Annotation>, AnnotatedParameterProcessor> annotatedArgumentProcessors;
|
||||
private final Map<String, Method> processedMethods = new HashMap<>();
|
||||
|
||||
private final ConversionService conversionService;
|
||||
private final Param.Expander expander;
|
||||
private ResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||
|
||||
public SpringMvcContract() {
|
||||
this(Collections.<AnnotatedParameterProcessor> emptyList());
|
||||
}
|
||||
|
||||
public SpringMvcContract(
|
||||
List<AnnotatedParameterProcessor> annotatedParameterProcessors) {
|
||||
this(annotatedParameterProcessors, new DefaultConversionService());
|
||||
}
|
||||
|
||||
public SpringMvcContract(
|
||||
List<AnnotatedParameterProcessor> annotatedParameterProcessors,
|
||||
ConversionService conversionService) {
|
||||
Assert.notNull(annotatedParameterProcessors,
|
||||
"Parameter processors can not be null.");
|
||||
Assert.notNull(conversionService, "ConversionService can not be null.");
|
||||
|
||||
List<AnnotatedParameterProcessor> processors;
|
||||
if (!annotatedParameterProcessors.isEmpty()) {
|
||||
processors = new ArrayList<>(annotatedParameterProcessors);
|
||||
}
|
||||
else {
|
||||
processors = getDefaultAnnotatedArgumentsProcessors();
|
||||
}
|
||||
this.annotatedArgumentProcessors = toAnnotatedArgumentProcessorMap(processors);
|
||||
this.conversionService = conversionService;
|
||||
this.expander = new ConvertingExpander(conversionService);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processAnnotationOnClass(MethodMetadata data, Class<?> clz) {
|
||||
if (clz.getInterfaces().length == 0) {
|
||||
RequestMapping classAnnotation = findMergedAnnotation(clz,
|
||||
RequestMapping.class);
|
||||
if (classAnnotation != null) {
|
||||
// Prepend path from class annotation if specified
|
||||
if (classAnnotation.value().length > 0) {
|
||||
String pathValue = emptyToNull(classAnnotation.value()[0]);
|
||||
pathValue = resolve(pathValue);
|
||||
if (!pathValue.startsWith("/")) {
|
||||
pathValue = "/" + pathValue;
|
||||
}
|
||||
data.template().insert(0, pathValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
|
||||
this.processedMethods.put(Feign.configKey(targetType, method), method);
|
||||
MethodMetadata md = super.parseAndValidateMetadata(targetType, method);
|
||||
|
||||
RequestMapping classAnnotation = findMergedAnnotation(targetType,
|
||||
RequestMapping.class);
|
||||
if (classAnnotation != null) {
|
||||
// produces - use from class annotation only if method has not specified this
|
||||
if (!md.template().headers().containsKey(ACCEPT)) {
|
||||
parseProduces(md, method, classAnnotation);
|
||||
}
|
||||
|
||||
// consumes -- use from class annotation only if method has not specified this
|
||||
if (!md.template().headers().containsKey(CONTENT_TYPE)) {
|
||||
parseConsumes(md, method, classAnnotation);
|
||||
}
|
||||
|
||||
// headers -- class annotation is inherited to methods, always write these if
|
||||
// present
|
||||
parseHeaders(md, method, classAnnotation);
|
||||
}
|
||||
return md;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processAnnotationOnMethod(MethodMetadata data,
|
||||
Annotation methodAnnotation, Method method) {
|
||||
if (!(methodAnnotation instanceof RequestMapping)) {
|
||||
return;
|
||||
}
|
||||
|
||||
RequestMapping methodMapping = findMergedAnnotation(method, RequestMapping.class);
|
||||
// HTTP Method
|
||||
RequestMethod[] methods = methodMapping.method();
|
||||
if (methods.length == 0) {
|
||||
methods = new RequestMethod[] { RequestMethod.GET };
|
||||
}
|
||||
checkOne(method, methods, "method");
|
||||
data.template().method(methods[0].name());
|
||||
|
||||
// path
|
||||
checkAtMostOne(method, methodMapping.value(), "value");
|
||||
if (methodMapping.value().length > 0) {
|
||||
String pathValue = emptyToNull(methodMapping.value()[0]);
|
||||
if (pathValue != null) {
|
||||
pathValue = resolve(pathValue);
|
||||
// Append path from @RequestMapping if value is present on method
|
||||
if (!pathValue.startsWith("/")
|
||||
&& !data.template().toString().endsWith("/")) {
|
||||
pathValue = "/" + pathValue;
|
||||
}
|
||||
data.template().append(pathValue);
|
||||
}
|
||||
}
|
||||
|
||||
// produces
|
||||
parseProduces(data, method, methodMapping);
|
||||
|
||||
// consumes
|
||||
parseConsumes(data, method, methodMapping);
|
||||
|
||||
// headers
|
||||
parseHeaders(data, method, methodMapping);
|
||||
|
||||
data.indexToExpander(new LinkedHashMap<Integer, Param.Expander>());
|
||||
}
|
||||
|
||||
private String resolve(String value) {
|
||||
if (StringUtils.hasText(value)
|
||||
&& this.resourceLoader instanceof ConfigurableApplicationContext) {
|
||||
return ((ConfigurableApplicationContext) this.resourceLoader).getEnvironment()
|
||||
.resolvePlaceholders(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private void checkAtMostOne(Method method, Object[] values, String fieldName) {
|
||||
checkState(values != null && (values.length == 0 || values.length == 1),
|
||||
"Method %s can only contain at most 1 %s field. Found: %s",
|
||||
method.getName(), fieldName,
|
||||
values == null ? null : Arrays.asList(values));
|
||||
}
|
||||
|
||||
private void checkOne(Method method, Object[] values, String fieldName) {
|
||||
checkState(values != null && values.length == 1,
|
||||
"Method %s can only contain 1 %s field. Found: %s", method.getName(),
|
||||
fieldName, values == null ? null : Arrays.asList(values));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean processAnnotationsOnParameter(MethodMetadata data,
|
||||
Annotation[] annotations, int paramIndex) {
|
||||
boolean isHttpAnnotation = false;
|
||||
|
||||
AnnotatedParameterProcessor.AnnotatedParameterContext context = new SimpleAnnotatedParameterContext(
|
||||
data, paramIndex);
|
||||
Method method = this.processedMethods.get(data.configKey());
|
||||
for (Annotation parameterAnnotation : annotations) {
|
||||
AnnotatedParameterProcessor processor = this.annotatedArgumentProcessors
|
||||
.get(parameterAnnotation.annotationType());
|
||||
if (processor != null) {
|
||||
Annotation processParameterAnnotation;
|
||||
// synthesize, handling @AliasFor, while falling back to parameter name on
|
||||
// missing String #value():
|
||||
processParameterAnnotation = synthesizeWithMethodParameterNameAsFallbackValue(
|
||||
parameterAnnotation, method, paramIndex);
|
||||
isHttpAnnotation |= processor.processArgument(context,
|
||||
processParameterAnnotation);
|
||||
}
|
||||
}
|
||||
if (isHttpAnnotation && data.indexToExpander().get(paramIndex) == null
|
||||
&& !isMultiValued(method.getParameterTypes()[paramIndex])
|
||||
&& this.conversionService.canConvert(
|
||||
method.getParameterTypes()[paramIndex], String.class)) {
|
||||
data.indexToExpander().put(paramIndex, this.expander);
|
||||
}
|
||||
return isHttpAnnotation;
|
||||
}
|
||||
|
||||
private boolean isMultiValued(Class<?> type) {
|
||||
// Feign will deal with each element in a collection individually (with no
|
||||
// expander as of 8.16.2, but we'd rather have no conversion than convert a
|
||||
// collection to a String (which ends up being a csv).
|
||||
return Collection.class.isAssignableFrom(type);
|
||||
}
|
||||
|
||||
private void parseProduces(MethodMetadata md, Method method,
|
||||
RequestMapping annotation) {
|
||||
checkAtMostOne(method, annotation.produces(), "produces");
|
||||
String[] serverProduces = annotation.produces();
|
||||
String clientAccepts = serverProduces.length == 0 ? null
|
||||
: emptyToNull(serverProduces[0]);
|
||||
if (clientAccepts != null) {
|
||||
md.template().header(ACCEPT, clientAccepts);
|
||||
}
|
||||
}
|
||||
|
||||
private void parseConsumes(MethodMetadata md, Method method,
|
||||
RequestMapping annotation) {
|
||||
checkAtMostOne(method, annotation.consumes(), "consumes");
|
||||
String[] serverConsumes = annotation.consumes();
|
||||
String clientProduces = serverConsumes.length == 0 ? null
|
||||
: emptyToNull(serverConsumes[0]);
|
||||
if (clientProduces != null) {
|
||||
md.template().header(CONTENT_TYPE, clientProduces);
|
||||
}
|
||||
}
|
||||
|
||||
private void parseHeaders(MethodMetadata md, Method method,
|
||||
RequestMapping annotation) {
|
||||
// TODO: only supports one header value per key
|
||||
if (annotation.headers() != null && annotation.headers().length > 0) {
|
||||
for (String header : annotation.headers()) {
|
||||
int index = header.indexOf('=');
|
||||
md.template().header(resolve(header.substring(0, index)),
|
||||
resolve(header.substring(index + 1).trim()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Map<Class<? extends Annotation>, AnnotatedParameterProcessor> toAnnotatedArgumentProcessorMap(
|
||||
List<AnnotatedParameterProcessor> processors) {
|
||||
Map<Class<? extends Annotation>, AnnotatedParameterProcessor> result = new HashMap<>();
|
||||
for (AnnotatedParameterProcessor processor : processors) {
|
||||
result.put(processor.getAnnotationType(), processor);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<AnnotatedParameterProcessor> getDefaultAnnotatedArgumentsProcessors() {
|
||||
|
||||
List<AnnotatedParameterProcessor> annotatedArgumentResolvers = new ArrayList<>();
|
||||
|
||||
annotatedArgumentResolvers.add(new PathVariableParameterProcessor());
|
||||
annotatedArgumentResolvers.add(new RequestParamParameterProcessor());
|
||||
annotatedArgumentResolvers.add(new RequestHeaderParameterProcessor());
|
||||
|
||||
return annotatedArgumentResolvers;
|
||||
}
|
||||
|
||||
private Annotation synthesizeWithMethodParameterNameAsFallbackValue(
|
||||
Annotation parameterAnnotation, Method method, int parameterIndex) {
|
||||
Map<String, Object> annotationAttributes = AnnotationUtils
|
||||
.getAnnotationAttributes(parameterAnnotation);
|
||||
Object defaultValue = AnnotationUtils.getDefaultValue(parameterAnnotation);
|
||||
if (defaultValue instanceof String
|
||||
&& defaultValue.equals(annotationAttributes.get(AnnotationUtils.VALUE))) {
|
||||
Type[] parameterTypes = method.getGenericParameterTypes();
|
||||
String[] parameterNames = PARAMETER_NAME_DISCOVERER.getParameterNames(method);
|
||||
if (shouldAddParameterName(parameterIndex, parameterTypes, parameterNames)) {
|
||||
annotationAttributes.put(AnnotationUtils.VALUE,
|
||||
parameterNames[parameterIndex]);
|
||||
}
|
||||
}
|
||||
return AnnotationUtils.synthesizeAnnotation(annotationAttributes,
|
||||
parameterAnnotation.annotationType(), null);
|
||||
}
|
||||
|
||||
private boolean shouldAddParameterName(int parameterIndex, Type[] parameterTypes, String[] parameterNames) {
|
||||
// has a parameter name
|
||||
return parameterNames != null && parameterNames.length > parameterIndex
|
||||
// has a type
|
||||
&& parameterTypes != null && parameterTypes.length > parameterIndex
|
||||
// and it is a simple property
|
||||
&& BeanUtils.isSimpleProperty(parameterTypes[parameterIndex].getClass());
|
||||
}
|
||||
|
||||
private class SimpleAnnotatedParameterContext
|
||||
implements AnnotatedParameterProcessor.AnnotatedParameterContext {
|
||||
|
||||
private final MethodMetadata methodMetadata;
|
||||
|
||||
private final int parameterIndex;
|
||||
|
||||
public SimpleAnnotatedParameterContext(MethodMetadata methodMetadata,
|
||||
int parameterIndex) {
|
||||
this.methodMetadata = methodMetadata;
|
||||
this.parameterIndex = parameterIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodMetadata getMethodMetadata() {
|
||||
return this.methodMetadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getParameterIndex() {
|
||||
return this.parameterIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParameterName(String name) {
|
||||
nameParam(this.methodMetadata, name, this.parameterIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> setTemplateParameter(String name,
|
||||
Collection<String> rest) {
|
||||
return addTemplatedParam(rest, name);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConvertingExpander implements Param.Expander {
|
||||
|
||||
private final ConversionService conversionService;
|
||||
|
||||
public ConvertingExpander(ConversionService conversionService) {
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String expand(Object value) {
|
||||
return this.conversionService.convert(value, String.class);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.hystrix;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
|
||||
|
||||
/**
|
||||
* Convenience annotation for clients to enable Hystrix circuit breakers (specifically).
|
||||
* Use this (optionally) in case you want discovery and know for sure that it is Hystrix
|
||||
* you want. All it does is turn on circuit breakers and let the autoconfiguration find
|
||||
* the Hystrix classes if they are available (i.e. you need Hystrix on the classpath as
|
||||
* well).
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
@EnableCircuitBreaker
|
||||
public @interface EnableHystrix {
|
||||
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2013-2014 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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.hystrix;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.ConditionalOnEnabledHealthIndicator;
|
||||
import org.springframework.boot.actuate.autoconfigure.HealthIndicatorAutoConfiguration;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import com.netflix.hystrix.Hystrix;
|
||||
|
||||
/**
|
||||
* Auto configuration for Hystrix.
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass({ Hystrix.class, HealthIndicator.class })
|
||||
@AutoConfigureAfter({ HealthIndicatorAutoConfiguration.class })
|
||||
public class HystrixAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnEnabledHealthIndicator("hystrix")
|
||||
public HystrixHealthIndicator hystrixHealthIndicator() {
|
||||
return new HystrixHealthIndicator();
|
||||
}
|
||||
|
||||
}
|
||||
+213
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.hystrix;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.catalina.core.ApplicationContext;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.endpoint.Endpoint;
|
||||
import org.springframework.boot.actuate.metrics.GaugeService;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.client.actuator.HasFeatures;
|
||||
import org.springframework.cloud.client.actuator.NamedFeature;
|
||||
import org.springframework.context.SmartLifecycle;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.netflix.hystrix.Hystrix;
|
||||
import com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCommandAspect;
|
||||
import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsPoller;
|
||||
import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsPoller.MetricsAsJsonPollerListener;
|
||||
import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
* @author Christian Dupuis
|
||||
* @author Venil Noronha
|
||||
*/
|
||||
@Configuration
|
||||
public class HystrixCircuitBreakerConfiguration {
|
||||
|
||||
@Bean
|
||||
public HystrixCommandAspect hystrixCommandAspect() {
|
||||
return new HystrixCommandAspect();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HystrixShutdownHook hystrixShutdownHook() {
|
||||
return new HystrixShutdownHook();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HasFeatures hystrixFeature() {
|
||||
return HasFeatures.namedFeatures(new NamedFeature("Hystrix", HystrixCommandAspect.class));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnProperty(value = "hystrix.stream.endpoint.enabled", matchIfMissing = true)
|
||||
@ConditionalOnWebApplication
|
||||
@ConditionalOnClass({ Endpoint.class, HystrixMetricsStreamServlet.class })
|
||||
protected static class HystrixWebConfiguration {
|
||||
|
||||
@Bean
|
||||
public HystrixStreamEndpoint hystrixStreamEndpoint() {
|
||||
return new HystrixStreamEndpoint();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HasFeatures hystrixFeature() {
|
||||
return HasFeatures.namedFeature("Hystrix Stream Servlet", HystrixStreamEndpoint.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnProperty(value = "hystrix.metrics.enabled", matchIfMissing = true)
|
||||
@ConditionalOnClass({ HystrixMetricsPoller.class, GaugeService.class })
|
||||
@EnableConfigurationProperties(HystrixMetricsProperties.class)
|
||||
protected static class HystrixMetricsPollerConfiguration implements SmartLifecycle {
|
||||
|
||||
private static Log logger = LogFactory
|
||||
.getLog(HystrixMetricsPollerConfiguration.class);
|
||||
|
||||
@Autowired(required = false)
|
||||
private GaugeService gauges;
|
||||
|
||||
@Autowired
|
||||
private HystrixMetricsProperties metricsProperties;
|
||||
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
private HystrixMetricsPoller poller;
|
||||
|
||||
private Set<String> reserved = new HashSet<String>(Arrays.asList("group", "name",
|
||||
"type", "currentTime"));
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (this.gauges == null) {
|
||||
return;
|
||||
}
|
||||
MetricsAsJsonPollerListener listener = new MetricsAsJsonPollerListener() {
|
||||
@Override
|
||||
public void handleJsonMetric(String json) {
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map = HystrixMetricsPollerConfiguration.this.mapper
|
||||
.readValue(json, Map.class);
|
||||
if (map != null && map.containsKey("type")) {
|
||||
addMetrics(map, "hystrix.");
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
this.poller = new HystrixMetricsPoller(listener,
|
||||
metricsProperties.getPollingIntervalMs());
|
||||
// start polling and it will write directly to the listener
|
||||
this.poller.start();
|
||||
logger.info("Starting poller");
|
||||
}
|
||||
|
||||
private void addMetrics(Map<String, Object> map, String root) {
|
||||
StringBuilder prefixBuilder = new StringBuilder(root);
|
||||
if (map.containsKey("type")) {
|
||||
prefixBuilder.append((String) map.get("type"));
|
||||
if (map.containsKey("group")) {
|
||||
prefixBuilder.append(".").append(map.get("group"));
|
||||
}
|
||||
prefixBuilder.append(".").append(map.get("name"));
|
||||
}
|
||||
String prefix = prefixBuilder.toString();
|
||||
for (String key : map.keySet()) {
|
||||
Object value = map.get(key);
|
||||
if (!this.reserved.contains(key)) {
|
||||
if (value instanceof Number) {
|
||||
String name = prefix + "." + key;
|
||||
this.gauges.submit(name, ((Number) value).doubleValue());
|
||||
}
|
||||
else if (value instanceof Map) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> sub = (Map<String, Object>) value;
|
||||
addMetrics(sub, prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
if (this.poller != null) {
|
||||
this.poller.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return this.poller != null ? this.poller.isRunning() : false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPhase() {
|
||||
return Ordered.LOWEST_PRECEDENCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoStartup() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop(Runnable callback) {
|
||||
if (this.poller != null) {
|
||||
this.poller.shutdown();
|
||||
}
|
||||
callback.run();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link DisposableBean} that makes sure that Hystrix internal state is cleared when
|
||||
* {@link ApplicationContext} shuts down.
|
||||
*/
|
||||
private class HystrixShutdownHook implements DisposableBean {
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
// Just call Hystrix to reset thread pool etc.
|
||||
Hystrix.reset();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.hystrix;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public interface HystrixConstants {
|
||||
|
||||
String HYSTRIX_STREAM_DESTINATION = "springCloudHystrixStream";
|
||||
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2013-2014 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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.hystrix;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Health.Builder;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
|
||||
import com.netflix.hystrix.HystrixCircuitBreaker;
|
||||
import com.netflix.hystrix.HystrixCommandMetrics;
|
||||
|
||||
/**
|
||||
* A {@link HealthIndicator} implementation for Hystrix circuit breakers.
|
||||
* <p>
|
||||
* This default implementation will not change the system state (e.g. <code>OK</code>) but
|
||||
* includes all open circuits by name.
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
*/
|
||||
public class HystrixHealthIndicator extends AbstractHealthIndicator {
|
||||
|
||||
private static final Status CIRCUIT_OPEN = new Status("CIRCUIT_OPEN");
|
||||
|
||||
@Override
|
||||
protected void doHealthCheck(Builder builder) throws Exception {
|
||||
List<String> openCircuitBreakers = new ArrayList<String>();
|
||||
|
||||
// Collect all open circuit breakers from Hystrix
|
||||
for (HystrixCommandMetrics metrics : HystrixCommandMetrics.getInstances()) {
|
||||
HystrixCircuitBreaker circuitBreaker = HystrixCircuitBreaker.Factory
|
||||
.getInstance(metrics.getCommandKey());
|
||||
if (circuitBreaker != null && circuitBreaker.isOpen()) {
|
||||
openCircuitBreakers.add(metrics.getCommandGroup().name() + "::"
|
||||
+ metrics.getCommandKey().name());
|
||||
}
|
||||
}
|
||||
|
||||
// If there is at least one open circuit report OUT_OF_SERVICE adding the command
|
||||
// group
|
||||
// and key name
|
||||
if (openCircuitBreakers.size() > 0) {
|
||||
builder.status(CIRCUIT_OPEN).withDetail("openCircuitBreakers",
|
||||
openCircuitBreakers);
|
||||
}
|
||||
else {
|
||||
builder.up();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.hystrix;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author Venil Noronha
|
||||
*/
|
||||
@Data
|
||||
@ConfigurationProperties("hystrix.metrics")
|
||||
public class HystrixMetricsProperties {
|
||||
|
||||
/** Enable Hystrix metrics polling. Defaults to true. */
|
||||
private boolean enabled = true;
|
||||
|
||||
/** Interval between subsequent polling of metrics. Defaults to 2000 ms. */
|
||||
private Integer pollingIntervalMs = 2000;
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2013-2014 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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.hystrix;
|
||||
|
||||
import org.springframework.cloud.netflix.endpoint.ServletWrappingEndpoint;
|
||||
|
||||
import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class HystrixStreamEndpoint extends ServletWrappingEndpoint {
|
||||
|
||||
public HystrixStreamEndpoint() {
|
||||
super(HystrixMetricsStreamServlet.class, "hystrixStream", "/hystrix.stream",
|
||||
false, true);
|
||||
}
|
||||
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.hystrix.security;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.AllNestedConditions;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.netflix.hystrix.security.HystrixSecurityAutoConfiguration.HystrixSecurityCondition;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
|
||||
import com.netflix.hystrix.Hystrix;
|
||||
import com.netflix.hystrix.strategy.HystrixPlugins;
|
||||
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
|
||||
import com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier;
|
||||
import com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;
|
||||
import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisher;
|
||||
import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;
|
||||
|
||||
/**
|
||||
* @author Daniel Lavoie
|
||||
*/
|
||||
@Configuration
|
||||
@Conditional(HystrixSecurityCondition.class)
|
||||
@ConditionalOnClass({ Hystrix.class, SecurityContext.class })
|
||||
public class HystrixSecurityAutoConfiguration {
|
||||
@Autowired(required = false)
|
||||
private HystrixConcurrencyStrategy existingConcurrencyStrategy;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
// Keeps references of existing Hystrix plugins.
|
||||
HystrixEventNotifier eventNotifier = HystrixPlugins.getInstance()
|
||||
.getEventNotifier();
|
||||
HystrixMetricsPublisher metricsPublisher = HystrixPlugins.getInstance()
|
||||
.getMetricsPublisher();
|
||||
HystrixPropertiesStrategy propertiesStrategy = HystrixPlugins.getInstance()
|
||||
.getPropertiesStrategy();
|
||||
HystrixCommandExecutionHook commandExecutionHook = HystrixPlugins.getInstance()
|
||||
.getCommandExecutionHook();
|
||||
|
||||
HystrixPlugins.reset();
|
||||
|
||||
// Registers existing plugins excepts the Concurrent Strategy plugin.
|
||||
HystrixPlugins.getInstance().registerConcurrencyStrategy(
|
||||
new SecurityContextConcurrencyStrategy(existingConcurrencyStrategy));
|
||||
HystrixPlugins.getInstance().registerEventNotifier(eventNotifier);
|
||||
HystrixPlugins.getInstance().registerMetricsPublisher(metricsPublisher);
|
||||
HystrixPlugins.getInstance().registerPropertiesStrategy(propertiesStrategy);
|
||||
HystrixPlugins.getInstance().registerCommandExecutionHook(commandExecutionHook);
|
||||
}
|
||||
|
||||
static class HystrixSecurityCondition extends AllNestedConditions {
|
||||
|
||||
public HystrixSecurityCondition() {
|
||||
super(ConfigurationPhase.REGISTER_BEAN);
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(name = "feign.hystrix.enabled", matchIfMissing = true)
|
||||
static class HystrixEnabled {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(name = "hystrix.shareSecurityContext")
|
||||
static class ShareSecurityContext {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.hystrix.security;
|
||||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.security.concurrent.DelegatingSecurityContextCallable;
|
||||
|
||||
import com.netflix.hystrix.HystrixThreadPoolKey;
|
||||
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
|
||||
import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariable;
|
||||
import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariableLifecycle;
|
||||
import com.netflix.hystrix.strategy.properties.HystrixProperty;
|
||||
|
||||
/**
|
||||
* @author daniellavoie
|
||||
*/
|
||||
public class SecurityContextConcurrencyStrategy extends HystrixConcurrencyStrategy {
|
||||
private HystrixConcurrencyStrategy existingConcurrencyStrategy;
|
||||
|
||||
public SecurityContextConcurrencyStrategy(
|
||||
HystrixConcurrencyStrategy existingConcurrencyStrategy) {
|
||||
this.existingConcurrencyStrategy = existingConcurrencyStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockingQueue<Runnable> getBlockingQueue(int maxQueueSize) {
|
||||
return existingConcurrencyStrategy != null
|
||||
? existingConcurrencyStrategy.getBlockingQueue(maxQueueSize)
|
||||
: super.getBlockingQueue(maxQueueSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> HystrixRequestVariable<T> getRequestVariable(
|
||||
HystrixRequestVariableLifecycle<T> rv) {
|
||||
return existingConcurrencyStrategy != null
|
||||
? existingConcurrencyStrategy.getRequestVariable(rv)
|
||||
: super.getRequestVariable(rv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
|
||||
HystrixProperty<Integer> corePoolSize,
|
||||
HystrixProperty<Integer> maximumPoolSize,
|
||||
HystrixProperty<Integer> keepAliveTime, TimeUnit unit,
|
||||
BlockingQueue<Runnable> workQueue) {
|
||||
return existingConcurrencyStrategy != null
|
||||
? existingConcurrencyStrategy.getThreadPool(threadPoolKey, corePoolSize,
|
||||
maximumPoolSize, keepAliveTime, unit, workQueue)
|
||||
: super.getThreadPool(threadPoolKey, corePoolSize, maximumPoolSize,
|
||||
keepAliveTime, unit, workQueue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Callable<T> wrapCallable(Callable<T> callable) {
|
||||
return existingConcurrencyStrategy != null
|
||||
? existingConcurrencyStrategy
|
||||
.wrapCallable(new DelegatingSecurityContextCallable<T>(callable))
|
||||
: super.wrapCallable(new DelegatingSecurityContextCallable<T>(callable));
|
||||
}
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.metrics;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
|
||||
/**
|
||||
* @author Jon Schneider
|
||||
*/
|
||||
public class DefaultMetricsTagProvider implements MetricsTagProvider {
|
||||
@Override
|
||||
public Map<String, String> clientHttpRequestTags(HttpRequest request,
|
||||
ClientHttpResponse response) {
|
||||
String urlTemplate = RestTemplateUrlTemplateHolder.getRestTemplateUrlTemplate();
|
||||
if (urlTemplate == null) {
|
||||
urlTemplate = "none";
|
||||
}
|
||||
|
||||
String status;
|
||||
try {
|
||||
status = (response == null) ? "CLIENT_ERROR" : ((Integer) response
|
||||
.getRawStatusCode()).toString();
|
||||
}
|
||||
catch (IOException e) {
|
||||
status = "IO_ERROR";
|
||||
}
|
||||
|
||||
String host = request.getURI().getHost();
|
||||
if( host == null ) {
|
||||
host = "none";
|
||||
}
|
||||
|
||||
String strippedUrlTemplate = urlTemplate.replaceAll("^https?://[^/]+/", "");
|
||||
|
||||
Map<String, String> tags = new HashMap<>();
|
||||
tags.put("method", request.getMethod().name());
|
||||
tags.put("uri", sanitizeUrlTemplate(strippedUrlTemplate));
|
||||
tags.put("status", status);
|
||||
tags.put("clientName", host);
|
||||
|
||||
return Collections.unmodifiableMap(tags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> httpRequestTags(HttpServletRequest request,
|
||||
HttpServletResponse response, Object handler, String caller) {
|
||||
Map<String, String> tags = new HashMap<>();
|
||||
|
||||
tags.put("method", request.getMethod());
|
||||
tags.put("status", ((Integer) response.getStatus()).toString());
|
||||
|
||||
String uri = (String) request
|
||||
.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
|
||||
if (uri == null) {
|
||||
uri = request.getPathInfo();
|
||||
}
|
||||
if (!StringUtils.hasText(uri)) {
|
||||
uri = "/";
|
||||
}
|
||||
uri = sanitizeUrlTemplate(uri.substring(1));
|
||||
tags.put("uri", uri.isEmpty() ? "root" : uri);
|
||||
|
||||
Object exception = request.getAttribute("exception");
|
||||
if (exception != null) {
|
||||
tags.put("exception", exception.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
if (caller != null) {
|
||||
tags.put("caller", caller);
|
||||
}
|
||||
|
||||
return tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* As is, the urlTemplate is not suitable for use with Atlas, as all interactions with
|
||||
* Atlas take place via query parameters
|
||||
*/
|
||||
protected String sanitizeUrlTemplate(String urlTemplate) {
|
||||
String sanitized = urlTemplate
|
||||
.replaceAll("\\{(\\w+):.+}(?=/|$)", "-$1-") // extract path variable names from regex expressions
|
||||
.replaceAll("/", "_")
|
||||
.replaceAll("[{}]", "-");
|
||||
if (!StringUtils.hasText(sanitized)) {
|
||||
sanitized = "none";
|
||||
}
|
||||
return sanitized;
|
||||
}
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.metrics;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.cloud.netflix.metrics.servo.ServoMonitorCache;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.client.ClientHttpRequestExecution;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
|
||||
import com.netflix.servo.MonitorRegistry;
|
||||
import com.netflix.servo.monitor.MonitorConfig;
|
||||
import com.netflix.servo.tag.SmallTagMap;
|
||||
import com.netflix.servo.tag.Tags;
|
||||
|
||||
/**
|
||||
* Intercepts RestTemplate requests and records metrics about execution time and results.
|
||||
*
|
||||
* @author Jon Schneider
|
||||
*/
|
||||
public class MetricsClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {
|
||||
/**
|
||||
* The interceptor writes to a Servo MonitorRegistry, which we get away with for now
|
||||
* because our Spectator implementation is underpinned by a ServoRegistry. When Spring
|
||||
* Boot (Actuator) provides a more general purpose abstraction for dimensional metrics
|
||||
* systems, this can be moved there and rewritten against that abstraction.
|
||||
*/
|
||||
private final MonitorRegistry registry;
|
||||
|
||||
private final Collection<MetricsTagProvider> tagProviders;
|
||||
|
||||
private final ServoMonitorCache servoMonitorCache;
|
||||
|
||||
private final String metricName;
|
||||
|
||||
public MetricsClientHttpRequestInterceptor(MonitorRegistry registry,
|
||||
Collection<MetricsTagProvider> tagProviders,
|
||||
ServoMonitorCache servoMonitorCache, String metricName) {
|
||||
this.registry = registry;
|
||||
this.tagProviders = tagProviders;
|
||||
this.servoMonitorCache = servoMonitorCache;
|
||||
this.metricName = metricName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientHttpResponse intercept(HttpRequest request, byte[] body,
|
||||
ClientHttpRequestExecution execution) throws IOException {
|
||||
long startTime = System.nanoTime();
|
||||
|
||||
ClientHttpResponse response = null;
|
||||
try {
|
||||
response = execution.execute(request, body);
|
||||
return response;
|
||||
}
|
||||
finally {
|
||||
SmallTagMap.Builder builder = SmallTagMap.builder();
|
||||
for (MetricsTagProvider tagProvider : tagProviders) {
|
||||
for (Map.Entry<String, String> tag : tagProvider
|
||||
.clientHttpRequestTags(request, response).entrySet()) {
|
||||
builder.add(Tags.newTag(tag.getKey(), tag.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
MonitorConfig.Builder monitorConfigBuilder = MonitorConfig
|
||||
.builder(metricName);
|
||||
monitorConfigBuilder.withTags(builder);
|
||||
|
||||
servoMonitorCache.getTimer(monitorConfigBuilder.build())
|
||||
.record(System.nanoTime() - startTime, TimeUnit.NANOSECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.metrics;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.cloud.netflix.metrics.servo.ServoMonitorCache;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
||||
|
||||
import com.netflix.servo.MonitorRegistry;
|
||||
import com.netflix.servo.monitor.MonitorConfig;
|
||||
import com.netflix.servo.tag.SmallTagMap;
|
||||
import com.netflix.servo.tag.Tags;
|
||||
|
||||
import static org.springframework.web.context.request.RequestAttributes.SCOPE_REQUEST;
|
||||
|
||||
/**
|
||||
* Intercepts incoming HTTP requests and records metrics about execution time and results.
|
||||
*
|
||||
* @author Jon Schneider
|
||||
*/
|
||||
public class MetricsHandlerInterceptor extends HandlerInterceptorAdapter {
|
||||
@Value("${netflix.metrics.rest.metricName:rest}")
|
||||
String metricName;
|
||||
|
||||
@Value("${netflix.metrics.rest.callerHeader:#{null}}")
|
||||
String callerHeader;
|
||||
|
||||
@Autowired
|
||||
MonitorRegistry registry;
|
||||
|
||||
@Autowired
|
||||
ServoMonitorCache servoMonitorCache;
|
||||
|
||||
@Autowired
|
||||
Collection<MetricsTagProvider> tagProviders;
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
|
||||
Object handler) throws Exception {
|
||||
RequestContextHolder.getRequestAttributes().setAttribute("requestStartTime",
|
||||
System.nanoTime(), SCOPE_REQUEST);
|
||||
return super.preHandle(request, response, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
|
||||
Object handler, Exception ex) throws Exception {
|
||||
RequestContextHolder.getRequestAttributes().setAttribute("exception", ex,
|
||||
SCOPE_REQUEST);
|
||||
Long startTime = (Long) RequestContextHolder.getRequestAttributes().getAttribute(
|
||||
"requestStartTime", SCOPE_REQUEST);
|
||||
if (startTime != null)
|
||||
recordMetric(request, response, handler, startTime);
|
||||
super.afterCompletion(request, response, handler, ex);
|
||||
}
|
||||
|
||||
protected void recordMetric(HttpServletRequest request, HttpServletResponse response,
|
||||
Object handler, Long startTime) {
|
||||
String caller = null;
|
||||
if (callerHeader != null) {
|
||||
caller = request.getHeader(callerHeader);
|
||||
}
|
||||
|
||||
SmallTagMap.Builder builder = SmallTagMap.builder();
|
||||
for (MetricsTagProvider tagProvider : tagProviders) {
|
||||
Map<String, String> tags = tagProvider.httpRequestTags(request, response,
|
||||
handler, caller);
|
||||
for (Map.Entry<String, String> tag : tags.entrySet()) {
|
||||
builder.add(Tags.newTag(tag.getKey(), tag.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
MonitorConfig.Builder monitorConfigBuilder = MonitorConfig.builder(metricName);
|
||||
monitorConfigBuilder.withTags(builder);
|
||||
|
||||
servoMonitorCache.getTimer(monitorConfigBuilder.build()).record(
|
||||
System.nanoTime() - startTime, TimeUnit.NANOSECONDS);
|
||||
}
|
||||
}
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.metrics;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.netflix.servo.MonitorRegistry;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.boot.actuate.metrics.reader.MetricReader;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.cloud.netflix.metrics.servo.ServoMonitorCache;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
|
||||
import com.netflix.servo.monitor.Monitors;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author Jon Schneider
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnProperty(value = "spring.cloud.netflix.metrics.enabled", havingValue = "true", matchIfMissing = true)
|
||||
@ConditionalOnClass({ Monitors.class, MetricReader.class })
|
||||
public class MetricsInterceptorConfiguration {
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnWebApplication
|
||||
static class MetricsWebResourceConfiguration extends WebMvcConfigurerAdapter {
|
||||
@Bean
|
||||
MetricsHandlerInterceptor servoMonitoringWebResourceInterceptor() {
|
||||
return new MetricsHandlerInterceptor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(servoMonitoringWebResourceInterceptor());
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(JoinPoint.class)
|
||||
@ConditionalOnProperty(value = "spring.aop.enabled", havingValue = "true", matchIfMissing = true)
|
||||
@ConditionalOnBean({ RestTemplate.class })
|
||||
static class MetricsRestTemplateAspectConfiguration {
|
||||
|
||||
@Bean
|
||||
RestTemplateUrlTemplateCapturingAspect restTemplateUrlTemplateCapturingAspect() {
|
||||
return new RestTemplateUrlTemplateCapturingAspect();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnBean({ RestTemplate.class })
|
||||
@ConditionalOnClass(name = "javax.servlet.http.HttpServletRequest")
|
||||
static class MetricsRestTemplateConfiguration {
|
||||
|
||||
@Value("${netflix.metrics.restClient.metricName:restclient}")
|
||||
String metricName;
|
||||
|
||||
@Bean
|
||||
MetricsClientHttpRequestInterceptor spectatorLoggingClientHttpRequestInterceptor(
|
||||
MonitorRegistry registry, Collection<MetricsTagProvider> tagProviders,
|
||||
ServoMonitorCache servoMonitorCache) {
|
||||
return new MetricsClientHttpRequestInterceptor(registry, tagProviders,
|
||||
servoMonitorCache, this.metricName);
|
||||
}
|
||||
|
||||
@Bean
|
||||
BeanPostProcessor spectatorRestTemplateInterceptorPostProcessor() {
|
||||
return new MetricsInterceptorPostProcessor();
|
||||
}
|
||||
|
||||
private static class MetricsInterceptorPostProcessor
|
||||
implements BeanPostProcessor, ApplicationContextAware {
|
||||
private ApplicationContext context;
|
||||
private MetricsClientHttpRequestInterceptor interceptor;
|
||||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) {
|
||||
if (bean instanceof RestTemplate) {
|
||||
if (this.interceptor == null) {
|
||||
this.interceptor = this.context
|
||||
.getBean(MetricsClientHttpRequestInterceptor.class);
|
||||
}
|
||||
RestTemplate restTemplate = (RestTemplate) bean;
|
||||
// create a new list as the old one may be unmodifiable (ie Arrays.asList())
|
||||
ArrayList<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
|
||||
interceptors.add(interceptor);
|
||||
interceptors.addAll(restTemplate.getInterceptors());
|
||||
restTemplate.setInterceptors(interceptors);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext context)
|
||||
throws BeansException {
|
||||
this.context = context;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.metrics;
|
||||
|
||||
import java.util.Map;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
|
||||
/**
|
||||
* @author Jon Schneider
|
||||
*/
|
||||
public interface MetricsTagProvider {
|
||||
/**
|
||||
* @param request RestTemplate client HTTP request
|
||||
* @param response may be null in the event of a client error
|
||||
* @return a map of tags added to every client HTTP request metric
|
||||
*/
|
||||
Map<String, String> clientHttpRequestTags(HttpRequest request,
|
||||
ClientHttpResponse response);
|
||||
|
||||
/**
|
||||
* @param request HTTP request
|
||||
* @param response HTTP response
|
||||
* @param handler the request method that is responsible for handling the request
|
||||
* @return a map of tags added to every Spring MVC HTTP request metric
|
||||
*/
|
||||
Map<String, String> httpRequestTags(HttpServletRequest request,
|
||||
HttpServletResponse response, Object handler, String caller);
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.metrics;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
|
||||
/**
|
||||
* @author Jon Schneider
|
||||
*/
|
||||
public class MetricsTagProviderAdapter implements MetricsTagProvider {
|
||||
@Override
|
||||
public Map<String, String> clientHttpRequestTags(HttpRequest request,
|
||||
ClientHttpResponse response) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> httpRequestTags(HttpServletRequest request,
|
||||
HttpServletResponse response, Object handler, String caller) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.metrics;
|
||||
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
|
||||
/**
|
||||
* Captures the still-templated URI because currently the ClientHttpRequestInterceptor
|
||||
* currently only gives us the means to retrieve the substituted URI.
|
||||
*
|
||||
* @author Jon Schneider
|
||||
*/
|
||||
@Aspect
|
||||
public class RestTemplateUrlTemplateCapturingAspect {
|
||||
@Around("execution(* org.springframework.web.client.RestOperations+.*(String, ..))")
|
||||
Object captureUrlTemplate(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
try {
|
||||
String urlTemplate = (String) joinPoint.getArgs()[0];
|
||||
RestTemplateUrlTemplateHolder.setRestTemplateUrlTemplate(urlTemplate);
|
||||
return joinPoint.proceed();
|
||||
}
|
||||
finally {
|
||||
RestTemplateUrlTemplateHolder.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.metrics;
|
||||
|
||||
import org.springframework.core.NamedThreadLocal;
|
||||
|
||||
/**
|
||||
* Holding area for the still-templated URI because currently the
|
||||
* ClientHttpRequestInterceptor only gives us the means to retrieve the substituted URI.
|
||||
*
|
||||
* @author Jon Schneider
|
||||
*/
|
||||
public class RestTemplateUrlTemplateHolder {
|
||||
private static final ThreadLocal<String> restTemplateUrlTemplateHolder = new NamedThreadLocal<String>(
|
||||
"Rest Template URL Template");
|
||||
|
||||
public static String getRestTemplateUrlTemplate() {
|
||||
return restTemplateUrlTemplateHolder.get();
|
||||
}
|
||||
|
||||
public static void setRestTemplateUrlTemplate(String urlTemplate) {
|
||||
restTemplateUrlTemplateHolder.set(urlTemplate);
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
restTemplateUrlTemplateHolder.remove();
|
||||
}
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.metrics;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.env.EnvironmentPostProcessor;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.core.env.MutablePropertySources;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class ServoEnvironmentPostProcessor implements EnvironmentPostProcessor {
|
||||
|
||||
private static final Log log = LogFactory.getLog(ServoEnvironmentPostProcessor.class);
|
||||
|
||||
@Override
|
||||
public void postProcessEnvironment(ConfigurableEnvironment environment,
|
||||
SpringApplication application) {
|
||||
if (ClassUtils.isPresent("com.netflix.servo.monitor.Monitors", null)) {
|
||||
// Make spring AOP default to target class so RestTemplates can be customized
|
||||
log.debug("Setting 'spring.aop.proxyTargetClass=true' to make spring AOP default to target class so RestTemplates can be customized");
|
||||
addDefaultProperty(environment, "spring.aop.proxyTargetClass", "true");
|
||||
}
|
||||
}
|
||||
|
||||
private void addDefaultProperty(ConfigurableEnvironment environment, String name,
|
||||
String value) {
|
||||
MutablePropertySources sources = environment.getPropertySources();
|
||||
Map<String, Object> map = null;
|
||||
if (sources.contains("defaultProperties")) {
|
||||
PropertySource<?> source = sources.get("defaultProperties");
|
||||
if (source instanceof MapPropertySource) {
|
||||
map = ((MapPropertySource) source).getSource();
|
||||
}
|
||||
}
|
||||
else {
|
||||
map = new LinkedHashMap<>();
|
||||
sources.addLast(new MapPropertySource("defaultProperties", map));
|
||||
}
|
||||
if (map != null) {
|
||||
map.put(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.metrics.atlas;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.actuate.metrics.export.Exporter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.cloud.netflix.metrics.servo.ServoMetricsAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.netflix.servo.MonitorRegistry;
|
||||
import com.netflix.servo.publish.MonitorRegistryMetricPoller;
|
||||
import com.netflix.servo.tag.BasicTagList;
|
||||
|
||||
/**
|
||||
* Configures the Atlas metrics backend, also configuring Spectator to collect metrics if necessary.
|
||||
*
|
||||
* @author Jon Schneider
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(AtlasMetricObserver.class)
|
||||
@Import(ServoMetricsAutoConfiguration.class)
|
||||
public class AtlasConfiguration {
|
||||
@Autowired(required = false)
|
||||
private Collection<AtlasTagProvider> tagProviders;
|
||||
|
||||
@Autowired(required = false)
|
||||
@Qualifier("atlasRestTemplate")
|
||||
private RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
@Bean
|
||||
public AtlasMetricObserverConfigBean atlasObserverConfig() {
|
||||
return new AtlasMetricObserverConfigBean();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public AtlasMetricObserver atlasObserver(AtlasMetricObserverConfigBean atlasObserverConfig) {
|
||||
BasicTagList tags = (BasicTagList) BasicTagList.EMPTY;
|
||||
if (tagProviders != null) {
|
||||
for (AtlasTagProvider tagProvider : tagProviders) {
|
||||
for (Map.Entry<String, String> tag : tagProvider.defaultTags().entrySet()) {
|
||||
if (tag.getValue() != null)
|
||||
tags = tags.copy(tag.getKey(), tag.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
return new AtlasMetricObserver(atlasObserverConfig, restTemplate, tags);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Exporter exporter(AtlasMetricObserver observer, MonitorRegistry monitorRegistry) {
|
||||
return new AtlasExporter(observer, new MonitorRegistryMetricPoller(monitorRegistry));
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.metrics.atlas;
|
||||
|
||||
import org.springframework.boot.actuate.metrics.export.Exporter;
|
||||
|
||||
import com.netflix.servo.publish.BasicMetricFilter;
|
||||
import com.netflix.servo.publish.MetricPoller;
|
||||
|
||||
/**
|
||||
* @author Jon Schneider
|
||||
*/
|
||||
public class AtlasExporter implements Exporter {
|
||||
private AtlasMetricObserver observer;
|
||||
private MetricPoller poller;
|
||||
|
||||
public AtlasExporter(AtlasMetricObserver observer, MetricPoller poller) {
|
||||
this.observer = observer;
|
||||
this.poller = poller;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void export() {
|
||||
observer.update(poller.poll(BasicMetricFilter.MATCH_ALL));
|
||||
}
|
||||
}
|
||||
+273
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.metrics.atlas;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.client.HttpClientErrorException;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonEncoding;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.dataformat.smile.SmileFactory;
|
||||
import com.netflix.servo.Metric;
|
||||
import com.netflix.servo.annotations.DataSourceType;
|
||||
import com.netflix.servo.monitor.MonitorConfig;
|
||||
import com.netflix.servo.publish.MetricObserver;
|
||||
import com.netflix.servo.tag.BasicTag;
|
||||
import com.netflix.servo.tag.Tag;
|
||||
import com.netflix.servo.tag.TagList;
|
||||
|
||||
/**
|
||||
* Observer that forwards metrics to atlas. In addition to being a MetricObserver, it also
|
||||
* supports a push model that sends metrics as soon as possible (asynchronously).
|
||||
*
|
||||
* @author Jon Schneider
|
||||
*/
|
||||
public class AtlasMetricObserver implements MetricObserver {
|
||||
private static final Log logger = LogFactory.getLog(AtlasMetricObserver.class);
|
||||
private static final SmileFactory smileFactory = new SmileFactory();
|
||||
private static final Tag atlasRateTag = new BasicTag("atlas.dstype", "rate");
|
||||
private static final Tag atlasCounterTag = new BasicTag("atlas.dstype", "counter");
|
||||
private static final Tag atlasGaugeTag = new BasicTag("atlas.dstype", "gauge");
|
||||
private static final Pattern validAtlasTag = Pattern.compile("[\\.\\-\\w]+");
|
||||
|
||||
private AtlasMetricObserverConfigBean config;
|
||||
private RestTemplate restTemplate;
|
||||
private TagList commonTags;
|
||||
private String uri;
|
||||
|
||||
public AtlasMetricObserver(AtlasMetricObserverConfigBean config,
|
||||
RestTemplate restTemplate, TagList commonTags) {
|
||||
this.config = config;
|
||||
this.commonTags = commonTags;
|
||||
this.restTemplate = restTemplate;
|
||||
this.uri = normalizeAtlasUri(config.getUri());
|
||||
|
||||
if (!validTags(commonTags)) {
|
||||
throw new IllegalArgumentException(
|
||||
"One or more atlas tags contain invalid characters, must match [\\.\\-\\w]+");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "atlas";
|
||||
}
|
||||
|
||||
protected static boolean validTags(TagList tags) {
|
||||
for (Tag tag : tags) {
|
||||
if (!validAtlasTag.matcher(tag.getKey()).matches()) {
|
||||
logger.debug("Invalid tag key " + tag.getKey());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!validAtlasTag.matcher(tag.getValue()).matches()) {
|
||||
logger.debug("Invalid tag value " + tag.getValue());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static String normalizeAtlasUri(String uri) {
|
||||
if (uri != null) {
|
||||
Matcher matcher = Pattern.compile("(.+?)(/api/v1/publish)?/?").matcher(uri);
|
||||
if (matcher.matches())
|
||||
return matcher.group(1) + "/api/v1/publish";
|
||||
else
|
||||
throw new IllegalStateException("netflix.atlas.uri is not a valid uri");
|
||||
}
|
||||
throw new IllegalStateException("netflix.atlas.uri was not found in your properties and is required to communicate with Atlas");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(List<Metric> rawMetrics) {
|
||||
if (!config.isEnabled()) {
|
||||
logger.debug("Atlas metric observer disabled. Not sending metrics.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (rawMetrics.isEmpty()) {
|
||||
logger.debug("Metrics list is empty, no data being sent to server.");
|
||||
return;
|
||||
}
|
||||
|
||||
List<Metric> metrics = sanitizeTags(addTypeTagsAsNecessary(rawMetrics));
|
||||
|
||||
for (int i = 0; i < metrics.size(); i += config.getBatchSize()) {
|
||||
List<Metric> batch = metrics.subList(i,
|
||||
Math.min(metrics.size(), config.getBatchSize() + i));
|
||||
logger.debug("Sending a metrics batch of size " + batch.size());
|
||||
sendMetricsBatch(batch);
|
||||
}
|
||||
}
|
||||
|
||||
enum PublishMetricsBatchStatus {
|
||||
NothingToDo, Success, PartialSuccess, Failure
|
||||
}
|
||||
|
||||
PublishMetricsBatchStatus sendMetricsBatch(List<Metric> metrics) {
|
||||
try {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
JsonGenerator gen = smileFactory.createGenerator(output, JsonEncoding.UTF8);
|
||||
|
||||
gen.writeStartObject();
|
||||
|
||||
writeCommonTags(gen);
|
||||
if (writeMetrics(gen, metrics) == 0)
|
||||
return PublishMetricsBatchStatus.NothingToDo; // short circuit this batch if no valid/numeric metrics existed
|
||||
|
||||
gen.writeEndObject();
|
||||
gen.flush();
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.valueOf("application/x-jackson-smile"));
|
||||
HttpEntity<byte[]> entity = new HttpEntity<>(output.toByteArray(), headers);
|
||||
try {
|
||||
ResponseEntity<Map> response = restTemplate.exchange(uri, HttpMethod.POST, entity, Map.class);
|
||||
if(response.getStatusCode() == HttpStatus.ACCEPTED) {
|
||||
// partial success processing the metrics batch
|
||||
List<String> messages = (List<String>) response.getBody().get("message");
|
||||
if(messages != null) {
|
||||
for (String message : messages) {
|
||||
logger.error("Failed to write metric to atlas: " + message);
|
||||
}
|
||||
}
|
||||
return PublishMetricsBatchStatus.PartialSuccess;
|
||||
}
|
||||
}
|
||||
catch (HttpClientErrorException e) {
|
||||
logger.error("Failed to write metrics to atlas: " + e.getResponseBodyAsString());
|
||||
return PublishMetricsBatchStatus.Failure;
|
||||
}
|
||||
catch (RestClientException e) {
|
||||
logger.error("Failed to write metrics to atlas", e);
|
||||
return PublishMetricsBatchStatus.Failure;
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
return PublishMetricsBatchStatus.Failure;
|
||||
}
|
||||
|
||||
return PublishMetricsBatchStatus.Success;
|
||||
}
|
||||
|
||||
private void writeCommonTags(JsonGenerator gen) throws IOException {
|
||||
gen.writeObjectFieldStart("tags");
|
||||
for (Tag tag : commonTags)
|
||||
gen.writeStringField(tag.getKey(), tag.getValue());
|
||||
gen.writeEndObject();
|
||||
}
|
||||
|
||||
private int writeMetrics(JsonGenerator gen, List<Metric> metrics) throws IOException {
|
||||
int totalMetricsInBatch = 0;
|
||||
gen.writeArrayFieldStart("metrics");
|
||||
|
||||
for (Metric m : metrics) {
|
||||
if (!validTags(m.getConfig().getTags()))
|
||||
continue;
|
||||
|
||||
if (!Number.class.isAssignableFrom(m.getValue().getClass()))
|
||||
continue;
|
||||
|
||||
gen.writeStartObject();
|
||||
|
||||
gen.writeObjectFieldStart("tags");
|
||||
gen.writeStringField("name", m.getConfig().getName());
|
||||
for (Tag tag : m.getConfig().getTags())
|
||||
gen.writeStringField(tag.getKey(), tag.getValue());
|
||||
gen.writeEndObject();
|
||||
|
||||
gen.writeNumberField("start", m.getTimestamp());
|
||||
gen.writeNumberField("value", m.getNumberValue().doubleValue());
|
||||
|
||||
gen.writeEndObject();
|
||||
|
||||
totalMetricsInBatch++;
|
||||
}
|
||||
|
||||
gen.writeEndArray();
|
||||
return totalMetricsInBatch;
|
||||
}
|
||||
|
||||
static List<Metric> sanitizeTags(List<Metric> metrics) {
|
||||
List<Metric> sanitized = new ArrayList<>(metrics.size());
|
||||
for (Metric m : metrics) {
|
||||
MonitorConfig.Builder config = MonitorConfig.builder(toValidCharset(m.getConfig().getName()));
|
||||
for (Tag tag : m.getConfig().getTags()) {
|
||||
config.withTag(toValidCharset(tag.getKey()), toValidCharset(tag.getValue()));
|
||||
}
|
||||
config.withPublishingPolicy(m.getConfig().getPublishingPolicy());
|
||||
sanitized.add(new Metric(config.build(), m.getTimestamp(), m.getValue()));
|
||||
}
|
||||
return sanitized;
|
||||
}
|
||||
|
||||
private static String toValidCharset(String name) {
|
||||
return name.replaceAll("[^\\.\\-\\w]", "_");
|
||||
}
|
||||
|
||||
static List<Metric> addTypeTagsAsNecessary(List<Metric> metrics) {
|
||||
List<Metric> typedMetrics = new ArrayList<>(metrics.size());
|
||||
for (Metric m : metrics) {
|
||||
String value = m.getConfig().getTags().getValue(DataSourceType.KEY);
|
||||
Metric transformed;
|
||||
|
||||
// Atlas will not normalize metrics tagged with atlas.dstype=gauge. Since
|
||||
// these metric types are pre-normalized, we do not want Atlas to touch the
|
||||
// value
|
||||
if (DataSourceType.GAUGE.name().equals(value)
|
||||
|| DataSourceType.RATE.name().equals(value)
|
||||
|| DataSourceType.NORMALIZED.name().equals(value)) {
|
||||
transformed = new Metric(m.getConfig().withAdditionalTag(atlasGaugeTag),
|
||||
m.getTimestamp(), m.getValue());
|
||||
}
|
||||
|
||||
// atlas.dstype=counter means you're sending the absolute value of the counter
|
||||
// (a monotonically increasing value), and Atlas will keep the previous value
|
||||
// and convert it to a rate per second when the metric is received
|
||||
else if (DataSourceType.COUNTER.name().equals(value)) {
|
||||
transformed = new Metric(
|
||||
m.getConfig().withAdditionalTag(atlasCounterTag),
|
||||
m.getTimestamp(), m.getValue());
|
||||
}
|
||||
|
||||
// Atlas will normalize the value to a minute boundary based on its timestamp
|
||||
else {
|
||||
transformed = new Metric(m.getConfig().withAdditionalTag(atlasRateTag),
|
||||
m.getTimestamp(), m.getValue());
|
||||
}
|
||||
|
||||
typedMetrics.add(transformed);
|
||||
}
|
||||
return typedMetrics;
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.metrics.atlas;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* @author Jon Schneider
|
||||
*/
|
||||
@ConfigurationProperties("netflix.atlas")
|
||||
public class AtlasMetricObserverConfigBean {
|
||||
private String uri;
|
||||
private boolean enabled = true;
|
||||
private Integer batchSize = 10000;
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public int getBatchSize() {
|
||||
return batchSize;
|
||||
}
|
||||
|
||||
public String getUri() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public void setBatchSize(Integer batchSize) {
|
||||
this.batchSize = batchSize;
|
||||
}
|
||||
|
||||
public void setUri(String uri) {
|
||||
this.uri = uri;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user