mirror of
https://github.com/jlengrand/helidon.git
synced 2026-03-10 08:21:17 +00:00
Extract common HTTP classes to common module.
Update version to 0.10.0 due to backward incompatible changes
This commit is contained in:
committed by
Tomas Langer
parent
df28d67d68
commit
c3ddab97fe
@@ -23,7 +23,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon</groupId>
|
||||
<artifactId>helidon-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-bom</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.common</groupId>
|
||||
<artifactId>helidon-common-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-common</artifactId>
|
||||
<name>Helidon Common</name>
|
||||
|
||||
46
common/common/src/main/java/io/helidon/common/SpiHelper.java
Normal file
46
common/common/src/main/java/io/helidon/common/SpiHelper.java
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package io.helidon.common;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
/**
|
||||
* Utility methods to help with loading of java services (mostly SPI related).
|
||||
*/
|
||||
public final class SpiHelper {
|
||||
private SpiHelper() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the first service implementation or throw an exception if nothing found.
|
||||
*
|
||||
* @param service the service class to load
|
||||
* @param <T> service type
|
||||
* @return the loaded service
|
||||
* @throws IllegalStateException if none implementation found
|
||||
*/
|
||||
public static <T> T loadSpi(Class<T> service) {
|
||||
ServiceLoader<T> servers = ServiceLoader.load(service);
|
||||
Iterator<T> serversIt = servers.iterator();
|
||||
if (serversIt.hasNext()) {
|
||||
return serversIt.next();
|
||||
} else {
|
||||
throw new IllegalStateException("No implementation found for SPI: " + service.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.common</groupId>
|
||||
<artifactId>helidon-common-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<name>Helidon Common Configurable</name>
|
||||
<artifactId>helidon-common-configurable</artifactId>
|
||||
|
||||
54
common/http/pom.xml
Normal file
54
common/http/pom.xml
Normal file
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
-->
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>helidon-common-project</artifactId>
|
||||
<groupId>io.helidon.common</groupId>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>helidon-common-http</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.helidon.common</groupId>
|
||||
<artifactId>helidon-common-reactive</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.helidon.common</groupId>
|
||||
<artifactId>helidon-common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest-all</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.helidon.webserver;
|
||||
package io.helidon.common.http;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,10 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.helidon.webserver;
|
||||
package io.helidon.common.http;
|
||||
|
||||
/**
|
||||
* Signals that a method has been invoked on already completed {@link ServerResponse} or {@link ResponseHeaders}.
|
||||
* Signals that a mutation method has been invoked on a resource that is already completed.
|
||||
*
|
||||
* It is no longer possible to mute state of these objects.
|
||||
*/
|
||||
public class AlreadyCompletedException extends IllegalStateException {
|
||||
@@ -34,9 +35,9 @@ public class AlreadyCompletedException extends IllegalStateException {
|
||||
/**
|
||||
* Constructs an {@link AlreadyCompletedException} with the specified detail message and cause.
|
||||
*
|
||||
* @param message the detail message (which is saved for later retrieval by the {@link Throwable#getMessage()} method).
|
||||
* @param cause the cause (which is saved for later retrieval by the {@link Throwable#getCause()} method).
|
||||
* (A {@code null} value is permitted, and indicates that the cause is nonexistent or unknown.)
|
||||
* @param message the detail message (which is saved for later retrieval by the {@link Throwable#getMessage()} method).
|
||||
* @param cause the cause (which is saved for later retrieval by the {@link Throwable#getCause()} method).
|
||||
* (A {@code null} value is permitted, and indicates that the cause is nonexistent or unknown.)
|
||||
*/
|
||||
public AlreadyCompletedException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
@@ -45,8 +46,8 @@ public class AlreadyCompletedException extends IllegalStateException {
|
||||
/**
|
||||
* Constructs an {@link AlreadyCompletedException} with the specified cause.
|
||||
*
|
||||
* @param cause the cause (which is saved for later retrieval by the {@link Throwable#getCause()} method).
|
||||
* (A {@code null} value is permitted, and indicates that the cause is nonexistent or unknown.)
|
||||
* @param cause the cause (which is saved for later retrieval by the {@link Throwable#getCause()} method).
|
||||
* (A {@code null} value is permitted, and indicates that the cause is nonexistent or unknown.)
|
||||
*/
|
||||
public AlreadyCompletedException(Throwable cause) {
|
||||
super(cause);
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.helidon.webserver;
|
||||
package io.helidon.common.http;
|
||||
|
||||
/**
|
||||
* Extracted from Guava.
|
||||
@@ -85,7 +85,6 @@ final class Ascii {
|
||||
return isUpperCase(c) ? (char) (c ^ 0x20) : c;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Indicates whether {@code c} is one of the twenty-six lowercase ASCII alphabetic characters
|
||||
* between {@code 'a'} and {@code 'z'} inclusive. All others (including non-ASCII characters)
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,13 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.helidon.webserver;
|
||||
package io.helidon.common.http;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.BitSet;
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
/**
|
||||
* Extracted from Guava.
|
||||
* <p>
|
||||
@@ -45,7 +44,257 @@ import java.util.Objects;
|
||||
@SuppressWarnings({"checkstyle:VisibilityModifier", "checkstyle:RedundantModifier"})
|
||||
abstract class CharMatcher {
|
||||
|
||||
/** Implementation of {@link #ascii()}. */
|
||||
/**
|
||||
* Constructor for use by subclasses. When subclassing, you may want to override
|
||||
* {@code toString()} to provide a useful description.
|
||||
*/
|
||||
protected CharMatcher() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a character is ASCII, meaning that its code point is less than 128.
|
||||
*
|
||||
* @since 19.0 (since 1.0 as constant {@code ASCII})
|
||||
*/
|
||||
public static CharMatcher ascii() {
|
||||
return Ascii.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code char} matcher that matches any character except the one specified.
|
||||
*
|
||||
* <p>To negate another {@code CharMatcher}, use {@link #negate()}.
|
||||
*/
|
||||
public static CharMatcher isNot(final char match) {
|
||||
return new IsNot(match);
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches any character.
|
||||
*
|
||||
* @since 19.0 (since 1.0 as constant {@code ANY})
|
||||
*/
|
||||
public static CharMatcher any() {
|
||||
return Any.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches no characters.
|
||||
*
|
||||
* @since 19.0 (since 1.0 as constant {@code NONE})
|
||||
*/
|
||||
public static CharMatcher none() {
|
||||
return None.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a character is an ISO control character as specified by
|
||||
* {@link Character#isISOControl(char)}.
|
||||
*
|
||||
* @since 19.0 (since 1.0 as constant {@code JAVA_ISO_CONTROL})
|
||||
*/
|
||||
public static CharMatcher javaIsoControl() {
|
||||
return JavaIsoControl.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code char} matcher that matches only one specified character.
|
||||
*/
|
||||
public static CharMatcher is(final char match) {
|
||||
return new Is(match);
|
||||
}
|
||||
|
||||
private static CharMatcher.IsEither isEither(char c1, char c2) {
|
||||
return new CharMatcher.IsEither(c1, c2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code char} matcher that matches any character not present in the given character
|
||||
* sequence.
|
||||
*/
|
||||
public static CharMatcher noneOf(CharSequence sequence) {
|
||||
return anyOf(sequence).negate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code char} matcher that matches any character present in the given character
|
||||
* sequence.
|
||||
*/
|
||||
public static CharMatcher anyOf(final CharSequence sequence) {
|
||||
switch (sequence.length()) {
|
||||
case 0:
|
||||
return none();
|
||||
case 1:
|
||||
return is(sequence.charAt(0));
|
||||
case 2:
|
||||
return isEither(sequence.charAt(0), sequence.charAt(1));
|
||||
default:
|
||||
// TODO(lowasser): is it potentially worth just going ahead and building a precomputed
|
||||
// matcher?
|
||||
return new AnyOf(sequence);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Java Unicode escape sequence for the given character, in the form "\u12AB" where
|
||||
* "12AB" is the four hexadecimal digits representing the 16 bits of the UTF-16 character.
|
||||
*/
|
||||
private static String showCharacter(char c) {
|
||||
String hex = "0123456789ABCDEF";
|
||||
char[] tmp = {'\\', 'u', '\0', '\0', '\0', '\0'};
|
||||
for (int i = 0; i < 4; i++) {
|
||||
tmp[5 - i] = hex.charAt(c & 0xF);
|
||||
c = (char) (c >> 4);
|
||||
}
|
||||
return String.copyValueOf(tmp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines a true or false value for the given character.
|
||||
*/
|
||||
public abstract boolean matches(char c);
|
||||
|
||||
/**
|
||||
* Returns a matcher that matches any character not matched by this matcher.
|
||||
*/
|
||||
public CharMatcher negate() {
|
||||
return new Negated(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a matcher that matches any character matched by both this matcher and {@code other}.
|
||||
*/
|
||||
public CharMatcher and(CharMatcher other) {
|
||||
return new And(this, other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a matcher that matches any character matched by either this matcher or {@code other}.
|
||||
*/
|
||||
public CharMatcher or(CharMatcher other) {
|
||||
return new Or(this, other);
|
||||
}
|
||||
|
||||
// Abstract methods
|
||||
|
||||
/**
|
||||
* Sets bits in {@code table} matched by this matcher.
|
||||
*/
|
||||
void setBits(BitSet table) {
|
||||
for (int c = Character.MAX_VALUE; c >= Character.MIN_VALUE; c--) {
|
||||
if (matches((char) c)) {
|
||||
table.set(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Non-static factories
|
||||
|
||||
/**
|
||||
* Returns {@code true} if a character sequence contains at least one matching character.
|
||||
* Equivalent to {@code !matchesNoneOf(sequence)}.
|
||||
*
|
||||
* <p>The default implementation iterates over the sequence, invoking {@link #matches} for each
|
||||
* character, until this returns {@code true} or the end is reached.
|
||||
*
|
||||
* @param sequence the character sequence to examine, possibly empty
|
||||
* @return {@code true} if this matcher matches at least one character in the sequence
|
||||
* @since 8.0
|
||||
*/
|
||||
public boolean matchesAnyOf(CharSequence sequence) {
|
||||
return !matchesNoneOf(sequence);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if a character sequence contains only matching characters.
|
||||
*
|
||||
* <p>The default implementation iterates over the sequence, invoking {@link #matches} for each
|
||||
* character, until this returns {@code false} or the end is reached.
|
||||
*
|
||||
* @param sequence the character sequence to examine, possibly empty
|
||||
* @return {@code true} if this matcher matches every character in the sequence, including when
|
||||
* the sequence is empty
|
||||
*/
|
||||
public boolean matchesAllOf(CharSequence sequence) {
|
||||
for (int i = sequence.length() - 1; i >= 0; i--) {
|
||||
if (!matches(sequence.charAt(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if a character sequence contains no matching characters. Equivalent to
|
||||
* {@code !matchesAnyOf(sequence)}.
|
||||
*
|
||||
* <p>The default implementation iterates over the sequence, invoking {@link #matches} for each
|
||||
* character, until this returns {@code true} or the end is reached.
|
||||
*
|
||||
* @param sequence the character sequence to examine, possibly empty
|
||||
* @return {@code true} if this matcher matches no characters in the sequence, including when
|
||||
* the sequence is empty
|
||||
*/
|
||||
public boolean matchesNoneOf(CharSequence sequence) {
|
||||
return indexIn(sequence) == -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the first matching character in a character sequence, or {@code -1} if no
|
||||
* matching character is present.
|
||||
*
|
||||
* <p>The default implementation iterates over the sequence in forward order calling
|
||||
* {@link #matches} for each character.
|
||||
*
|
||||
* @param sequence the character sequence to examine from the beginning
|
||||
* @return an index, or {@code -1} if no character matches
|
||||
*/
|
||||
public int indexIn(CharSequence sequence) {
|
||||
return indexIn(sequence, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the first matching character in a character sequence, starting from a
|
||||
* given position, or {@code -1} if no character matches after that position.
|
||||
*
|
||||
* <p>The default implementation iterates over the sequence in forward order, beginning at {@code
|
||||
* start}, calling {@link #matches} for each character.
|
||||
*
|
||||
* @param sequence the character sequence to examine
|
||||
* @param start the first index to examine; must be nonnegative and no greater than {@code
|
||||
* sequence.length()}
|
||||
* @return the index of the first matching character, guaranteed to be no less than {@code start},
|
||||
* or {@code -1} if no character matches
|
||||
* @throws IndexOutOfBoundsException if start is negative or greater than {@code
|
||||
* sequence.length()}
|
||||
*/
|
||||
public int indexIn(CharSequence sequence, int start) {
|
||||
int length = sequence.length();
|
||||
Preconditions.checkPositionIndex(start, length);
|
||||
for (int i = start; i < length; i++) {
|
||||
if (matches(sequence.charAt(i))) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of matching characters found in a character sequence.
|
||||
*/
|
||||
public int countIn(CharSequence sequence) {
|
||||
int count = 0;
|
||||
for (int i = 0; i < sequence.length(); i++) {
|
||||
if (matches(sequence.charAt(i))) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of {@link #ascii()}.
|
||||
*/
|
||||
private static final class Ascii extends NamedFastMatcher {
|
||||
|
||||
static final Ascii INSTANCE = new Ascii();
|
||||
@@ -60,7 +309,9 @@ abstract class CharMatcher {
|
||||
}
|
||||
}
|
||||
|
||||
/** {@link FastMatcher} which overrides {@code toString()} with a custom name. */
|
||||
/**
|
||||
* {@link FastMatcher} which overrides {@code toString()} with a custom name.
|
||||
*/
|
||||
abstract static class NamedFastMatcher extends FastMatcher {
|
||||
|
||||
private final String description;
|
||||
@@ -75,13 +326,15 @@ abstract class CharMatcher {
|
||||
}
|
||||
}
|
||||
|
||||
/** A matcher for which precomputation will not yield any significant benefit. */
|
||||
/**
|
||||
* A matcher for which precomputation will not yield any significant benefit.
|
||||
*/
|
||||
abstract static class FastMatcher extends CharMatcher {
|
||||
|
||||
// @Override
|
||||
// public final CharMatcher precomputed() {
|
||||
// return this;
|
||||
// }
|
||||
// @Override
|
||||
// public final CharMatcher precomputed() {
|
||||
// return this;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public CharMatcher negate() {
|
||||
@@ -89,20 +342,24 @@ abstract class CharMatcher {
|
||||
}
|
||||
}
|
||||
|
||||
/** Negation of a {@link FastMatcher}. */
|
||||
/**
|
||||
* Negation of a {@link FastMatcher}.
|
||||
*/
|
||||
static class NegatedFastMatcher extends Negated {
|
||||
|
||||
NegatedFastMatcher(CharMatcher original) {
|
||||
super(original);
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public final CharMatcher precomputed() {
|
||||
// return this;
|
||||
// }
|
||||
// @Override
|
||||
// public final CharMatcher precomputed() {
|
||||
// return this;
|
||||
// }
|
||||
}
|
||||
|
||||
/** Implementation of {@link #javaIsoControl()}. */
|
||||
/**
|
||||
* Implementation of {@link #javaIsoControl()}.
|
||||
*/
|
||||
private static final class JavaIsoControl extends NamedFastMatcher {
|
||||
|
||||
static final JavaIsoControl INSTANCE = new JavaIsoControl();
|
||||
@@ -117,8 +374,11 @@ abstract class CharMatcher {
|
||||
}
|
||||
}
|
||||
|
||||
// Text processing routines
|
||||
|
||||
/** Implementation of {@link #negate()}. */
|
||||
/**
|
||||
* Implementation of {@link #negate()}.
|
||||
*/
|
||||
private static class Negated extends CharMatcher {
|
||||
|
||||
final CharMatcher original;
|
||||
@@ -166,8 +426,9 @@ abstract class CharMatcher {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Implementation of {@link #and(CharMatcher)}. */
|
||||
/**
|
||||
* Implementation of {@link #and(CharMatcher)}.
|
||||
*/
|
||||
private static final class And extends CharMatcher {
|
||||
|
||||
final CharMatcher first;
|
||||
@@ -199,7 +460,9 @@ abstract class CharMatcher {
|
||||
}
|
||||
}
|
||||
|
||||
/** Implementation of {@link #or(CharMatcher)}. */
|
||||
/**
|
||||
* Implementation of {@link #or(CharMatcher)}.
|
||||
*/
|
||||
private static final class Or extends CharMatcher {
|
||||
|
||||
final CharMatcher first;
|
||||
@@ -227,7 +490,9 @@ abstract class CharMatcher {
|
||||
}
|
||||
}
|
||||
|
||||
/** Implementation of {@link #isNot(char)}. */
|
||||
/**
|
||||
* Implementation of {@link #isNot(char)}.
|
||||
*/
|
||||
private static final class IsNot extends FastMatcher {
|
||||
|
||||
private final char match;
|
||||
@@ -268,8 +533,9 @@ abstract class CharMatcher {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Implementation of {@link #anyOf(CharSequence)} for three or more characters. */
|
||||
/**
|
||||
* Implementation of {@link #anyOf(CharSequence)} for three or more characters.
|
||||
*/
|
||||
private static final class AnyOf extends CharMatcher {
|
||||
|
||||
private final char[] chars;
|
||||
@@ -302,7 +568,9 @@ abstract class CharMatcher {
|
||||
}
|
||||
}
|
||||
|
||||
/** Implementation of {@link #is(char)}. */
|
||||
/**
|
||||
* Implementation of {@link #is(char)}.
|
||||
*/
|
||||
private static final class Is extends FastMatcher {
|
||||
|
||||
private final char match;
|
||||
@@ -316,10 +584,10 @@ abstract class CharMatcher {
|
||||
return c == match;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public String replaceFrom(CharSequence sequence, char replacement) {
|
||||
// return sequence.toString().replace(match, replacement);
|
||||
// }
|
||||
// @Override
|
||||
// public String replaceFrom(CharSequence sequence, char replacement) {
|
||||
// return sequence.toString().replace(match, replacement);
|
||||
// }
|
||||
|
||||
@Override
|
||||
public CharMatcher and(CharMatcher other) {
|
||||
@@ -347,7 +615,9 @@ abstract class CharMatcher {
|
||||
}
|
||||
}
|
||||
|
||||
/** Implementation of {@link #any()}. */
|
||||
/**
|
||||
* Implementation of {@link #any()}.
|
||||
*/
|
||||
private static final class Any extends NamedFastMatcher {
|
||||
|
||||
static final Any INSTANCE = new Any();
|
||||
@@ -373,10 +643,10 @@ abstract class CharMatcher {
|
||||
return (start == length) ? -1 : start;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public int lastIndexIn(CharSequence sequence) {
|
||||
// return sequence.length() - 1;
|
||||
// }
|
||||
// @Override
|
||||
// public int lastIndexIn(CharSequence sequence) {
|
||||
// return sequence.length() - 1;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public boolean matchesAllOf(CharSequence sequence) {
|
||||
@@ -389,38 +659,38 @@ abstract class CharMatcher {
|
||||
return sequence.length() == 0;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public String removeFrom(CharSequence sequence) {
|
||||
// Objects.requireNonNull(sequence);
|
||||
// return "";
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String replaceFrom(CharSequence sequence, char replacement) {
|
||||
// char[] array = new char[sequence.length()];
|
||||
// Arrays.fill(array, replacement);
|
||||
// return new String(array);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String replaceFrom(CharSequence sequence, CharSequence replacement) {
|
||||
// StringBuilder result = new StringBuilder(sequence.length() * replacement.length());
|
||||
// for (int i = 0; i < sequence.length(); i++) {
|
||||
// result.append(replacement);
|
||||
// }
|
||||
// return result.toString();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String collapseFrom(CharSequence sequence, char replacement) {
|
||||
// return (sequence.length() == 0) ? "" : String.valueOf(replacement);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String trimFrom(CharSequence sequence) {
|
||||
// Objects.requireNonNull(sequence);
|
||||
// return "";
|
||||
// }
|
||||
// @Override
|
||||
// public String removeFrom(CharSequence sequence) {
|
||||
// Objects.requireNonNull(sequence);
|
||||
// return "";
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String replaceFrom(CharSequence sequence, char replacement) {
|
||||
// char[] array = new char[sequence.length()];
|
||||
// Arrays.fill(array, replacement);
|
||||
// return new String(array);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String replaceFrom(CharSequence sequence, CharSequence replacement) {
|
||||
// StringBuilder result = new StringBuilder(sequence.length() * replacement.length());
|
||||
// for (int i = 0; i < sequence.length(); i++) {
|
||||
// result.append(replacement);
|
||||
// }
|
||||
// return result.toString();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String collapseFrom(CharSequence sequence, char replacement) {
|
||||
// return (sequence.length() == 0) ? "" : String.valueOf(replacement);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String trimFrom(CharSequence sequence) {
|
||||
// Objects.requireNonNull(sequence);
|
||||
// return "";
|
||||
// }
|
||||
|
||||
@Override
|
||||
public int countIn(CharSequence sequence) {
|
||||
@@ -444,8 +714,9 @@ abstract class CharMatcher {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Implementation of {@link #none()}. */
|
||||
/**
|
||||
* Implementation of {@link #none()}.
|
||||
*/
|
||||
private static final class None extends NamedFastMatcher {
|
||||
|
||||
static final None INSTANCE = new None();
|
||||
@@ -472,11 +743,11 @@ abstract class CharMatcher {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public int lastIndexIn(CharSequence sequence) {
|
||||
// Objects.requireNonNull(sequence);
|
||||
// return -1;
|
||||
// }
|
||||
// @Override
|
||||
// public int lastIndexIn(CharSequence sequence) {
|
||||
// Objects.requireNonNull(sequence);
|
||||
// return -1;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public boolean matchesAllOf(CharSequence sequence) {
|
||||
@@ -489,41 +760,41 @@ abstract class CharMatcher {
|
||||
return true;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public String removeFrom(CharSequence sequence) {
|
||||
// return sequence.toString();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String replaceFrom(CharSequence sequence, char replacement) {
|
||||
// return sequence.toString();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String replaceFrom(CharSequence sequence, CharSequence replacement) {
|
||||
// Objects.requireNonNull(replacement);
|
||||
// return sequence.toString();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String collapseFrom(CharSequence sequence, char replacement) {
|
||||
// return sequence.toString();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String trimFrom(CharSequence sequence) {
|
||||
// return sequence.toString();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String trimLeadingFrom(CharSequence sequence) {
|
||||
// return sequence.toString();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String trimTrailingFrom(CharSequence sequence) {
|
||||
// return sequence.toString();
|
||||
// }
|
||||
// @Override
|
||||
// public String removeFrom(CharSequence sequence) {
|
||||
// return sequence.toString();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String replaceFrom(CharSequence sequence, char replacement) {
|
||||
// return sequence.toString();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String replaceFrom(CharSequence sequence, CharSequence replacement) {
|
||||
// Objects.requireNonNull(replacement);
|
||||
// return sequence.toString();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String collapseFrom(CharSequence sequence, char replacement) {
|
||||
// return sequence.toString();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String trimFrom(CharSequence sequence) {
|
||||
// return sequence.toString();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String trimLeadingFrom(CharSequence sequence) {
|
||||
// return sequence.toString();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String trimTrailingFrom(CharSequence sequence) {
|
||||
// return sequence.toString();
|
||||
// }
|
||||
|
||||
@Override
|
||||
public int countIn(CharSequence sequence) {
|
||||
@@ -549,100 +820,8 @@ abstract class CharMatcher {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a character is ASCII, meaning that its code point is less than 128.
|
||||
*
|
||||
* @since 19.0 (since 1.0 as constant {@code ASCII})
|
||||
* Implementation of {@link #anyOf(CharSequence)} for exactly two characters.
|
||||
*/
|
||||
public static CharMatcher ascii() {
|
||||
return Ascii.INSTANCE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for use by subclasses. When subclassing, you may want to override
|
||||
* {@code toString()} to provide a useful description.
|
||||
*/
|
||||
protected CharMatcher() {}
|
||||
|
||||
// Abstract methods
|
||||
|
||||
/** Determines a true or false value for the given character. */
|
||||
public abstract boolean matches(char c);
|
||||
|
||||
// Non-static factories
|
||||
|
||||
/**
|
||||
* Returns a matcher that matches any character not matched by this matcher.
|
||||
*/
|
||||
public CharMatcher negate() {
|
||||
return new Negated(this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a matcher that matches any character matched by both this matcher and {@code other}.
|
||||
*/
|
||||
public CharMatcher and(CharMatcher other) {
|
||||
return new And(this, other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a matcher that matches any character matched by either this matcher or {@code other}.
|
||||
*/
|
||||
public CharMatcher or(CharMatcher other) {
|
||||
return new Or(this, other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code char} matcher that matches any character except the one specified.
|
||||
*
|
||||
* <p>To negate another {@code CharMatcher}, use {@link #negate()}.
|
||||
*/
|
||||
public static CharMatcher isNot(final char match) {
|
||||
return new IsNot(match);
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches any character.
|
||||
*
|
||||
* @since 19.0 (since 1.0 as constant {@code ANY})
|
||||
*/
|
||||
public static CharMatcher any() {
|
||||
return Any.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches no characters.
|
||||
*
|
||||
* @since 19.0 (since 1.0 as constant {@code NONE})
|
||||
*/
|
||||
public static CharMatcher none() {
|
||||
return None.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a character is an ISO control character as specified by
|
||||
* {@link Character#isISOControl(char)}.
|
||||
*
|
||||
* @since 19.0 (since 1.0 as constant {@code JAVA_ISO_CONTROL})
|
||||
*/
|
||||
public static CharMatcher javaIsoControl() {
|
||||
return JavaIsoControl.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code char} matcher that matches only one specified character.
|
||||
*/
|
||||
public static CharMatcher is(final char match) {
|
||||
return new Is(match);
|
||||
}
|
||||
|
||||
|
||||
private static CharMatcher.IsEither isEither(char c1, char c2) {
|
||||
return new CharMatcher.IsEither(c1, c2);
|
||||
}
|
||||
|
||||
/** Implementation of {@link #anyOf(CharSequence)} for exactly two characters. */
|
||||
private static final class IsEither extends FastMatcher {
|
||||
|
||||
private final char match1;
|
||||
@@ -669,167 +848,4 @@ abstract class CharMatcher {
|
||||
return "CharMatcher.anyOf(\"" + showCharacter(match1) + showCharacter(match2) + "\")";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets bits in {@code table} matched by this matcher.
|
||||
*/
|
||||
void setBits(BitSet table) {
|
||||
for (int c = Character.MAX_VALUE; c >= Character.MIN_VALUE; c--) {
|
||||
if (matches((char) c)) {
|
||||
table.set(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Text processing routines
|
||||
|
||||
/**
|
||||
* Returns {@code true} if a character sequence contains at least one matching character.
|
||||
* Equivalent to {@code !matchesNoneOf(sequence)}.
|
||||
*
|
||||
* <p>The default implementation iterates over the sequence, invoking {@link #matches} for each
|
||||
* character, until this returns {@code true} or the end is reached.
|
||||
*
|
||||
* @param sequence the character sequence to examine, possibly empty
|
||||
* @return {@code true} if this matcher matches at least one character in the sequence
|
||||
* @since 8.0
|
||||
*/
|
||||
public boolean matchesAnyOf(CharSequence sequence) {
|
||||
return !matchesNoneOf(sequence);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if a character sequence contains only matching characters.
|
||||
*
|
||||
* <p>The default implementation iterates over the sequence, invoking {@link #matches} for each
|
||||
* character, until this returns {@code false} or the end is reached.
|
||||
*
|
||||
* @param sequence the character sequence to examine, possibly empty
|
||||
* @return {@code true} if this matcher matches every character in the sequence, including when
|
||||
* the sequence is empty
|
||||
*/
|
||||
public boolean matchesAllOf(CharSequence sequence) {
|
||||
for (int i = sequence.length() - 1; i >= 0; i--) {
|
||||
if (!matches(sequence.charAt(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if a character sequence contains no matching characters. Equivalent to
|
||||
* {@code !matchesAnyOf(sequence)}.
|
||||
*
|
||||
* <p>The default implementation iterates over the sequence, invoking {@link #matches} for each
|
||||
* character, until this returns {@code true} or the end is reached.
|
||||
*
|
||||
* @param sequence the character sequence to examine, possibly empty
|
||||
* @return {@code true} if this matcher matches no characters in the sequence, including when
|
||||
* the sequence is empty
|
||||
*/
|
||||
public boolean matchesNoneOf(CharSequence sequence) {
|
||||
return indexIn(sequence) == -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code char} matcher that matches any character not present in the given character
|
||||
* sequence.
|
||||
*/
|
||||
public static CharMatcher noneOf(CharSequence sequence) {
|
||||
return anyOf(sequence).negate();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a {@code char} matcher that matches any character present in the given character
|
||||
* sequence.
|
||||
*/
|
||||
public static CharMatcher anyOf(final CharSequence sequence) {
|
||||
switch (sequence.length()) {
|
||||
case 0:
|
||||
return none();
|
||||
case 1:
|
||||
return is(sequence.charAt(0));
|
||||
case 2:
|
||||
return isEither(sequence.charAt(0), sequence.charAt(1));
|
||||
default:
|
||||
// TODO(lowasser): is it potentially worth just going ahead and building a precomputed
|
||||
// matcher?
|
||||
return new AnyOf(sequence);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the index of the first matching character in a character sequence, or {@code -1} if no
|
||||
* matching character is present.
|
||||
*
|
||||
* <p>The default implementation iterates over the sequence in forward order calling
|
||||
* {@link #matches} for each character.
|
||||
*
|
||||
* @param sequence the character sequence to examine from the beginning
|
||||
* @return an index, or {@code -1} if no character matches
|
||||
*/
|
||||
public int indexIn(CharSequence sequence) {
|
||||
return indexIn(sequence, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the first matching character in a character sequence, starting from a
|
||||
* given position, or {@code -1} if no character matches after that position.
|
||||
*
|
||||
* <p>The default implementation iterates over the sequence in forward order, beginning at {@code
|
||||
* start}, calling {@link #matches} for each character.
|
||||
*
|
||||
* @param sequence the character sequence to examine
|
||||
* @param start the first index to examine; must be nonnegative and no greater than {@code
|
||||
* sequence.length()}
|
||||
* @return the index of the first matching character, guaranteed to be no less than {@code start},
|
||||
* or {@code -1} if no character matches
|
||||
* @throws IndexOutOfBoundsException if start is negative or greater than {@code
|
||||
* sequence.length()}
|
||||
*/
|
||||
public int indexIn(CharSequence sequence, int start) {
|
||||
int length = sequence.length();
|
||||
Preconditions.checkPositionIndex(start, length);
|
||||
for (int i = start; i < length; i++) {
|
||||
if (matches(sequence.charAt(i))) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of matching characters found in a character sequence.
|
||||
*/
|
||||
public int countIn(CharSequence sequence) {
|
||||
int count = 0;
|
||||
for (int i = 0; i < sequence.length(); i++) {
|
||||
if (matches(sequence.charAt(i))) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Java Unicode escape sequence for the given character, in the form "\u12AB" where
|
||||
* "12AB" is the four hexadecimal digits representing the 16 bits of the UTF-16 character.
|
||||
*/
|
||||
private static String showCharacter(char c) {
|
||||
String hex = "0123456789ABCDEF";
|
||||
char[] tmp = {'\\', 'u', '\0', '\0', '\0', '\0'};
|
||||
for (int i = 0; i < 4; i++) {
|
||||
tmp[5 - i] = hex.charAt(c & 0xF);
|
||||
c = (char) (c >> 4);
|
||||
}
|
||||
return String.copyValueOf(tmp);
|
||||
}
|
||||
}
|
||||
128
common/http/src/main/java/io/helidon/common/http/Content.java
Normal file
128
common/http/src/main/java/io/helidon/common/http/Content.java
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package io.helidon.common.http;
|
||||
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import io.helidon.common.reactive.Flow;
|
||||
|
||||
/**
|
||||
* Represents an HTTP entity as a {@link Flow.Publisher publisher} of {@link DataChunk chunks} with specific
|
||||
* features.
|
||||
* <h3>Default publisher contract</h3>
|
||||
* Default publisher accepts only single subscriber. Other subscribers receives
|
||||
* {@link Flow.Subscriber#onError(Throwable) onError()}.
|
||||
* <p>
|
||||
* {@link DataChunk} provided by {@link Flow.Subscriber#onNext(Object) onNext()} method <b>must</b> be consumed in this
|
||||
* method call. Buffer can be reused by network infrastructure as soon as {@code onNext()} method returns.
|
||||
* This behavior can be inconvenient yet it helps to provide excellent performance.
|
||||
*
|
||||
* <h3>Publisher Overwrite.</h3>
|
||||
* It is possible to modify contract of the original publisher by registration of a new publisher using
|
||||
* {@link #registerFilter(Function)} method. It can be used to wrap or replace previously registered (or default) publisher.
|
||||
*
|
||||
* <h3>Entity Readers</h3>
|
||||
* It is possible to register function to convert publisher to {@link CompletionStage} of a single entity using
|
||||
* {@link #registerReader(Class, Reader)} or {@link #registerReader(Predicate, Reader)} methods. It
|
||||
* is then possible to use {@link #as(Class)} method to obtain such entity.
|
||||
*/
|
||||
public interface Content extends Flow.Publisher<DataChunk> {
|
||||
/**
|
||||
* If possible, adds the given Subscriber to this publisher. This publisher is effectively
|
||||
* either the original publisher
|
||||
* or the last publisher registered by the method {@link #registerFilter(Function)}.
|
||||
* <p>
|
||||
* Note that the original publisher allows only a single subscriber and requires the passed
|
||||
* {@link DataChunk} in the {@link Flow.Subscriber#onNext(Object)} call
|
||||
* to be consumed before the method completes as specified by the {@link Content Default Publisher Contract}.
|
||||
*
|
||||
* @param subscriber the subscriber
|
||||
* @throws NullPointerException if subscriber is null
|
||||
*/
|
||||
@Override
|
||||
void subscribe(Flow.Subscriber<? super DataChunk> subscriber);
|
||||
|
||||
/**
|
||||
* Registers a filter that allows a control of the original publisher.
|
||||
* <p>
|
||||
* The provided function is evaluated upon calling either of {@link #subscribe(Flow.Subscriber)}
|
||||
* or {@link #as(Class)}.
|
||||
* The first evaluation of the function transforms the original publisher to a new publisher.
|
||||
* Any subsequent evaluation receives the publisher transformed by the last previously
|
||||
* registered filter.
|
||||
* It is up to the implementor of the given function to respect the contract of both the original
|
||||
* publisher and the previously registered ones.
|
||||
*
|
||||
* @param function a function that transforms a given publisher (that is either the original
|
||||
* publisher or the publisher transformed by the last previously registered filter).
|
||||
*/
|
||||
void registerFilter(Function<Flow.Publisher<DataChunk>, Flow.Publisher<DataChunk>> function);
|
||||
|
||||
/**
|
||||
* Registers a reader for a later use with an appropriate {@link #as(Class)} method call.
|
||||
* <p>
|
||||
* The reader must transform the published byte buffers into a completion stage of the
|
||||
* requested type.
|
||||
* <p>
|
||||
* Upon calling {@link #as(Class)} a matching reader is searched in the same order as the
|
||||
* readers were registered. If no matching reader is found, or when the function throws
|
||||
* an exception, the resulting completion stage ends exceptionally.
|
||||
*
|
||||
* @param type the requested type the completion stage is be associated with.
|
||||
* @param reader the reader as a function that transforms a publisher into completion stage.
|
||||
* If an exception is thrown, the resulting completion stage of
|
||||
* {@link #as(Class)} method call ends exceptionally.
|
||||
* @param <T> the requested type
|
||||
*/
|
||||
<T> void registerReader(Class<T> type, Reader<T> reader);
|
||||
|
||||
/**
|
||||
* Registers a reader for a later use with an appropriate {@link #as(Class)} method call.
|
||||
* <p>
|
||||
* The reader must transform the published byte buffers into a completion stage of the
|
||||
* requested type.
|
||||
* <p>
|
||||
* Upon calling {@link #as(Class)} a matching reader is searched in the same order as the
|
||||
* readers were registered. If no matching reader is found or when the predicate throws
|
||||
* an exception, or when the function throws an exception, the resulting completion stage
|
||||
* ends exceptionally.
|
||||
*
|
||||
* @param predicate the predicate that determines whether the registered reader can handle
|
||||
* the requested type. If an exception is thrown, the resulting completion
|
||||
* stage of {@link #as(Class)} method call ends exceptionally.
|
||||
* @param reader the reader as a function that transforms a publisher into completion stage.
|
||||
* If an exception is thrown, the resulting completion stage of
|
||||
* {@link #as(Class)} method call ends exceptionally.
|
||||
* @param <T> the requested type
|
||||
*/
|
||||
<T> void registerReader(Predicate<Class<?>> predicate, Reader<T> reader);
|
||||
|
||||
/**
|
||||
* Consumes and converts the request content into a completion stage of the requested type.
|
||||
* <p>
|
||||
* The conversion requires an appropriate reader to be already registered
|
||||
* (see {@link #registerReader(Predicate, Reader)}). If no such reader is found, the
|
||||
* resulting completion stage ends exceptionally.
|
||||
*
|
||||
* @param type the requested type class
|
||||
* @param <T> the requested type
|
||||
* @return a completion stage of the requested type
|
||||
*/
|
||||
<T> CompletionStage<T> as(Class<T> type);
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.helidon.webserver;
|
||||
package io.helidon.common.http;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
@@ -22,12 +22,12 @@ import java.util.function.Supplier;
|
||||
/**
|
||||
* A registry for context objects. Enables instance localization between several <i>services / components / ...</i> integrated in
|
||||
* a particular known scope. ContextualRegistry instance is intended to be associated with a scope aware object such as
|
||||
* {@link WebServer} or {@link ServerRequest}.
|
||||
* WebServer, ServerRequest or ClientRequest.
|
||||
*
|
||||
* <p>Context contains also a notion of <i>classifiers</i>. Classifier is any object defining additional <i>key</i> for registered
|
||||
* objects. To obtain such registered object, the same classifier (precisely, any equal object) has to be used.
|
||||
*
|
||||
* <p>Classifiers can be used as folows:<ol>
|
||||
* <p>Classifiers can be used as follows:<ol>
|
||||
* <li>As an additional identifier for registered objects of common types, like a {@link String}, ...<br>
|
||||
* <pre>{@code
|
||||
* // User detail provider service
|
||||
@@ -49,6 +49,27 @@ import java.util.function.Supplier;
|
||||
*/
|
||||
public interface ContextualRegistry {
|
||||
|
||||
/**
|
||||
* Creates a new empty instance.
|
||||
*
|
||||
* @return new instance
|
||||
*/
|
||||
static ContextualRegistry create() {
|
||||
return new ListContextualRegistry();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new empty instance backed by its parent read-through {@link ContextualRegistry}.
|
||||
*
|
||||
* <p>Parent {@code registry} is used only for get methods and only if this registry doesn't have registered required type.
|
||||
*
|
||||
* @param parent a parent registry
|
||||
* @return new instance
|
||||
*/
|
||||
static ContextualRegistry create(ContextualRegistry parent) {
|
||||
return new ListContextualRegistry(parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new instance.
|
||||
*
|
||||
@@ -96,7 +117,8 @@ public interface ContextualRegistry {
|
||||
|
||||
/**
|
||||
* Registers a new instance using a provided supplier. The supplier is guarantied to be called at most once when it's
|
||||
* requested by the {@link #get(Object, Class)} method. The returned value gets registered and the supplier is never called again.
|
||||
* requested by the {@link #get(Object, Class)} method. The returned value gets registered and the supplier is never called
|
||||
* again.
|
||||
*
|
||||
* <p>Registered instance can be obtained only using {@link #get(Object, Class)} method with a {@code classifier} equal with
|
||||
* the one used during registration.
|
||||
@@ -122,25 +144,4 @@ public interface ContextualRegistry {
|
||||
* @throws NullPointerException If {@code classifier} is null.
|
||||
*/
|
||||
<T> Optional<T> get(Object classifier, Class<T> type);
|
||||
|
||||
/**
|
||||
* Creates a new empty instance.
|
||||
*
|
||||
* @return new instance
|
||||
*/
|
||||
static ContextualRegistry create() {
|
||||
return new ListContextualRegistry();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new empty instance backed by its parent read-through {@link ContextualRegistry}.
|
||||
*
|
||||
* <p>Parent {@code registry} is used only for get methods and only if this registry doesn't have registered required type.
|
||||
*
|
||||
* @param parent a parent registry
|
||||
* @return new instance
|
||||
*/
|
||||
static ContextualRegistry create(ContextualRegistry parent) {
|
||||
return new ListContextualRegistry(parent);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,16 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.helidon.webserver;
|
||||
package io.helidon.common.http;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* The RequestChunk represents a part of the HTTP request body content.
|
||||
* The DataChunk represents a part of the HTTP body content.
|
||||
* <p>
|
||||
* The ReqeustChunk and the content it carries stay immutable as long as method
|
||||
* The DataChunk and the content it carries stay immutable as long as method
|
||||
* {@link #release()} is not called. After that, the given instance and the associated
|
||||
* data structure instances (e.g., the {@link ByteBuffer} obtained by {@link #data()})
|
||||
* should not be used. The idea behind this class is to be able to
|
||||
@@ -34,36 +32,76 @@ import java.nio.ByteBuffer;
|
||||
* the methods of this class (such as {@link #data()}, {@link #release()} from different
|
||||
* threads may result in a race condition unless an external synchronization is used.
|
||||
*/
|
||||
public interface RequestChunk {
|
||||
@FunctionalInterface
|
||||
public interface DataChunk {
|
||||
/**
|
||||
* Creates a simple {@link ByteBuffer} backed data chunk. The resulting
|
||||
* instance doesn't have any kind of a lifecycle and as such, it doesn't need
|
||||
* to be released.
|
||||
*
|
||||
* @param byteBuffer a byte buffer to create the request chunk from
|
||||
* @return a request chunk
|
||||
*/
|
||||
static DataChunk create(ByteBuffer byteBuffer) {
|
||||
return create(false, byteBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the content of the underlying {@link ByteBuffer} as an array of bytes.
|
||||
* If the the ByteBuffer was read, the returned array contains only the part of
|
||||
* data that wasn't read yet. On the other hand, calling this method doesn't cause
|
||||
* the underlying {@link ByteBuffer} to be read.
|
||||
* <p>
|
||||
* It is expected the returned byte array holds a reference to data that
|
||||
* will become stale upon calling method {@link #release()}. (For instance,
|
||||
* the memory segment is pooled by the underlying TCP server and is reused
|
||||
* for a subsequent request chunk.) The idea behind this class is to be able to
|
||||
* minimize data copying; ideally, in order to achieve the best performance,
|
||||
* to not copy them at all. However, the implementations may choose otherwise.
|
||||
* <p>
|
||||
* Note that the methods of this instance are expected to be called by a single
|
||||
* thread; if not, external synchronization must be used.
|
||||
* Creates a simple byte array backed data chunk. The resulting
|
||||
* instance doesn't have any kind of a lifecycle and as such, it doesn't need
|
||||
* to be released.
|
||||
*
|
||||
* @return an array of bytes that is guarantied to stay immutable as long as
|
||||
* method {@link #release()} is not called
|
||||
* @param bytes a byte array to create the request chunk from
|
||||
* @return a request chunk
|
||||
*/
|
||||
default byte[] bytes() {
|
||||
try {
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
Utils.write(data().asReadOnlyBuffer(), stream);
|
||||
return stream.toByteArray();
|
||||
} catch (IOException e) {
|
||||
// never happens with ByteArrayOutputStream
|
||||
throw new AssertionError("ByteArrayOutputStream is not expected to throw an IO Exception.", e);
|
||||
}
|
||||
static DataChunk create(byte[] bytes) {
|
||||
return create(false, ByteBuffer.wrap(bytes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a reusable data chunk.
|
||||
*
|
||||
* @param flush a signal that chunk should be written and flushed from any cache if possible
|
||||
* @param data a data chunk. Should not be reused until {@code releaseCallback} is used
|
||||
* @return a reusable data chunk with no release callback
|
||||
*/
|
||||
static DataChunk create(boolean flush, ByteBuffer data) {
|
||||
return create(flush, data, Utils.EMPTY_RUNNABLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a reusable data chunk.
|
||||
*
|
||||
* @param flush a signal that chunk should be written and flushed from any cache if possible
|
||||
* @param data a data chunk. Should not be reused until {@code releaseCallback} is used
|
||||
* @param releaseCallback a callback which is called when this chunk is completely processed and instance is free for reuse
|
||||
* @return a reusable data chunk with a release callback
|
||||
*/
|
||||
static DataChunk create(boolean flush, ByteBuffer data, Runnable releaseCallback) {
|
||||
return new DataChunk() {
|
||||
private boolean isReleased = false;
|
||||
|
||||
@Override
|
||||
public ByteBuffer data() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean flush() {
|
||||
return flush;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
releaseCallback.run();
|
||||
isReleased = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReleased() {
|
||||
return isReleased;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,6 +125,38 @@ public interface RequestChunk {
|
||||
*/
|
||||
ByteBuffer data();
|
||||
|
||||
/**
|
||||
* The tracing ID of this chunk.
|
||||
*
|
||||
* @return the tracing ID of this chunk
|
||||
*/
|
||||
default long id() {
|
||||
return System.identityHashCode(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the content of the underlying {@link ByteBuffer} as an array of bytes.
|
||||
* If the the ByteBuffer was read, the returned array contains only the part of
|
||||
* data that wasn't read yet. On the other hand, calling this method doesn't cause
|
||||
* the underlying {@link ByteBuffer} to be read.
|
||||
* <p>
|
||||
* It is expected the returned byte array holds a reference to data that
|
||||
* will become stale upon calling method {@link #release()}. (For instance,
|
||||
* the memory segment is pooled by the underlying TCP server and is reused
|
||||
* for a subsequent request chunk.) The idea behind this class is to be able to
|
||||
* minimize data copying; ideally, in order to achieve the best performance,
|
||||
* to not copy them at all. However, the implementations may choose otherwise.
|
||||
* <p>
|
||||
* Note that the methods of this instance are expected to be called by a single
|
||||
* thread; if not, external synchronization must be used.
|
||||
*
|
||||
* @return an array of bytes that is guarantied to stay immutable as long as
|
||||
* method {@link #release()} is not called
|
||||
*/
|
||||
default byte[] bytes() {
|
||||
return Utils.toByteArray(data().asReadOnlyBuffer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this chunk is released and the associated data structures returned
|
||||
* by methods (such as {@link #data()} or {@link #bytes()}) should not be used.
|
||||
@@ -96,9 +166,11 @@ public interface RequestChunk {
|
||||
* Note that the methods of this instance are expected to be called by a single
|
||||
* thread; if not, external synchronization must be used.
|
||||
*
|
||||
* @return whether this chunk has been released
|
||||
* @return whether this chunk has been released, defaults to false
|
||||
*/
|
||||
boolean isReleased();
|
||||
default boolean isReleased() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases this chunk. The underlying data as well as the data structure instances returned by
|
||||
@@ -109,38 +181,17 @@ public interface RequestChunk {
|
||||
* Note that the methods of this instance are expected to be called by a single
|
||||
* thread; if not, external synchronization must be used.
|
||||
*/
|
||||
void release();
|
||||
|
||||
/**
|
||||
* The tracing ID of this chunk.
|
||||
*
|
||||
* @return the tracing ID of this chunk
|
||||
*/
|
||||
default long id() {
|
||||
return System.identityHashCode(this);
|
||||
default void release() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a simple {@link ByteBuffer} backed request chunk. The resulting
|
||||
* instance doesn't have any kind of a lifecycle and as such, it doesn't need
|
||||
* to be released.
|
||||
* Returns {@code true} if all caches are requested to flush when this chunk is written.
|
||||
* This method is only meaningful when handing data over to
|
||||
* Helidon APIs (e.g. for server response and client requests).
|
||||
*
|
||||
* @param byteBuffer a byte buffer to create the request chunk from
|
||||
* @return a request chunk
|
||||
* @return {@code true} if it is requested to flush all caches after this chunk is written, defaults to {@code false}.
|
||||
*/
|
||||
static RequestChunk from(ByteBuffer byteBuffer) {
|
||||
return new ByteBufferRequestChunk(byteBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a simple byte array backed request chunk. The resulting
|
||||
* instance doesn't have any kind of a lifecycle and as such, it doesn't need
|
||||
* to be released.
|
||||
*
|
||||
* @param bytes a byte array to create the request chunk from
|
||||
* @return a request chunk
|
||||
*/
|
||||
static RequestChunk from(byte[] bytes) {
|
||||
return new ByteBufferRequestChunk(ByteBuffer.wrap(bytes));
|
||||
default boolean flush() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.helidon.webserver;
|
||||
package io.helidon.common.http;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@@ -22,9 +22,6 @@ import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Extends {@link Parameters} interface by adding methods convenient for HTTP headers.
|
||||
*
|
||||
* @see RequestHeaders
|
||||
* @see ResponseHeaders
|
||||
*/
|
||||
public interface Headers extends Parameters {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package io.helidon.common.http;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Common attributes of an HTTP Request, that are used both in server requests and in client requests.
|
||||
*/
|
||||
public interface HttpRequest {
|
||||
/**
|
||||
* Returns an HTTP request method. See also {@link Http.Method HTTP standard methods} utility class.
|
||||
*
|
||||
* @return an HTTP method
|
||||
* @see Http.Method
|
||||
*/
|
||||
Http.RequestMethod method();
|
||||
|
||||
/**
|
||||
* Returns an HTTP version from the request line.
|
||||
* <p>
|
||||
* See {@link Http.Version HTTP Version} enumeration for supported versions.
|
||||
* <p>
|
||||
* If communication starts as a {@code HTTP/1.1} with {@code h2c} upgrade, then it will be automatically
|
||||
* upgraded and this method returns {@code HTTP/2.0}.
|
||||
*
|
||||
* @return an HTTP version
|
||||
*/
|
||||
Http.Version version();
|
||||
|
||||
/**
|
||||
* Returns a Request-URI (or alternatively path) as defined in request line.
|
||||
*
|
||||
* @return a request URI
|
||||
*/
|
||||
URI uri();
|
||||
|
||||
/**
|
||||
* Returns an encoded query string without leading '?' character.
|
||||
*
|
||||
* @return an encoded query string
|
||||
*/
|
||||
String query();
|
||||
|
||||
/**
|
||||
* Returns query parameters.
|
||||
*
|
||||
* @return an parameters representing query parameters
|
||||
*/
|
||||
Parameters queryParams();
|
||||
|
||||
/**
|
||||
* Returns a path which was accepted by matcher in actual routing. It is path without a context root
|
||||
* of the routing.
|
||||
* <p>
|
||||
* Use {@link Path#absolute()} method to obtain absolute request URI path representation.
|
||||
* <p>
|
||||
* Returned {@link Path} also provide access to path template parameters. An absolute path then provides access to
|
||||
* all (including) context parameters if any. In case of conflict between parameter names, most recent value is returned.
|
||||
*
|
||||
* @return a path
|
||||
*/
|
||||
Path path();
|
||||
|
||||
/**
|
||||
* Returns a decoded request URI fragment without leading hash '#' character.
|
||||
*
|
||||
* @return a decoded URI fragment
|
||||
*/
|
||||
String fragment();
|
||||
|
||||
/**
|
||||
* Represents requested normalised URI path.
|
||||
*/
|
||||
interface Path {
|
||||
|
||||
/**
|
||||
* Returns value of single parameter resolved from path pattern.
|
||||
*
|
||||
* @param name a parameter name
|
||||
* @return a parameter value or {@code null} if not exist
|
||||
*/
|
||||
String param(String name);
|
||||
|
||||
/**
|
||||
* Returns path as a list of its segments.
|
||||
*
|
||||
* @return a list of path segments
|
||||
*/
|
||||
List<String> segments();
|
||||
|
||||
/**
|
||||
* Returns a path string representation with leading slash.
|
||||
*
|
||||
* @return a path
|
||||
*/
|
||||
String toString();
|
||||
|
||||
/**
|
||||
* If the instance represents a path relative to some context root then returns absolute requested path otherwise
|
||||
* returns this instance.
|
||||
* <p>
|
||||
* The absolute path also contains access to path parameters defined in context matchers. If there is
|
||||
* name conflict then value represents latest matcher result.
|
||||
*
|
||||
* @return an absolute requested URI path
|
||||
*/
|
||||
Path absolute();
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.helidon.webserver;
|
||||
package io.helidon.common.http;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -109,6 +109,12 @@ class ListContextualRegistry implements ContextualRegistry {
|
||||
}
|
||||
}
|
||||
|
||||
private interface RegisteredItem<T> {
|
||||
T get();
|
||||
|
||||
Class<T> getType();
|
||||
}
|
||||
|
||||
private static class ClassifiedRegistry {
|
||||
private final ReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
private final List<RegisteredItem> content = new ArrayList<>();
|
||||
@@ -162,11 +168,6 @@ class ListContextualRegistry implements ContextualRegistry {
|
||||
}
|
||||
}
|
||||
|
||||
private interface RegisteredItem<T> {
|
||||
T get();
|
||||
Class<T> getType();
|
||||
}
|
||||
|
||||
private static class RegisteredSupplier<T> implements RegisteredItem<T> {
|
||||
private final Class<T> type;
|
||||
private final Supplier<T> supplier;
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.helidon.webserver;
|
||||
package io.helidon.common.http;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@@ -31,118 +31,98 @@ import java.util.function.Supplier;
|
||||
* @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7">HTTP/1.1 section 3.7</a>
|
||||
*/
|
||||
public class MediaType implements AcceptPredicate<MediaType> {
|
||||
// must be first, as this is used to create instances of media types
|
||||
private static final Map<MediaType, MediaType> KNOWN_TYPES = new HashMap<>();
|
||||
|
||||
/**
|
||||
* The media type {@value CHARSET_PARAMETER} parameter name.
|
||||
*/
|
||||
public static final String CHARSET_PARAMETER = "charset";
|
||||
|
||||
private static final Map<MediaType, MediaType> KNOWN_TYPES = new HashMap<>();
|
||||
|
||||
private static MediaType createMediaType() {
|
||||
MediaType mediaType = new MediaType();
|
||||
KNOWN_TYPES.put(mediaType, mediaType);
|
||||
return mediaType;
|
||||
}
|
||||
|
||||
private static MediaType createMediaType(String type, String subtype) {
|
||||
MediaType mediaType = new MediaType(type, subtype);
|
||||
KNOWN_TYPES.put(mediaType, mediaType);
|
||||
return mediaType;
|
||||
}
|
||||
|
||||
// Common media type constants
|
||||
|
||||
/**
|
||||
* A {@link MediaType} constant representing wildcard media type.
|
||||
*/
|
||||
public static final MediaType WILDCARD = createMediaType();
|
||||
|
||||
// Common media type constants
|
||||
/**
|
||||
* A {@link MediaType} constant representing {@code application/xml} media type.
|
||||
*/
|
||||
public static final MediaType APPLICATION_XML = createMediaType("application", "xml");
|
||||
|
||||
/**
|
||||
* A {@link MediaType} constant representing {@code application/atom+xml} media type.
|
||||
*/
|
||||
public static final MediaType APPLICATION_ATOM_XML = createMediaType("application", "atom+xml");
|
||||
|
||||
/**
|
||||
* A {@link MediaType} constant representing {@code application/xhtml+xml} media type.
|
||||
*/
|
||||
public static final MediaType APPLICATION_XHTML_XML = createMediaType("application", "xhtml+xml");
|
||||
|
||||
/**
|
||||
* A {@link MediaType} constant representing {@code application/svg+xml} media type.
|
||||
*/
|
||||
public static final MediaType APPLICATION_SVG_XML = createMediaType("application", "svg+xml");
|
||||
|
||||
/**
|
||||
* A {@link MediaType} constant representing {@code application/json} media type.
|
||||
*/
|
||||
public static final MediaType APPLICATION_JSON = createMediaType("application", "json");
|
||||
|
||||
/**
|
||||
* A {@link MediaType} constant representing {@code application/x-www-form-urlencoded} media type.
|
||||
*/
|
||||
public static final MediaType APPLICATION_FORM_URLENCODED = createMediaType("application", "x-www-form-urlencoded");
|
||||
|
||||
/**
|
||||
* A {@link MediaType} constant representing {@code multipart/form-data} media type.
|
||||
*/
|
||||
public static final MediaType MULTIPART_FORM_DATA = createMediaType("multipart", "form-data");
|
||||
|
||||
/**
|
||||
* A {@link MediaType} constant representing {@code application/octet-stream} media type.
|
||||
*/
|
||||
public static final MediaType APPLICATION_OCTET_STREAM = createMediaType("application", "octet-stream");
|
||||
|
||||
/**
|
||||
* A {@link MediaType} constant representing {@code text/plain} media type.
|
||||
*/
|
||||
public static final MediaType TEXT_PLAIN = createMediaType("text", "plain");
|
||||
|
||||
/**
|
||||
* A {@link MediaType} constant representing {@code text/xml} media type.
|
||||
*/
|
||||
public static final MediaType TEXT_XML = createMediaType("text", "xml");
|
||||
|
||||
/**
|
||||
* A {@link MediaType} constant representing {@code text/html} media type.
|
||||
*/
|
||||
public static final MediaType TEXT_HTML = createMediaType("text", "html");
|
||||
|
||||
// Common predicates
|
||||
|
||||
private static final MediaType APPLICATION_JAVASCRIPT = createMediaType("application", "javascript");
|
||||
|
||||
// Common predicates
|
||||
/**
|
||||
* Predicate to test if {@link MediaType} is {@code application/xml} or {@code text/xml} or has {@code xml} suffix.
|
||||
*/
|
||||
public static final Predicate<MediaType> XML_PREDICATE = APPLICATION_XML.or(TEXT_XML).or(mt -> mt.hasSuffix("xml"));
|
||||
|
||||
/**
|
||||
* Predicate to test if {@link MediaType} is {@code application/json} or has {@code json} suffix.
|
||||
*/
|
||||
public static final Predicate<MediaType> JSON_PREDICATE = APPLICATION_JSON
|
||||
.or(APPLICATION_JAVASCRIPT)
|
||||
.or(mt -> mt.hasSuffix("json"));
|
||||
|
||||
/**
|
||||
* Predicate to test if {@link MediaType} is {@code application/xml} or {@code text/xml} or has {@code xml} suffix.
|
||||
* Matcher for type, subtype and attributes.
|
||||
*/
|
||||
public static final Predicate<MediaType> XML_PREDICATE = APPLICATION_XML.or(TEXT_XML).or(mt -> mt.hasSuffix("xml"));
|
||||
|
||||
private static final CharMatcher TOKEN_MATCHER =
|
||||
CharMatcher.ascii()
|
||||
.and(CharMatcher.javaIsoControl().negate())
|
||||
.and(CharMatcher.isNot(' '))
|
||||
.and(CharMatcher.noneOf("()<>@,;:\\\"/[]?="));
|
||||
private static final CharMatcher QUOTED_TEXT_MATCHER = CharMatcher.ascii().and(CharMatcher.noneOf("\"\\\r"));
|
||||
/*
|
||||
* This matches the same characters as linear-white-space from RFC 822, but we make no effort to
|
||||
* enforce any particular rules with regards to line folding as stated in the class docs.
|
||||
*/
|
||||
private static final CharMatcher LINEAR_WHITE_SPACE = CharMatcher.anyOf(" \t\r\n");
|
||||
private static final String CHARSET_ATTRIBUTE = "charset";
|
||||
private String type;
|
||||
private String subtype;
|
||||
private Map<String, String> parameters;
|
||||
|
||||
private static TreeMap<String, String> createParametersMap(Map<String, String> initialValues) {
|
||||
final TreeMap<String, String> map = new TreeMap<>(String::compareToIgnoreCase);
|
||||
if (initialValues != null) {
|
||||
for (Map.Entry<String, String> e : initialValues.entrySet()) {
|
||||
map.put(e.getKey().toLowerCase(), e.getValue());
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@code MediaType} with the supplied type, subtype and
|
||||
* parameters.
|
||||
@@ -187,13 +167,13 @@ public class MediaType implements AcceptPredicate<MediaType> {
|
||||
* Consider using the constant {@link #WILDCARD_VALUE} instead.
|
||||
*/
|
||||
public MediaType() {
|
||||
this(WILDCARD_VALUE, WILDCARD_VALUE, null, null);
|
||||
this(AcceptPredicate.WILDCARD_VALUE, AcceptPredicate.WILDCARD_VALUE, null, null);
|
||||
}
|
||||
|
||||
private MediaType(String type, String subtype, String charset, Map<String, String> parameterMap) {
|
||||
|
||||
this.type = type == null ? WILDCARD_VALUE : type;
|
||||
this.subtype = subtype == null ? WILDCARD_VALUE : subtype;
|
||||
this.type = type == null ? AcceptPredicate.WILDCARD_VALUE : type;
|
||||
this.subtype = subtype == null ? AcceptPredicate.WILDCARD_VALUE : subtype;
|
||||
|
||||
if (parameterMap == null) {
|
||||
parameterMap = new TreeMap<>(String::compareToIgnoreCase);
|
||||
@@ -205,120 +185,35 @@ public class MediaType implements AcceptPredicate<MediaType> {
|
||||
this.parameters = Collections.unmodifiableMap(parameterMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for primary type.
|
||||
*
|
||||
* @return value of primary type.
|
||||
*/
|
||||
public String getType() {
|
||||
return this.type;
|
||||
private static MediaType createMediaType() {
|
||||
MediaType mediaType = new MediaType();
|
||||
KNOWN_TYPES.put(mediaType, mediaType);
|
||||
return mediaType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the primary type is a wildcard.
|
||||
*
|
||||
* @return true if the primary type is a wildcard.
|
||||
*/
|
||||
public boolean isWildcardType() {
|
||||
return this.getType().equals(WILDCARD_VALUE);
|
||||
private static MediaType createMediaType(String type, String subtype) {
|
||||
MediaType mediaType = new MediaType(type, subtype);
|
||||
KNOWN_TYPES.put(mediaType, mediaType);
|
||||
return mediaType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for subtype.
|
||||
*
|
||||
* @return value of subtype.
|
||||
*/
|
||||
public String getSubtype() {
|
||||
return this.subtype;
|
||||
private static TreeMap<String, String> createParametersMap(Map<String, String> initialValues) {
|
||||
final TreeMap<String, String> map = new TreeMap<>(String::compareToIgnoreCase);
|
||||
if (initialValues != null) {
|
||||
for (Map.Entry<String, String> e : initialValues.entrySet()) {
|
||||
map.put(e.getKey().toLowerCase(), e.getValue());
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the subtype is a wildcard.
|
||||
*
|
||||
* @return true if the subtype is a wildcard.
|
||||
*/
|
||||
public boolean isWildcardSubtype() {
|
||||
return this.getSubtype().equals(WILDCARD_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for a read-only parameter map. Keys are case-insensitive.
|
||||
*
|
||||
* @return an immutable map of parameters.
|
||||
*/
|
||||
public Map<String, String> getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code MediaType} instance with the same type, subtype and parameters
|
||||
* copied from the original instance and the supplied {@value #CHARSET_PARAMETER} parameter.
|
||||
*
|
||||
* @param charset the {@value #CHARSET_PARAMETER} parameter value. If {@code null} or empty
|
||||
* the {@value #CHARSET_PARAMETER} parameter will not be set or updated.
|
||||
* @return copy of the current {@code MediaType} instance with the {@value #CHARSET_PARAMETER}
|
||||
* parameter set to the supplied value.
|
||||
* @since 2.0
|
||||
*/
|
||||
public MediaType withCharset(String charset) {
|
||||
return new MediaType(this.type, this.subtype, charset, createParametersMap(this.parameters));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets {@link Optional} value of charset parameter.
|
||||
*
|
||||
* @return Charset parameter.
|
||||
*/
|
||||
public Optional<String> getCharset() {
|
||||
return Optional.ofNullable(parameters.get(CHARSET_PARAMETER));
|
||||
}
|
||||
|
||||
@Override
|
||||
public double qualityFactor() {
|
||||
String q = parameters.get(QUALITY_FACTOR_PARAMETER);
|
||||
return q == null ? 1D : Double.valueOf(q);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this media type is compatible with another media type. E.g.
|
||||
* image/* is compatible with image/jpeg, image/png, etc. Media type
|
||||
* parameters are ignored. The function is commutative.
|
||||
*
|
||||
* @param other the media type to compare with.
|
||||
* @return true if the types are compatible, false otherwise.
|
||||
*/
|
||||
// fixme: Bidirectional wildcard compatibility
|
||||
public boolean test(MediaType other) {
|
||||
return other != null && // return false if other is null, else
|
||||
(type.equals(WILDCARD_VALUE)
|
||||
|| other.type.equals(WILDCARD_VALUE)
|
||||
|| (type.equalsIgnoreCase(other.type)
|
||||
&& (subtype.equals(WILDCARD_VALUE) || other.subtype.equals(WILDCARD_VALUE)))
|
||||
|| (type.equalsIgnoreCase(other.type) && this.subtype.equalsIgnoreCase(other.subtype)));
|
||||
}
|
||||
|
||||
/** Matcher for type, subtype and attributes. */
|
||||
private static final CharMatcher TOKEN_MATCHER =
|
||||
CharMatcher.ascii()
|
||||
.and(CharMatcher.javaIsoControl().negate())
|
||||
.and(CharMatcher.isNot(' '))
|
||||
.and(CharMatcher.noneOf("()<>@,;:\\\"/[]?="));
|
||||
private static final CharMatcher QUOTED_TEXT_MATCHER = CharMatcher.ascii().and(CharMatcher.noneOf("\"\\\r"));
|
||||
/*
|
||||
* This matches the same characters as linear-white-space from RFC 822, but we make no effort to
|
||||
* enforce any particular rules with regards to line folding as stated in the class docs.
|
||||
*/
|
||||
private static final CharMatcher LINEAR_WHITE_SPACE = CharMatcher.anyOf(" \t\r\n");
|
||||
|
||||
private static final String CHARSET_ATTRIBUTE = "charset";
|
||||
|
||||
/**
|
||||
* Parses a media type from its string representation.
|
||||
*
|
||||
* @param input the input string representing a media type
|
||||
* @throws IllegalArgumentException if the input is not parsable
|
||||
* @throws NullPointerException if the input is {@code null}
|
||||
* @return parsed {@link MediaType} instance
|
||||
* @throws IllegalArgumentException if the input is not parsable
|
||||
* @throws NullPointerException if the input is {@code null}
|
||||
*/
|
||||
public static MediaType parse(String input) {
|
||||
Objects.requireNonNull(input, "Parameter 'input' is null!");
|
||||
@@ -359,55 +254,6 @@ public class MediaType implements AcceptPredicate<MediaType> {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("checkstyle:VisibilityModifier")
|
||||
private static final class Tokenizer {
|
||||
final String input;
|
||||
int position = 0;
|
||||
|
||||
Tokenizer(String input) {
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
String consumeTokenIfPresent(CharMatcher matcher) {
|
||||
checkState(hasMore(), "No more elements!");
|
||||
int startPosition = position;
|
||||
position = matcher.negate().indexIn(input, startPosition);
|
||||
return hasMore() ? input.substring(startPosition, position) : input.substring(startPosition);
|
||||
}
|
||||
|
||||
String consumeToken(CharMatcher matcher) {
|
||||
int startPosition = position;
|
||||
String token = consumeTokenIfPresent(matcher);
|
||||
checkState(position != startPosition, () ->
|
||||
String.format("Position '%d' should not be '%d'!", position, startPosition));
|
||||
return token;
|
||||
}
|
||||
|
||||
char consumeCharacter(CharMatcher matcher) {
|
||||
checkState(hasMore(), "No more elements!");
|
||||
char c = previewChar();
|
||||
checkState(matcher.matches(c), "Unexpected character matched: " + c);
|
||||
position++;
|
||||
return c;
|
||||
}
|
||||
|
||||
char consumeCharacter(char c) {
|
||||
checkState(hasMore(), "No more elements!");
|
||||
checkState(previewChar() == c, () -> "Unexpected character: " + c);
|
||||
position++;
|
||||
return c;
|
||||
}
|
||||
|
||||
char previewChar() {
|
||||
checkState(hasMore(), "No more elements!");
|
||||
return input.charAt(position);
|
||||
}
|
||||
|
||||
boolean hasMore() {
|
||||
return (position >= 0) && (position < input.length());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the truth of an expression involving the state of the calling instance, but not
|
||||
* involving any parameters to the calling method.
|
||||
@@ -465,6 +311,102 @@ public class MediaType implements AcceptPredicate<MediaType> {
|
||||
return CHARSET_ATTRIBUTE.equals(attribute) ? Ascii.toLowerCase(value) : value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for primary type.
|
||||
*
|
||||
* @return value of primary type.
|
||||
*/
|
||||
public String getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the primary type is a wildcard.
|
||||
*
|
||||
* @return true if the primary type is a wildcard.
|
||||
*/
|
||||
public boolean isWildcardType() {
|
||||
return this.getType().equals(AcceptPredicate.WILDCARD_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for subtype.
|
||||
*
|
||||
* @return value of subtype.
|
||||
*/
|
||||
public String getSubtype() {
|
||||
return this.subtype;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the subtype is a wildcard.
|
||||
*
|
||||
* @return true if the subtype is a wildcard.
|
||||
*/
|
||||
public boolean isWildcardSubtype() {
|
||||
return this.getSubtype().equals(AcceptPredicate.WILDCARD_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for a read-only parameter map. Keys are case-insensitive.
|
||||
*
|
||||
* @return an immutable map of parameters.
|
||||
*/
|
||||
public Map<String, String> getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code MediaType} instance with the same type, subtype and parameters
|
||||
* copied from the original instance and the supplied {@value #CHARSET_PARAMETER} parameter.
|
||||
*
|
||||
* @param charset the {@value #CHARSET_PARAMETER} parameter value. If {@code null} or empty
|
||||
* the {@value #CHARSET_PARAMETER} parameter will not be set or updated.
|
||||
* @return copy of the current {@code MediaType} instance with the {@value #CHARSET_PARAMETER}
|
||||
* parameter set to the supplied value.
|
||||
* @since 2.0
|
||||
*/
|
||||
public MediaType withCharset(String charset) {
|
||||
return new MediaType(this.type, this.subtype, charset, createParametersMap(this.parameters));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets {@link Optional} value of charset parameter.
|
||||
*
|
||||
* @return Charset parameter.
|
||||
*/
|
||||
public Optional<String> getCharset() {
|
||||
return Optional.ofNullable(parameters.get(CHARSET_PARAMETER));
|
||||
}
|
||||
|
||||
@Override
|
||||
public double qualityFactor() {
|
||||
String q = parameters.get(AcceptPredicate.QUALITY_FACTOR_PARAMETER);
|
||||
return q == null ? 1D : Double.valueOf(q);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this media type is compatible with another media type. E.g.
|
||||
* image/* is compatible with image/jpeg, image/png, etc. Media type
|
||||
* parameters are ignored. The function is commutative.
|
||||
*
|
||||
* @param other the media type to compare with.
|
||||
* @return true if the types are compatible, false otherwise.
|
||||
*/
|
||||
// fixme: Bidirectional wildcard compatibility
|
||||
public boolean test(MediaType other) {
|
||||
return other != null && // return false if other is null, else
|
||||
(
|
||||
type.equals(AcceptPredicate.WILDCARD_VALUE)
|
||||
|| other.type.equals(AcceptPredicate.WILDCARD_VALUE)
|
||||
|| (
|
||||
type.equalsIgnoreCase(other.type)
|
||||
&& (
|
||||
subtype.equals(AcceptPredicate.WILDCARD_VALUE) || other.subtype
|
||||
.equals(AcceptPredicate.WILDCARD_VALUE)))
|
||||
|| (type.equalsIgnoreCase(other.type) && this.subtype.equalsIgnoreCase(other.subtype)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares {@code obj} to this media type to see if they are the same by comparing
|
||||
* type, subtype and parameters. Note that the case-sensitivity of parameter
|
||||
@@ -491,7 +433,8 @@ public class MediaType implements AcceptPredicate<MediaType> {
|
||||
}
|
||||
|
||||
MediaType other = (MediaType) obj;
|
||||
return (this.type.equalsIgnoreCase(other.type)
|
||||
return (
|
||||
this.type.equalsIgnoreCase(other.type)
|
||||
&& this.subtype.equalsIgnoreCase(other.subtype)
|
||||
&& this.parameters.equals(other.parameters));
|
||||
}
|
||||
@@ -549,4 +492,53 @@ public class MediaType implements AcceptPredicate<MediaType> {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("checkstyle:VisibilityModifier")
|
||||
private static final class Tokenizer {
|
||||
final String input;
|
||||
int position = 0;
|
||||
|
||||
Tokenizer(String input) {
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
String consumeTokenIfPresent(CharMatcher matcher) {
|
||||
checkState(hasMore(), "No more elements!");
|
||||
int startPosition = position;
|
||||
position = matcher.negate().indexIn(input, startPosition);
|
||||
return hasMore() ? input.substring(startPosition, position) : input.substring(startPosition);
|
||||
}
|
||||
|
||||
String consumeToken(CharMatcher matcher) {
|
||||
int startPosition = position;
|
||||
String token = consumeTokenIfPresent(matcher);
|
||||
checkState(position != startPosition, () ->
|
||||
String.format("Position '%d' should not be '%d'!", position, startPosition));
|
||||
return token;
|
||||
}
|
||||
|
||||
char consumeCharacter(CharMatcher matcher) {
|
||||
checkState(hasMore(), "No more elements!");
|
||||
char c = previewChar();
|
||||
checkState(matcher.matches(c), "Unexpected character matched: " + c);
|
||||
position++;
|
||||
return c;
|
||||
}
|
||||
|
||||
char consumeCharacter(char c) {
|
||||
checkState(hasMore(), "No more elements!");
|
||||
checkState(previewChar() == c, () -> "Unexpected character: " + c);
|
||||
position++;
|
||||
return c;
|
||||
}
|
||||
|
||||
char previewChar() {
|
||||
checkState(hasMore(), "No more elements!");
|
||||
return input.charAt(position);
|
||||
}
|
||||
|
||||
boolean hasMore() {
|
||||
return (position >= 0) && (position < input.length());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.helidon.webserver;
|
||||
package io.helidon.common.http;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -25,7 +25,7 @@ import java.util.function.Function;
|
||||
/**
|
||||
* Parameters represents {@code key : value} pairs where {@code key} is a {@code String} with potentially multiple values.
|
||||
* <p>
|
||||
* This structure represents query parameters, headers and path parameters in {@link ServerRequest} and {@link ServerResponse}.
|
||||
* This structure represents query parameters, headers and path parameters in e.g. {@link HttpRequest}.
|
||||
* <p>
|
||||
* Interface focus on most convenient use cases in HTTP Request and Response processing, like
|
||||
* <pre>
|
||||
@@ -39,8 +39,8 @@ import java.util.function.Function;
|
||||
* <p>
|
||||
* Mutable operations are defined in two forms:
|
||||
* <ul>
|
||||
* <li>{@code put...} create or replace association.</li>
|
||||
* <li>{@code add...} create association or add values to existing association.</li>
|
||||
* <li>{@code put...} create or replace association.</li>
|
||||
* <li>{@code add...} create association or add values to existing association.</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* It is possible to use {@link #toMap()} method to get immutable map view of data.
|
||||
@@ -49,6 +49,18 @@ import java.util.function.Function;
|
||||
*/
|
||||
public interface Parameters {
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable view.
|
||||
*
|
||||
* @param parameters a parameters for unmodifiable view.
|
||||
* @return An unmodifiable view.
|
||||
* @throws NullPointerException if parameter {@code parameters} is null.
|
||||
*/
|
||||
static Parameters toUnmodifiableParameters(Parameters parameters) {
|
||||
Objects.requireNonNull(parameters, "Parameter 'parameters' is null!");
|
||||
return new UnmodifiableParameters(parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Optional} containing the first value of the given
|
||||
* parameter (and possibly multi-valued) parameter. If the parameter is
|
||||
@@ -75,11 +87,10 @@ public interface Parameters {
|
||||
* Associates specified values with the specified key (optional operation).
|
||||
* If parameters previously contained a mapping for the key, the old values fully replaced.
|
||||
*
|
||||
* @param key key with which the specified value is to be associated
|
||||
* @param key key with which the specified value is to be associated
|
||||
* @param values value to be associated with the specified key
|
||||
* @return the previous values associated with key, or empty {@code List} if there was no mapping for key.
|
||||
*
|
||||
* @throws NullPointerException if the specified key is null.
|
||||
* @throws NullPointerException if the specified key is null.
|
||||
* @throws UnsupportedOperationException if put operation is not supported (unmodifiable Parameters).
|
||||
*/
|
||||
List<String> put(String key, String... values);
|
||||
@@ -88,11 +99,10 @@ public interface Parameters {
|
||||
* Associates specified values with the specified key (optional operation).
|
||||
* If parameters previously contained a mapping for the key, the old values fully replaced.
|
||||
*
|
||||
* @param key key with which the specified value is to be associated
|
||||
* @param key key with which the specified value is to be associated
|
||||
* @param values value to be associated with the specified key. If {@code null} then association will be removed.
|
||||
* @return the previous values associated with key, or empty {@code List} if there was no mapping for key.
|
||||
*
|
||||
* @throws NullPointerException if the specified key is null.
|
||||
* @throws NullPointerException if the specified key is null.
|
||||
* @throws UnsupportedOperationException if put operation is not supported (unmodifiable Parameters).
|
||||
*/
|
||||
List<String> put(String key, Iterable<String> values);
|
||||
@@ -101,11 +111,10 @@ public interface Parameters {
|
||||
* If the specified key is not already associated with a value associates it with the given value and returns empty
|
||||
* {@code List}, else returns the current value (optional operation).
|
||||
*
|
||||
* @param key key with which the specified value is to be associated
|
||||
* @param key key with which the specified value is to be associated
|
||||
* @param values value to be associated with the specified key
|
||||
* @return the previous values associated with key, or empty {@code List} if there was no mapping for key.
|
||||
*
|
||||
* @throws NullPointerException if the specified key is null.
|
||||
* @throws NullPointerException if the specified key is null.
|
||||
* @throws UnsupportedOperationException if put operation is not supported (unmodifiable Parameters).
|
||||
*/
|
||||
List<String> putIfAbsent(String key, String... values);
|
||||
@@ -114,11 +123,10 @@ public interface Parameters {
|
||||
* If the specified key is not already associated with a value associates it with the given value and returns empty
|
||||
* {@code List}, else returns the current value (optional operation).
|
||||
*
|
||||
* @param key key with which the specified value is to be associated
|
||||
* @param key key with which the specified value is to be associated
|
||||
* @param values value to be associated with the specified key
|
||||
* @return the previous values associated with key, or empty {@code List} if there was no mapping for key.
|
||||
*
|
||||
* @throws NullPointerException if the specified key is null.
|
||||
* @throws NullPointerException if the specified key is null.
|
||||
* @throws UnsupportedOperationException if put operation is not supported (unmodifiable Parameters).
|
||||
*/
|
||||
List<String> putIfAbsent(String key, Iterable<String> values);
|
||||
@@ -127,18 +135,17 @@ public interface Parameters {
|
||||
* If the specified key is not already associated with a value computes new association using the given function and returns
|
||||
* empty {@code List}, else returns the current value (optional operation).
|
||||
*
|
||||
* @param key key with which the specified value is to be associated
|
||||
* @param key key with which the specified value is to be associated
|
||||
* @param values value to be associated with the specified key
|
||||
* @return the current (potentially computed) values associated with key,
|
||||
* or empty {@code List} if function returns {@code null}
|
||||
*
|
||||
* @throws NullPointerException if the specified key is null
|
||||
* or empty {@code List} if function returns {@code null}
|
||||
* @throws NullPointerException if the specified key is null
|
||||
* @throws UnsupportedOperationException if put operation is not supported (unmodifiable Parameters)
|
||||
* @throws IllegalStateException if the computation detectably
|
||||
* attempts a recursive update to this map that would
|
||||
* otherwise never complete
|
||||
* @throws RuntimeException or Error if the mappingFunction does so,
|
||||
* in which case the mapping is left unestablished
|
||||
* @throws IllegalStateException if the computation detectably
|
||||
* attempts a recursive update to this map that would
|
||||
* otherwise never complete
|
||||
* @throws RuntimeException or Error if the mappingFunction does so,
|
||||
* in which case the mapping is left unestablished
|
||||
*/
|
||||
List<String> computeIfAbsent(String key, Function<String, Iterable<String>> values);
|
||||
|
||||
@@ -146,18 +153,17 @@ public interface Parameters {
|
||||
* If the specified key is not already associated with a value computes new association using the given function and returns
|
||||
* empty {@code List}, else returns the current value (optional operation).
|
||||
*
|
||||
* @param key a key with which the specified value is to be associated
|
||||
* @param key a key with which the specified value is to be associated
|
||||
* @param value a single value to be associated with the specified key
|
||||
* @return the current (potentially computed) values associated with key,
|
||||
* or empty {@code List} if function returns {@code null}
|
||||
*
|
||||
* @throws NullPointerException if the specified key is null.
|
||||
* or empty {@code List} if function returns {@code null}
|
||||
* @throws NullPointerException if the specified key is null.
|
||||
* @throws UnsupportedOperationException if put operation is not supported (unmodifiable Parameters).
|
||||
* @throws IllegalStateException if the computation detectably
|
||||
* attempts a recursive update to this map that would
|
||||
* otherwise never complete
|
||||
* @throws RuntimeException or Error if the mappingFunction does so,
|
||||
* in which case the mapping is left unestablished
|
||||
* @throws IllegalStateException if the computation detectably
|
||||
* attempts a recursive update to this map that would
|
||||
* otherwise never complete
|
||||
* @throws RuntimeException or Error if the mappingFunction does so,
|
||||
* in which case the mapping is left unestablished
|
||||
*/
|
||||
List<String> computeSingleIfAbsent(String key, Function<String, String> value);
|
||||
|
||||
@@ -166,8 +172,7 @@ public interface Parameters {
|
||||
* (optional operation).
|
||||
*
|
||||
* @param parameters to copy.
|
||||
*
|
||||
* @throws NullPointerException if the specified {@code parameters} are null.
|
||||
* @throws NullPointerException if the specified {@code parameters} are null.
|
||||
* @throws UnsupportedOperationException if put operation is not supported (unmodifiable Parameters).
|
||||
*/
|
||||
void putAll(Parameters parameters);
|
||||
@@ -176,10 +181,9 @@ public interface Parameters {
|
||||
* Adds specified values tu association with the specified key (optional operation).
|
||||
* If parameters doesn't contains mapping, new mapping is created.
|
||||
*
|
||||
* @param key key with which the specified value is to be associated
|
||||
* @param key key with which the specified value is to be associated
|
||||
* @param values value to be add to association with the specified key
|
||||
*
|
||||
* @throws NullPointerException if the specified key is null.
|
||||
* @throws NullPointerException if the specified key is null.
|
||||
* @throws UnsupportedOperationException if put operation is not supported (unmodifiable Parameters).
|
||||
*/
|
||||
void add(String key, String... values);
|
||||
@@ -188,10 +192,9 @@ public interface Parameters {
|
||||
* Adds specified values tu association with the specified key (optional operation).
|
||||
* If parameters doesn't contains mapping, new mapping is created.
|
||||
*
|
||||
* @param key key with which the specified value is to be associated
|
||||
* @param key key with which the specified value is to be associated
|
||||
* @param values value to be add to association with the specified key. If {@code null} then noting will be add.
|
||||
*
|
||||
* @throws NullPointerException if the specified key is null.
|
||||
* @throws NullPointerException if the specified key is null.
|
||||
* @throws UnsupportedOperationException if put operation is not supported (unmodifiable Parameters).
|
||||
*/
|
||||
void add(String key, Iterable<String> values);
|
||||
@@ -201,8 +204,7 @@ public interface Parameters {
|
||||
* (optional operation).
|
||||
*
|
||||
* @param parameters to copy.
|
||||
*
|
||||
* @throws NullPointerException if the specified {@code parameters} are null.
|
||||
* @throws NullPointerException if the specified {@code parameters} are null.
|
||||
* @throws UnsupportedOperationException if put operation is not supported (unmodifiable Parameters).
|
||||
*/
|
||||
void addAll(Parameters parameters);
|
||||
@@ -223,16 +225,4 @@ public interface Parameters {
|
||||
* @return the {@code Map}
|
||||
*/
|
||||
Map<String, List<String>> toMap();
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable view.
|
||||
*
|
||||
* @param parameters a parameters for unmodifiable view.
|
||||
* @return An unmodifiable view.
|
||||
* @throws NullPointerException if parameter {@code parameters} is null.
|
||||
*/
|
||||
static Parameters toUnmodifiableParameters(Parameters parameters) {
|
||||
Objects.requireNonNull("Parameter 'parameters' is null!");
|
||||
return new UnmodifiableParameters(parameters);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.helidon.webserver;
|
||||
package io.helidon.common.http;
|
||||
|
||||
/**
|
||||
* Copied from Guava.
|
||||
@@ -95,10 +95,10 @@ final class Preconditions {
|
||||
* size {@code size}. A position index may range from zero to {@code size}, inclusive.
|
||||
*
|
||||
* @param index a user-supplied index identifying a position in an array, list or string
|
||||
* @param size the size of that array, list or string
|
||||
* @param size the size of that array, list or string
|
||||
* @return the value of {@code index}
|
||||
* @throws IndexOutOfBoundsException if {@code index} is negative or is greater than {@code size}
|
||||
* @throws IllegalArgumentException if {@code size} is negative
|
||||
* @throws IllegalArgumentException if {@code size} is negative
|
||||
*/
|
||||
public static int checkPositionIndex(int index, int size) {
|
||||
return checkPositionIndex(index, size, "index");
|
||||
@@ -109,11 +109,11 @@ final class Preconditions {
|
||||
* size {@code size}. A position index may range from zero to {@code size}, inclusive.
|
||||
*
|
||||
* @param index a user-supplied index identifying a position in an array, list or string
|
||||
* @param size the size of that array, list or string
|
||||
* @param desc the text to use to describe this index in an error message
|
||||
* @param size the size of that array, list or string
|
||||
* @param desc the text to use to describe this index in an error message
|
||||
* @return the value of {@code index}
|
||||
* @throws IndexOutOfBoundsException if {@code index} is negative or is greater than {@code size}
|
||||
* @throws IllegalArgumentException if {@code size} is negative
|
||||
* @throws IllegalArgumentException if {@code size} is negative
|
||||
*/
|
||||
public static int checkPositionIndex(int index, int size, String desc) {
|
||||
// Carefully optimized for execution by hotspot (explanatory comment above)
|
||||
@@ -129,11 +129,11 @@ final class Preconditions {
|
||||
* {@code size}, inclusive.
|
||||
*
|
||||
* @param start a user-supplied index identifying a starting position in an array, list or string
|
||||
* @param end a user-supplied index identifying a ending position in an array, list or string
|
||||
* @param size the size of that array, list or string
|
||||
* @param end a user-supplied index identifying a ending position in an array, list or string
|
||||
* @param size the size of that array, list or string
|
||||
* @throws IndexOutOfBoundsException if either index is negative or is greater than {@code size},
|
||||
* or if {@code end} is less than {@code start}
|
||||
* @throws IllegalArgumentException if {@code size} is negative
|
||||
* or if {@code end} is less than {@code start}
|
||||
* @throws IllegalArgumentException if {@code size} is negative
|
||||
*/
|
||||
public static void checkPositionIndexes(int start, int end, int size) {
|
||||
// Carefully optimized for execution by hotspot (explanatory comment above)
|
||||
@@ -153,7 +153,6 @@ final class Preconditions {
|
||||
return format("end index (%s) must not be less than start index (%s)", end, start);
|
||||
}
|
||||
|
||||
|
||||
private static String badPositionIndex(int index, int size, String desc) {
|
||||
if (index < 0) {
|
||||
return format("%s (%s) must not be negative", desc, index);
|
||||
@@ -171,8 +170,8 @@ final class Preconditions {
|
||||
* square braces.
|
||||
*
|
||||
* @param template a non-null string containing 0 or more {@code %s} placeholders.
|
||||
* @param args the arguments to be substituted into the message template. Arguments are converted
|
||||
* to strings using {@link String#valueOf(Object)}. Arguments can be null.
|
||||
* @param args the arguments to be substituted into the message template. Arguments are converted
|
||||
* to strings using {@link String#valueOf(Object)}. Arguments can be null.
|
||||
*/
|
||||
// Note that this is somewhat-improperly used from Verify.java as well.
|
||||
static String format(String template, Object... args) {
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.helidon.webserver;
|
||||
package io.helidon.common.http;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -57,6 +57,31 @@ public class ReadOnlyParameters implements Parameters {
|
||||
this(parameters == null ? null : parameters.toMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns empty and immutable singleton.
|
||||
*
|
||||
* @return the parameters singleton instance which is empty and immutable.
|
||||
*/
|
||||
public static ReadOnlyParameters empty() {
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a deep copy of provided multi-map which is completely unmodifiable.
|
||||
*
|
||||
* @param data data to copy, if {@code null} then returns empty map.
|
||||
* @return unmodifiable map, never {@code null}.
|
||||
*/
|
||||
static Map<String, List<String>> copyMultimapAsImutable(Map<String, List<String>> data) {
|
||||
if (data == null || data.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
} else {
|
||||
// Deep copy
|
||||
Map<String, List<String>> h = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
data.forEach((k, v) -> h.put(k, Collections.unmodifiableList(new ArrayList<>(v))));
|
||||
return Collections.unmodifiableMap(h);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> first(String name) {
|
||||
@@ -129,30 +154,4 @@ public class ReadOnlyParameters implements Parameters {
|
||||
data.forEach((k, v) -> h.put(k, new ArrayList<>(v)));
|
||||
return h;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns empty and immutable singleton.
|
||||
*
|
||||
* @return the parameters singleton instance which is empty and immutable.
|
||||
*/
|
||||
public static ReadOnlyParameters empty() {
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a deep copy of provided multi-map which is completely unmodifiable.
|
||||
*
|
||||
* @param data data to copy, if {@code null} then returns empty map.
|
||||
* @return unmodifiable map, never {@code null}.
|
||||
*/
|
||||
static Map<String, List<String>> copyMultimapAsImutable(Map<String, List<String>> data) {
|
||||
if (data == null || data.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
} else {
|
||||
// Deep copy
|
||||
Map<String, List<String>> h = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
data.forEach((k, v) -> h.put(k, Collections.unmodifiableList(new ArrayList<>(v))));
|
||||
return Collections.unmodifiableMap(h);
|
||||
}
|
||||
}
|
||||
}
|
||||
80
common/http/src/main/java/io/helidon/common/http/Reader.java
Normal file
80
common/http/src/main/java/io/helidon/common/http/Reader.java
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package io.helidon.common.http;
|
||||
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import io.helidon.common.reactive.Flow;
|
||||
|
||||
/**
|
||||
* The Reader transforms a {@link DataChunk} publisher into a completion stage of the associated type.
|
||||
*
|
||||
* @param <R> the requested type
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface Reader<R> extends BiFunction<Flow.Publisher<DataChunk>, Class<? super R>, CompletionStage<? extends R>> {
|
||||
|
||||
/**
|
||||
* Transforms a publisher into a completion stage.
|
||||
* If an exception is thrown, the resulting completion stage of
|
||||
* {@link Content#as(Class)} method call ends exceptionally.
|
||||
*
|
||||
* @param publisher the publisher to transform
|
||||
* @param clazz the requested type to be returned as a completion stage. The purpose of
|
||||
* this parameter is to know what the user of this Reader actually requested.
|
||||
* @return the result as a completion stage
|
||||
*/
|
||||
@Override
|
||||
CompletionStage<? extends R> apply(Flow.Publisher<DataChunk> publisher, Class<? super R> clazz);
|
||||
|
||||
/**
|
||||
* Transforms a publisher into a completion stage.
|
||||
* If an exception is thrown, the resulting completion stage of
|
||||
* {@link Content#as(Class)} method call ends exceptionally.
|
||||
* <p>
|
||||
* The default implementation calls {@link #apply(Flow.Publisher, Class)} with {@link Object} as
|
||||
* the class parameter.
|
||||
*
|
||||
* @param publisher the publisher to transform
|
||||
* @return the result as a completion stage
|
||||
*/
|
||||
default CompletionStage<? extends R> apply(Flow.Publisher<DataChunk> publisher) {
|
||||
return apply(publisher, Object.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a publisher into a completion stage.
|
||||
* If an exception is thrown, the resulting completion stage of
|
||||
* {@link Content#as(Class)} method call ends exceptionally.
|
||||
* <p>
|
||||
* The default implementation calls {@link #apply(Flow.Publisher, Class)} with {@link Object} as
|
||||
* the class parameter.
|
||||
*
|
||||
* @param publisher the publisher to transform
|
||||
* @param type the desired type to cast the guarantied {@code R} type to
|
||||
* @param <T> the desired type to cast the guarantied {@code R} type to
|
||||
* @return the result as a completion stage which might end exceptionally with
|
||||
* {@link ClassCastException} if the {@code R} type wasn't possible to cast
|
||||
* to {@code T}
|
||||
*/
|
||||
default <T extends R> CompletionStage<? extends T> applyAndCast(Flow.Publisher<DataChunk> publisher, Class<T> type) {
|
||||
// if this was implemented as (CompletionStage<? extends T>) apply(publisher, (Class<R>) clazz);
|
||||
// the class cast exception might occur outside of the completion stage which might be confusing
|
||||
return apply(publisher, (Class<R>) type).thenApply(type::cast);
|
||||
}
|
||||
}
|
||||
195
common/http/src/main/java/io/helidon/common/http/SetCookie.java
Normal file
195
common/http/src/main/java/io/helidon/common/http/SetCookie.java
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package io.helidon.common.http;
|
||||
|
||||
import java.net.URI;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents {@code 'Set-Cookie'} header value specified by <a href="https://tools.ietf.org/html/rfc6265">RFC6265</a>.
|
||||
*
|
||||
* <p>It is mutable and fluent builder.
|
||||
*/
|
||||
public class SetCookie {
|
||||
|
||||
private static final String PARAM_SEPARATOR = "; ";
|
||||
|
||||
private final String name;
|
||||
private final String value;
|
||||
private ZonedDateTime expires;
|
||||
private Duration maxAge;
|
||||
private String domain;
|
||||
private String path;
|
||||
private boolean secure;
|
||||
private boolean httpOnly;
|
||||
|
||||
/**
|
||||
* Creates new instance.
|
||||
*
|
||||
* @param name a cookie name.
|
||||
* @param value a cookie value.
|
||||
*/
|
||||
public SetCookie(String name, String value) {
|
||||
Objects.requireNonNull(name, "Parameter 'name' is null!");
|
||||
//todo validate accepted characters
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@code Expires} parameter.
|
||||
*
|
||||
* @param expires an {@code Expires} parameter.
|
||||
* @return Updated instance.
|
||||
*/
|
||||
public SetCookie expires(ZonedDateTime expires) {
|
||||
this.expires = expires;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@code Expires} parameter.
|
||||
*
|
||||
* @param expires an {@code Expires} parameter.
|
||||
* @return Updated instance.
|
||||
*/
|
||||
public SetCookie expires(Instant expires) {
|
||||
if (expires == null) {
|
||||
this.expires = null;
|
||||
} else {
|
||||
this.expires = ZonedDateTime.ofInstant(expires, ZoneId.systemDefault());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@code Max-Age} parameter.
|
||||
*
|
||||
* @param maxAge an {@code Max-Age} parameter.
|
||||
* @return Updated instance.
|
||||
*/
|
||||
public SetCookie maxAge(Duration maxAge) {
|
||||
this.maxAge = maxAge;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@code Domain} parameter.
|
||||
*
|
||||
* @param domain an {@code Domain} parameter.
|
||||
* @return Updated instance.
|
||||
*/
|
||||
public SetCookie domain(String domain) {
|
||||
this.domain = domain;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@code Path} parameter.
|
||||
*
|
||||
* @param path an {@code Path} parameter.
|
||||
* @return Updated instance.
|
||||
*/
|
||||
public SetCookie path(String path) {
|
||||
this.path = path;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@code Domain} and {@code Path} parameters.
|
||||
*
|
||||
* @param domainAndPath an URI to specify {@code Domain} and {@code Path} parameters.
|
||||
* @return Updated instance.
|
||||
*/
|
||||
public SetCookie domainAndPath(URI domainAndPath) {
|
||||
if (domainAndPath == null) {
|
||||
this.domain = null;
|
||||
this.path = null;
|
||||
} else {
|
||||
this.domain = domainAndPath.getHost();
|
||||
this.path = domainAndPath.getPath();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@code Secure} parameter.
|
||||
*
|
||||
* @param secure an {@code Secure} parameter.
|
||||
* @return Updated instance.
|
||||
*/
|
||||
public SetCookie secure(boolean secure) {
|
||||
this.secure = secure;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@code HttpOnly} parameter.
|
||||
*
|
||||
* @param httpOnly an {@code HttpOnly} parameter.
|
||||
* @return Updated instance.
|
||||
*/
|
||||
public SetCookie httpOnly(boolean httpOnly) {
|
||||
this.httpOnly = httpOnly;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns content of this instance as a 'Set-Cookie:' header value specified
|
||||
* by <a href="https://tools.ietf.org/html/rfc6265">RFC6265</a>.
|
||||
*
|
||||
* @return a 'Set-Cookie:' header value.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder result = new StringBuilder();
|
||||
result.append(name).append('=').append(value);
|
||||
if (expires != null) {
|
||||
result.append(PARAM_SEPARATOR);
|
||||
result.append("Expires=");
|
||||
result.append(expires.format(Http.DateTime.RFC_1123_DATE_TIME));
|
||||
}
|
||||
if (maxAge != null && !maxAge.isNegative() && !maxAge.isZero()) {
|
||||
result.append(PARAM_SEPARATOR);
|
||||
result.append("Max-Age=");
|
||||
result.append(maxAge.getSeconds());
|
||||
}
|
||||
if (domain != null) {
|
||||
result.append(PARAM_SEPARATOR);
|
||||
result.append("Domain=");
|
||||
result.append(domain);
|
||||
}
|
||||
if (path != null) {
|
||||
result.append(PARAM_SEPARATOR);
|
||||
result.append("Path=");
|
||||
result.append(path);
|
||||
}
|
||||
if (secure) {
|
||||
result.append(PARAM_SEPARATOR);
|
||||
result.append("Secure");
|
||||
}
|
||||
if (httpOnly) {
|
||||
result.append(PARAM_SEPARATOR);
|
||||
result.append("HttpOnly");
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.helidon.webserver;
|
||||
package io.helidon.common.http;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,42 +14,24 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.helidon.webserver;
|
||||
package io.helidon.common.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
/**
|
||||
* Internal utility methods.
|
||||
*/
|
||||
final class Utils {
|
||||
public final class Utils {
|
||||
static final Runnable EMPTY_RUNNABLE = () -> {
|
||||
};
|
||||
|
||||
private Utils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the first service implementation or throw an exception if nothing found.
|
||||
*
|
||||
* @param service the service class to load
|
||||
* @param <T> service type
|
||||
* @return the loaded service
|
||||
* @throws IllegalStateException if none implementation found
|
||||
*/
|
||||
static <T> T loadSpi(Class<T> service) {
|
||||
ServiceLoader<T> servers = ServiceLoader.load(service);
|
||||
Iterator<T> serversIt = servers.iterator();
|
||||
if (serversIt.hasNext()) {
|
||||
return serversIt.next();
|
||||
} else {
|
||||
throw new IllegalStateException("No implementation found for SPI: " + service.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tokenize provide {@code text} by {@code separator} char respecting quoted sub-sequences. Quoted sub-sequences are
|
||||
* parts of {@code text} which starts and ends by the same {@code quoteChar}.
|
||||
@@ -61,7 +43,7 @@ final class Utils {
|
||||
* @param text a text to be tokenized.
|
||||
* @return A list of tokens without separator characters.
|
||||
*/
|
||||
static List<String> tokenize(char separator, String quoteChars, boolean includeEmptyTokens, String text) {
|
||||
public static List<String> tokenize(char separator, String quoteChars, boolean includeEmptyTokens, String text) {
|
||||
char[] quotes = quoteChars == null ? new char[0] : quoteChars.toCharArray();
|
||||
StringBuilder token = new StringBuilder();
|
||||
List<String> result = new ArrayList<>();
|
||||
@@ -105,7 +87,7 @@ final class Utils {
|
||||
* @param byteBuffer the byte buffer to append to the stream
|
||||
* @throws IOException in case of an IO problem
|
||||
*/
|
||||
static void write(ByteBuffer byteBuffer, OutputStream out) throws IOException {
|
||||
public static void write(ByteBuffer byteBuffer, OutputStream out) throws IOException {
|
||||
if (byteBuffer.hasArray()) {
|
||||
out.write(byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position(), byteBuffer.remaining());
|
||||
} else {
|
||||
@@ -114,4 +96,16 @@ final class Utils {
|
||||
out.write(buff);
|
||||
}
|
||||
}
|
||||
|
||||
static byte[] toByteArray(ByteBuffer byteBuffer) {
|
||||
byte[] buff = new byte[byteBuffer.remaining()];
|
||||
|
||||
if (byteBuffer.hasArray()) {
|
||||
System.arraycopy(byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position(), buff, 0, buff.length);
|
||||
} else {
|
||||
byteBuffer.get(buff);
|
||||
}
|
||||
|
||||
return buff;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* HTTP APIs and implementations usable by both server and client side of the HTTP story.
|
||||
*/
|
||||
package io.helidon.common.http;
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,22 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.helidon.webserver;
|
||||
|
||||
/**
|
||||
* This Builder should be implemented by all the builders in order to enable
|
||||
* seamless exchange between the builder itself and the objects it's
|
||||
* building when calling the methods. Such methods need to have overloads
|
||||
* with builder parameters as well as concrete instances.
|
||||
*
|
||||
* @param <T> the type this builder is building
|
||||
* Helidon Common classes for HTTP server and client.
|
||||
*/
|
||||
public interface Builder<T> {
|
||||
module io.helidon.common.http {
|
||||
requires java.logging;
|
||||
requires io.helidon.common;
|
||||
requires io.helidon.common.reactive;
|
||||
|
||||
/**
|
||||
* Builds the object.
|
||||
*
|
||||
* @return the built object
|
||||
*/
|
||||
T build();
|
||||
exports io.helidon.common.http;
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package io.helidon.common.http;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
* Unit test for {@link DataChunk}.
|
||||
*/
|
||||
class DataChunkTest {
|
||||
@Test
|
||||
public void testSimpleWrapping() {
|
||||
byte[] bytes = "urzatron".getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
DataChunk chunk = DataChunk.create(bytes);
|
||||
|
||||
assertThat(chunk.bytes(), is(bytes));
|
||||
assertThat(chunk.flush(), is(false));
|
||||
assertThat(chunk.id(), not(0L));
|
||||
assertThat(chunk.isReleased(), is(false));
|
||||
assertThat(chunk.data().array(), is(bytes));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReleasing() {
|
||||
byte[] bytes = "urzatron".getBytes(StandardCharsets.UTF_8);
|
||||
AtomicBoolean ab = new AtomicBoolean(false);
|
||||
|
||||
DataChunk chunk = DataChunk.create(true, ByteBuffer.wrap(bytes), () -> ab.set(true));
|
||||
|
||||
assertThat(chunk.bytes(), is(bytes));
|
||||
assertThat(chunk.flush(), is(true));
|
||||
assertThat(chunk.id(), not(0L));
|
||||
assertThat(chunk.data().array(), is(bytes));
|
||||
assertThat(chunk.isReleased(), is(false));
|
||||
assertThat(ab.get(), is(false));
|
||||
chunk.release();
|
||||
assertThat(chunk.isReleased(), is(true));
|
||||
assertThat(ab.get(), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReleasingNoRunnable() {
|
||||
byte[] bytes = "urzatron".getBytes(StandardCharsets.UTF_8);
|
||||
DataChunk chunk = DataChunk.create(true, ByteBuffer.wrap(bytes));
|
||||
|
||||
assertThat(chunk.bytes(), is(bytes));
|
||||
assertThat(chunk.flush(), is(true));
|
||||
assertThat(chunk.id(), not(0L));
|
||||
assertThat(chunk.data().array(), is(bytes));
|
||||
assertThat(chunk.isReleased(), is(false));
|
||||
chunk.release();
|
||||
assertThat(chunk.isReleased(), is(true));
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.helidon.webserver;
|
||||
package io.helidon.common.http;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
@@ -22,7 +22,7 @@ import java.time.ZonedDateTime;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||
|
||||
/**
|
||||
@@ -30,8 +30,8 @@ import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||
*/
|
||||
public class DateTimeTest {
|
||||
|
||||
public static final ZonedDateTime ZDT = ZonedDateTime.of(2008, 6, 3, 11, 5, 30, 0, ZoneId.of("Z"));
|
||||
public static final ZonedDateTime ZDT2 = ZonedDateTime.of(2008, 6, 17, 11, 5, 30, 0, ZoneId.of("Z"));
|
||||
private static final ZonedDateTime ZDT = ZonedDateTime.of(2008, 6, 3, 11, 5, 30, 0, ZoneId.of("Z"));
|
||||
private static final ZonedDateTime ZDT2 = ZonedDateTime.of(2008, 6, 17, 11, 5, 30, 0, ZoneId.of("Z"));
|
||||
|
||||
@Test
|
||||
public void rfc1123() throws Exception {
|
||||
@@ -14,14 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.helidon.webserver;
|
||||
package io.helidon.common.http;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
/**
|
||||
* Tests {@link ListContextualRegistry} and {@link ContextualRegistry}.
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package io.helidon.common.http;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
* Unit test for {@link MediaType}.
|
||||
*/
|
||||
class MediaTypeTest {
|
||||
|
||||
@Test
|
||||
void testText() {
|
||||
MediaType textPlain = MediaType.TEXT_PLAIN;
|
||||
|
||||
assertThat(textPlain.getType(), is("text"));
|
||||
assertThat(textPlain.getSubtype(), is("plain"));
|
||||
assertThat(textPlain.getCharset(), is(Optional.empty()));
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,23 +14,26 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.helidon.webserver;
|
||||
package io.helidon.common.http;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* Tests {@link Utils}.
|
||||
*/
|
||||
public class UtilsTest {
|
||||
class UtilsTest {
|
||||
|
||||
@Test
|
||||
public void tokenize() throws Exception {
|
||||
void tokenize() throws Exception {
|
||||
String text = ",aa,,fo\"oooo\",\"bar\",co\"o'l,e\"c,df'hk,lm',";
|
||||
List<String> tokens = Utils.tokenize(',', null, false, text);
|
||||
assertThat(tokens, contains("aa", "fo\"oooo\"", "\"bar\"", "co\"o'l", "e\"c", "df'hk", "lm'"));
|
||||
@@ -48,4 +51,13 @@ public class UtilsTest {
|
||||
assertEquals(1, tokens.size());
|
||||
assertEquals(text, tokens.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testByteBufferToByteArray() {
|
||||
byte[] array = "halleluja".getBytes(StandardCharsets.UTF_8);
|
||||
ByteBuffer wrap = ByteBuffer.wrap(array);
|
||||
byte[] unwrapped = Utils.toByteArray(wrap);
|
||||
|
||||
assertThat(unwrapped, is(array));
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.common</groupId>
|
||||
<artifactId>helidon-common-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-common-key-util</artifactId>
|
||||
<name>Helidon Common Key Util</name>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon</groupId>
|
||||
<artifactId>helidon-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<groupId>io.helidon.common</groupId>
|
||||
<artifactId>helidon-common-project</artifactId>
|
||||
@@ -35,5 +35,6 @@
|
||||
<module>reactive</module>
|
||||
<module>configurable</module>
|
||||
<module>key-util</module>
|
||||
<module>http</module>
|
||||
</modules>
|
||||
</project>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.common</groupId>
|
||||
<artifactId>helidon-common-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-common-reactive</artifactId>
|
||||
<name>Helidon Common Reactive</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config</groupId>
|
||||
<artifactId>helidon-config-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-bundle</artifactId>
|
||||
<name>Helidon Config Bundle</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config</groupId>
|
||||
<artifactId>helidon-config-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config</artifactId>
|
||||
<name>Helidon Config</name>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config</groupId>
|
||||
<artifactId>helidon-config-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-etcd</artifactId>
|
||||
<name>Helidon Config Etcd</name>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config.examples</groupId>
|
||||
<artifactId>helidon-config-examples-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-examples-basics</artifactId>
|
||||
<name>Helidon Config Examples Basics</name>
|
||||
@@ -33,7 +33,7 @@
|
||||
</description>
|
||||
|
||||
<properties>
|
||||
<helidon.version>0.9.2-SNAPSHOT</helidon.version>
|
||||
<helidon.version>0.10.0-SNAPSHOT</helidon.version>
|
||||
<example.mainClass>io.helidon.config.examples.basics.Main</example.mainClass>
|
||||
</properties>
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<artifactId>helidon-config-examples-project</artifactId>
|
||||
<groupId>io.helidon.config.examples</groupId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-examples-changes</artifactId>
|
||||
<name>Helidon Config Examples Changes</name>
|
||||
@@ -34,7 +34,7 @@
|
||||
</description>
|
||||
|
||||
<properties>
|
||||
<helidon.version>0.9.2-SNAPSHOT</helidon.version>
|
||||
<helidon.version>0.10.0-SNAPSHOT</helidon.version>
|
||||
<example.mainClass>io.helidon.config.examples.changes.Main</example.mainClass>
|
||||
</properties>
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config.examples</groupId>
|
||||
<artifactId>helidon-config-examples-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-examples-git</artifactId>
|
||||
<name>Helidon Config Examples Git</name>
|
||||
@@ -32,7 +32,7 @@
|
||||
</description>
|
||||
|
||||
<properties>
|
||||
<helidon.version>0.9.2-SNAPSHOT</helidon.version>
|
||||
<helidon.version>0.10.0-SNAPSHOT</helidon.version>
|
||||
<example.mainClass>io.helidon.config.examples.git.Main</example.mainClass>
|
||||
</properties>
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config.examples</groupId>
|
||||
<artifactId>helidon-config-examples-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-examples-mapping</artifactId>
|
||||
<name>Helidon Config Examples Mapping</name>
|
||||
@@ -33,7 +33,7 @@
|
||||
</description>
|
||||
|
||||
<properties>
|
||||
<helidon.version>0.9.2-SNAPSHOT</helidon.version>
|
||||
<helidon.version>0.10.0-SNAPSHOT</helidon.version>
|
||||
<example.mainClass>io.helidon.config.examples.mapping.Main</example.mainClass>
|
||||
</properties>
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config.examples</groupId>
|
||||
<artifactId>helidon-config-examples-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-examples-overrides</artifactId>
|
||||
<name>Helidon Config Examples Overrides</name>
|
||||
@@ -33,7 +33,7 @@
|
||||
</description>
|
||||
|
||||
<properties>
|
||||
<helidon.version>0.9.2-SNAPSHOT</helidon.version>
|
||||
<helidon.version>0.10.0-SNAPSHOT</helidon.version>
|
||||
<example.mainClass>io.helidon.config.examples.overrides.Main</example.mainClass>
|
||||
</properties>
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config</groupId>
|
||||
<artifactId>helidon-config-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<groupId>io.helidon.config.examples</groupId>
|
||||
<artifactId>helidon-config-examples-project</artifactId>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config.examples</groupId>
|
||||
<artifactId>helidon-config-examples-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-examples-sources</artifactId>
|
||||
<name>Helidon Config Examples Sources</name>
|
||||
@@ -33,7 +33,7 @@
|
||||
</description>
|
||||
|
||||
<properties>
|
||||
<helidon.version>0.9.2-SNAPSHOT</helidon.version>
|
||||
<helidon.version>0.10.0-SNAPSHOT</helidon.version>
|
||||
<example.mainClass>io.helidon.config.examples.sources.Main</example.mainClass>
|
||||
</properties>
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config</groupId>
|
||||
<artifactId>helidon-config-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-git</artifactId>
|
||||
<name>Helidon Config Git</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config</groupId>
|
||||
<artifactId>helidon-config-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-hocon</artifactId>
|
||||
<name>Helidon Config HOCON</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon</groupId>
|
||||
<artifactId>helidon-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<groupId>io.helidon.config</groupId>
|
||||
<artifactId>helidon-config-project</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config</groupId>
|
||||
<artifactId>helidon-config-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-test-infrastructure</artifactId>
|
||||
<name>Helidon Config Test Infrastructure</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config</groupId>
|
||||
<artifactId>helidon-config-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-testing</artifactId>
|
||||
<name>Helidon Config Testing</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config.tests</groupId>
|
||||
<artifactId>helidon-config-tests-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-tests-integration-tests</artifactId>
|
||||
<name>Helidon Config Tests Integration</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config.tests</groupId>
|
||||
<artifactId>helidon-config-tests-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-tests-module-mappers-1-base</artifactId>
|
||||
<name>Helidon Config Tests Mappers 1</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config.tests</groupId>
|
||||
<artifactId>helidon-config-tests-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-tests-module-mappers-2-override</artifactId>
|
||||
<name>Helidon Config Tests Parser 2</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config.tests</groupId>
|
||||
<artifactId>helidon-config-tests-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-tests-module-meta-source-1</artifactId>
|
||||
<name>Helidon Config Tests Meta Source 1</name>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config.tests</groupId>
|
||||
<artifactId>helidon-config-tests-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-tests-module-meta-source-2</artifactId>
|
||||
<name>Helidon Config Tests Meta Source 2</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config.tests</groupId>
|
||||
<artifactId>helidon-config-tests-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-tests-module-parsers-1-override</artifactId>
|
||||
<name>Helidon Config Tests Parser 1</name>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config</groupId>
|
||||
<artifactId>helidon-config-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<groupId>io.helidon.config.tests</groupId>
|
||||
<artifactId>helidon-config-tests-project</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config.tests</groupId>
|
||||
<artifactId>helidon-config-tests-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-tests-test-bundle</artifactId>
|
||||
<name>Helidon Config Tests Bundle</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config.tests</groupId>
|
||||
<artifactId>helidon-config-tests-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-tests-test-default_config-1-properties</artifactId>
|
||||
<name>Helidon Config Tests Default Config 1</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config.tests</groupId>
|
||||
<artifactId>helidon-config-tests-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-tests-test-default_config-2-hocon-json</artifactId>
|
||||
<name>Helidon Config Tests Default Config 2</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config.tests</groupId>
|
||||
<artifactId>helidon-config-tests-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-tests-test-default_config-3-hocon</artifactId>
|
||||
<name>Helidon Config Tests Default Config 3</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config.tests</groupId>
|
||||
<artifactId>helidon-config-tests-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-tests-test-default_config-4-yaml</artifactId>
|
||||
<name>Helidon Config Tests Default Config 4</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config.tests</groupId>
|
||||
<artifactId>helidon-config-tests-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-tests-test-default_config-5-env_vars</artifactId>
|
||||
<name>Helidon Config Tests Default Config 5</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config.tests</groupId>
|
||||
<artifactId>helidon-config-tests-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-tests-test-default_config-6-meta-properties</artifactId>
|
||||
<name>Helidon Config Tests Default Config 6</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config.tests</groupId>
|
||||
<artifactId>helidon-config-tests-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-tests-test-default_config-7-meta-hocon-json</artifactId>
|
||||
<name>Helidon Config Tests Default Config 7</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config.tests</groupId>
|
||||
<artifactId>helidon-config-tests-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-tests-test-default_config-8-meta-hocon</artifactId>
|
||||
<name>Helidon Config Tests Default Config 8</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config.tests</groupId>
|
||||
<artifactId>helidon-config-tests-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-tests-test-default_config-9-meta-yaml</artifactId>
|
||||
<name>Helidon Config Tests Default Config 9</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config.tests</groupId>
|
||||
<artifactId>helidon-config-tests-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-tests-test-mappers-1-common</artifactId>
|
||||
<name>Helidon Config Tests Mappers Common 1</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config.tests</groupId>
|
||||
<artifactId>helidon-config-tests-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-tests-test-mappers-2-complex</artifactId>
|
||||
<name>Helidon Config Tests Parsers 2</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config.tests</groupId>
|
||||
<artifactId>helidon-config-tests-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-tests-test-meta-source</artifactId>
|
||||
<name>Helidon Config Tests Meta Source</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config.tests</groupId>
|
||||
<artifactId>helidon-config-tests-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-tests-test-parsers-1-complex</artifactId>
|
||||
<name>Helidon Config Tests Parsers 1</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.config</groupId>
|
||||
<artifactId>helidon-config-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-config-yaml</artifactId>
|
||||
<name>Helidon Config YAML</name>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon</groupId>
|
||||
<artifactId>helidon-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-docs</artifactId>
|
||||
<name>Helidon Documentation</name>
|
||||
|
||||
@@ -19,6 +19,6 @@
|
||||
archetype.groupId=io.helidon.archetypes
|
||||
# Expanded by create-archetypes.sh script
|
||||
archetype.artifactId=${archetypeArtifactId}
|
||||
archetype.version=0.9.2-SNAPSHOT
|
||||
archetype.version=0.10.0-SNAPSHOT
|
||||
archetype.languages=java, docker
|
||||
excludePatterns=**/.idea/**, *.iml, target/**, build/**, build.gradle, settings.gradle, .gradle/**
|
||||
|
||||
@@ -29,7 +29,7 @@ tasks.withType(JavaCompile) {
|
||||
}
|
||||
|
||||
ext {
|
||||
helidonversion = '0.9.2-SNAPSHOT'
|
||||
helidonversion = '0.10.0-SNAPSHOT'
|
||||
}
|
||||
|
||||
repositories {
|
||||
|
||||
@@ -19,18 +19,17 @@
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://mav
|
||||
en.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>io.helidon.examples</groupId>
|
||||
<artifactId>quickstart-mp</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
<name>${project.artifactId}</name>
|
||||
|
||||
<properties>
|
||||
<helidon.version>0.9.2-SNAPSHOT</helidon.version>
|
||||
<helidon.version>0.10.0-SNAPSHOT</helidon.version>
|
||||
<!-- Default package. Will be overriden by Maven archetype -->
|
||||
<package>io.helidon.examples.quickstart.mp</package>
|
||||
<mainClass>${package}.Main</mainClass>
|
||||
|
||||
@@ -29,7 +29,7 @@ tasks.withType(JavaCompile) {
|
||||
}
|
||||
|
||||
ext {
|
||||
helidonversion = '0.9.2-SNAPSHOT'
|
||||
helidonversion = '0.10.0-SNAPSHOT'
|
||||
}
|
||||
|
||||
repositories {
|
||||
|
||||
@@ -19,18 +19,17 @@
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://mav
|
||||
en.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>io.helidon.examples</groupId>
|
||||
<artifactId>quickstart-se</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
<name>${project.artifactId}</name>
|
||||
|
||||
<properties>
|
||||
<helidon.version>0.9.2-SNAPSHOT</helidon.version>
|
||||
<helidon.version>0.10.0-SNAPSHOT</helidon.version>
|
||||
<!-- Default package. Will be overriden by Maven archetype -->
|
||||
<package>io.helidon.examples.quickstart.se</package>
|
||||
<mainClass>${package}.Main</mainClass>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon</groupId>
|
||||
<artifactId>helidon-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<groupId>io.helidon.examples</groupId>
|
||||
<artifactId>helidon-examples-project</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.demo.todos</groupId>
|
||||
<artifactId>helidon-demo-todos-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-todos-backend</artifactId>
|
||||
<name>Helidon Examples TODOs Demo Backend</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.demo.todos</groupId>
|
||||
<artifactId>helidon-demo-todos-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-todos-frontend</artifactId>
|
||||
<name>Helidon Examples TODOs Demo Frontend</name>
|
||||
|
||||
@@ -30,9 +30,9 @@ import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
import io.helidon.common.CollectionsHelper;
|
||||
import io.helidon.common.http.Http;
|
||||
import io.helidon.config.Config;
|
||||
import io.helidon.security.SecurityContext;
|
||||
import io.helidon.webserver.Http;
|
||||
import io.helidon.webserver.ServerResponse;
|
||||
|
||||
import io.opentracing.Span;
|
||||
|
||||
@@ -22,9 +22,9 @@ import java.util.function.Consumer;
|
||||
import javax.json.JsonObject;
|
||||
|
||||
import io.helidon.common.OptionalHelper;
|
||||
import io.helidon.common.http.Http;
|
||||
import io.helidon.metrics.RegistryFactory;
|
||||
import io.helidon.security.SecurityContext;
|
||||
import io.helidon.webserver.Http;
|
||||
import io.helidon.webserver.Routing;
|
||||
import io.helidon.webserver.ServerRequest;
|
||||
import io.helidon.webserver.ServerResponse;
|
||||
@@ -78,6 +78,7 @@ public final class TodosHandler implements Service {
|
||||
|
||||
/**
|
||||
* Create a new {@code TodosHandler} instance.
|
||||
*
|
||||
* @param bsc the {@code BackendServiceClient} to use
|
||||
*/
|
||||
public TodosHandler(BackendServiceClient bsc) {
|
||||
@@ -109,6 +110,7 @@ public final class TodosHandler implements Service {
|
||||
|
||||
/**
|
||||
* Handler for {@code POST /todo}.
|
||||
*
|
||||
* @param req the server request
|
||||
* @param res the server response
|
||||
*/
|
||||
@@ -116,12 +118,13 @@ public final class TodosHandler implements Service {
|
||||
secure(req, res, sc -> json(req, res, json -> {
|
||||
createCounter.inc();
|
||||
sendResponse(res, bsc.create(sc, req.spanContext(), json),
|
||||
Http.Status.INTERNAL_SERVER_ERROR_500);
|
||||
Http.Status.INTERNAL_SERVER_ERROR_500);
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for {@code GET /todo}.
|
||||
*
|
||||
* @param req the server request
|
||||
* @param res the server response
|
||||
*/
|
||||
@@ -131,6 +134,7 @@ public final class TodosHandler implements Service {
|
||||
|
||||
/**
|
||||
* Handler for {@code PUT /todo/id}.
|
||||
*
|
||||
* @param req the server request
|
||||
* @param res the server response
|
||||
*/
|
||||
@@ -139,12 +143,13 @@ public final class TodosHandler implements Service {
|
||||
updateCounter.inc();
|
||||
// example of asynchronous processing
|
||||
bsc.update(sc, req.spanContext(),
|
||||
req.path().param("id"), json, res);
|
||||
req.path().param("id"), json, res);
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for {@code DELETE /todo/id}.
|
||||
*
|
||||
* @param req the server request
|
||||
* @param res the server response
|
||||
*/
|
||||
@@ -152,28 +157,30 @@ public final class TodosHandler implements Service {
|
||||
secure(req, res, sc -> {
|
||||
deleteCounter.inc();
|
||||
sendResponse(res,
|
||||
bsc.deleteSingle(sc, req.spanContext(),
|
||||
req.path().param("id")),
|
||||
Http.Status.NOT_FOUND_404);
|
||||
bsc.deleteSingle(sc, req.spanContext(),
|
||||
req.path().param("id")),
|
||||
Http.Status.NOT_FOUND_404);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for {@code GET /todo/id}.
|
||||
*
|
||||
* @param req the server request
|
||||
* @param res the server response
|
||||
*/
|
||||
private void getSingle(final ServerRequest req, final ServerResponse res) {
|
||||
secure(req, res, sc -> {
|
||||
sendResponse(res,
|
||||
bsc.getSingle(sc, req.spanContext(),
|
||||
req.path().param("id")),
|
||||
Http.Status.NOT_FOUND_404);
|
||||
bsc.getSingle(sc, req.spanContext(),
|
||||
req.path().param("id")),
|
||||
Http.Status.NOT_FOUND_404);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a response with a {@code 500} status code.
|
||||
*
|
||||
* @param res the server response
|
||||
*/
|
||||
private void noSecurityContext(final ServerResponse res) {
|
||||
@@ -184,8 +191,9 @@ public final class TodosHandler implements Service {
|
||||
/**
|
||||
* Send the response entity if {@code jsonResponse} has a value, otherwise
|
||||
* sets the status to {@code failureStatus}.
|
||||
* @param res the server response
|
||||
* @param jsonResponse the response entity
|
||||
*
|
||||
* @param res the server response
|
||||
* @param jsonResponse the response entity
|
||||
* @param failureStatus the status to use if {@code jsonResponse} is empty
|
||||
*/
|
||||
private void sendResponse(final ServerResponse res,
|
||||
@@ -200,8 +208,9 @@ public final class TodosHandler implements Service {
|
||||
* Reads a request entity as {@JsonObject}, and if successful invoke the
|
||||
* given consumer, otherwise terminate the request with a {@code 500}
|
||||
* status code.
|
||||
* @param req the server request
|
||||
* @param res the server response
|
||||
*
|
||||
* @param req the server request
|
||||
* @param res the server response
|
||||
* @param json the {@code JsonObject} consumer
|
||||
*/
|
||||
private void json(final ServerRequest req,
|
||||
@@ -214,7 +223,7 @@ public final class TodosHandler implements Service {
|
||||
.exceptionally(throwable -> {
|
||||
res.status(Http.Status.INTERNAL_SERVER_ERROR_500);
|
||||
res.send(throwable.getClass().getName()
|
||||
+ ": " + throwable.getMessage());
|
||||
+ ": " + throwable.getMessage());
|
||||
return null;
|
||||
});
|
||||
}
|
||||
@@ -223,6 +232,7 @@ public final class TodosHandler implements Service {
|
||||
* Reads the request security context, and if successful invoke the given
|
||||
* consumer, otherwise terminate the request with a {@code 500}
|
||||
* status code.
|
||||
*
|
||||
* @param req the server request
|
||||
* @param res the server response
|
||||
* @param ctx the {@code SecurityContext} consumer
|
||||
@@ -232,7 +242,7 @@ public final class TodosHandler implements Service {
|
||||
final Consumer<SecurityContext> ctx) {
|
||||
|
||||
OptionalHelper.from(req.context()
|
||||
.get(SecurityContext.class))
|
||||
.get(SecurityContext.class))
|
||||
.ifPresentOrElse(ctx, () -> noSecurityContext(res));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<groupId>io.helidon.demo.todos</groupId>
|
||||
<artifactId>helidon-demo-todos-project</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
<name>Helidon Examples TODOs Demo</name>
|
||||
|
||||
<description>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon</groupId>
|
||||
<artifactId>helidon-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-javadocs</artifactId>
|
||||
<name>Helidon Javadocs</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.microprofile.bundles</groupId>
|
||||
<artifactId>bundles-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-microprofile-1.0</artifactId>
|
||||
<name>Helidon Microprofile Bundles 1.0</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.microprofile.bundles</groupId>
|
||||
<artifactId>bundles-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-microprofile-1.1</artifactId>
|
||||
<name>Helidon Microprofile Bundles 1.1</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.microprofile.bundles</groupId>
|
||||
<artifactId>bundles-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-microprofile-1.2</artifactId>
|
||||
<name>Helidon Microprofile Bundles 1.2</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.microprofile.bundles</groupId>
|
||||
<artifactId>bundles-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>internal-test-libs</artifactId>
|
||||
<name>Helidon Microprofile Bundles Test Libraries</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.microprofile</groupId>
|
||||
<artifactId>helidon-microprofile-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<packaging>pom</packaging>
|
||||
<groupId>io.helidon.microprofile.bundles</groupId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.microprofile.config</groupId>
|
||||
<artifactId>helidon-microprofile-config-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-microprofile-config-cdi</artifactId>
|
||||
<name>Helidon Microprofile Config CDI</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.microprofile.config</groupId>
|
||||
<artifactId>helidon-microprofile-config-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-microprofile-config</artifactId>
|
||||
<name>Helidon Microprofile Config Core</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.microprofile</groupId>
|
||||
<artifactId>helidon-microprofile-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<packaging>pom</packaging>
|
||||
<groupId>io.helidon.microprofile.config</groupId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.microprofile.examples</groupId>
|
||||
<artifactId>examples-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>hello-world-explicit</artifactId>
|
||||
<name>Helidon Microprofile Examples Explicit Hello World</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.microprofile.examples</groupId>
|
||||
<artifactId>examples-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>hello-world-implicit</artifactId>
|
||||
<name>Helidon Microprofile Examples Implicit Hello World</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.microprofile.examples</groupId>
|
||||
<artifactId>examples-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>security-idcs</artifactId>
|
||||
<name>Helidon Microprofile Examples IDCS Security</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.microprofile.examples</groupId>
|
||||
<artifactId>examples-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>mp1_1-security</artifactId>
|
||||
<name>Helidon Microprofile Examples MP 1.1 Security</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.microprofile.examples</groupId>
|
||||
<artifactId>examples-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>mp1_1-static-content</artifactId>
|
||||
<name>Helidon Microprofile Examples MP 1.1 Static Content</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.microprofile</groupId>
|
||||
<artifactId>helidon-microprofile-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<packaging>pom</packaging>
|
||||
<groupId>io.helidon.microprofile.examples</groupId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.microprofile.health</groupId>
|
||||
<artifactId>helidon-microprofile-health-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-microprofile-health-checks</artifactId>
|
||||
<name>Helidon Microprofile Health Checks</name>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>io.helidon.microprofile.health</groupId>
|
||||
<artifactId>helidon-microprofile-health-project</artifactId>
|
||||
<version>0.9.2-SNAPSHOT</version>
|
||||
<version>0.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>helidon-microprofile-health-core</artifactId>
|
||||
<name>Helidon Microprofile Health Core</name>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user